rubybreaker 0.0.8 → 0.0.9

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 (73) hide show
  1. data/NEWS +6 -0
  2. data/VERSION +1 -1
  3. data/bin/rubybreaker +3 -3
  4. data/lib/rubybreaker.rb +15 -11
  5. data/lib/rubybreaker/doc/rdoc.rb +1 -1
  6. data/lib/rubybreaker/runtime/monitor.rb +8 -6
  7. data/lib/rubybreaker/runtime/object_wrapper.rb +38 -16
  8. data/lib/rubybreaker/runtime/overrides.rb +42 -30
  9. data/lib/rubybreaker/runtime/type_system.rb +45 -14
  10. data/lib/rubybreaker/type/type_unparser.rb +4 -8
  11. data/lib/rubybreaker/typing/subtyping.rb +1 -0
  12. data/test/integrated/tc_original_behavior.rb +38 -0
  13. data/test/integrated/tc_simple1.rb +20 -0
  14. data/test/integrated/tc_simple_algorithms.rb +135 -0
  15. data/test/runtime/tc_obj_wrapper.rb +3 -3
  16. data/test/ts_integrated.rb +1 -0
  17. data/test/type/tc_parser.rb +24 -0
  18. data/webpage/rdoc/Object.html +0 -2
  19. data/webpage/rdoc/Rake.html +0 -2
  20. data/webpage/rdoc/Rake/RubyBreakerTestTask.html +0 -2
  21. data/webpage/rdoc/RubyBreaker.html +1 -3
  22. data/webpage/rdoc/RubyBreaker/Breakable.html +0 -2
  23. data/webpage/rdoc/RubyBreaker/Broken.html +0 -2
  24. data/webpage/rdoc/RubyBreaker/Context.html +0 -2
  25. data/webpage/rdoc/RubyBreaker/Errors.html +0 -2
  26. data/webpage/rdoc/RubyBreaker/Errors/ArgumentTypeError.html +0 -2
  27. data/webpage/rdoc/RubyBreaker/Errors/ArityError.html +0 -2
  28. data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +0 -2
  29. data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +0 -2
  30. data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +0 -2
  31. data/webpage/rdoc/RubyBreaker/Errors/ReturnTypeError.html +0 -2
  32. data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +0 -2
  33. data/webpage/rdoc/RubyBreaker/Errors/UserError.html +0 -2
  34. data/webpage/rdoc/RubyBreaker/ObjectPosition.html +0 -2
  35. data/webpage/rdoc/RubyBreaker/Position.html +0 -2
  36. data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +0 -2
  37. data/webpage/rdoc/RubyBreaker/Runtime.html +7 -3
  38. data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +0 -2
  39. data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +0 -2
  40. data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +12 -13
  41. data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +6 -7
  42. data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +4 -6
  43. data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +21 -19
  44. data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +0 -2
  45. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +0 -2
  46. data/webpage/rdoc/RubyBreaker/Runtime/TypeSigUnparser.html +0 -2
  47. data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +52 -23
  48. data/webpage/rdoc/RubyBreaker/TypeComparer.html +0 -2
  49. data/webpage/rdoc/RubyBreaker/TypeDefs.html +0 -2
  50. data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +0 -2
  51. data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +0 -2
  52. data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +0 -2
  53. data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +0 -2
  54. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +0 -2
  55. data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +0 -2
  56. data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +0 -2
  57. data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +0 -2
  58. data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +0 -2
  59. data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +0 -2
  60. data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +0 -2
  61. data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +2 -4
  62. data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +0 -2
  63. data/webpage/rdoc/RubyBreaker/TypeUnparser.html +1 -3
  64. data/webpage/rdoc/RubyBreaker/Typing.html +1 -3
  65. data/webpage/rdoc/RubyBreaker/Util.html +0 -2
  66. data/webpage/rdoc/Test.html +0 -2
  67. data/webpage/rdoc/Test/Unit.html +0 -2
  68. data/webpage/rdoc/created.rid +10 -10
  69. data/webpage/rdoc/index.html +0 -2
  70. data/webpage/rdoc/js/search_index.js +1 -1
  71. data/webpage/rdoc/table_of_contents.html +31 -38
  72. metadata +3 -3
  73. data/webpage/rdoc/RubyBreaker/RDocSupport.html +0 -328
data/NEWS CHANGED
@@ -1,3 +1,9 @@
1
+ # VERSION 0.0.9
2
+ * More critical bug fixes
3
+
4
+ # VERSION 0.0.8
5
+ * Bug fixes
6
+
1
7
  # VERSION 0.0.7
2
8
  * Early dynamic type check is implemented.
3
9
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.8
1
+ 0.0.9
@@ -9,10 +9,10 @@ module RubyBreaker
9
9
  exit(1)
10
10
  end
11
11
 
12
- # This method prepares shell mode execution of RubyBreaker.
12
+ # This method prepares the command mode execution of RubyBreaker.
13
13
  def self.main()
14
14
  RubyBreaker.setup_logger()
15
- RubyBreaker.verbose("Running RubyBreaker in shell mode")
15
+ RubyBreaker.verbose("Running RubyBreaker in the command mode")
16
16
 
17
17
  # parse the command-line arguments
18
18
  OPTION_PARSER.parse!
@@ -60,7 +60,7 @@ module RubyBreaker
60
60
  self.verbose("Done importing #{lib}")
61
61
  end
62
62
 
63
- # Now, RubyBreaker shell mode will run this
63
+ # Runs the main library code at this point
64
64
  RubyBreaker.run()
65
65
 
66
66
  # Run the program file!
@@ -133,18 +133,22 @@ module RubyBreaker
133
133
  if fname && OPTIONS[:save_output]
134
134
  # Check if the file already exists--that is, if it was used for input
135
135
  io_exist = File.exists?(fname)
136
- RubyBreaker.verbose("Saving it to #{fname}")
137
- # Append the result to the input file (or create a new file)
138
- fmode = OPTIONS[:append] ? "a" : "w"
139
- open(fname, fmode) do |f|
140
- # When append, do not write the header
141
- unless OPTIONS[:append]
142
- f.puts "# This file is auto-generated by RubyBreaker"
136
+ if File.writable?(fname)
137
+ RubyBreaker.verbose("Saving it to #{fname}")
138
+ # Append the result to the input file (or create a new file)
139
+ fmode = OPTIONS[:append] ? "a" : "w"
140
+ open(fname, fmode) do |f|
141
+ # When append, do not write the header
142
+ unless OPTIONS[:append]
143
+ f.puts "# This file is auto-generated by RubyBreaker"
144
+ end
145
+ # But time stamp always
146
+ f.puts "# Last modified: #{Time.now}"
147
+ f.puts "require \"rubybreaker\"" unless OPTIONS[:append]
148
+ f.print code
143
149
  end
144
- # But time stamp always
145
- f.puts "# Last modified: #{Time.now}"
146
- f.puts "require \"rubybreaker\"" unless OPTIONS[:append]
147
- f.print code
150
+ else
151
+ RubyBreaker.verbose("Cannot write to #{fname}.")
148
152
  end
149
153
  end
150
154
 
@@ -5,7 +5,7 @@ module RubyBreaker
5
5
 
6
6
  # This module has functionalities that are necessary for supporting RDoc
7
7
  # output
8
- module RDocSupport
8
+ module RDocSupport #:nodoc:
9
9
 
10
10
  include TypeDefs
11
11
 
@@ -94,14 +94,13 @@ module RubyBreaker
94
94
  mm.check_before_method(obj, meth_info)
95
95
  end
96
96
  rescue ::Exception => e
97
+ RubyBreaker.log("Exception #{e.class} has been raised.", :debug, CONTEXT)
97
98
  # Trap it, turn on the global monitor and then re-raise the
98
99
  # exception
99
100
  GLOBAL_MONITOR_SWITCH.turn_on()
100
101
  raise e
101
102
  end
102
103
 
103
- RubyBreaker.log("break_before_method ended")
104
-
105
104
  # we are going to turn the switch back on
106
105
  GLOBAL_MONITOR_SWITCH.turn_on()
107
106
 
@@ -109,9 +108,10 @@ module RubyBreaker
109
108
  retval = obj.send(stub_meth_name.to_sym, *meth_info.args,
110
109
  &meth_info.blk)
111
110
 
112
- # turn it off
111
+ # turn the switch off again
113
112
  GLOBAL_MONITOR_SWITCH.turn_off()
114
113
 
114
+ # Remember the return value in the method info object.
115
115
  meth_info.ret = retval
116
116
 
117
117
  begin
@@ -124,6 +124,7 @@ module RubyBreaker
124
124
  rescue ::Exception => e
125
125
  # Trap it, turn on the global monitor and then re-raise the
126
126
  # exception
127
+ RubyBreaker.log("Exception #{e.class} has been raised.", :debug, CONTEXT)
127
128
  GLOBAL_MONITOR_SWITCH.turn_on()
128
129
  raise e
129
130
  end
@@ -143,7 +144,7 @@ module RubyBreaker
143
144
 
144
145
  # This method returns the alternative (renamed) method name
145
146
  def self.get_alt_meth_name(meth_name)
146
- return "__#{meth_name}"
147
+ return "__rubybreaker_#{meth_name}"
147
148
  end
148
149
 
149
150
  # This method returns the original method name
@@ -237,11 +238,11 @@ module RubyBreaker
237
238
  # Installs an module (class) monitor to the object.
238
239
  def self.install_monitor(monitor_type, mod)
239
240
 
240
- RubyBreaker.log("Installing module monitor for #{mod}")
241
+ RubyBreaker.log("Installing #{monitor_type} monitor for #{mod} started.")
241
242
 
242
243
  # Do not re-install monitor if already done so.
243
244
  if MONITOR_MAP[mod]
244
- RubyBreaker.log("Skip #{mod} as it has a monitor installed.")
245
+ RubyBreaker.log("#{mod} already has a monitor installed.")
245
246
  return
246
247
  end
247
248
 
@@ -266,6 +267,7 @@ module RubyBreaker
266
267
  end
267
268
  end
268
269
 
270
+ RubyBreaker.log("Installing #{monitor_type} monitor for #{mod} ended.")
269
271
  end
270
272
 
271
273
  end
@@ -35,13 +35,25 @@ module RubyBreaker
35
35
  return @__rubybreaker_type
36
36
  end
37
37
 
38
+ # This method computes the wrap level of any given wrapped object. In
39
+ # theory, this should always be 1.
40
+ #
41
+ # Used for internal debugging purpose only
42
+ def __rubybreaker_wrap_level() #:nodoc:
43
+ val = 1
44
+ if @__rubybreaker_obj.respond_to?(WRAPPED_INDICATOR)
45
+ val += @__rubybreaker_obj.__rubybreaker_wrap_level
46
+ end
47
+ return val
48
+ end
49
+
38
50
  #--
39
51
  # The following code generates the "serious problem" warning which is
40
52
  # suppressed by the hack using $VERBOSE. This is ok. This meta
41
53
  # programming code block re-defines BasicObject's methods to redirect
42
54
  # to the actual object.
43
55
  [:"!", :"!=", :"==", :"equal?", :"eql?", :"__id__", :"object_id",
44
- :"send", :"__send__", :"instance_eval",
56
+ :"send", :"__send__", :"instance_eval", :class,
45
57
  :"instance_exec"].each do |meth|
46
58
 
47
59
  orig_verbose = $VERBOSE
@@ -65,14 +77,20 @@ module RubyBreaker
65
77
  return true if mname.to_sym == WRAPPED_INDICATOR
66
78
  return @__rubybreaker_obj.respond_to?(mname)
67
79
  end
80
+
81
+ # # Keep track of methods that MUST NOT take wrapped arguments.
82
+ # WRAP_BLACKLIST = {
83
+ # ::Array => [:[], :[]=],
84
+ # ::Hash => [:[], :[]=],
85
+ # }
68
86
 
69
87
  # This method missing method redirects all other method calls.
70
88
  def method_missing(mname,*args,&blk)
71
- ::RubyBreaker.log("Method_missing for #{mname}")
72
89
  if GLOBAL_MONITOR_SWITCH.switch
73
90
 
74
91
  # Be safe and turn the switch off
75
92
  GLOBAL_MONITOR_SWITCH.turn_off
93
+ ::RubyBreaker.log("Object wrapper method_missing for #{mname} started")
76
94
 
77
95
  # Must handle send method specially (do not track them)
78
96
  if [:"__send__", :send].include?(mname)
@@ -88,16 +106,18 @@ module RubyBreaker
88
106
  is_obj_mod = (obj.class == ::Class or obj.class == ::Module)
89
107
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
90
108
 
91
- # Monitor map doesn't exist MEANS it's not being monitored.
92
- unless MONITOR_MAP[mod]
93
- args.map! do |arg|
94
- if arg.respond_to?(WRAPPED_INDICATOR)
95
- arg.__rubybreaker_obj
96
- else
97
- arg
98
- end
99
- end
100
- end
109
+ # # There are certain methods that should not take wrapped
110
+ # # argument(s) whatsoever. Use WRAP_BLACKLIST for these.
111
+ # if !MONITOR_MAP[mod] && WRAP_BLACKLIST[mod] &&
112
+ # WRAP_BLACKLIST[mod].include?(mname)
113
+ # args.map! do |arg|
114
+ # if arg.respond_to?(WRAPPED_INDICATOR)
115
+ # arg.__rubybreaker_obj
116
+ # else
117
+ # arg
118
+ # end
119
+ # end
120
+ # end
101
121
 
102
122
  # Turn on the global switch again
103
123
  GLOBAL_MONITOR_SWITCH.turn_on
@@ -105,13 +125,15 @@ module RubyBreaker
105
125
  # And call the original method
106
126
  retval = @__rubybreaker_obj.send(mname, *args, &blk)
107
127
 
108
- # No need to wrap the object again...if it's wrapped already
109
- unless retval.respond_to?(WRAPPED_INDICATOR)
110
- retval = ObjectWrapper.new(retval)
111
- end
128
+ # # No need to wrap the object again...if it's wrapped already
129
+ # unless retval.respond_to?(WRAPPED_INDICATOR)
130
+ # retval = ObjectWrapper.new(retval)
131
+ # end
112
132
  else
133
+ ::RubyBreaker.log("Object wrapper method_missing for #{mname} started")
113
134
  retval = @__rubybreaker_obj.send(mname, *args, &blk)
114
135
  end
136
+ ::RubyBreaker.log("Object wrapper method_missing for #{mname} ended")
115
137
  return retval
116
138
  end
117
139
  end
@@ -19,19 +19,31 @@ module RubyBreaker
19
19
  # indicate overridden methods.
20
20
  OVERRIDE_PREFIX = "__rubybreaker"
21
21
 
22
- # Prohibit these module/class+method from being overriden
22
+ # Prohibit these module/class+method from being overriden.
23
23
  BLACKLIST = {
24
24
  String => [:to_s, :<<, :concat, :gsub],
25
25
  }
26
26
 
27
+ # Allow certain methods of these classes/modules to be overrriden. That
28
+ # is, they will take unwrapped arguments whatsoever.
29
+ WHITELIST = {
30
+ Kernel => [:puts, :putc, :gets, :print, :printf, :raise],
31
+ IO => [:getc, :gets, :putc, :puts, :print, :printf,
32
+ :readlines, :readline, :read],
33
+ Object => [:"==", :equal?, :eql?, :"!="],
34
+ Enumerable => [:"==", :equal?, :eql?, :"!="],
35
+ Array => [:"==", :equal?, :eql?, :"!=", :[], :[]=],
36
+ Hash => [:"==", :equal?, :eql?, :"!=", :[], :[]=],
37
+ }
38
+
27
39
  end
28
40
 
29
41
  end
30
42
 
31
43
  # TODO: More IO related stuff need to be overriden!
32
- [Kernel, IO].each do |mod|
44
+ RubyBreaker::Runtime::WHITELIST.each_pair do |mod, mlist|
33
45
 
34
- [:"puts", :"putc", :"printf", :print].each do |meth_name|
46
+ mlist.each do |meth_name|
35
47
 
36
48
  mod.module_eval <<-EOS
37
49
 
@@ -58,7 +70,7 @@ end
58
70
 
59
71
  end
60
72
 
61
- [Symbol, Numeric, Fixnum, Float, Integer, Bignum, String].each do |mod|
73
+ [Exception, StandardError, ArgumentError, Symbol, Numeric, Fixnum, Float, Integer, Bignum, String].each do |mod|
62
74
  mod.instance_methods(false).each do |meth_name|
63
75
  black_list = RubyBreaker::Runtime::BLACKLIST
64
76
  next if black_list[mod] && black_list[mod].include?(meth_name)
@@ -83,32 +95,32 @@ end
83
95
  end
84
96
  end
85
97
 
86
- # TODO: add more modules here as necessary!
87
- [Object, Enumerable, Array, Hash].each do |mod|
88
-
89
- [:"==", :equal?, :eql?].each do |meth_name|
90
-
91
- # Create a unique alias name for each module. (It causes some issue when
92
- # not done this way.)
93
- alias_name = "RubyBreaker::Runtime::OVERRIDE_PREFIX_#{mod.object_id}" +
94
- "_#{meth_name}"
95
-
96
- mod.module_eval <<-EOS
97
-
98
- alias :"#{alias_name}" :"#{meth_name}"
99
-
100
- def #{meth_name}(other)
101
- if other.respond_to?(RubyBreaker::Runtime::WRAPPED_INDICATOR)
102
- other = other.__rubybreaker_obj
103
- end
104
- return self.send(:"#{alias_name}",other)
105
- end
106
-
107
- EOS
108
-
109
- end
110
-
111
- end
98
+ # # TODO: add more modules here as necessary!
99
+ # [Object, Enumerable, Array, Hash].each do |mod|
100
+ #
101
+ # [:"==", :equal?, :eql?, :"!="].each do |meth_name|
102
+ #
103
+ # # Create a unique alias name for each module. (It causes some issue when
104
+ # # not done this way.)
105
+ # alias_name = "RubyBreaker::Runtime::OVERRIDE_PREFIX_#{mod.object_id}" +
106
+ # "_#{meth_name}"
107
+ #
108
+ # mod.module_eval <<-EOS
109
+ #
110
+ # alias :"#{alias_name}" :"#{meth_name}"
111
+ #
112
+ # def #{meth_name}(other)
113
+ # if other.respond_to?(RubyBreaker::Runtime::WRAPPED_INDICATOR)
114
+ # other = other.__rubybreaker_obj
115
+ # end
116
+ # return self.send(:"#{alias_name}",other)
117
+ # end
118
+ #
119
+ # EOS
120
+ #
121
+ # end
122
+ #
123
+ # end
112
124
 
113
125
 
114
126
 
@@ -41,21 +41,31 @@ module RubyBreaker
41
41
  # most restrictive for the given test cases.
42
42
  arg_types = []
43
43
 
44
+ # Resolve the argument types first.
44
45
  exist_meth_type.arg_types.each_with_index do |exist_arg_type, i|
45
46
  arg_type = nil
46
47
  new_arg_type = new_meth_type.arg_types[i]
47
48
  if !exist_arg_type
48
- # nil means there hasn't been any type observed
49
+ # nil means there hasn't been any type observed so use the new
50
+ # argument type as "resolved".
49
51
  arg_type = new_arg_type
50
52
  elsif new_arg_type.subtype_of?(exist_arg_type)
53
+ # Pick the subtype argument since we are resolving in
54
+ # contra-variance
55
+ arg_type = new_arg_type
56
+ elsif exist_arg_type.subtype_of?(new_arg_type)
57
+ # Pick the subtype argument since we are resolving in
58
+ # contra-variance
51
59
  arg_type = exist_arg_type
52
- elsif !exist_arg_type.subtype_of?(new_arg_type)
53
- # No subtype relation between them, so OR them
60
+ else
61
+ # No subtype relation between them, so OR them.
54
62
  arg_type = OrType.new([new_arg_type, exist_arg_type])
55
63
  end
56
64
  arg_types << arg_type
57
65
  end
58
66
 
67
+ # Now, resolve the return type
68
+
59
69
  new_ret_type = new_meth_type.ret_type
60
70
  exist_ret_type = exist_meth_type.ret_type
61
71
 
@@ -63,10 +73,12 @@ module RubyBreaker
63
73
  ret_type = new_ret_type
64
74
  resolved = true
65
75
  elsif exist_ret_type.subtype_of?(new_ret_type)
66
- ret_type = exist_ret_type
76
+ # Co-variance
77
+ ret_type = new_ret_type
67
78
  resolved = true
68
79
  elsif new_ret_type.subtype_of?(exist_ret_type)
69
- ret_type = new_ret_type
80
+ # Co-variance
81
+ ret_type = exist_ret_type
70
82
  resolved = true
71
83
  else
72
84
  resolved = false
@@ -213,6 +225,8 @@ module RubyBreaker
213
225
  args = meth_info.args
214
226
  # blk = meth_info.blk
215
227
 
228
+ RubyBreaker.log("check_before_method #{mod}##{meth_name} started")
229
+
216
230
  # Get the registered method type for this method
217
231
  meth_type = meth_type_map[meth_name]
218
232
 
@@ -263,6 +277,7 @@ module RubyBreaker
263
277
  end
264
278
  end
265
279
 
280
+ RubyBreaker.log("check_before_method #{mod}##{meth_name} ended")
266
281
  end
267
282
 
268
283
  # This method is invoked after the original method is executed.
@@ -270,13 +285,16 @@ module RubyBreaker
270
285
  is_obj_mod = (obj.class == Class or obj.class == Module)
271
286
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
272
287
 
288
+ # Get the method type map for the module/class from the global map.
273
289
  meth_type_map = TYPE_MAP[mod]
274
- return unless meth_type_map
290
+ return unless meth_type_map
275
291
 
276
292
  # Let's take things out of the MethodInfo object
277
293
  meth_name = meth_info.meth_name
278
294
  ret = meth_info.ret
279
295
 
296
+ RubyBreaker.log("check_after_method #{mod}##{meth_name} started")
297
+
280
298
  # Get the registered method type for this method
281
299
  meth_type = meth_type_map[meth_name]
282
300
 
@@ -286,6 +304,8 @@ module RubyBreaker
286
304
  " return value does not have type #{ret_type.unparse()}."
287
305
  raise Errors::ReturnTypeError.new(msg)
288
306
  end
307
+
308
+ RubyBreaker.log("check_after_method #{mod}##{meth_name} started")
289
309
  end
290
310
 
291
311
  # This method occurs before every call to a "monitored" method in a
@@ -298,30 +318,37 @@ module RubyBreaker
298
318
  is_obj_mod = (obj.class == Class or obj.class == Module)
299
319
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
300
320
 
301
- meth_type_map = TYPE_MAP[mod]
302
-
303
321
  # Let's take things out of the MethodInfo object
304
322
  meth_name = meth_info.meth_name
305
323
  args = meth_info.args
306
324
  blk = meth_info.blk
307
325
  ret = meth_info.ret
308
326
 
327
+ RubyBreaker.log("break_before_method #{mod}##{meth_name} started")
328
+
309
329
  args = args.map do |arg|
310
330
  if arg == nil || arg.kind_of?(TrueClass) || arg.kind_of?(FalseClass)
311
331
  # XXX: would overrides resolve this issue?
312
332
  arg
333
+ elsif arg.respond_to?(WRAPPED_INDICATOR)
334
+ # Don't need to wrap an object that is already wrapped
335
+ arg
313
336
  else
314
337
  ObjectWrapper.new(arg)
315
338
  end
316
339
  end
317
340
 
318
- RubyBreaker.log("In module monitor_before #{meth_name}")
319
-
341
+ # Using this module object, retrieve the method type map which
342
+ # maps method names to method types.
343
+ meth_type_map = TYPE_MAP[mod]
344
+
345
+ # Using the method name, get the type of this method from the map.
320
346
  meth_type = meth_type_map[meth_name]
321
347
 
322
348
  if meth_type
323
349
  # This means the method type has been created previously.
324
- unless (blk == nil && meth_type.blk_type == nil) &&
350
+ unless !meth_type.instance_of?(MethodType) ||
351
+ (blk == nil && meth_type.blk_type == nil) &&
325
352
  (!blk || blk.arity == meth_type.blk_type.arg_types.length)
326
353
  raise Errors::TypeError.new("Block usage is inconsistent")
327
354
  end
@@ -349,6 +376,8 @@ module RubyBreaker
349
376
 
350
377
  meth_info.args = args
351
378
 
379
+ RubyBreaker.log("break_before_method #{mod}##{meth_name} ended")
380
+
352
381
  end
353
382
 
354
383
  # This method occurs after every call to a "monitored" method call of
@@ -359,16 +388,16 @@ module RubyBreaker
359
388
  is_obj_mod = (obj.class == Class or obj.class == Module)
360
389
  mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
361
390
 
362
- # Take things out
391
+ # Take things out of the method info object
363
392
  meth_name = meth_info.meth_name
364
393
  retval = meth_info.ret
365
394
  args = meth_info.args
366
395
  blk = meth_info.blk
367
396
 
368
- RubyBreaker.log("In module monitor_after #{meth_name}")
397
+ RubyBreaker.log("break_after_method #{mod}##{meth_name} started")
369
398
 
370
399
  # Compute the least upper bound
371
- lub(obj, TYPE_MAP[mod],meth_name,retval,*args,&blk)
400
+ lub(obj, TYPE_MAP[mod], meth_name, retval, *args, &blk)
372
401
 
373
402
  if obj == retval
374
403
  # It is possible that the method receiver is a wrapped object if
@@ -378,6 +407,8 @@ module RubyBreaker
378
407
  meth_info.ret = obj
379
408
  end
380
409
 
410
+ RubyBreaker.log("break_after_method #{mod}##{meth_name} ended")
411
+
381
412
  end
382
413
 
383
414
  end