darthjee-core_ext 1.7.4 → 2.0.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +7 -1
  3. data/.gitignore +2 -0
  4. data/.reek.yml +3 -0
  5. data/ARRAY_README.md +72 -15
  6. data/CLASS_README.md +154 -0
  7. data/DATE_README.md +19 -9
  8. data/Dockerfile +2 -5
  9. data/ENUMERABLE_README.md +154 -4
  10. data/HASH_README.md +276 -135
  11. data/MATH_README.md +14 -10
  12. data/OBJECT_README.md +18 -35
  13. data/README.md +8 -4
  14. data/Rakefile +1 -0
  15. data/SYMBOL_README.md +13 -18
  16. data/config/rubycritc.rb +12 -0
  17. data/config/yardstick.yml +45 -3
  18. data/core_ext.gemspec +10 -8
  19. data/docker-compose.yml +15 -7
  20. data/lib/darthjee/core_ext/array.rb +17 -12
  21. data/lib/darthjee/core_ext/array/hash_builder.rb +20 -4
  22. data/lib/darthjee/core_ext/class.rb +28 -10
  23. data/lib/darthjee/core_ext/date.rb +1 -0
  24. data/lib/darthjee/core_ext/enumerable.rb +67 -30
  25. data/lib/darthjee/core_ext/hash.rb +4 -2
  26. data/lib/darthjee/core_ext/hash/cameliazable.rb +39 -8
  27. data/lib/darthjee/core_ext/hash/chain_fetcher.rb +17 -1
  28. data/lib/darthjee/core_ext/hash/changeable.rb +88 -0
  29. data/lib/darthjee/core_ext/hash/deep_hash_constructor.rb +127 -63
  30. data/lib/darthjee/core_ext/hash/deep_hash_constructor/setter.rb +112 -0
  31. data/lib/darthjee/core_ext/hash/key_changeable.rb +126 -54
  32. data/lib/darthjee/core_ext/hash/key_changer.rb +140 -40
  33. data/lib/darthjee/core_ext/hash/keys_sorter.rb +42 -6
  34. data/lib/darthjee/core_ext/hash/squasher.rb +131 -18
  35. data/lib/darthjee/core_ext/hash/transformable.rb +133 -41
  36. data/lib/darthjee/core_ext/hash/transposeable.rb +37 -8
  37. data/lib/darthjee/core_ext/hash/value_changer.rb +76 -36
  38. data/lib/darthjee/core_ext/math.rb +37 -6
  39. data/lib/darthjee/core_ext/numeric.rb +10 -0
  40. data/lib/darthjee/core_ext/object.rb +29 -0
  41. data/lib/darthjee/core_ext/symbol.rb +22 -2
  42. data/lib/darthjee/core_ext/version.rb +1 -1
  43. data/scripts/check_readme.sh +6 -0
  44. data/scripts/rubycritic.sh +10 -0
  45. data/spec/integration/readme/array_spec.rb +96 -0
  46. data/spec/integration/readme/class_spec.rb +123 -0
  47. data/spec/integration/readme/date_spec.rb +20 -0
  48. data/spec/integration/readme/enumerable_spec.rb +87 -0
  49. data/spec/integration/readme/hash_spec.rb +391 -0
  50. data/spec/integration/readme/math_spec.rb +31 -0
  51. data/spec/integration/readme/object_spec.rb +49 -0
  52. data/spec/integration/readme/symbol_spec.rb +29 -0
  53. data/spec/integration/yard/darthjee/core_ext/enumerable_spec.rb +24 -4
  54. data/spec/integration/yard/darthjee/core_ext/hash/cameliazable_spec.rb +11 -0
  55. data/spec/integration/yard/darthjee/core_ext/hash/changeable_spec.rb +68 -0
  56. data/spec/integration/yard/darthjee/core_ext/hash/deep_hash_constructor/setter_spec.rb +34 -0
  57. data/spec/integration/yard/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +65 -0
  58. data/spec/integration/yard/darthjee/core_ext/hash/key_changeable_spec.rb +8 -0
  59. data/spec/integration/yard/darthjee/core_ext/hash/key_changer_spec.rb +59 -0
  60. data/spec/integration/yard/darthjee/core_ext/hash/keys_sorter_spec.rb +25 -0
  61. data/spec/integration/yard/darthjee/core_ext/hash/squasher_spec.rb +60 -0
  62. data/spec/integration/yard/darthjee/core_ext/hash/transformable_spec.rb +66 -36
  63. data/spec/integration/yard/darthjee/core_ext/hash/transposeable_spec.rb +35 -0
  64. data/spec/integration/yard/darthjee/core_ext/hash_spec.rb +13 -2
  65. data/spec/integration/yard/darthjee/core_ext/math_spec.rb +28 -0
  66. data/spec/integration/yard/darthjee/core_ext/numeric_spec.rb +11 -0
  67. data/spec/integration/yard/darthjee/core_ext/object_spec.rb +47 -0
  68. data/spec/integration/yard/darthjee/core_ext/symbol_spec.rb +17 -0
  69. data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor/setter_spec.rb +64 -0
  70. data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +16 -156
  71. data/spec/lib/darthjee/core_ext/hash/keys_sorter_spec.rb +5 -4
  72. data/spec/lib/darthjee/core_ext/hash/squasher_spec.rb +8 -2
  73. data/spec/lib/darthjee/core_ext/hash/value_changer_spec.rb +4 -12
  74. data/spec/lib/hash_spec.rb +92 -146
  75. data/spec/lib/object_spec.rb +32 -0
  76. data/spec/support/models/client.rb +22 -0
  77. data/spec/support/shared_examples/hash/deep_hash.rb +166 -0
  78. data/spec/support/shared_examples/hash/hash_squasher.rb +54 -9
  79. data/spec/support/shared_examples/hash/keys_sorter.rb +266 -6
  80. metadata +70 -8
  81. data/lib/darthjee/core_ext/hash/to_hash_mapper.rb +0 -25
  82. data/spec/lib/darthjee/core_ext/hash/to_hash_mapper_spec.rb +0 -11
@@ -216,8 +216,8 @@ describe Darthjee::CoreExt::Hash::ValueChanger do
216
216
  expect(changer.change(object)).to eq(expected)
217
217
  end
218
218
 
219
- it 'does not change original array' do
220
- expect { changer.change(object) }.not_to(change { array })
219
+ it 'change original array' do
220
+ expect { changer.change(object) }.to(change { array })
221
221
  end
222
222
  end
223
223
 
@@ -230,16 +230,8 @@ describe Darthjee::CoreExt::Hash::ValueChanger do
230
230
  expect(changer.change(object)).to eq(expected)
231
231
  end
232
232
 
233
- it 'does not change original array' do
234
- expect { changer.change(object) }.not_to(change { array })
235
- end
236
- end
237
-
238
- context 'when object is not an array or hash' do
239
- let(:object) { Object.new }
240
-
241
- it 'returns object' do
242
- expect(changer.change(object)).to eq(object)
233
+ it 'changes original array' do
234
+ expect { changer.change(object) }.to(change { array })
243
235
  end
244
236
  end
245
237
  end
@@ -16,16 +16,64 @@ describe Hash do
16
16
  let(:result) { hash.chain_fetch(*keys, &block) }
17
17
  end
18
18
 
19
- it_behaves_like 'a class that has a method to squash a hash' do
20
- let(:squashed) { hash.squash }
19
+ describe '#squash' do
20
+ subject(:hash) { { a: { b: { c: 10 } } } }
21
+
22
+ it_behaves_like 'a method to squash a hash' do
23
+ let(:squashed) { hash.squash }
24
+ end
25
+
26
+ it_behaves_like 'a method to squash a hash', '/' do
27
+ let(:squashed) { hash.squash('/') }
28
+ end
29
+
30
+ it 'does not change the hash' do
31
+ expect { hash.squash }
32
+ .not_to(change { hash })
33
+ end
34
+ end
35
+
36
+ describe '#squash!' do
37
+ subject(:hash) { { a: { b: { c: 10 } } } }
38
+
39
+ it_behaves_like 'a method to squash a hash' do
40
+ let(:squashed) { hash.squash! }
41
+ end
42
+
43
+ it_behaves_like 'a method to squash a hash', '/' do
44
+ let(:squashed) { hash.squash!('/') }
45
+ end
46
+
47
+ it 'does not change the hash' do
48
+ expect { hash.squash! }
49
+ .to change { hash }
50
+ .from(a: { b: { c: 10 } })
51
+ .to('a.b.c' => 10)
52
+ end
21
53
  end
22
54
 
23
55
  it_behaves_like 'a hash with map_to_hash method' do
24
56
  let(:mapped) { hash.map_to_hash(&mapping_block) }
25
57
  end
26
58
 
27
- it_behaves_like 'a class with a keys sort method' do
28
- let(:result) { hash.sort_keys(**options) }
59
+ describe '#sort_keys!' do
60
+ it_behaves_like 'a class with a keys sort method' do
61
+ let(:result) { hash.sort_keys!(**options) }
62
+ end
63
+
64
+ it_behaves_like 'a class with a keys sort method that changes original' do
65
+ let(:result) { hash.sort_keys!(**options) }
66
+ end
67
+ end
68
+
69
+ describe '#sort_keys' do
70
+ it_behaves_like 'a class with a keys sort method' do
71
+ let(:result) { hash.sort_keys(**options) }
72
+ end
73
+
74
+ it_behaves_like 'a class with a keys sort method that not change self' do
75
+ let(:result) { hash.sort_keys(**options) }
76
+ end
29
77
  end
30
78
 
31
79
  describe '#exclusive_merge' do
@@ -59,159 +107,38 @@ describe Hash do
59
107
  describe '#to_deep_hash' do
60
108
  subject(:hash) do
61
109
  {
62
- 'person.name' => 'Some name',
63
- 'person.age' => 22,
64
- 'status' => :success,
65
- 'vehicle.fuel' => 'GASOLINE',
66
- 'vehicle.doors' => 4
67
- }
68
- end
69
-
70
- let(:expected) do
71
- {
72
- 'person' => { 'name' => 'Some name', 'age' => 22 },
73
- 'vehicle' => { 'fuel' => 'GASOLINE', 'doors' => 4 },
74
- 'status' => :success
110
+ 'person.name' => 'John',
111
+ 'person.age' => '22'
75
112
  }
76
113
  end
77
114
 
78
- it 'build a deep hash' do
79
- expect(hash.to_deep_hash).to eq(expected)
115
+ it_behaves_like 'a method that returns a deep hash' do
116
+ let(:result) { hash.to_deep_hash(*args) }
80
117
  end
81
118
 
82
- context 'with indexed keys' do
83
- subject(:hash) do
84
- {
85
- 'person[0].name' => 'First person',
86
- 'person[0].age' => 22,
87
- 'person[1].name' => 'Second person',
88
- 'person[1].age' => 27,
89
- 'device[0]' => 'GEAR_LOCK',
90
- 'device[1]' => 'GPS',
91
- 'zipCode' => '122345-123'
92
- }
93
- end
94
-
95
- let(:expected) do
96
- {
97
- 'person' => [
98
- { 'name' => 'First person', 'age' => 22 },
99
- { 'name' => 'Second person', 'age' => 27 }
100
- ],
101
- 'device' => %w[GEAR_LOCK GPS],
102
- 'zipCode' => '122345-123'
103
- }
104
- end
105
-
106
- it 'build a deep hash with arrays' do
107
- expect(hash.to_deep_hash).to eq(expected)
108
- end
119
+ it 'does not change hash' do
120
+ expect { hash.to_deep_hash }
121
+ .not_to(change { hash })
109
122
  end
123
+ end
110
124
 
111
- context 'with a n level hash' do
112
- subject(:hash) do
113
- {
114
- 'quote_request.personal.person.name' => 'Some name',
115
- 'quote_request.personal.person.age' => 22,
116
- 'quote_request.insurance.vehicle.fuel' => 'GASOLINE',
117
- 'quote_request.insurance.vehicle.doors' => 4,
118
- 'request.status' => :success,
119
- 'trials' => 3
120
- }
121
- end
122
-
123
- let(:expected) do
124
- {
125
- 'quote_request' => {
126
- 'personal' => {
127
- 'person' => { 'name' => 'Some name', 'age' => 22 }
128
- },
129
- 'insurance' => {
130
- 'vehicle' => { 'fuel' => 'GASOLINE', 'doors' => 4 }
131
- }
132
- },
133
- 'request' => { 'status' => :success },
134
- 'trials' => 3
135
- }
136
- end
137
-
138
- it 'build a deep hash with arrays' do
139
- expect(hash.to_deep_hash).to eq(expected)
140
- end
141
- end
142
-
143
- context 'with a n level hash and arrays' do
144
- subject(:hash) do
145
- {
146
- 'quote_request.personal.person[0].name' => 'Some name 1',
147
- 'quote_request.personal.person[0].age' => 22,
148
- 'quote_request.personal.person[1].name' => 'Some name 2',
149
- 'quote_request.personal.person[1].age' => 23,
150
- 'request[0].status.clazz' => String,
151
- 'request[1].status.clazz' => Integer,
152
- 'request[2].status.clazz' => Date,
153
- 'trials' => 3
154
- }
155
- end
156
-
157
- let(:expected) do
158
- {
159
- 'quote_request' => {
160
- 'personal' => {
161
- 'person' => [
162
- { 'name' => 'Some name 1', 'age' => 22 },
163
- { 'name' => 'Some name 2', 'age' => 23 }
164
- ]
165
- }
166
- },
167
- 'request' => [
168
- { 'status' => { 'clazz' => String } },
169
- { 'status' => { 'clazz' => Integer } },
170
- { 'status' => { 'clazz' => Date } }
171
- ],
172
- 'trials' => 3
173
- }
174
- end
175
-
176
- it 'build a deep hash with arrays' do
177
- expect(hash.to_deep_hash).to eq(expected)
178
- end
125
+ describe '#to_deep_hash!' do
126
+ subject(:hash) do
127
+ {
128
+ 'person.name' => 'John',
129
+ 'person.age' => '22'
130
+ }
179
131
  end
180
132
 
181
- context 'with custom separator' do
182
- subject(:hash) do
183
- {
184
- 'person_name' => 'Some name',
185
- 'person_age' => 22,
186
- 'status' => :success,
187
- 'vehicle_fuel' => 'GASOLINE',
188
- 'vehicle_doors' => 4
189
- }
190
- end
191
-
192
- it 'build a deep hash with arrays' do
193
- expect(hash.to_deep_hash('_')).to eq(expected)
194
- end
133
+ it_behaves_like 'a method that returns a deep hash' do
134
+ let(:result) { hash.to_deep_hash!(*args) }
195
135
  end
196
136
 
197
- context 'with custom separator on n level deep hash' do
198
- subject(:hash) do
199
- {
200
- 'person_name_clazz' => String
201
- }
202
- end
203
-
204
- let(:expected) do
205
- {
206
- 'person' => {
207
- 'name' => { 'clazz' => String }
208
- }
209
- }
210
- end
211
-
212
- it 'build a deep hash with arrays' do
213
- expect(hash.to_deep_hash('_')).to eq(expected)
214
- end
137
+ it 'does changes hash' do
138
+ expect { hash.to_deep_hash! }
139
+ .to change { hash }
140
+ .from('person.name' => 'John', 'person.age' => '22')
141
+ .to('person' => { 'name' => 'John', 'age' => '22' })
215
142
  end
216
143
  end
217
144
 
@@ -283,6 +210,24 @@ describe Hash do
283
210
  it { expect(list).to be_empty }
284
211
  end
285
212
 
213
+ context 'when mapping returns empty arrays' do
214
+ let(:block) { proc { [] } }
215
+
216
+ it { expect(list).not_to be_empty }
217
+ end
218
+
219
+ context 'when mapping returns empty arrays' do
220
+ let(:block) { proc { [] } }
221
+
222
+ it { expect(list).not_to be_empty }
223
+ end
224
+
225
+ context 'when mapping returns empty strings' do
226
+ let(:block) { proc { '' } }
227
+
228
+ it { expect(list).not_to be_empty }
229
+ end
230
+
286
231
  context 'when block returns false' do
287
232
  let(:block) { proc { false } }
288
233
 
@@ -315,6 +260,7 @@ describe Hash do
315
260
  end
316
261
 
317
262
  it { expect(list).to eq(hash.values[1..-1].map(&:to_s)) }
263
+
318
264
  it 'calls the mapping only once for each value' do
319
265
  expect(transformer).to have_received(:transform).exactly(4)
320
266
  end
@@ -34,4 +34,36 @@ describe Object do
34
34
  end
35
35
  end
36
36
  end
37
+
38
+ # rubocop: disable RSpec/PredicateMatcher
39
+ describe '#trueful?' do
40
+ context 'when object is an empty array' do
41
+ it { expect([].trueful?).to be_truthy }
42
+ end
43
+
44
+ context 'when object is an empty hash' do
45
+ it { expect({}.trueful?).to be_truthy }
46
+ end
47
+
48
+ context 'when object is an empty string' do
49
+ it { expect(''.trueful?).to be_truthy }
50
+ end
51
+
52
+ context 'when object is a simple object' do
53
+ it { expect(described_class.new.trueful?).to be_truthy }
54
+ end
55
+
56
+ context 'when object is true' do
57
+ it { expect(true.trueful?).to be_truthy }
58
+ end
59
+
60
+ context 'when object is nil' do
61
+ it { expect(nil.trueful?).not_to be_truthy }
62
+ end
63
+
64
+ context 'when object is false' do
65
+ it { expect(false.trueful?).not_to be_truthy }
66
+ end
67
+ end
68
+ # rubocop: enable RSpec/PredicateMatcher
37
69
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Client
4
+ def initialize(existing_ids)
5
+ @existing_ids = existing_ids
6
+ end
7
+
8
+ def request(id)
9
+ requested << id
10
+
11
+ return unless existing_ids.include?(id)
12
+ { id: id }
13
+ end
14
+
15
+ def requested
16
+ @requested ||= []
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :existing_ids
22
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples 'a method that returns a deep hash' do
4
+ subject(:hash) do
5
+ {
6
+ 'person.name' => 'Some name',
7
+ 'person.age' => 22,
8
+ 'status' => :success,
9
+ 'vehicle.fuel' => 'GASOLINE',
10
+ 'vehicle.doors' => 4
11
+ }
12
+ end
13
+
14
+ let(:args) { [] }
15
+
16
+ let(:expected) do
17
+ {
18
+ 'person' => { 'name' => 'Some name', 'age' => 22 },
19
+ 'vehicle' => { 'fuel' => 'GASOLINE', 'doors' => 4 },
20
+ 'status' => :success
21
+ }
22
+ end
23
+
24
+ it 'build a deep hash' do
25
+ expect(result).to eq(expected)
26
+ end
27
+
28
+ context 'with indexed keys' do
29
+ subject(:hash) do
30
+ {
31
+ 'person[0].name' => 'First person',
32
+ 'person[0].age' => 22,
33
+ 'person[1].name' => 'Second person',
34
+ 'person[1].age' => 27,
35
+ 'device[0]' => 'GEAR_LOCK',
36
+ 'device[1]' => 'GPS',
37
+ 'zipCode' => '122345-123'
38
+ }
39
+ end
40
+
41
+ let(:expected) do
42
+ {
43
+ 'person' => [
44
+ { 'name' => 'First person', 'age' => 22 },
45
+ { 'name' => 'Second person', 'age' => 27 }
46
+ ],
47
+ 'device' => %w[GEAR_LOCK GPS],
48
+ 'zipCode' => '122345-123'
49
+ }
50
+ end
51
+
52
+ it 'build a deep hash with arrays' do
53
+ expect(result).to eq(expected)
54
+ end
55
+ end
56
+
57
+ context 'with a n level hash' do
58
+ subject(:hash) do
59
+ {
60
+ 'quote_request.personal.person.name' => 'Some name',
61
+ 'quote_request.personal.person.age' => 22,
62
+ 'quote_request.insurance.vehicle.fuel' => 'GASOLINE',
63
+ 'quote_request.insurance.vehicle.doors' => 4,
64
+ 'request.status' => :success,
65
+ 'trials' => 3
66
+ }
67
+ end
68
+
69
+ let(:expected) do
70
+ {
71
+ 'quote_request' => {
72
+ 'personal' => {
73
+ 'person' => { 'name' => 'Some name', 'age' => 22 }
74
+ },
75
+ 'insurance' => {
76
+ 'vehicle' => { 'fuel' => 'GASOLINE', 'doors' => 4 }
77
+ }
78
+ },
79
+ 'request' => { 'status' => :success },
80
+ 'trials' => 3
81
+ }
82
+ end
83
+
84
+ it 'build a deep hash with arrays' do
85
+ expect(result).to eq(expected)
86
+ end
87
+ end
88
+
89
+ context 'with a n level hash and arrays' do
90
+ subject(:hash) do
91
+ {
92
+ 'quote_request.personal.person[0].name' => 'Some name 1',
93
+ 'quote_request.personal.person[0].age' => 22,
94
+ 'quote_request.personal.person[1].name' => 'Some name 2',
95
+ 'quote_request.personal.person[1].age' => 23,
96
+ 'request[0].status.clazz' => 'String',
97
+ 'request[1].status.clazz' => 'Integer',
98
+ 'request[2].status.clazz' => 'Date',
99
+ 'trials' => 3
100
+ }
101
+ end
102
+
103
+ let(:expected) do
104
+ {
105
+ 'quote_request' => {
106
+ 'personal' => {
107
+ 'person' => [
108
+ { 'name' => 'Some name 1', 'age' => 22 },
109
+ { 'name' => 'Some name 2', 'age' => 23 }
110
+ ]
111
+ }
112
+ },
113
+ 'request' => [
114
+ { 'status' => { 'clazz' => 'String' } },
115
+ { 'status' => { 'clazz' => 'Integer' } },
116
+ { 'status' => { 'clazz' => 'Date' } }
117
+ ],
118
+ 'trials' => 3
119
+ }
120
+ end
121
+
122
+ it 'build a deep hash with arrays' do
123
+ expect(result).to eq(expected)
124
+ end
125
+ end
126
+
127
+ context 'with custom separator' do
128
+ subject(:hash) do
129
+ {
130
+ 'person_name' => 'Some name',
131
+ 'person_age' => 22,
132
+ 'status' => :success,
133
+ 'vehicle_fuel' => 'GASOLINE',
134
+ 'vehicle_doors' => 4
135
+ }
136
+ end
137
+
138
+ let(:args) { ['_'] }
139
+
140
+ it 'build a deep hash with arrays' do
141
+ expect(result).to eq(expected)
142
+ end
143
+ end
144
+
145
+ context 'with custom separator on n level deep hash' do
146
+ subject(:hash) do
147
+ {
148
+ 'person_name_clazz' => 'String'
149
+ }
150
+ end
151
+
152
+ let(:args) { ['_'] }
153
+
154
+ let(:expected) do
155
+ {
156
+ 'person' => {
157
+ 'name' => { 'clazz' => 'String' }
158
+ }
159
+ }
160
+ end
161
+
162
+ it 'build a deep hash with arrays' do
163
+ expect(result).to eq(expected)
164
+ end
165
+ end
166
+ end