rubybreaker 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/NEWS +4 -0
  2. data/README.md +33 -19
  3. data/Rakefile +31 -13
  4. data/TODO +6 -4
  5. data/VERSION +1 -1
  6. data/bin/rubybreaker +0 -1
  7. data/lib/rubybreaker/debug/debug.rb +1 -1
  8. data/lib/rubybreaker/runtime/typesig_unparser.rb +96 -0
  9. data/lib/rubybreaker/runtime.rb +1 -0
  10. data/lib/rubybreaker/test/rspec.rb +15 -0
  11. data/lib/rubybreaker/test/testcase.rb +4 -4
  12. data/lib/rubybreaker/test.rb +1 -0
  13. data/lib/rubybreaker/type/type_grammar.treetop +5 -4
  14. data/lib/rubybreaker/type/type_unparser.rb +69 -25
  15. data/lib/rubybreaker.rb +9 -77
  16. data/test/integrated/tc_namespace.rb +56 -0
  17. data/test/ts_integrated.rb +1 -0
  18. data/test/ts_rspec.rb +31 -0
  19. data/test/ts_type.rb +2 -0
  20. data/test/type/tc_camelize.rb +24 -0
  21. data/test/type/tc_namespace.rb +25 -0
  22. data/test/type/tc_unparser.rb +31 -32
  23. data/webpage/index.html +34 -19
  24. data/webpage/rdoc/Object.html +308 -0
  25. data/webpage/rdoc/RubyBreaker/Breakable.html +5 -1
  26. data/webpage/rdoc/RubyBreaker/Broken/BrokenEigen.html +5 -1
  27. data/webpage/rdoc/RubyBreaker/Broken.html +5 -1
  28. data/webpage/rdoc/RubyBreaker/Context.html +5 -1
  29. data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +4 -0
  30. data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +4 -0
  31. data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +4 -0
  32. data/webpage/rdoc/RubyBreaker/Errors/SubtypeFailure.html +4 -0
  33. data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +4 -0
  34. data/webpage/rdoc/RubyBreaker/Errors/UserError.html +4 -0
  35. data/webpage/rdoc/RubyBreaker/Errors.html +4 -0
  36. data/webpage/rdoc/RubyBreaker/Main.html +17 -132
  37. data/webpage/rdoc/RubyBreaker/ObjectPosition.html +5 -1
  38. data/webpage/rdoc/RubyBreaker/Position.html +5 -1
  39. data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +4 -0
  40. data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +4 -0
  41. data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +5 -1
  42. data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +5 -1
  43. data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +4 -0
  44. data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +5 -1
  45. data/webpage/rdoc/RubyBreaker/Runtime/MonitorUtils.html +4 -0
  46. data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +4 -0
  47. data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +4 -0
  48. data/webpage/rdoc/RubyBreaker/Runtime/TypePlaceholder.html +5 -1
  49. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +4 -0
  50. data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +5 -1
  51. data/webpage/rdoc/RubyBreaker/Runtime/TypesigUnparser.html +404 -0
  52. data/webpage/rdoc/RubyBreaker/Runtime.html +5 -0
  53. data/webpage/rdoc/RubyBreaker/TestCase.html +47 -43
  54. data/webpage/rdoc/RubyBreaker/TypeComparer.html +4 -0
  55. data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +4 -0
  56. data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +4 -0
  57. data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +4 -0
  58. data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +4 -0
  59. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +4 -0
  60. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +4 -0
  61. data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +4 -0
  62. data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +4 -0
  63. data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +4 -0
  64. data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +4 -0
  65. data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +4 -0
  66. data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +11 -6
  67. data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +4 -0
  68. data/webpage/rdoc/RubyBreaker/TypeDefs.html +4 -0
  69. data/webpage/rdoc/RubyBreaker/TypeUnparser.html +15 -7
  70. data/webpage/rdoc/RubyBreaker/Typing.html +4 -0
  71. data/webpage/rdoc/RubyBreaker/Util.html +4 -0
  72. data/webpage/rdoc/RubyBreaker.html +6 -6
  73. data/webpage/rdoc/created.rid +9 -7
  74. data/webpage/rdoc/index.html +4 -0
  75. data/webpage/rdoc/js/search_index.js +1 -1
  76. data/webpage/rdoc/table_of_contents.html +36 -24
  77. metadata +13 -7
data/NEWS CHANGED
@@ -1,3 +1,7 @@
1
+ # VERSION 0.0.4
2
+ * RSpec is supported.
3
+ * Namespace is recognized in type signatures.
4
+
1
5
  # VERSION 0.0.3
2
6
  * A class or module can be both Breakable and Broken at the same time.
3
7
  * Better logging/debugging output
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Introduction
4
4
 
5
- RubyBreaker is a dynamic type documentation tool written purely in Ruby. It
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 RubyDoc. Overall, this tool should help Ruby programmers
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
- * No parametric polymorphic types are supported.
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. *This is necessary as
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 has a built-in testing
230
- framework that (supposedly :)) works seemlessly with the existing tests of
231
- the program.
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 RubyBreaker Testing Framework
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
- Currently, RubyBreaker only supports the standard unit test framework.
251
- Other testing frameworks such as RSpec and Cucumber are not supported at the
252
- moment (but will be in future/hopefully).
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
- break unless defined?(RDiscount)
43
- dir = File.dirname(__FILE__)
44
- readme_md = "#{dir}/README.md"
45
- output = "#{dir}/webpage/index.html"
46
- body = RDiscount.new(File.read(readme_md)).to_html
47
- header = File.read("#{dir}/webpage/header.html")
48
- footer = File.read("#{dir}/webpage/footer.html")
49
- html = header + body + footer
50
- File.open(output, "w") { |f| f.write(html) }
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
- t.test_files = FileList["test/*.rb"]
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
- # More Testing Frameworks
9
+ # Additional Testing Frameworks
10
10
 
11
- The Ruby community has other testing frameworks such as RSpec and Cucumber.
12
- RubyBreaker should be able to support these frameworks so that those test
13
- suites can be used for RubyBreaker.
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.3
1
+ 0.0.4
data/bin/rubybreaker CHANGED
@@ -56,7 +56,6 @@ module RubyBreaker
56
56
 
57
57
  # There has to be an input file
58
58
  if ARGV.length < 1 then
59
- puts "Specify a Ruby program"
60
59
  puts option_parser.banner
61
60
  exit(1)
62
61
  end
@@ -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
@@ -5,6 +5,7 @@
5
5
 
6
6
  require_relative "runtime/overrides"
7
7
  require_relative "runtime/typesig_parser"
8
+ require_relative "runtime/typesig_unparser"
8
9
  require_relative "runtime/monitor"
9
10
  require_relative "runtime/inspector"
10
11
 
@@ -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.setup()
12
+ def self.__rubybreaker_setup()
13
13
  Main.setup()
14
14
  end
15
15
 
16
- def self.teardown()
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.setup()
28
+ RubyBreaker::TestCase.__rubybreaker_setup()
29
29
  __run(*args,&blk)
30
- RubyBreaker::TestCase.teardown()
30
+ RubyBreaker::TestCase.__rubybreaker_teardown()
31
31
  end
32
32
 
33
33
  EOS
@@ -1 +1,2 @@
1
1
  require_relative "test/testcase"
2
+ require_relative "test/rspec"
@@ -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 mod_name
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
- tname = Util.underscore(t.mod)
41
- tokens = tname.split("/")
42
- tname = tokens.last if tokens.size > 1
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 is used to display any RubyBreaker type in a user-friendly
123
- # way using the pretty print method.
124
- def self.unparse(t)
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 unparses the type using the pretty print 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