Class: Simple::Immutable

Inherits:
Object
  • Object
show all
Defined in:
lib/simple/immutable.rb

Constant Summary collapse

SELF =
self

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, &block) ⇒ Object (private)

Raises:

  • (ArgumentError)


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/simple/immutable.rb', line 70

def method_missing(sym, *args, &block)
  raise ArgumentError, "Immutable: called attribute method with arguments" unless args.empty?
  raise ArgumentError, "Immutable: called attribute method with arguments" if block

  if sym.end_with?("?")
    # If the symbol ends in "?" we do not raise a NameError, but instead
    # returns nil if the attribute is not known.
    sym = sym[0...-1]

    # Note that sym is now a String. However, we are String/Symbol agnostic
    # (in fetch_symbol_or_string_from_hash), so this is ok.
    fetch_attribute!(sym, raise_when_missing: false)
  else
    fetch_attribute!(sym, raise_when_missing: true)
  end
end

Class Method Details

.create(object, max_depth: 8, null_record: nil, fallback: nil) ⇒ Object

turns an object, which can be a hash or array of hashes, arrays, and scalars into an object which you can use to access with dot methods.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/simple/immutable.rb', line 9

def self.create(object, max_depth: 8, null_record: nil, fallback: nil)
  # Note that null_record is deprecated.
  fallback ||= null_record

  case object
  when Array
    raise ArgumentError, "Object nested too deep (or inner loop?)" if max_depth < 0

    object.map { |obj| create obj, fallback: fallback, max_depth: max_depth - 1 }
  when Hash
    new(object, fallback)
  else
    object
  end
end

.raw_data(immutable) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/simple/immutable.rb', line 25

def self.raw_data(immutable)
  case immutable
  when SELF
    hsh = immutable.instance_variable_get :@hsh
    fallback = immutable.instance_variable_get :@fallback

    if fallback
      fallback.merge(hsh)
    else
      hsh
    end
  when Array
    immutable.map { |e| raw_data(e) }
  else
    immutable
  end
end

Instance Method Details

#==(other) ⇒ Object



128
129
130
# File 'lib/simple/immutable.rb', line 128

def ==(other)
  @hsh == other
end

#as_json(opts) ⇒ Object

adds to_json support.



44
45
46
47
# File 'lib/simple/immutable.rb', line 44

def as_json(opts)
  data = SELF.raw_data(self)
  data.as_json(opts)
end

#fetch_attribute!(sym, raise_when_missing:) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/simple/immutable.rb', line 89

def fetch_attribute!(sym, raise_when_missing:)
  value = SELF.fetch_symbol_or_string_from_hash(@hsh, sym) do
    SELF.fetch_symbol_or_string_from_hash(@fallback, sym) do
      raise NameError, "unknown immutable attribute '#{sym}'" if raise_when_missing

      nil
    end
  end

  SELF.create(value)
end

#inspectObject



101
102
103
104
105
106
107
# File 'lib/simple/immutable.rb', line 101

def inspect
  if @fallback
    "<#{self.class.name}: #{@hsh.inspect}, w/fallback: #{@fallback.inspect}>"
  else
    "<#{self.class.name}: #{@hsh.inspect}>"
  end
end

#respond_to?(sym, include_all = false) ⇒ Boolean

rubocop:disable Style/OptionalBooleanParameter

Returns:

  • (Boolean)


124
125
126
# File 'lib/simple/immutable.rb', line 124

def respond_to?(sym, include_all = false)
  super || @hsh.key?(sym.to_s) || @hsh.key?(sym.to_sym)
end

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

Returns:

  • (Boolean)


109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/simple/immutable.rb', line 109

def respond_to_missing?(method_name, include_private = false)
  return true if method_name.end_with?("?")

  key = method_name.to_sym
  return true if @hsh.key?(key)
  return true if @fallback&.key?(key)

  key = method_name.to_s
  return true if @hsh.key?(key)
  return true if @fallback&.key?(key)

  super
end