hashie 2.0.5 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1fd1f73bdb3a592938fb9e274e7306c16c2410b8
4
+ data.tar.gz: 545f19b3a9989433f31c047af0fdf477789f8d10
5
+ SHA512:
6
+ metadata.gz: 4a96ffb374b4560d0276412d43ceaa5717aa963e5c8e596343c6cf484081cc2f1b49b7725b97eb9c64baf33631e96f8ccecc1ee95dc470c2fe677334f3c38a45
7
+ data.tar.gz: e67465dc21d6a9eef56e3eb7b603d41471a926c42e2a4f687d4e2c4ead92522e04dc03408b6854f7d594b7a9510d517d432208e94287a1f77c13008d4a5a40f8
@@ -0,0 +1,36 @@
1
+ AllCops:
2
+ Exclude:
3
+ - vendor/**
4
+ - bin/**
5
+ - .bundle/**
6
+
7
+ LineLength:
8
+ Enabled: false
9
+
10
+ MethodLength:
11
+ Enabled: false
12
+
13
+ ClassLength:
14
+ Enabled: false
15
+
16
+ Documentation:
17
+ # don't require classes to be documented
18
+ Enabled: false
19
+
20
+ Encoding:
21
+ # no need to always specify encoding
22
+ Enabled: false
23
+
24
+ Lambda:
25
+ # TODO: replace all lambda with -> or Proc
26
+ Enabled: false
27
+
28
+ CyclomaticComplexity:
29
+ Enabled: false
30
+
31
+ DoubleNegation:
32
+ Enabled: false
33
+
34
+ CaseEquality:
35
+ Enabled: false
36
+
@@ -1,8 +1,15 @@
1
+ language: ruby
1
2
  rvm:
2
- - 2.0.0
3
- - 1.8.7
4
- - 1.9.2
5
- - rbx
6
- - ree
7
3
  - ruby-head
8
- - jruby
4
+ - 2.1.1
5
+ - 2.1.0
6
+ - 2.0.0
7
+ - 1.9.3
8
+ - jruby-19mode
9
+ - jruby-head
10
+ - rbx-2.1
11
+ - rbx-2.2
12
+ matrix:
13
+ allow_failures:
14
+ - rvm: ruby-head
15
+ - rvm: jruby-head
@@ -1,39 +1,58 @@
1
- # CHANGELOG
1
+ ## Next Release
2
+
3
+ * [#134](https://github.com/intridea/hashie/pull/134): Add deep_fetch extension for nested access - [@tylerdooling](https://github.com/tylerdooling).
4
+ * Removed support for Ruby 1.8.7 - [@dblock](https://github.com/dblock).
5
+ * Ruby style now enforced with Rubocop - [@dblock](https://github.com/dblock).
6
+ * [#138](https://github.com/intridea/hashie/pull/138): Added Hashie#Rash, a hash whose keys can be regular expressions or ranges - [@epitron](https://github.com/epitron).
7
+ * [#131](https://github.com/intridea/hashie/pull/131): Added IgnoreUndeclared, an extension to silently ignore undeclared properties at intialization - [@righi](https://github.com/righi).
8
+ * [#136](https://github.com/intridea/hashie/issues/136): Removed Hashie::Extensions::Structure - [@markiz](https://github.com/markiz).
9
+ * [#107](https://github.com/intridea/hashie/pull/107): Fixed excessive value conversions, poor performance of deep merge in Hashie::Mash - [@davemitchell](https://github.com/dblock), [@dblock](https://github.com/dblock).
10
+ * [#69](https://github.com/intridea/hashie/issues/69): Fixed assigning multiple properties in Hashie::Trash - [@einzige](https://github.com/einzige).
11
+ * [#100](https://github.com/intridea/hashie/pull/100): IndifferentAccess#store will respect indifference - [@jrochkind](https://github.com/jrochkind).
12
+ * [#103](https://github.com/intridea/hashie/pull/103): Fixed support for Hashie::Dash properties that end in bang - [@thedavemarshall](https://github.com/thedavemarshall).
13
+ * [89](https://github.com/intridea/hashie/issues/89): Do not respond to every method with suffix in Hashie::Mash, fixes Rails strong_parameters - [@Maxim-Filimonov](https://github.com/Maxim-Filimonov).
14
+ * [#110](https://github.com/intridea/hashie/pull/110): Correctly use Hash#default from Mash#method_missing - [@ryansouza](https://github.com/ryansouza).
15
+ * [#120](https://github.com/intridea/hashie/pull/120): Pass options to recursive to_hash calls - [@pwillett](https://github.com/pwillett).
16
+ * [#113](https://github.com/intridea/hashie/issues/113): Fixed Hash#merge with Hashie::Dash - [@spencer1248](https://github.com/spencer1248).
17
+ * [#99](https://github.com/intridea/hashie/issues/99): Hash#deep_merge raises errors when it encounters integers - [@defsprite](https://github.com/defsprite).
18
+ * [#133](https://github.com/intridea/hashie/pull/133): Fixed Hash##to_hash with symbolize_keys - [@mhuggins](https://github.com/mhuggins).
19
+ * [#130](https://github.com/intridea/hashie/pull/130): IndifferentAccess now works without MergeInitializer - [@npj](https://github.com/npj).
20
+ * [#111](https://github.com/intridea/hashie/issues/111): Trash#translations correctly maps original to translated names - [@artm](https://github.com/artm).
21
+ * [#129](https://github.com/intridea/hashie/pull/129): Added Trash#permitted_input_keys and inverse_translations - [@artm](https://github.com/artm).
2
22
 
3
23
  ## 2.0.5
4
24
 
5
- * make coercion work better with non-symbol keys in mash wapcaplet #96
25
+ * [#96](https://github.com/intridea/hashie/pull/96): Make coercion work better with non-symbol keys in Hashie::Mash - [@wapcaplet](https://github.com/wapcaplet).
6
26
 
7
27
  ## 2.0.4
8
28
 
9
- * make #fetch method consistent with normal Hash markiz #94
10
- * various doc tweaks craiglittle #90
29
+ * [#04](https://github.com/intridea/hashie/pull/94): Make #fetch method consistent with normal Hash - [@markiz](https://github.com/markiz).
30
+ * [#90](https://github.com/intridea/hashie/pull/90): Various doc tweaks - [@craiglittle](https://github.com/craiglittle).
11
31
 
12
32
  ## 2.0.3
13
33
 
14
- * Hashie::Mash.new(abc: true).respond_to?(:abc?) works 7even #88
15
- * Fix #replace jimeh #68
34
+ * [#88](https://github.com/intridea/hashie/pull/88): Hashie::Mash.new(abc: true).respond_to?(:abc?) works - [@7even](https://github.com/7even).
35
+ * [#68](https://github.com/intridea/hashie/pull/68): Fix #replace - [@jimeh](https://github.com/jimeh).
16
36
 
17
37
  ## 2.0.2
18
38
 
19
- * adding symbolize_keys back to to_hash cromulus #85
39
+ * [#85](https://github.com/intridea/hashie/pull/85): adding symbolize_keys back to to_hash - [@cromulus](https://github.com/cromulus).
20
40
 
21
41
  ## 2.0.1
22
42
 
23
- * remove Mash#object_id override matschaffer #81
24
- * gem cleanup: remove VERSION, Gemfile.lock jch, mbleigh
43
+ * [#81](https://github.com/intridea/hashie/pull/81): remove Mash#object_id override - [@matschaffer](https://github.com/matschaffer).
44
+ * Gem cleanup: removed VERSION, Gemfile.lock [@jch](https://github.com/jch), [@mbleigh](https://github.com/mbleigh).
25
45
 
26
46
  ## 2.0.0
27
47
 
28
- * update gemspec with license info jordimassaguerpla #72
29
- * fix readme typo jcamenisch #71
30
- * initialize with merge coerces values mattfawcett #27
31
- * Hashie::Extensions::Coercion coerce_keys takes arguments mattfawcett #28
32
- * Trash removes translated values on initialization sleverbor #39
33
- * Mash#fetch works with symbol or string keys arthwood #66
34
- * Hashie::Hash inherits from ::Hash to avoid ambiguity meh, orend #49
35
- * update respond_to? method signature to match ruby core definition dlupu #62
36
- * DeepMerge extension nashby #41
37
- * Dash defaults are dup'ed before assigned ohrite #63
38
- * remove id, type, and object_id as special allowable keys jch #77
39
- * merge and update accepts a block jch #78
48
+ * [#72](https://github.com/intridea/hashie/pull/72): Updated gemspec with license info - [@jordimassaguerpla](https://github.com/jordimassaguerpla).
49
+ * [#27](https://github.com/intridea/hashie/pull/27): Initialized with merge coerces values - [@mattfawcett](https://github.com/mattfawcett).
50
+ * [#28](https://github.com/intridea/hashie/pull/28): Hashie::Extensions::Coercion coerce_keys takes arguments - [@mattfawcett](https://github.com/mattfawcett).
51
+ * [#39](https://github.com/intridea/hashie/pull/39): Trash removes translated values on initialization - [@sleverbor](https://github.com/sleverbor).
52
+ * [#66](https://github.com/intridea/hashie/pull/66): Mash#fetch works with symbol or string keys - [@arthwood](https://github.com/arthwood).
53
+ * [#49](https://github.com/intridea/hashie/pull/49): Hashie::Hash inherits from ::Hash to avoid ambiguity - [@meh](https://github.com/meh), [@orend](https://github.com/orend).
54
+ * [#62](https://github.com/intridea/hashie/pull/62): update respond_to? method signature to match ruby core definition - [@dlupu](https://github.com/dlupu).
55
+ * [#41](https://github.com/intridea/hashie/pull/41): DeepMerge extension - [@nashby](https://github.com/nashby).
56
+ * [#63](https://github.com/intridea/hashie/pull/63): Dash defaults are dup'ed before assigned - [@ohrite](https://github.com/ohrite).
57
+ * [#77](https://github.com/intridea/hashie/pull/77): Remove id, type, and object_id as special allowable keys [@jch](https://github.com/jch).
58
+ * [#78](https://github.com/intridea/hashie/pull/78): Merge and update accepts a block - [@jch](https://github.com/jch).
@@ -1,27 +1,118 @@
1
- ## Note on Patches/Pull Requests
1
+ Contributing to Hashie
2
+ ======================
2
3
 
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:
4
+ Hashie is work of [many contributors](https://github.com/intridea/hashie/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/intridea/hashie/pulls), [propose features and discuss issues](https://github.com/intridea/hashie/issues).
5
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.
6
+ #### Fork the Project
10
7
 
11
- To propose a change:
8
+ Fork the [project on Github](https://github.com/intridea/hashie) and check out your copy.
12
9
 
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).
10
+ ```
11
+ git clone https://github.com/contributor/hashie.git
12
+ cd hashie
13
+ git remote add upstream https://github.com/intridea/hashie.git
14
+ ```
19
15
 
20
- ## Bug triage
16
+ #### Create a Topic Branch
21
17
 
22
- Have a problem? File an [issue here](https://github.com/intridea/hashie/issues).
18
+ Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
23
19
 
24
- To make bug squashing easier, include the following in your issue:
20
+ ```
21
+ git checkout master
22
+ git pull upstream master
23
+ git checkout -b my-feature-branch
24
+ ```
25
25
 
26
- * What version of hashie are you using?
27
- * Is it still a problem in master?
26
+ #### Bundle Install and Test
27
+
28
+ Ensure that you can build the project and run tests.
29
+
30
+ ```
31
+ bundle install
32
+ bundle exec rake
33
+ ```
34
+
35
+ #### Write Tests
36
+
37
+ Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [spec/hashie](spec/hashie).
38
+
39
+ We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
40
+
41
+ #### Write Code
42
+
43
+ Implement your feature or bug fix.
44
+
45
+ Ruby style is enforced with [Rubocop](https://github.com/bbatsov/rubocop), run `bundle exec rubocop` and fix any style issues highlighted.
46
+
47
+ Make sure that `bundle exec rake` completes without errors.
48
+
49
+ #### Write Documentation
50
+
51
+ Document any external behavior in the [README](README.md).
52
+
53
+ #### Update Changelog
54
+
55
+ Add a line to [CHANGELOG](CHANGELOG.md) under *Next Release*. Make it look like every other line, including your name and link to your Github account.
56
+
57
+ #### Commit Changes
58
+
59
+ Make sure git knows your name and email address:
60
+
61
+ ```
62
+ git config --global user.name "Your Name"
63
+ git config --global user.email "contributor@example.com"
64
+ ```
65
+
66
+ Writing good commit logs is important. A commit log should describe what changed and why.
67
+
68
+ ```
69
+ git add ...
70
+ git commit
71
+ ```
72
+
73
+ #### Push
74
+
75
+ ```
76
+ git push origin my-feature-branch
77
+ ```
78
+
79
+ #### Make a Pull Request
80
+
81
+ Go to https://github.com/contributor/hashie and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days.
82
+
83
+ #### Rebase
84
+
85
+ If you've been working on a change for a while, rebase with upstream/master.
86
+
87
+ ```
88
+ git fetch upstream
89
+ git rebase upstream/master
90
+ git push origin my-feature-branch -f
91
+ ```
92
+
93
+ #### Update CHANGELOG Again
94
+
95
+ Update the [CHANGELOG](CHANGELOG.md) with the pull request number. A typical entry looks as follows.
96
+
97
+ ```
98
+ * [#123](https://github.com/intridea/hashie/pull/123): Reticulated splines - [@contributor](https://github.com/contributor).
99
+ ```
100
+
101
+ Amend your previous commit and force push the changes.
102
+
103
+ ```
104
+ git commit --amend
105
+ git push origin my-feature-branch -f
106
+ ```
107
+
108
+ #### Check on Your Pull Request
109
+
110
+ Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
111
+
112
+ #### Be Patient
113
+
114
+ It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there!
115
+
116
+ #### Thank You
117
+
118
+ Please do know that we really appreciate and value your time and work. We love you, really.
data/Gemfile CHANGED
@@ -1,2 +1,11 @@
1
1
  source 'http://rubygems.org'
2
+
3
+ platforms :rbx do
4
+ gem 'rubysl'
5
+ gem 'rubinius-developer_tools'
6
+ gem 'racc'
7
+ end
8
+
2
9
  gemspec
10
+
11
+ gem 'rubocop', '0.20.0'
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Intridea, Inc.
1
+ Copyright (c) 2009 Intridea, Inc., and Contributors
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -0,0 +1,347 @@
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
+ ```bash
11
+ $ gem install hashie
12
+ ```
13
+
14
+ ## Hash Extensions
15
+
16
+ The library is broken up into a number of atomically includeable Hash
17
+ extension modules as described below. This provides maximum flexibility
18
+ for users to mix and match functionality while maintaining feature parity
19
+ with earlier versions of Hashie.
20
+
21
+ Any of the extensions listed below can be mixed into a class by
22
+ `include`-ing `Hashie::Extensions::ExtensionName`.
23
+
24
+ ### Coercion
25
+
26
+ Coercions allow you to set up "coercion rules" based either on the key
27
+ or the value type to massage data as it's being inserted into the Hash.
28
+ Key coercions might be used, for example, in lightweight data modeling
29
+ applications such as an API client:
30
+
31
+ ```ruby
32
+ class Tweet < Hash
33
+ include Hashie::Extensions::Coercion
34
+ coerce_key :user, User
35
+ end
36
+
37
+ user_hash = { name: "Bob" }
38
+ Tweet.new(user: user_hash)
39
+ # => automatically calls User.coerce(user_hash) or
40
+ # User.new(user_hash) if that isn't present.
41
+ ```
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
+ ```ruby
48
+ class SpecialHash < Hash
49
+ include Hashie::Extensions::Coercion
50
+ coerce_value Hash, SpecialHash
51
+
52
+ def initialize(hash = {})
53
+ super
54
+ hash.each_pair do |k,v|
55
+ self[k] = v
56
+ end
57
+ end
58
+ end
59
+ ```
60
+
61
+ ### KeyConversion
62
+
63
+ The KeyConversion extension gives you the convenience methods of
64
+ `symbolize_keys` and `stringify_keys` along with their bang
65
+ counterparts. You can also include just stringify or just symbolize with
66
+ `Hashie::Extensions::StringifyKeys` or `Hashie::Extensions::SymbolizeKeys`.
67
+
68
+ ### MergeInitializer
69
+
70
+ The MergeInitializer extension simply makes it possible to initialize a
71
+ Hash subclass with another Hash, giving you a quick short-hand.
72
+
73
+ ### MethodAccess
74
+
75
+ The MethodAccess extension allows you to quickly build method-based
76
+ reading, writing, and querying into your Hash descendant. It can also be
77
+ included as individual modules, i.e. `Hashie::Extensions::MethodReader`,
78
+ `Hashie::Extensions::MethodWriter` and `Hashie::Extensions::MethodQuery`
79
+
80
+ ```ruby
81
+ class MyHash < Hash
82
+ include Hashie::Extensions::MethodAccess
83
+ end
84
+
85
+ h = MyHash.new
86
+ h.abc = 'def'
87
+ h.abc # => 'def'
88
+ h.abc? # => true
89
+ ```
90
+
91
+ ### IndifferentAccess
92
+
93
+ This extension can be mixed in to instantly give you indifferent access
94
+ to your Hash subclass. This works just like the params hash in Rails and
95
+ other frameworks where whether you provide symbols or strings to access
96
+ keys, you will get the same results.
97
+
98
+ A unique feature of Hashie's IndifferentAccess mixin is that it will
99
+ inject itself recursively into subhashes *without* reinitializing the
100
+ hash in question. This means you can safely merge together indifferent
101
+ and non-indifferent hashes arbitrarily deeply without worrying about
102
+ whether you'll be able to `hash[:other][:another]` properly.
103
+
104
+ ### IgnoreUndeclared
105
+
106
+ This extension can be mixed in to silently ignore undeclared properties on
107
+ initialization instead of raising an error. This is useful when using a
108
+ Trash to capture a subset of a larger hash.
109
+
110
+ ```ruby
111
+ class Person < Trash
112
+ include Hashie::Extensions::IgnoreUndeclared
113
+ property :first_name
114
+ property :last_name
115
+ end
116
+
117
+ user_data = {
118
+ first_name: 'Freddy',
119
+ last_name: 'Nostrils',
120
+ email: 'freddy@example.com'
121
+ }
122
+
123
+ p = Person.new(user_data) # 'email' is silently ignored
124
+
125
+ p.first_name # => 'Freddy'
126
+ p.last_name # => 'Nostrils'
127
+ p.email # => NoMethodError
128
+ ```
129
+
130
+ ### DeepMerge
131
+
132
+ This extension allow you to easily include a recursive merging
133
+ system to any Hash descendant:
134
+
135
+ ```ruby
136
+ class MyHash < Hash
137
+ include Hashie::Extensions::DeepMerge
138
+ end
139
+
140
+ h1 = MyHash.new
141
+ h2 = MyHash.new
142
+
143
+ h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
144
+ h2 = { x: { y: [7,8,9] }, z: "xyz" }
145
+
146
+ h1.deep_merge(h2) #=> { x: { y: [7, 8, 9] }, z: "xyz" }
147
+ h2.deep_merge(h1) #=> { x: { y: [4, 5, 6] }, z: [7, 8, 9] }
148
+ ```
149
+
150
+ ### DeepFetch
151
+
152
+ This extension can be mixed in to provide for safe and concise retrieval of
153
+ deeply nested hash values. In the event that the requested key does not exist
154
+ a block can be provided and its value will be returned.
155
+
156
+ Though this is a hash extension, it conveniently allows for arrays to be
157
+ present in the nested structure. This feature makes the extension particularly
158
+ useful for working with JSON API responses.
159
+
160
+ ```ruby
161
+ user = {
162
+ name: { first: 'Bob', last: 'Boberts' },
163
+ groups: [
164
+ { name: 'Rubyists' },
165
+ { name: 'Open source enthusiasts' }
166
+ ]
167
+ }
168
+ user.extend Hashie::Extensions::DeepFetch
169
+
170
+ user.deep_fetch :name, :first #=> 'Bob'
171
+ user.deep_fetch :name, :middle #=> 'KeyError: Could not fetch middle'
172
+
173
+ # using a default block
174
+ user.deep_fetch :name, :middle { |key| 'default' } #=> 'default'
175
+
176
+ # a nested array
177
+ user.deep_fetch :groups, 1, :name #=> 'Open source enthusiasts'
178
+ ```
179
+
180
+ ## Mash
181
+
182
+ Mash is an extended Hash that gives simple pseudo-object functionality
183
+ that can be built from hashes and easily extended. It is designed to
184
+ be used in RESTful API libraries to provide easy object-like access
185
+ to JSON and XML parsed hashes.
186
+
187
+ ### Example:
188
+
189
+ ```ruby
190
+ mash = Hashie::Mash.new
191
+ mash.name? # => false
192
+ mash.name # => nil
193
+ mash.name = "My Mash"
194
+ mash.name # => "My Mash"
195
+ mash.name? # => true
196
+ mash.inspect # => <Hashie::Mash name="My Mash">
197
+
198
+ mash = Mash.new
199
+ # use bang methods for multi-level assignment
200
+ mash.author!.name = "Michael Bleigh"
201
+ mash.author # => <Hashie::Mash name="Michael Bleigh">
202
+
203
+ mash = Mash.new
204
+ # use under-bang methods for multi-level testing
205
+ mash.author_.name? # => false
206
+ mash.inspect # => <Hashie::Mash>
207
+ ```
208
+
209
+ **Note:** The `?` method will return false if a key has been set
210
+ to false or nil. In order to check if a key has been set at all, use the
211
+ `mash.key?('some_key')` method instead.
212
+
213
+ ## Dash
214
+
215
+ Dash is an extended Hash that has a discrete set of defined properties
216
+ and only those properties may be set on the hash. Additionally, you
217
+ can set defaults for each property. You can also flag a property as
218
+ required. Required properties will raise an exception if unset.
219
+
220
+ ### Example:
221
+
222
+ ```ruby
223
+ class Person < Hashie::Dash
224
+ property :name, required: true
225
+ property :email
226
+ property :occupation, default: 'Rubyist'
227
+ end
228
+
229
+ p = Person.new # => ArgumentError: The property 'name' is required for this Dash.
230
+
231
+ p = Person.new(name: "Bob")
232
+ p.name # => 'Bob'
233
+ p.name = nil # => ArgumentError: The property 'name' is required for this Dash.
234
+ p.email = 'abc@def.com'
235
+ p.occupation # => 'Rubyist'
236
+ p.email # => 'abc@def.com'
237
+ p[:awesome] # => NoMethodError
238
+ p[:occupation] # => 'Rubyist'
239
+ ```
240
+
241
+ ## Trash
242
+
243
+ A Trash is a Dash that allows you to translate keys on initialization.
244
+ It is used like so:
245
+
246
+ ```ruby
247
+ class Person < Hashie::Trash
248
+ property :first_name, from: :firstName
249
+ end
250
+ ```
251
+
252
+ This will automatically translate the <tt>firstName</tt> key to <tt>first_name</tt>
253
+ when it is initialized using a hash such as through:
254
+
255
+ ```ruby
256
+ Person.new(firstName: 'Bob')
257
+ ```
258
+
259
+ Trash also supports translations using lambda, this could be useful when dealing with
260
+ external API's. You can use it in this way:
261
+
262
+ ```ruby
263
+ class Result < Hashie::Trash
264
+ property :id, transform_with: lambda { |v| v.to_i }
265
+ property :created_at, from: :creation_date, with: lambda { |v| Time.parse(v) }
266
+ end
267
+ ```
268
+
269
+ this will produce the following
270
+
271
+ ```ruby
272
+ result = Result.new(id: '123', creation_date: '2012-03-30 17:23:28')
273
+ result.id.class # => Fixnum
274
+ result.created_at.class # => Time
275
+ ```
276
+
277
+ ## Clash
278
+
279
+ Clash is a Chainable Lazy Hash that allows you to easily construct
280
+ complex hashes using method notation chaining. This will allow you
281
+ to use a more action-oriented approach to building options hashes.
282
+
283
+ Essentially, a Clash is a generalized way to provide much of the same
284
+ kind of "chainability" that libraries like Arel or Rails 2.x's named_scopes
285
+ provide.
286
+
287
+ ### Example:
288
+
289
+ ```ruby
290
+ c = Hashie::Clash.new
291
+ c.where(abc: 'def').order(:created_at)
292
+ c # => { where: { abc: 'def' }, order: :created_at }
293
+
294
+ # You can also use bang notation to chain into sub-hashes,
295
+ # jumping back up the chain with _end!
296
+ c = Hashie::Clash.new
297
+ c.where!.abc('def').ghi(123)._end!.order(:created_at)
298
+ c # => { where: { abc: 'def', ghi: 123 }, order: :created_at }
299
+
300
+ # Multiple hashes are merged automatically
301
+ c = Hashie::Clash.new
302
+ c.where(abc: 'def').where(hgi: 123)
303
+ c # => { where: { abc: 'def', hgi: 123 } }
304
+ ```
305
+
306
+ ## Rash
307
+
308
+ Rash is a Hash whose keys can be Regexps or Ranges, which will map many input keys to a value.
309
+
310
+ A good use case for the Rash is an URL router for a web framework, where URLs need to be mapped to actions; the Rash's keys match URL patterns, while the values call the action which handles the URL.
311
+
312
+ If the Rash's value is a `proc`, the `proc` will be automatically called with the regexp's MatchData (matched groups) as a block argument.
313
+
314
+ ### Example:
315
+
316
+ ```ruby
317
+
318
+ # Mapping names to appropriate greetings
319
+ greeting = Hashie::Rash.new( /^Mr./ => "Hello sir!", /^Mrs./ => "Evening, madame." )
320
+ greeting["Mr. Steve Austin"] #=> "Hello sir!"
321
+ greeting["Mrs. Steve Austin"] #=> "Evening, madame."
322
+
323
+ # Mapping statements to saucy retorts
324
+ mapper = Hashie::Rash.new(
325
+ /I like (.+)/ => proc { |m| "Who DOESN'T like #{m[1]}?!" },
326
+ /Get off my (.+)!/ => proc { |m| "Forget your #{m[1]}, old man!" }
327
+ )
328
+ mapper["I like traffic lights"] #=> "Who DOESN'T like traffic lights?!"
329
+ mapper["Get off my lawn!"] #=> "Forget your lawn, old man!"
330
+ ```
331
+
332
+ ### Auto-optimized
333
+
334
+ **Note:** The Rash is automatically optimized every 500 accesses
335
+ (which means that it sorts the list of Regexps, putting the most frequently matched ones at the beginning).
336
+
337
+ If this value is too low or too high for your needs, you can tune it by setting: `rash.optimize_every = n`.
338
+
339
+ ## Contributing
340
+
341
+ See [CONTRIBUTING.md](CONTRIBUTING.md)
342
+
343
+ ## Copyright
344
+
345
+ Copyright (c) 2009-2014 Intridea, Inc. (http://intridea.com/) and [contributors](https://github.com/intridea/hashie/graphs/contributors).
346
+
347
+ MIT License. See [LICENSE](LICENSE) for details.