hashie 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +16 -0
- data/CONTRIBUTING.md +27 -0
- data/Guardfile +1 -1
- data/README.markdown +240 -0
- data/VERSION +1 -0
- data/hashie.gemspec +4 -2
- data/lib/hashie.rb +20 -6
- data/lib/hashie/dash.rb +21 -8
- data/lib/hashie/extensions/coercion.rb +105 -0
- data/lib/hashie/extensions/deep_merge.rb +21 -0
- data/lib/hashie/extensions/indifferent_access.rb +114 -0
- data/lib/hashie/extensions/key_conversion.rb +92 -0
- data/lib/hashie/extensions/merge_initializer.rb +26 -0
- data/lib/hashie/extensions/method_access.rb +124 -0
- data/lib/hashie/extensions/structure.rb +47 -0
- data/lib/hashie/hash.rb +12 -6
- data/lib/hashie/mash.rb +48 -17
- data/lib/hashie/trash.rb +41 -5
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/dash_spec.rb +25 -0
- data/spec/hashie/extensions/coercion_spec.rb +89 -0
- data/spec/hashie/extensions/deep_merge_spec.rb +20 -0
- data/spec/hashie/extensions/indifferent_access_spec.rb +74 -0
- data/spec/hashie/extensions/key_conversion_spec.rb +102 -0
- data/spec/hashie/extensions/merge_initializer_spec.rb +20 -0
- data/spec/hashie/extensions/method_access_spec.rb +112 -0
- data/spec/hashie/hash_spec.rb +2 -12
- data/spec/hashie/mash_spec.rb +105 -17
- data/spec/hashie/trash_spec.rb +75 -0
- metadata +72 -24
- data/Gemfile.lock +0 -34
- data/README.rdoc +0 -120
data/.gitignore
CHANGED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-m markdown
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
## 2.0.0
|
4
|
+
|
5
|
+
* update gemspec with license info jordimassaguerpla #72
|
6
|
+
* fix readme typo jcamenisch #71
|
7
|
+
* initialize with merge coerces values mattfawcett #27
|
8
|
+
* Hashie::Extensions::Coercion coerce_keys takes arguments mattfawcett #28
|
9
|
+
* Trash removes translated values on initialization sleverbor #39
|
10
|
+
* Mash#fetch works with symbol or string keys arthwood #66
|
11
|
+
* Hashie::Hash inherits from ::Hash to avoid ambiguity meh, orend #49
|
12
|
+
* update respond_to? method signature to match ruby core definition dlupu #62
|
13
|
+
* DeepMerge extension nashby #41
|
14
|
+
* Dash defaults are dup'ed before assigned ohrite #63
|
15
|
+
* remove id, type, and object_id as special allowable keys jch #77
|
16
|
+
* merge and update accepts a block jch #78
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
## Note on Patches/Pull Requests
|
2
|
+
|
3
|
+
Thanks for taking the time to contribute back! To make it easier for us to
|
4
|
+
review your changes, try to follow these guidelines:
|
5
|
+
|
6
|
+
* Keep changesets small and on topic. Itching to refactor or clean something
|
7
|
+
up? Do it in a separate branch.
|
8
|
+
* Stay consistent with existing code conventions.
|
9
|
+
* Break changes into smaller logical commits.
|
10
|
+
|
11
|
+
To propose a change:
|
12
|
+
|
13
|
+
* [Fork the project.](https://help.github.com/articles/fork-a-repo)
|
14
|
+
* Make your feature addition or bug fix.
|
15
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
16
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
17
|
+
* [Send me a pull request](https://help.github.com/articles/using-pull-requests). Bonus points for topic branches.
|
18
|
+
* [Check that your pull request passes the build](https://travis-ci.org/intridea/hashie/pull_requests).
|
19
|
+
|
20
|
+
## Bug triage
|
21
|
+
|
22
|
+
Have a problem? File an [issue here](https://github.com/intridea/hashie/issues).
|
23
|
+
|
24
|
+
To make bug squashing easier, include the following in your issue:
|
25
|
+
|
26
|
+
* What version of hashie are you using?
|
27
|
+
* Is it still a problem in master?
|
data/Guardfile
CHANGED
data/README.markdown
ADDED
@@ -0,0 +1,240 @@
|
|
1
|
+
**Note:** This documentation is for the unreleased version 2.0 of
|
2
|
+
Hashie. See the [1-1-stable branch](https://github.com/intridea/hashie/tree/1-1-stable) for documentation of the released version.
|
3
|
+
|
4
|
+
# Hashie [](http://travis-ci.org/intridea/hashie) [](https://gemnasium.com/intridea/hashie)
|
5
|
+
|
6
|
+
Hashie is a growing collection of tools that extend Hashes and make
|
7
|
+
them more useful.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Hashie is available as a RubyGem:
|
12
|
+
|
13
|
+
gem install hashie
|
14
|
+
|
15
|
+
## Hash Extensions
|
16
|
+
|
17
|
+
New to version 2.0 of Hashie, the library has been broken up into a
|
18
|
+
number of atomically includeable Hash extension modules as described
|
19
|
+
below. This provides maximum flexibility for users to mix and match
|
20
|
+
functionality while maintaining feature parity with earlier versions of
|
21
|
+
Hashie.
|
22
|
+
|
23
|
+
Any of the extensions listed below can be mixed into a class by
|
24
|
+
`include`-ing `Hashie::Extensions::ExtensionName`.
|
25
|
+
|
26
|
+
### Coercion
|
27
|
+
|
28
|
+
Coercions allow you to set up "coercion rules" based either on the key
|
29
|
+
or the value type to massage data as it's being inserted into the Hash.
|
30
|
+
Key coercions might be used, for example, in lightweight data modeling
|
31
|
+
applications such as an API client:
|
32
|
+
|
33
|
+
class Tweet < Hash
|
34
|
+
include Hashie::Extensions::Coercion
|
35
|
+
coerce_key :user, User
|
36
|
+
end
|
37
|
+
|
38
|
+
user_hash = {:name => "Bob"}
|
39
|
+
Tweet.new(:user => user_hash)
|
40
|
+
# => automatically calls User.coerce(user_hash) or
|
41
|
+
# User.new(user_hash) if that isn't present.
|
42
|
+
|
43
|
+
Value coercions, on the other hand, will coerce values based on the type
|
44
|
+
of the value being inserted. This is useful if you are trying to build a
|
45
|
+
Hash-like class that is self-propagating.
|
46
|
+
|
47
|
+
class SpecialHash < Hash
|
48
|
+
include Hashie::Extensions::Coercion
|
49
|
+
coerce_value Hash, SpecialHash
|
50
|
+
|
51
|
+
def initialize(hash = {})
|
52
|
+
super
|
53
|
+
hash.each_pair do |k,v|
|
54
|
+
self[k] = v
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
### KeyConversion
|
60
|
+
|
61
|
+
The KeyConversion extension gives you the convenience methods of
|
62
|
+
`symbolize_keys` and `stringify_keys` along with their bang
|
63
|
+
counterparts. You can also include just stringify or just symbolize with
|
64
|
+
`Hashie::Extensions::StringifyKeys` or `Hashie::Extensions::SymbolizeKeys`.
|
65
|
+
|
66
|
+
### MergeInitializer
|
67
|
+
|
68
|
+
The MergeInitializer extension simply makes it possible to initialize a
|
69
|
+
Hash subclass with another Hash, giving you a quick short-hand.
|
70
|
+
|
71
|
+
### MethodAccess
|
72
|
+
|
73
|
+
The MethodAccess extension allows you to quickly build method-based
|
74
|
+
reading, writing, and querying into your Hash descendant. It can also be
|
75
|
+
included as individual modules, i.e. `Hashie::Extensions::MethodReader`,
|
76
|
+
`Hashie::Extensions::MethodWriter` and `Hashie::Extensions::MethodQuery`
|
77
|
+
|
78
|
+
class MyHash < Hash
|
79
|
+
include Hashie::Extensions::MethodAccess
|
80
|
+
end
|
81
|
+
|
82
|
+
h = MyHash.new
|
83
|
+
h.abc = 'def'
|
84
|
+
h.abc # => 'def'
|
85
|
+
h.abc? # => true
|
86
|
+
|
87
|
+
### IndifferentAccess
|
88
|
+
|
89
|
+
This extension can be mixed in to instantly give you indifferent access
|
90
|
+
to your Hash subclass. This works just like the params hash in Rails and
|
91
|
+
other frameworks where whether you provide symbols or strings to access
|
92
|
+
keys, you will get the same results.
|
93
|
+
|
94
|
+
A unique feature of Hashie's IndifferentAccess mixin is that it will
|
95
|
+
inject itself recursively into subhashes *without* reinitializing the
|
96
|
+
hash in question. This means you can safely merge together indifferent
|
97
|
+
and non-indifferent hashes arbitrarily deeply without worrying about
|
98
|
+
whether you'll be able to `hash[:other][:another]` properly.
|
99
|
+
|
100
|
+
### DeepMerge
|
101
|
+
|
102
|
+
This extension allow you to easily include a recursive merging
|
103
|
+
system to any Hash descendant:
|
104
|
+
|
105
|
+
class MyHash < Hash
|
106
|
+
include Hashie::Extensions::DeepMerge
|
107
|
+
end
|
108
|
+
|
109
|
+
h1 = MyHash.new
|
110
|
+
h2 = MyHash.new
|
111
|
+
|
112
|
+
h1 = {:x => {:y => [4,5,6]}, :z => [7,8,9]}
|
113
|
+
h2 = {:x => {:y => [7,8,9]}, :z => "xyz"}
|
114
|
+
|
115
|
+
h1.deep_merge(h2) #=> { :x => {:y => [7, 8, 9]}, :z => "xyz" }
|
116
|
+
h2.deep_merge(h1) #=> { :x => {:y => [4, 5, 6]}, :z => [7, 8, 9] }
|
117
|
+
|
118
|
+
## Mash
|
119
|
+
|
120
|
+
Mash is an extended Hash that gives simple pseudo-object functionality
|
121
|
+
that can be built from hashes and easily extended. It is designed to
|
122
|
+
be used in RESTful API libraries to provide easy object-like access
|
123
|
+
to JSON and XML parsed hashes.
|
124
|
+
|
125
|
+
### Example:
|
126
|
+
|
127
|
+
mash = Hashie::Mash.new
|
128
|
+
mash.name? # => false
|
129
|
+
mash.name # => nil
|
130
|
+
mash.name = "My Mash"
|
131
|
+
mash.name # => "My Mash"
|
132
|
+
mash.name? # => true
|
133
|
+
mash.inspect # => <Hashie::Mash name="My Mash">
|
134
|
+
|
135
|
+
mash = Mash.new
|
136
|
+
# use bang methods for multi-level assignment
|
137
|
+
mash.author!.name = "Michael Bleigh"
|
138
|
+
mash.author # => <Hashie::Mash name="Michael Bleigh">
|
139
|
+
|
140
|
+
mash = Mash.new
|
141
|
+
# use under-bang methods for multi-level testing
|
142
|
+
mash.author_.name? # => false
|
143
|
+
mash.inspect # => <Hashie::Mash>
|
144
|
+
|
145
|
+
**Note:** The `?` method will return false if a key has been set
|
146
|
+
to false or nil. In order to check if a key has been set at all, use the
|
147
|
+
`mash.key?('some_key')` method instead.
|
148
|
+
|
149
|
+
## Dash
|
150
|
+
|
151
|
+
Dash is an extended Hash that has a discrete set of defined properties
|
152
|
+
and only those properties may be set on the hash. Additionally, you
|
153
|
+
can set defaults for each property. You can also flag a property as
|
154
|
+
required. Required properties will raise an exception if unset.
|
155
|
+
|
156
|
+
### Example:
|
157
|
+
|
158
|
+
class Person < Hashie::Dash
|
159
|
+
property :name, :required => true
|
160
|
+
property :email
|
161
|
+
property :occupation, :default => 'Rubyist'
|
162
|
+
end
|
163
|
+
|
164
|
+
p = Person.new # => ArgumentError: The property 'name' is required for this Dash.
|
165
|
+
|
166
|
+
p = Person.new(:name => "Bob")
|
167
|
+
p.name # => 'Bob'
|
168
|
+
p.name = nil # => ArgumentError: The property 'name' is required for this Dash.
|
169
|
+
p.email = 'abc@def.com'
|
170
|
+
p.occupation # => 'Rubyist'
|
171
|
+
p.email # => 'abc@def.com'
|
172
|
+
p[:awesome] # => NoMethodError
|
173
|
+
p[:occupation] # => 'Rubyist'
|
174
|
+
|
175
|
+
## Trash
|
176
|
+
|
177
|
+
A Trash is a Dash that allows you to translate keys on initialization.
|
178
|
+
It is used like so:
|
179
|
+
|
180
|
+
class Person < Hashie::Trash
|
181
|
+
property :first_name, :from => :firstName
|
182
|
+
end
|
183
|
+
|
184
|
+
This will automatically translate the <tt>firstName</tt> key to <tt>first_name</tt>
|
185
|
+
when it is initialized using a hash such as through:
|
186
|
+
|
187
|
+
Person.new(:firstName => 'Bob')
|
188
|
+
|
189
|
+
Trash also supports translations using lambda, this could be useful when dealing with
|
190
|
+
external API's. You can use it in this way:
|
191
|
+
|
192
|
+
class Result < Hashie::Trash
|
193
|
+
property :id, :transform_with => lambda { |v| v.to_i }
|
194
|
+
property :created_at, :from => :creation_date, :with => lambda { |v| Time.parse(v) }
|
195
|
+
end
|
196
|
+
|
197
|
+
this will produce the following
|
198
|
+
|
199
|
+
result = Result.new(:id => '123', :creation_date => '2012-03-30 17:23:28')
|
200
|
+
result.id.class # => Fixnum
|
201
|
+
result.created_at.class # => Time
|
202
|
+
|
203
|
+
## Clash
|
204
|
+
|
205
|
+
Clash is a Chainable Lazy Hash that allows you to easily construct
|
206
|
+
complex hashes using method notation chaining. This will allow you
|
207
|
+
to use a more action-oriented approach to building options hashes.
|
208
|
+
|
209
|
+
Essentially, a Clash is a generalized way to provide much of the same
|
210
|
+
kind of "chainability" that libraries like Arel or Rails 2.x's named_scopes
|
211
|
+
provide.
|
212
|
+
|
213
|
+
### Example
|
214
|
+
|
215
|
+
c = Hashie::Clash.new
|
216
|
+
c.where(:abc => 'def').order(:created_at)
|
217
|
+
c # => {:where => {:abc => 'def'}, :order => :created_at}
|
218
|
+
|
219
|
+
# You can also use bang notation to chain into sub-hashes,
|
220
|
+
# jumping back up the chain with _end!
|
221
|
+
c = Hashie::Clash.new
|
222
|
+
c.where!.abc('def').ghi(123)._end!.order(:created_at)
|
223
|
+
c # => {:where => {:abc => 'def', :ghi => 123}, :order => :created_at}
|
224
|
+
|
225
|
+
# Multiple hashes are merged automatically
|
226
|
+
c = Hashie::Clash.new
|
227
|
+
c.where(:abc => 'def').where(:hgi => 123)
|
228
|
+
c # => {:where => {:abc => 'def', :hgi => 123}}
|
229
|
+
|
230
|
+
## Contributing
|
231
|
+
|
232
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
233
|
+
|
234
|
+
## Authors
|
235
|
+
|
236
|
+
* Michael Bleigh
|
237
|
+
|
238
|
+
## Copyright
|
239
|
+
|
240
|
+
Copyright (c) 2009-2011 Intridea, Inc. (http://intridea.com/). See LICENSE for details.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/hashie.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require File.expand_path('../lib/hashie/version', __FILE__)
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
|
-
gem.authors = ["Michael Bleigh"]
|
5
|
-
gem.email = ["michael@intridea.com"]
|
4
|
+
gem.authors = ["Michael Bleigh", "Jerry Cheung"]
|
5
|
+
gem.email = ["michael@intridea.com", "jollyjerry@gmail.com"]
|
6
6
|
gem.description = %q{Hashie is a small collection of tools that make hashes more powerful. Currently includes Mash (Mocking Hash) and Dash (Discrete Hash).}
|
7
7
|
gem.summary = %q{Your friendly neighborhood hash toolkit.}
|
8
8
|
gem.homepage = 'https://github.com/intridea/hashie'
|
@@ -13,9 +13,11 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.name = "hashie"
|
14
14
|
gem.require_paths = ['lib']
|
15
15
|
gem.version = Hashie::VERSION
|
16
|
+
gem.license = "MIT"
|
16
17
|
|
17
18
|
gem.add_development_dependency 'rake', '~> 0.9.2'
|
18
19
|
gem.add_development_dependency 'rspec', '~> 2.5'
|
19
20
|
gem.add_development_dependency 'guard'
|
20
21
|
gem.add_development_dependency 'guard-rspec'
|
22
|
+
gem.add_development_dependency 'growl'
|
21
23
|
end
|
data/lib/hashie.rb
CHANGED
@@ -1,9 +1,23 @@
|
|
1
1
|
module Hashie
|
2
|
+
autoload :Clash, 'hashie/clash'
|
3
|
+
autoload :Dash, 'hashie/dash'
|
4
|
+
autoload :Hash, 'hashie/hash'
|
2
5
|
autoload :HashExtensions, 'hashie/hash_extensions'
|
3
|
-
autoload :
|
4
|
-
autoload :
|
5
|
-
autoload :Trash,
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
autoload :Mash, 'hashie/mash'
|
7
|
+
autoload :PrettyInspect, 'hashie/hash_extensions'
|
8
|
+
autoload :Trash, 'hashie/trash'
|
9
|
+
|
10
|
+
module Extensions
|
11
|
+
autoload :Coercion, 'hashie/extensions/coercion'
|
12
|
+
autoload :DeepMerge, 'hashie/extensions/deep_merge'
|
13
|
+
autoload :KeyConversion, 'hashie/extensions/key_conversion'
|
14
|
+
autoload :IndifferentAccess, 'hashie/extensions/indifferent_access'
|
15
|
+
autoload :MergeInitializer, 'hashie/extensions/merge_initializer'
|
16
|
+
autoload :MethodAccess, 'hashie/extensions/method_access'
|
17
|
+
autoload :MethodQuery, 'hashie/extensions/method_access'
|
18
|
+
autoload :MethodReader, 'hashie/extensions/method_access'
|
19
|
+
autoload :MethodWriter, 'hashie/extensions/method_access'
|
20
|
+
autoload :StringifyKeys, 'hashie/extensions/key_conversion'
|
21
|
+
autoload :SymbolizeKeys, 'hashie/extensions/key_conversion'
|
22
|
+
end
|
9
23
|
end
|
data/lib/hashie/dash.rb
CHANGED
@@ -12,8 +12,8 @@ module Hashie
|
|
12
12
|
#
|
13
13
|
# It is preferrable to a Struct because of the in-class
|
14
14
|
# API for defining properties as well as per-property defaults.
|
15
|
-
class Dash <
|
16
|
-
include
|
15
|
+
class Dash < Hash
|
16
|
+
include PrettyInspect
|
17
17
|
alias_method :to_s, :inspect
|
18
18
|
|
19
19
|
# Defines a property on the Dash. Options are
|
@@ -90,12 +90,14 @@ module Hashie
|
|
90
90
|
super(&block)
|
91
91
|
|
92
92
|
self.class.defaults.each_pair do |prop, value|
|
93
|
-
self[prop] =
|
93
|
+
self[prop] = begin
|
94
|
+
value.dup
|
95
|
+
rescue TypeError
|
96
|
+
value
|
97
|
+
end
|
94
98
|
end
|
95
99
|
|
96
|
-
attributes
|
97
|
-
self[att] = value
|
98
|
-
end if attributes
|
100
|
+
initialize_attributes(attributes)
|
99
101
|
assert_required_properties_set!
|
100
102
|
end
|
101
103
|
|
@@ -108,8 +110,13 @@ module Hashie
|
|
108
110
|
def [](property)
|
109
111
|
assert_property_exists! property
|
110
112
|
value = super(property.to_s)
|
111
|
-
|
112
|
-
value
|
113
|
+
# If the value is a lambda, proc, or whatever answers to call, eval the thing!
|
114
|
+
if value.is_a? Proc
|
115
|
+
self[property] = value.call # Set the result of the call as a value
|
116
|
+
else
|
117
|
+
yield value if block_given?
|
118
|
+
value
|
119
|
+
end
|
113
120
|
end
|
114
121
|
|
115
122
|
# Set a value on the Dash in a Hash-like way. Only works
|
@@ -122,6 +129,12 @@ module Hashie
|
|
122
129
|
|
123
130
|
private
|
124
131
|
|
132
|
+
def initialize_attributes(attributes)
|
133
|
+
attributes.each_pair do |att, value|
|
134
|
+
self[att] = value
|
135
|
+
end if attributes
|
136
|
+
end
|
137
|
+
|
125
138
|
def assert_property_exists!(property)
|
126
139
|
unless self.class.property?(property)
|
127
140
|
raise NoMethodError, "The property '#{property}' is not defined for this Dash."
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
module Coercion
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
base.send :include, InstanceMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
def []=(key, value)
|
11
|
+
into = self.class.key_coercion(key) || self.class.value_coercion(value)
|
12
|
+
|
13
|
+
if value && into
|
14
|
+
if into.respond_to?(:coerce)
|
15
|
+
value = into.coerce(value)
|
16
|
+
else
|
17
|
+
value = into.new(value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
super(key, value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
# Set up a coercion rule such that any time the specified
|
27
|
+
# key is set it will be coerced into the specified class.
|
28
|
+
# Coercion will occur by first attempting to call Class.coerce
|
29
|
+
# and then by calling Class.new with the value as an argument
|
30
|
+
# in either case.
|
31
|
+
#
|
32
|
+
# @param [Object] key the key or array of keys you would like to be coerced.
|
33
|
+
# @param [Class] into the class into which you want the key(s) coerced.
|
34
|
+
#
|
35
|
+
# @example Coerce a "user" subhash into a User object
|
36
|
+
# class Tweet < Hash
|
37
|
+
# include Hashie::Extensions::Coercion
|
38
|
+
# coerce_key :user, User
|
39
|
+
# end
|
40
|
+
def coerce_key(*attrs)
|
41
|
+
@key_coercions ||= {}
|
42
|
+
into = attrs.pop
|
43
|
+
attrs.each { |key| @key_coercions[key] = into }
|
44
|
+
end
|
45
|
+
|
46
|
+
alias :coerce_keys :coerce_key
|
47
|
+
|
48
|
+
# Returns a hash of any existing key coercions.
|
49
|
+
def key_coercions
|
50
|
+
@key_coercions || {}
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the specific key coercion for the specified key,
|
54
|
+
# if one exists.
|
55
|
+
def key_coercion(key)
|
56
|
+
key_coercions[key]
|
57
|
+
end
|
58
|
+
|
59
|
+
# Set up a coercion rule such that any time a value of the
|
60
|
+
# specified type is set it will be coerced into the specified
|
61
|
+
# class.
|
62
|
+
#
|
63
|
+
# @param [Class] from the type you would like coerced.
|
64
|
+
# @param [Class] into the class into which you would like the value coerced.
|
65
|
+
# @option options [Boolean] :strict (true) whether use exact source class only or include ancestors
|
66
|
+
#
|
67
|
+
# @example Coerce all hashes into this special type of hash
|
68
|
+
# class SpecialHash < Hash
|
69
|
+
# include Hashie::Extensions::Coercion
|
70
|
+
# coerce_value Hash, SpecialHash
|
71
|
+
#
|
72
|
+
# def initialize(hash = {})
|
73
|
+
# super
|
74
|
+
# hash.each_pair do |k,v|
|
75
|
+
# self[k] = v
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
def coerce_value(from, into, options = {})
|
80
|
+
options = {:strict => true}.merge(options)
|
81
|
+
|
82
|
+
if options[:strict]
|
83
|
+
(@strict_value_coercions ||= {})[from] = into
|
84
|
+
else
|
85
|
+
while from.superclass && from.superclass != Object
|
86
|
+
(@lenient_value_coercions ||= {})[from] = into
|
87
|
+
from = from.superclass
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Return all value coercions that have the :strict rule as true.
|
93
|
+
def strict_value_coercions; @strict_value_coercions || {} end
|
94
|
+
# Return all value coercions that have the :strict rule as false.
|
95
|
+
def lenient_value_coercions; @value_coercions || {} end
|
96
|
+
|
97
|
+
# Fetch the value coercion, if any, for the specified object.
|
98
|
+
def value_coercion(value)
|
99
|
+
from = value.class
|
100
|
+
strict_value_coercions[from] || lenient_value_coercions[from]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|