hashie 2.0.5 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +13 -6
- data/CHANGELOG.md +40 -21
- data/CONTRIBUTING.md +110 -19
- data/Gemfile +9 -0
- data/LICENSE +1 -1
- data/README.md +347 -0
- data/Rakefile +4 -2
- data/hashie.gemspec +4 -7
- data/lib/hashie.rb +3 -0
- data/lib/hashie/clash.rb +19 -19
- data/lib/hashie/dash.rb +47 -39
- data/lib/hashie/extensions/coercion.rb +10 -6
- data/lib/hashie/extensions/deep_fetch.rb +29 -0
- data/lib/hashie/extensions/deep_merge.rb +15 -6
- data/lib/hashie/extensions/ignore_undeclared.rb +41 -0
- data/lib/hashie/extensions/indifferent_access.rb +37 -10
- data/lib/hashie/extensions/key_conversion.rb +3 -3
- data/lib/hashie/extensions/method_access.rb +9 -9
- data/lib/hashie/hash.rb +7 -7
- data/lib/hashie/hash_extensions.rb +5 -7
- data/lib/hashie/mash.rb +38 -31
- data/lib/hashie/rash.rb +119 -0
- data/lib/hashie/trash.rb +31 -22
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/clash_spec.rb +43 -45
- data/spec/hashie/dash_spec.rb +115 -53
- data/spec/hashie/extensions/coercion_spec.rb +42 -37
- data/spec/hashie/extensions/deep_fetch_spec.rb +70 -0
- data/spec/hashie/extensions/deep_merge_spec.rb +11 -9
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +23 -0
- data/spec/hashie/extensions/indifferent_access_spec.rb +117 -64
- data/spec/hashie/extensions/key_conversion_spec.rb +28 -27
- data/spec/hashie/extensions/merge_initializer_spec.rb +13 -10
- data/spec/hashie/extensions/method_access_spec.rb +49 -40
- data/spec/hashie/hash_spec.rb +25 -13
- data/spec/hashie/mash_spec.rb +243 -187
- data/spec/hashie/rash_spec.rb +44 -0
- data/spec/hashie/trash_spec.rb +81 -43
- data/spec/hashie/version_spec.rb +7 -0
- data/spec/spec_helper.rb +0 -4
- metadata +27 -78
- data/.document +0 -5
- data/README.markdown +0 -236
- data/lib/hashie/extensions/structure.rb +0 -47
checksums.yaml
ADDED
@@ -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
|
data/.rubocop.yml
ADDED
@@ -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
|
+
|
data/.travis.yml
CHANGED
@@ -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
|
-
-
|
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
|
data/CHANGELOG.md
CHANGED
@@ -1,39 +1,58 @@
|
|
1
|
-
|
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
|
-
*
|
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
|
-
*
|
10
|
-
*
|
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
|
15
|
-
* Fix #replace jimeh
|
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
|
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
|
24
|
-
*
|
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
|
-
*
|
29
|
-
*
|
30
|
-
*
|
31
|
-
*
|
32
|
-
*
|
33
|
-
*
|
34
|
-
*
|
35
|
-
*
|
36
|
-
*
|
37
|
-
*
|
38
|
-
*
|
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).
|
data/CONTRIBUTING.md
CHANGED
@@ -1,27 +1,118 @@
|
|
1
|
-
|
1
|
+
Contributing to Hashie
|
2
|
+
======================
|
2
3
|
|
3
|
-
|
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
|
-
|
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
|
-
|
8
|
+
Fork the [project on Github](https://github.com/intridea/hashie) and check out your copy.
|
12
9
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
16
|
+
#### Create a Topic Branch
|
21
17
|
|
22
|
-
|
18
|
+
Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
|
23
19
|
|
24
|
-
|
20
|
+
```
|
21
|
+
git checkout master
|
22
|
+
git pull upstream master
|
23
|
+
git checkout -b my-feature-branch
|
24
|
+
```
|
25
25
|
|
26
|
-
|
27
|
-
|
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
data/LICENSE
CHANGED
data/README.md
ADDED
@@ -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.
|