tash 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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