assert_type 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/lib/assert_type/assertion_error.rb +8 -4
- data/lib/assert_type/call_error.rb +3 -1
- data/lib/assert_type/error.rb +4 -0
- data/lib/assert_type/parse_error.rb +6 -0
- data/lib/assert_type/type_assertion_error.rb +11 -0
- data/lib/assert_type/type_node.rb +12 -0
- data/lib/assert_type/type_string_parser.rb +42 -0
- data/lib/assert_type/type_string_tokeniser.rb +45 -0
- data/lib/assert_type/type_validator.rb +32 -0
- data/lib/assert_type/version.rb +1 -1
- data/lib/assert_type.rb +13 -18
- data/spec/assert_type_spec.rb +4 -3
- data/spec/type_string_parser_spec.rb +45 -0
- data/spec/type_string_tokeniser_spec.rb +20 -0
- data/spec/type_validator_spec.rb +102 -0
- metadata +14 -4
@@ -1,9 +1,13 @@
|
|
1
|
+
require File.expand_path("./error.rb", File.dirname(__FILE__))
|
2
|
+
|
1
3
|
module AssertType
|
2
|
-
class AssertionError <
|
4
|
+
class AssertionError < Error
|
5
|
+
|
6
|
+
attr_reader :expected, :actual
|
3
7
|
|
4
|
-
def initialize expected, actual
|
5
|
-
@expected =
|
6
|
-
@actual =
|
8
|
+
def initialize expected, actual
|
9
|
+
@expected = expected
|
10
|
+
@actual = actual
|
7
11
|
end
|
8
12
|
|
9
13
|
def message
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path('./type_string_tokeniser.rb', File.dirname(__FILE__))
|
2
|
+
require File.expand_path('./type_node.rb', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
module AssertType
|
5
|
+
class TypeStringParser
|
6
|
+
|
7
|
+
# @param type_string [String] like Array<Fixnum>
|
8
|
+
def self.parse type_string
|
9
|
+
new(type_string).parse
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize type_string
|
13
|
+
@type_string = type_string
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse
|
17
|
+
first_token = tokens.shift
|
18
|
+
main_type = first_token.value
|
19
|
+
node = TypeNode.new main_type
|
20
|
+
previous_word = node
|
21
|
+
current_words = []
|
22
|
+
tokens.each do |token|
|
23
|
+
case token.name
|
24
|
+
when :open_angle
|
25
|
+
current_words.push previous_word
|
26
|
+
when :close_angle
|
27
|
+
current_words.pop
|
28
|
+
when :word
|
29
|
+
current_words.last.children << (previous_word = TypeNode.new(token.value))
|
30
|
+
when :comma
|
31
|
+
# ignore commas
|
32
|
+
end
|
33
|
+
end
|
34
|
+
node
|
35
|
+
end
|
36
|
+
|
37
|
+
def tokens
|
38
|
+
@tokens ||= TypeStringTokeniser.tokenise @type_string
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module AssertType
|
2
|
+
class TypeStringTokeniser
|
3
|
+
|
4
|
+
# @param type_string [String] like Array<Fixnum>
|
5
|
+
def self.tokenise type_string
|
6
|
+
new(type_string).tokens
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize type_string
|
10
|
+
@type_string = type_string.strip
|
11
|
+
end
|
12
|
+
|
13
|
+
def tokens
|
14
|
+
tokens = []
|
15
|
+
while (t = next_token) do
|
16
|
+
tokens << t
|
17
|
+
end
|
18
|
+
tokens
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
Token = Struct.new :name, :value
|
24
|
+
|
25
|
+
TOKEN_MATCHERS = [
|
26
|
+
{:token_name => :word, :matcher => /^\w+/},
|
27
|
+
{:token_name => :open_angle, :matcher => /^</},
|
28
|
+
{:token_name => :close_angle, :matcher => /^>/},
|
29
|
+
{:token_name => :comma, :matcher => /^,/}
|
30
|
+
]
|
31
|
+
|
32
|
+
# @return [Token, nil]
|
33
|
+
def next_token
|
34
|
+
value = nil
|
35
|
+
matcher = TOKEN_MATCHERS.detect do |tm_hash|
|
36
|
+
value = @type_string.scan(tm_hash[:matcher])[0]
|
37
|
+
!value.nil?
|
38
|
+
end
|
39
|
+
matcher && (Token.new(matcher[:token_name], value).tap do |t|
|
40
|
+
@type_string = (@type_string.slice(value.length, @type_string.length) || '').strip
|
41
|
+
end)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module AssertType
|
2
|
+
class TypeValidator
|
3
|
+
class << self
|
4
|
+
|
5
|
+
# @param type_node [AssertType::TypeNode]
|
6
|
+
# @param value [Object]
|
7
|
+
def valid? type_node, value
|
8
|
+
type_node.name == value.class.to_s &&
|
9
|
+
children_valid?(type_node, value)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def children_valid? type_node, value
|
15
|
+
type_node.children.empty? ||
|
16
|
+
value_empty?(value) ||
|
17
|
+
type_node.children.any? do |node|
|
18
|
+
valid?(node, value_first_child(value))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def value_first_child value
|
23
|
+
value.first
|
24
|
+
end
|
25
|
+
|
26
|
+
def value_empty? value
|
27
|
+
value.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/assert_type/version.rb
CHANGED
data/lib/assert_type.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require "assert_type/version"
|
2
2
|
require "assert_type/assertion_error"
|
3
|
+
require "assert_type/type_assertion_error"
|
3
4
|
require "assert_type/call_error"
|
5
|
+
require "assert_type/parse_error"
|
4
6
|
|
5
7
|
module AssertType
|
6
8
|
|
@@ -13,37 +15,30 @@ module AssertType
|
|
13
15
|
|
14
16
|
def at_assert_equal expected, actual
|
15
17
|
unless expected == actual
|
16
|
-
raise AssertionError.new expected, actual
|
18
|
+
raise AssertionError.new expected, actual
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
22
|
def at_assert_type expected_type, value
|
21
23
|
if expected_type.is_a? Class
|
22
24
|
unless expected_type === value
|
23
|
-
raise
|
25
|
+
raise TypeAssertionError.new expected_type.to_s, value
|
24
26
|
end
|
25
27
|
elsif expected_type.is_a? Array
|
26
28
|
unless expected_type.any? {|t| t === value}
|
27
|
-
types = expected_type.
|
28
|
-
|
29
|
-
end.join(' or ')
|
30
|
-
raise AssertionError.new types, value, true
|
29
|
+
types = expected_type.join(' or ')
|
30
|
+
raise TypeAssertionError.new types, value
|
31
31
|
end
|
32
|
-
|
33
|
-
if
|
34
|
-
|
35
|
-
|
36
|
-
e_type = Object.const_get(enumerable_type)
|
37
|
-
c_type = Object.const_get(child_type)
|
38
|
-
unless e_type === value
|
39
|
-
raise AssertionError.new e_type, value, false
|
40
|
-
end
|
41
|
-
unless value.first.nil? || c_type === value.first
|
42
|
-
raise AssertionError.new "#{e_type}<#{c_type}>", "#{e_type}<#{value.first.class}>", true
|
32
|
+
elsif expected_type.is_a? String
|
33
|
+
if node = AssertType::TypeStringParser.parse(expected_type)
|
34
|
+
unless AssertType::TypeValidator.valid?(node, value)
|
35
|
+
raise TypeAssertionError.new expected_type, value
|
43
36
|
end
|
44
37
|
else
|
45
|
-
raise
|
38
|
+
raise ParseError.new
|
46
39
|
end
|
40
|
+
else
|
41
|
+
raise CallError.new
|
47
42
|
end
|
48
43
|
end
|
49
44
|
end
|
data/spec/assert_type_spec.rb
CHANGED
@@ -7,16 +7,17 @@ describe AssertType do
|
|
7
7
|
it "quick and nasty tests" do
|
8
8
|
|
9
9
|
at_assert_type Array, []
|
10
|
-
|
10
|
+
at_assert_type "Array", []
|
11
|
+
at_assert_type "Array", [1,2,3]
|
11
12
|
at_assert_type "Array<Fixnum>", [1,2,3]
|
12
13
|
at_assert_type "Array<Fixnum>", []
|
13
14
|
expect { at_assert_type "Array<Fixnum>", ["one", "two", "three"] }.to raise_error(AssertType::AssertionError) { |error|
|
14
|
-
error.message.should include %{expected Array<Fixnum> but was
|
15
|
+
error.message.should include %{expected Array<Fixnum> but was}
|
15
16
|
}
|
16
17
|
at_assert_type [Fixnum, String], 1
|
17
18
|
at_assert_type [Fixnum, String], "1"
|
18
19
|
expect { at_assert_type [Fixnum, String], 1.1 }.to raise_error(AssertType::AssertionError) { |error|
|
19
|
-
error.message.should include %{expected
|
20
|
+
error.message.should include %{expected Fixnum or String but was 1.1}
|
20
21
|
}
|
21
22
|
|
22
23
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path('../lib/assert_type/type_string_parser.rb', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
module AssertType
|
5
|
+
describe TypeStringParser do
|
6
|
+
|
7
|
+
context "converts string to node tree" do
|
8
|
+
|
9
|
+
it "example: Array" do
|
10
|
+
node = TypeStringParser.parse("Array")
|
11
|
+
node.name.should == "Array"
|
12
|
+
node.children.length.should == 0
|
13
|
+
end
|
14
|
+
|
15
|
+
it "example: Array<Fixnum>" do
|
16
|
+
node = TypeStringParser.parse("Array<Fixnum>")
|
17
|
+
node.name.should == "Array"
|
18
|
+
node.children.length.should == 1
|
19
|
+
node.children.first.name.should == "Fixnum"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "example: Array<Fixnum, String>" do
|
23
|
+
node = TypeStringParser.parse("Array<Fixnum, String>")
|
24
|
+
node.name.should == "Array"
|
25
|
+
node.children.length.should == 2
|
26
|
+
node.children[0].name.should == "Fixnum"
|
27
|
+
node.children[1].name.should == "String"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "example: Array<Array<Fixnum>, Array<String>>" do
|
31
|
+
node = TypeStringParser.parse("Array<Array<Fixnum>, Array<String>>")
|
32
|
+
node.name.should == "Array"
|
33
|
+
node.children.length.should == 2
|
34
|
+
node.children[0].name.should == "Array"
|
35
|
+
node.children[1].name.should == "Array"
|
36
|
+
node.children[0].children.length.should == 1
|
37
|
+
node.children[0].children[0].name.should == "Fixnum"
|
38
|
+
node.children[1].children.length.should == 1
|
39
|
+
node.children[1].children[0].name.should == "String"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path('../lib/assert_type/type_string_tokeniser.rb', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
module AssertType
|
5
|
+
describe TypeStringTokeniser do
|
6
|
+
|
7
|
+
it "converts string to array of tokens" do
|
8
|
+
|
9
|
+
TypeStringTokeniser.tokenise("Array<Fixnum>").collect{|t|[t.name,t.value]}.should == [
|
10
|
+
[:word, "Array"], [:open_angle, "<"], [:word, "Fixnum"], [:close_angle, ">"]
|
11
|
+
]
|
12
|
+
|
13
|
+
TypeStringTokeniser.tokenise("Array<Fixnum, String>").collect{|t|[t.name,t.value]}.should == [
|
14
|
+
[:word, "Array"], [:open_angle, "<"], [:word, "Fixnum"], [:comma, ","], [:word, "String"], [:close_angle, ">"]
|
15
|
+
]
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path('../lib/assert_type/type_validator.rb', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
module AssertType
|
5
|
+
describe TypeValidator do
|
6
|
+
|
7
|
+
it "example: Array" do
|
8
|
+
node = stub("TypeNode", :name => "Array", :children => [])
|
9
|
+
TypeValidator.valid?(node, []).should be_true
|
10
|
+
TypeValidator.valid?(node, [1,2,3]).should be_true
|
11
|
+
TypeValidator.valid?(node, ["one","two","three"]).should be_true
|
12
|
+
TypeValidator.valid?(node, {}).should be_false
|
13
|
+
end
|
14
|
+
|
15
|
+
it "example: Set" do
|
16
|
+
node = stub("TypeNode", :name => "Set", :children => [])
|
17
|
+
TypeValidator.valid?(node, Set.new).should be_true
|
18
|
+
TypeValidator.valid?(node, Set.new([1,2,3])).should be_true
|
19
|
+
TypeValidator.valid?(node, Set.new(["one","two","three"])).should be_true
|
20
|
+
TypeValidator.valid?(node, []).should be_false
|
21
|
+
TypeValidator.valid?(node, [1,2,3]).should be_false
|
22
|
+
TypeValidator.valid?(node, ["one","two","three"]).should be_false
|
23
|
+
TypeValidator.valid?(node, {}).should be_false
|
24
|
+
end
|
25
|
+
|
26
|
+
it "example: Hash" do
|
27
|
+
node = stub("TypeNode", :name => "Hash", :children => [])
|
28
|
+
TypeValidator.valid?(node, {}).should be_true
|
29
|
+
TypeValidator.valid?(node, {:one => 1, :two => 2}).should be_true
|
30
|
+
TypeValidator.valid?(node, []).should be_false
|
31
|
+
TypeValidator.valid?(node, [1,2,3]).should be_false
|
32
|
+
TypeValidator.valid?(node, ["one","two","three"]).should be_false
|
33
|
+
end
|
34
|
+
|
35
|
+
it "example: Array<Fixnum>" do
|
36
|
+
node = stub("TypeNode", :name => "Array", :children => [
|
37
|
+
stub("TypeNode", :name => "Fixnum", :children => [])
|
38
|
+
])
|
39
|
+
TypeValidator.valid?(node, [1,2,3]).should be_true
|
40
|
+
TypeValidator.valid?(node, []).should be_true
|
41
|
+
TypeValidator.valid?(node, ["one", "two", "three"]).should be_false
|
42
|
+
end
|
43
|
+
|
44
|
+
it "example: Array<Fixnum, String>" do
|
45
|
+
node = stub("TypeNode", :name => "Array", :children => [
|
46
|
+
stub("TypeNode", :name => "Fixnum", :children => []),
|
47
|
+
stub("TypeNode", :name => "String", :children => [])
|
48
|
+
])
|
49
|
+
TypeValidator.valid?(node, [1,2,3]).should be_true
|
50
|
+
TypeValidator.valid?(node, ["one", "two", "three"]).should be_true
|
51
|
+
TypeValidator.valid?(node, []).should be_true
|
52
|
+
TypeValidator.valid?(node, [1.1,2.2,3.3]).should be_false
|
53
|
+
end
|
54
|
+
|
55
|
+
it "example: Array<Array<Fixnum>>" do
|
56
|
+
node = stub("TypeNode", :name => "Array", :children => [
|
57
|
+
stub("TypeNode", :name => "Array", :children => [
|
58
|
+
stub("TypeNode", :name => "Fixnum", :children => [])
|
59
|
+
])
|
60
|
+
])
|
61
|
+
TypeValidator.valid?(node, [[1,2,3]]).should be_true
|
62
|
+
TypeValidator.valid?(node, [[]]).should be_true
|
63
|
+
TypeValidator.valid?(node, []).should be_true
|
64
|
+
TypeValidator.valid?(node, [1,2,3]).should be_false
|
65
|
+
TypeValidator.valid?(node, ["one", "two", "three"]).should be_false
|
66
|
+
TypeValidator.valid?(node, [["one", "two", "three"]]).should be_false
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
it "example: Array<Set<Fixnum>>" do
|
71
|
+
node = stub("TypeNode", :name => "Array", :children => [
|
72
|
+
stub("TypeNode", :name => "Set", :children => [
|
73
|
+
stub("TypeNode", :name => "Fixnum", :children => []),
|
74
|
+
])
|
75
|
+
])
|
76
|
+
|
77
|
+
TypeValidator.valid?(node, [Set.new([1,2,3])]).should be_true
|
78
|
+
TypeValidator.valid?(node, [Set.new]).should be_true
|
79
|
+
TypeValidator.valid?(node, []).should be_true
|
80
|
+
TypeValidator.valid?(node, [Set.new(["one", "two", "three"])]).should be_false
|
81
|
+
TypeValidator.valid?(node, [{}]).should be_false
|
82
|
+
TypeValidator.valid?(node, [[]]).should be_false
|
83
|
+
end
|
84
|
+
|
85
|
+
## Note: we can't parse this yet
|
86
|
+
#xit "example: Hash{Symbol => Fixnum}" do
|
87
|
+
# node = stub("TypeNode", :name => "Hash", :children => [
|
88
|
+
# stub("TypeNode", :name => "_params", :children => [
|
89
|
+
# stub("TypeNode", :name => "Symbol", :children => []),
|
90
|
+
# stub("TypeNode", :name => "Fixnum", :children => [])
|
91
|
+
# ])
|
92
|
+
# ])
|
93
|
+
# TypeValidator.valid?(node, {}).should be_true
|
94
|
+
# TypeValidator.valid?(node, {:one => 1, :two => 2}).should be_true
|
95
|
+
# TypeValidator.valid?(node, {:one => "1", :two => "2"}).should be_false
|
96
|
+
# TypeValidator.valid?(node, []).should be_false
|
97
|
+
# TypeValidator.valid?(node, [1,2,3]).should be_false
|
98
|
+
# TypeValidator.valid?(node, ["one","two","three"]).should be_false
|
99
|
+
#end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: assert_type
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Joel Plane
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2013-01-
|
18
|
+
date: 2013-01-15 00:00:00 Z
|
19
19
|
dependencies: []
|
20
20
|
|
21
21
|
description: A method for very basic nested type assertions
|
@@ -35,9 +35,19 @@ files:
|
|
35
35
|
- lib/assert_type.rb
|
36
36
|
- lib/assert_type/assertion_error.rb
|
37
37
|
- lib/assert_type/call_error.rb
|
38
|
+
- lib/assert_type/error.rb
|
39
|
+
- lib/assert_type/parse_error.rb
|
40
|
+
- lib/assert_type/type_assertion_error.rb
|
41
|
+
- lib/assert_type/type_node.rb
|
42
|
+
- lib/assert_type/type_string_parser.rb
|
43
|
+
- lib/assert_type/type_string_tokeniser.rb
|
44
|
+
- lib/assert_type/type_validator.rb
|
38
45
|
- lib/assert_type/version.rb
|
39
46
|
- spec/assert_type_spec.rb
|
40
47
|
- spec/spec_helper.rb
|
48
|
+
- spec/type_string_parser_spec.rb
|
49
|
+
- spec/type_string_tokeniser_spec.rb
|
50
|
+
- spec/type_validator_spec.rb
|
41
51
|
homepage: ""
|
42
52
|
licenses: []
|
43
53
|
|