immutable-ruby 0.0.1 → 0.0.2
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 +4 -4
- data/lib/immutable/core_ext/struct.rb +9 -0
- data/lib/immutable/enumerable.rb +9 -0
- data/lib/immutable/hash.rb +104 -4
- data/lib/immutable/list.rb +13 -13
- data/lib/immutable/nested.rb +3 -0
- data/lib/immutable/vector.rb +21 -11
- data/lib/immutable/version.rb +1 -1
- data/spec/lib/immutable/hash/dig_spec.rb +34 -0
- data/spec/lib/immutable/hash/fetch_values_spec.rb +22 -0
- data/spec/lib/immutable/hash/put_spec.rb +9 -0
- data/spec/lib/immutable/hash/subset_spec.rb +42 -0
- data/spec/lib/immutable/hash/superset_spec.rb +42 -0
- data/spec/lib/immutable/hash/to_proc_spec.rb +39 -0
- data/spec/lib/immutable/hash/values_at_spec.rb +26 -6
- data/spec/lib/immutable/list/all_spec.rb +1 -1
- data/spec/lib/immutable/list/any_spec.rb +1 -1
- data/spec/lib/immutable/list/at_spec.rb +1 -1
- data/spec/lib/immutable/list/construction_spec.rb +1 -1
- data/spec/lib/immutable/list/count_spec.rb +1 -1
- data/spec/lib/immutable/list/each_slice_spec.rb +1 -1
- data/spec/lib/immutable/list/each_spec.rb +1 -1
- data/spec/lib/immutable/list/empty_spec.rb +1 -1
- data/spec/lib/immutable/list/eql_spec.rb +1 -1
- data/spec/lib/immutable/list/find_index_spec.rb +1 -1
- data/spec/lib/immutable/list/find_spec.rb +1 -1
- data/spec/lib/immutable/list/group_by_spec.rb +1 -1
- data/spec/lib/immutable/list/hash_spec.rb +1 -1
- data/spec/lib/immutable/list/include_spec.rb +1 -1
- data/spec/lib/immutable/list/index_spec.rb +6 -2
- data/spec/lib/immutable/list/indices_spec.rb +1 -1
- data/spec/lib/immutable/list/inspect_spec.rb +1 -1
- data/spec/lib/immutable/list/join_spec.rb +1 -1
- data/spec/lib/immutable/list/last_spec.rb +1 -1
- data/spec/lib/immutable/list/maximum_spec.rb +1 -1
- data/spec/lib/immutable/list/minimum_spec.rb +1 -1
- data/spec/lib/immutable/list/multithreading_spec.rb +4 -4
- data/spec/lib/immutable/list/none_spec.rb +1 -1
- data/spec/lib/immutable/list/one_spec.rb +1 -1
- data/spec/lib/immutable/list/product_spec.rb +1 -1
- data/spec/lib/immutable/list/reduce_spec.rb +1 -1
- data/spec/lib/immutable/list/reverse_spec.rb +1 -1
- data/spec/lib/immutable/list/size_spec.rb +1 -1
- data/spec/lib/immutable/list/sum_spec.rb +1 -1
- data/spec/lib/immutable/list/tail_spec.rb +1 -1
- data/spec/lib/immutable/list/to_a_spec.rb +1 -1
- data/spec/lib/immutable/list/to_ary_spec.rb +1 -1
- data/spec/lib/immutable/nested/construction_spec.rb +11 -5
- data/spec/lib/immutable/set/add_spec.rb +4 -2
- data/spec/lib/immutable/set/grep_spec.rb +10 -10
- data/spec/lib/immutable/set/grep_v_spec.rb +59 -0
- data/spec/lib/immutable/vector/dig_spec.rb +30 -0
- data/spec/spec_helper.rb +4 -0
- metadata +323 -306
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a963e4f0565bc516534d1cf81f0206357b252f3a
|
4
|
+
data.tar.gz: 38a237bd2bdcef74cb66971375e1414ea36c67bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '040888fc5816c86d1df3333bd1e7e922096c7775e196f5bf3c9e9dedc599dc55b888cf31c1b602bcc4bfda8c06e28b436a793d4e221fca54855e69b0b2d2e523'
|
7
|
+
data.tar.gz: fb6bffbec4a70ccc00058140a563007cbf7617c55af03328c2a8385772caaf4d6e0d22e9e10664541ec04ad3f1dfe43f5b3b327268539841d6edb9c7683af1dc
|
data/lib/immutable/enumerable.rb
CHANGED
@@ -30,6 +30,15 @@ module Immutable
|
|
30
30
|
result
|
31
31
|
end
|
32
32
|
|
33
|
+
# Search the collection for elements which are not `#===` to `item`. Yield
|
34
|
+
# them to the optional code block if provided, and return them as a new
|
35
|
+
# collection.
|
36
|
+
def grep_v(pattern, &block)
|
37
|
+
result = select { |item| !(pattern === item) }
|
38
|
+
result = result.map(&block) if block_given?
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
33
42
|
# Yield all integers from 0 up to, but not including, the number of items in
|
34
43
|
# this collection. For collections which provide indexed access, these are all
|
35
44
|
# the valid, non-negative indices into the collection.
|
data/lib/immutable/hash.rb
CHANGED
@@ -264,6 +264,12 @@ module Immutable
|
|
264
264
|
end
|
265
265
|
end
|
266
266
|
|
267
|
+
# @private
|
268
|
+
# @raise NoMethodError
|
269
|
+
def []=(*)
|
270
|
+
raise NoMethodError, "Immutable::Hash doesn't support `[]='; use `put' instead"
|
271
|
+
end
|
272
|
+
|
267
273
|
# Return a new `Hash` with a deeply nested value modified to the result of
|
268
274
|
# the given code block. When traversing the nested `Hash`es and `Vector`s,
|
269
275
|
# non-existing keys are created with empty `Hash` values.
|
@@ -570,20 +576,54 @@ module Immutable
|
|
570
576
|
end
|
571
577
|
|
572
578
|
# Return a {Vector} of the values which correspond to the `wanted` keys.
|
573
|
-
# If any of the `wanted` keys are not present in this `Hash`,
|
579
|
+
# If any of the `wanted` keys are not present in this `Hash`, `nil` will be
|
580
|
+
# placed instead, or the result of the default proc (if one is defined),
|
581
|
+
# similar to the behavior of {#get}.
|
574
582
|
#
|
575
583
|
# @example
|
576
584
|
# h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
|
577
|
-
# h.values_at("B", "A", "D") # => Immutable::Vector[2, 1]
|
585
|
+
# h.values_at("B", "A", "D") # => Immutable::Vector[2, 1, nil]
|
578
586
|
#
|
579
587
|
# @param wanted [Array] The keys to retrieve
|
580
588
|
# @return [Vector]
|
581
589
|
def values_at(*wanted)
|
582
|
-
|
583
|
-
|
590
|
+
Vector.new(wanted.map { |key| get(key) }.freeze)
|
591
|
+
end
|
592
|
+
|
593
|
+
# Return a {Vector} of the values which correspond to the `wanted` keys.
|
594
|
+
# If any of the `wanted` keys are not present in this `Hash`, raise `KeyError`
|
595
|
+
# exception.
|
596
|
+
#
|
597
|
+
# @example
|
598
|
+
# h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
|
599
|
+
# h.fetch_values("C", "A") # => Immutable::Vector[3, 1]
|
600
|
+
# h.fetch_values("C", "Z") # => KeyError: key not found: "Z"
|
601
|
+
#
|
602
|
+
# @param wanted [Array] The keys to retrieve
|
603
|
+
# @return [Vector]
|
604
|
+
def fetch_values(*wanted)
|
605
|
+
array = wanted.map { |key| fetch(key) }
|
584
606
|
Vector.new(array.freeze)
|
585
607
|
end
|
586
608
|
|
609
|
+
# Return the value of successively indexing into a nested collection.
|
610
|
+
# If any of the keys is not present, return `nil`.
|
611
|
+
#
|
612
|
+
# @example
|
613
|
+
# h = Immutable::Hash[a: 9, b: Immutable::Hash[c: 'a', d: 4], e: nil]
|
614
|
+
# h.dig(:b, :c) # => "a"
|
615
|
+
# h.dig(:b, :f) # => nil
|
616
|
+
#
|
617
|
+
# @return [Object]
|
618
|
+
def dig(key, *rest)
|
619
|
+
value = self[key]
|
620
|
+
if rest.empty? || value.nil?
|
621
|
+
value
|
622
|
+
else
|
623
|
+
value.dig(*rest)
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
587
627
|
# Return a new {Set} containing the keys from this `Hash`.
|
588
628
|
#
|
589
629
|
# @example
|
@@ -734,6 +774,50 @@ module Immutable
|
|
734
774
|
self.eql?(other) || (other.respond_to?(:to_hash) && to_hash.eql?(other.to_hash))
|
735
775
|
end
|
736
776
|
|
777
|
+
# Return true if this `Hash` is a proper superset of `other`, which means
|
778
|
+
# all `other`'s keys are contained in this `Hash` with identical
|
779
|
+
# values, and the two hashes are not identical.
|
780
|
+
#
|
781
|
+
# @param other [Immutable::Hash] The object to compare with
|
782
|
+
# @return [Boolean]
|
783
|
+
def >(other)
|
784
|
+
self != other && self >= other
|
785
|
+
end
|
786
|
+
|
787
|
+
# Return true if this `Hash` is a superset of `other`, which means all
|
788
|
+
# `other`'s keys are contained in this `Hash` with identical values.
|
789
|
+
#
|
790
|
+
# @param other [Immutable::Hash] The object to compare with
|
791
|
+
# @return [Boolean]
|
792
|
+
def >=(other)
|
793
|
+
other.each do |key, value|
|
794
|
+
if self[key] != value
|
795
|
+
return false
|
796
|
+
end
|
797
|
+
end
|
798
|
+
true
|
799
|
+
end
|
800
|
+
|
801
|
+
# Return true if this `Hash` is a proper subset of `other`, which means all
|
802
|
+
# its keys are contained in `other` with the identical values, and the two
|
803
|
+
# hashes are not identical.
|
804
|
+
#
|
805
|
+
# @param other [Immutable::Hash] The object to compare with
|
806
|
+
# @return [Boolean]
|
807
|
+
def <(other)
|
808
|
+
other > self
|
809
|
+
end
|
810
|
+
|
811
|
+
# Return true if this `Hash` is a subset of `other`, which means all its
|
812
|
+
# keys are contained in `other` with the identical values, and the two
|
813
|
+
# hashes are not identical.
|
814
|
+
#
|
815
|
+
# @param other [Immutable::Hash] The object to compare with
|
816
|
+
# @return [Boolean]
|
817
|
+
def <=(other)
|
818
|
+
other >= self
|
819
|
+
end
|
820
|
+
|
737
821
|
# See `Object#hash`.
|
738
822
|
# @return [Integer]
|
739
823
|
def hash
|
@@ -801,6 +885,22 @@ module Immutable
|
|
801
885
|
end
|
802
886
|
alias :to_h :to_hash
|
803
887
|
|
888
|
+
# Return a `Proc` which accepts a key as an argument and returns the value.
|
889
|
+
# The `Proc` behaves like {#get} (when the key is missing, it returns nil or
|
890
|
+
# the result of the default proc).
|
891
|
+
#
|
892
|
+
# @example
|
893
|
+
# h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
|
894
|
+
# h.to_proc.call("B")
|
895
|
+
# # => 2
|
896
|
+
# ["A", "C", "X"].map(&h) # The & is short for .to_proc in Ruby
|
897
|
+
# # => [1, 3, nil]
|
898
|
+
#
|
899
|
+
# @return [Proc]
|
900
|
+
def to_proc
|
901
|
+
lambda { |key| get(key) }
|
902
|
+
end
|
903
|
+
|
804
904
|
# @return [::Hash]
|
805
905
|
# @private
|
806
906
|
def marshal_dump
|
data/lib/immutable/list.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require "thread"
|
2
2
|
require "set"
|
3
|
-
require "concurrent
|
3
|
+
require "concurrent"
|
4
4
|
|
5
5
|
require "immutable/undefined"
|
6
6
|
require "immutable/enumerable"
|
@@ -1311,23 +1311,23 @@ module Immutable
|
|
1311
1311
|
def initialize(&block)
|
1312
1312
|
@head = block # doubles as storage for block while yet unrealized
|
1313
1313
|
@tail = nil
|
1314
|
-
@atomic = Concurrent::
|
1314
|
+
@atomic = Concurrent::Atom.new(0) # haven't yet run block
|
1315
1315
|
@size = nil
|
1316
1316
|
end
|
1317
1317
|
|
1318
1318
|
def head
|
1319
|
-
realize if @atomic.
|
1319
|
+
realize if @atomic.value != 2
|
1320
1320
|
@head
|
1321
1321
|
end
|
1322
1322
|
alias :first :head
|
1323
1323
|
|
1324
1324
|
def tail
|
1325
|
-
realize if @atomic.
|
1325
|
+
realize if @atomic.value != 2
|
1326
1326
|
@tail
|
1327
1327
|
end
|
1328
1328
|
|
1329
1329
|
def empty?
|
1330
|
-
realize if @atomic.
|
1330
|
+
realize if @atomic.value != 2
|
1331
1331
|
@size == 0
|
1332
1332
|
end
|
1333
1333
|
|
@@ -1348,7 +1348,7 @@ module Immutable
|
|
1348
1348
|
def realize
|
1349
1349
|
while true
|
1350
1350
|
# try to "claim" the right to run the block which realizes target
|
1351
|
-
if @atomic.
|
1351
|
+
if @atomic.compare_and_set(0,1) # full memory barrier here
|
1352
1352
|
begin
|
1353
1353
|
list = @head.call
|
1354
1354
|
if list.empty?
|
@@ -1357,22 +1357,22 @@ module Immutable
|
|
1357
1357
|
@head, @tail = list.head, list.tail
|
1358
1358
|
end
|
1359
1359
|
rescue
|
1360
|
-
@atomic.
|
1360
|
+
@atomic.reset(0)
|
1361
1361
|
MUTEX.synchronize { QUEUE.broadcast }
|
1362
1362
|
raise
|
1363
1363
|
end
|
1364
|
-
@atomic.
|
1364
|
+
@atomic.reset(2)
|
1365
1365
|
MUTEX.synchronize { QUEUE.broadcast }
|
1366
1366
|
return
|
1367
1367
|
end
|
1368
1368
|
# we failed to "claim" it, another thread must be running it
|
1369
|
-
if @atomic.
|
1369
|
+
if @atomic.value == 1 # another thread is running the block
|
1370
1370
|
MUTEX.synchronize do
|
1371
1371
|
# check value of @atomic again, in case another thread already changed it
|
1372
1372
|
# *and* went past the call to QUEUE.broadcast before we got here
|
1373
|
-
QUEUE.wait(MUTEX) if @atomic.
|
1373
|
+
QUEUE.wait(MUTEX) if @atomic.value == 1
|
1374
1374
|
end
|
1375
|
-
elsif @atomic.
|
1375
|
+
elsif @atomic.value == 2 # another thread finished the block
|
1376
1376
|
return
|
1377
1377
|
end
|
1378
1378
|
end
|
@@ -1591,5 +1591,5 @@ module Immutable
|
|
1591
1591
|
true
|
1592
1592
|
end
|
1593
1593
|
end
|
1594
|
-
end
|
1595
|
-
end
|
1594
|
+
end.freeze
|
1595
|
+
end
|
data/lib/immutable/nested.rb
CHANGED
@@ -5,6 +5,7 @@ require "immutable/vector"
|
|
5
5
|
require "immutable/sorted_set"
|
6
6
|
require "immutable/list"
|
7
7
|
require "immutable/deque"
|
8
|
+
require "immutable/core_ext/struct"
|
8
9
|
|
9
10
|
module Immutable
|
10
11
|
class << self
|
@@ -30,6 +31,8 @@ module Immutable
|
|
30
31
|
when ::Array
|
31
32
|
res = obj.map { |element| from(element) }
|
32
33
|
Immutable::Vector.new(res)
|
34
|
+
when ::Struct
|
35
|
+
from(obj.to_h)
|
33
36
|
when ::SortedSet
|
34
37
|
# This clause must go before ::Set clause, since ::SortedSet is a ::Set.
|
35
38
|
res = obj.map { |element| from(element) }
|
data/lib/immutable/vector.rb
CHANGED
@@ -279,6 +279,24 @@ module Immutable
|
|
279
279
|
end
|
280
280
|
end
|
281
281
|
|
282
|
+
# Return the value of successively indexing into a nested collection.
|
283
|
+
# If any of the keys is not present, return `nil`.
|
284
|
+
#
|
285
|
+
# @example
|
286
|
+
# v = Immutable::Vector[9, Immutable::Hash[c: 'a', d: 4]]
|
287
|
+
# v.dig(1, :c) # => "a"
|
288
|
+
# v.dig(1, :f) # => nil
|
289
|
+
#
|
290
|
+
# @return [Object]
|
291
|
+
def dig(key, *rest)
|
292
|
+
value = self[key]
|
293
|
+
if rest.empty? || value.nil?
|
294
|
+
value
|
295
|
+
else
|
296
|
+
value.dig(*rest)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
282
300
|
# Return specific objects from the `Vector`. All overloads return `nil` if
|
283
301
|
# the starting index is out of range.
|
284
302
|
#
|
@@ -536,17 +554,9 @@ module Immutable
|
|
536
554
|
# @return [Vector]
|
537
555
|
def uniq(&block)
|
538
556
|
array = self.to_a
|
539
|
-
if
|
540
|
-
|
541
|
-
|
542
|
-
elsif array.uniq!(&block) # returns nil if no changes were made
|
543
|
-
self.class.new(array.freeze)
|
544
|
-
else
|
545
|
-
self
|
546
|
-
end
|
547
|
-
elsif array.frozen?
|
548
|
-
self.class.new(array.uniq.freeze)
|
549
|
-
elsif array.uniq! # returns nil if no changes were made
|
557
|
+
if array.frozen?
|
558
|
+
self.class.new(array.uniq(&block).freeze)
|
559
|
+
elsif array.uniq!(&block) # returns nil if no changes were made
|
550
560
|
self.class.new(array.freeze)
|
551
561
|
else
|
552
562
|
self
|
data/lib/immutable/version.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "immutable/hash"
|
3
|
+
|
4
|
+
describe Immutable::Hash do
|
5
|
+
describe "#dig" do
|
6
|
+
let(:h) { H[:a => 9, :b => H[:c => 'a', :d => 4], :e => nil] }
|
7
|
+
it "returns the value with one argument to dig" do
|
8
|
+
expect(h.dig(:a)).to eq(9)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns the value in nested hashes" do
|
12
|
+
expect(h.dig(:b, :c)).to eq('a')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns nil if the key is not present" do
|
16
|
+
expect(h.dig(:f, :foo)).to eq(nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns nil if you dig out the end of the hash" do
|
20
|
+
expect(h.dig(:f, :foo, :bar)).to eq(nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
# This is a bit different from Ruby's Hash; it raises TypeError for
|
24
|
+
# objects which don't respond to #dig
|
25
|
+
it "raises a NoMethodError if a value does not support #dig" do
|
26
|
+
expect { h.dig(:a, :foo) }.to raise_error(NoMethodError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns the correct value when there is a default proc" do
|
30
|
+
default_hash = H.new { |k, v| "#{k}-default" }
|
31
|
+
expect(default_hash.dig(:a)).to eq("a-default")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "immutable/hash"
|
3
|
+
|
4
|
+
describe Immutable::Hash do
|
5
|
+
describe "#fetch_values" do
|
6
|
+
context "when the all the requested keys exist" do
|
7
|
+
it "returns a vector of values for the given keys" do
|
8
|
+
h = H[:a => 9, :b => 'a', :c => -10, :d => nil]
|
9
|
+
h.fetch_values.should be_kind_of(Immutable::Vector)
|
10
|
+
h.fetch_values.should eql(V.empty)
|
11
|
+
h.fetch_values(:a, :d, :b).should be_kind_of(Immutable::Vector)
|
12
|
+
h.fetch_values(:a, :d, :b).should eql(V[9, nil, 'a'])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when the key does not exist" do
|
17
|
+
it "raises a KeyError" do
|
18
|
+
-> { H["A" => "aye", "C" => "Cee"].fetch_values("A", "B") }.should raise_error(KeyError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,6 +1,15 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Immutable::Hash do
|
4
|
+
describe "#[]=" do
|
5
|
+
let(:hash) { H["A" => "aye", "B" => "bee", "C" => "see"] }
|
6
|
+
|
7
|
+
it 'raises error pointing to #put' do
|
8
|
+
expect { hash[:A] = 'aye' }
|
9
|
+
.to raise_error(NoMethodError, /Immutable::Hash.*`put'/)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
4
13
|
describe "#put" do
|
5
14
|
let(:hash) { H["A" => "aye", "B" => "bee", "C" => "see"] }
|
6
15
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "immutable/hash"
|
3
|
+
|
4
|
+
describe Immutable::Hash do
|
5
|
+
describe "#<=" do
|
6
|
+
[
|
7
|
+
[{}, {}, true],
|
8
|
+
[{"A" => 1}, {}, false],
|
9
|
+
[{}, {"A" => 1}, true],
|
10
|
+
[{"A" => 1}, {"A" => 1}, true],
|
11
|
+
[{"A" => 1}, {"A" => 2}, false],
|
12
|
+
[{"B" => 2}, {"A" => 1, "B" => 2, "C" => 3}, true],
|
13
|
+
[{"A" => 1, "B" => 2, "C" => 3}, {"B" => 2}, false],
|
14
|
+
[{"B" => 0}, {"A" => 1, "B" => 2, "C" => 3}, false],
|
15
|
+
].each do |a, b, expected|
|
16
|
+
describe "for #{a.inspect} and #{b.inspect}" do
|
17
|
+
it "returns #{expected}" do
|
18
|
+
expect(H[a] <= H[b]).to eq(expected)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#<" do
|
25
|
+
[
|
26
|
+
[{}, {}, false],
|
27
|
+
[{"A" => 1}, {}, false],
|
28
|
+
[{}, {"A" => 1}, true],
|
29
|
+
[{"A" => 1}, {"A" => 1}, false],
|
30
|
+
[{"A" => 1}, {"A" => 2}, false],
|
31
|
+
[{"B" => 2}, {"A" => 1, "B" => 2, "C" => 3}, true],
|
32
|
+
[{"A" => 1, "B" => 2, "C" => 3}, {"B" => 2}, false],
|
33
|
+
[{"B" => 0}, {"A" => 1, "B" => 2, "C" => 3}, false],
|
34
|
+
].each do |a, b, expected|
|
35
|
+
describe "for #{a.inspect} and #{b.inspect}" do
|
36
|
+
it "returns #{expected}" do
|
37
|
+
expect(H[a] < H[b]).to eq(expected)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|