hashie 3.1.0 → 3.2.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.
- 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
|