Class: SmartHash
- Inherits:
-
Hash
- Object
- Hash
- SmartHash
- Defined in:
- lib/smart_hash.rb,
lib/smart_hash/loose.rb,
lib/smart_hash/version.rb,
lib/smart_hash/dynamic_methods.rb
Overview
A smarter alternative to OpenStruct
Major features:
-
You can access attributes as methods or keys.
-
Attribute access is strict by default.
-
You can use any attribute names.
-
Descends from ‘Hash` and inherits its rich feature set.
See rubydoc documentation for basic usage examples.
Direct Known Subclasses
Defined Under Namespace
Modules: DynamicMethods Classes: Loose
Constant Summary collapse
- ATTR_REGEXP =
Attribute name regexp without delimiters.
/[a-zA-Z_]\w*/
- FORBIDDEN_ATTRS =
Attribute names that are forbidden. Forbidden attrs cannot be manupulated as such and are handled as methods only.
[:default, :default_proc, :strict]
- VERSION =
Gem version.
"0.1.1"
Instance Attribute Summary collapse
-
#declared_attrs ⇒ Object
readonly
See #declare.
-
#protected_attrs ⇒ Object
readonly
See #protect.
-
#strict ⇒ Object
Strict mode.
Class Method Summary collapse
-
.[](*args) ⇒ Object
Alternative constructor.
Instance Method Summary collapse
-
#declare(*attrs) ⇒ Object
Declare attributes.
-
#initialize(*args) ⇒ SmartHash
constructor
A new instance of SmartHash.
-
#protect(*attrs) ⇒ Object
Protect attributes from being assigned.
- #undeclare(*attrs) ⇒ Object
- #unprotect(*attrs) ⇒ Object
Constructor Details
#initialize(*args) ⇒ SmartHash
Returns a new instance of SmartHash.
46 47 48 49 |
# File 'lib/smart_hash.rb', line 46 def initialize(*args) super _smart_hash_init end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args) ⇒ Object (private)
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/smart_hash.rb', line 199 def method_missing(method_name, *args) # NOTE: No need to check for forbidden attrs here, since they exist as methods by definition. case method_name when /\A(.+)=\z/ # Assignment. Method name is pre-validated for us by Ruby. attr = $1.to_sym raise ArgumentError, "Attribute is protected: #{attr}" if @protected_attrs.include? attr self[attr] = args[0] when /\A(#{ATTR_REGEXP})\z/ # Access. attr = $1.to_sym if @strict _smart_hash_fetch(attr) else self[attr] end else super end end |
Instance Attribute Details
#declared_attrs ⇒ Object (readonly)
See #declare.
32 33 34 |
# File 'lib/smart_hash.rb', line 32 def declared_attrs @declared_attrs end |
#protected_attrs ⇒ Object (readonly)
See #protect.
35 36 37 |
# File 'lib/smart_hash.rb', line 35 def protected_attrs @protected_attrs end |
#strict ⇒ Object
Strict mode. Default is true
.
person = SmartHash[]
person.invalid_stuff # KeyError: key not found: :invalid_stuff
person.strict = false
person.invalid_stuff # => nil
44 45 46 |
# File 'lib/smart_hash.rb', line 44 def strict @strict end |
Class Method Details
.[](*args) ⇒ Object
Alternative constructor.
person = SmartHash[]
54 55 56 57 58 59 60 |
# File 'lib/smart_hash.rb', line 54 def self.[](*args) super.tap do |_| _.instance_eval do _smart_hash_init end end end |
Instance Method Details
#declare(*attrs) ⇒ Object
Declare attributes. By declaring the attributes you ensure that there’s no interference from existing methods.
person = SmartHash[]
person.declare(:size)
person.size # KeyError: key not found: :size
person.size = "XL"
person.size # => "XL"
See also #undeclare.
73 74 75 76 77 78 79 80 |
# File 'lib/smart_hash.rb', line 73 def declare(*attrs) raise ArgumentError, "No attributes specified" if attrs.empty? attrs.each do |attr| [attr, Symbol].tap {|v, klass| v.is_a?(klass) or raise ArgumentError, "#{klass} expected, #{v.class} (#{v.inspect}) given"} attr.to_s.match /\A#{ATTR_REGEXP}\z/ or raise ArgumentError, "Incorrect attribute name: #{attr}" @declared_attrs << attr # `Set` is returned. end end |
#protect(*attrs) ⇒ Object
Protect attributes from being assigned.
person = SmartHash[]
person.name = "John"
person.protect(:name)
person.name = "Bob" # ArgumentError: Attribute 'name' is protected
See also #unprotect.
91 92 93 94 95 96 97 98 |
# File 'lib/smart_hash.rb', line 91 def protect(*attrs) raise ArgumentError, "No attributes specified" if attrs.empty? attrs.each do |attr| [attr, Symbol].tap {|v, klass| v.is_a?(klass) or raise ArgumentError, "#{klass} expected, #{v.class} (#{v.inspect}) given"} attr.to_s.match /\A#{ATTR_REGEXP}\z/ or raise ArgumentError, "Incorrect attribute name: #{attr}" @protected_attrs << attr end end |
#undeclare(*attrs) ⇒ Object
100 101 102 103 104 105 |
# File 'lib/smart_hash.rb', line 100 def undeclare(*attrs) raise ArgumentError, "No attributes specified" if attrs.empty? attrs.each do |attr| @declared_attrs.delete(attr) # `Set` is returned. end end |
#unprotect(*attrs) ⇒ Object
107 108 109 110 111 112 |
# File 'lib/smart_hash.rb', line 107 def unprotect(*attrs) raise ArgumentError, "No attributes specified" if attrs.empty? attrs.each do |attr| @protected_attrs.delete(attr) end end |