Class: RecursiveOpenStruct

Inherits:
OpenStruct
  • Object
show all
Includes:
DebugInspect, Ruby19Backport
Defined in:
lib/recursive_open_struct.rb,
lib/recursive_open_struct/version.rb

Defined Under Namespace

Modules: DebugInspect, Ruby19Backport Classes: DeepDup

Constant Summary collapse

VERSION =
"1.0.2"

Instance Method Summary collapse

Methods included from DebugInspect

#debug_inspect, #display_recursive_open_struct

Methods included from Ruby19Backport

#[]=, #each_pair, #eql?, #hash

Constructor Details

#initialize(hash = nil, args = {}) ⇒ RecursiveOpenStruct

Returns a new instance of RecursiveOpenStruct.



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/recursive_open_struct.rb', line 12

def initialize(hash=nil, args={})
  hash ||= {}
  @recurse_over_arrays = args.fetch(:recurse_over_arrays, false)
  @preserve_original_keys = args.fetch(:preserve_original_keys, false)
  @deep_dup = DeepDup.new(
    recurse_over_arrays: @recurse_over_arrays,
    preserve_original_keys: @preserve_original_keys
  )

  @table = args.fetch(:mutate_input_hash, false) ? hash : @deep_dup.call(hash)

  @sub_elements = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(mid, *args) ⇒ Object

Adapted implementation of method_missing to accomodate the differences between ROS and OS.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/recursive_open_struct.rb', line 52

def method_missing(mid, *args)
  len = args.length
  if mid =~ /^(.*)=$/
    if len != 1
      raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
    end
    modifiable[new_ostruct_member($1.to_sym)] = args[0]
  elsif len == 0
    key = mid
    key = $1 if key =~ /^(.*)_as_a_hash$/
    if @table.key?(_get_key_from_table_(key))
      new_ostruct_member(key)
      send(mid)
    end
  else
    err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
    err.set_backtrace caller(1)
    raise err
  end
end

Instance Method Details

#[](name) ⇒ Object



41
42
43
# File 'lib/recursive_open_struct.rb', line 41

def [](name)
  public_send(name)
end

#delete_field(name) ⇒ Object



103
104
105
106
107
108
# File 'lib/recursive_open_struct.rb', line 103

def delete_field(name)
  sym = _get_key_from_table_(name)
  singleton_class.__send__(:remove_method, sym, "#{sym}=") rescue NoMethodError # ignore if methods not yet generated.
  @sub_elements.delete sym
  @table.delete sym
end

#initialize_copy(orig) ⇒ Object



26
27
28
29
30
31
32
33
# File 'lib/recursive_open_struct.rb', line 26

def initialize_copy(orig)
  super

  # deep copy the table to separate the two objects
  @table = @deep_dup.call(orig.instance_variable_get(:@table))
  # Forget any memoized sub-elements
  @sub_elements = {}
end

#new_ostruct_member(name) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/recursive_open_struct.rb', line 73

def new_ostruct_member(name)
  key_name = _get_key_from_table_ name
  unless self.methods.include?(name.to_sym)
    class << self; self; end.class_eval do
      define_method(name) do
        v = @table[key_name]
        if v.is_a?(Hash)
          @sub_elements[key_name] ||= self.class.new(
            v,
            recurse_over_arrays: @recurse_over_arrays,
            preserve_original_keys: @preserve_original_keys,
            mutate_input_hash: true
          )
        elsif v.is_a?(Array) and @recurse_over_arrays
          @sub_elements[key_name] ||= recurse_over_array(v)
          @sub_elements[key_name] = recurse_over_array(@sub_elements[key_name])
        else
          v
        end
      end
      define_method("#{name}=") do |x|
        @sub_elements.delete(key_name)
        modifiable[key_name] = x
      end
      define_method("#{name}_as_a_hash") { @table[key_name] }
    end
  end
  key_name
end

#respond_to_missing?(mid, include_private = false) ⇒ Boolean

Makes sure ROS responds as expected on #respond_to? and #method requests

Returns:

  • (Boolean)


46
47
48
49
# File 'lib/recursive_open_struct.rb', line 46

def respond_to_missing?(mid, include_private = false)
  mname = _get_key_from_table_(mid.to_s.chomp('=').chomp('_as_a_hash'))
  @table.key?(mname) || super
end

#to_hObject Also known as: to_hash



35
36
37
# File 'lib/recursive_open_struct.rb', line 35

def to_h
  @deep_dup.call(@table)
end