aetherknight / recursive-open-struct

OpenStruct subclass that returns nested hash attributes as RecursiveOpenStructs
Other
276 stars 54 forks source link

On ros.inspect I can't see my array if recurse_over_arrays: true #46

Closed PedroSena closed 7 years ago

PedroSena commented 8 years ago

Hi,

I'm trying to upgrade ROS from 0.5 to 1.0 and I noticed a behavior that was working previously:

bar = OpenStruct.new({a: 'a'})
bar.foos = []
bar.foos << {b: 'b'}
bar.inspect
=> "#<OpenStruct a=\"a\", foos=[{:b=>\"b\"}]>"

bar = RecursiveOpenStruct.new({a: 'a'})
bar.foos = []
bar.foos << {b: 'b'}
bar.inspect
=> "#<RecursiveOpenStruct a=\"a\", foos=[{:b=>\"b\"}]>"

bar = RecursiveOpenStruct.new({a: 'a'}, recurse_over_arrays: true)
bar.foos = []
bar.foos << {b: 'b'}
bar.inspect
=> "#<RecursiveOpenStruct a=\"a\", foos=[]>"

Apparently when I set recurse_over_arrays: true ROS is no longer able to return me this information when I use inspect (same happens when I try to call render json: ros on Rails for instance), however the information is apparently there:

bar.foos
=> [#<RecursiveOpenStruct b="b">]

Thanks

aetherknight commented 8 years ago

Good catch. Actually, the bug is worse. It looks like appending to an array while recurse_over_arrays is true isn't updating the internal state correctly.

bar = RecursiveOpenStruct.new({a: 'a'}, recurse_over_arrays: true)
bar.foos = []
bar.foos << {b: 'b'}
bar.foos[0].b
=> "b"
bar.to_h.inspect
=> "{:a=>\"a\", :foos=>[]}"
aetherknight commented 8 years ago

I suspect this is the same issue as https://github.com/aetherknight/recursive-open-struct/issues/29#issuecomment-103767000

aetherknight commented 8 years ago

There isn't a straightforward solution to using << to modify the array. Currently, ROS does not use a special implementation of Array to update the internal @table whenever the array is modified (whereas the nested ROS objects have access to a nested hash that is part of the parent ROS's @table so they can mutate it).

When you call bar.foo << {b: 'b'}, ROS returns the array that corresponds to bar.foo, but then Array#<< is called to mutate the returned array. ROS could try to detect the change on every method call that might examine the @table to ensure it is up-to-date before using the @table, however that is prone to missing some place where it might be used. Alternately, it could use a special subclass of Array that keeps the array within @table up-to-date (it would have to override every method that could mutate the array).

I am happy to review and accept a PR that provides one of these solutions, but I don't have the time or inclination to implement it myself (My interest in ROS is limited to using it in a read-only capacity)

aetherknight commented 7 years ago

Per the description of #47 this should now be fixed by @PedroSena and released in 1.0.2