axiom-types 0.0.2 → 0.0.3
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/.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
|