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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f8151e8630508db39e56ae5ac2b5333913573f3f
4
- data.tar.gz: de13b700b22ff856acabc7be36581e32f50ea43e
3
+ metadata.gz: 9392e6b092e218e8f232ce4232ffc42e593321d8
4
+ data.tar.gz: 96d123ecbe640bf034bd43108e27da8d437d9720
5
5
  SHA512:
6
- metadata.gz: 4a2ea8a3fd07a80a75bbb4a687258c0ae92f3a85fdef18178bc9319fc0bc122a1c2b7d7f47fdfd6ba378d3459165642cdf8610e491d7e6438254a289434ed75f
7
- data.tar.gz: cf309ea2aec15071033875bcdeb4885f2a4755a0611856acdb44c4d92c07b2b8a739d5e81c42ba163014a0485788f7597ca055ae86f913105e6efea3f90b8519
6
+ metadata.gz: 13c30a48d328a2427cfe2325f0690e2621fcf601bc0354b5d0831f005e4c23ea4fc83b40aef250ce85b9c4434fe6733cff2b5be2822f313b9535485e7003eef6
7
+ data.tar.gz: e03895318b6f26ac05e394069c30eb9eb8a98f86b206996f04a19402dd2c283ad2cd52f203e739b7a2b30f7ae4282840a6be783ea8f21cf550e047d2ed732129
@@ -2,7 +2,7 @@ language: ruby
2
2
 
3
3
  rvm:
4
4
  - ruby-head
5
- - 2.1.1
5
+ - 2.1.2
6
6
  - 2.1.0
7
7
  - 2.0.0
8
8
  - 1.9.3
@@ -1,4 +1,14 @@
1
- ## 3.1 (7/25/2014)
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
@@ -8,4 +8,7 @@ end
8
8
 
9
9
  gemspec
10
10
 
11
- gem 'rubocop', '0.21.0'
11
+ gem 'rubocop', '0.24.1'
12
+
13
+ # ActiveSupport required to test compatibility with ActiveSupport Core Extensions.
14
+ gem 'activesupport', require: false
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.1. Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
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
@@ -10,6 +10,6 @@ RSpec::Core::RakeTask.new do |spec|
10
10
  end
11
11
 
12
12
  require 'rubocop/rake_task'
13
- Rubocop::RakeTask.new(:rubocop)
13
+ RuboCop::RakeTask.new(:rubocop)
14
14
 
15
15
  task default: [:rubocop, :spec]
@@ -1,3 +1,5 @@
1
+ require 'hashie/version'
2
+
1
3
  module Hashie
2
4
  autoload :Clash, 'hashie/clash'
3
5
  autoload :Dash, 'hashie/dash'
@@ -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 []=(key, value)
13
+ def set_value_with_coercion(key, value)
11
14
  into = self.class.key_coercion(key) || self.class.value_coercion(value)
12
15
 
13
- if value && into
14
- if into.respond_to?(:coerce)
15
- value = into.coerce(value)
16
- else
17
- value = into.new(value)
18
- end
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
- super(key, value)
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.kind_of? Array
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
- if self.class.property?(att) || (self.class.respond_to?(:translations) && self.class.translations.include?(att.to_sym))
35
- self[att] = value
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
@@ -128,6 +128,10 @@ module Hashie
128
128
  super(convert_key(key))
129
129
  end
130
130
 
131
+ def values_at(*keys)
132
+ super(*keys.map { |key| convert_key(key) })
133
+ end
134
+
131
135
  alias_method :regular_dup, :dup
132
136
  # Duplicates the current mash as a new mash.
133
137
  def dup
@@ -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
- if 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
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 Integer
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.include? query
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
- if (@lookups += 1) >= @optimize_every
114
- @regexes = @regex_counts.sort_by { |_, count| -count }.map { |regex, _| regex }
115
- @lookups = 0
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
@@ -1,3 +1,3 @@
1
1
  module Hashie
2
- VERSION = '3.1.0'
2
+ VERSION = '3.2.0'
3
3
  end
@@ -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
@@ -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 non-recursively' do
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
@@ -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
@@ -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
- # /.+/ => "EVERYTHING"
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.1.0
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-06-25 00:00:00.000000000 Z
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.0.14
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