assert_type 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,13 @@
1
+ require File.expand_path("./error.rb", File.dirname(__FILE__))
2
+
1
3
  module AssertType
2
- class AssertionError < RuntimeError
4
+ class AssertionError < Error
5
+
6
+ attr_reader :expected, :actual
3
7
 
4
- def initialize expected, actual, expected_is_nested_type
5
- @expected = expected_is_nested_type ? expected.to_s : expected.inspect
6
- @actual = expected_is_nested_type ? actual.to_s : actual.inspect
8
+ def initialize expected, actual
9
+ @expected = expected
10
+ @actual = actual
7
11
  end
8
12
 
9
13
  def message
@@ -1,4 +1,6 @@
1
+ require File.expand_path("./error.rb", File.dirname(__FILE__))
2
+
1
3
  module AssertType
2
- class CallError < RuntimeError
4
+ class CallError < Error
3
5
  end
4
6
  end
@@ -0,0 +1,4 @@
1
+ module AssertType
2
+ class Error < RuntimeError
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path("./error.rb", File.dirname(__FILE__))
2
+
3
+ module AssertType
4
+ class ParseError < Error
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ require File.expand_path("./assertion_error.rb", File.dirname(__FILE__))
2
+
3
+ module AssertType
4
+ class TypeAssertionError < AssertionError
5
+
6
+ def message
7
+ "assertion failed - expected #{@expected} but was #{@actual.inspect}"
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module AssertType
2
+ class TypeNode
3
+
4
+ attr_reader :name, :children
5
+
6
+ def initialize name
7
+ @name = name
8
+ @children = []
9
+ end
10
+
11
+ end
12
+ end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module AssertType
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
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, false
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 AssertionError.new expected_type, value, false
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.collect do |t|
28
- "<#{t}>"
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
- else
33
- if (matches = expected_type.match /([a-zA-Z0-9]+)\<([a-zA-Z0-9]+)\>/)
34
- enumerable_type = matches[1]
35
- child_type = matches[2]
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 CallError.new
38
+ raise ParseError.new
46
39
  end
40
+ else
41
+ raise CallError.new
47
42
  end
48
43
  end
49
44
  end
@@ -7,16 +7,17 @@ describe AssertType do
7
7
  it "quick and nasty tests" do
8
8
 
9
9
  at_assert_type Array, []
10
- expect { at_assert_type "Array", [] }.to raise_error AssertType::CallError
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 Array<String>}
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 <Fixnum> or <String> but was 1.1}
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: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
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-14 00:00:00 Z
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