Class: RecursiveOpenStruct
- Inherits:
-
OpenStruct
- Object
- OpenStruct
- RecursiveOpenStruct
- Includes:
- DebugInspect, Dig, Ruby19Backport
- Defined in:
- lib/recursive_open_struct.rb,
lib/recursive_open_struct/dig.rb,
lib/recursive_open_struct/version.rb
Overview
TODO: When we care less about Rubies before 2.4.0, match OpenStruct’s method names instead of doing things like aliasing ‘new_ostruct_member` to `new_ostruct_member!`
TODO: ‘#*_as_a_hash` deprecated. Nested hashes can be referenced using `#to_h`.
Defined Under Namespace
Modules: DebugInspect, Dig, Ruby19Backport Classes: DeepDup
Constant Summary collapse
- VERSION =
"1.1.1"
Instance Method Summary collapse
- #[](name) ⇒ Object
- #delete_field(name) ⇒ Object
-
#initialize(hash = nil, args = {}) ⇒ RecursiveOpenStruct
constructor
A new instance of RecursiveOpenStruct.
- #initialize_copy(orig) ⇒ Object
-
#method_missing(mid, *args) ⇒ Object
Adapted implementation of method_missing to accommodate the differences between ROS and OS.
-
#new_ostruct_member(name) ⇒ Object
(also: #new_ostruct_member!)
TODO: Rename to new_ostruct_member! once we care less about Rubies before 2.4.0.
-
#respond_to_missing?(mid, include_private = false) ⇒ Boolean
Makes sure ROS responds as expected on #respond_to? and #method requests.
- #to_h ⇒ Object (also: #to_hash)
Methods included from DebugInspect
#debug_inspect, #display_recursive_open_struct
Methods included from Dig
Methods included from Ruby19Backport
#[]=, #each_pair, #eql?, #hash
Constructor Details
#initialize(hash = nil, args = {}) ⇒ RecursiveOpenStruct
Returns a new instance of RecursiveOpenStruct.
24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/recursive_open_struct.rb', line 24 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 accommodate the differences between ROS and OS.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/recursive_open_struct.rb', line 92 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
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/recursive_open_struct.rb', line 55 def [](name) key_name = _get_key_from_table_(name) 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 |
#delete_field(name) ⇒ Object
141 142 143 144 145 146 |
# File 'lib/recursive_open_struct.rb', line 141 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
38 39 40 41 42 43 44 45 |
# File 'lib/recursive_open_struct.rb', line 38 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 Also known as: new_ostruct_member!
TODO: Rename to new_ostruct_member! once we care less about Rubies before 2.4.0.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/recursive_open_struct.rb', line 115 def new_ostruct_member(name) key_name = _get_key_from_table_(name) unless self.singleton_class.method_defined?(name.to_sym) class << self; self; end.class_eval do define_method(name) do self[key_name] 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
74 75 76 77 |
# File 'lib/recursive_open_struct.rb', line 74 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_h ⇒ Object Also known as: to_hash
47 48 49 |
# File 'lib/recursive_open_struct.rb', line 47 def to_h @deep_dup.call(@table) end |