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 =
"0.6.5"

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
# File 'lib/recursive_open_struct.rb', line 12

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

  @table = args.fetch(:mutate_input_hash, false) ? hash : @deep_dup.call(hash)
  @table && @table.each_key { |k| new_ostruct_member(k) }

  @sub_elements = {}
end

Instance Method Details

#[](name) ⇒ Object



38
39
40
# File 'lib/recursive_open_struct.rb', line 38

def [](name)
  send name
end

#delete_field(name) ⇒ Object



84
85
86
87
88
89
# File 'lib/recursive_open_struct.rb', line 84

def delete_field(name)
  sym = _get_key_from_table_(name)
  singleton_class.__send__(:remove_method, sym, "#{sym}=")
  @sub_elements.delete sym
  @table.delete sym
end

#initialize_copy(orig) ⇒ Object



23
24
25
26
27
28
29
30
# File 'lib/recursive_open_struct.rb', line 23

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



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/recursive_open_struct.rb', line 42

def new_ostruct_member(name)
  key_name = _get_key_from_table_ name
  unless self.respond_to?(name)
    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,
            :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

#recurse_over_array(array) ⇒ Object

TODO: Make me private if/when we do an API-breaking change release



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/recursive_open_struct.rb', line 72

def recurse_over_array(array)
  array.map do |a|
    if a.is_a? Hash
      self.class.new(a, :recurse_over_arrays => true, :mutate_input_hash => true)
    elsif a.is_a? Array
      recurse_over_array a
    else
      a
    end
  end
end

#to_hObject Also known as: to_hash



32
33
34
# File 'lib/recursive_open_struct.rb', line 32

def to_h
  @deep_dup.call(@table)
end