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.
Files changed (47) hide show
  1. data/.rspec +1 -0
  2. data/.travis.yml +11 -16
  3. data/Gemfile +5 -2
  4. data/Gemfile.devtools +19 -24
  5. data/Guardfile +18 -10
  6. data/README.md +5 -28
  7. data/axiom-types.gemspec +2 -3
  8. data/config/flay.yml +2 -2
  9. data/config/flog.yml +1 -1
  10. data/config/reek.yml +15 -13
  11. data/config/rubocop.yml +62 -0
  12. data/lib/axiom/types.rb +5 -3
  13. data/lib/axiom/types/boolean.rb +4 -2
  14. data/lib/axiom/types/collection.rb +5 -2
  15. data/lib/axiom/types/encodable.rb +1 -1
  16. data/lib/axiom/types/float.rb +3 -0
  17. data/lib/axiom/types/hash.rb +8 -3
  18. data/lib/axiom/types/length_comparable.rb +7 -4
  19. data/lib/axiom/types/numeric.rb +5 -0
  20. data/lib/axiom/types/object.rb +2 -2
  21. data/lib/axiom/types/support/infinity.rb +116 -0
  22. data/lib/axiom/types/support/options.rb +9 -18
  23. data/lib/axiom/types/time.rb +2 -2
  24. data/lib/axiom/types/type.rb +13 -9
  25. data/lib/axiom/types/value_comparable.rb +5 -2
  26. data/lib/axiom/types/version.rb +1 -1
  27. data/spec/unit/axiom/types/boolean/class_methods/infer_spec.rb +6 -0
  28. data/spec/unit/axiom/types/collection/class_methods/finalize_spec.rb +3 -3
  29. data/spec/unit/axiom/types/encodable/class_methods/extended_spec.rb +8 -7
  30. data/spec/unit/axiom/types/encodable/finalize_spec.rb +30 -8
  31. data/spec/unit/axiom/types/hash/class_methods/infer_spec.rb +17 -17
  32. data/spec/unit/axiom/types/infinity/class_methods/coerce_spec.rb +64 -0
  33. data/spec/unit/axiom/types/infinity/class_methods/spaceship_operator_spec.rb +67 -0
  34. data/spec/unit/axiom/types/infinity/class_methods/succ_spec.rb +11 -0
  35. data/spec/unit/axiom/types/length_comparable/class_methods/extended_spec.rb +17 -8
  36. data/spec/unit/axiom/types/negative_infinity/class_methods/spaceship_operator_spec.rb +67 -0
  37. data/spec/unit/axiom/types/object/class_methods/coercion_method_spec.rb +2 -2
  38. data/spec/unit/axiom/types/object/class_methods/infer_spec.rb +13 -1
  39. data/spec/unit/axiom/types/object/class_methods/primitive_spec.rb +4 -4
  40. data/spec/unit/axiom/types/options/accept_options_spec.rb +12 -4
  41. data/spec/unit/axiom/types/options/inherited_spec.rb +10 -36
  42. data/spec/unit/axiom/types/type/class_methods/constraint_spec.rb +6 -11
  43. data/spec/unit/axiom/types/type/class_methods/include_predicate_spec.rb +7 -7
  44. data/spec/unit/axiom/types/type/class_methods/includes_spec.rb +2 -2
  45. data/spec/unit/axiom/types/value_comparable/class_methods/extended_spec.rb +17 -8
  46. metadata +29 -31
  47. checksums.yaml +0 -7
@@ -2,27 +2,28 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Axiom::Types::Encodable, '.extended', :if => RUBY_VERSION >= '1.9' do
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 RSpec
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 the
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', :if => RUBY_VERSION >= '1.9' do
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
- defined?(::Encoding) && Encoding.list.each do |encoding|
19
- if encoding.ascii_compatible?
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(''.force_encoding(encoding))
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(''.force_encoding(encoding))
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
- defined?(::Encoding) && Encoding.list.each do |encoding|
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(''.force_encoding(encoding))
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(''.force_encoding(encoding))
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 'when the argument is the type object' do
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 'when the argument is ::Hash' do
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 'when the argument is an empty Hash' do
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 'when the argument is an Hash with a key type and nil value' do
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 'when the argument is an Hash with a nil key and value type' do
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 'when the argument is an Hash with key and value types' do
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 'when the argument is an Hash with a key primitive and nil value' do
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 'when the argument is an Hash with a nil key and value primitive' do
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 'when the argument is an Hash with key and value primitives' do
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 'when the argument is an empty Hash' do
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 'when the argument is an Hash with a key type and nil value' do
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 'when the argument is an Hash with a nil key and value type' do
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 'when the argument is an Hash with key and value types' do
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 'when the argument is an Hash with a key primitive and nil value' do
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 'when the argument is an Hash with a nil key and value primitive' do
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 'when the argument is an Hash with key and value primitives' do
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 'when the argument is nil' do
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
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Axiom::Types::Infinity, '.succ' do
6
+ subject { object.succ }
7
+
8
+ let(:object) { described_class }
9
+
10
+ it { should be(object) }
11
+ 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 RSpec
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 the
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