type 0.1.0 → 0.2.0

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.
@@ -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