tash 1.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.
data/spec/tash_spec.rb ADDED
@@ -0,0 +1,1148 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Tash do
4
+ subject(:tash) { described_class.new(&:downcase) }
5
+
6
+ describe '.[]' do
7
+ it 'fails if the number of inputs is odd' do
8
+ expect do
9
+ described_class[:a]
10
+ end.to raise_error(ArgumentError).with_message("odd number of arguments for #{described_class}")
11
+ expect do
12
+ described_class[:a, 1, :b]
13
+ end.to raise_error(ArgumentError).with_message("odd number of arguments for #{described_class}")
14
+ end
15
+
16
+ context 'without a block' do
17
+ it "returns a new empty #{described_class}" do
18
+ tash = described_class[]
19
+
20
+ expect(tash).to be_a_kind_of described_class
21
+ expect(tash.size).to be 0
22
+ end
23
+
24
+ context "with a #{described_class}" do
25
+ it "returns a #{described_class} containing the keys of the other class" do
26
+ tash[:A] = 1
27
+ tash[:b] = 2
28
+
29
+ tash2 = described_class[tash]
30
+
31
+ expect(tash2).to eq tash
32
+ expect(tash2).to_not be tash
33
+ end
34
+
35
+ it "copies over the transform strategy from the provided #{described_class}" do
36
+ tash[:A] = 1
37
+ tash[:b] = 2
38
+
39
+ tash2 = described_class[tash]
40
+ tash2[:C] = 3
41
+
42
+ expect(tash2[:c]).to be 3
43
+ end
44
+ end
45
+
46
+ it 'works with a Hash' do
47
+ hash = { A: 1, b: 2 }
48
+
49
+ tash = described_class[hash]
50
+
51
+ expect(tash).to be_a_kind_of described_class
52
+ expect(tash[:A]).to be 1
53
+ expect(tash[:b]).to be 2
54
+ expect(tash.size).to be 2
55
+ end
56
+
57
+ it 'works with an even number of inputs' do
58
+ tash = described_class[:A, 1, :b, 2]
59
+
60
+ expect(tash).to be_a_kind_of described_class
61
+ expect(tash[:A]).to be 1
62
+ expect(tash[:b]).to be 2
63
+ expect(tash.size).to be 2
64
+ end
65
+ end
66
+
67
+ context 'with a block' do
68
+ it "returns a new empty #{described_class}" do
69
+ tash = described_class[&:downcase]
70
+
71
+ expect(tash).to be_a_kind_of described_class
72
+ expect(tash).to be_empty
73
+
74
+ tash[:A] = 1
75
+
76
+ expect(tash[:a]).to be 1
77
+ end
78
+
79
+ it "treats the #{described_class} like a Hash using to_hash" do
80
+ tash[:A] = 1
81
+ tash[:b] = 2
82
+
83
+ tash2 = described_class[tash, &:downcase]
84
+
85
+ expect(tash2[:a]).to be 1
86
+ expect(tash2[:b]).to be 2
87
+ expect(tash2.size).to be 2
88
+ end
89
+
90
+ it 'works with a Hash' do
91
+ hash = { A: 1, b: 2 }
92
+
93
+ tash = described_class[hash, &:downcase]
94
+
95
+ expect(tash[:a]).to be 1
96
+ expect(tash[:b]).to be 2
97
+ expect(tash.size).to be 2
98
+ end
99
+
100
+ it 'works with an even number of inputs' do
101
+ tash = described_class[:A, 1, :b, 2, &:downcase]
102
+
103
+ expect(tash).to be_a_kind_of described_class
104
+ expect(tash[:a]).to be 1
105
+ expect(tash[:b]).to be 2
106
+ expect(tash.size).to be 2
107
+ end
108
+ end
109
+ end
110
+
111
+ describe '.new' do
112
+ context 'without a block' do
113
+ it 'operates like a Hash' do
114
+ tash = described_class.new
115
+ tash[:A] = 1
116
+
117
+ expect(tash[:A]).to be 1
118
+ end
119
+ end
120
+ end
121
+
122
+ describe '#==' do
123
+ it "fails if the object is not a #{described_class}" do
124
+ expect(tash == 1).to be false
125
+ end
126
+
127
+ it 'fails if the keys are different' do
128
+ tash1 = described_class
129
+ .new(&:downcase)
130
+ .tap do |n|
131
+ n[:A] = 1
132
+ n[:B] = 2
133
+ end
134
+ tash2 = described_class
135
+ .new(&:downcase)
136
+ .tap do |n|
137
+ n[:A] = 1
138
+ n[:C] = 2
139
+ end
140
+
141
+ expect(tash1 == tash2).to be false
142
+ end
143
+
144
+ it 'fails if the values are different' do
145
+ tash1 = described_class
146
+ .new(&:downcase)
147
+ .tap do |n|
148
+ n[:A] = 1
149
+ n[:B] = 2
150
+ end
151
+ tash2 = described_class
152
+ .new(&:downcase)
153
+ .tap do |n|
154
+ n[:A] = 1
155
+ n[:B] = 3
156
+ end
157
+
158
+ expect(tash1 == tash2).to be false
159
+ end
160
+
161
+ it 'fails if one is only a subset of the other' do
162
+ tash1 = described_class
163
+ .new(&:downcase)
164
+ .tap do |n|
165
+ n[:A] = 1
166
+ n[:B] = 2
167
+ n[:C] = 3
168
+ end
169
+ tash2 = described_class
170
+ .new(&:downcase)
171
+ .tap do |n|
172
+ n[:A] = 1
173
+ n[:B] = 2
174
+ end
175
+
176
+ expect(tash1 == tash2).to be false
177
+ end
178
+
179
+ it 'succeeds if it has the same keys and values' do
180
+ tash1 = described_class
181
+ .new(&:downcase)
182
+ .tap do |n|
183
+ n[:A] = 1
184
+ n[:B] = 2
185
+ end
186
+ tash2 = described_class
187
+ .new(&:downcase)
188
+ .tap do |n|
189
+ n[:b] = 2.0
190
+ n[:a] = 1.0
191
+ end
192
+
193
+ expect(tash1 == tash2).to be true
194
+ end
195
+ end
196
+
197
+ describe '#[]' do
198
+ it 'returns the set value' do
199
+ tash[:one] = 1
200
+
201
+ expect(tash[:one]).to be 1
202
+ end
203
+
204
+ it 'transforms the key' do
205
+ tash[:one] = 1
206
+
207
+ expect(tash[:ONE]).to be 1
208
+ end
209
+ end
210
+
211
+ describe '#[]=' do
212
+ it 'sets a key' do
213
+ tash[:a] = 1
214
+
215
+ expect(tash[:a]).to be 1
216
+ end
217
+
218
+ it 'returns the set value' do
219
+ expect(tash[:a] = 1).to be 1
220
+ end
221
+
222
+ it 'transforms the key' do
223
+ tash[:A] = 1
224
+
225
+ expect(tash[:a]).to be 1
226
+ end
227
+ end
228
+
229
+ describe '#assoc' do
230
+ it 'returns nil if no key is found' do
231
+ expect(tash.assoc(:a)).to be_nil
232
+ end
233
+
234
+ it 'returns a key-value pair if the key is found' do
235
+ tash[:a] = 1
236
+
237
+ expect(tash.assoc(:a)).to eql [:a, 1]
238
+ end
239
+
240
+ it 'transforms the key' do
241
+ tash[:A] = 1
242
+
243
+ expect(tash.assoc(:a)).to eql [:a, 1]
244
+ end
245
+ end
246
+
247
+ describe '#clear' do
248
+ it 'emptys the tash' do
249
+ tash[:A] = 1
250
+ tash[:b] = 2
251
+
252
+ expect(tash.clear).to be_empty
253
+ end
254
+
255
+ it 'returns itself' do
256
+ expect(tash.clear).to be tash
257
+ end
258
+ end
259
+
260
+ describe '#compact' do
261
+ it 'removes keys with nil values' do
262
+ tash[:A] = 1
263
+ tash[:b] = nil
264
+
265
+ result = tash.compact
266
+
267
+ expect(result).to be_a_kind_of described_class
268
+ expect(result).to eq described_class[a: 1]
269
+ end
270
+ end
271
+
272
+ describe '#compact!' do
273
+ it 'returns self if compaction occurred' do
274
+ tash[:A] = 1
275
+ tash[:b] = nil
276
+
277
+ expect(tash.compact!).to eq described_class[a: 1]
278
+ end
279
+
280
+ it 'returns nil if compaction did not occur' do
281
+ tash[:A] = 1
282
+ tash[:b] = 2
283
+
284
+ expect(tash.compact!).to be_nil
285
+ end
286
+ end
287
+
288
+ describe '#compare_by_identity' do
289
+ it 'returns itself' do
290
+ expect(tash.compare_by_identity).to be tash
291
+ end
292
+ end
293
+
294
+ describe '#deconstruct_keys' do
295
+ context 'when given nil' do
296
+ it 'returns an empty hash' do
297
+ tash[:A] = 1
298
+ tash[:b] = 2
299
+
300
+ expect(tash.deconstruct_keys(nil)).to eql({})
301
+ end
302
+ end
303
+
304
+ context 'when given keys' do
305
+ it 'transforms the keys' do
306
+ tash[:A] = 1
307
+ tash[:b] = 2
308
+
309
+ result =
310
+ case tash
311
+ in { A: a, B: 2 }
312
+ a
313
+ else
314
+ nil
315
+ end
316
+
317
+ expect(result).to eq tash[:a]
318
+ end
319
+ end
320
+ end
321
+
322
+ describe '#default' do
323
+ context 'without a key' do
324
+ it 'returns the default value' do
325
+ tash.default = :default
326
+ expect(tash.default).to be :default
327
+ end
328
+ end
329
+
330
+ context 'with a key' do
331
+ it 'returns the default value for that key' do
332
+ tash[:Foo] = 0
333
+ tash.default_proc = ->(t, k) { t[k] = "No key #{k}" }
334
+
335
+ expect(tash.default(:FOO)).to eql 'No key foo'
336
+ end
337
+ end
338
+
339
+ context 'with too many arguments' do
340
+ it 'throws an ArgumentError' do
341
+ expect { tash.default(1, 2) }.to raise_error ArgumentError
342
+ end
343
+ end
344
+ end
345
+
346
+ describe '#default_proc=' do
347
+ it 'provides the tash and transformed key to the block' do
348
+ tash.default_proc = ->(t, k) { t.is_a?(described_class) && k == :does_not_exist }
349
+
350
+ expect(tash[:DOES_NOT_EXIST]).to be true
351
+ end
352
+
353
+ it 'sets the proc to what is given (does not ruin comparisons by overwriting it)' do
354
+ prok = ->(t, k) { t.is_a?(described_class) && k == :does_not_exist }
355
+ tash.default_proc = prok
356
+
357
+ expect(tash.default_proc).to be prok
358
+ end
359
+ end
360
+
361
+ describe '#delete' do
362
+ context 'without a block' do
363
+ it 'returns the value related to the transformed key if found' do
364
+ tash[:A] = 1
365
+
366
+ expect(tash.delete(:a)).to be 1
367
+ end
368
+
369
+ it 'returns nil if the key is not found' do
370
+ expect(tash.delete(:does_not_exist)).to be_nil
371
+ end
372
+ end
373
+
374
+ context 'with a block' do
375
+ it 'provides the transformed key to the block' do
376
+ expect(tash.delete(:DOES_NOT_EXIST) { |k| k == :does_not_exist }).to be true
377
+ end
378
+
379
+ it 'returns the value related to the transformed key if found' do
380
+ tash[:A] = 1
381
+
382
+ expect(tash.delete(:a) { 2 }).to be 1
383
+ end
384
+
385
+ it 'returns the value of the block if the transformed key is not found' do
386
+ expect(tash.delete(:does_not_exist) { 1 }).to be 1
387
+ end
388
+ end
389
+ end
390
+
391
+ describe '#delete_if' do
392
+ context 'without a block' do
393
+ it 'returns an enumerator' do
394
+ expect(tash.delete_if).to be_a_kind_of Enumerator
395
+ end
396
+ end
397
+
398
+ context 'with a block' do
399
+ it 'deletes the transformed keys that return false from the block' do
400
+ tash[:A] = 1
401
+ tash[:b] = 2
402
+ tash[:c] = 3
403
+
404
+ tash.delete_if do |_, v|
405
+ v > 1
406
+ end
407
+
408
+ expect(tash).to eql described_class[a: 1]
409
+ end
410
+
411
+ it 'returns itself' do
412
+ result = tash.delete_if { false }
413
+
414
+ expect(result).to be tash
415
+ end
416
+ end
417
+ end
418
+
419
+ describe '#dig' do
420
+ it 'returns the value if the transformed key is found' do
421
+ tash[:Foo] = described_class[Bar: 2, &:downcase]
422
+
423
+ expect(tash.dig(:foo, :bar)).to be 2
424
+ end
425
+
426
+ it 'returns nil if no transformed key is found' do
427
+ tash[:Foo] = described_class[Bar: 2, &:downcase]
428
+
429
+ expect(tash.dig(:foo, :baz)).to be_nil
430
+ end
431
+
432
+ it 'calls into other objects that accept dig' do
433
+ tash[:foo] = %i[a b c]
434
+
435
+ expect(tash.dig(:foo, 2)).to be :c
436
+ end
437
+ end
438
+
439
+ describe '#each' do
440
+ context 'without a block' do
441
+ it 'returns an enumerator' do
442
+ expect(tash.each).to be_a_kind_of Enumerator
443
+ end
444
+ end
445
+
446
+ context 'with a block' do
447
+ it 'enumerates each key-value pair' do
448
+ tash[:A] = 1
449
+ tash[:b] = 2
450
+
451
+ output = []
452
+ tash.each do |k, v|
453
+ output << [k, v]
454
+ end
455
+
456
+ expect(output).to eql [
457
+ [:a, 1],
458
+ [:b, 2]
459
+ ]
460
+ end
461
+
462
+ it 'returns itself' do
463
+ result = tash.each do |k, v|
464
+ # noop
465
+ end
466
+
467
+ expect(result).to be tash
468
+ end
469
+ end
470
+ end
471
+
472
+ describe '#each_key' do
473
+ context 'without a block' do
474
+ it 'returns an enumerator' do
475
+ expect(tash.each_key).to be_a_kind_of Enumerator
476
+ end
477
+ end
478
+
479
+ context 'with a block' do
480
+ it 'enumerates each key-value pair' do
481
+ tash[:A] = 1
482
+ tash[:b] = 2
483
+
484
+ output = []
485
+ tash.each_key do |k|
486
+ output << k
487
+ end
488
+
489
+ expect(output).to eql %i[a b]
490
+ end
491
+
492
+ it 'returns itself' do
493
+ result = tash.each_key do |k|
494
+ # noop
495
+ end
496
+
497
+ expect(result).to be tash
498
+ end
499
+ end
500
+ end
501
+
502
+ describe '#each_value' do
503
+ context 'without a block' do
504
+ it 'returns an enumerator' do
505
+ expect(tash.each_value).to be_a_kind_of Enumerator
506
+ end
507
+ end
508
+
509
+ context 'with a block' do
510
+ it 'enumerates each key-value pair' do
511
+ tash[:A] = 1
512
+ tash[:b] = 2
513
+
514
+ output = []
515
+ tash.each_value do |v|
516
+ output << v
517
+ end
518
+
519
+ expect(output).to eql [1, 2]
520
+ end
521
+
522
+ it 'returns itself' do
523
+ result = tash.each_value do |v|
524
+ # noop
525
+ end
526
+
527
+ expect(result).to be tash
528
+ end
529
+ end
530
+ end
531
+
532
+ describe '#eql?' do
533
+ it "fails if the object is not a #{described_class}" do
534
+ expect(tash.eql?(1)).to be false
535
+ end
536
+
537
+ it 'fails if the keys are different' do
538
+ tash1 = described_class
539
+ .new(&:downcase)
540
+ .tap do |n|
541
+ n[:A] = 1
542
+ n[:B] = 2
543
+ end
544
+ tash2 = described_class
545
+ .new(&:downcase)
546
+ .tap do |n|
547
+ n[:A] = 1
548
+ n[:C] = 2
549
+ end
550
+
551
+ expect(tash1.eql?(tash2)).to be false
552
+ end
553
+
554
+ it 'fails if the values are different' do
555
+ tash1 = described_class
556
+ .new(&:downcase)
557
+ .tap do |n|
558
+ n[:A] = 1
559
+ n[:B] = 2
560
+ end
561
+ tash2 = described_class
562
+ .new(&:downcase)
563
+ .tap do |n|
564
+ n[:A] = 1
565
+ n[:B] = 3
566
+ end
567
+
568
+ expect(tash1.eql?(tash2)).to be false
569
+ end
570
+
571
+ it 'fails if one is only a subset of the other' do
572
+ tash1 = described_class
573
+ .new(&:downcase)
574
+ .tap do |n|
575
+ n[:A] = 1
576
+ n[:B] = 2
577
+ n[:C] = 3
578
+ end
579
+ tash2 = described_class
580
+ .new(&:downcase)
581
+ .tap do |n|
582
+ n[:A] = 1
583
+ n[:B] = 2
584
+ end
585
+
586
+ expect(tash1.eql?(tash2)).to be false
587
+ end
588
+
589
+ it 'succeeds if it has the same keys and values' do
590
+ tash1 = described_class
591
+ .new(&:downcase)
592
+ .tap do |n|
593
+ n[:A] = 1
594
+ n[:B] = 2
595
+ end
596
+ tash2 = described_class
597
+ .new(&:downcase)
598
+ .tap do |n|
599
+ n[:b] = 2
600
+ n[:a] = 1
601
+ end
602
+
603
+ expect(tash1.eql?(tash2)).to be true
604
+ end
605
+ end
606
+
607
+ when_ruby_above('2.7') do
608
+ describe '#except' do
609
+ it "removes keys given from the #{described_class} and returns a new one" do
610
+ tash[:A] = 1
611
+ tash[:b] = 2
612
+
613
+ result = tash.except(:a)
614
+
615
+ expect(result).to be_a_kind_of described_class
616
+ expect(result).to eq described_class[b: 2]
617
+ end
618
+ end
619
+ end
620
+
621
+ describe '#fetch' do
622
+ it 'throws an error if passed too many args' do
623
+ expect { tash.fetch(:does_not_exist, 1, 2) }.to raise_error ArgumentError
624
+ end
625
+
626
+ context 'without a block' do
627
+ it 'fetches the value for the transformed key' do
628
+ tash[:A] = 1
629
+
630
+ expect(tash.fetch(:a)).to be 1
631
+ end
632
+
633
+ it 'throws a KeyError if the transformed key does not exist' do
634
+ expect { tash.fetch(:does_not_exist) }.to raise_error KeyError
635
+ end
636
+
637
+ context 'with a default_value' do
638
+ it 'returns knows keys' do
639
+ tash[:A] = 1
640
+
641
+ expect(tash.fetch(:a, 2)).to be 1
642
+ end
643
+
644
+ it 'uses the default_value if the key does not exist' do
645
+ expect(tash.fetch(:does_not_exist, 1)).to be 1
646
+ end
647
+ end
648
+ end
649
+
650
+ context 'with a block' do
651
+ it 'provides the transformed key to the block' do
652
+ expect(tash.fetch(:DOES_NOT_EXIST) { |k| k == :does_not_exist }).to be true
653
+ end
654
+
655
+ it 'fetches the value for the transformed key' do
656
+ tash[:A] = 1
657
+
658
+ expect(tash.fetch(:a) { |k| k }).to be 1
659
+ end
660
+
661
+ it 'overrides a default value' do
662
+ expect(tash.fetch(:does_not_exist, 1) { 2 }).to be 2
663
+ end
664
+ end
665
+ end
666
+
667
+ describe '#fetch_values' do
668
+ context 'without a block' do
669
+ it 'gets the values for the keys requested' do
670
+ tash[:A] = 1
671
+ tash[:b] = 2
672
+
673
+ expect(tash.fetch_values(:A)).to eql [1]
674
+ end
675
+ end
676
+
677
+ context 'with a block' do
678
+ it 'provides the transformed key to the block' do
679
+ expect(tash.fetch_values(:DOES_NOT_EXIST) { |k| k == :does_not_exist }).to eql [true]
680
+ end
681
+
682
+ it 'gets the values for the keys requested' do
683
+ tash[:A] = 1
684
+ tash[:b] = 2
685
+
686
+ expect(tash.fetch_values(:DOES_NOT_EXIST, :A) { 3 }).to eql [3, 1]
687
+ end
688
+ end
689
+ end
690
+
691
+ describe '#invert' do
692
+ it 'flips the keys and values while running the values through the transform' do
693
+ tash[:a] = 'A'
694
+ tash[:b] = 'B'
695
+
696
+ result = tash.invert
697
+
698
+ expect(result).to be_a_kind_of described_class
699
+ expect(result).to eq described_class['a' => :a, 'b' => :b]
700
+ end
701
+ end
702
+
703
+ describe '#keep_if' do
704
+ context 'without a block' do
705
+ it 'returns an enumerator' do
706
+ expect(tash.keep_if).to be_a_kind_of Enumerator
707
+ end
708
+ end
709
+
710
+ context 'with a block' do
711
+ it 'keeps the transformed keys that return true from the block' do
712
+ tash[:A] = 1
713
+ tash[:b] = 2
714
+ tash[:c] = 3
715
+
716
+ tash.keep_if do |_, v|
717
+ v > 1
718
+ end
719
+
720
+ expect(tash).to eql described_class[b: 2, c: 3]
721
+ end
722
+
723
+ it 'returns itself' do
724
+ result = tash.keep_if { true }
725
+
726
+ expect(result).to be tash
727
+ end
728
+ end
729
+ end
730
+
731
+ describe '#key?' do
732
+ it 'transforms the key' do
733
+ tash[:A] = 1
734
+
735
+ expect(tash.key?(:a)).to be true
736
+ end
737
+ end
738
+
739
+ describe '#merge' do
740
+ context 'with no arguments' do
741
+ it 'returns a copy of self' do
742
+ tash[:A] = 1
743
+ tash[:b] = 2
744
+
745
+ tash2 = tash.merge
746
+
747
+ expect(tash2).to eq tash
748
+ expect(tash2).to_not be tash
749
+ end
750
+
751
+ it 'copies over the transform strategy' do
752
+ tash[:A] = 1
753
+ tash[:b] = 2
754
+
755
+ tash2 = tash.merge
756
+ tash2[:C] = 3
757
+
758
+ expect(tash2[:c]).to be 3
759
+ end
760
+
761
+ it 'does not execute the block' do
762
+ expect { tash.merge { raise StandardError } }.to_not raise_error StandardError
763
+ end
764
+ end
765
+
766
+ context 'without a block' do
767
+ it 'merges all tash and hashes in order' do
768
+ tash[:A] = 0
769
+ tash[:b] = 1
770
+ tash[:C] = 2
771
+ t1 = described_class[d: 3, B: 4]
772
+ h = { E: 5, d: 6 }
773
+
774
+ result = tash.merge(t1, h)
775
+
776
+ expect(result).to be_a_kind_of described_class
777
+ expect(result).to eq described_class[a: 0, b: 4, c: 2, d: 6, e: 5]
778
+ end
779
+ end
780
+
781
+ context 'with a block' do
782
+ it 'handles collisions by calling the block' do
783
+ tash[:A] = 0
784
+ tash[:b] = 1
785
+ tash[:C] = 2
786
+ t1 = described_class[d: 3, B: 4]
787
+ h = { E: 5, d: 6 }
788
+
789
+ result = tash.merge(t1, h) { |_, old_v, new_v| old_v + new_v }
790
+
791
+ expect(result).to be_a_kind_of described_class
792
+ expect(result).to eq described_class[a: 0, b: 5, c: 2, d: 9, e: 5]
793
+ end
794
+
795
+ it 'provides the transformed key to the block' do
796
+ tash[:a] = 1
797
+
798
+ expect(tash.merge(A: 2) { |k| k == :a }[:a]).to be true
799
+ end
800
+ end
801
+ end
802
+
803
+ describe '#merge!' do
804
+ context 'with no arguments' do
805
+ it 'returns itself' do
806
+ tash2 = tash.merge!
807
+
808
+ expect(tash2).to be tash
809
+ end
810
+
811
+ it 'does not execute the block' do
812
+ expect { tash.merge! { raise StandardError } }.to_not raise_error StandardError
813
+ end
814
+ end
815
+
816
+ context 'without a block' do
817
+ it 'merges all tash and hashes in order' do
818
+ tash[:A] = 0
819
+ tash[:b] = 1
820
+ tash[:C] = 2
821
+ t1 = described_class[d: 3, B: 4]
822
+ h = { E: 5, d: 6 }
823
+
824
+ expect(tash.merge!(t1, h)).to be tash
825
+ expect(tash).to eq described_class[a: 0, b: 4, c: 2, d: 6, e: 5]
826
+ end
827
+ end
828
+
829
+ context 'with a block' do
830
+ it 'handles collisions by calling the block' do
831
+ tash[:A] = 0
832
+ tash[:b] = 1
833
+ tash[:C] = 2
834
+ t1 = described_class[d: 3, B: 4]
835
+ h = { E: 5, d: 6 }
836
+
837
+ expect(tash.merge!(t1, h) { |_, old_v, new_v| old_v + new_v }).to be tash
838
+ expect(tash).to eq described_class[a: 0, b: 5, c: 2, d: 9, e: 5]
839
+ end
840
+
841
+ it 'provides the transformed key to the block' do
842
+ tash[:a] = 1
843
+
844
+ expect(tash.merge!(A: 2) { |k| k == :a }[:a]).to be true
845
+ end
846
+ end
847
+ end
848
+
849
+ describe '#reject' do
850
+ context 'without a block' do
851
+ it 'returns an enumerator' do
852
+ expect(tash.reject).to be_a_kind_of Enumerator
853
+ end
854
+ end
855
+
856
+ context 'with a block' do
857
+ it "select the #{described_class} and returns a new one" do
858
+ tash[:A] = 1
859
+ tash[:b] = 2
860
+
861
+ result = tash.reject { |_k, v| v.even? }
862
+
863
+ expect(result).to be_a_kind_of described_class
864
+ expect(result).to eq described_class[a: 1]
865
+ end
866
+ end
867
+ end
868
+
869
+ describe '#reject!' do
870
+ context 'without a block' do
871
+ it 'returns an enumerator' do
872
+ expect(tash.reject!).to be_a_kind_of Enumerator
873
+ end
874
+ end
875
+
876
+ context 'with a block' do
877
+ it 'returns nil if no change occurs' do
878
+ expect(tash.reject! { true }).to be_nil
879
+ end
880
+
881
+ it "select the #{described_class} and returns a new one" do
882
+ tash[:A] = 1
883
+ tash[:b] = 2
884
+
885
+ result = tash.reject! { |_k, v| v.even? }
886
+
887
+ expect(result).to be tash
888
+ expect(tash).to eq described_class[a: 1]
889
+ end
890
+ end
891
+ end
892
+
893
+ describe '#replace' do
894
+ context 'with a hash' do
895
+ it 'is the same tash' do
896
+ expect(tash.replace({})).to be tash
897
+ end
898
+
899
+ it 'replaces the contents' do
900
+ tash[:A] = 1
901
+ tash[:b] = 2
902
+ tash[:c] = 3
903
+
904
+ tash.replace({ D: 4, e: 5 })
905
+
906
+ expect(tash.size).to be 2
907
+ expect(tash[:d]).to be 4
908
+ expect(tash[:e]).to be 5
909
+ end
910
+ end
911
+
912
+ context 'with a tash' do
913
+ it 'is the same tash' do
914
+ expect(tash.replace(described_class.new)).to be tash
915
+ end
916
+
917
+ it 'replaces the contents' do
918
+ tash[:A] = 1
919
+ tash[:b] = 2
920
+ tash[:c] = 3
921
+
922
+ tash.replace(described_class[D: 4, e: 5])
923
+
924
+ expect(tash.size).to be 2
925
+ expect(tash[:D]).to be 4
926
+ expect(tash[:e]).to be 5
927
+ end
928
+
929
+ it 'replaces the transform block' do
930
+ tash[:A] = 1
931
+ tash[:b] = 2
932
+ tash[:c] = 3
933
+
934
+ tash.replace(described_class[D: 4, e: 5, &:upcase])
935
+
936
+ expect(tash.keys).to eql %i[D E]
937
+ end
938
+ end
939
+ end
940
+
941
+ describe '#select' do
942
+ context 'without a block' do
943
+ it 'returns an enumerator' do
944
+ expect(tash.select).to be_a_kind_of Enumerator
945
+ end
946
+ end
947
+
948
+ context 'with a block' do
949
+ it "selects key-value pairs from self and returns a new #{described_class}" do
950
+ tash[:A] = 1
951
+ tash[:b] = 2
952
+
953
+ result = tash.select { |_k, v| v.even? }
954
+
955
+ expect(result).to be_a_kind_of described_class
956
+ expect(result).to eq described_class[b: 2]
957
+ end
958
+ end
959
+ end
960
+
961
+ describe '#select!' do
962
+ context 'without a block' do
963
+ it 'returns an enumerator' do
964
+ expect(tash.select!).to be_a_kind_of Enumerator
965
+ end
966
+ end
967
+
968
+ context 'with a block' do
969
+ it 'returns nil if no change occurs' do
970
+ expect(tash.select! { true }).to be_nil
971
+ end
972
+
973
+ it 'selects key-value pairs from self and returns self' do
974
+ tash[:A] = 1
975
+ tash[:b] = 2
976
+
977
+ result = tash.select! { |_k, v| v.even? }
978
+
979
+ expect(result).to be tash
980
+ expect(tash).to eq described_class[b: 2]
981
+ end
982
+ end
983
+ end
984
+
985
+ describe '#slice' do
986
+ it 'returns a new Tash containing the selected keys' do
987
+ tash[:A] = 1
988
+ tash[:b] = 2
989
+ tash[:C] = 3
990
+
991
+ result = tash.slice(:B, :c)
992
+
993
+ expect(result).to be_a_kind_of described_class
994
+ expect(result).to eq described_class[b: 2, c: 3]
995
+ end
996
+ end
997
+
998
+ describe '#to_h' do
999
+ context 'without a block' do
1000
+ it 'returns a hash' do
1001
+ expect(tash.to_h).to be_a_kind_of Hash
1002
+ end
1003
+
1004
+ it 'copies the contents' do
1005
+ tash[:A] = 1
1006
+ tash[:b] = 2
1007
+
1008
+ expect(tash.to_h).to eql({ a: 1, b: 2 })
1009
+ end
1010
+
1011
+ it 'does not return the internal hash' do
1012
+ h = tash.to_h
1013
+ h[:a] = 1
1014
+
1015
+ expect(tash).to be_empty
1016
+ end
1017
+ end
1018
+
1019
+ context 'with a block' do
1020
+ it 'returns a hash based on the block' do
1021
+ tash[:A] = 1
1022
+ tash[:b] = 2
1023
+
1024
+ expect(tash.to_h { |k, v| [v, k] }).to eql({ 1 => :a, 2 => :b })
1025
+ end
1026
+
1027
+ it 'does not return the internal hash' do
1028
+ h = tash.to_h { |k, v| [v, k] }
1029
+ h[:c] = 3
1030
+
1031
+ expect(tash).to be_empty
1032
+ end
1033
+ end
1034
+ end
1035
+
1036
+ describe '#to_hash' do
1037
+ it 'returns a hash' do
1038
+ expect(tash.to_hash).to be_a_kind_of Hash
1039
+ end
1040
+
1041
+ it 'copies the contents' do
1042
+ tash[:A] = 1
1043
+ tash[:b] = 2
1044
+
1045
+ expect(tash.to_hash).to eql({ a: 1, b: 2 })
1046
+ end
1047
+
1048
+ it 'does not return the internal hash' do
1049
+ h = tash.to_hash
1050
+ h[:a] = 1
1051
+
1052
+ expect(tash).to be_empty
1053
+ end
1054
+ end
1055
+
1056
+ describe '#to_proc' do
1057
+ it 'returns a lambda' do
1058
+ expect(tash.to_proc).to be_a_kind_of Proc
1059
+ expect(tash.to_proc).to be_lambda
1060
+ end
1061
+
1062
+ it 'maps a transformed key to its value' do
1063
+ tash[:A] = 1
1064
+ tash[:b] = 2
1065
+
1066
+ p = tash.to_proc
1067
+
1068
+ expect(p.call(:a)).to be 1
1069
+ expect(p.call(:B)).to be 2
1070
+ expect(p.call(:c)).to be_nil
1071
+ end
1072
+
1073
+ it 'uses the original hash' do
1074
+ p = tash.to_proc
1075
+
1076
+ expect(p.call(:a)).to be_nil
1077
+
1078
+ tash[:a] = 1
1079
+
1080
+ expect(p.call(:a)).to be 1
1081
+ end
1082
+ end
1083
+
1084
+ describe '#transform_proc' do
1085
+ it 'returns nil when there is none' do
1086
+ expect(described_class.new.transform_proc).to be_nil
1087
+ end
1088
+
1089
+ it 'returns the proc when there is one' do
1090
+ p = proc { |k| k.to_s }
1091
+ tash = described_class.new(&p)
1092
+
1093
+ expect(tash.transform_proc).to be p
1094
+ end
1095
+ end
1096
+
1097
+ describe '#transform_values' do
1098
+ context 'without a block' do
1099
+ it 'returns an enumerator' do
1100
+ expect(tash.transform_values).to be_a_kind_of Enumerator
1101
+ end
1102
+ end
1103
+
1104
+ context 'with a block' do
1105
+ it "transforms the values and returns a new #{described_class}" do
1106
+ tash[:A] = 1
1107
+ tash[:b] = 2
1108
+
1109
+ result = tash.transform_values { |v| v * 100 }
1110
+
1111
+ expect(result).to be_a_kind_of described_class
1112
+ expect(result).to eq described_class[a: 100, b: 200]
1113
+ end
1114
+ end
1115
+ end
1116
+
1117
+ describe '#transform_values!' do
1118
+ context 'without a block' do
1119
+ it 'returns an enumerator' do
1120
+ expect(tash.transform_values!).to be_a_kind_of Enumerator
1121
+ end
1122
+ end
1123
+
1124
+ context 'with a block' do
1125
+ it 'transforms the values and returns self' do
1126
+ tash[:A] = 1
1127
+ tash[:b] = 2
1128
+
1129
+ result = tash.transform_values! { |v| v * 100 }
1130
+
1131
+ expect(result).to be tash
1132
+ expect(result).to eq described_class[a: 100, b: 200]
1133
+ end
1134
+ end
1135
+ end
1136
+
1137
+ describe '#values_at' do
1138
+ it 'returns a new Tash containing the selected keys' do
1139
+ tash[:A] = 1
1140
+ tash[:b] = 2
1141
+ tash[:C] = 3
1142
+
1143
+ result = tash.values_at(:B, :c, :d)
1144
+
1145
+ expect(result).to eq [2, 3, nil]
1146
+ end
1147
+ end
1148
+ end