rubybreaker 0.0.3 → 0.0.4
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/NEWS +4 -0
- data/README.md +33 -19
- data/Rakefile +31 -13
- data/TODO +6 -4
- data/VERSION +1 -1
- data/bin/rubybreaker +0 -1
- data/lib/rubybreaker/debug/debug.rb +1 -1
- data/lib/rubybreaker/runtime/typesig_unparser.rb +96 -0
- data/lib/rubybreaker/runtime.rb +1 -0
- data/lib/rubybreaker/test/rspec.rb +15 -0
- data/lib/rubybreaker/test/testcase.rb +4 -4
- data/lib/rubybreaker/test.rb +1 -0
- data/lib/rubybreaker/type/type_grammar.treetop +5 -4
- data/lib/rubybreaker/type/type_unparser.rb +69 -25
- data/lib/rubybreaker.rb +9 -77
- data/test/integrated/tc_namespace.rb +56 -0
- data/test/ts_integrated.rb +1 -0
- data/test/ts_rspec.rb +31 -0
- data/test/ts_type.rb +2 -0
- data/test/type/tc_camelize.rb +24 -0
- data/test/type/tc_namespace.rb +25 -0
- data/test/type/tc_unparser.rb +31 -32
- data/webpage/index.html +34 -19
- data/webpage/rdoc/Object.html +308 -0
- data/webpage/rdoc/RubyBreaker/Breakable.html +5 -1
- data/webpage/rdoc/RubyBreaker/Broken/BrokenEigen.html +5 -1
- data/webpage/rdoc/RubyBreaker/Broken.html +5 -1
- data/webpage/rdoc/RubyBreaker/Context.html +5 -1
- data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +4 -0
- data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +4 -0
- data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +4 -0
- data/webpage/rdoc/RubyBreaker/Errors/SubtypeFailure.html +4 -0
- data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +4 -0
- data/webpage/rdoc/RubyBreaker/Errors/UserError.html +4 -0
- data/webpage/rdoc/RubyBreaker/Errors.html +4 -0
- data/webpage/rdoc/RubyBreaker/Main.html +17 -132
- data/webpage/rdoc/RubyBreaker/ObjectPosition.html +5 -1
- data/webpage/rdoc/RubyBreaker/Position.html +5 -1
- data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +4 -0
- data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +4 -0
- data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +5 -1
- data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +5 -1
- data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +4 -0
- data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +5 -1
- data/webpage/rdoc/RubyBreaker/Runtime/MonitorUtils.html +4 -0
- data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +4 -0
- data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +4 -0
- data/webpage/rdoc/RubyBreaker/Runtime/TypePlaceholder.html +5 -1
- data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +4 -0
- data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +5 -1
- data/webpage/rdoc/RubyBreaker/Runtime/TypesigUnparser.html +404 -0
- data/webpage/rdoc/RubyBreaker/Runtime.html +5 -0
- data/webpage/rdoc/RubyBreaker/TestCase.html +47 -43
- data/webpage/rdoc/RubyBreaker/TypeComparer.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +11 -6
- data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeDefs.html +4 -0
- data/webpage/rdoc/RubyBreaker/TypeUnparser.html +15 -7
- data/webpage/rdoc/RubyBreaker/Typing.html +4 -0
- data/webpage/rdoc/RubyBreaker/Util.html +4 -0
- data/webpage/rdoc/RubyBreaker.html +6 -6
- data/webpage/rdoc/created.rid +9 -7
- data/webpage/rdoc/index.html +4 -0
- data/webpage/rdoc/js/search_index.js +1 -1
- data/webpage/rdoc/table_of_contents.html +36 -24
- metadata +13 -7
data/lib/rubybreaker.rb
CHANGED
|
@@ -30,9 +30,6 @@ module RubyBreaker
|
|
|
30
30
|
# monitor.
|
|
31
31
|
INSTALLED = []
|
|
32
32
|
|
|
33
|
-
# This array lists monitored modules/classes that are outputed.
|
|
34
|
-
DOCUMENTED = []
|
|
35
|
-
|
|
36
33
|
# Extension used by RubyBreaker for output/input
|
|
37
34
|
EXTENSION = "rubybreaker"
|
|
38
35
|
|
|
@@ -75,71 +72,6 @@ module RubyBreaker
|
|
|
75
72
|
eval "load \"#{OPTIONS[:io_file]}\"", TOPLEVEL_BINDING
|
|
76
73
|
end
|
|
77
74
|
|
|
78
|
-
# Pretty prints type information for methods
|
|
79
|
-
def self.pp_methods(pp, meth_type_map)
|
|
80
|
-
meth_type_map.each { |meth_name, meth_type|
|
|
81
|
-
case meth_type
|
|
82
|
-
when MethodType
|
|
83
|
-
pp.breakable()
|
|
84
|
-
pp.text("typesig(\"")
|
|
85
|
-
TypeUnparser.unparse_pp(pp,meth_type)
|
|
86
|
-
pp.text("\")")
|
|
87
|
-
when MethodListType
|
|
88
|
-
meth_type.types.each { |real_meth_type|
|
|
89
|
-
pp.breakable()
|
|
90
|
-
pp.text("typesig(\"")
|
|
91
|
-
TypeUnparser.unparse_pp(pp,real_meth_type)
|
|
92
|
-
pp.text("\")")
|
|
93
|
-
}
|
|
94
|
-
else
|
|
95
|
-
# Can't happen
|
|
96
|
-
end
|
|
97
|
-
}
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# Pretty prints type information for the module/class
|
|
101
|
-
def self.pp_module(pp, mod)
|
|
102
|
-
# Skip it if we already have seen it
|
|
103
|
-
return if DOCUMENTED.include?(mod) || mod.to_s[0..1] == "#<"
|
|
104
|
-
|
|
105
|
-
# Remember that we have documented this module/class
|
|
106
|
-
DOCUMENTED << mod
|
|
107
|
-
|
|
108
|
-
# Get the method type mapping
|
|
109
|
-
meth_type_map = Inspector.inspect_all(mod)
|
|
110
|
-
|
|
111
|
-
# Check if this module is a class
|
|
112
|
-
keyword = mod.instance_of?(Class) ? "class" : "module"
|
|
113
|
-
|
|
114
|
-
pp.text("#{keyword} #{mod.to_s}", 80)
|
|
115
|
-
pp.nest(2) do
|
|
116
|
-
pp.breakable("")
|
|
117
|
-
pp.text("include RubyBreaker::Broken", 80)
|
|
118
|
-
|
|
119
|
-
# See if there is any class method to show
|
|
120
|
-
eigen = Runtime.eigen_class(mod)
|
|
121
|
-
|
|
122
|
-
if !DOCUMENTED.include?(eigen)
|
|
123
|
-
DOCUMENTED << eigen
|
|
124
|
-
eigen_meth_type_map = Inspector.inspect_all(eigen)
|
|
125
|
-
if eigen_meth_type_map.size > 0
|
|
126
|
-
pp.breakable()
|
|
127
|
-
pp.text("class << self", 80)
|
|
128
|
-
pp.nest(2) do
|
|
129
|
-
self.pp_methods(pp, eigen_meth_type_map)
|
|
130
|
-
end
|
|
131
|
-
pp.breakable()
|
|
132
|
-
pp.text("end", 80)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
self.pp_methods(pp, meth_type_map)
|
|
136
|
-
|
|
137
|
-
end
|
|
138
|
-
pp.breakable()
|
|
139
|
-
pp.text("end",80)
|
|
140
|
-
pp.breakable()
|
|
141
|
-
end
|
|
142
|
-
|
|
143
75
|
# This method will generate the output.
|
|
144
76
|
def self.output()
|
|
145
77
|
|
|
@@ -147,15 +79,15 @@ module RubyBreaker
|
|
|
147
79
|
|
|
148
80
|
io_exist = OPTIONS[:io_file] && File.exist?(OPTIONS[:io_file])
|
|
149
81
|
|
|
150
|
-
|
|
151
|
-
pp = PrettyPrint.new(str)
|
|
152
|
-
|
|
82
|
+
code = ""
|
|
153
83
|
# Document each module that was monitored
|
|
154
|
-
INSTALLED.each { |mod|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
84
|
+
INSTALLED.each { |mod|
|
|
85
|
+
str = Runtime::TypesigUnparser.unparse(mod)
|
|
86
|
+
code << str
|
|
87
|
+
if OPTIONS[:mode] == :lib
|
|
88
|
+
print str
|
|
89
|
+
end
|
|
90
|
+
}
|
|
159
91
|
|
|
160
92
|
# If this was a library mode run, exit now.
|
|
161
93
|
return if OPTIONS[:mode] == :lib
|
|
@@ -166,7 +98,7 @@ module RubyBreaker
|
|
|
166
98
|
f.puts "# This file is auto-generated by RubyBreaker"
|
|
167
99
|
f.puts "require \"rubybreaker\""
|
|
168
100
|
end
|
|
169
|
-
f.
|
|
101
|
+
f.print code
|
|
170
102
|
end
|
|
171
103
|
|
|
172
104
|
RubyBreaker.verbose("Done generating type documentation")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require "test/unit"
|
|
2
|
+
require_relative "../../lib/rubybreaker"
|
|
3
|
+
|
|
4
|
+
class IntegratedNamespaceTest < Test::Unit::TestCase
|
|
5
|
+
include RubyBreaker
|
|
6
|
+
include RubyBreaker::TestCase
|
|
7
|
+
|
|
8
|
+
class A < String
|
|
9
|
+
class C < String
|
|
10
|
+
class D < String
|
|
11
|
+
class E < String
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
class F
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class B
|
|
20
|
+
include RubyBreaker::Breakable
|
|
21
|
+
def foo(x); x.to_s end
|
|
22
|
+
def bar(x); x.to_s end
|
|
23
|
+
def baz(x); x.to_s end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_namspace_b_foo
|
|
27
|
+
a = A.new
|
|
28
|
+
b = B.new
|
|
29
|
+
b.foo(a)
|
|
30
|
+
meth_type = Runtime::Inspector.inspect_meth(B, :foo)
|
|
31
|
+
str = RubyBreaker::TypeUnparser.unparse(meth_type)
|
|
32
|
+
# puts str
|
|
33
|
+
assert_equal("foo(integrated_namespace_test/a[to_s]) -> string", str, "B#foo failed.")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_namspace_b_foo_nested
|
|
37
|
+
a = A::C.new
|
|
38
|
+
b = B.new
|
|
39
|
+
b.bar(a)
|
|
40
|
+
meth_type = Runtime::Inspector.inspect_meth(B, :bar)
|
|
41
|
+
str = RubyBreaker::TypeUnparser.unparse(meth_type)
|
|
42
|
+
# puts str
|
|
43
|
+
assert_equal("bar(integrated_namespace_test/a/c[to_s]) -> string", str, "B#bar failed.")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_namespace_e_baz
|
|
47
|
+
e = A::C::D::E.new
|
|
48
|
+
b = B.new
|
|
49
|
+
b.baz(e)
|
|
50
|
+
meth_type = Runtime::Inspector.inspect_meth(B, :baz)
|
|
51
|
+
str = meth_type.unparse(:namespace => A::C::F)
|
|
52
|
+
assert_equal("baz(d/e[to_s]) -> string", str, "B#baz failed.")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
data/test/ts_integrated.rb
CHANGED
data/test/ts_rspec.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "rspec"
|
|
2
|
+
require_relative "../lib/rubybreaker"
|
|
3
|
+
|
|
4
|
+
class RSpecTestA
|
|
5
|
+
include RubyBreaker::Breakable
|
|
6
|
+
def foo(x); x.to_s end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class RSpecTestB
|
|
10
|
+
include RubyBreaker::Broken
|
|
11
|
+
typesig("foo(fixnum[to_s]) -> string")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe RSpecTestA do
|
|
15
|
+
it "should return a string of number" do
|
|
16
|
+
a = RSpecTestA.new
|
|
17
|
+
a.foo(1)
|
|
18
|
+
a_foo_type = RubyBreaker::Runtime::Inspector.inspect_meth(RSpecTestA, :foo)
|
|
19
|
+
str = a_foo_type.unparse()
|
|
20
|
+
str.should == "foo(fixnum[to_s]) -> string"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe RSpecTestB do
|
|
25
|
+
it "should return the documented type of B#foo" do
|
|
26
|
+
b_foo_type = RubyBreaker::Runtime::Inspector.inspect_meth(RSpecTestB, :foo)
|
|
27
|
+
str = b_foo_type.unparse()
|
|
28
|
+
str.should == "foo(fixnum[to_s]) -> string"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
data/test/ts_type.rb
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# This test verifies type unparser for RubyBreaker types.
|
|
2
|
+
require "test/unit"
|
|
3
|
+
require_relative "../../lib/rubybreaker/type"
|
|
4
|
+
|
|
5
|
+
class UnparserCamelizeTest < Test::Unit::TestCase
|
|
6
|
+
|
|
7
|
+
include RubyBreaker
|
|
8
|
+
|
|
9
|
+
class CamelizedClassName; end
|
|
10
|
+
|
|
11
|
+
def test_camelize_type()
|
|
12
|
+
t1 = NominalType.new(CamelizedClassName)
|
|
13
|
+
str1 = t1.unparse({:style => :camelize, :namespace => UnparserCamelizeTest})
|
|
14
|
+
# puts str1
|
|
15
|
+
assert_equal("CamelizedClassName",str1.strip())
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_camelize_no_namespace_type()
|
|
19
|
+
t1 = NominalType.new(CamelizedClassName)
|
|
20
|
+
str1 = t1.unparse({:style => :camelize, :namespace => UnparserCamelizeTest})
|
|
21
|
+
# puts str1
|
|
22
|
+
assert_equal("CamelizedClassName",str1.strip())
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# This test verifies handling of namespace in parsing types.
|
|
2
|
+
require "test/unit"
|
|
3
|
+
require_relative "../../lib/rubybreaker/type"
|
|
4
|
+
|
|
5
|
+
class TypeNamespaceTest < Test::Unit::TestCase
|
|
6
|
+
|
|
7
|
+
include RubyBreaker
|
|
8
|
+
|
|
9
|
+
class A
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def setup
|
|
13
|
+
@parser = Runtime::TypeSigParser::PARSER
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def teardown
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_namespace_1
|
|
20
|
+
t1 = @parser.parse("foo(type_namespace_test/a[to_s]) -> string").value
|
|
21
|
+
str = t1.unparse(:style => :camelize)
|
|
22
|
+
assert_equal("foo(TypeNamespaceTest::A[to_s]) -> String", str)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
data/test/type/tc_unparser.rb
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# This test verifies type unparser for RubyBreaker types.
|
|
2
2
|
|
|
3
|
-
dir = File.dirname(__FILE__)
|
|
4
3
|
require "test/unit"
|
|
5
|
-
|
|
4
|
+
require_relative "../../lib/rubybreaker/type"
|
|
6
5
|
|
|
7
6
|
class UnparserTest < Test::Unit::TestCase
|
|
8
7
|
|
|
@@ -30,14 +29,14 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
30
29
|
|
|
31
30
|
def test_nominal_type()
|
|
32
31
|
t1 = NominalType.new(A)
|
|
33
|
-
str1 = TypeUnparser.unparse(t1)
|
|
32
|
+
str1 = TypeUnparser.unparse(t1, :namespace => UnparserTest)
|
|
34
33
|
# puts str1
|
|
35
34
|
assert_equal("a",str1)
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
def test_self_type()
|
|
39
38
|
t1 = SelfType.new()
|
|
40
|
-
str1 = TypeUnparser.unparse(t1)
|
|
39
|
+
str1 = TypeUnparser.unparse(t1, :namespace => UnparserTest)
|
|
41
40
|
# puts str1
|
|
42
41
|
assert_equal("self", str1)
|
|
43
42
|
end
|
|
@@ -45,7 +44,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
45
44
|
def test_opt_type()
|
|
46
45
|
t1 = NominalType.new(A)
|
|
47
46
|
t2 = OptionalType.new(t1)
|
|
48
|
-
str2 = TypeUnparser.unparse(t2)
|
|
47
|
+
str2 = TypeUnparser.unparse(t2, :namespace => UnparserTest)
|
|
49
48
|
# puts str1
|
|
50
49
|
assert_equal("a?",str2)
|
|
51
50
|
end
|
|
@@ -55,7 +54,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
55
54
|
t2 = NominalType.new(B)
|
|
56
55
|
t3 = OrType.new([t1, t2])
|
|
57
56
|
t4 = OptionalType.new(t3)
|
|
58
|
-
str4 = TypeUnparser.unparse(t4)
|
|
57
|
+
str4 = TypeUnparser.unparse(t4, :namespace => UnparserTest)
|
|
59
58
|
# puts str1
|
|
60
59
|
assert_equal("(a || b)?",str4)
|
|
61
60
|
end
|
|
@@ -63,15 +62,15 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
63
62
|
def test_star_type()
|
|
64
63
|
t1 = NominalType.new(A)
|
|
65
64
|
t2 = VarLengthType.new(t1)
|
|
66
|
-
str2 = TypeUnparser.unparse(t2)
|
|
65
|
+
str2 = TypeUnparser.unparse(t2, :namespace => UnparserTest)
|
|
67
66
|
# puts str1
|
|
68
|
-
assert_equal("a*",str2)
|
|
67
|
+
assert_equal("a*", str2)
|
|
69
68
|
end
|
|
70
69
|
|
|
71
70
|
def test_star_duck_type()
|
|
72
71
|
t1 = DuckType.new([:foo, :bar])
|
|
73
72
|
t2 = VarLengthType.new(t1)
|
|
74
|
-
str2 = TypeUnparser.unparse(t2)
|
|
73
|
+
str2 = TypeUnparser.unparse(t2, :namespace => UnparserTest)
|
|
75
74
|
# puts str1
|
|
76
75
|
assert_equal("[bar, foo]*",str2)
|
|
77
76
|
end
|
|
@@ -79,7 +78,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
79
78
|
def test_star_fusion_type()
|
|
80
79
|
t1 = FusionType.new(NominalType.new(A), [:foo, :bar])
|
|
81
80
|
t2 = VarLengthType.new(t1)
|
|
82
|
-
str2 = TypeUnparser.unparse(t2)
|
|
81
|
+
str2 = TypeUnparser.unparse(t2, :namespace => UnparserTest)
|
|
83
82
|
# puts str1
|
|
84
83
|
assert_equal("a[bar, foo]*",str2)
|
|
85
84
|
end
|
|
@@ -89,49 +88,49 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
89
88
|
t2 = NominalType.new(B)
|
|
90
89
|
t3 = OrType.new([t1, t2])
|
|
91
90
|
t4 = VarLengthType.new(t3)
|
|
92
|
-
str4 = TypeUnparser.unparse(t4)
|
|
91
|
+
str4 = TypeUnparser.unparse(t4, :namespace => UnparserTest)
|
|
93
92
|
# puts str1
|
|
94
93
|
assert_equal("(a || b)*",str4)
|
|
95
94
|
end
|
|
96
95
|
|
|
97
96
|
def test_duck_type()
|
|
98
97
|
t1 = DuckType.new(["+"])
|
|
99
|
-
str1 = TypeUnparser.unparse(t1)
|
|
98
|
+
str1 = TypeUnparser.unparse(t1, :namespace => UnparserTest)
|
|
100
99
|
# puts str1
|
|
101
100
|
assert_equal("[+]",str1)
|
|
102
101
|
end
|
|
103
102
|
|
|
104
103
|
def test_duck_type_more_meths()
|
|
105
104
|
t1 = DuckType.new(["+","foo","bar"])
|
|
106
|
-
str1 = TypeUnparser.unparse(t1)
|
|
105
|
+
str1 = TypeUnparser.unparse(t1, :namespace => UnparserTest)
|
|
107
106
|
#puts str1
|
|
108
107
|
assert_equal("[+, bar, foo]",str1)
|
|
109
108
|
end
|
|
110
109
|
|
|
111
110
|
def test_duck_type_symbolic_meths()
|
|
112
111
|
t1 = DuckType.new(["+","-","[]","[]="])
|
|
113
|
-
str1 = TypeUnparser.unparse(t1)
|
|
112
|
+
str1 = TypeUnparser.unparse(t1, :namespace => UnparserTest)
|
|
114
113
|
#puts str1
|
|
115
114
|
assert_equal("[+, -, [], []=]",str1)
|
|
116
115
|
end
|
|
117
116
|
|
|
118
117
|
def test_fusion_type()
|
|
119
118
|
t1 = FusionType.new(NominalType.new(A), ["+"])
|
|
120
|
-
str1 = TypeUnparser.unparse(t1)
|
|
119
|
+
str1 = TypeUnparser.unparse(t1, :namespace => UnparserTest)
|
|
121
120
|
# puts str1
|
|
122
121
|
assert_equal("a[+]",str1)
|
|
123
122
|
end
|
|
124
123
|
|
|
125
124
|
def test_fusion_type_more_meths()
|
|
126
125
|
t1 = FusionType.new(NominalType.new(A), ["+","foo","bar"])
|
|
127
|
-
str1 = TypeUnparser.unparse(t1)
|
|
126
|
+
str1 = TypeUnparser.unparse(t1, :namespace => UnparserTest)
|
|
128
127
|
# puts str1
|
|
129
128
|
assert_equal("a[+, bar, foo]",str1)
|
|
130
129
|
end
|
|
131
130
|
|
|
132
131
|
def test_fusion_type_symbolic_meths()
|
|
133
132
|
t1 = FusionType.new(NominalType.new(A), ["+","-","[]","[]="])
|
|
134
|
-
str1 = TypeUnparser.unparse(t1)
|
|
133
|
+
str1 = TypeUnparser.unparse(t1, :namespace => UnparserTest)
|
|
135
134
|
# puts str1
|
|
136
135
|
assert_equal("a[+, -, [], []=]",str1)
|
|
137
136
|
end
|
|
@@ -140,7 +139,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
140
139
|
t1 = NominalType.new(A)
|
|
141
140
|
t2 = NominalType.new(B)
|
|
142
141
|
t3 = OrType.new([t1,t2])
|
|
143
|
-
str3 = TypeUnparser.unparse(t3)
|
|
142
|
+
str3 = TypeUnparser.unparse(t3, :namespace => UnparserTest)
|
|
144
143
|
# puts str3
|
|
145
144
|
assert_equal("a || b", str3)
|
|
146
145
|
end
|
|
@@ -150,7 +149,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
150
149
|
t2 = NominalType.new(B)
|
|
151
150
|
t3 = NominalType.new(C)
|
|
152
151
|
t4 = OrType.new([t1,t2,t3])
|
|
153
|
-
str4 = TypeUnparser.unparse(t4)
|
|
152
|
+
str4 = TypeUnparser.unparse(t4, :namespace => UnparserTest)
|
|
154
153
|
# puts str3
|
|
155
154
|
assert_equal("a || b || c", str4)
|
|
156
155
|
end
|
|
@@ -159,7 +158,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
159
158
|
t1 = NominalType.new(A)
|
|
160
159
|
t2 = NominalType.new(B)
|
|
161
160
|
t3 = BlockType.new([t1],nil,t2)
|
|
162
|
-
str3 = TypeUnparser.unparse(t3)
|
|
161
|
+
str3 = TypeUnparser.unparse(t3, :namespace => UnparserTest)
|
|
163
162
|
# puts str3
|
|
164
163
|
assert_equal("|a| -> b",str3)
|
|
165
164
|
end
|
|
@@ -169,7 +168,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
169
168
|
t2 = NominalType.new(B)
|
|
170
169
|
t3 = NominalType.new(C)
|
|
171
170
|
t4 = BlockType.new([t1,t2],nil,t3)
|
|
172
|
-
str4 = TypeUnparser.unparse(t4)
|
|
171
|
+
str4 = TypeUnparser.unparse(t4, :namespace => UnparserTest)
|
|
173
172
|
# puts str3
|
|
174
173
|
assert_equal("|a, b| -> c",str4)
|
|
175
174
|
end
|
|
@@ -179,7 +178,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
179
178
|
t2 = NominalType.new(B)
|
|
180
179
|
t3 = SelfType.new()
|
|
181
180
|
t4 = BlockType.new([t1,t2],nil,t3)
|
|
182
|
-
str4 = TypeUnparser.unparse(t4)
|
|
181
|
+
str4 = TypeUnparser.unparse(t4, :namespace => UnparserTest)
|
|
183
182
|
# puts str3
|
|
184
183
|
assert_equal("|a, b| -> self",str4)
|
|
185
184
|
end
|
|
@@ -190,7 +189,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
190
189
|
t3 = NominalType.new(C)
|
|
191
190
|
t4 = NominalType.new(D)
|
|
192
191
|
t5 = BlockType.new([t1],BlockType.new([t2],nil,t3),t4)
|
|
193
|
-
str5 = TypeUnparser.unparse(t5)
|
|
192
|
+
str5 = TypeUnparser.unparse(t5, :namespace => UnparserTest)
|
|
194
193
|
# puts str5
|
|
195
194
|
assert_equal("|a| {|b| -> c} -> d",str5)
|
|
196
195
|
end
|
|
@@ -202,7 +201,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
202
201
|
t4 = NominalType.new(D)
|
|
203
202
|
t5 = NominalType.new(E)
|
|
204
203
|
t6 = BlockType.new([t1,t2],BlockType.new([t3],nil,t4),t5)
|
|
205
|
-
str6 = TypeUnparser.unparse(t6)
|
|
204
|
+
str6 = TypeUnparser.unparse(t6, :namespace => UnparserTest)
|
|
206
205
|
# puts str5
|
|
207
206
|
assert_equal("|a, b| {|c| -> d} -> e",str6)
|
|
208
207
|
end
|
|
@@ -214,7 +213,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
214
213
|
t4 = NominalType.new(D)
|
|
215
214
|
t5 = NominalType.new(E)
|
|
216
215
|
t6 = BlockType.new([OrType.new([t1,t2])],BlockType.new([t3],nil,t4),t5)
|
|
217
|
-
str6 = TypeUnparser.unparse(t6)
|
|
216
|
+
str6 = TypeUnparser.unparse(t6, :namespace => UnparserTest)
|
|
218
217
|
# puts str5
|
|
219
218
|
assert_equal("|a || b| {|c| -> d} -> e",str6)
|
|
220
219
|
end
|
|
@@ -223,7 +222,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
223
222
|
t1 = NominalType.new(A)
|
|
224
223
|
t2 = NominalType.new(B)
|
|
225
224
|
t3 = MethodType.new("m",[t1],nil,t2)
|
|
226
|
-
str3 = TypeUnparser.unparse(t3)
|
|
225
|
+
str3 = TypeUnparser.unparse(t3, :namespace => UnparserTest)
|
|
227
226
|
# puts str3
|
|
228
227
|
assert_equal("m(a) -> b", str3)
|
|
229
228
|
end
|
|
@@ -232,7 +231,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
232
231
|
t1 = NominalType.new(A)
|
|
233
232
|
t2 = NominalType.new(B)
|
|
234
233
|
t3 = MethodType.new("==",[t1],nil,t2)
|
|
235
|
-
str3 = TypeUnparser.unparse(t3)
|
|
234
|
+
str3 = TypeUnparser.unparse(t3, :namespace => UnparserTest)
|
|
236
235
|
# puts str3
|
|
237
236
|
assert_equal("==(a) -> b", str3)
|
|
238
237
|
end
|
|
@@ -242,7 +241,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
242
241
|
t2 = NominalType.new(B)
|
|
243
242
|
t3 = NominalType.new(C)
|
|
244
243
|
t4 = MethodType.new("m",[t1,t2],nil,t3)
|
|
245
|
-
str4 = TypeUnparser.unparse(t4)
|
|
244
|
+
str4 = TypeUnparser.unparse(t4, :namespace => UnparserTest)
|
|
246
245
|
# puts str3
|
|
247
246
|
assert_equal("m(a, b) -> c", str4)
|
|
248
247
|
end
|
|
@@ -252,7 +251,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
252
251
|
t2 = NominalType.new(B)
|
|
253
252
|
t3 = SelfType.new()
|
|
254
253
|
t4 = MethodType.new("m",[t1,t2],nil,t3)
|
|
255
|
-
str4 = TypeUnparser.unparse(t4)
|
|
254
|
+
str4 = TypeUnparser.unparse(t4, :namespace => UnparserTest)
|
|
256
255
|
# puts str3
|
|
257
256
|
assert_equal("m(a, b) -> self", str4)
|
|
258
257
|
end
|
|
@@ -262,7 +261,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
262
261
|
t2 = NominalType.new(B)
|
|
263
262
|
t3 = NominalType.new(C)
|
|
264
263
|
t4 = MethodType.new("m",[OrType.new([t1,t2])],nil,t3)
|
|
265
|
-
str4 = TypeUnparser.unparse(t4)
|
|
264
|
+
str4 = TypeUnparser.unparse(t4, :namespace => UnparserTest)
|
|
266
265
|
# puts str3
|
|
267
266
|
assert_equal("m(a || b) -> c", str4)
|
|
268
267
|
end
|
|
@@ -273,7 +272,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
273
272
|
t3 = NominalType.new(C)
|
|
274
273
|
t4 = NominalType.new(D)
|
|
275
274
|
t5 = MethodType.new("m",[t1],BlockType.new([t2],nil,t3),t4)
|
|
276
|
-
str5 = TypeUnparser.unparse(t5)
|
|
275
|
+
str5 = TypeUnparser.unparse(t5, :namespace => UnparserTest)
|
|
277
276
|
# puts str5
|
|
278
277
|
assert_equal("m(a) {|b| -> c} -> d", str5)
|
|
279
278
|
end
|
|
@@ -285,7 +284,7 @@ class UnparserTest < Test::Unit::TestCase
|
|
|
285
284
|
t4 = NominalType.new(D)
|
|
286
285
|
t5 = NominalType.new(E)
|
|
287
286
|
t6 = MethodType.new("m",[t1,t2],BlockType.new([t3],nil,t4),t5)
|
|
288
|
-
str6 = TypeUnparser.unparse(t6)
|
|
287
|
+
str6 = TypeUnparser.unparse(t6, :namespace => UnparserTest)
|
|
289
288
|
# puts str5
|
|
290
289
|
assert_equal("m(a, b) {|c| -> d} -> e", str6)
|
|
291
290
|
end
|
data/webpage/index.html
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
<h1>Introduction</h1>
|
|
18
18
|
|
|
19
|
-
<p>RubyBreaker is a dynamic type documentation tool written
|
|
19
|
+
<p>RubyBreaker is a dynamic type documentation tool written in pure Ruby. It
|
|
20
20
|
provides the framework for dynamically instrumenting a Ruby program to
|
|
21
21
|
monitor objects during executions and document the observed type
|
|
22
22
|
information. The type documentation generated by RubyBreaker is also an
|
|
@@ -27,7 +27,7 @@ program.</p>
|
|
|
27
27
|
<p>The primary goal of RubyBreaker is to assign a type signature to every
|
|
28
28
|
method in designated modules and classes. A type signature is written in
|
|
29
29
|
the RubyBreaker Type Annotation Language which resembles the documentation
|
|
30
|
-
style used in
|
|
30
|
+
style used in Ruby API Doc. Overall, this tool should help Ruby programmers
|
|
31
31
|
document their code more rigorously and effectively. Currently, manual
|
|
32
32
|
modification of the user program is required to run RubyBreaker, but this is
|
|
33
33
|
kept minimal.</p>
|
|
@@ -40,10 +40,9 @@ be found in <a href="rdoc/index.html">here</a>.</p>
|
|
|
40
40
|
<h2>Limitations</h2>
|
|
41
41
|
|
|
42
42
|
<ul>
|
|
43
|
-
<li>It only works on toy Ruby programs so far :)</li>
|
|
44
43
|
<li>Block argument cannot be auto-documented. (Inherent)</li>
|
|
45
44
|
<li>Manual modification (minimal) of code is required.</li>
|
|
46
|
-
<li>
|
|
45
|
+
<li>Parametric polymorphic types are not supported.</li>
|
|
47
46
|
</ul>
|
|
48
47
|
|
|
49
48
|
|
|
@@ -153,7 +152,8 @@ necessary to obtain precise type information.</p>
|
|
|
153
152
|
First, the user must indicate which modules are subject to analysis and
|
|
154
153
|
which modules can be used for the analysis. Next, the user has to indicate
|
|
155
154
|
where the entry point of the program is. Alternatively, he has to make a
|
|
156
|
-
small change to the test cases to use RubyBreaker's testing framework
|
|
155
|
+
small change to the test cases to use RubyBreaker's testing framework. (If
|
|
156
|
+
you are using RSpec, there is no need for this change.)</p>
|
|
157
157
|
|
|
158
158
|
<h3>Breakable and Broken</h3>
|
|
159
159
|
|
|
@@ -236,9 +236,7 @@ end
|
|
|
236
236
|
<p>In Ruby, as soon as a file is <code>require</code>d, the execution of that file begins.
|
|
237
237
|
For RubyBreaker, however, it is not trivial to find the actual starting
|
|
238
238
|
point of the program because there <em>has</em> to be a clear point in time at
|
|
239
|
-
which monitoring of <code>Breakable</code> modules begins
|
|
240
|
-
attempting to instrument and monitor at the same time will cause an infinite
|
|
241
|
-
loop!</em></p>
|
|
239
|
+
which monitoring of <code>Breakable</code> modules begins.</p>
|
|
242
240
|
|
|
243
241
|
<p>Indicating the program entry point is simply done by inserting the following
|
|
244
242
|
line at the code (assuming "<code>require 'rubybreaker'</code>" is already placed at
|
|
@@ -254,11 +252,11 @@ run the instrumented code (for <code>Breakable</code> modules) which will gather
|
|
|
254
252
|
information for methods.</p>
|
|
255
253
|
|
|
256
254
|
<p>Although this seems simple and easy, this is not the recommended way for
|
|
257
|
-
analyzing a program. Why? Because RubyBreaker
|
|
258
|
-
|
|
259
|
-
|
|
255
|
+
analyzing a program. Why? Because RubyBreaker comes with a replacement for
|
|
256
|
+
the built-in testing framework for Ruby. Even better, if you are using
|
|
257
|
+
RSpec, there is no need to change any test code.</p>
|
|
260
258
|
|
|
261
|
-
<h3>Using
|
|
259
|
+
<h3>Using the Built-in Testing Framework</h3>
|
|
262
260
|
|
|
263
261
|
<p>Instead of manually inserting the entry point indicator into the program,
|
|
264
262
|
the user can take advantage of the Ruby Unit Test framework. This is the
|
|
@@ -274,11 +272,28 @@ class TestClassA < Test::Unit::TestCase
|
|
|
274
272
|
end
|
|
275
273
|
</code></pre>
|
|
276
274
|
|
|
277
|
-
<p>That's it
|
|
275
|
+
<p>That's it! Also, remember that classes and modules can be re-opened for
|
|
276
|
+
"patches" in Ruby. This means that the original classes or modules do not
|
|
277
|
+
need to be modified to include <code>Broken</code> and/or <code>Breakable</code>. In each test
|
|
278
|
+
suite or test case, those classes and modules can be re-opened to include
|
|
279
|
+
<code>Broken</code> and/or <code>Breakable</code>. The following shows an example of such a test
|
|
280
|
+
case.</p>
|
|
278
281
|
|
|
279
|
-
<
|
|
280
|
-
|
|
281
|
-
|
|
282
|
+
<pre><code>require "rubybreaker"
|
|
283
|
+
require "test/unit"
|
|
284
|
+
class A
|
|
285
|
+
include RubyBreaker::Breakable
|
|
286
|
+
end
|
|
287
|
+
class TestClassA < Test::Unit::TestCase
|
|
288
|
+
...
|
|
289
|
+
end
|
|
290
|
+
</code></pre>
|
|
291
|
+
|
|
292
|
+
<h3>Using RSpec</h3>
|
|
293
|
+
|
|
294
|
+
<p>If using RSpec, it is even easier! No changes are needed for the test code.
|
|
295
|
+
Really! <em>Well, it is still necessary to <code>require rubybreaker</code> and manually
|
|
296
|
+
insert <code>Breakable</code> and <code>Broken</code> to appropriate classes and modules.</em></p>
|
|
282
297
|
|
|
283
298
|
<h2>Type Annotation</h2>
|
|
284
299
|
|
|
@@ -316,7 +331,9 @@ instance, <code>fixnum</code> is an object of type <code>Fixnum</code>. Use lowe
|
|
|
316
331
|
underscores instead of <em>camelized</em> name. <code>MyClass</code>, for example would be
|
|
317
332
|
<code>my_class</code> in RubyBreaker type signatures. There is no particular
|
|
318
333
|
reason for this convention other than it is the common practice used in
|
|
319
|
-
RubyDoc
|
|
334
|
+
RubyDoc. Use <code>/</code> to indicate the namespace delimiter <code>::</code>. For example,
|
|
335
|
+
<code>NamspaceA::ClassB</code> would be represented by <code>namespace_a/class_b</code> in
|
|
336
|
+
a RubyBreaker type signature.</p>
|
|
320
337
|
|
|
321
338
|
<h3>Self Type</h3>
|
|
322
339
|
|
|
@@ -475,8 +492,6 @@ RubyBreaker. <em>Technical documentation coming soon...</em></p>
|
|
|
475
492
|
University of Maryland and represents an object using a structural type with
|
|
476
493
|
respect to a nominal type.</p>
|
|
477
494
|
|
|
478
|
-
<hr />
|
|
479
|
-
|
|
480
495
|
<h1>Copyright</h1>
|
|
481
496
|
|
|
482
497
|
<p>Copyright (c) 2012 Jong-hoon (David) An. All Rights Reserved.</p>
|