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
@@ -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.