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
@@ -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}, {}, true],
|
9
|
+
[{}, {"A" => 1}, false],
|
10
|
+
[{"A" => 1}, {"A" => 1}, true],
|
11
|
+
[{"A" => 1}, {"A" => 2}, false],
|
12
|
+
[{"A" => 1, "B" => 2, "C" => 3}, {"B" => 2}, true],
|
13
|
+
[{"B" => 2}, {"A" => 1, "B" => 2, "C" => 3}, false],
|
14
|
+
[{"A" => 1, "B" => 2, "C" => 3}, {"B" => 0}, 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}, {}, true],
|
28
|
+
[{}, {"A" => 1}, false],
|
29
|
+
[{"A" => 1}, {"A" => 1}, false],
|
30
|
+
[{"A" => 1}, {"A" => 2}, false],
|
31
|
+
[{"A" => 1, "B" => 2, "C" => 3}, {"B" => 2}, true],
|
32
|
+
[{"B" => 2}, {"A" => 1, "B" => 2, "C" => 3}, false],
|
33
|
+
[{"A" => 1, "B" => 2, "C" => 3}, {"B" => 0}, 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
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "immutable/hash"
|
3
|
+
|
4
|
+
describe Immutable::Hash do
|
5
|
+
describe "#to_proc" do
|
6
|
+
context "on Hash without default proc" do
|
7
|
+
let(:hash) { H.new("A" => "aye") }
|
8
|
+
|
9
|
+
it "returns a Proc instance" do
|
10
|
+
hash.to_proc.should be_kind_of(Proc)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns a Proc that returns the value of an existing key" do
|
14
|
+
hash.to_proc.call("A").should == "aye"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns a Proc that returns nil for a missing key" do
|
18
|
+
hash.to_proc.call("B").should be_nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "on Hash with a default proc" do
|
23
|
+
let(:hash) { H.new("A" => "aye") { |key| "#{key}-VAL" } }
|
24
|
+
|
25
|
+
it "returns a Proc instance" do
|
26
|
+
hash.to_proc.should be_kind_of(Proc)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns a Proc that returns the value of an existing key" do
|
30
|
+
hash.to_proc.call("A").should == "aye"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns a Proc that returns the result of the hash's default proc for a missing key" do
|
34
|
+
hash.to_proc.call("B").should == "B-VAL"
|
35
|
+
hash.should == H.new("A" => "aye")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -2,12 +2,32 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Immutable::Hash do
|
4
4
|
describe "#values_at" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
context "on Hash without default proc" do
|
6
|
+
let(:hash) { H[:a => 9, :b => 'a', :c => -10, :d => nil] }
|
7
|
+
|
8
|
+
it "returns an empty vector when no keys are given" do
|
9
|
+
hash.values_at.should be_kind_of(Immutable::Vector)
|
10
|
+
hash.values_at.should eql(V.empty)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns a vector of values for the given keys" do
|
14
|
+
hash.values_at(:a, :d, :b).should be_kind_of(Immutable::Vector)
|
15
|
+
hash.values_at(:a, :d, :b).should eql(V[9, nil, 'a'])
|
16
|
+
end
|
17
|
+
|
18
|
+
it "fills nil when keys are missing" do
|
19
|
+
hash.values_at(:x, :a, :y, :b).should be_kind_of(Immutable::Vector)
|
20
|
+
hash.values_at(:x, :a, :y, :b).should eql(V[nil, 9, nil, 'a'])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "on Hash with default proc" do
|
25
|
+
let(:hash) { Immutable::Hash.new(:a => 9) { |key| "#{key}-VAL" } }
|
26
|
+
|
27
|
+
it "fills the result of the default proc when keys are missing" do
|
28
|
+
hash.values_at(:x, :a, :y).should be_kind_of(Immutable::Vector)
|
29
|
+
hash.values_at(:x, :a, :y).should eql(V['x-VAL', 9, 'y-VAL'])
|
30
|
+
end
|
11
31
|
end
|
12
32
|
end
|
13
33
|
end
|
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
describe Immutable::List do
|
4
4
|
describe "#all?" do
|
5
5
|
context "on a really big list" do
|
6
|
-
let(:list) {
|
6
|
+
let(:list) { BigList }
|
7
7
|
|
8
8
|
it "doesn't run out of stack" do
|
9
9
|
-> { list.all? }.should_not raise_error
|
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
describe Immutable::List do
|
4
4
|
describe "#any?" do
|
5
5
|
context "on a really big list" do
|
6
|
-
let(:list) {
|
6
|
+
let(:list) { BigList }
|
7
7
|
|
8
8
|
it "doesn't run out of stack" do
|
9
9
|
-> { list.any? { false } }.should_not raise_error
|
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
describe Immutable::List do
|
4
4
|
describe "#at" do
|
5
5
|
context "on a really big list" do
|
6
|
-
let(:list) {
|
6
|
+
let(:list) { BigList }
|
7
7
|
|
8
8
|
it "doesn't run out of stack" do
|
9
9
|
-> { list.at(STACK_OVERFLOW_DEPTH) }.should_not raise_error
|
@@ -90,7 +90,7 @@ describe Immutable do
|
|
90
90
|
it "realizes values as they are needed" do
|
91
91
|
# this example shows that Lists are not as lazy as they could be
|
92
92
|
# if Lists were fully lazy, you would have to take(4) to hit the exception
|
93
|
-
expect { list.take(3).to_a }.to raise_exception
|
93
|
+
expect { list.take(3).to_a }.to raise_exception(RuntimeError)
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -5,7 +5,7 @@ describe Immutable::List do
|
|
5
5
|
describe "##{method}" do
|
6
6
|
context "on a really big list" do
|
7
7
|
it "doesn't run out of stack" do
|
8
|
-
-> {
|
8
|
+
-> { BigList.send(method, 1) { |item| } }.should_not raise_error
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#each" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.each { |item| } }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#empty?" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.select(&:nil?).empty? }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#eql?" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.eql?(Immutable.interval(0, STACK_OVERFLOW_DEPTH)) }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -5,7 +5,7 @@ describe Immutable::List do
|
|
5
5
|
describe "##{method}" do
|
6
6
|
context "on a really big list" do
|
7
7
|
it "doesn't run out of stack" do
|
8
|
-
-> {
|
8
|
+
-> { BigList.send(method) { |item| false } }.should_not raise_error
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -5,7 +5,7 @@ describe Immutable::List do
|
|
5
5
|
describe "##{method}" do
|
6
6
|
context "on a really big list" do
|
7
7
|
it "doesn't run out of stack" do
|
8
|
-
-> {
|
8
|
+
-> { BigList.send(method) { false } }.should_not raise_error
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -5,7 +5,7 @@ describe Immutable::List do
|
|
5
5
|
describe "##{method}" do
|
6
6
|
context "on a really big list" do
|
7
7
|
it "doesn't run out of stack" do
|
8
|
-
-> {
|
8
|
+
-> { BigList.send(method) }.should_not raise_error
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -5,7 +5,7 @@ describe Immutable::List do
|
|
5
5
|
describe "##{method}" do
|
6
6
|
context "on a really big list" do
|
7
7
|
it "doesn't run out of stack" do
|
8
|
-
-> {
|
8
|
+
-> { BigList.send(method, nil) }.should_not raise_error
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#index" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.index(nil) }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -25,7 +25,11 @@ describe Immutable::List do
|
|
25
25
|
].each do |values, item, expected|
|
26
26
|
context "looking for #{item.inspect} in #{values.inspect}" do
|
27
27
|
it "returns #{expected.inspect}" do
|
28
|
-
|
28
|
+
if RUBY_ENGINE == 'jruby' && RUBY_VERSION <= '2.2.2' && values[0].is_a?(Fixnum) && item.is_a?(Float)
|
29
|
+
skip "On JRuby, Enumerable#find_index doesn't test equality properly"
|
30
|
+
else
|
31
|
+
L[*values].index(item).should == expected
|
32
|
+
end
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -11,7 +11,7 @@ describe Immutable::List do
|
|
11
11
|
|
12
12
|
context "on a large list which doesn't contain desired item" do
|
13
13
|
it "doesn't blow the stack" do
|
14
|
-
-> {
|
14
|
+
-> { BigList.indices { |x| x < 0 }.size }.should_not raise_error
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#inspect" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.inspect }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -3,8 +3,8 @@ require "concurrent/atomics"
|
|
3
3
|
|
4
4
|
describe Immutable::List do
|
5
5
|
it "ensures each node of a lazy list will only be realized on ONE thread, even when accessed by multiple threads" do
|
6
|
-
counter = Concurrent::
|
7
|
-
list = (1..10000).to_list.map { |x| counter.
|
6
|
+
counter = Concurrent::Atom.new(0)
|
7
|
+
list = (1..10000).to_list.map { |x| counter.swap { |count| count + 1 }; x * 2 }
|
8
8
|
|
9
9
|
threads = 10.times.collect do
|
10
10
|
Thread.new do
|
@@ -14,7 +14,7 @@ describe Immutable::List do
|
|
14
14
|
end
|
15
15
|
threads.each(&:join)
|
16
16
|
|
17
|
-
counter.
|
17
|
+
counter.value.should == 10000
|
18
18
|
list.sum.should == 100010000
|
19
19
|
end
|
20
20
|
|
@@ -44,4 +44,4 @@ describe Immutable::List do
|
|
44
44
|
elapsed = Time.now - start
|
45
45
|
elapsed.should_not > 0.3
|
46
46
|
end
|
47
|
-
end
|
47
|
+
end
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#none?" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.none? { false } }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#one?" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.one? { false } }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#product" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.product }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -5,7 +5,7 @@ describe Immutable::List do
|
|
5
5
|
describe "##{method}" do
|
6
6
|
context "on a really big list" do
|
7
7
|
it "doesn't run out of stack" do
|
8
|
-
-> {
|
8
|
+
-> { BigList.send(method, &:+) }.should_not raise_error
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#reverse" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.reverse }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -5,7 +5,7 @@ describe Immutable::List do
|
|
5
5
|
describe "##{method}" do
|
6
6
|
context "on a really big list" do
|
7
7
|
it "doesn't run out of stack" do
|
8
|
-
-> {
|
8
|
+
-> { BigList.size }.should_not raise_error
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -4,7 +4,7 @@ describe Immutable::List do
|
|
4
4
|
describe "#tail" do
|
5
5
|
context "on a really big list" do
|
6
6
|
it "doesn't run out of stack" do
|
7
|
-
-> {
|
7
|
+
-> { BigList.select(&:nil?).tail }.should_not raise_error
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|