Skip to content

Support Zeitwerk #163

Description

@adfoster-r7

Just copy/pasting a separate idea from #157 that I would love to have opinions on; the goal is to solve the problem of there being a global central registry in BinData for resolving class details - which has caused issues for a larger code base with lazy loading, or accidentally having duplicate definitions etc

I wonder if it'd be possible to support a more explicit method for the bindata DSL, so that instead of relying on metaprogramming for the type lookups - the user could supply the type explicitly via a model (or field, etc) method:

class Request < BinData::Record
    endian :big
    uint8 :message_type, initial_value: 3
    uint8 :incremental
-   rectangle :rectangle
+   field :rectangle, type: Rectangle
end

Since we can explicitly specify the Ruby class this has the benefit of Ruby's inbuilt namespacing support (field :rectangle, type: V1::Rectangle etc), being compatible with Zeitwerk for lazy-loading large/complex object graphs (as currently we have to eagerly load complex models upfront to ensure the types are available for the bindata DSL to work), and it also better integrates with a code editor out of the box - code completion, refactoring, navigating to definitions etc.

Choice example before/after:

-  class TightCompressionBasicCompression < BinData::Record
+  class BasicCompression < BinData::Record
     endian :big
 
-    search_prefix :tight_compression_basic_compression
-
     # Two bits dedicated to which stream to use
     #
     # 00 - Use stream 0
@@ -150,12 +149,14 @@ class RubyVnc::Decoder::Tight
     uint8 :filter_id, onlyif: -> { (compression_flag & 0b0100) >> 2 == 1 }
 
     choice :filter_value, selection: -> { filter_id } do
-      copy_filter BasicCompressionFilterType::COPY_FILTER,
-                  width: -> { width },
-                  height: -> { height }
-      palette_filter BasicCompressionFilterType::PALETTE_FILTER,
-                     width: -> { width },
-                     height: -> { height }
+      field BasicCompressionFilterType::COPY_FILTER,
+            type: CopyFilter,
+            width: -> { width },
+            height: -> { height }
+      field BasicCompressionFilterType::PALETTE_FILTER,
+            type: PaletteFilter,
+            width: -> { width },
+            height: -> { height }
     end
   end

In the above snippet we can drop the search_prefix workaround since we rely on Ruby's resolving logic for looking up the Ruby class, and we can drop the verbose TightCompressionBasicCompression class name prefix from our bindata definitions - which I had added previously to support bindata's type resolution lookup:

class RubyVnc::Decoder::Tight

-  class TightCompressionBasicCompressionPaletteSize < BinData::BasePrimitive
+  class PaletteSize < BinData::BasePrimitive
...

-  class TightCompressionBasicCompression < BinData::Record
+  class BasicCompression < BinData::Record

...

My local bindata hack for spiking this was just a branch of v4.10.0 (since that's what my older app was using at the time):

diff --git a/lib/bindata/sanitize.rb b/lib/bindata/sanitize.rb
index 7325b20..347c8fe 100644
--- a/lib/bindata/sanitize.rb
+++ b/lib/bindata/sanitize.rb
@@ -15,6 +15,9 @@ module BinData
 
       if BinData::Base === obj_type
         obj_class = obj_type
+      elsif :field == obj_type
+        # TODO: Confirm if raw_hints should be honored here
+        obj_class = obj_params[:type]
       else
         obj_class = RegisteredClasses.lookup(obj_type, raw_hints)
       end

A real implementation would likely have to honor raw_hints - and provide a way to opt out of registering with bindata's global dsl registry

I didn't run through all of the edgecases, so apologies if this approach has been discussed and ruled out as a valid approach previously! 💯

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions