Class: Inquery::MethodAccessibleHash
- Inherits:
-
Object
- Object
- Inquery::MethodAccessibleHash
- Defined in:
- lib/inquery/method_accessible_hash.rb
Overview
A safe alternative for ‘OpenStruct` in Ruby. It provides convenient method access to a set of key-value pairs, just like `OpenStruct`, but uses `method_missing` instead of defining methods on-the-fly.
Unlike a ‘Hash`, this class deliberately does not inherit from `Hash` (or include `Enumerable`). If it did, keys whose names collide with `Hash` / `Enumerable` methods (e.g. `group_by`, `count`, `zip`, `select`, …) would invoke the inherited method instead of returning the stored value, because `method_missing` is only called for methods that are not already defined.
Usage example:
“‘ruby default_options = { foo: :bar } options = MethodAccessibleHash.new(default_options) options = :green options.foo # => :bar options.color # => :green “`
Constant Summary collapse
- CONVERSION_METHODS =
Methods that participate in Ruby’s implicit type-coercion protocol. We must neither pretend to respond to these (‘respond_to_missing?`) nor fabricate a `nil` value for them (`method_missing`). Otherwise constructs such as `**hash`, `Hash(obj)`, `Array(obj)` or Rails’ implicit conversions would detect the method, call it, receive ‘nil` and raise a `TypeError`. Keys actually present under one of these names are still returned normally.
%i[to_ary to_a to_hash to_str to_int to_proc].freeze
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#[](key) ⇒ Object
Returns the value stored under the given key.
-
#[]=(key, value) ⇒ Object
Stores the given value under the given (symbolized) key.
- #freeze ⇒ Object
-
#initialize(hash = {}) ⇒ MethodAccessibleHash
constructor
Takes an optional hash as argument and constructs a new MethodAccessibleHash.
-
#merge(other = {}) ⇒ Object
Returns a new MethodAccessibleHash with the given hash merged in.
- #method_missing(method, *args, &_block) ⇒ Object
- #respond_to_missing?(method, _include_private = false) ⇒ Boolean
-
#to_h ⇒ Object
Returns a (shallow) copy of the underlying data as a plain Hash with symbol keys.
- #to_s ⇒ Object (also: #inspect)
Constructor Details
#initialize(hash = {}) ⇒ MethodAccessibleHash
Takes an optional hash as argument and constructs a new MethodAccessibleHash. Keys are symbolized.
33 34 35 36 37 38 |
# File 'lib/inquery/method_accessible_hash.rb', line 33 def initialize(hash = {}) @table = {} (hash || {}).each do |key, value| @table[key.to_sym] = value end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &_block) ⇒ Object
89 90 91 92 93 94 95 96 97 98 |
# File 'lib/inquery/method_accessible_hash.rb', line 89 def method_missing(method, *args, &_block) name = method.to_s if name.end_with?('=') self[name[0..-2].to_sym] = args.first elsif CONVERSION_METHODS.include?(method) && !@table.key?(method) super else @table[method.to_sym] end end |
Instance Method Details
#==(other) ⇒ Object
65 66 67 68 69 70 71 72 73 74 |
# File 'lib/inquery/method_accessible_hash.rb', line 65 def ==(other) case other when MethodAccessibleHash to_h == other.to_h when ::Hash to_h == other.symbolize_keys else false end end |
#[](key) ⇒ Object
Returns the value stored under the given key. Keys are accessed indifferently as the storage is symbolized.
42 43 44 |
# File 'lib/inquery/method_accessible_hash.rb', line 42 def [](key) @table[key.to_sym] end |
#[]=(key, value) ⇒ Object
Stores the given value under the given (symbolized) key. Modifying a frozen instance raises a ‘FrozenError`, because `@table` is frozen alongside the instance (see `freeze` and `initialize_copy`).
49 50 51 |
# File 'lib/inquery/method_accessible_hash.rb', line 49 def []=(key, value) @table[key.to_sym] = value end |
#freeze ⇒ Object
83 84 85 86 |
# File 'lib/inquery/method_accessible_hash.rb', line 83 def freeze @table.freeze super end |
#merge(other = {}) ⇒ Object
Returns a new MethodAccessibleHash with the given hash merged in.
60 61 62 |
# File 'lib/inquery/method_accessible_hash.rb', line 60 def merge(other = {}) self.class.new(to_h.merge(other.to_h.symbolize_keys)) end |
#respond_to_missing?(method, _include_private = false) ⇒ Boolean
101 102 103 104 105 |
# File 'lib/inquery/method_accessible_hash.rb', line 101 def respond_to_missing?(method, _include_private = false) return false if CONVERSION_METHODS.include?(method) && !@table.key?(method) true end |
#to_h ⇒ Object
Returns a (shallow) copy of the underlying data as a plain Hash with symbol keys.
55 56 57 |
# File 'lib/inquery/method_accessible_hash.rb', line 55 def to_h @table.dup end |
#to_s ⇒ Object Also known as: inspect
77 78 79 |
# File 'lib/inquery/method_accessible_hash.rb', line 77 def to_s @table.to_s end |