rubybreaker 0.0.4 → 0.0.5

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.
Files changed (97) hide show
  1. data/NEWS +5 -0
  2. data/NOTES +9 -0
  3. data/README.md +100 -183
  4. data/Rakefile +21 -6
  5. data/VERSION +1 -1
  6. data/bin/rubybreaker +34 -50
  7. data/lib/rubybreaker/debug/debug.rb +6 -0
  8. data/lib/rubybreaker/doc/rdoc.rb +37 -0
  9. data/lib/rubybreaker/doc.rb +3 -0
  10. data/lib/rubybreaker/runtime/inspector.rb +6 -28
  11. data/lib/rubybreaker/runtime/monitor.rb +21 -17
  12. data/lib/rubybreaker/runtime/object_wrapper.rb +7 -2
  13. data/lib/rubybreaker/runtime/type_system.rb +3 -5
  14. data/lib/rubybreaker/runtime/typesig_unparser.rb +1 -4
  15. data/lib/rubybreaker/runtime.rb +64 -105
  16. data/lib/rubybreaker/task.rb +97 -0
  17. data/lib/rubybreaker/test/rspec.rb +1 -1
  18. data/lib/rubybreaker/test/testcase.rb +13 -28
  19. data/lib/rubybreaker/type/type.rb +1 -1
  20. data/lib/rubybreaker/typing/subtyping.rb +10 -5
  21. data/lib/rubybreaker/util.rb +0 -1
  22. data/lib/rubybreaker.rb +163 -115
  23. data/test/integrated/tc_both_broken_breakable.rb +5 -4
  24. data/test/integrated/tc_class_methods.rb +4 -3
  25. data/test/integrated/tc_inherit_broken.rb +4 -3
  26. data/test/integrated/tc_method_missing.rb +4 -4
  27. data/test/integrated/tc_namespace.rb +4 -2
  28. data/test/integrated/tc_simple1.rb +4 -3
  29. data/test/runtime/tc_obj_wrapper.rb +25 -6
  30. data/test/runtime/tc_typesig_parser.rb +0 -1
  31. data/test/testtask/sample.rb +10 -0
  32. data/test/testtask/tc_testtask.rb +25 -0
  33. data/test/ts_rspec.rb +21 -15
  34. data/test/typing/tc_typing.rb +2 -3
  35. data/webpage/index.html +105 -193
  36. data/webpage/rdoc/Kernel.html +286 -0
  37. data/webpage/rdoc/Object.html +17 -11
  38. data/webpage/rdoc/Rake/RubyBreakerTestTask.html +374 -0
  39. data/webpage/rdoc/Rake.html +212 -0
  40. data/webpage/rdoc/RubyBreaker/Breakable.html +24 -40
  41. data/webpage/rdoc/RubyBreaker/Broken.html +21 -69
  42. data/webpage/rdoc/RubyBreaker/Context.html +16 -10
  43. data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +16 -10
  44. data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +16 -10
  45. data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +16 -10
  46. data/webpage/rdoc/RubyBreaker/Errors/SubtypeFailure.html +16 -10
  47. data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +16 -10
  48. data/webpage/rdoc/RubyBreaker/Errors/UserError.html +16 -10
  49. data/webpage/rdoc/RubyBreaker/Errors.html +16 -10
  50. data/webpage/rdoc/RubyBreaker/ObjectPosition.html +16 -10
  51. data/webpage/rdoc/RubyBreaker/Position.html +16 -10
  52. data/webpage/rdoc/RubyBreaker/{TestCase.html → RDocSupport.html} +81 -82
  53. data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +16 -10
  54. data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +25 -44
  55. data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +16 -10
  56. data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +19 -13
  57. data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +37 -25
  58. data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +20 -14
  59. data/webpage/rdoc/RubyBreaker/Runtime/MonitorUtils.html +21 -15
  60. data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +23 -12
  61. data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +16 -10
  62. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +16 -10
  63. data/webpage/rdoc/RubyBreaker/Runtime/{TypesigUnparser.html → TypeSigUnparser.html} +19 -16
  64. data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +18 -14
  65. data/webpage/rdoc/RubyBreaker/Runtime.html +145 -11
  66. data/webpage/rdoc/RubyBreaker/TypeComparer.html +16 -10
  67. data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +16 -10
  68. data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +16 -10
  69. data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +16 -10
  70. data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +16 -10
  71. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +16 -10
  72. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +16 -10
  73. data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +16 -10
  74. data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +16 -10
  75. data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +16 -10
  76. data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +16 -10
  77. data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +17 -11
  78. data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +17 -11
  79. data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +16 -10
  80. data/webpage/rdoc/RubyBreaker/TypeDefs.html +16 -10
  81. data/webpage/rdoc/RubyBreaker/TypeUnparser.html +16 -10
  82. data/webpage/rdoc/RubyBreaker/Typing.html +17 -11
  83. data/webpage/rdoc/RubyBreaker/Util.html +16 -10
  84. data/webpage/rdoc/RubyBreaker.html +167 -34
  85. data/webpage/rdoc/{RubyBreaker/Runtime/TypePlaceholder.html → Test/Unit/TestCase.html} +68 -39
  86. data/webpage/rdoc/Test/Unit.html +211 -0
  87. data/webpage/rdoc/Test.html +211 -0
  88. data/webpage/rdoc/created.rid +18 -17
  89. data/webpage/rdoc/index.html +16 -10
  90. data/webpage/rdoc/js/search_index.js +1 -1
  91. data/webpage/rdoc/table_of_contents.html +61 -48
  92. metadata +21 -12
  93. data/lib/rubybreaker/rubylib/core.rb +0 -2483
  94. data/lib/rubybreaker/rubylib.rb +0 -3
  95. data/lib/rubybreaker/runtime/type_placeholder.rb +0 -23
  96. data/webpage/rdoc/RubyBreaker/Broken/BrokenEigen.html +0 -305
  97. data/webpage/rdoc/RubyBreaker/Main.html +0 -458
@@ -1,6 +1,6 @@
1
1
  #--
2
2
  # This file defines the type inspector which fetches the type information
3
- # gathered or documented in a Breakable, Broken, or hybrid module.
3
+ # gathered or documented in a class.
4
4
 
5
5
  require_relative "util"
6
6
  require_relative "monitor"
@@ -9,26 +9,14 @@ module RubyBreaker
9
9
 
10
10
  module Runtime
11
11
 
12
- # This module inspects a Breakable module, a Broken module, or a hybrid
13
- # module to fetch the type information for each method.
12
+ # This module inspects type information gathered so far.
14
13
  module Inspector
15
14
 
16
15
  # This method inspects the module for the type of the specified
17
- # method. It returns the method type or method list type for the given
18
- # method, by looking at, first, the placeholder for the Breakable
19
- # side of the module, and then, the placeholder for the Broken side of
20
- # the module. If no method exists or if there is no type information
21
- # for the method, it returns nil.
16
+ # method.
22
17
  def self.inspect_meth(mod, mname)
23
18
  mname = mname.to_sym
24
- if Breakable::TYPE_PLACEHOLDER_MAP.has_key?(mod)
25
- placeholder = Breakable::TYPE_PLACEHOLDER_MAP[mod]
26
- end
27
- t = placeholder.meth_type_map[mname] if placeholder
28
- if !t && Broken::TYPE_PLACEHOLDER_MAP.has_key?(mod)
29
- placeholder = Broken::TYPE_PLACEHOLDER_MAP[mod]
30
- t = placeholder.meth_type_map[mname] if placeholder
31
- end
19
+ t = TYPE_MAP[mod][mname] if TYPE_MAP.has_key?(mod)
32
20
  return t
33
21
  end
34
22
 
@@ -52,18 +40,8 @@ module RubyBreaker
52
40
  # containing (method name, method type) pairs.
53
41
  def self.inspect_all(mod)
54
42
  mtypes = {}
55
- mm = Breakable::TYPE_PLACEHOLDER_MAP[mod]
56
- if mm
57
- mm.meth_type_map.each_pair {|im,mtype|
58
- mtypes[im] = mtype if mtype
59
- }
60
- end
61
- mm = Broken::TYPE_PLACEHOLDER_MAP[mod]
62
- if mm
63
- mm.meth_type_map.each_pair {|im,mtype|
64
- mtypes[im] = mtype if mtype
65
- }
66
- end
43
+ mm = TYPE_MAP[mod]
44
+ mm.each_pair {|im,mtype| mtypes[im] = mtype if mtype } if mm
67
45
  return mtypes
68
46
  end
69
47
 
@@ -1,14 +1,12 @@
1
1
  #--
2
2
  # This file contains the core of the runtime framework which injects the
3
- # monitoring code into Breakable classes/modules and actually monitors the
3
+ # monitoring code into breakable classes/modules and actually monitors the
4
4
  # instances of those classes/modules at runtime. It also provides some utility
5
5
  # functions for later use (after runtime).
6
6
 
7
7
  dir = File.dirname(__FILE__)
8
8
  require_relative "util"
9
9
  require_relative "../debug"
10
- require_relative "type_placeholder"
11
- require_relative "pluggable"
12
10
  require_relative "type_system"
13
11
 
14
12
  module RubyBreaker
@@ -132,11 +130,11 @@ module RubyBreaker
132
130
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
133
131
 
134
132
  # mm = get_module_monitor(mod) unless is_obj_mod
135
- mm = Breakable::MONITOR_MAP[mod]
133
+ mm = MONITOR_MAP[mod]
136
134
 
137
135
  # There is something wrong if there isn't a module monitor
138
136
  # associated with the call.
139
- # raise Exception if mm == nil || !mm.meth_type_map.include?(meth_name)
137
+ # raise Exception if mm == nil || !mm.include?(meth_name)
140
138
 
141
139
  meth_info = MethodInfo.new(meth_name, args, blk, nil)
142
140
 
@@ -212,24 +210,30 @@ module RubyBreaker
212
210
 
213
211
  RubyBreaker.log("Installing module monitor for #{mod}")
214
212
 
215
- Breakable::MONITOR_MAP[mod] = Monitor.new(mod, DEFAULT_TYPE_SYSTEM)
216
- Breakable::TYPE_PLACEHOLDER_MAP[mod] = TypePlaceholder.new
213
+ # Do not re-install monitor if already done so.
214
+ if MONITOR_MAP[mod]
215
+ RubyBreaker.log("Skip #{mod} as it has a monitor installed.")
216
+ return
217
+ end
218
+
219
+ MONITOR_MAP[mod] = Monitor.new(mod, DEFAULT_TYPE_SYSTEM)
217
220
 
218
- meth_type_map = []
221
+ # Create the type map if it does not exist already. Remember, this
222
+ # map could have been made by typesig().
223
+ TYPE_MAP[mod] = {} unless TYPE_MAP[mod]
224
+
225
+ # Get the list of instance methods but do not include inherited
226
+ # methods. Those are part of the owner's not this module.
219
227
  meths = mod.instance_methods(false)
220
228
 
221
- # RubyBreaker now supports the hybrid of Breakable and Broken. Here,
222
- # see if any methods are already broken.
223
- broken_meth_type_map = Inspector.inspect_all(mod)
224
- broken_meths = broken_meth_type_map.keys
229
+ # See if any method is already broken (explicitly typesig'ed)
230
+ broken_mt_map = Inspector.inspect_all(mod)
231
+ broken_meths = broken_mt_map.keys
225
232
 
226
233
  meths.each do |m|
227
- # As long as the method is not "Broken" yet, it is considered
228
- # Breakable (if the module is declared to be Breakable).
229
- unless broken_meths.include?(m)
230
- self.rename_meth(mod,m)
231
- end
234
+ self.rename_meth(mod,m) unless broken_meths.include?(m)
232
235
  end
236
+
233
237
  end
234
238
 
235
239
  end
@@ -70,11 +70,16 @@ module RubyBreaker
70
70
  def method_missing(mname,*args,&blk)
71
71
  ::RubyBreaker.log("Method_missing for #{mname}")
72
72
  if GLOBAL_MONITOR_SWITCH.switch
73
+ # Must handle send method specially (do not track them)
74
+ if [:"__send__", :send].include?(mname)
75
+ mname = args[0]
76
+ args = args[1..-1]
77
+ end
73
78
  @__rubybreaker_type.add_meth(mname)
74
- retval = @__rubybreaker_obj.send(mname,*args,&blk)
79
+ retval = @__rubybreaker_obj.send(mname, *args, &blk)
75
80
  retval = ObjectWrapper.new(retval)
76
81
  else
77
- retval = @__rubybreaker_obj.send(mname,*args,&blk)
82
+ retval = @__rubybreaker_obj.send(mname, *args, &blk)
78
83
  end
79
84
  return retval
80
85
  end
@@ -7,10 +7,10 @@
7
7
 
8
8
  require_relative "util"
9
9
  require_relative "object_wrapper"
10
- require_relative "type_placeholder"
11
10
  require_relative "../type"
12
11
  require_relative "../typing"
13
12
  require_relative "../debug"
13
+ require_relative "pluggable"
14
14
 
15
15
  module RubyBreaker
16
16
 
@@ -176,7 +176,7 @@ module RubyBreaker
176
176
  is_obj_mod = (obj.class == Class or obj.class == Module)
177
177
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
178
178
 
179
- meth_type_map = Breakable::TYPE_PLACEHOLDER_MAP[mod].meth_type_map
179
+ meth_type_map = TYPE_MAP[mod]
180
180
 
181
181
  # Let's take things out of the MethodInfo object
182
182
  meth_name = meth_info.meth_name
@@ -244,10 +244,8 @@ module RubyBreaker
244
244
 
245
245
  RubyBreaker.log("In module monitor_after #{meth_name}")
246
246
 
247
- meth_type_map = Breakable::TYPE_PLACEHOLDER_MAP[mod].meth_type_map
248
-
249
247
  # Compute the least upper bound
250
- lub(obj, meth_type_map,meth_name,retval,*args,&blk)
248
+ lub(obj, TYPE_MAP[mod],meth_name,retval,*args,&blk)
251
249
 
252
250
  if obj == retval
253
251
  # It is possible that the method receiver is a wrapped object if
@@ -6,7 +6,7 @@ module RubyBreaker
6
6
  module Runtime
7
7
 
8
8
  # This module handles unparsing type signatures.
9
- module TypesigUnparser
9
+ module TypeSigUnparser
10
10
 
11
11
  include TypeDefs
12
12
 
@@ -51,9 +51,6 @@ module RubyBreaker
51
51
 
52
52
  pp.text("#{keyword} #{mod.to_s}", 80)
53
53
  pp.nest(2) do
54
- pp.breakable("")
55
- pp.text("include RubyBreaker::Broken", 80)
56
-
57
54
  # See if there is any class method to show
58
55
  eigen = Runtime.eigen_class(mod)
59
56
  if !DOCUMENTED.include?(eigen)
@@ -1,8 +1,7 @@
1
1
  #--
2
- # This file defines Breakable and Broken module. Breakable module makes the
3
- # hosting module (and class) subject to type monitoring. Broken module makes
4
- # type information of the hosting module accessible.
5
-
2
+ # This file provides two methods breakable() and broken() that declares a
3
+ # module/class to be monitored
4
+ require "set"
6
5
  require_relative "runtime/overrides"
7
6
  require_relative "runtime/typesig_parser"
8
7
  require_relative "runtime/typesig_unparser"
@@ -11,122 +10,82 @@ require_relative "runtime/inspector"
11
10
 
12
11
  module RubyBreaker
13
12
 
14
- # Broken takes higher precedence than Breakable. Once a module is
15
- # "declared" to be Broken, it cannot be Breakable.
16
- #
17
- # TODO: In future, there will be a hybrid of two to allow documenting of
18
- # methods that are newly introduced in a broken class/module.
13
+ module Runtime
19
14
 
20
- # This array lists modules/classes that will be monitored.
21
- BREAKABLE = []
15
+ # This set keeps track of modules/classes that will be monitored.
16
+ # *DEPRECATED* : Use +breakable+ method instead.
17
+ BREAKABLES = Set.new
22
18
 
23
- # This array lists "broken" classes--i.e., with type signatures
24
- BROKEN = []
19
+ # This hash maps a module to a nested hash that maps a method name to a
20
+ # method type. This hash is shared between breakable modules/classes and
21
+ # non-breakable modules/classes.
22
+ TYPE_MAP = {} # module => {:meth_name => type}
25
23
 
26
- # This module should be included in classes or modules that you want to
27
- # monitor during runtime. The concept is that once a Breakable module is
28
- # monitored and its type documentation is generated, the module now becomes
29
- # a Broken module. The actual implementation is a simple trigger that
30
- # queues the target module into the list of modules to monitor. The queued
31
- # modules are then modified to be monitored dynamically.
32
- module Breakable
24
+ # This hash maps a (breakable) module to a type monitor
25
+ MONITOR_MAP = {} # module => monitor
33
26
 
34
- TYPE_PLACEHOLDER_MAP = {} # module => type_placeholder
35
- MONITOR_MAP = {} # module => monitor
27
+ # This set lists modules/classes that are actually instrumented with a
28
+ # monitor.
29
+ INSTALLED = Set.new
36
30
 
37
- # Simply keep track of this module and its eigen class so they are
38
- # monitored later on.
39
- def self.included(mod)
40
- BREAKABLE << mod
41
- BREAKABLE << Runtime.eigen_class(mod)
31
+ # This method installs a monitor for each breakable module.
32
+ # *DEPRECATED*: Use +breakable()+ method instead.
33
+ def self.instrument()
34
+ BREAKABLES.each do |mod|
35
+ # Duplicate checks in place in these calls.
36
+ MonitorInstaller.install_module_monitor(mod)
37
+ INSTALLED << mod
38
+ end
42
39
  end
43
40
 
44
- end
45
-
46
- # This module is included for "broken" classes.
47
- module Broken
48
-
49
- include TypeDefs
50
- include Runtime
51
-
52
- TYPE_PLACEHOLDER_MAP = {} # module => type_placeholder
53
-
54
- #-
55
- # This module will be "extended" to the eigen class of the class that
56
- # includes Broken module. This allows the eigen class to call 'typesig'
57
- # method to parse the type signature dynamically.
58
- #
59
- # Usage:
60
- # Class A
61
- # include RubyBreaker::Broken
62
- #
63
- # typesig("foo(fixnum) -> fixnum")
64
- # def foo(x) ... end
65
- # end
66
- #
67
- module BrokenEigen
68
-
69
- include TypeDefs
70
- include Runtime
71
-
72
- # This method can be used at the eigen level of the target module to
73
- # specify the type of a method.
74
- def typesig(str)
75
-
76
- # This MUST BE set for self type to work in type signatures.
77
- TypeDefs::SelfType.set_self(self)
78
-
79
- t = TypeSigParser.parse(str)
80
- placeholder = TYPE_PLACEHOLDER_MAP[self]
81
- if placeholder
82
- meth_type = placeholder.meth_type_map[t.meth_name]
83
- if meth_type
84
- # TODO: make a method list
85
- if meth_type.instance_of?(MethodListType)
86
- meth_type.types << t
87
- else
88
- # then upgrade it
89
- placeholder.meth_type_map[t.meth_name] =
90
- MethodListType.new([meth_type, t])
91
- end
92
- else
93
- placeholder.meth_type_map[t.meth_name] = t
41
+ # This method modifies specified modules/classes at the very moment
42
+ # (instead of registering them for later).
43
+ def self.breakable(*mods)
44
+ mods.each do |mod|
45
+ case mod
46
+ when Array
47
+ self.breakable(*mod)
48
+ when Module, Class
49
+ MonitorInstaller.install_module_monitor(mod)
50
+ eigen_class = self.eigen_class(mod)
51
+ MonitorInstaller.install_module_monitor(eigen_class)
52
+ INSTALLED << mod << eigen_class
53
+ when String, Symbol
54
+ begin
55
+ # Get the actual module and install it right now
56
+ mod = eval("#{mod}", TOPLEVEL_BINDING)
57
+ self.breakable(mod) if mod
58
+ rescue NameError => e
59
+ RubyBreaker.error("#{mod} cannot be found.")
94
60
  end
61
+ else
62
+ RubyBreaker.error("You must specify a module/class or its name.")
95
63
  end
96
- return t
97
64
  end
98
-
99
65
  end
100
-
101
- # This method is triggered when Broken module is included. This just
102
- # extends BrokenEigen into the target module so "typesig" method can be
103
- # called from the eigen level of the module. It also extends the eigen
104
- # class of the target module so that "typesig" can work for class
105
- # methods too.
106
- def self.included(mod)
66
+ end
107
67
 
108
- # Add to the list of broken modules
109
- BROKEN << mod
68
+ # *DEPRECATED*: Use +RubyBreaker.run()+ to indicate the point of entry.
69
+ def self.monitor()
70
+ end
110
71
 
111
- # Create if there is no type placeholder for this module yet
112
- placeholder = TYPE_PLACEHOLDER_MAP[mod]
113
- if !placeholder
114
- placeholder = TypePlaceholder.new()
115
- TYPE_PLACEHOLDER_MAP[mod] = placeholder
116
- end
117
- mod.extend(BrokenEigen)
72
+ # This method just redirects to Runtime's method.
73
+ def self.breakable(*mods)
74
+ Runtime.breakable(*mods)
75
+ end
118
76
 
119
- # Support up to one eigen level to support class methods
120
- eigen_class = Runtime.eigen_class(mod)
121
- BROKEN << eigen_class
122
- placeholder = TYPE_PLACEHOLDER_MAP[eigen_class]
123
- if !placeholder
124
- placeholder = TypePlaceholder.new()
125
- TYPE_PLACEHOLDER_MAP[eigen_class] = placeholder
126
- end
127
- eigen_class.extend(BrokenEigen)
77
+ # *DEPRECATED*: Use +Runtime.breakable()+ or +RubyBreaker.run()+ method
78
+ # instead.
79
+ module Breakable
80
+ def self.included(mod)
81
+ Runtime::BREAKABLES << mod << Runtime.eigen_class(mod)
128
82
  end
129
-
130
83
  end
131
84
 
85
+ # *DEPRECATED*: It has no effect.
86
+ module Broken
87
+ def self.included(mod)
88
+ # Runtime.broken(mod)
89
+ end
90
+ end
132
91
  end
@@ -0,0 +1,97 @@
1
+ require "ostruct"
2
+ require "optparse"
3
+ require "rake/testtask"
4
+ require "yaml"
5
+ require "tempfile"
6
+
7
+ module Rake
8
+
9
+ # This class can be used as a replacement for Rake::TestTask. It is a
10
+ # subclass of Rake::TestTask and maintains additional information for
11
+ # running RubyBreaker as a Rake test task.
12
+ #
13
+ # For example, the following shows how to run RubyBreaker in a test task:
14
+ #
15
+ # desc "Run testtask test"
16
+ # Rake::RubyBreakerTestTask.new(:"testtask_test") do |t|
17
+ # t.libs << "lib"
18
+ # t.test_files = ["test/testtask/tc_testtask.rb"]
19
+ # t.breakable = ["SampleClassA"]
20
+ # end
21
+ #
22
+ class RubyBreakerTestTask < Rake::TestTask
23
+
24
+ # List of Breakable modules/classes
25
+ attr_accessor :breakable
26
+
27
+ # RubyBreaker options
28
+ attr_accessor :rubybreaker_opts
29
+
30
+ # This overrides the testtask's constructor. In addition to the original
31
+ # behavior, it keeps track of RubyBreaker options and store them in a
32
+ # yaml file.
33
+ def initialize(taskname="", *args, &blk)
34
+
35
+ # Initialize extra instance variables
36
+ @rubybreaker_opts = []
37
+ @breakable = nil
38
+
39
+ # Call the original constructor first
40
+ super(taskname, *args, &blk)
41
+
42
+ # Parse the RubyBreaker options
43
+ case @rubybreaker_opts
44
+ when Array
45
+ opts = @rubybreaker_opts
46
+ when String
47
+ opts = @rubybreaker_opts.split(" ").select {|v| v != ""}
48
+ else
49
+ opts = []
50
+ end
51
+
52
+ # Construct the task configuration hash
53
+ config = {
54
+ name: taskname,
55
+ rubybreaker_opts: opts,
56
+ breakable: [], # Set doesn't work well with YAML; just use an array
57
+ test_files: @test_files,
58
+ }
59
+
60
+ # This allows a bulk declaration of Breakable modules/classes
61
+ @breakable.each { |b| config[:breakable] << b } if @breakable
62
+
63
+ # This code segment is a clever way to store yaml data in a ruby file
64
+ # that reads its own yaml data after __END__ when loaded.
65
+ code_data = <<-EOS
66
+ require "yaml"
67
+ f = File.new(__FILE__, "r")
68
+ while !(f.readline.match("^__END__.*$"))
69
+ # do nothing
70
+ end
71
+ data = f.read
72
+ $__rubybreaker_task = YAML.load(data)
73
+ __END__
74
+ #{YAML.dump(config)}
75
+ EOS
76
+
77
+ tmp_path = ""
78
+ # Tests are run different processes, so we must export this
79
+ # information to an external yaml file.
80
+ f = Tempfile.new(["#{taskname}",".rb"])
81
+ tmp_path = f.path
82
+ f.write(code_data)
83
+ f.close()
84
+
85
+ # Inject the -r option to load this yaml file
86
+ if @ruby_opts && @ruby_opts.empty?
87
+ @ruby_opts << "-r" << tmp_path
88
+ else
89
+ @ruby_opts = ["-r", tmp_path]
90
+ end
91
+
92
+ return self
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -9,7 +9,7 @@ if defined?(RSpec)
9
9
  end
10
10
 
11
11
  def describe(*args,&blk)
12
- RubyBreaker::Main.setup if defined?(RubyBreaker)
12
+ RubyBreaker.run if defined?(RubyBreaker)
13
13
  send(:"#{RUBYBREAKER_RSPEC_PREFIX}_describe", *args, &blk)
14
14
  end
15
15
 
@@ -1,38 +1,23 @@
1
1
  #--
2
- # This file mimics the Ruby testing framework. This is provided so that
3
- # RubyBreaker can be used seamlessly with the traditional Ruby framework
4
- # (supposedly :) ).
2
+ # This file overrides the test case behavior to work with RubyBreaker behind
3
+ # the scene without requiring the user to modify the code.
5
4
 
6
- module RubyBreaker
5
+ # Do this only if Test::Unit is defined
6
+ if defined?(Test) && defined?(Test::Unit)
7
7
 
8
- # This module overrides the normal behavior of Ruby Stdlib's TestCase
9
- # class.
10
- module TestCase
8
+ # This class is patched to run RubyBreaker along with the test cases.
9
+ class Test::Unit::TestCase
11
10
 
12
- def self.__rubybreaker_setup()
13
- Main.setup()
14
- end
11
+ # Save the original constructor method.
12
+ alias :__rubybreaker_initialize :initialize
15
13
 
16
- def self.__rubybreaker_teardown()
17
- # Main.output()
14
+ # This method overrides the original constructor to run RubyBreaker before
15
+ # calling the original constructor.
16
+ def initialize(*args, &blk)
17
+ RubyBreaker.run()
18
+ return send(:__rubybreaker_initialize, *args, &blk)
18
19
  end
19
20
 
20
- def self.included(mod)
21
-
22
- # hack to insert RubyBreaker's own setup and teardown methods
23
- mod.module_eval <<-EOS
24
-
25
- alias :__run :run
26
-
27
- def run(*args,&blk)
28
- RubyBreaker::TestCase.__rubybreaker_setup()
29
- __run(*args,&blk)
30
- RubyBreaker::TestCase.__rubybreaker_teardown()
31
- end
32
-
33
- EOS
34
-
35
- end
36
21
  end
37
22
  end
38
23
 
@@ -96,7 +96,7 @@ module RubyBreaker
96
96
  class SelfType < NominalType
97
97
 
98
98
  # This is a setter method for class variable mod.
99
- # NOTE: It is set every time Broken module is included.
99
+ # NOTE: It is set every time typesig() is called
100
100
  def self.set_self(mod)
101
101
  @@mod = mod
102
102
  end
@@ -9,7 +9,7 @@
9
9
  # any constraint graph to resolve subtype relations. This is the main
10
10
  # difference between Rubydust and RubyBreaker.
11
11
  #
12
- # If a module is not Broken but is Breakable (i.e., monitored), then it is
12
+ # If a module is not broken but is breakable (i.e., monitored), then it is
13
13
  # treated as non-Broken. At the end of the execution, the module will be
14
14
  # Broken--i.e., its type information is now revealed. If the user wishes to
15
15
  # use the result of the analysis, this type information will be documented
@@ -57,6 +57,11 @@ module RubyBreaker
57
57
 
58
58
  private
59
59
 
60
+ # This method determins if the module/class has its corresponding
61
+ def self.has_type_map?(mod)
62
+ return Runtime::TYPE_MAP[mod] != nil
63
+ end
64
+
60
65
  # Thie method checks if the module has all the methods specified in
61
66
  # meths array
62
67
  def self.module_has_methods?(mod, meths)
@@ -295,11 +300,11 @@ module RubyBreaker
295
300
  #
296
301
  def self.fusion_subtype_rel?(lhs,rhs)
297
302
  return false unless lhs.kind_of?(FusionType)
298
- if lhs.mod.kind_of?(Broken)
303
+ if self.has_type_map?(lhs.mod)
299
304
  if rhs.instance_of?(NominalType) # don't include self type
300
305
  if RubyTypeUtils.subclass_rel?(lhs.mod, rhs.mod)
301
306
  is_subtype = true
302
- elsif rhs.mod.kind_of?(Broken)
307
+ elsif self.has_type_map?(rhs.mod)
303
308
  # then do a type check for each method
304
309
  lhs_meths = Inspect.inspect_all(lhs.mod)
305
310
  rhs_meths = Inspect.inspect_all(rhs.mod)
@@ -311,7 +316,7 @@ module RubyBreaker
311
316
  elsif rhs.instance_of?(FusionType)
312
317
  if RubyTypeUtils.subclass_rel?(lhs.mod, rhs.mod)
313
318
  is_subtype = true
314
- elsif rhs.mod.kind_of?(Broken)
319
+ elsif self.has_type_map?(rhs.mod)
315
320
  # then do a type check for each method
316
321
  lhs_meths = Inspect.inspect_all(lhs.mod)
317
322
  rhs_meths = Inspect.inspect_meths(rhs.mod, lhs.meths.keys)
@@ -377,7 +382,7 @@ module RubyBreaker
377
382
  # If RHS is not broken, sorry no subtype relationship
378
383
  if RubyTypeUtils.subclass_rel?(lhs.mod, rhs.mod)
379
384
  is_subtype = true
380
- elsif lhs.kind_of?(Broken) && rhs.kind_of?(Broken)
385
+ elsif self.has_type_map?(lhs.mod) && self.has_type_map?(rhs.mod)
381
386
  is_subtype = true
382
387
  lhs_methods = lhs.mod.instance_methods
383
388
  rhs.meth_names.each {|m|
@@ -27,7 +27,6 @@ module RubyBreaker
27
27
  lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
28
28
  end
29
29
  end
30
-
31
30
  end
32
31
 
33
32
  end