-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypo.rb
127 lines (110 loc) · 2.91 KB
/
typo.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
gem 'binding_of_caller'
require 'binding_of_caller'
# # TODO
#
# - Test arguments in non-alphabetical order.
# - Add checker method for usage in methods without return value.
# - Give `ArgumentTypeError` and `ReturnTypeError` informative messages.
#
module Typo
ArgumentTypeError = Class.new(ArgumentError)
ReturnTypeError = Class.new(StandardError)
def returns(return_type)
binding_of_caller = binding.of_caller(1)
if binding_of_caller
locals =
eval('local_variables', binding_of_caller).reduce([]) do |vars, name|
vars << [name, eval(name.to_s, binding_of_caller)]
end
types =
begin
eval('____', binding_of_caller)
rescue NameError
[]
end
locals.zip(types).each do |((name, var), type)|
if type
var.is_a?(type) || (raise ArgumentTypeError.new('Better error description'))
end
end
end
return_value = yield
if return_value.is_a?(return_type)
return_value
else
raise ReturnTypeError.new('Better error description')
end
end
end
if $0 == __FILE__
gem 'minitest'
require 'minitest/autorun'
class TestTypo < Minitest::Test
class TestClass
include Typo
# Never used, only for style demonstration.
def a(numeric,
____=[Numeric])
returns Object do
:anything
end
end
def one_arg(string,
____ =[String])
returns Object do
string
end
end
def two_args(string, symbol,
____ =[String, Symbol])
returns Object do
string
end
end
def returns_anything
returns Object do
yield
end
end
def return_value
returns String do
yield
end
end
end
def test_one_arg_valid
test = TestClass.new
assert_equal 'string', test.one_arg('string')
end
def test_one_arg_invalid
test = TestClass.new
assert_raises Typo::ArgumentTypeError do
test.one_arg(:symbol)
end
end
def test_two_args_valid
test = TestClass.new
assert_equal 'string', test.two_args('string', :symbol)
end
def test_two_args_invalid
test = TestClass.new
assert_raises Typo::ArgumentTypeError do; test.two_args('string', 'string'); end
assert_raises Typo::ArgumentTypeError do; test.two_args(:symbol, :symbol); end
end
def test_returns_anything
test = TestClass.new
assert_equal 'string', test.returns_anything { 'string' }
assert_equal :symbol, test.returns_anything { :symbol }
end
def test_return_value_valid
test = TestClass.new
assert_equal 'string', test.return_value { 'string' }
end
def test_return_value_invalid
test = TestClass.new
assert_raises Typo::ReturnTypeError do
test.return_value { :symbol }
end
end
end
end