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/NEWS
CHANGED
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Introduction
|
|
4
4
|
|
|
5
|
-
RubyBreaker is a dynamic type documentation tool written
|
|
5
|
+
RubyBreaker is a dynamic type documentation tool written in pure Ruby. It
|
|
6
6
|
provides the framework for dynamically instrumenting a Ruby program to
|
|
7
7
|
monitor objects during executions and document the observed type
|
|
8
8
|
information. The type documentation generated by RubyBreaker is also an
|
|
@@ -13,7 +13,7 @@ program.
|
|
|
13
13
|
The primary goal of RubyBreaker is to assign a type signature to every
|
|
14
14
|
method in designated modules and classes. A type signature is written in
|
|
15
15
|
the RubyBreaker Type Annotation Language which resembles the documentation
|
|
16
|
-
style used in
|
|
16
|
+
style used in Ruby API Doc. Overall, this tool should help Ruby programmers
|
|
17
17
|
document their code more rigorously and effectively. Currently, manual
|
|
18
18
|
modification of the user program is required to run RubyBreaker, but this is
|
|
19
19
|
kept minimal.
|
|
@@ -25,10 +25,9 @@ be found in [here](rdoc/index.html).
|
|
|
25
25
|
|
|
26
26
|
## Limitations
|
|
27
27
|
|
|
28
|
-
* It only works on toy Ruby programs so far :)
|
|
29
28
|
* Block argument cannot be auto-documented. (Inherent)
|
|
30
29
|
* Manual modification (minimal) of code is required.
|
|
31
|
-
*
|
|
30
|
+
* Parametric polymorphic types are not supported.
|
|
32
31
|
|
|
33
32
|
## Requirements
|
|
34
33
|
|
|
@@ -129,7 +128,8 @@ In order to use RubyBreaker, there needs two kinds of manual code changes.
|
|
|
129
128
|
First, the user must indicate which modules are subject to analysis and
|
|
130
129
|
which modules can be used for the analysis. Next, the user has to indicate
|
|
131
130
|
where the entry point of the program is. Alternatively, he has to make a
|
|
132
|
-
small change to the test cases to use RubyBreaker's testing framework.
|
|
131
|
+
small change to the test cases to use RubyBreaker's testing framework. (If
|
|
132
|
+
you are using RSpec, there is no need for this change.)
|
|
133
133
|
|
|
134
134
|
### Breakable and Broken
|
|
135
135
|
|
|
@@ -209,9 +209,7 @@ auto-documented and manually documented, respectively.
|
|
|
209
209
|
In Ruby, as soon as a file is `require`d, the execution of that file begins.
|
|
210
210
|
For RubyBreaker, however, it is not trivial to find the actual starting
|
|
211
211
|
point of the program because there *has* to be a clear point in time at
|
|
212
|
-
which monitoring of `Breakable` modules begins.
|
|
213
|
-
attempting to instrument and monitor at the same time will cause an infinite
|
|
214
|
-
loop!*
|
|
212
|
+
which monitoring of `Breakable` modules begins.
|
|
215
213
|
|
|
216
214
|
Indicating the program entry point is simply done by inserting the following
|
|
217
215
|
line at the code (assuming "`require 'rubybreaker'`" is already placed at
|
|
@@ -226,11 +224,11 @@ run the instrumented code (for `Breakable` modules) which will gather type
|
|
|
226
224
|
information for methods.
|
|
227
225
|
|
|
228
226
|
Although this seems simple and easy, this is not the recommended way for
|
|
229
|
-
analyzing a program. Why? Because RubyBreaker
|
|
230
|
-
|
|
231
|
-
|
|
227
|
+
analyzing a program. Why? Because RubyBreaker comes with a replacement for
|
|
228
|
+
the built-in testing framework for Ruby. Even better, if you are using
|
|
229
|
+
RSpec, there is no need to change any test code.
|
|
232
230
|
|
|
233
|
-
### Using
|
|
231
|
+
### Using the Built-in Testing Framework
|
|
234
232
|
|
|
235
233
|
Instead of manually inserting the entry point indicator into the program,
|
|
236
234
|
the user can take advantage of the Ruby Unit Test framework. This is the
|
|
@@ -245,11 +243,27 @@ one.
|
|
|
245
243
|
# ...tests!...
|
|
246
244
|
end
|
|
247
245
|
|
|
248
|
-
That's it!
|
|
246
|
+
That's it! Also, remember that classes and modules can be re-opened for
|
|
247
|
+
"patches" in Ruby. This means that the original classes or modules do not
|
|
248
|
+
need to be modified to include `Broken` and/or `Breakable`. In each test
|
|
249
|
+
suite or test case, those classes and modules can be re-opened to include
|
|
250
|
+
`Broken` and/or `Breakable`. The following shows an example of such a test
|
|
251
|
+
case.
|
|
249
252
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
+
require "rubybreaker"
|
|
254
|
+
require "test/unit"
|
|
255
|
+
class A
|
|
256
|
+
include RubyBreaker::Breakable
|
|
257
|
+
end
|
|
258
|
+
class TestClassA < Test::Unit::TestCase
|
|
259
|
+
...
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
### Using RSpec
|
|
263
|
+
|
|
264
|
+
If using RSpec, it is even easier! No changes are needed for the test code.
|
|
265
|
+
Really! _Well, it is still necessary to `require rubybreaker` and manually
|
|
266
|
+
insert `Breakable` and `Broken` to appropriate classes and modules._
|
|
253
267
|
|
|
254
268
|
## Type Annotation
|
|
255
269
|
|
|
@@ -286,7 +300,9 @@ instance, `fixnum` is an object of type `Fixnum`. Use lower-case letters and
|
|
|
286
300
|
underscores instead of _camelized_ name. `MyClass`, for example would be
|
|
287
301
|
`my_class` in RubyBreaker type signatures. There is no particular
|
|
288
302
|
reason for this convention other than it is the common practice used in
|
|
289
|
-
RubyDoc.
|
|
303
|
+
RubyDoc. Use `/` to indicate the namespace delimiter `::`. For example,
|
|
304
|
+
`NamspaceA::ClassB` would be represented by `namespace_a/class_b` in
|
|
305
|
+
a RubyBreaker type signature.
|
|
290
306
|
|
|
291
307
|
### Self Type
|
|
292
308
|
|
|
@@ -443,8 +459,6 @@ The term, "Fusion Type," is first coined by Professor Michael W. Hicks at
|
|
|
443
459
|
University of Maryland and represents an object using a structural type with
|
|
444
460
|
respect to a nominal type.
|
|
445
461
|
|
|
446
|
-
* * *
|
|
447
|
-
|
|
448
462
|
# Copyright
|
|
449
463
|
Copyright (c) 2012 Jong-hoon (David) An. All Rights Reserved.
|
|
450
464
|
|
data/Rakefile
CHANGED
|
@@ -9,7 +9,13 @@ require "rake/clean"
|
|
|
9
9
|
begin
|
|
10
10
|
require "rdiscount" # used to generate the doc html page
|
|
11
11
|
rescue LoadError => e
|
|
12
|
-
puts "[WARNING] No rdiscount is installed."
|
|
12
|
+
puts "[WARNING] No rdiscount is installed on this computer."
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
require 'rspec/core/rake_task'
|
|
17
|
+
rescue LoadError => e
|
|
18
|
+
puts "[WARNING] No rspec-core is installed on this computer."
|
|
13
19
|
end
|
|
14
20
|
|
|
15
21
|
# Use rake/clean to remove generated files
|
|
@@ -23,7 +29,7 @@ CLEAN.concat(FileList["webpage/rdoc",
|
|
|
23
29
|
task :default => [:test]
|
|
24
30
|
|
|
25
31
|
desc "Do all"
|
|
26
|
-
task :all => [:parser, :test, :rdoc, :webpage, :gem] do |t|
|
|
32
|
+
task :all => [:parser, :test, :rspec, :rdoc, :webpage, :gem] do |t|
|
|
27
33
|
end
|
|
28
34
|
|
|
29
35
|
desc "Generate gemspec"
|
|
@@ -39,15 +45,16 @@ end
|
|
|
39
45
|
|
|
40
46
|
desc "Generate the webpage"
|
|
41
47
|
task :webpage do |t|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
if defined?(RDiscount)
|
|
49
|
+
dir = File.dirname(__FILE__)
|
|
50
|
+
readme_md = "#{dir}/README.md"
|
|
51
|
+
output = "#{dir}/webpage/index.html"
|
|
52
|
+
body = RDiscount.new(File.read(readme_md)).to_html
|
|
53
|
+
header = File.read("#{dir}/webpage/header.html")
|
|
54
|
+
footer = File.read("#{dir}/webpage/footer.html")
|
|
55
|
+
html = header + body + footer
|
|
56
|
+
File.open(output, "w") { |f| f.write(html) }
|
|
57
|
+
end
|
|
51
58
|
end
|
|
52
59
|
|
|
53
60
|
desc "Generate parser"
|
|
@@ -57,9 +64,20 @@ task :parser do |t|
|
|
|
57
64
|
end
|
|
58
65
|
|
|
59
66
|
desc "Run basic tests"
|
|
60
|
-
Rake::TestTask.new("test") do |t|
|
|
67
|
+
Rake::TestTask.new(:"test") do |t|
|
|
61
68
|
dir = File.dirname(__FILE__)
|
|
62
69
|
t.libs << "lib"
|
|
63
|
-
|
|
70
|
+
test_files = FileList["test/ts_*.rb"]
|
|
71
|
+
test_files.exclude("test/ts_rspec.rb")
|
|
72
|
+
t.test_files = test_files
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
if defined?(RSpec)
|
|
76
|
+
desc "Run RSpec test"
|
|
77
|
+
RSpec::Core::RakeTask.new(:rspec) do |t|
|
|
78
|
+
t.pattern = ["test/ts_rspec.rb"]
|
|
79
|
+
t.fail_on_error = false
|
|
80
|
+
end
|
|
64
81
|
end
|
|
65
82
|
|
|
83
|
+
|
data/TODO
CHANGED
|
@@ -6,11 +6,13 @@ to be dynamically instrumented (as "breakable" methods are) and inspected
|
|
|
6
6
|
for each argument type and return type. Although this is still a dynamic
|
|
7
7
|
type checking, it finds type errors earlier in the program execution.
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# Additional Testing Frameworks
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
RubyBreaker supports the built-in testing framework and RSpec. There are
|
|
12
|
+
other testing frameworks such as Cucumber or Shouda. Since RubyBreaker's
|
|
13
|
+
goal is to help Ruby programmers write better code by taking advantage of
|
|
14
|
+
existing test suites, it seems appropriate to support as many testing
|
|
15
|
+
frameworks as possible.
|
|
14
16
|
|
|
15
17
|
# RDoc and YARD Documentation Support
|
|
16
18
|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.4
|
data/bin/rubybreaker
CHANGED
|
@@ -11,7 +11,7 @@ module RubyBreaker
|
|
|
11
11
|
# This sets up the logger for debugging RubyBreaker
|
|
12
12
|
def self.setup_logger #:nodoc:
|
|
13
13
|
return if defined?(LOGGER)
|
|
14
|
-
out = if (defined?(OPTIONS) && !OPTIONS[:file].empty?)
|
|
14
|
+
out = if (defined?(OPTIONS) && OPTIONS[:debug] && !OPTIONS[:file].empty?)
|
|
15
15
|
then "#{OPTIONS[:file]}.log"
|
|
16
16
|
else STDOUT
|
|
17
17
|
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require "prettyprint"
|
|
2
|
+
require_relative "../type"
|
|
3
|
+
|
|
4
|
+
module RubyBreaker
|
|
5
|
+
|
|
6
|
+
module Runtime
|
|
7
|
+
|
|
8
|
+
# This module handles unparsing type signatures.
|
|
9
|
+
module TypesigUnparser
|
|
10
|
+
|
|
11
|
+
include TypeDefs
|
|
12
|
+
|
|
13
|
+
# This array lists monitored modules/classes that are outputed.
|
|
14
|
+
DOCUMENTED = []
|
|
15
|
+
|
|
16
|
+
# Pretty prints type information for methods
|
|
17
|
+
def self.pp_methods(pp, meth_type_map, opts={})
|
|
18
|
+
meth_type_map.each { |meth_name, meth_type|
|
|
19
|
+
case meth_type
|
|
20
|
+
when MethodType
|
|
21
|
+
pp.breakable()
|
|
22
|
+
pp.text("typesig(\"")
|
|
23
|
+
TypeUnparser.unparse_pp(pp, meth_type, opts)
|
|
24
|
+
pp.text("\")")
|
|
25
|
+
when MethodListType
|
|
26
|
+
meth_type.types.each { |real_meth_type|
|
|
27
|
+
pp.breakable()
|
|
28
|
+
pp.text("typesig(\"")
|
|
29
|
+
TypeUnparser.unparse_pp(pp, real_meth_type, opts)
|
|
30
|
+
pp.text("\")")
|
|
31
|
+
}
|
|
32
|
+
else
|
|
33
|
+
# Can't happen
|
|
34
|
+
end
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Pretty prints type information for the module/class
|
|
39
|
+
def self.pp_module(pp, mod, opts={})
|
|
40
|
+
# Skip it if we already have seen it
|
|
41
|
+
return if DOCUMENTED.include?(mod) || mod.to_s[0..1] == "#<"
|
|
42
|
+
|
|
43
|
+
# Remember that we have documented this module/class
|
|
44
|
+
DOCUMENTED << mod
|
|
45
|
+
|
|
46
|
+
# Get the method type mapping
|
|
47
|
+
meth_type_map = Inspector.inspect_all(mod)
|
|
48
|
+
|
|
49
|
+
# Check if this module is a class
|
|
50
|
+
keyword = mod.instance_of?(Class) ? "class" : "module"
|
|
51
|
+
|
|
52
|
+
pp.text("#{keyword} #{mod.to_s}", 80)
|
|
53
|
+
pp.nest(2) do
|
|
54
|
+
pp.breakable("")
|
|
55
|
+
pp.text("include RubyBreaker::Broken", 80)
|
|
56
|
+
|
|
57
|
+
# See if there is any class method to show
|
|
58
|
+
eigen = Runtime.eigen_class(mod)
|
|
59
|
+
if !DOCUMENTED.include?(eigen)
|
|
60
|
+
DOCUMENTED << eigen
|
|
61
|
+
eigen_meth_type_map = Inspector.inspect_all(eigen)
|
|
62
|
+
if eigen_meth_type_map.size > 0
|
|
63
|
+
pp.breakable()
|
|
64
|
+
pp.text("class << self", 80)
|
|
65
|
+
pp.nest(2) do
|
|
66
|
+
self.pp_methods(pp, eigen_meth_type_map, :namespace => eigen)
|
|
67
|
+
end
|
|
68
|
+
pp.breakable()
|
|
69
|
+
pp.text("end", 80)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
self.pp_methods(pp, meth_type_map, :namespace => mod)
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
pp.breakable()
|
|
77
|
+
pp.text("end",80)
|
|
78
|
+
pp.breakable()
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# This method unparses the type information in the specified module,
|
|
82
|
+
# displaying one or more type signatures for each method that is
|
|
83
|
+
# monitored during runtime.
|
|
84
|
+
def self.unparse(mod, opts={})
|
|
85
|
+
str = ""
|
|
86
|
+
pp = PrettyPrint.new(str)
|
|
87
|
+
self.pp_module(pp, mod, opts)
|
|
88
|
+
pp.flush
|
|
89
|
+
return str
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
data/lib/rubybreaker/runtime.rb
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#-
|
|
2
|
+
# This file overrides the describe method of RSpec to call the RubyBreaker
|
|
3
|
+
# setup first.
|
|
4
|
+
|
|
5
|
+
RUBYBREAKER_RSPEC_PREFIX = "__rubybreaker"
|
|
6
|
+
|
|
7
|
+
if defined?(RSpec)
|
|
8
|
+
alias :"#{RUBYBREAKER_RSPEC_PREFIX}_describe" :describe
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def describe(*args,&blk)
|
|
12
|
+
RubyBreaker::Main.setup if defined?(RubyBreaker)
|
|
13
|
+
send(:"#{RUBYBREAKER_RSPEC_PREFIX}_describe", *args, &blk)
|
|
14
|
+
end
|
|
15
|
+
|
|
@@ -9,11 +9,11 @@ module RubyBreaker
|
|
|
9
9
|
# class.
|
|
10
10
|
module TestCase
|
|
11
11
|
|
|
12
|
-
def self.
|
|
12
|
+
def self.__rubybreaker_setup()
|
|
13
13
|
Main.setup()
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def self.
|
|
16
|
+
def self.__rubybreaker_teardown()
|
|
17
17
|
# Main.output()
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -25,9 +25,9 @@ module RubyBreaker
|
|
|
25
25
|
alias :__run :run
|
|
26
26
|
|
|
27
27
|
def run(*args,&blk)
|
|
28
|
-
RubyBreaker::TestCase.
|
|
28
|
+
RubyBreaker::TestCase.__rubybreaker_setup()
|
|
29
29
|
__run(*args,&blk)
|
|
30
|
-
RubyBreaker::TestCase.
|
|
30
|
+
RubyBreaker::TestCase.__rubybreaker_teardown()
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
EOS
|
data/lib/rubybreaker/test.rb
CHANGED
|
@@ -227,15 +227,16 @@ grammar TypeGrammar
|
|
|
227
227
|
end
|
|
228
228
|
|
|
229
229
|
rule nominal_type
|
|
230
|
-
[a-z_]+ {
|
|
230
|
+
[a-z_/]+ { # FIXME: not really accurate
|
|
231
231
|
def value
|
|
232
232
|
pos = RubyBreaker::Position.get()
|
|
233
233
|
pos.col = interval.first
|
|
234
234
|
begin
|
|
235
235
|
mod_name = RubyBreaker::Util.camelize(text_value)
|
|
236
|
-
mod = eval
|
|
237
|
-
t = RubyBreaker::NominalType.new(mod,pos)
|
|
238
|
-
rescue
|
|
236
|
+
mod = eval(mod_name) # do it at the current binding
|
|
237
|
+
t = RubyBreaker::NominalType.new(mod, pos)
|
|
238
|
+
rescue => e
|
|
239
|
+
puts e
|
|
239
240
|
t = RubyBreaker::AnyType.new(pos)
|
|
240
241
|
end
|
|
241
242
|
return t # RubyBreaker::NominalType.new(text_value,pos)
|
|
@@ -15,16 +15,45 @@ module RubyBreaker
|
|
|
15
15
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
|
+
# This method resolves the mod_name's namespace with respect to the
|
|
19
|
+
# namespace. For example, if the current namespace is
|
|
20
|
+
#
|
|
21
|
+
# A::B
|
|
22
|
+
#
|
|
23
|
+
# and the given module is A::B::C::D, then we show
|
|
24
|
+
#
|
|
25
|
+
# C::D
|
|
26
|
+
#
|
|
27
|
+
#
|
|
28
|
+
# If the current namespace is
|
|
29
|
+
#
|
|
30
|
+
# A::B::C
|
|
31
|
+
#
|
|
32
|
+
# and the given module is A::B::D::E, then we show
|
|
33
|
+
#
|
|
34
|
+
# D::E
|
|
35
|
+
#
|
|
36
|
+
def self.resolve_namespace(namespace, mod_name)
|
|
37
|
+
return mod_name if namespace == nil || namespace.empty?
|
|
38
|
+
if mod_name.start_with?(namespace)
|
|
39
|
+
pattern = "^#{namespace}::"
|
|
40
|
+
return mod_name.sub(/#{pattern}/, "")
|
|
41
|
+
end
|
|
42
|
+
tokens = namespace.split("::")
|
|
43
|
+
return mod_name if tokens.size <= 1
|
|
44
|
+
return self.resolve_namespace(tokens[0..-2].join("::"), mod_name)
|
|
45
|
+
end
|
|
46
|
+
|
|
18
47
|
# This method is used to determine if the inner type of +t+ should be
|
|
19
48
|
# wrapped around a parenthesis. This is for optional type and variable
|
|
20
49
|
# length type.
|
|
21
|
-
def self.peek_and_unparse_pp_inner_type(pp,t)
|
|
50
|
+
def self.peek_and_unparse_pp_inner_type(pp, t, opts={})
|
|
22
51
|
if t.type.kind_of?(OrType)
|
|
23
52
|
pp.text("(")
|
|
24
|
-
self.unparse_pp(pp,t.type)
|
|
53
|
+
self.unparse_pp(pp, t.type, opts)
|
|
25
54
|
pp.text(")")
|
|
26
55
|
else
|
|
27
|
-
self.unparse_pp(pp,t.type)
|
|
56
|
+
self.unparse_pp(pp, t.type, opts)
|
|
28
57
|
end
|
|
29
58
|
end
|
|
30
59
|
|
|
@@ -35,23 +64,34 @@ module RubyBreaker
|
|
|
35
64
|
|
|
36
65
|
# This recursive method unparses a RubyBreaker type using the pretty
|
|
37
66
|
# print method.
|
|
38
|
-
def self.unparse_pp(pp,t)
|
|
67
|
+
def self.unparse_pp(pp, t, opts={})
|
|
39
68
|
if t.instance_of?(NominalType)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
69
|
+
if opts[:namespace] && opts[:namespace].name
|
|
70
|
+
# resolve the namespace for the module/class given the current
|
|
71
|
+
# namespace
|
|
72
|
+
mod_name = self.resolve_namespace(opts[:namespace].name, t.mod.name)
|
|
73
|
+
else
|
|
74
|
+
mod_name = t.mod.name
|
|
75
|
+
end
|
|
76
|
+
unless opts[:style] == :camelize
|
|
77
|
+
tname = Util.underscore(mod_name)
|
|
78
|
+
else
|
|
79
|
+
tname = mod_name
|
|
80
|
+
end
|
|
81
|
+
# tokens = tname.split("/")
|
|
82
|
+
# tname = tokens.last if tokens.size > 1
|
|
43
83
|
pp.text(tname)
|
|
44
84
|
elsif t.instance_of?(SelfType)
|
|
45
85
|
pp.text("self")
|
|
46
86
|
elsif t.instance_of?(DuckType)
|
|
47
87
|
unparse_pp_object_type(pp,t)
|
|
48
88
|
elsif t.instance_of?(FusionType)
|
|
49
|
-
unparse_pp(pp,t.nom_type)
|
|
89
|
+
unparse_pp(pp, t.nom_type, opts)
|
|
50
90
|
unparse_pp_object_type(pp,t)
|
|
51
91
|
elsif t.instance_of?(MethodType)
|
|
52
92
|
pp.text("#{t.meth_name}(")
|
|
53
93
|
t.arg_types.each_with_index do |arg_type,i|
|
|
54
|
-
unparse_pp(pp,arg_type)
|
|
94
|
+
unparse_pp(pp, arg_type, opts)
|
|
55
95
|
if i < t.arg_types.size - 1
|
|
56
96
|
pp.text(",")
|
|
57
97
|
pp.fill_breakable()
|
|
@@ -61,17 +101,17 @@ module RubyBreaker
|
|
|
61
101
|
pp.fill_breakable()
|
|
62
102
|
if t.blk_type
|
|
63
103
|
pp.text("{")
|
|
64
|
-
unparse_pp(pp,t.blk_type)
|
|
104
|
+
unparse_pp(pp, t.blk_type, opts)
|
|
65
105
|
pp.text("}")
|
|
66
106
|
pp.fill_breakable()
|
|
67
107
|
end
|
|
68
108
|
pp.text("->")
|
|
69
109
|
pp.fill_breakable()
|
|
70
|
-
unparse_pp(pp,t.ret_type)
|
|
110
|
+
unparse_pp(pp, t.ret_type, opts)
|
|
71
111
|
elsif t.instance_of?(BlockType)
|
|
72
112
|
pp.text("|")
|
|
73
113
|
t.arg_types.each_with_index do |arg_type,i|
|
|
74
|
-
unparse_pp(pp,arg_type)
|
|
114
|
+
unparse_pp(pp, arg_type, opts)
|
|
75
115
|
if i < t.arg_types.size - 1
|
|
76
116
|
pp.text(",")
|
|
77
117
|
pp.fill_breakable()
|
|
@@ -81,33 +121,33 @@ module RubyBreaker
|
|
|
81
121
|
pp.fill_breakable()
|
|
82
122
|
if t.blk_type
|
|
83
123
|
pp.text("{")
|
|
84
|
-
unparse_pp(pp,t.blk_type)
|
|
124
|
+
unparse_pp(pp, t.blk_type, opts)
|
|
85
125
|
pp.text("}")
|
|
86
126
|
pp.fill_breakable()
|
|
87
127
|
end
|
|
88
128
|
pp.text("->")
|
|
89
129
|
pp.fill_breakable()
|
|
90
|
-
unparse_pp(pp,t.ret_type)
|
|
130
|
+
unparse_pp(pp, t.ret_type, opts)
|
|
91
131
|
elsif t.instance_of?(MethodListType)
|
|
92
132
|
t.types.each_with_index do |typ,i|
|
|
93
|
-
unparse_pp(pp,typ)
|
|
133
|
+
unparse_pp(pp, typ, opts)
|
|
94
134
|
if i < t.types.size - 1
|
|
95
135
|
pp.fill_breakable()
|
|
96
136
|
end
|
|
97
137
|
end
|
|
98
138
|
elsif t.instance_of?(OrType)
|
|
99
139
|
t.types.each_with_index do |typ,i|
|
|
100
|
-
unparse_pp(pp,typ)
|
|
140
|
+
unparse_pp(pp, typ, opts)
|
|
101
141
|
if i < t.types.size - 1
|
|
102
142
|
pp.text(" ||")
|
|
103
143
|
pp.fill_breakable()
|
|
104
144
|
end
|
|
105
145
|
end
|
|
106
146
|
elsif t.instance_of?(OptionalType)
|
|
107
|
-
peek_and_unparse_pp_inner_type(pp,t)
|
|
147
|
+
peek_and_unparse_pp_inner_type(pp, t, opts)
|
|
108
148
|
pp.text("?")
|
|
109
149
|
elsif t.instance_of?(VarLengthType)
|
|
110
|
-
peek_and_unparse_pp_inner_type(pp,t)
|
|
150
|
+
peek_and_unparse_pp_inner_type(pp, t, opts)
|
|
111
151
|
pp.text("*")
|
|
112
152
|
elsif t.instance_of?(NilType)
|
|
113
153
|
pp.text("nil")
|
|
@@ -119,12 +159,16 @@ module RubyBreaker
|
|
|
119
159
|
|
|
120
160
|
public
|
|
121
161
|
|
|
122
|
-
# This method
|
|
123
|
-
#
|
|
124
|
-
|
|
162
|
+
# This method unparses the RubyBreaker type according to the specified
|
|
163
|
+
# options.
|
|
164
|
+
#
|
|
165
|
+
# t:: RubyBreaker type
|
|
166
|
+
# opts::
|
|
167
|
+
#
|
|
168
|
+
def self.unparse(t, opts={})
|
|
125
169
|
str = ""
|
|
126
170
|
pp = PrettyPrint.new(str)
|
|
127
|
-
self.unparse_pp(pp,t)
|
|
171
|
+
self.unparse_pp(pp, t, opts)
|
|
128
172
|
pp.flush
|
|
129
173
|
return str.strip()
|
|
130
174
|
end
|
|
@@ -132,9 +176,9 @@ module RubyBreaker
|
|
|
132
176
|
|
|
133
177
|
class TypeDefs::Type
|
|
134
178
|
|
|
135
|
-
# This method
|
|
136
|
-
def unparse()
|
|
137
|
-
TypeUnparser.unparse(self)
|
|
179
|
+
# This method is a shorthand for calling TypeUnparser.unparse(t).
|
|
180
|
+
def unparse(opts={})
|
|
181
|
+
TypeUnparser.unparse(self, opts)
|
|
138
182
|
end
|
|
139
183
|
end
|
|
140
184
|
|