Class: SmartHash
- Inherits:
-
Hash
- Object
- Hash
- SmartHash
- Defined in:
- lib/smart_hash.rb,
lib/smart_hash/loose.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.
Basic Usage
Create an object and set a few attributes:
>> person = SmartHash[]
>> person.name = "John"
>> person.age = 25
>> person
=> {:name=>"John", :age=>25}
Read attributes:
>> person.name
=> "John"
>> person[:name]
=> "John"
Access an unset attribute:
>> person.invalid_stuff
KeyError: key not found: :invalid_stuff
>> person[:invalid_stuff]
=> nil
Please note that `[]` access is always non-strict since `SmartHash` behaves as `Hash` here.
Manipulate attributes which exist as methods:
>> person = SmartHash[:name => "John"]
>> person.size
=> 1
>> person.size = "XL"
>> person.size
=> "XL"
*IMPORTANT:* You can use any attribute names excluding these: `default`, `default_proc`, `strict`.
Use `Hash` features, e.g. merge:
>> person = SmartHash[:name => "John"]
>> person.merge(:surname => "Smith", :age => 25)
=> {:name=>"John", :surname=>"Smith", :age=>25}
, or iterate:
>> person.each {|k, v| puts "#{k}: #{v}"}
name: John
surname: Smith
age: 25
Direct Known Subclasses
Defined Under Namespace
Classes: Loose
Constant Summary
- 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.0"
Instance Attribute Summary (collapse)
-
- (Object) declared_attrs
readonly
See #declare.
-
- (Object) protected_attrs
readonly
See #protect.
-
- (Object) strict
Strict mode.
Class Method Summary (collapse)
-
+ (Object) [](*args)
Alternative constructor.
Instance Method Summary (collapse)
-
- (Object) declare(*attrs)
Declare that specific key(s) are going to be used as attributes.
-
- (SmartHash) initialize(*args)
constructor
A new instance of SmartHash.
-
- (Object) protect(*attrs)
Protect attributes against assignment.
- - (Object) undeclare(*attrs)
- - (Object) unprotect(*attrs)
Constructor Details
- (SmartHash) initialize(*args)
A new instance of SmartHash
86 87 88 89 |
# File 'lib/smart_hash.rb', line 86 def initialize(*args) super _smart_hash_init end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
- (Object) method_missing(method_name, *args) (private)
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/smart_hash.rb', line 206 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/ # Case "r.attr=". Attribute assignment. Method name is pre-validated for us by Ruby. attr = $1.to_sym raise ArgumentError, "Attribute '#{attr}' is protected" if @protected_attrs.include? attr self[attr] = args[0] when /\A#{ATTR_REGEXP}\z/ # Case "r.attr". if @strict _smart_hash_fetch(method_name) else self[method_name] end else super end end |
Instance Attribute Details
- (Object) declared_attrs (readonly)
See #declare.
78 79 80 |
# File 'lib/smart_hash.rb', line 78 def declared_attrs @declared_attrs end |
- (Object) protected_attrs (readonly)
See #protect.
81 82 83 |
# File 'lib/smart_hash.rb', line 81 def protected_attrs @protected_attrs end |
- (Object) strict
Strict mode. Default is true.
84 85 86 |
# File 'lib/smart_hash.rb', line 84 def strict @strict end |
Class Method Details
+ (Object) [](*args)
Alternative constructor.
h = SmartHash[]
94 95 96 97 98 99 100 |
# File 'lib/smart_hash.rb', line 94 def self.[](*args) super.tap do |_| _.instance_eval do _smart_hash_init end end end |
Instance Method Details
- (Object) declare(*attrs)
Declare that specific key(s) are going to be used as attributes. Thus, exception will be raised when trying to access declared attributes if they are not set, even if the corresponding method exists in Hash class.
r.declare(:size)
r.size # `KeyError` or `IndexError` will be raised.
r.declare(:count, :size) # Declare more than one attribute at once.
110 111 112 113 114 115 116 117 |
# File 'lib/smart_hash.rb', line 110 def declare(*attrs) raise ArgumentError, "No attrs specified" if attrs.empty? attrs.each do |attr| (v = attr).is_a?(klass = Symbol) 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 |
- (Object) protect(*attrs)
Protect attributes against assignment.
r.protect(:size)
r.size = 1 # Exception.
123 124 125 126 127 128 129 130 |
# File 'lib/smart_hash.rb', line 123 def protect(*attrs) raise ArgumentError, "No attrs specified" if attrs.empty? attrs.each do |attr| (v = attr).is_a?(klass = Symbol) 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 |
- (Object) undeclare(*attrs)
132 133 134 135 136 137 |
# File 'lib/smart_hash.rb', line 132 def undeclare(*attrs) raise ArgumentError, "No attrs specified" if attrs.empty? attrs.each do |attr| @declared_attrs.delete(attr) # `Set` is returned. end end |
- (Object) unprotect(*attrs)
139 140 141 142 143 144 |
# File 'lib/smart_hash.rb', line 139 def unprotect(*attrs) raise ArgumentError, "No attrs specified" if attrs.empty? attrs.each do |attr| @protected_attrs.delete(attr) end end |