type 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ ---
2
+ language: ruby
3
+ script: "bundle exec rake spec"
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.0
8
+ - jruby-19mode
9
+ - rbx
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Next release (TBD)
4
4
 
5
+ ## 0.2.0 (2014-02-01)
6
+
7
+ - Improve Type::Boolean to cast truthy and falsy objects to true and false.
8
+ - Improve exception message when casting an out-of-range integer via one of
9
+ the range-limited Integer type definitions (e.g., Int32)
10
+ - Improve performance when casting already-valid objects.
11
+ - Fixed tests for JRuby and Type::Int64
12
+ - Fixed Type::Hash to make it less surprising on Ruby 2+ via `Kernel::Hash()`
13
+
5
14
  ## 0.1.0 (2014-01-29)
6
15
 
7
16
  - Initial Implementation
@@ -1,6 +1,6 @@
1
1
  # Contributing
2
2
 
3
- `Type` is [Apache-liennsed](LICENSE.txt).
3
+ `Type` is [Apache-licensed](LICENSE.txt).
4
4
 
5
5
  ## Git-Flow
6
6
 
data/Gemfile CHANGED
@@ -2,5 +2,12 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
+ platforms :rbx do
6
+ # These are the ruby standard library dependencies
7
+ gem 'rubysl-irb'
8
+ gem 'rubysl-singleton'
9
+ gem 'rubysl-set'
10
+ end
11
+
5
12
  # Gem dependencies are specified in the gemspec
6
13
  gemspec
data/README.md CHANGED
@@ -37,6 +37,12 @@ Type::Int32!(input) # alias for Type::Int32.cast!(input)
37
37
  `Type` comes with a variety of built-in type defintions, which can be used for
38
38
  validation or casting.
39
39
 
40
+ - [Scalar](#scalar-type-definitions)
41
+ - [Nilable Modifier](#nilable-type-definitions)
42
+ - [Collection](#collection-type-definitions)
43
+ - [Constrained Collections](#constrained-collection-type-definitions)
44
+ - [Nilable Constrained Collections](#nilable-constrained-collection-type-definitions)
45
+
40
46
  ### Scalar Type Definitions:
41
47
 
42
48
  The most basic type definitions are scalar
@@ -63,6 +69,21 @@ Type::Int32!('three')
63
69
  #! Type::CastError: Could not cast "three"(String) with Type::Int32
64
70
  ~~~
65
71
 
72
+ The complete list of built-in scalar type definitions is:
73
+
74
+ ~~~ ruby
75
+ Type::Integer # {x∈ℤ}
76
+ Type::Int32 # {x∈ℤ|[-2^31,2^31)}
77
+ Type::Int64 # {x∈ℤ|[-2^63,2^63)}
78
+ Type::UInt32 # {x∈ℕ|[0,2^32)}
79
+ Type::UInt64 # {x∈ℕ|[0,2^64)}
80
+ Type::Float # {x∈ℝ,+∞,-∞}
81
+ Type::Float32 # {x∈ℝ}
82
+ Type::Float64 # {x∈ℝ}
83
+ Type::Boolean # {true,false}
84
+ Type::String # any string
85
+ ~~~
86
+
66
87
  ### Nilable Type Definitions:
67
88
 
68
89
  Any `Type::Definition` can be declared nilable -- that is, it will report `nil`
@@ -109,6 +130,14 @@ Type::Set!('foo')
109
130
  #! Type::CastError: Could not cast "foo"(String) with Type::Set
110
131
  ~~~
111
132
 
133
+ The complete list of built-in collection type definitions is:
134
+
135
+ ~~~ ruby
136
+ Type::Array
137
+ Type::Set
138
+ Type::Hash
139
+ ~~~
140
+
112
141
  ### Constrained Collection Type Definitions:
113
142
 
114
143
  The real power of type-casting collections is when their contents can also be
@@ -1,111 +1,4 @@
1
1
  # encoding: utf-8
2
2
 
3
- # The built-in types are defined here.
4
- module Type
5
- scalar(:Integer) do
6
- validate do |input|
7
- input.kind_of?(::Integer)
8
- end
9
- cast do |input|
10
- Kernel::Integer(input)
11
- end
12
- end
13
-
14
- scalar(:Int32).from(:Integer) do
15
- int32_range = (-(1 << 31) ... (1 << 31))
16
- validate do |input|
17
- int32_range.include?(input)
18
- end
19
- end
20
-
21
- scalar(:Int64).from(:Integer) do
22
- int64_range = (-(1 << 63) ... (1 << 63))
23
- validate do |input|
24
- int64_range.include?(input)
25
- end
26
- end
27
-
28
- scalar(:UInt32).from(:Integer) do
29
- int32_range = (0 ... (1 << 32))
30
- validate do |input|
31
- int32_range.include?(input)
32
- end
33
- end
34
-
35
- scalar(:UInt64).from(:Integer) do
36
- int64_range = (0 ... (1 << 64))
37
- validate do |input|
38
- int64_range.include?(input)
39
- end
40
- end
41
-
42
- scalar(:Float) do
43
- validate do |input|
44
- input.kind_of?(::Float)
45
- end
46
- cast do |input|
47
- Kernel::Float(input)
48
- end
49
- end
50
-
51
- scalar(:Float32).from(:Float) do
52
- validate do |input|
53
- input.finite?
54
- end
55
- end
56
-
57
- scalar(:Float64).from(:Float) do
58
- validate do |input|
59
- input.finite?
60
- end
61
- end
62
-
63
- scalar(:Boolean) do
64
- require 'set'
65
- booleans = Set.new([true, false])
66
- validate do |input|
67
- booleans.include?(input)
68
- end
69
- end
70
-
71
- scalar(:String) do
72
- validate do |input|
73
- input.kind_of?(::String)
74
- end
75
- cast do |input|
76
- Kernel::String(input)
77
- end
78
- end
79
-
80
- collection(:Array) do
81
- validate do |input|
82
- input.kind_of?(::Array)
83
- end
84
- cast do |input|
85
- Kernel::Array(input)
86
- end
87
- end
88
-
89
- collection(:Hash) do
90
- validate do |input|
91
- input.kind_of?(::Hash)
92
- end
93
- cast do |input|
94
- if Kernel.respond_to?(:Hash)
95
- Kernel::Hash(input)
96
- else
97
- ::Hash[input]
98
- end
99
- end
100
- end
101
-
102
- collection(:Set) do
103
- require 'set'
104
- validate do |input|
105
- input.kind_of?(::Set)
106
- end
107
- cast do |input|
108
- ::Set.new(input)
109
- end
110
- end
111
- end
3
+ require 'type/builtin/scalar'
4
+ require 'type/builtin/collection'
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ # The built-in collection types are defined here.
4
+ module Type
5
+ collection(:Array) do
6
+ validate do |input|
7
+ input.kind_of?(::Array)
8
+ end
9
+ cast do |input|
10
+ Kernel::Array(input)
11
+ end
12
+ end
13
+
14
+ collection(:Hash) do
15
+ validate do |input|
16
+ input.kind_of?(::Hash)
17
+ end
18
+
19
+ cast_1_9 = proc do |input|
20
+ ::Hash[input]
21
+ end
22
+
23
+ cast_2_0 = proc do |input|
24
+ begin
25
+ Kernel::Hash(input)
26
+ rescue TypeError
27
+ cast_1_9[input]
28
+ end
29
+ end
30
+
31
+ cast do |input|
32
+ if Kernel.respond_to?(:Hash)
33
+ cast_2_0[input]
34
+ else
35
+ cast_1_9[input]
36
+ end
37
+ end
38
+ end
39
+
40
+ collection(:Set) do
41
+ require 'set'
42
+ validate do |input|
43
+ input.kind_of?(::Set)
44
+ end
45
+ cast do |input|
46
+ ::Set.new(input)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,95 @@
1
+ # encoding: utf-8
2
+
3
+ # The built-in scalar types are defined here.
4
+ module Type
5
+ scalar(:Integer) do
6
+ validate do |input|
7
+ input.kind_of?(::Integer)
8
+ end
9
+ cast do |input|
10
+ Kernel::Integer(input)
11
+ end
12
+ end
13
+
14
+ scalar(:Int32).from(:Integer) do
15
+ int32_range = (-(1 << 31) ... (1 << 31))
16
+ validate do |input|
17
+ unless int32_range.include?(input)
18
+ raise RangeError.new("#{input} not in #{int32_range}")
19
+ end
20
+ true
21
+ end
22
+ end
23
+
24
+ scalar(:Int64).from(:Integer) do
25
+ int64_range = (-(1 << 63) ... (1 << 63))
26
+ validate do |input|
27
+ unless int64_range.include?(input)
28
+ raise RangeError.new("#{input} not in #{int64_range}")
29
+ end
30
+ true
31
+ end
32
+ end
33
+
34
+ scalar(:UInt32).from(:Integer) do
35
+ uint32_range = (0 ... (1 << 32))
36
+ validate do |input|
37
+ unless uint32_range.include?(input)
38
+ raise RangeError.new("#{input} not in #{uint32_range}")
39
+ end
40
+ true
41
+ end
42
+ end
43
+
44
+ scalar(:UInt64).from(:Integer) do
45
+ uint64_range = (0 ... (1 << 64))
46
+ validate do |input|
47
+ unless uint64_range.include?(input)
48
+ raise RangeError.new("#{input} not in #{uint64_range}")
49
+ end
50
+ true
51
+ end
52
+ end
53
+
54
+ scalar(:Float) do
55
+ validate do |input|
56
+ input.kind_of?(::Float)
57
+ end
58
+ cast do |input|
59
+ Kernel::Float(input)
60
+ end
61
+ end
62
+
63
+ scalar(:Float32).from(:Float) do
64
+ validate do |input|
65
+ input.finite?
66
+ end
67
+ end
68
+
69
+ scalar(:Float64).from(:Float) do
70
+ validate do |input|
71
+ input.finite?
72
+ end
73
+ end
74
+
75
+ scalar(:Boolean) do
76
+ require 'set'
77
+ booleans = Set.new([true, false])
78
+ validate do |input|
79
+ booleans.include?(input)
80
+ end
81
+ cast do |input|
82
+ input ? true : false
83
+ end
84
+ end
85
+
86
+ scalar(:String) do
87
+ validate do |input|
88
+ input.kind_of?(::String)
89
+ end
90
+ cast do |input|
91
+ raise TypeError if input.nil?
92
+ Kernel::String(input)
93
+ end
94
+ end
95
+ end
@@ -89,10 +89,12 @@ module Type
89
89
  attr_reader :name
90
90
 
91
91
  # @param input [Object]
92
+ # @param squash_exceptions [Boolean] (true)
92
93
  # @return [Boolean]
93
- def valid?(input)
94
+ def valid?(input, squash_exceptions = true)
94
95
  validators.all? { |proc| proc[input] }
95
- rescue
96
+ rescue Exception
97
+ raise unless squash_exceptions
96
98
  false
97
99
  end
98
100
 
@@ -100,12 +102,11 @@ module Type
100
102
  # @return [Object] the result of casting, guaranteed to be valid.
101
103
  # @raise [Type::CastError]
102
104
  def cast!(input)
103
- input = yield if block_given?
104
- raise CastError.new(input, self) if input.nil?
105
+ return input if valid?(input)
105
106
  castors.reduce(input) do |intermediate, castor|
106
107
  castor[intermediate]
107
108
  end.tap do |output|
108
- raise ValidationError.new(output, self) unless valid?(output)
109
+ raise ValidationError.new(output, self) unless valid?(output, false)
109
110
  end
110
111
  rescue
111
112
  raise CastError.new(input, self)
@@ -17,7 +17,7 @@ module Type
17
17
  class Collection
18
18
  include Definition
19
19
 
20
- def valid?(input, &block)
20
+ def valid?(input, *args, &block)
21
21
  return false unless input.kind_of?(Enumerable)
22
22
  super
23
23
  end
@@ -25,7 +25,7 @@ module Type
25
25
  end
26
26
 
27
27
  # Returns true if input is nil *or* the input is valid
28
- def valid?(input)
28
+ def valid?(input, *args)
29
29
  input.nil? || super
30
30
  end
31
31
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Type
4
4
  # The Type gem is semantically versioned.
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.0'
6
6
  end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec::Matchers.define(:cast) do |input|
4
+ match do |definition|
5
+ begin
6
+ @actual = definition.cast!(input)
7
+ if @chained
8
+ failure_message_for_should do
9
+ "Expected result to be #{@expected.inspect}(#{@expected.class}) " +
10
+ "but got #{@actual.inspect}(#{@actual.class}) instead"
11
+ end
12
+ @expected == @actual
13
+ else
14
+ true
15
+ end
16
+ rescue Type::CastError => cast_error
17
+ failure_message_for_should do
18
+ "#{definition} failed to cast #{input.inspect}(#{input.class}) " +
19
+ "by raising #{cast_error}(#{cast_error.cause})."
20
+ end
21
+ false
22
+ end
23
+ end
24
+
25
+ description do
26
+ "cast #{input.inspect}(#{input.class})"
27
+ end
28
+
29
+ chain(:to) do |expected|
30
+ description do
31
+ "cast #{input.inspect}(#{input.class}) to #{expected.inspect}(#{expected.class})"
32
+ end
33
+ @chained = true
34
+ @expected = expected
35
+ end
36
+
37
+ chain(:unchanged) do
38
+ description do
39
+ "cast #{input.inspect}(#{input.class}) unchanged"
40
+ end
41
+ @chained = true
42
+ @expected = input
43
+ end
44
+ end
45
+
46
+ RSpec::Matchers.define :validate do |input|
47
+ match do |definition|
48
+ definition.valid?(input)
49
+ end
50
+ description do
51
+ "validate #{input.inspect}(#{input.class})"
52
+ end
53
+ end
54
+
55
+ shared_examples_for 'Type::Definition::Nilable compatibility' do
56
+ context 'when nilable' do
57
+ subject { described_class.nilable }
58
+ it { should be_a_kind_of Type::Definition::Nilable }
59
+ it { should be_nilable }
60
+ it { should cast(nil).to(nil) }
61
+ it { should validate(nil) }
62
+ end
63
+ it { should_not be_a_kind_of Type::Definition::Nilable }
64
+ it { should_not be_nilable }
65
+ it { should_not validate(nil) }
66
+ end
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+ require 'type'
3
+
4
+ require_relative '../../spec_helper'
5
+
6
+ describe Type::Array do
7
+ its(:to_s) { should match(/Type::Array/) }
8
+ it { should_not cast(nil) }
9
+ it { should be_a_kind_of Type::Definition::Collection }
10
+ it { should validate(['asdf']) }
11
+ it { should cast(['foo']).unchanged }
12
+ it { should cast(['asdf', 1]).unchanged }
13
+ end
14
+
15
+ describe Type::Array.of(:String) do
16
+ its(:to_s) { should match(/Type::Array\(.*String.*\)/) }
17
+ it { should_not cast(nil) }
18
+ it { should be_a_kind_of Type::Definition::Collection::Constrained }
19
+ it { should validate(['asdf']) }
20
+ it { should_not validate([nil, 'asdf']) }
21
+ it { should_not validate([:asdf]) }
22
+ it { should cast([:abc, 1]).to(['abc', '1']) }
23
+ it { should_not cast([nil, 1]) }
24
+ end
25
+
26
+ describe Type::Array.of(:String?) do
27
+ it { should be_a_kind_of Type::Definition::Collection::Constrained }
28
+ it { should_not cast(nil) }
29
+ it { should validate(['asdf']) }
30
+ it { should validate([nil, 'asdf']) }
31
+ it { should_not validate([:asdf]) }
32
+ it { should cast([:abc, 1]).to(['abc', '1']) }
33
+ it { should cast([nil, 1]).to([nil, '1']) }
34
+ end
35
+
36
+ describe Type::Hash do
37
+ its(:to_s) { should match(/Type::Hash/) }
38
+ it { should_not cast(nil) }
39
+ it { should cast([[1, 2], [3, 4]]).to(1 => 2, 3 => 4) }
40
+ it { should_not cast(17) }
41
+ end
42
+
43
+ describe Type::Hash.of(:String => :Integer) do
44
+ its(:to_s) { should match(/Type::Hash\(.*String.*Integer.*\)/) }
45
+ it { should_not cast(nil) }
46
+ it { should be_a_kind_of Type::Definition::Collection::Constrained }
47
+ it { should validate('foo' => 12) }
48
+ it { should_not validate(foo: 12) }
49
+ it { should_not validate('foo' => '12') }
50
+ it { should cast('foo' => '12', :bar => 3).to('foo' => 12, 'bar' => 3) }
51
+ it { should cast('foo' => 12, 'bar' => 3).unchanged }
52
+ it { should cast([['12', 34], [56, '78']]).to('12' => 34, '56' => 78) }
53
+ it { should_not cast('foo' => 'foo') }
54
+ end
55
+
56
+ describe Type::Set do
57
+ it { should_not cast(nil) }
58
+ it { should_not validate([123, 456]) }
59
+ it { should validate(Set.new([123, 456])) }
60
+ it { should_not validate(17) }
61
+ it { should cast([123, 456]).to(Set.new([123, 456])) }
62
+ it { should cast(Set.new([123, 456])).to(Set.new([123, 456])) }
63
+ it { should_not cast(17) }
64
+ end
65
+
66
+ describe Type::Set.of(:Integer) do
67
+ its(:to_s) { should match(/Type::Set(.*Integer.*)/) }
68
+ it { should_not cast(nil) }
69
+ it { should validate(Set.new([1, 2, 3, 4])) }
70
+ it { should_not validate([1, 2, 3, 4]) }
71
+ it { should cast(Set.new([1, 2, 3, 4])).unchanged }
72
+ it { should cast([1, 2, 3, 4]).to(Set.new([1, 2, 3, 4])) }
73
+ end
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+ require 'type'
3
+
4
+ require_relative '../../spec_helper'
5
+
6
+ shared_examples_for 'Type::Definition::Scalar' do
7
+ include_examples 'Type::Definition::Nilable compatibility'
8
+ it { should be_a_kind_of Type::Definition }
9
+ it { should be_a_kind_of Type::Definition::Scalar }
10
+ end
11
+
12
+ shared_examples_for 'Type::Integer' do
13
+ it_should_behave_like 'Type::Definition::Scalar'
14
+ it { should_not cast(nil) }
15
+
16
+ it { should cast(414).unchanged }
17
+ it { should cast('123').to(123) }
18
+ it { should cast(456).to(456) }
19
+ it { should cast(Math::PI).to(3) } # alabama ftw
20
+
21
+ it { should_not cast('not a number') }
22
+ it { should_not cast(Hash.new) }
23
+
24
+ it { should validate(123) }
25
+ it { should_not validate('123') }
26
+ end
27
+
28
+ describe Type::Integer do
29
+ it_should_behave_like 'Type::Integer'
30
+ end
31
+
32
+ shared_examples_for 'bounded Type::Integer' do
33
+ it_should_behave_like 'Type::Integer'
34
+
35
+ let(:range_max) { valid_range.end - (valid_range.exclude_end? ? 1 : 0) }
36
+ let(:range_min) { valid_range.begin }
37
+
38
+ it { should cast(range_max).unchanged }
39
+ it { should cast(range_min).unchanged }
40
+
41
+ it { should_not cast(range_max + 1) }
42
+ it { should_not cast(range_min - 1) }
43
+
44
+ it { should validate(range_max) }
45
+ it { should_not validate(range_max + 1) }
46
+ it { should validate(range_min) }
47
+ it { should_not validate(range_min - 1) }
48
+ end
49
+
50
+ describe Type::Int32 do
51
+ let(:valid_range) { (-1 << 31)...(1 << 31) }
52
+ it_should_behave_like 'bounded Type::Integer'
53
+ end
54
+
55
+ describe Type::Int64 do
56
+ let(:valid_range) { (-1 << 63)...(1 << 63) }
57
+ it_should_behave_like 'bounded Type::Integer'
58
+ end
59
+
60
+ describe Type::UInt32 do
61
+ let(:valid_range) { 0...(1 << 32) }
62
+ it_should_behave_like 'bounded Type::Integer'
63
+ end
64
+
65
+ describe Type::UInt64 do
66
+ let(:valid_range) { 0...(1 << 64) }
67
+ it_should_behave_like 'bounded Type::Integer'
68
+ end
69
+
70
+ describe Type::Boolean do
71
+ it_should_behave_like 'Type::Definition::Scalar'
72
+ it { should validate true }
73
+ it { should validate false }
74
+ it { should_not validate nil }
75
+ it { should_not validate 'true' }
76
+ it { should_not validate 'false' }
77
+ it { should cast(true).unchanged }
78
+ it { should cast(false).unchanged }
79
+ it { should cast(nil).to(false) }
80
+ it { should cast(Object.new).to(true) }
81
+ end
82
+
83
+ shared_examples_for 'Type::Float' do
84
+ it_should_behave_like 'Type::Definition::Scalar'
85
+ it { should_not cast(nil) }
86
+ it { should cast(10).to(10.0) }
87
+ it { should cast(12.3).unchanged }
88
+ it { should cast('12.3').to(12.3) }
89
+ it { should cast('123e-1').to(12.3) }
90
+ it { should cast('12.3e10').to(123000000000.0) }
91
+ it { should cast('123e10').to(1230000000000.0) }
92
+ it { should_not cast('a string') }
93
+ it { should_not cast(Hash.new) }
94
+ it { should validate(12.3) }
95
+ it { should_not validate(12) }
96
+ end
97
+
98
+ describe Type::Float do
99
+ include_examples 'Type::Float'
100
+ it { should validate(Float::INFINITY) }
101
+ it { should validate(-Float::INFINITY) }
102
+ end
103
+
104
+ describe Type::Float32 do
105
+ include_examples 'Type::Float'
106
+ it { should_not validate(Float::INFINITY) }
107
+ it { should_not validate(-Float::INFINITY) }
108
+ end
109
+
110
+ describe Type::Float64 do
111
+ include_examples 'Type::Float'
112
+ it { should_not validate(Float::INFINITY) }
113
+ it { should_not validate(-Float::INFINITY) }
114
+ end
115
+
116
+ describe Type::String do
117
+ its(:to_s) { should match(/Type::String/) }
118
+ it { should_not cast(nil) }
119
+ it_should_behave_like 'Type::Definition::Scalar'
120
+ it { should cast(:abc).to('abc') }
121
+ end
@@ -1,6 +1,8 @@
1
1
  # encoding: utf-8
2
2
  require 'type'
3
3
 
4
+ require_relative '../spec_helper'
5
+
4
6
  Proc.const_set(:IDENTITY, ->(x) { x }) unless defined?(Proc::IDENTITY)
5
7
 
6
8
  describe Type::Definition do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: type
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-29 00:00:00.000000000 Z
12
+ date: 2014-02-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -101,6 +101,7 @@ extra_rdoc_files: []
101
101
  files:
102
102
  - .githooks/pre-commit/ruby-appraiser
103
103
  - .gitignore
104
+ - .travis.yml
104
105
  - CHANGELOG.md
105
106
  - CONTRIBUTING.md
106
107
  - Gemfile
@@ -109,6 +110,8 @@ files:
109
110
  - Rakefile
110
111
  - lib/type.rb
111
112
  - lib/type/builtin.rb
113
+ - lib/type/builtin/collection.rb
114
+ - lib/type/builtin/scalar.rb
112
115
  - lib/type/definition.rb
113
116
  - lib/type/definition/collection.rb
114
117
  - lib/type/definition/collection/constrained.rb
@@ -117,7 +120,9 @@ files:
117
120
  - lib/type/definition/scalar.rb
118
121
  - lib/type/error.rb
119
122
  - lib/type/version.rb
120
- - spec/type/builtin_spec.rb
123
+ - spec/spec_helper.rb
124
+ - spec/type/builtin/collection_spec.rb
125
+ - spec/type/builtin/scalar_spec.rb
121
126
  - spec/type/definition_spec.rb
122
127
  - type.gemspec
123
128
  homepage: https://github.com/simplymeasured/type-gem
@@ -146,6 +151,8 @@ signing_key:
146
151
  specification_version: 3
147
152
  summary: Type validation and Type casting
148
153
  test_files:
149
- - spec/type/builtin_spec.rb
154
+ - spec/spec_helper.rb
155
+ - spec/type/builtin/collection_spec.rb
156
+ - spec/type/builtin/scalar_spec.rb
150
157
  - spec/type/definition_spec.rb
151
158
  has_rdoc:
@@ -1,242 +0,0 @@
1
- # encoding: utf-8
2
- require 'type'
3
-
4
- RSpec::Matchers.define(:cast) do |input|
5
- match do |definition|
6
- begin
7
- @actual = definition.cast!(input)
8
- if @chained
9
- failure_message_for_should do
10
- "Expected result to be #{@expected.inspect}(#{@expected.class}) " +
11
- "but got #{@actual.inspect}(#{@actual.class}) instead"
12
- end
13
- @expected == @actual
14
- else
15
- true
16
- end
17
- rescue Type::CastError => cast_error
18
- failure_message_for_should do
19
- "#{definition} failed to cast #{input.inspect}(#{input.class}) " +
20
- "by raising #{cast_error}(#{cast_error.cause})."
21
- end
22
- false
23
- end
24
- end
25
-
26
- description do
27
- "cast #{input.inspect}(#{input.class})"
28
- end
29
-
30
- chain(:to) do |expected|
31
- description do
32
- "cast #{input.inspect}(#{input.class}) to #{expected.inspect}(#{expected.class})"
33
- end
34
- @chained = true
35
- @expected = expected
36
- end
37
-
38
- chain(:unchanged) do
39
- description do
40
- "cast #{input.inspect}(#{input.class}) unchanged"
41
- end
42
- @chained = true
43
- @expected = input
44
- end
45
- end
46
-
47
- RSpec::Matchers.define :validate do |input|
48
- match do |definition|
49
- definition.valid?(input)
50
- end
51
- description do
52
- "validate #{input.inspect}(#{input.class})"
53
- end
54
- end
55
-
56
- shared_examples_for 'Type::Definition::Nilable compatibility' do
57
- context 'when nilable' do
58
- subject { described_class.nilable }
59
- it { should be_a_kind_of Type::Definition::Nilable }
60
- it { should be_nilable }
61
- it { should cast(nil).to(nil) }
62
- it { should validate(nil) }
63
- it { should_not cast(Object.new) unless described_class == Type::String }
64
- end
65
- it { should_not be_a_kind_of Type::Definition::Nilable }
66
- it { should_not be_nilable }
67
- it { should_not cast(nil) }
68
- it { should_not validate(nil) }
69
- it { should_not cast(Object.new) unless described_class == Type::String }
70
- end
71
-
72
- shared_examples_for 'Type::Definition::Scalar' do
73
- include_examples 'Type::Definition::Nilable compatibility'
74
- it { should be_a_kind_of Type::Definition }
75
- it { should be_a_kind_of Type::Definition::Scalar }
76
- end
77
-
78
- shared_examples_for 'Type::Integer' do
79
- it_should_behave_like 'Type::Definition::Scalar'
80
-
81
- it { should cast(414).unchanged }
82
- it { should cast('123').to(123) }
83
- it { should cast(456).to(456) }
84
- it { should cast(Math::PI).to(3) } # alabama ftw
85
-
86
- it { should_not cast('not a number') }
87
- it { should_not cast(Hash.new) }
88
-
89
- it { should validate(123) }
90
- it { should_not validate('123') }
91
- end
92
-
93
- shared_examples_for 'bounded Type::Integer' do
94
- it_should_behave_like 'Type::Integer'
95
-
96
- let(:range_max) { valid_range.end - (valid_range.exclude_end? ? 1 : 0) }
97
- let(:range_min) { valid_range.begin }
98
-
99
- it { should cast(range_max).unchanged }
100
- it { should cast(range_min).unchanged }
101
-
102
- it { should_not cast(range_max.next) }
103
- it { should_not cast(range_min.pred) }
104
-
105
- it { should validate(range_max) }
106
- it { should_not validate(range_max.next) }
107
- end
108
-
109
- describe Type::Integer do
110
- it_should_behave_like 'Type::Integer'
111
- end
112
-
113
- describe Type::Int32 do
114
- let(:valid_range) { (-1 << 31)...(1 << 31) }
115
- it_should_behave_like 'bounded Type::Integer'
116
- end
117
-
118
- describe Type::Int64 do
119
- let(:valid_range) { (-1 << 63)...(1 << 63) }
120
- it_should_behave_like 'bounded Type::Integer'
121
- end
122
-
123
- describe Type::UInt32 do
124
- let(:valid_range) { 0...(1 << 32) }
125
- it_should_behave_like 'bounded Type::Integer'
126
- end
127
-
128
- describe Type::UInt64 do
129
- let(:valid_range) { 0...(1 << 64) }
130
- it_should_behave_like 'bounded Type::Integer'
131
- end
132
-
133
- describe Type::Boolean do
134
- it_should_behave_like 'Type::Definition::Scalar'
135
- it { should validate true }
136
- it { should validate false }
137
- it { should_not validate nil }
138
- it { should_not validate 'true' }
139
- it { should_not validate 'false' }
140
- it { should cast(true).unchanged }
141
- it { should cast(false).unchanged }
142
- end
143
-
144
- shared_examples_for 'Type::Float' do
145
- it_should_behave_like 'Type::Definition::Scalar'
146
- it { should cast(10).to(10.0) }
147
- it { should cast(12.3).unchanged }
148
- it { should cast('12.3').to(12.3) }
149
- it { should cast('123e-1').to(12.3) }
150
- it { should cast('12.3e10').to(123000000000.0) }
151
- it { should cast('123e10').to(1230000000000.0) }
152
- it { should_not cast('a string') }
153
- it { should_not cast(Hash.new) }
154
- it { should validate(12.3) }
155
- it { should_not validate(12) }
156
- end
157
-
158
- describe Type::Float do
159
- include_examples 'Type::Float'
160
- it { should validate(Float::INFINITY) }
161
- it { should validate(-Float::INFINITY) }
162
- end
163
-
164
- describe Type::Float32 do
165
- include_examples 'Type::Float'
166
- it { should_not validate(Float::INFINITY) }
167
- it { should_not validate(-Float::INFINITY) }
168
- end
169
-
170
- describe Type::Float64 do
171
- include_examples 'Type::Float'
172
- it { should_not validate(Float::INFINITY) }
173
- it { should_not validate(-Float::INFINITY) }
174
- end
175
-
176
- describe Type::String do
177
- its(:to_s) { should match(/Type::String/) }
178
- it_should_behave_like 'Type::Definition::Scalar'
179
- it { should cast(:abc).to('abc') }
180
- end
181
-
182
- describe Type::Array do
183
- its(:to_s) { should match(/Type::Array/) }
184
- it { should be_a_kind_of Type::Definition::Collection }
185
- it { should validate(['asdf']) }
186
- it { should cast(['foo']).unchanged }
187
- it { should cast(['asdf', 1]).unchanged }
188
- end
189
-
190
- describe Type::Array.of(:String) do
191
- its(:to_s) { should match(/Type::Array\(.*String.*\)/) }
192
- it { should be_a_kind_of Type::Definition::Collection::Constrained }
193
- it { should validate(['asdf']) }
194
- it { should_not validate([nil, 'asdf']) }
195
- it { should_not validate([:asdf]) }
196
- it { should cast([:abc, 1]).to(['abc', '1']) }
197
- it { should_not cast([nil, 1]) }
198
- end
199
-
200
- describe Type::Array.of(:String?) do
201
- it { should be_a_kind_of Type::Definition::Collection::Constrained }
202
- it { should validate(['asdf']) }
203
- it { should validate([nil, 'asdf']) }
204
- it { should_not validate([:asdf]) }
205
- it { should cast([:abc, 1]).to(['abc', '1']) }
206
- it { should cast([nil, 1]).to([nil, '1']) }
207
- end
208
-
209
- describe Type::Hash do
210
- its(:to_s) { should match(/Type::Hash/) }
211
- it { should cast([[1, 2], [3, 4]]).to(1 => 2, 3 => 4) }
212
- it { should_not cast(17) }
213
- end
214
-
215
- describe Type::Hash.of(:String => :Integer) do
216
- its(:to_s) { should match(/Type::Hash\(.*String.*Integer.*\)/) }
217
- it { should be_a_kind_of Type::Definition::Collection::Constrained }
218
- it { should validate('foo' => 12) }
219
- it { should_not validate(foo: 12) }
220
- it { should_not validate('foo' => '12') }
221
- it { should cast('foo' => '12', :bar => 3).to('foo' => 12, 'bar' => 3) }
222
- it { should cast('foo' => 12, 'bar' => 3).unchanged }
223
- it { should cast([['12', 34], [56, '78']]).to('12' => 34, '56' => 78) }
224
- it { should_not cast('foo' => 'foo') }
225
- end
226
-
227
- describe Type::Set do
228
- it { should_not validate([123, 456]) }
229
- it { should validate(Set.new([123, 456])) }
230
- it { should_not validate(17) }
231
- it { should cast([123, 456]).to(Set.new([123, 456])) }
232
- it { should cast(Set.new([123, 456])).to(Set.new([123, 456])) }
233
- it { should_not cast(17) }
234
- end
235
-
236
- describe Type::Set.of(:Integer) do
237
- its(:to_s) { should match(/Type::Set(.*Integer.*)/) }
238
- it { should validate(Set.new([1, 2, 3, 4])) }
239
- it { should_not validate([1, 2, 3, 4]) }
240
- it { should cast(Set.new([1, 2, 3, 4])).unchanged }
241
- it { should cast([1, 2, 3, 4]).to(Set.new([1, 2, 3, 4])) }
242
- end