dmendel / bindata

BinData - Reading and Writing Binary Data in Ruby
BSD 2-Clause "Simplified" License
577 stars 55 forks source link

Is there any trivial way to assign an object which is defined by several nested structure? #119

Closed tan-wei closed 4 years ago

tan-wei commented 4 years ago

Firstly, thanks for the great tool to parse messages. It works quite well and elegant when parsing a structured message. Maybe the most powerful tool in all programming languages, after I've tried dozens of tools to parse message.

But I have a question about the object assignment. For example:

class YetAnotherNested < BinData::Record
    uint8 :d
end

class Nested < BinData::Record
    uint8 :b
    yet_another_nested :c
end

class A < BinData::Record
    uint8 :a
    nested :nested
end

pp A.new # => {:a=>0, :nested=>{:b=>0, :c=>{:d=>0}}}

If we want to create a new A with assign a, b, and d, according to the documents and examples (compared to parsing process, assignment process is less mentioned), we can do it like this:

pp A.new({:a=>1, :nested=>{:b=>2, :c=>{:d=>3}}}) # => {:a=>1, :nested=>{:b=>2, :c=>{:d=>3}}}

It works well. However, for a complex object, is there a trival way to assign a valid object? A workaround may be done like this:

def templated_assign(a, b, d)
    A.new({:a=>a, :nested=>{:b=>b, :c=>{:d=>d}}})
end

pp templated_assign(1, 2, 3)

But I don't know whether there is a trival and elegant one. Thanks!

dmendel commented 4 years ago

Trivial and (possibly) elegant, yes. Safe, no.

This approach will cause problems if there are fields in different nested structures with the same name.

a = A.new
a.flat_assign(:a => 1, :b => 2, :d => 3)
class BinData::Struct
  def flat_assign(val)
    assign(val)

    unassigned = val.keep_if { |k,v| ! field_names.include? k }
    field_names.each do |field|
      self[field].flat_assign(unassigned) rescue NoMethodError
    end
  end
end
tan-wei commented 4 years ago

Got it. Maybe provide a templated assign maybe a more safe solution. Yes, I've think of sometinng just like flat_assign, it requries every names in every nested stuctures have different names in order to set their values in the corrent location. But in many cases, different names for all is not an elegent solution...

Thanks very much.