hashie 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +13 -2
- data/Gemfile +4 -1
- data/README.md +45 -1
- data/Rakefile +1 -1
- data/lib/hashie.rb +2 -0
- data/lib/hashie/extensions/coercion.rb +22 -9
- data/lib/hashie/extensions/deep_fetch.rb +1 -1
- data/lib/hashie/extensions/ignore_undeclared.rb +2 -3
- data/lib/hashie/extensions/indifferent_access.rb +2 -2
- data/lib/hashie/extensions/stringify_keys.rb +6 -0
- data/lib/hashie/mash.rb +4 -0
- data/lib/hashie/rash.rb +12 -14
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/extensions/coercion_spec.rb +91 -0
- data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +177 -0
- data/spec/hashie/hash_spec.rb +2 -2
- data/spec/hashie/mash_spec.rb +23 -0
- data/spec/hashie/rash_spec.rb +7 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9392e6b092e218e8f232ce4232ffc42e593321d8
|
4
|
+
data.tar.gz: 96d123ecbe640bf034bd43108e27da8d437d9720
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13c30a48d328a2427cfe2325f0690e2621fcf601bc0354b5d0831f005e4c23ea4fc83b40aef250ce85b9c4434fe6733cff2b5be2822f313b9535485e7003eef6
|
7
|
+
data.tar.gz: e03895318b6f26ac05e394069c30eb9eb8a98f86b206996f04a19402dd2c283ad2cd52f203e739b7a2b30f7ae4282840a6be783ea8f21cf550e047d2ed732129
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
## 3.
|
1
|
+
## 3.2.0 (7/10/2014)
|
2
|
+
|
3
|
+
* [#164](https://github.com/intridea/hashie/pull/164), [#165](https://github.com/intridea/hashie/pull/165), [#166](https://github.com/intridea/hashie/pull/166): Fixed stack overflow when coercing mashes that contain ActiveSupport::HashWithIndifferentAccess values - [@numinit](https://github.com/numinit), [@kgrz](https://github.com/kgrz).
|
4
|
+
* [#177](https://github.com/intridea/hashie/pull/177): Added support for coercing enumerables and collections - [@gregory](https://github.com/gregory).
|
5
|
+
* [#179](https://github.com/intridea/hashie/pull/179): Mash#values_at will convert each key before doing the lookup - [@nahiluhmot](https://github.com/nahiluhmot).
|
6
|
+
* [#184](https://github.com/intridea/hashie/pull/184): Allow ranges on Rash to match all Numeric types - [@medcat](https://github.com/medcat).
|
7
|
+
* [#187](https://github.com/intridea/hashie/pull/187): Automatically require version - [@medcat](https://github.com/medcat).
|
8
|
+
* [#190](https://github.com/intridea/hashie/issues/190): Fixed `coerce_key` with `from` Trash feature and Coercion extension - [@gregory](https://github.com/gregory).
|
9
|
+
* [#192](https://github.com/intridea/hashie/pull/192): Fixed StringifyKeys#stringify_keys! to recursively stringify keys of embedded ::Hash types - [@dblock](https://github.com/dblock).
|
10
|
+
|
11
|
+
## 3.1.0 (6/25/2014)
|
2
12
|
|
3
13
|
* [#169](https://github.com/intridea/hashie/pull/169): Hash#to_hash will also convert nested objects that implement to_hash - [@gregory](https://github.com/gregory).
|
4
14
|
* [#171](https://github.com/intridea/hashie/pull/171): Include Trash and Dash class name when raising `NoMethodError` - [@gregory](https://github.com/gregory).
|
@@ -6,7 +16,7 @@
|
|
6
16
|
* [#173](https://github.com/intridea/hashie/pull/173): Auto include Dash::IndifferentAccess when IndiferentAccess is included in Dash - [@gregory](https://github.com/gregory).
|
7
17
|
* [#174](https://github.com/intridea/hashie/pull/174): Fixed `from` and `transform_with` Trash features when IndifferentAccess is included - [@gregory](https://github.com/gregory).
|
8
18
|
|
9
|
-
## 3.0 (6/3/2014)
|
19
|
+
## 3.0.0 (6/3/2014)
|
10
20
|
|
11
21
|
**Note:** This version introduces several backward incompatible API changes. See [UPGRADING](UPGRADING.md) for details.
|
12
22
|
|
@@ -18,6 +28,7 @@
|
|
18
28
|
* [#149](https://github.com/intridea/hashie/issues/149): Allow IgnoreUndeclared and DeepMerge to be used with undeclared properties - [@jhaesus](https://github.com/jhaesus).
|
19
29
|
|
20
30
|
## 2.1.1 (4/12/2014)
|
31
|
+
|
21
32
|
* [#144](https://github.com/intridea/hashie/issues/144): Fixed regression invoking `to_hash` with no parameters - [@mbleigh](https://github.com/mbleigh).
|
22
33
|
|
23
34
|
## 2.1.0 (4/6/2014)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -12,7 +12,7 @@ $ gem install hashie
|
|
12
12
|
|
13
13
|
## Upgrading
|
14
14
|
|
15
|
-
You're reading the documentation for the stable release of Hashie, 3.
|
15
|
+
You're reading the documentation for the stable release of Hashie, 3.2.0. Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
|
16
16
|
|
17
17
|
## Hash Extensions
|
18
18
|
|
@@ -52,6 +52,50 @@ class SpecialHash < Hash
|
|
52
52
|
end
|
53
53
|
```
|
54
54
|
|
55
|
+
### Coercing Collections
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class Tweet < Hash
|
59
|
+
include Hashie::Extensions::Coercion
|
60
|
+
coerce_key :mentions, Array[User]
|
61
|
+
coerce_key :friends, Set[User]
|
62
|
+
end
|
63
|
+
|
64
|
+
user_hash = { name: "Bob" }
|
65
|
+
mentions_hash= [user_hash, user_hash]
|
66
|
+
friends_hash = [user_hash]
|
67
|
+
tweet = Tweet.new(mentions: mentions_hash, friends: friends_hash)
|
68
|
+
# => automatically calls User.coerce(user_hash) or
|
69
|
+
# User.new(user_hash) if that isn't present on each element of the array
|
70
|
+
|
71
|
+
tweet.mentions.map(&:class) # => [User, User]
|
72
|
+
tweet.friends.class # => Set
|
73
|
+
```
|
74
|
+
|
75
|
+
### Coercing Hashes
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
class Relation
|
79
|
+
def initialize(string)
|
80
|
+
@relation = string
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Tweet < Hash
|
85
|
+
include Hashie::Extensions::Coercion
|
86
|
+
coerce_key :relations, Hash[User => Relation]
|
87
|
+
end
|
88
|
+
|
89
|
+
user_hash = { name: "Bob" }
|
90
|
+
relations_hash= { user_hash => "father", user_hash => "friend" }
|
91
|
+
tweet = Tweet.new(relations: relations_hash)
|
92
|
+
tweet.relations.map { |k,v| [k.class, v.class] } # => [[User, Relation], [User, Relation]]
|
93
|
+
tweet.relations.class # => Hash
|
94
|
+
|
95
|
+
# => automatically calls User.coerce(user_hash) on each key
|
96
|
+
# and Relation.new on each value since Relation doesn't define the `coerce` class method
|
97
|
+
```
|
98
|
+
|
55
99
|
### KeyConversion
|
56
100
|
|
57
101
|
The KeyConversion extension gives you the convenience methods of `symbolize_keys` and `stringify_keys` along with their bang counterparts. You can also include just stringify or just symbolize with `Hashie::Extensions::StringifyKeys` or `Hashie::Extensions::SymbolizeKeys`.
|
data/Rakefile
CHANGED
data/lib/hashie.rb
CHANGED
@@ -2,25 +2,38 @@ module Hashie
|
|
2
2
|
module Extensions
|
3
3
|
module Coercion
|
4
4
|
def self.included(base)
|
5
|
-
base.extend ClassMethods
|
6
5
|
base.send :include, InstanceMethods
|
6
|
+
base.extend ClassMethods # NOTE: we wanna make sure we first define set_value_with_coercion before extending
|
7
|
+
|
8
|
+
base.send :alias_method, :'set_value_without_coercion', :[]=
|
9
|
+
base.send :alias_method, :[]=, :'set_value_with_coercion'
|
7
10
|
end
|
8
11
|
|
9
12
|
module InstanceMethods
|
10
|
-
def
|
13
|
+
def set_value_with_coercion(key, value)
|
11
14
|
into = self.class.key_coercion(key) || self.class.value_coercion(value)
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
return set_value_without_coercion(key, value) unless value && into
|
17
|
+
return set_value_without_coercion(key, coerce_or_init(into).call(value)) unless into.is_a?(Enumerable)
|
18
|
+
|
19
|
+
if into.class >= Hash
|
20
|
+
key_coerce = coerce_or_init(into.flatten[0])
|
21
|
+
value_coerce = coerce_or_init(into.flatten[-1])
|
22
|
+
value = Hash[value.map { |k, v| [key_coerce.call(k), value_coerce.call(v)] }]
|
23
|
+
else # Enumerable but not Hash: Array, Set
|
24
|
+
value_coerce = coerce_or_init(into.first)
|
25
|
+
value = into.class.new(value.map { |v| value_coerce.call(v) })
|
19
26
|
end
|
20
27
|
|
21
|
-
|
28
|
+
set_value_without_coercion(key, value)
|
22
29
|
end
|
23
30
|
|
31
|
+
def coerce_or_init(type)
|
32
|
+
type.respond_to?(:coerce) ? ->(v) { type.coerce(v) } : ->(v) { type.new(v) }
|
33
|
+
end
|
34
|
+
|
35
|
+
private :coerce_or_init
|
36
|
+
|
24
37
|
def custom_writer(key, value, _convert = true)
|
25
38
|
self[key] = value
|
26
39
|
end
|
@@ -16,7 +16,7 @@ module Hashie
|
|
16
16
|
def deep_fetch(*args, &block)
|
17
17
|
args.reduce(self) do |obj, arg|
|
18
18
|
begin
|
19
|
-
arg = Integer(arg) if obj.
|
19
|
+
arg = Integer(arg) if obj.is_a? Array
|
20
20
|
obj.fetch(arg)
|
21
21
|
rescue ArgumentError, IndexError, NoMethodError => e
|
22
22
|
break block.call(arg) if block
|
@@ -31,9 +31,8 @@ module Hashie
|
|
31
31
|
module IgnoreUndeclared
|
32
32
|
def initialize_attributes(attributes)
|
33
33
|
attributes.each_pair do |att, value|
|
34
|
-
|
35
|
-
|
36
|
-
end
|
34
|
+
next unless self.class.property?(att) || (self.class.respond_to?(:translations) && self.class.translations.include?(att.to_sym))
|
35
|
+
self[att] = value
|
37
36
|
end if attributes
|
38
37
|
end
|
39
38
|
|
@@ -29,11 +29,11 @@ module Hashie
|
|
29
29
|
end
|
30
30
|
|
31
31
|
base.class_eval do
|
32
|
-
alias_method :regular_writer, :[]=
|
32
|
+
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
33
33
|
alias_method :[]=, :indifferent_writer
|
34
34
|
alias_method :store, :indifferent_writer
|
35
35
|
%w(default update replace fetch delete key? values_at).each do |m|
|
36
|
-
alias_method "regular_#{m}", m
|
36
|
+
alias_method "regular_#{m}", m unless method_defined?("regular_#{m}")
|
37
37
|
alias_method m, "indifferent_#{m}"
|
38
38
|
end
|
39
39
|
|
@@ -35,6 +35,12 @@ module Hashie
|
|
35
35
|
object
|
36
36
|
elsif object.respond_to?(:stringify_keys!)
|
37
37
|
object.stringify_keys!
|
38
|
+
elsif ::Hash === object
|
39
|
+
object.keys.each do |k|
|
40
|
+
stringify_keys_recursively!(object[k])
|
41
|
+
object[k.to_s] = object.delete(k)
|
42
|
+
end
|
43
|
+
object
|
38
44
|
else
|
39
45
|
object
|
40
46
|
end
|
data/lib/hashie/mash.rb
CHANGED
data/lib/hashie/rash.rb
CHANGED
@@ -78,21 +78,20 @@ module Hashie
|
|
78
78
|
# see if any of the regexps match the string
|
79
79
|
@regexes.each do |regex|
|
80
80
|
match = regex.match(query)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
81
|
+
next unless match
|
82
|
+
@regex_counts[regex] += 1
|
83
|
+
value = @hash[regex]
|
84
|
+
if value.respond_to? :call
|
85
|
+
yield value.call(match)
|
86
|
+
else
|
87
|
+
yield value
|
89
88
|
end
|
90
89
|
end
|
91
90
|
|
92
|
-
when
|
91
|
+
when Numeric
|
93
92
|
# see if any of the ranges match the integer
|
94
93
|
@ranges.each do |range|
|
95
|
-
yield @hash[range] if range.
|
94
|
+
yield @hash[range] if range.cover? query
|
96
95
|
end
|
97
96
|
|
98
97
|
when Regexp
|
@@ -110,10 +109,9 @@ module Hashie
|
|
110
109
|
private
|
111
110
|
|
112
111
|
def optimize_if_necessary!
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
112
|
+
return unless (@lookups += 1) >= @optimize_every
|
113
|
+
@regexes = @regex_counts.sort_by { |_, count| -count }.map { |regex, _| regex }
|
114
|
+
@lookups = 0
|
117
115
|
end
|
118
116
|
end
|
119
117
|
end
|
data/lib/hashie/version.rb
CHANGED
@@ -50,6 +50,48 @@ describe Hashie::Extensions::Coercion do
|
|
50
50
|
expect(instance[:bar]).to be_coerced
|
51
51
|
end
|
52
52
|
|
53
|
+
it 'supports coercion for Array' do
|
54
|
+
subject.coerce_key :foo, Array[Coercable]
|
55
|
+
|
56
|
+
instance[:foo] = %w('bar', 'bar2')
|
57
|
+
expect(instance[:foo]).to all(be_coerced)
|
58
|
+
expect(instance[:foo]).to be_a(Array)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'supports coercion for Set' do
|
62
|
+
subject.coerce_key :foo, Set[Coercable]
|
63
|
+
|
64
|
+
instance[:foo] = Set.new(%w('bar', 'bar2'))
|
65
|
+
expect(instance[:foo]).to all(be_coerced)
|
66
|
+
expect(instance[:foo]).to be_a(Set)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'supports coercion for Set of primitive' do
|
70
|
+
subject.coerce_key :foo, Set[Initializable]
|
71
|
+
|
72
|
+
instance[:foo] = %w('bar', 'bar2')
|
73
|
+
expect(instance[:foo].map(&:value)).to all(eq 'String')
|
74
|
+
expect(instance[:foo]).to be_none { |v| v.coerced? }
|
75
|
+
expect(instance[:foo]).to be_a(Set)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'supports coercion for Hash' do
|
79
|
+
subject.coerce_key :foo, Hash[Coercable => Coercable]
|
80
|
+
|
81
|
+
instance[:foo] = { 'bar_key' => 'bar_value', 'bar2_key' => 'bar2_value' }
|
82
|
+
expect(instance[:foo].keys).to all(be_coerced)
|
83
|
+
expect(instance[:foo].values).to all(be_coerced)
|
84
|
+
expect(instance[:foo]).to be_a(Hash)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'supports coercion for Hash with primitive as value' do
|
88
|
+
subject.coerce_key :foo, Hash[Coercable => Initializable]
|
89
|
+
|
90
|
+
instance[:foo] = { 'bar_key' => '1', 'bar2_key' => '2' }
|
91
|
+
expect(instance[:foo].values.map(&:value)).to all(eq 'String')
|
92
|
+
expect(instance[:foo].keys).to all(be_coerced)
|
93
|
+
end
|
94
|
+
|
53
95
|
it 'calls #new if no coerce method is available' do
|
54
96
|
subject.coerce_key :foo, Initializable
|
55
97
|
|
@@ -114,6 +156,55 @@ describe Hashie::Extensions::Coercion do
|
|
114
156
|
expect(tweet[:user]).to be_a(UserMash)
|
115
157
|
end
|
116
158
|
end
|
159
|
+
|
160
|
+
context 'when used with a Trash' do
|
161
|
+
class UserTrash < Hashie::Trash
|
162
|
+
property :email
|
163
|
+
end
|
164
|
+
class TweetTrash < Hashie::Trash
|
165
|
+
include Hashie::Extensions::Coercion
|
166
|
+
|
167
|
+
property :user, from: :user_data
|
168
|
+
coerce_key :user, UserTrash
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'coerces with instance initialization' do
|
172
|
+
tweet = TweetTrash.new(user_data: { email: 'foo@bar.com' })
|
173
|
+
expect(tweet[:user]).to be_a(UserTrash)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'when used with IndifferentAccess to coerce a Mash' do
|
178
|
+
class MyHash < Hash
|
179
|
+
include Hashie::Extensions::Coercion
|
180
|
+
include Hashie::Extensions::IndifferentAccess
|
181
|
+
include Hashie::Extensions::MergeInitializer
|
182
|
+
end
|
183
|
+
|
184
|
+
class UserHash < MyHash
|
185
|
+
end
|
186
|
+
|
187
|
+
class TweetHash < MyHash
|
188
|
+
coerce_key :user, UserHash
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'coerces with instance initialization' do
|
192
|
+
tweet = TweetHash.new(user: Hashie::Mash.new(email: 'foo@bar.com'))
|
193
|
+
expect(tweet[:user]).to be_a(UserHash)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'coerces when setting with string index' do
|
197
|
+
tweet = TweetHash.new
|
198
|
+
tweet['user'] = Hashie::Mash.new(email: 'foo@bar.com')
|
199
|
+
expect(tweet[:user]).to be_a(UserHash)
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'coerces when setting with symbol index' do
|
203
|
+
tweet = TweetHash.new
|
204
|
+
tweet[:user] = Hashie::Mash.new(email: 'foo@bar.com')
|
205
|
+
expect(tweet[:user]).to be_a(UserHash)
|
206
|
+
end
|
207
|
+
end
|
117
208
|
end
|
118
209
|
|
119
210
|
describe '#coerce_value' do
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# This set of tests verifies that Hashie::Extensions::IndifferentAccess works with
|
2
|
+
# ActiveSupport HashWithIndifferentAccess hashes. See #164 and #166 for details.
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
require 'active_support/hash_with_indifferent_access'
|
6
|
+
|
7
|
+
describe Hashie::Extensions::IndifferentAccess do
|
8
|
+
class IndifferentHashWithMergeInitializer < Hash
|
9
|
+
include Hashie::Extensions::MergeInitializer
|
10
|
+
include Hashie::Extensions::IndifferentAccess
|
11
|
+
|
12
|
+
class << self
|
13
|
+
alias_method :build, :new
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class IndifferentHashWithArrayInitializer < Hash
|
18
|
+
include Hashie::Extensions::IndifferentAccess
|
19
|
+
|
20
|
+
class << self
|
21
|
+
alias_method :build, :[]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class IndifferentHashWithTryConvertInitializer < Hash
|
26
|
+
include Hashie::Extensions::IndifferentAccess
|
27
|
+
|
28
|
+
class << self
|
29
|
+
alias_method :build, :try_convert
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
shared_examples_for 'hash with indifferent access' do
|
34
|
+
it 'is able to access via string or symbol' do
|
35
|
+
indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(abc: 123)
|
36
|
+
h = subject.build(indifferent_hash)
|
37
|
+
expect(h[:abc]).to eq 123
|
38
|
+
expect(h['abc']).to eq 123
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#values_at' do
|
42
|
+
it 'indifferently finds values' do
|
43
|
+
indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(
|
44
|
+
:foo => 'bar', 'baz' => 'qux'
|
45
|
+
)
|
46
|
+
h = subject.build(indifferent_hash)
|
47
|
+
expect(h.values_at('foo', :baz)).to eq %w(bar qux)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#fetch' do
|
52
|
+
it 'works like normal fetch, but indifferent' do
|
53
|
+
indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar')
|
54
|
+
h = subject.build(indifferent_hash)
|
55
|
+
expect(h.fetch(:foo)).to eq h.fetch('foo')
|
56
|
+
expect(h.fetch(:foo)).to eq 'bar'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#delete' do
|
61
|
+
it 'deletes indifferently' do
|
62
|
+
indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(
|
63
|
+
:foo => 'bar',
|
64
|
+
'baz' => 'qux'
|
65
|
+
)
|
66
|
+
h = subject.build(indifferent_hash)
|
67
|
+
h.delete('foo')
|
68
|
+
h.delete(:baz)
|
69
|
+
expect(h).to be_empty
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#key?' do
|
74
|
+
let(:h) do
|
75
|
+
indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar')
|
76
|
+
subject.build(indifferent_hash)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'finds it indifferently' do
|
80
|
+
expect(h).to be_key(:foo)
|
81
|
+
expect(h).to be_key('foo')
|
82
|
+
end
|
83
|
+
|
84
|
+
%w(include? member? has_key?).each do |key_alias|
|
85
|
+
it "is aliased as #{key_alias}" do
|
86
|
+
expect(h.send(key_alias.to_sym, :foo)).to be(true)
|
87
|
+
expect(h.send(key_alias.to_sym, 'foo')).to be(true)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#update' do
|
93
|
+
let(:h) do
|
94
|
+
indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar')
|
95
|
+
subject.build(indifferent_hash)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'allows keys to be indifferent still' do
|
99
|
+
h.update(baz: 'qux')
|
100
|
+
expect(h['foo']).to eq 'bar'
|
101
|
+
expect(h['baz']).to eq 'qux'
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'recursively injects indifference into sub-hashes' do
|
105
|
+
h.update(baz: { qux: 'abc' })
|
106
|
+
expect(h['baz']['qux']).to eq 'abc'
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'does not change the ancestors of the injected object class' do
|
110
|
+
h.update(baz: { qux: 'abc' })
|
111
|
+
expect(Hash.new).not_to be_respond_to(:indifferent_access?)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#replace' do
|
116
|
+
let(:h) do
|
117
|
+
indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar')
|
118
|
+
subject.build(indifferent_hash).replace(bar: 'baz', hi: 'bye')
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'returns self' do
|
122
|
+
expect(h).to be_a(subject)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'removes old keys' do
|
126
|
+
[:foo, 'foo'].each do |k|
|
127
|
+
expect(h[k]).to be_nil
|
128
|
+
expect(h.key?(k)).to be_falsy
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'creates new keys with indifferent access' do
|
133
|
+
[:bar, 'bar', :hi, 'hi'].each { |k| expect(h.key?(k)).to be_truthy }
|
134
|
+
expect(h[:bar]).to eq 'baz'
|
135
|
+
expect(h['bar']).to eq 'baz'
|
136
|
+
expect(h[:hi]).to eq 'bye'
|
137
|
+
expect(h['hi']).to eq 'bye'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#try_convert' do
|
142
|
+
describe 'with conversion' do
|
143
|
+
let(:h) do
|
144
|
+
indifferent_hash = ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar')
|
145
|
+
subject.try_convert(indifferent_hash)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'is a subject' do
|
149
|
+
expect(h).to be_a(subject)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe 'without conversion' do
|
154
|
+
let(:h) { subject.try_convert('{ :foo => bar }') }
|
155
|
+
|
156
|
+
it 'is nil' do
|
157
|
+
expect(h).to be_nil
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe 'with merge initializer' do
|
164
|
+
subject { IndifferentHashWithMergeInitializer }
|
165
|
+
it_should_behave_like 'hash with indifferent access'
|
166
|
+
end
|
167
|
+
|
168
|
+
describe 'with array initializer' do
|
169
|
+
subject { IndifferentHashWithArrayInitializer }
|
170
|
+
it_should_behave_like 'hash with indifferent access'
|
171
|
+
end
|
172
|
+
|
173
|
+
describe 'with try convert initializer' do
|
174
|
+
subject { IndifferentHashWithTryConvertInitializer }
|
175
|
+
it_should_behave_like 'hash with indifferent access'
|
176
|
+
end
|
177
|
+
end
|
data/spec/hashie/hash_spec.rb
CHANGED
@@ -13,10 +13,10 @@ describe Hash do
|
|
13
13
|
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => 'bob']
|
14
14
|
end
|
15
15
|
|
16
|
-
it '#stringify_keys! turns all keys into strings
|
16
|
+
it '#stringify_keys! turns all keys into strings recursively' do
|
17
17
|
hash = Hashie::Hash[:a => 'hey', 123 => { 345 => 'hey' }]
|
18
18
|
hash.stringify_keys!
|
19
|
-
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => { 345 => 'hey' }]
|
19
|
+
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => { '345' => 'hey' }]
|
20
20
|
end
|
21
21
|
|
22
22
|
it '#stringify_keys returns a hash with stringified keys' do
|
data/spec/hashie/mash_spec.rb
CHANGED
@@ -476,4 +476,27 @@ describe Hashie::Mash do
|
|
476
476
|
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => { '345' => 'hey' }]
|
477
477
|
end
|
478
478
|
end
|
479
|
+
|
480
|
+
describe '#values_at' do
|
481
|
+
let(:hash) { { 'key_one' => 1, :key_two => 2 } }
|
482
|
+
let(:mash) { Hashie::Mash.new(hash) }
|
483
|
+
|
484
|
+
context 'when the original type is given' do
|
485
|
+
it 'returns the values' do
|
486
|
+
expect(mash.values_at('key_one', :key_two)).to eq([1, 2])
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
context 'when a different, but acceptable type is given' do
|
491
|
+
it 'returns the values' do
|
492
|
+
expect(mash.values_at(:key_one, 'key_two')).to eq([1, 2])
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
context 'when a key is given that is not in the Mash' do
|
497
|
+
it 'returns nil for that value' do
|
498
|
+
expect(mash.values_at('key_one', :key_three)).to eq([1, nil])
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
479
502
|
end
|
data/spec/hashie/rash_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe Hashie::Rash do
|
|
10
10
|
1 => 'awesome',
|
11
11
|
1..1000 => 'rangey',
|
12
12
|
/(bcd)/ => proc { |m| m[1] }
|
13
|
-
|
13
|
+
# /.+/ => "EVERYTHING"
|
14
14
|
)
|
15
15
|
end
|
16
16
|
|
@@ -37,6 +37,12 @@ describe Hashie::Rash do
|
|
37
37
|
expect(subject[1001]).to be_nil
|
38
38
|
end
|
39
39
|
|
40
|
+
it 'finds floats from ranges' do
|
41
|
+
expect(subject[10.1]).to eq 'rangey'
|
42
|
+
expect(subject[1.0]).to eq 'rangey'
|
43
|
+
expect(subject[1000.1]).to be_nil
|
44
|
+
end
|
45
|
+
|
40
46
|
it 'evaluates proc values' do
|
41
47
|
expect(subject['abcdef']).to eq 'bcd'
|
42
48
|
expect(subject['ffffff']).to be_nil
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hashie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Bleigh
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-07-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -89,6 +89,7 @@ files:
|
|
89
89
|
- spec/hashie/extensions/deep_merge_spec.rb
|
90
90
|
- spec/hashie/extensions/ignore_undeclared_spec.rb
|
91
91
|
- spec/hashie/extensions/indifferent_access_spec.rb
|
92
|
+
- spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb
|
92
93
|
- spec/hashie/extensions/key_conversion_spec.rb
|
93
94
|
- spec/hashie/extensions/merge_initializer_spec.rb
|
94
95
|
- spec/hashie/extensions/method_access_spec.rb
|
@@ -118,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
119
|
version: '0'
|
119
120
|
requirements: []
|
120
121
|
rubyforge_project:
|
121
|
-
rubygems_version: 2.
|
122
|
+
rubygems_version: 2.1.11
|
122
123
|
signing_key:
|
123
124
|
specification_version: 4
|
124
125
|
summary: Your friendly neighborhood hash library.
|
@@ -131,6 +132,7 @@ test_files:
|
|
131
132
|
- spec/hashie/extensions/deep_merge_spec.rb
|
132
133
|
- spec/hashie/extensions/ignore_undeclared_spec.rb
|
133
134
|
- spec/hashie/extensions/indifferent_access_spec.rb
|
135
|
+
- spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb
|
134
136
|
- spec/hashie/extensions/key_conversion_spec.rb
|
135
137
|
- spec/hashie/extensions/merge_initializer_spec.rb
|
136
138
|
- spec/hashie/extensions/method_access_spec.rb
|