axiom-types 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.travis.yml +11 -16
- data/Gemfile +5 -2
- data/Gemfile.devtools +19 -24
- data/Guardfile +18 -10
- data/README.md +5 -28
- data/axiom-types.gemspec +2 -3
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/reek.yml +15 -13
- data/config/rubocop.yml +62 -0
- data/lib/axiom/types.rb +5 -3
- data/lib/axiom/types/boolean.rb +4 -2
- data/lib/axiom/types/collection.rb +5 -2
- data/lib/axiom/types/encodable.rb +1 -1
- data/lib/axiom/types/float.rb +3 -0
- data/lib/axiom/types/hash.rb +8 -3
- data/lib/axiom/types/length_comparable.rb +7 -4
- data/lib/axiom/types/numeric.rb +5 -0
- data/lib/axiom/types/object.rb +2 -2
- data/lib/axiom/types/support/infinity.rb +116 -0
- data/lib/axiom/types/support/options.rb +9 -18
- data/lib/axiom/types/time.rb +2 -2
- data/lib/axiom/types/type.rb +13 -9
- data/lib/axiom/types/value_comparable.rb +5 -2
- data/lib/axiom/types/version.rb +1 -1
- data/spec/unit/axiom/types/boolean/class_methods/infer_spec.rb +6 -0
- data/spec/unit/axiom/types/collection/class_methods/finalize_spec.rb +3 -3
- data/spec/unit/axiom/types/encodable/class_methods/extended_spec.rb +8 -7
- data/spec/unit/axiom/types/encodable/finalize_spec.rb +30 -8
- data/spec/unit/axiom/types/hash/class_methods/infer_spec.rb +17 -17
- data/spec/unit/axiom/types/infinity/class_methods/coerce_spec.rb +64 -0
- data/spec/unit/axiom/types/infinity/class_methods/spaceship_operator_spec.rb +67 -0
- data/spec/unit/axiom/types/infinity/class_methods/succ_spec.rb +11 -0
- data/spec/unit/axiom/types/length_comparable/class_methods/extended_spec.rb +17 -8
- data/spec/unit/axiom/types/negative_infinity/class_methods/spaceship_operator_spec.rb +67 -0
- data/spec/unit/axiom/types/object/class_methods/coercion_method_spec.rb +2 -2
- data/spec/unit/axiom/types/object/class_methods/infer_spec.rb +13 -1
- data/spec/unit/axiom/types/object/class_methods/primitive_spec.rb +4 -4
- data/spec/unit/axiom/types/options/accept_options_spec.rb +12 -4
- data/spec/unit/axiom/types/options/inherited_spec.rb +10 -36
- data/spec/unit/axiom/types/type/class_methods/constraint_spec.rb +6 -11
- data/spec/unit/axiom/types/type/class_methods/include_predicate_spec.rb +7 -7
- data/spec/unit/axiom/types/type/class_methods/includes_spec.rb +2 -2
- data/spec/unit/axiom/types/value_comparable/class_methods/extended_spec.rb +17 -8
- metadata +29 -31
- checksums.yaml +0 -7
@@ -2,27 +2,28 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe Axiom::Types::Encodable, '.extended'
|
5
|
+
describe Axiom::Types::Encodable, '.extended' do
|
6
6
|
subject { object.extend(described_class) }
|
7
7
|
|
8
8
|
let(:object) { Class.new(Axiom::Types::Type) }
|
9
9
|
|
10
10
|
it 'delegates to the ancestor' do
|
11
11
|
# RSpec will reset stubbed methods after the example. A normal expectation
|
12
|
-
# causes a SystemStackError to be thrown, so we stub it first so that
|
13
|
-
# tracks the original method (if any), then we add our own stub that
|
14
|
-
# actually works, and finally when the example finishes RSpec will reset
|
15
|
-
# Module#extended method back to it's original state.
|
12
|
+
# causes a SystemStackError to be thrown, so we stub it first so that
|
13
|
+
# RSpec tracks the original method (if any), then we add our own stub that
|
14
|
+
# actually works, and finally when the example finishes RSpec will reset
|
15
|
+
# the Module#extended method back to it's original state.
|
16
16
|
Module.any_instance.stub(:extended).with(object)
|
17
17
|
|
18
18
|
delegated_ancestor = false
|
19
|
+
Module.send(:undef_method, :extended)
|
19
20
|
Module.send(:define_method, :extended) { |_| delegated_ancestor = true }
|
20
21
|
expect { subject }.to change { delegated_ancestor }.from(false).to(true)
|
21
22
|
end
|
22
23
|
|
23
24
|
it 'adds encoding method' do
|
24
|
-
expect { subject }.to change { object.respond_to?(:encoding) }
|
25
|
-
from(false).to(true)
|
25
|
+
expect { subject }.to change { object.respond_to?(:encoding) }
|
26
|
+
.from(false).to(true)
|
26
27
|
end
|
27
28
|
|
28
29
|
it 'sets the encoding default to UTF-8' do
|
@@ -2,11 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe Axiom::Types::Encodable, '#finalize'
|
5
|
+
describe Axiom::Types::Encodable, '#finalize' do
|
6
6
|
subject { object.finalize }
|
7
7
|
|
8
8
|
let(:object) { Class.new(Axiom::Types::Type).extend(described_class) }
|
9
9
|
|
10
|
+
# Test if Symbol encoding is supported
|
11
|
+
let(:symbol_encoding) do
|
12
|
+
! RUBY_PLATFORM.include?('java') && begin
|
13
|
+
encoding = Encoding::UTF_32BE
|
14
|
+
''.force_encoding(encoding).to_sym.encoding.equal?(encoding)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
10
18
|
context 'when an ascii compatible encoding (UTF-8) is used' do
|
11
19
|
it_should_behave_like 'a command method'
|
12
20
|
it_should_behave_like 'an idempotent method'
|
@@ -15,14 +23,24 @@ describe Axiom::Types::Encodable, '#finalize', :if => RUBY_VERSION >= '1.9' do
|
|
15
23
|
|
16
24
|
its(:constraint) { should be_frozen }
|
17
25
|
|
18
|
-
|
19
|
-
if encoding.
|
26
|
+
Encoding.list.each do |encoding|
|
27
|
+
if encoding.equal?(Encoding::UTF_8)
|
28
|
+
string = '𝒜wesome'.force_encoding(encoding)
|
29
|
+
it "adds a constraint that returns true for #{encoding} encoding" do
|
30
|
+
should include(string)
|
31
|
+
should include(string.to_sym) if symbol_encoding
|
32
|
+
end
|
33
|
+
elsif encoding.ascii_compatible?
|
34
|
+
string = ''.force_encoding(encoding)
|
20
35
|
it "adds a constraint that returns true for #{encoding} encoding" do
|
21
|
-
should include(
|
36
|
+
should include(string)
|
37
|
+
should include(string.to_sym) if symbol_encoding
|
22
38
|
end
|
23
39
|
else
|
40
|
+
string = ''.force_encoding(encoding)
|
24
41
|
it "adds a constraint that returns false for #{encoding} encoding" do
|
25
|
-
should_not include(
|
42
|
+
should_not include(string)
|
43
|
+
should_not include(string.to_sym) if symbol_encoding
|
26
44
|
end
|
27
45
|
end
|
28
46
|
end
|
@@ -40,14 +58,18 @@ describe Axiom::Types::Encodable, '#finalize', :if => RUBY_VERSION >= '1.9' do
|
|
40
58
|
|
41
59
|
its(:constraint) { should be_frozen }
|
42
60
|
|
43
|
-
|
61
|
+
Encoding.list.each do |encoding|
|
44
62
|
if encoding.equal?(Encoding::UTF_16BE)
|
63
|
+
string = '𝒜wesome'.force_encoding(encoding)
|
45
64
|
it "adds a constraint that returns true for #{encoding} encoding" do
|
46
|
-
should include(
|
65
|
+
should include(string)
|
66
|
+
should include(string.to_sym) if symbol_encoding
|
47
67
|
end
|
48
68
|
else
|
69
|
+
string = ''.force_encoding(encoding)
|
49
70
|
it "adds a constraint that returns false for #{encoding} encoding" do
|
50
|
-
should_not include(
|
71
|
+
should_not include(string)
|
72
|
+
should_not include(string.to_sym) if symbol_encoding
|
51
73
|
end
|
52
74
|
end
|
53
75
|
end
|
@@ -12,25 +12,25 @@ describe Axiom::Types::Hash, '.infer' do
|
|
12
12
|
context 'with Axiom::Types::Hash' do
|
13
13
|
let(:object) { described_class }
|
14
14
|
|
15
|
-
context '
|
15
|
+
context 'with a type object' do
|
16
16
|
let(:arg) { object }
|
17
17
|
|
18
18
|
it { should be(object) }
|
19
19
|
end
|
20
20
|
|
21
|
-
context '
|
21
|
+
context 'with a ::Hash' do
|
22
22
|
let(:arg) { ::Hash }
|
23
23
|
|
24
24
|
it { should be(object) }
|
25
25
|
end
|
26
26
|
|
27
|
-
context '
|
27
|
+
context 'with an empty Hash' do
|
28
28
|
let(:arg) { ::Hash[] }
|
29
29
|
|
30
30
|
it { should be(object) }
|
31
31
|
end
|
32
32
|
|
33
|
-
context '
|
33
|
+
context 'with an Hash with a key type and nil value' do
|
34
34
|
let(:arg) { ::Hash[object => nil] }
|
35
35
|
|
36
36
|
its(:ancestors) { should include(object) }
|
@@ -42,7 +42,7 @@ describe Axiom::Types::Hash, '.infer' do
|
|
42
42
|
its(:value_type) { should be(Axiom::Types::Object) }
|
43
43
|
end
|
44
44
|
|
45
|
-
context '
|
45
|
+
context 'with an Hash with a nil key and value type' do
|
46
46
|
let(:arg) { ::Hash[nil => object] }
|
47
47
|
|
48
48
|
its(:ancestors) { should include(object) }
|
@@ -54,7 +54,7 @@ describe Axiom::Types::Hash, '.infer' do
|
|
54
54
|
its(:value_type) { should be(object) }
|
55
55
|
end
|
56
56
|
|
57
|
-
context '
|
57
|
+
context 'with an Hash with key and value types' do
|
58
58
|
let(:arg) { ::Hash[object => object] }
|
59
59
|
|
60
60
|
its(:ancestors) { should include(object) }
|
@@ -66,7 +66,7 @@ describe Axiom::Types::Hash, '.infer' do
|
|
66
66
|
its(:value_type) { should be(object) }
|
67
67
|
end
|
68
68
|
|
69
|
-
context '
|
69
|
+
context 'with an Hash with a key primitive and nil value' do
|
70
70
|
let(:arg) { ::Hash[::Hash => nil] }
|
71
71
|
|
72
72
|
its(:ancestors) { should include(object) }
|
@@ -78,7 +78,7 @@ describe Axiom::Types::Hash, '.infer' do
|
|
78
78
|
its(:value_type) { should be(Axiom::Types::Object) }
|
79
79
|
end
|
80
80
|
|
81
|
-
context '
|
81
|
+
context 'with an Hash with a nil key and value primitive' do
|
82
82
|
let(:arg) { ::Hash[nil => ::Hash] }
|
83
83
|
|
84
84
|
its(:ancestors) { should include(object) }
|
@@ -90,7 +90,7 @@ describe Axiom::Types::Hash, '.infer' do
|
|
90
90
|
its(:value_type) { should be(object) }
|
91
91
|
end
|
92
92
|
|
93
|
-
context '
|
93
|
+
context 'with an Hash with key and value primitives' do
|
94
94
|
let(:arg) { ::Hash[::Hash => ::Hash] }
|
95
95
|
|
96
96
|
its(:ancestors) { should include(object) }
|
@@ -124,49 +124,49 @@ describe Axiom::Types::Hash, '.infer' do
|
|
124
124
|
it { should be(object) }
|
125
125
|
end
|
126
126
|
|
127
|
-
context '
|
127
|
+
context 'with an empty Hash' do
|
128
128
|
let(:arg) { ::Hash[] }
|
129
129
|
|
130
130
|
it { should be(object) }
|
131
131
|
end
|
132
132
|
|
133
|
-
context '
|
133
|
+
context 'with an Hash with a key type and nil value' do
|
134
134
|
let(:arg) { ::Hash[object => nil] }
|
135
135
|
|
136
136
|
it { should be_nil }
|
137
137
|
end
|
138
138
|
|
139
|
-
context '
|
139
|
+
context 'with an Hash with a nil key and value type' do
|
140
140
|
let(:arg) { ::Hash[nil => object] }
|
141
141
|
|
142
142
|
it { should be_nil }
|
143
143
|
end
|
144
144
|
|
145
|
-
context '
|
145
|
+
context 'with an Hash with key and value types' do
|
146
146
|
let(:arg) { ::Hash[object => object] }
|
147
147
|
|
148
148
|
it { should be_nil }
|
149
149
|
end
|
150
150
|
|
151
|
-
context '
|
151
|
+
context 'with an Hash with a key primitive and nil value' do
|
152
152
|
let(:arg) { ::Hash[::Hash => nil] }
|
153
153
|
|
154
154
|
it { should be_nil }
|
155
155
|
end
|
156
156
|
|
157
|
-
context '
|
157
|
+
context 'with an Hash with a nil key and value primitive' do
|
158
158
|
let(:arg) { ::Hash[nil => ::Hash] }
|
159
159
|
|
160
160
|
it { should be_nil }
|
161
161
|
end
|
162
162
|
|
163
|
-
context '
|
163
|
+
context 'with an Hash with key and value primitives' do
|
164
164
|
let(:arg) { ::Hash[::Hash => ::Hash] }
|
165
165
|
|
166
166
|
it { should be_nil }
|
167
167
|
end
|
168
168
|
|
169
|
-
context '
|
169
|
+
context 'with a nil' do
|
170
170
|
let(:arg) { nil }
|
171
171
|
|
172
172
|
it { should be_nil }
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Axiom::Types::Infinity, '.coerce' do
|
6
|
+
subject { object.coerce(other) }
|
7
|
+
|
8
|
+
let(:object) { described_class }
|
9
|
+
|
10
|
+
[
|
11
|
+
1, # Fixnum
|
12
|
+
2**63, # Bignum
|
13
|
+
1.0, # Float
|
14
|
+
Rational(1, 1), # Rational
|
15
|
+
BigDecimal('1'), # BigDecimal
|
16
|
+
].each do |number|
|
17
|
+
context "when other is a #{number.class}" do
|
18
|
+
let(:other) { number }
|
19
|
+
|
20
|
+
it 'coerces into an array containing inverse and self' do
|
21
|
+
should eql([Axiom::Types::NegativeInfinity, object])
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'coerces when comparing' do
|
25
|
+
expect(other).to be < object
|
26
|
+
expect(other).to_not be == object
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when other is a Float::INFINITY' do
|
32
|
+
let(:other) { Float::INFINITY }
|
33
|
+
|
34
|
+
it 'coerces into an array containing inverse and self' do
|
35
|
+
should eql([Axiom::Types::Infinity, object])
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'coerces when comparing' do
|
39
|
+
expect(other).to_not be < object
|
40
|
+
expect(other).to be == object
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when other is a -Float::INFINITY' do
|
45
|
+
let(:other) { -Float::INFINITY }
|
46
|
+
|
47
|
+
it 'coerces into an array containing inverse and self' do
|
48
|
+
should eql([Axiom::Types::NegativeInfinity, object])
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'coerces when comparing' do
|
52
|
+
expect(other).to be < object
|
53
|
+
expect(other).to_not be == object
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when other is not a number' do
|
58
|
+
let(:other) { 'string' }
|
59
|
+
|
60
|
+
specify do
|
61
|
+
expect { subject }.to raise_error(TypeError, 'String cannot be coerced')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Axiom::Types::Infinity, '.<=>' do
|
6
|
+
subject { object <=> other }
|
7
|
+
|
8
|
+
let(:object) { described_class }
|
9
|
+
|
10
|
+
[
|
11
|
+
1, # Fixnum
|
12
|
+
2**63, # Bignum
|
13
|
+
1.0, # Float
|
14
|
+
Rational(1, 1), # Rational
|
15
|
+
BigDecimal('1'), # BigDecimal
|
16
|
+
].each do |number|
|
17
|
+
context "when other object is a #{number.class}" do
|
18
|
+
let(:other) { number }
|
19
|
+
|
20
|
+
it { should be(1) }
|
21
|
+
|
22
|
+
it 'is symmetric' do
|
23
|
+
should be(-(other <=> object))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when the other object is negative infinity' do
|
29
|
+
let(:other) { Axiom::Types::NegativeInfinity }
|
30
|
+
|
31
|
+
it { should be(1) }
|
32
|
+
|
33
|
+
it 'is symmetric' do
|
34
|
+
should be(-(other <=> object))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when the other object is infinity' do
|
39
|
+
let(:other) { object }
|
40
|
+
|
41
|
+
it { should be(0) }
|
42
|
+
|
43
|
+
it 'is symmetric' do
|
44
|
+
should be(-(other <=> object))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when the other object is Float::INFINITY' do
|
49
|
+
let(:other) { Float::INFINITY }
|
50
|
+
|
51
|
+
it { should be(0) }
|
52
|
+
|
53
|
+
it 'is symmetric' do
|
54
|
+
should be(-(other <=> object))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when the other object is not comparable' do
|
59
|
+
let(:other) { 'string' }
|
60
|
+
|
61
|
+
it { should be_nil }
|
62
|
+
|
63
|
+
it 'is symmetric' do
|
64
|
+
should be(other <=> object)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -9,24 +9,33 @@ describe Axiom::Types::LengthComparable, '.extended' do
|
|
9
9
|
|
10
10
|
it 'delegates to the ancestor' do
|
11
11
|
# RSpec will reset stubbed methods after the example. A normal expectation
|
12
|
-
# causes a SystemStackError to be thrown, so we stub it first so that
|
13
|
-
# tracks the original method (if any), then we add our own stub that
|
14
|
-
# actually works, and finally when the example finishes RSpec will reset
|
15
|
-
# Module#extended method back to it's original state.
|
12
|
+
# causes a SystemStackError to be thrown, so we stub it first so that
|
13
|
+
# RSpec tracks the original method (if any), then we add our own stub that
|
14
|
+
# actually works, and finally when the example finishes RSpec will reset
|
15
|
+
# the Module#extended method back to it's original state.
|
16
16
|
Module.any_instance.stub(:extended).with(object)
|
17
17
|
|
18
18
|
delegated_ancestor = false
|
19
|
+
Module.send(:undef_method, :extended)
|
19
20
|
Module.send(:define_method, :extended) { |_| delegated_ancestor = true }
|
20
21
|
expect { subject }.to change { delegated_ancestor }.from(false).to(true)
|
21
22
|
end
|
22
23
|
|
23
24
|
it 'adds minimum_length method' do
|
24
|
-
expect { subject }.to change { object.respond_to?(:minimum_length) }
|
25
|
-
from(false).to(true)
|
25
|
+
expect { subject }.to change { object.respond_to?(:minimum_length) }
|
26
|
+
.from(false).to(true)
|
26
27
|
end
|
27
28
|
|
28
29
|
it 'adds maxumum_length method' do
|
29
|
-
expect { subject }.to change { object.respond_to?(:maximum_length) }
|
30
|
-
from(false).to(true)
|
30
|
+
expect { subject }.to change { object.respond_to?(:maximum_length) }
|
31
|
+
.from(false).to(true)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'sets the default minimum_length' do
|
35
|
+
expect(subject.minimum_length).to equal(Axiom::Types::Infinity)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'sets the default maximum_length' do
|
39
|
+
expect(subject.maximum_length).to equal(Axiom::Types::NegativeInfinity)
|
31
40
|
end
|
32
41
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Axiom::Types::NegativeInfinity, '.<=>' do
|
6
|
+
subject { object <=> other }
|
7
|
+
|
8
|
+
let(:object) { described_class }
|
9
|
+
|
10
|
+
[
|
11
|
+
1, # Fixnum
|
12
|
+
2**63, # Bignum
|
13
|
+
1.0, # Float
|
14
|
+
Rational(1, 1), # Rational
|
15
|
+
BigDecimal('1'), # BigDecimal
|
16
|
+
].each do |number|
|
17
|
+
context "when other object is a #{number.class}" do
|
18
|
+
let(:other) { number }
|
19
|
+
|
20
|
+
it { should be(-1) }
|
21
|
+
|
22
|
+
it 'is symmetric' do
|
23
|
+
should be(-(other <=> object))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when the other object is infinity' do
|
29
|
+
let(:other) { Axiom::Types::Infinity }
|
30
|
+
|
31
|
+
it { should be(-1) }
|
32
|
+
|
33
|
+
it 'is symmetric' do
|
34
|
+
should be(-(other <=> object))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when the other object is negative infinity' do
|
39
|
+
let(:other) { object }
|
40
|
+
|
41
|
+
it { should be(0) }
|
42
|
+
|
43
|
+
it 'is symmetric' do
|
44
|
+
should be(other <=> object)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when the other object is -Float::INFINITY' do
|
49
|
+
let(:other) { -Float::INFINITY }
|
50
|
+
|
51
|
+
it { should be(0) }
|
52
|
+
|
53
|
+
it 'is symmetric' do
|
54
|
+
should be(other <=> object)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when the other object is not comparable' do
|
59
|
+
let(:other) { 'string' }
|
60
|
+
|
61
|
+
it { should be_nil }
|
62
|
+
|
63
|
+
it 'is symmetric' do
|
64
|
+
should be(other <=> object)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|