bidu-core_ext 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,287 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash do
4
+ it_behaves_like 'a class with change_key method'
5
+ it_behaves_like 'a class with camlize_keys method'
6
+ it_behaves_like 'a class with append_keys method'
7
+ it_behaves_like 'a class with change_kvalues method'
8
+ it_behaves_like 'a class with remap method'
9
+ it_behaves_like 'an object with chain_fetch method'
10
+
11
+ describe :squash do
12
+ let(:hash) { { a: { b: 1, c: { d: 2 } } } }
13
+
14
+ it 'flattens the hash' do
15
+ expect(hash.squash).to eq('a.b' => 1, 'a.c.d' => 2)
16
+ end
17
+
18
+ it { expect { hash.squash }.not_to change { hash } }
19
+
20
+ context 'with array value' do
21
+ let(:hash) { { a: { b: [1, { x: 3, y: { z: 4 } }] } } }
22
+
23
+ it 'flattens the hash' do
24
+ expect(hash.squash).to eq('a.b' => [1, { x: 3, y: { z: 4 } }])
25
+ end
26
+ end
27
+ end
28
+
29
+ describe :sort_keys do
30
+ it 'sorts keys as symbols' do
31
+ expect({ b: 1, a: 2 }.sort_keys).to eq(a: 2, b: 1)
32
+ end
33
+ it 'sorts keys as string' do
34
+ expect({ 'b' => 1, 'a' => 2 }.sort_keys).to eq('a' => 2, 'b' => 1)
35
+ end
36
+ it 'sorts keys recursively' do
37
+ expect({ b: 1, a: { d: 3, c: 4 } }.sort_keys).to eq(a: { c: 4, d: 3 }, b: 1)
38
+ end
39
+ it 'sorts keys recursively when argumen is passed' do
40
+ expect({ b: 1, a: { d: 3, c: 4 } }.sort_keys(recursive: true)).to eq(a: { c: 4, d: 3 }, b: 1)
41
+ end
42
+ it 'does not sorts keys recursively when argumen is passed' do
43
+ expect({ b: 1, a: { d: 3, c: 4 } }.sort_keys(recursive: false)).to eq(a: { d: 3, c: 4 }, b: 1)
44
+ end
45
+ it 'sort recursevely on many levels' do
46
+ hash = { b: 1, a: { d: 2, c: { e: 3, f: 4 } } }
47
+ expected = { a: { c: { f: 4, e: 3 }, d: 2 }, b: 1 }
48
+ expect(hash.sort_keys(recursive: true)).to eq(expected)
49
+ end
50
+ it 'applies to arrays as well' do
51
+ hash = { b: 1, a: { d: 2, c: [{ e: 3, f: 4 }] } }
52
+ expected = { a: { c: [{ f: 4, e: 3 }], d: 2 }, b: 1 }
53
+ expect(hash.sort_keys(recursive: true)).to eq(expected)
54
+ end
55
+ end
56
+
57
+ describe :exclusive_merge do
58
+ let(:subject) { { a: 1, b: 2 } }
59
+ let(:other) { { b: 3, c: 4 } }
60
+
61
+ it 'merge only the common keys' do
62
+ expect(subject.exclusive_merge(other)).to eq(a: 1, b: 3)
63
+ end
64
+
65
+ it 'does not change the original hash' do
66
+ expect { subject.exclusive_merge(other) }.not_to change { subject }
67
+ end
68
+ end
69
+
70
+ describe :exclusive_merge! do
71
+ let(:subject) { { a: 1, b: 2 } }
72
+ let(:other) { { b: 3, c: 4 } }
73
+
74
+ it 'merge only the common keys' do
75
+ expect(subject.exclusive_merge!(other)).to eq(a: 1, b: 3)
76
+ end
77
+
78
+ it 'does not change the original hash' do
79
+ expect { subject.exclusive_merge!(other) }.to change { subject }
80
+ end
81
+ end
82
+
83
+ describe :to_deep_hash do
84
+ let(:subject) do
85
+ {
86
+ 'person.name' => 'Some name',
87
+ 'person.age' => 22,
88
+ 'status' => :success,
89
+ 'vehicle.fuel' => 'GASOLINE',
90
+ 'vehicle.doors' => 4
91
+ }
92
+ end
93
+
94
+ let(:expected) do
95
+ {
96
+ 'person' => { 'name' => 'Some name', 'age' => 22 },
97
+ 'vehicle' => { 'fuel' => 'GASOLINE', 'doors' => 4 },
98
+ 'status' => :success
99
+ }
100
+ end
101
+
102
+ it 'build a deep hash' do
103
+ expect(subject.to_deep_hash).to eq(expected)
104
+ end
105
+
106
+ context 'with indexed keys' do
107
+ let(:subject) do
108
+ {
109
+ 'person[0].name' => 'First person',
110
+ 'person[0].age' => 22,
111
+ 'person[1].name' => 'Second person',
112
+ 'person[1].age' => 27,
113
+ 'device[0]' => 'GEAR_LOCK',
114
+ 'device[1]' => 'GPS',
115
+ 'zipCode' => '122345-123'
116
+ }
117
+ end
118
+
119
+ let(:expected) do
120
+ {
121
+ 'person' => [
122
+ { 'name' => 'First person', 'age' => 22 },
123
+ { 'name' => 'Second person', 'age' => 27 }
124
+ ],
125
+ 'device' => %w(GEAR_LOCK GPS),
126
+ 'zipCode' => '122345-123'
127
+ }
128
+ end
129
+
130
+ it 'build a deep hash with arrays' do
131
+ expect(subject.to_deep_hash).to eq(expected)
132
+ end
133
+ end
134
+
135
+ context 'with a n level hash' do
136
+ let(:subject) do
137
+ {
138
+ 'quote_request.personal.person.name' => 'Some name',
139
+ 'quote_request.personal.person.age' => 22,
140
+ 'quote_request.insurance.vehicle.fuel' => 'GASOLINE',
141
+ 'quote_request.insurance.vehicle.doors' => 4,
142
+ 'request.status' => :success,
143
+ 'trials' => 3
144
+ }
145
+ end
146
+
147
+ let(:expected) do
148
+ {
149
+ 'quote_request' => {
150
+ 'personal' => {
151
+ 'person' => { 'name' => 'Some name', 'age' => 22 }
152
+ },
153
+ 'insurance' => {
154
+ 'vehicle' => { 'fuel' => 'GASOLINE', 'doors' => 4 }
155
+ }
156
+ },
157
+ 'request' => { 'status' => :success },
158
+ 'trials' => 3
159
+ }
160
+ end
161
+
162
+ it 'build a deep hash with arrays' do
163
+ expect(subject.to_deep_hash).to eq(expected)
164
+ end
165
+ end
166
+
167
+ context 'with a n level hash and arrays' do
168
+ let(:subject) do
169
+ {
170
+ 'quote_request.personal.person[0].name' => 'Some name 1',
171
+ 'quote_request.personal.person[0].age' => 22,
172
+ 'quote_request.personal.person[1].name' => 'Some name 2',
173
+ 'quote_request.personal.person[1].age' => 23,
174
+ 'request[0].status.clazz' => String,
175
+ 'request[1].status.clazz' => Fixnum,
176
+ 'request[2].status.clazz' => Date,
177
+ 'trials' => 3
178
+ }
179
+ end
180
+
181
+ let(:expected) do
182
+ {
183
+ 'quote_request' => {
184
+ 'personal' => {
185
+ 'person' => [
186
+ { 'name' => 'Some name 1', 'age' => 22 },
187
+ { 'name' => 'Some name 2', 'age' => 23 }
188
+ ]
189
+ }
190
+ },
191
+ 'request' => [
192
+ { 'status' => { 'clazz' => String } },
193
+ { 'status' => { 'clazz' => Fixnum } },
194
+ { 'status' => { 'clazz' => Date } }
195
+ ],
196
+ 'trials' => 3
197
+ }
198
+ end
199
+
200
+ it 'build a deep hash with arrays' do
201
+ expect(subject.to_deep_hash).to eq(expected)
202
+ end
203
+ end
204
+
205
+ context 'with custom separator' do
206
+ let(:subject) do
207
+ {
208
+ 'person_name' => 'Some name',
209
+ 'person_age' => 22,
210
+ 'status' => :success,
211
+ 'vehicle_fuel' => 'GASOLINE',
212
+ 'vehicle_doors' => 4
213
+ }
214
+ end
215
+
216
+ it 'build a deep hash with arrays' do
217
+ expect(subject.to_deep_hash('_')).to eq(expected)
218
+ end
219
+ end
220
+
221
+ context 'with custom separator on n level deep hash' do
222
+ let(:subject) do
223
+ {
224
+ 'person_name_clazz' => String
225
+ }
226
+ end
227
+
228
+ let(:expected) do
229
+ {
230
+ 'person' => {
231
+ 'name' => { 'clazz' => String }
232
+ }
233
+ }
234
+ end
235
+
236
+ it 'build a deep hash with arrays' do
237
+ expect(subject.to_deep_hash('_')).to eq(expected)
238
+ end
239
+ end
240
+ end
241
+
242
+ describe '#map_and_find' do
243
+ let(:hash) { { a: 1, b: 2, c: 3, d: 4 } }
244
+ let(:value) { hash.map_and_find(&block) }
245
+
246
+ context 'when block returns nil' do
247
+ let(:block) { proc {} }
248
+ it { expect(value).to be_nil }
249
+ end
250
+
251
+ context 'when block returns false' do
252
+ let(:block) { proc { false } }
253
+ it { expect(value).to be_nil }
254
+ end
255
+
256
+ context 'when block returns a true evaluated value' do
257
+ let(:block) { proc { |_, v| v.to_s } }
258
+
259
+ it { expect(value).to eq('1') }
260
+
261
+ context 'but not for the first value' do
262
+ let(:transformer) { double(:transformer) }
263
+ let(:block) { proc { |_, v| transformer.transform(v) } }
264
+
265
+ before do
266
+ allow(transformer).to receive(:transform) do |v|
267
+ v.to_s if v > 1
268
+ end
269
+ value
270
+ end
271
+
272
+ it { expect(value).to eq('2') }
273
+ it 'calls the mapping only until it returns a valid value' do
274
+ expect(transformer).to have_received(:transform).exactly(2)
275
+ end
276
+ end
277
+ end
278
+
279
+ context 'when the block accepts one argument' do
280
+ let(:block) { proc { |v| v } }
281
+
282
+ it do
283
+ expect(value).to eq([:a, 1])
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Numeric do
4
+ describe '#percent_of' do
5
+ context 'when number is float' do
6
+ let(:number) { 120.0 }
7
+
8
+ it 'converts to percentage of number' do
9
+ expect(number.percent_of(240)).to eq(50)
10
+ end
11
+
12
+ it 'converts to percentage of number' do
13
+ expect(number.percent_of(60)).to eq(200)
14
+ end
15
+
16
+ it 'do not raise an error when divisor is 0' do
17
+ expect(100.0.percent_of(0)).to eq(Float::INFINITY)
18
+ end
19
+
20
+ it 'do not raise an error when divisor is 0.0' do
21
+ expect(100.0.percent_of(0.0)).to eq(Float::INFINITY)
22
+ end
23
+ end
24
+
25
+ context 'when number is integer' do
26
+ it 'converts to percentage of number' do
27
+ expect(500.percent_of(50)).to eq(1000)
28
+ end
29
+
30
+ it 'converts to percentage of number' do
31
+ expect(0.percent_of(50)).to eq(0)
32
+ end
33
+
34
+ it 'converts to percentage of number' do
35
+ expect(10.percent_of(100)).to eq(10)
36
+ end
37
+
38
+ it 'do not raise an error when divisor is 0' do
39
+ expect(100.percent_of(0)).to eq(Float::INFINITY)
40
+ end
41
+ end
42
+
43
+ context 'when a number is 0' do
44
+ context 'when divident is 0' do
45
+ it { expect(0.percent_of(100)).to eq(0) }
46
+ end
47
+
48
+ context 'when divisor is 0' do
49
+ it { expect(100.percent_of(0)).to eq(Float::INFINITY) }
50
+ end
51
+
52
+ context 'both are 0' do
53
+ it { expect(0.percent_of(0)).to eq(Float::INFINITY) }
54
+ end
55
+ end
56
+
57
+ context 'when divisor is nil' do
58
+ it { expect(100.percent_of(nil)).to eq(Float::INFINITY) }
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Symbol do
4
+ describe '#camelize' do
5
+ it { expect(:sym.camelize).to be_kind_of(Symbol) }
6
+
7
+ context 'when called with upper option' do
8
+ it 'camelize the symbol' do
9
+ expect(:underscore_sym.camelize(:upper)).to eq(:UnderscoreSym)
10
+ end
11
+ end
12
+
13
+ context 'when called with lower option' do
14
+ it 'snake case the symbol' do
15
+ expect(:underscore_sym.camelize(:lower)).to eq(:underscoreSym)
16
+ end
17
+ end
18
+
19
+ context 'when called without option' do
20
+ it 'camelize the symbol' do
21
+ expect(:underscore_sym.camelize).to eq(:UnderscoreSym)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.profiles.define 'gem' do
4
+ add_filter '/spec/'
5
+ end
6
+
7
+ SimpleCov.start 'gem'
8
+ require 'bidu/core_ext'
9
+
10
+ # This file was generated by the `rspec --init` command. Conventionally, all
11
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
12
+ # Require this file using `require "spec_helper"` to ensure that it is only
13
+ # loaded once.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+
17
+ # Requires supporting ruby files with custom matchers and macros, etc,
18
+ # in spec/support/ and its subdirectories.
19
+ Dir['./spec/support/**/*.rb'].each { |f| require f }
20
+
21
+ RSpec.configure do |config|
22
+ config.treat_symbols_as_metadata_keys_with_true_values = true
23
+ config.run_all_when_everything_filtered = true
24
+ config.filter_run :focus
25
+
26
+ # Run specs in random order to surface order dependencies. If you find an
27
+ # order dependency and want to debug it, you can fix the order by providing
28
+ # the seed, which is printed after each run.
29
+ # --seed 1234
30
+ config.order = 'random'
31
+ end
@@ -0,0 +1,88 @@
1
+ shared_examples 'an object with chain_fetch method' do
2
+ describe :chain_fetch do
3
+ let(:value) { 10 }
4
+ let(:hash) do
5
+ {
6
+ b: 1, c: 2, d: 3, a: {
7
+ c: 3, d: 5, b: {
8
+ d: 6, a: 1, b: 2, c: {
9
+ d: value
10
+ }
11
+ }
12
+ }
13
+ }
14
+ end
15
+ let(:keys) { [:a, :b, :c, :d] }
16
+ let(:result) { hash.chain_fetch(*keys) }
17
+
18
+ context 'when fetching existing keys' do
19
+ it 'returns the value' do
20
+ expect(result).to eq(value)
21
+ end
22
+ end
23
+
24
+ context 'when fetching non existing keys keys' do
25
+ let(:keys) { [:a, :x, :y] }
26
+
27
+ context 'when there is no default value' do
28
+ it 'raises fetch error' do
29
+ expect { result }.to raise_error(KeyError)
30
+ end
31
+
32
+ context 'when the hash has no keys' do
33
+ let(:hash) { {} }
34
+ let(:keys) { [:a] }
35
+
36
+ it 'raises fetch error' do
37
+ expect { result }.to raise_error(KeyError)
38
+ end
39
+ end
40
+
41
+ context 'with a simple level hash' do
42
+ let(:hash) { { a: 1 } }
43
+ let(:keys) { [:c] }
44
+
45
+ it 'raises fetch error' do
46
+ expect { result }.to raise_error(KeyError)
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'but a default value block is given' do
52
+ let(:default_value) { 100 }
53
+ let(:result) { hash.chain_fetch(*keys) { default_value } }
54
+
55
+ it 'returns the default_value' do
56
+ expect(result).to eq(default_value)
57
+ end
58
+
59
+ context 'and the block logs the missing keys' do
60
+ it 'hnadles the missing keys' do
61
+ missing_keys = nil
62
+ hash.chain_fetch(*keys) do |_, keys|
63
+ missing_keys = keys
64
+ end
65
+
66
+ expect(missing_keys).to eq([:y])
67
+ end
68
+ end
69
+
70
+ context 'and the block uses the key for the return' do
71
+ let(:result) { hash.chain_fetch(*keys) { |k| "returned #{k}" } }
72
+ it 'hnadles the missing keys' do
73
+ expect(result).to eq('returned x')
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ context 'when mixing key types' do
80
+ let(:hash) { { a: { 'b' => { 100 => { true => value } } } } }
81
+ let(:keys) { [:a, 'b', 100, true] }
82
+
83
+ it 'returns the value' do
84
+ expect(result).to eq(value)
85
+ end
86
+ end
87
+ end
88
+ end