hashie 2.0.5 → 2.1.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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +36 -0
  3. data/.travis.yml +13 -6
  4. data/CHANGELOG.md +40 -21
  5. data/CONTRIBUTING.md +110 -19
  6. data/Gemfile +9 -0
  7. data/LICENSE +1 -1
  8. data/README.md +347 -0
  9. data/Rakefile +4 -2
  10. data/hashie.gemspec +4 -7
  11. data/lib/hashie.rb +3 -0
  12. data/lib/hashie/clash.rb +19 -19
  13. data/lib/hashie/dash.rb +47 -39
  14. data/lib/hashie/extensions/coercion.rb +10 -6
  15. data/lib/hashie/extensions/deep_fetch.rb +29 -0
  16. data/lib/hashie/extensions/deep_merge.rb +15 -6
  17. data/lib/hashie/extensions/ignore_undeclared.rb +41 -0
  18. data/lib/hashie/extensions/indifferent_access.rb +37 -10
  19. data/lib/hashie/extensions/key_conversion.rb +3 -3
  20. data/lib/hashie/extensions/method_access.rb +9 -9
  21. data/lib/hashie/hash.rb +7 -7
  22. data/lib/hashie/hash_extensions.rb +5 -7
  23. data/lib/hashie/mash.rb +38 -31
  24. data/lib/hashie/rash.rb +119 -0
  25. data/lib/hashie/trash.rb +31 -22
  26. data/lib/hashie/version.rb +1 -1
  27. data/spec/hashie/clash_spec.rb +43 -45
  28. data/spec/hashie/dash_spec.rb +115 -53
  29. data/spec/hashie/extensions/coercion_spec.rb +42 -37
  30. data/spec/hashie/extensions/deep_fetch_spec.rb +70 -0
  31. data/spec/hashie/extensions/deep_merge_spec.rb +11 -9
  32. data/spec/hashie/extensions/ignore_undeclared_spec.rb +23 -0
  33. data/spec/hashie/extensions/indifferent_access_spec.rb +117 -64
  34. data/spec/hashie/extensions/key_conversion_spec.rb +28 -27
  35. data/spec/hashie/extensions/merge_initializer_spec.rb +13 -10
  36. data/spec/hashie/extensions/method_access_spec.rb +49 -40
  37. data/spec/hashie/hash_spec.rb +25 -13
  38. data/spec/hashie/mash_spec.rb +243 -187
  39. data/spec/hashie/rash_spec.rb +44 -0
  40. data/spec/hashie/trash_spec.rb +81 -43
  41. data/spec/hashie/version_spec.rb +7 -0
  42. data/spec/spec_helper.rb +0 -4
  43. metadata +27 -78
  44. data/.document +0 -5
  45. data/README.markdown +0 -236
  46. data/lib/hashie/extensions/structure.rb +0 -47
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
@@ -1,236 +0,0 @@
1
- # Hashie [![Build Status](https://secure.travis-ci.org/intridea/hashie.png)](http://travis-ci.org/intridea/hashie) [![Dependency Status](https://gemnasium.com/intridea/hashie.png)](https://gemnasium.com/intridea/hashie)
2
-
3
- Hashie is a growing collection of tools that extend Hashes and make
4
- them more useful.
5
-
6
- ## Installation
7
-
8
- Hashie is available as a RubyGem:
9
-
10
- gem install hashie
11
-
12
- ## Hash Extensions
13
-
14
- The library is broken up into a number of atomically includeable Hash
15
- extension modules as described below. This provides maximum flexibility
16
- for users to mix and match functionality while maintaining feature parity
17
- with earlier versions of Hashie.
18
-
19
- Any of the extensions listed below can be mixed into a class by
20
- `include`-ing `Hashie::Extensions::ExtensionName`.
21
-
22
- ### Coercion
23
-
24
- Coercions allow you to set up "coercion rules" based either on the key
25
- or the value type to massage data as it's being inserted into the Hash.
26
- Key coercions might be used, for example, in lightweight data modeling
27
- applications such as an API client:
28
-
29
- class Tweet < Hash
30
- include Hashie::Extensions::Coercion
31
- coerce_key :user, User
32
- end
33
-
34
- user_hash = {:name => "Bob"}
35
- Tweet.new(:user => user_hash)
36
- # => automatically calls User.coerce(user_hash) or
37
- # User.new(user_hash) if that isn't present.
38
-
39
- Value coercions, on the other hand, will coerce values based on the type
40
- of the value being inserted. This is useful if you are trying to build a
41
- Hash-like class that is self-propagating.
42
-
43
- class SpecialHash < Hash
44
- include Hashie::Extensions::Coercion
45
- coerce_value Hash, SpecialHash
46
-
47
- def initialize(hash = {})
48
- super
49
- hash.each_pair do |k,v|
50
- self[k] = v
51
- end
52
- end
53
- end
54
-
55
- ### KeyConversion
56
-
57
- The KeyConversion extension gives you the convenience methods of
58
- `symbolize_keys` and `stringify_keys` along with their bang
59
- counterparts. You can also include just stringify or just symbolize with
60
- `Hashie::Extensions::StringifyKeys` or `Hashie::Extensions::SymbolizeKeys`.
61
-
62
- ### MergeInitializer
63
-
64
- The MergeInitializer extension simply makes it possible to initialize a
65
- Hash subclass with another Hash, giving you a quick short-hand.
66
-
67
- ### MethodAccess
68
-
69
- The MethodAccess extension allows you to quickly build method-based
70
- reading, writing, and querying into your Hash descendant. It can also be
71
- included as individual modules, i.e. `Hashie::Extensions::MethodReader`,
72
- `Hashie::Extensions::MethodWriter` and `Hashie::Extensions::MethodQuery`
73
-
74
- class MyHash < Hash
75
- include Hashie::Extensions::MethodAccess
76
- end
77
-
78
- h = MyHash.new
79
- h.abc = 'def'
80
- h.abc # => 'def'
81
- h.abc? # => true
82
-
83
- ### IndifferentAccess
84
-
85
- This extension can be mixed in to instantly give you indifferent access
86
- to your Hash subclass. This works just like the params hash in Rails and
87
- other frameworks where whether you provide symbols or strings to access
88
- keys, you will get the same results.
89
-
90
- A unique feature of Hashie's IndifferentAccess mixin is that it will
91
- inject itself recursively into subhashes *without* reinitializing the
92
- hash in question. This means you can safely merge together indifferent
93
- and non-indifferent hashes arbitrarily deeply without worrying about
94
- whether you'll be able to `hash[:other][:another]` properly.
95
-
96
- ### DeepMerge
97
-
98
- This extension allow you to easily include a recursive merging
99
- system to any Hash descendant:
100
-
101
- class MyHash < Hash
102
- include Hashie::Extensions::DeepMerge
103
- end
104
-
105
- h1 = MyHash.new
106
- h2 = MyHash.new
107
-
108
- h1 = {:x => {:y => [4,5,6]}, :z => [7,8,9]}
109
- h2 = {:x => {:y => [7,8,9]}, :z => "xyz"}
110
-
111
- h1.deep_merge(h2) #=> { :x => {:y => [7, 8, 9]}, :z => "xyz" }
112
- h2.deep_merge(h1) #=> { :x => {:y => [4, 5, 6]}, :z => [7, 8, 9] }
113
-
114
- ## Mash
115
-
116
- Mash is an extended Hash that gives simple pseudo-object functionality
117
- that can be built from hashes and easily extended. It is designed to
118
- be used in RESTful API libraries to provide easy object-like access
119
- to JSON and XML parsed hashes.
120
-
121
- ### Example:
122
-
123
- mash = Hashie::Mash.new
124
- mash.name? # => false
125
- mash.name # => nil
126
- mash.name = "My Mash"
127
- mash.name # => "My Mash"
128
- mash.name? # => true
129
- mash.inspect # => <Hashie::Mash name="My Mash">
130
-
131
- mash = Mash.new
132
- # use bang methods for multi-level assignment
133
- mash.author!.name = "Michael Bleigh"
134
- mash.author # => <Hashie::Mash name="Michael Bleigh">
135
-
136
- mash = Mash.new
137
- # use under-bang methods for multi-level testing
138
- mash.author_.name? # => false
139
- mash.inspect # => <Hashie::Mash>
140
-
141
- **Note:** The `?` method will return false if a key has been set
142
- to false or nil. In order to check if a key has been set at all, use the
143
- `mash.key?('some_key')` method instead.
144
-
145
- ## Dash
146
-
147
- Dash is an extended Hash that has a discrete set of defined properties
148
- and only those properties may be set on the hash. Additionally, you
149
- can set defaults for each property. You can also flag a property as
150
- required. Required properties will raise an exception if unset.
151
-
152
- ### Example:
153
-
154
- class Person < Hashie::Dash
155
- property :name, :required => true
156
- property :email
157
- property :occupation, :default => 'Rubyist'
158
- end
159
-
160
- p = Person.new # => ArgumentError: The property 'name' is required for this Dash.
161
-
162
- p = Person.new(:name => "Bob")
163
- p.name # => 'Bob'
164
- p.name = nil # => ArgumentError: The property 'name' is required for this Dash.
165
- p.email = 'abc@def.com'
166
- p.occupation # => 'Rubyist'
167
- p.email # => 'abc@def.com'
168
- p[:awesome] # => NoMethodError
169
- p[:occupation] # => 'Rubyist'
170
-
171
- ## Trash
172
-
173
- A Trash is a Dash that allows you to translate keys on initialization.
174
- It is used like so:
175
-
176
- class Person < Hashie::Trash
177
- property :first_name, :from => :firstName
178
- end
179
-
180
- This will automatically translate the <tt>firstName</tt> key to <tt>first_name</tt>
181
- when it is initialized using a hash such as through:
182
-
183
- Person.new(:firstName => 'Bob')
184
-
185
- Trash also supports translations using lambda, this could be useful when dealing with
186
- external API's. You can use it in this way:
187
-
188
- class Result < Hashie::Trash
189
- property :id, :transform_with => lambda { |v| v.to_i }
190
- property :created_at, :from => :creation_date, :with => lambda { |v| Time.parse(v) }
191
- end
192
-
193
- this will produce the following
194
-
195
- result = Result.new(:id => '123', :creation_date => '2012-03-30 17:23:28')
196
- result.id.class # => Fixnum
197
- result.created_at.class # => Time
198
-
199
- ## Clash
200
-
201
- Clash is a Chainable Lazy Hash that allows you to easily construct
202
- complex hashes using method notation chaining. This will allow you
203
- to use a more action-oriented approach to building options hashes.
204
-
205
- Essentially, a Clash is a generalized way to provide much of the same
206
- kind of "chainability" that libraries like Arel or Rails 2.x's named_scopes
207
- provide.
208
-
209
- ### Example
210
-
211
- c = Hashie::Clash.new
212
- c.where(:abc => 'def').order(:created_at)
213
- c # => {:where => {:abc => 'def'}, :order => :created_at}
214
-
215
- # You can also use bang notation to chain into sub-hashes,
216
- # jumping back up the chain with _end!
217
- c = Hashie::Clash.new
218
- c.where!.abc('def').ghi(123)._end!.order(:created_at)
219
- c # => {:where => {:abc => 'def', :ghi => 123}, :order => :created_at}
220
-
221
- # Multiple hashes are merged automatically
222
- c = Hashie::Clash.new
223
- c.where(:abc => 'def').where(:hgi => 123)
224
- c # => {:where => {:abc => 'def', :hgi => 123}}
225
-
226
- ## Contributing
227
-
228
- See [CONTRIBUTING.md](CONTRIBUTING.md)
229
-
230
- ## Authors
231
-
232
- * Michael Bleigh
233
-
234
- ## Copyright
235
-
236
- Copyright (c) 2009-2013 Intridea, Inc. (http://intridea.com/). See LICENSE for details.
@@ -1,47 +0,0 @@
1
- module Hashie
2
- module Extensions
3
- # The Structure extension provides facilities for declaring
4
- # properties that a Hash can have. This provides for the
5
- # creation of structures that still behave like hashes but
6
- # do not allow setting non-allowed keys.
7
- #
8
- # @example
9
- # class RestrictedHash < Hash
10
- # include Hashie::Extensions::MergeInitializer
11
- # include Hashie::Extensions::Structure
12
- #
13
- # key :first
14
- # key :second, :default => 'foo'
15
- # end
16
- #
17
- # h = RestrictedHash.new(:first => 1)
18
- # h[:first] # => 1
19
- # h[:second] # => 'foo'
20
- # h[:third] # => ArgumentError
21
- #
22
- module Structure
23
- def self.included(base)
24
- base.extend ClassMethods
25
- base.class_eval do
26
- @permitted_keys = superclass.permitted_keys if superclass.respond_to?(:permitted_keys)
27
- end
28
- end
29
-
30
- module ClassMethods
31
- def key(key, options = {})
32
- (@permitted_keys ||= []) << key
33
-
34
- if options[:default]
35
- (@default_values ||= {})[key] = options.delete(:default)
36
- end
37
-
38
- permitted_keys
39
- end
40
-
41
- def permitted_keys
42
- @permitted_keys
43
- end
44
- end
45
- end
46
- end
47
- end