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