tspec 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a54636f321a831faea2655843bad6ce92b99fe65
4
- data.tar.gz: aab6a5ebe27dd54bbbfd6a2002cc5fcb01034189
3
+ metadata.gz: 84d333dcb760ef858b22802125d730f1b92620e3
4
+ data.tar.gz: e584d70cc0359970c93dc0b5c4953a526a20720b
5
5
  SHA512:
6
- metadata.gz: 1b5b2c4157f1656b8634add26ed21e442d65e871afd0d91e3daaf89ad31b0fd2d93c70879628c077713970b6fc987b1c369ac5fd9257cdf0f56fdc503bbf448b
7
- data.tar.gz: fc291a4ed9f314232b7082c036b6917641cfa3ef802f13623ddb0c77e629f9b8d49061368cbef9d5e5761cd496af9e01a140d6acb6278f5be8b4feb75be43aac
6
+ metadata.gz: 89a5b92412920594c39e4ea503a693e82036bbec41ef4447e2d4520267af63192c83e1fd663cf66949f006623ce956f363ba5b74979e5fb4e4f27e87ed4e6646
7
+ data.tar.gz: dbe9ac78c9a44d35889114b8365aca4cfd8ec85f8c35bc34daa2609ed79bc87cc5febb31f73fa3b20ec2555c968b9ea1a7e97066ff3062df93cc7e4febf90425
data/lib/tspec/core.rb ADDED
@@ -0,0 +1,127 @@
1
+ class Symbol
2
+ def return(*types)
3
+ self
4
+ end
5
+
6
+ def receive(*type, **types)
7
+ self
8
+ end
9
+ end
10
+
11
+ class UnboundMethod
12
+ def return(*types)
13
+ self
14
+ end
15
+
16
+ def receive(*type, **types)
17
+ self
18
+ end
19
+ end
20
+
21
+ class Method
22
+ def return(*types)
23
+ self
24
+ end
25
+
26
+ def receive(*type, **types)
27
+ self
28
+ end
29
+ end
30
+
31
+ module TSpec
32
+ module_function
33
+
34
+ def value_type_check(value, *types)
35
+ types.any? do |type|
36
+ if type.instance_of?(Array)
37
+ return false unless value.instance_of?(Array)
38
+
39
+ value.all? do |v|
40
+ type.any? do |t|
41
+ value_type_check(v, t)
42
+ end
43
+ end
44
+ else
45
+ value.instance_of?(type)
46
+ end
47
+ end
48
+ end
49
+
50
+ def regist_type(method_id, ctx, keys)
51
+ types = ctx.local_variable_get(:types)
52
+
53
+ case method_id
54
+ when :return
55
+ regist_return_type(keys, types)
56
+ when :receive
57
+ regist_receive_type(keys, types, ctx.local_variable_get(:type))
58
+ end
59
+ end
60
+
61
+ def get_keys(tp, btp)
62
+ ctx = tp.binding
63
+ keys = []
64
+
65
+ if %i(instance_method method).include?(btp[:method_id])
66
+ keys << "#{tp.self.owner}::#{tp.self.name}"
67
+ else
68
+ if btp[:method_id] == :singleton_method_added
69
+ klass = btp[:self].singleton_class
70
+
71
+ if @module_function_flags[btp[:self]]
72
+ keys << "#{btp[:self]}::#{ctx.receiver}"
73
+ end
74
+ else
75
+ klass = btp[:self]
76
+ end
77
+
78
+ keys << "#{klass}::#{ctx.receiver}"
79
+ end
80
+
81
+ keys
82
+ end
83
+
84
+ def regist_return_type(keys, types)
85
+ keys.each do |key|
86
+ @method_return_type_table[key] = types
87
+ end
88
+ end
89
+
90
+ def regist_receive_type(keys, types, type)
91
+ keys.each do |key|
92
+ @method_arguments_type_table[key] = types
93
+
94
+ if @method_arguments_type_table[key].empty?
95
+ @method_arguments_type_table[key] = { type.__id__ => type }
96
+ end
97
+ end
98
+ end
99
+
100
+ def check_type(tp)
101
+ key = "#{tp.defined_class}::#{tp.method_id}"
102
+
103
+ if types = @method_arguments_type_table[key]
104
+ arguments = tp.binding.eval("method(:#{tp.method_id}).parameters.map(&:last)")
105
+
106
+ types.each do |name, type|
107
+ name = arguments.first if name == type.__id__
108
+
109
+ unless arguments.include?(name)
110
+ @type_error_flag = true
111
+ raise NotFoundArgumentNameError, "undefined arguments `#{name}' for #{key}"
112
+ end
113
+
114
+ value = tp.binding.local_variable_get(name)
115
+
116
+ unless value_type_check(value, *type)
117
+ @type_error_flag = true
118
+ if type.instance_of?(Array)
119
+ raise ArgumentTypeError, "##{tp.method_id} '#{name}' variable should be #{type.map(&:inspect).join(' or ')}, but actual '#{value.inspect}' - #{value.class}"
120
+ else
121
+ raise ArgumentTypeError, "##{tp.method_id} '#{name}' variable should be #{type.inspect}, but actual '#{value.inspect}' - #{value.class}"
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,3 @@
1
+ module TSpec
2
+ VERSION = '0.4.0'
3
+ end
data/lib/tspec.rb CHANGED
@@ -1,125 +1,74 @@
1
+ require 'tspec/version'
1
2
  require 'tspec/type_error'
2
-
3
- class Symbol
4
- def return(*types)
5
- self
6
- end
7
-
8
- def receive(*type, **types)
9
- self
10
- end
11
- end
12
-
13
- class UnboundMethod
14
- def return(*types)
15
- self
16
- end
17
-
18
- def receive(*type, **types)
19
- self
20
- end
21
- end
22
-
23
- class Method
24
- def return(*types)
25
- self
26
- end
27
-
28
- def receive(*type, **types)
29
- self
30
- end
31
- end
3
+ require 'tspec/core'
32
4
 
33
5
  module TSpec
34
6
  @method_return_type_table = {}
35
7
  @method_arguments_type_table = {}
36
8
  @before_trace = {}
9
+ @module_function_flags = {}
10
+ @module_function_mode = {}
37
11
  @type_error_flag = false
12
+ HOOK_EVENT = %i(call return c_call c_return line)
38
13
  DEFINE_METHOD_SYMBOLS = %i(method_added singleton_method_added define_method instance_method method)
39
14
 
40
- def self.value_type_check(value, *types)
41
- types.any? do |type|
42
- if type.instance_of?(Array)
43
- return false unless value.instance_of?(Array)
44
-
45
- value.all? do |v|
46
- type.any? do |t|
47
- value_type_check(v, t)
48
- end
49
- end
50
- else
51
- value.instance_of?(type)
52
- end
53
- end
54
- end
55
-
56
- TracePoint.trace do |tp|
57
- case tp.event
58
- when :call
59
- if %i(return receive).include?(tp.method_id) && DEFINE_METHOD_SYMBOLS.include?(@before_trace[:method_id])
60
- ctx = tp.binding
61
-
62
- if %i(instance_method method).include?(@before_trace[:method_id])
63
- key = "#{tp.self.owner}::#{tp.self.name}"
15
+ @trace = TracePoint.new(*HOOK_EVENT) do |tp|
16
+ @trace.disable do
17
+ case tp.event
18
+ when :call
19
+ if %i(return receive).include?(tp.method_id) && DEFINE_METHOD_SYMBOLS.include?(@before_trace[:method_id])
20
+ ctx = tp.binding
21
+ keys = get_keys(tp, @before_trace)
22
+ regist_type(tp.method_id, ctx, keys)
64
23
  else
65
- klass = (@before_trace[:method_id] == :singleton_method_added) ? @before_trace[:self].singleton_class : @before_trace[:self]
66
- key = "#{klass}::#{ctx.receiver}"
67
- end
68
-
69
- case tp.method_id
70
- when :return
71
- @method_return_type_table[key] = ctx.local_variable_get(:types)
72
- when :receive
73
- @method_arguments_type_table[key] = ctx.local_variable_get(:types)
74
-
75
- if @method_arguments_type_table[key].empty?
76
- @method_arguments_type_table[key] = {ctx.local_variable_get(:type).__id__ => ctx.local_variable_get(:type)}
77
- end
24
+ check_type(tp)
78
25
  end
79
- else
80
- key = "#{tp.defined_class}::#{tp.method_id}"
81
-
82
- if types = @method_arguments_type_table[key]
83
- arguments = tp.binding.eval("method(:#{tp.method_id}).parameters.map(&:last)")
84
-
85
- types.each do |name, type|
86
- name = arguments.first if name == type.__id__
26
+ when :c_call
27
+ if tp.method_id == :module_function && tp.defined_class == Module
28
+ @module_function_mode[tp.self] = true
87
29
 
88
- unless arguments.include?(name)
89
- @type_error_flag = true
90
- raise NotFoundArgumentNameError, "undefined arguments `#{name}' for #{key}"
91
- end
30
+ line = File.readlines(tp.path)[tp.lineno-1]
31
+ names = line.scan(/:.+/)
92
32
 
93
- value = tp.binding.local_variable_get(name)
33
+ if names.empty?
34
+ @module_function_flags[tp.self] = true
35
+ else
36
+ names.each do |name|
37
+ key = "#{tp.self}:#{name}"
94
38
 
95
- unless value_type_check(value, *type)
96
- @type_error_flag = true
97
- if type.instance_of?(Array)
98
- raise ArgumentTypeError, "##{tp.method_id} '#{name}' variable should be #{type.map(&:inspect).join(' or ')}, but actual '#{value.inspect}' - #{value.class}"
99
- else
100
- raise ArgumentTypeError, "##{tp.method_id} '#{name}' variable should be #{type.inspect}, but actual '#{value.inspect}' - #{value.class}"
39
+ if type = @method_return_type_table[key]
40
+ @method_return_type_table["#{tp.self.singleton_class}:#{name}"] = type
41
+ end
42
+ if type = @method_arguments_type_table[key]
43
+ @method_arguments_type_table["#{tp.self.singleton_class}:#{name}"] = type
101
44
  end
102
45
  end
103
46
  end
104
47
  end
105
- end
106
- when :return
107
- if !@type_error_flag
108
- key = "#{tp.defined_class}::#{tp.method_id}"
48
+ when :c_return
49
+ if tp.method_id == :module_function && tp.defined_class == Module
50
+ @module_function_mode[tp.self] = false
51
+ end
52
+ when :return
53
+ if !@type_error_flag
54
+ key = "#{tp.defined_class}::#{tp.method_id}"
109
55
 
110
- if types = @method_return_type_table[key]
111
- unless value_type_check(tp.return_value, *types)
112
- @type_error_flag = true
113
- raise ReturnValueTypeError, "`#{tp.method_id}' expected return #{types.map(&:inspect).join(' or ')}, but actual `#{tp.return_value.inspect}' - #{tp.return_value.class}"
56
+ if types = @method_return_type_table[key]
57
+ unless value_type_check(tp.return_value, *types)
58
+ @type_error_flag = true
59
+ raise ReturnValueTypeError, "`#{tp.method_id}' expected return #{types.map(&:inspect).join(' or ')}, but actual `#{tp.return_value.inspect}' - #{tp.return_value.class}"
60
+ end
114
61
  end
115
62
  end
116
- end
117
- end
63
+ end
118
64
 
119
- @type_error_flag = false
65
+ @type_error_flag = false
120
66
 
121
- if tp.defined_class != Symbol || !%i(return receive).include?(tp.method_id)
122
- @before_trace = {self: tp.self, method_id: tp.method_id}
67
+ if tp.defined_class != Symbol || !%i(return receive).include?(tp.method_id)
68
+ @before_trace = { self: tp.self, method_id: tp.method_id }
69
+ end
123
70
  end
124
71
  end
72
+
73
+ @trace.enable
125
74
  end
data/tspec.gemspec CHANGED
@@ -2,9 +2,11 @@
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
+ require 'tspec/version'
6
+
5
7
  Gem::Specification.new do |spec|
6
8
  spec.name = "tspec"
7
- spec.version = "0.3.0"
9
+ spec.version = TSpec::VERSION
8
10
  spec.authors = ["siman-man"]
9
11
  spec.email = ["k128585@ie.u-ryukyu.ac.jp"]
10
12
 
@@ -25,4 +27,5 @@ Gem::Specification.new do |spec|
25
27
  spec.add_development_dependency "bundler", "~> 1.14"
26
28
  spec.add_development_dependency "rake", "~> 10.0"
27
29
  spec.add_development_dependency "rspec", "~> 3.0"
30
+ spec.add_development_dependency "coderay", "~> 1.1"
28
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - siman-man
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-17 00:00:00.000000000 Z
11
+ date: 2017-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: coderay
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
55
69
  description: Add type check method
56
70
  email:
57
71
  - k128585@ie.u-ryukyu.ac.jp
@@ -74,7 +88,9 @@ files:
74
88
  - examples/return_failed.rb
75
89
  - examples/return_success.rb
76
90
  - lib/tspec.rb
91
+ - lib/tspec/core.rb
77
92
  - lib/tspec/type_error.rb
93
+ - lib/tspec/version.rb
78
94
  - tspec.gemspec
79
95
  homepage: https://github.com/siman-man/tspec
80
96
  licenses: