rubybreaker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/AUTHORS +7 -0
  2. data/LICENSE +26 -0
  3. data/README.md +403 -0
  4. data/Rakefile +90 -0
  5. data/TODO +30 -0
  6. data/bin/gen_stub_rubylib +64 -0
  7. data/bin/rubybreaker +67 -0
  8. data/lib/rubybreaker/context.rb +122 -0
  9. data/lib/rubybreaker/debug.rb +48 -0
  10. data/lib/rubybreaker/error.rb +59 -0
  11. data/lib/rubybreaker/rubylib/core.rb +2316 -0
  12. data/lib/rubybreaker/rubylib.rb +3 -0
  13. data/lib/rubybreaker/runtime/inspector.rb +57 -0
  14. data/lib/rubybreaker/runtime/monitor.rb +235 -0
  15. data/lib/rubybreaker/runtime/object_wrapper.rb +77 -0
  16. data/lib/rubybreaker/runtime/overrides.rb +42 -0
  17. data/lib/rubybreaker/runtime/pluggable.rb +57 -0
  18. data/lib/rubybreaker/runtime/type_placeholder.rb +27 -0
  19. data/lib/rubybreaker/runtime/type_system.rb +228 -0
  20. data/lib/rubybreaker/runtime/typesig_parser.rb +45 -0
  21. data/lib/rubybreaker/runtime.rb +103 -0
  22. data/lib/rubybreaker/test/testcase.rb +39 -0
  23. data/lib/rubybreaker/test.rb +1 -0
  24. data/lib/rubybreaker/type/type.rb +241 -0
  25. data/lib/rubybreaker/type/type_comparer.rb +143 -0
  26. data/lib/rubybreaker/type/type_grammar.treetop +285 -0
  27. data/lib/rubybreaker/type/type_unparser.rb +142 -0
  28. data/lib/rubybreaker/type.rb +2 -0
  29. data/lib/rubybreaker/typing/rubytype.rb +47 -0
  30. data/lib/rubybreaker/typing/subtyping.rb +480 -0
  31. data/lib/rubybreaker/typing.rb +3 -0
  32. data/lib/rubybreaker/util.rb +31 -0
  33. data/lib/rubybreaker.rb +193 -0
  34. data/test/integrated/tc_method_missing.rb +30 -0
  35. data/test/integrated/tc_simple1.rb +77 -0
  36. data/test/runtime/tc_obj_wrapper.rb +73 -0
  37. data/test/runtime/tc_typesig_parser.rb +33 -0
  38. data/test/ts_integrated.rb +4 -0
  39. data/test/ts_runtime.rb +5 -0
  40. data/test/ts_type.rb +5 -0
  41. data/test/ts_typing.rb +4 -0
  42. data/test/type/tc_comparer.rb +211 -0
  43. data/test/type/tc_parser.rb +219 -0
  44. data/test/type/tc_unparser.rb +276 -0
  45. data/test/typing/tc_rubytype.rb +63 -0
  46. data/test/typing/tc_typing.rb +219 -0
  47. data/webpage/footer.html +5 -0
  48. data/webpage/generated_toc.js +319 -0
  49. data/webpage/header.html +14 -0
  50. data/webpage/images/logo.png +0 -0
  51. data/webpage/index.html +439 -0
  52. data/webpage/rubybreaker.css +53 -0
  53. metadata +119 -0
@@ -0,0 +1,228 @@
1
+ #--
2
+ # This file contains the default type system for RubyBreaker. It uses
3
+ # subtyping defined in ../typing/subtyping.rb. It is not a constraint-based
4
+ # type system and does not check type errors statically. The main purpose of
5
+ # this type system is to give a readable type signature to every method in
6
+ # designated modules and classes.
7
+
8
+ require_relative "object_wrapper"
9
+ require_relative "type_placeholder"
10
+ require_relative "../type"
11
+ require_relative "../typing"
12
+
13
+ module RubyBreaker
14
+
15
+ module Runtime
16
+
17
+ # This is the default type system for RubyBreaker. It can be overridden
18
+ # by a user specified type system. See +pluggable.rb+ for how this can
19
+ # be done.
20
+ class TypeSystem
21
+
22
+ include Pluggable # not needed but for the sake of documentation...
23
+ include TypeDefs
24
+
25
+ protected
26
+
27
+ # Check if the object is wrapped by a monitor
28
+ def is_object_wrapped?(obj)
29
+ return obj.respond_to?(WRAPPED_INDICATOR)
30
+ end
31
+
32
+ # This method is a helper for computing the least upper bound. It
33
+ # handles the case where existing method type is a method type (and
34
+ # not a method list type). If there is no compatibility of the two
35
+ # types, then it returns false.
36
+ def lub_helper(exist_meth_type, new_meth_type)
37
+
38
+ # most restrictive for the given test cases.
39
+ arg_types = []
40
+
41
+ exist_meth_type.arg_types.each_with_index do |exist_arg_type, i|
42
+ arg_type = nil
43
+ new_arg_type = new_meth_type.arg_types[i]
44
+ if !exist_arg_type
45
+ # nil means there hasn't been any type observed
46
+ arg_type = new_arg_type
47
+ elsif new_arg_type.subtype_of?(exist_arg_type)
48
+ arg_type = exist_arg_type
49
+ elsif !exist_arg_type.subtype_of?(new_arg_type)
50
+ # No subtype relation between them, so OR them
51
+ arg_type = OrType.new([new_arg_type, exist_arg_type])
52
+ end
53
+ arg_types << arg_type
54
+ end
55
+
56
+ new_ret_type = new_meth_type.ret_type
57
+ exist_ret_type = exist_meth_type.ret_type
58
+
59
+ if !exist_ret_type
60
+ ret_type = new_ret_type
61
+ resolved = true
62
+ elsif exist_ret_type.subtype_of?(new_ret_type)
63
+ ret_type = exist_ret_type
64
+ resolved = true
65
+ elsif new_ret_type.subtype_of?(exist_ret_type)
66
+ ret_type = new_ret_type
67
+ resolved = true
68
+ else
69
+ resolved = false
70
+ end
71
+
72
+ if resolved
73
+ exist_meth_type.arg_types = arg_types
74
+ exist_meth_type.ret_type = ret_type
75
+ end
76
+
77
+ return resolved
78
+ end
79
+
80
+ # This method computes the least upper bound of the existing method
81
+ # type and newly observed argument/block/return types. There are a few
82
+ # cases to consider:
83
+ #
84
+ # If the existing type is a method list type, the new observed type
85
+ # will be either "consolidated" into one of the method types in the
86
+ # list or added to the list.
87
+ #
88
+ # If there is no compatibility between the existing method type and
89
+ # the observed type, then the method type will be promoted to a method
90
+ # list type. And the newly observed type will be added to the list.
91
+ #
92
+ # For each method type,
93
+ #
94
+ # It basically consolidates the existing type information for the
95
+ # invoked method and the observed type.
96
+ #
97
+ # For arguments, we look for most general type that can handle all
98
+ # types we have seen. This means we find the super type of all types
99
+ # we have seen (excluding unknown types).
100
+ #
101
+ # For return, we look for most specific type that can handle both
102
+ # types. Therefore, if two types have no subtype relation, we AND
103
+ # them. But we do not allow AND types in the return type. We must turn
104
+ # the method type to a method list type.
105
+ #
106
+ # obj:: the receive of the method call
107
+ # inst_meths:: a hash object that maps method names to method types
108
+ # meth_name:: the name of the method being invoked
109
+ # retval:: the return value of the original method call
110
+ # args:: the arguments
111
+ # blk:: the block argument
112
+ #
113
+ def lub(obj, inst_meths, meth_name, retval, *args, &blk)
114
+
115
+ exist_meth_type = inst_meths[meth_name.to_sym]
116
+
117
+ # Construct the newly observed method type first
118
+ new_meth_type = MethodType.new(meth_name)
119
+ args.each {|arg|
120
+ if is_object_wrapped?(arg)
121
+ arg_type = arg.__rubybreaker_type
122
+ else
123
+ arg_type = NominalType.new(arg.class)
124
+ end
125
+ new_meth_type.arg_types << arg_type
126
+ }
127
+ if (obj == retval)
128
+ # the return value is same as the message receiver. This means the
129
+ # return value has the self type.
130
+ SelfType.set_self(obj.class)
131
+ ret_type = SelfType.new()
132
+ else
133
+ # Otherwise, construct a nominal type.
134
+ ret_type = NominalType.new(retval.class)
135
+ end
136
+ new_meth_type.ret_type = ret_type
137
+
138
+ resolved = false
139
+ if exist_meth_type.instance_of?(MethodListType)
140
+ exist_meth_type.types.each {|meth_type|
141
+ resolved = lub_helper(meth_type, new_meth_type)
142
+ break if resolved
143
+ }
144
+ else
145
+ resolved = lub_helper(exist_meth_type, new_meth_type)
146
+ if !resolved
147
+ # Could not resolve the types, so promote the method type to a
148
+ # method list type
149
+ exist_meth_type = MethodListType.new([exist_meth_type])
150
+ inst_meths[meth_name.to_sym] = exist_meth_type
151
+ end
152
+ end
153
+ if !resolved
154
+ exist_meth_type.types << new_meth_type
155
+ end
156
+ end
157
+
158
+ public
159
+
160
+ # This method occurs before every "monitored" method call. It wraps
161
+ # each argument with the object wrapper.
162
+ def before_method(obj, meth_info)
163
+
164
+ mod = obj.class
165
+ inst_meths = Breakable::TYPE_PLACEHOLDER_MAP[mod].inst_meths
166
+
167
+ # Let's take things out of the MethodInfo object
168
+ meth_name = meth_info.meth_name
169
+ args = meth_info.args
170
+ blk = meth_info.blk
171
+ ret = meth_info.ret
172
+
173
+ args = args.map do |arg|
174
+ if arg.kind_of?(TrueClass) || arg.kind_of?(FalseClass)
175
+ # XXX: would overrides resolve this issue?
176
+ arg
177
+ else
178
+ ObjectWrapper.new(arg)
179
+ end
180
+ end
181
+
182
+ Debug.msg("In module monitor_before #{meth_name}")
183
+
184
+ meth_type = inst_meths[meth_name]
185
+
186
+ if meth_type
187
+ # This means the method type has been created previously.
188
+ unless (blk == nil && meth_type.blk_type == nil) &&
189
+ (!blk || blk.arity == meth_type.blk_type.arg_types.length)
190
+ raise Errors::TypeError("Block usage is inconsistent")
191
+ end
192
+ else
193
+ # No method type has been created for this method yet. Create a
194
+ # blank method type (where each argument type, block type, and
195
+ # return type are all nil).
196
+ arg_types = args.map {|arg| nil }
197
+ blk_type = blk ? BlockType.new(Array.new(blk.arity), nil, nil) : nil
198
+ meth_type = MethodType.new(meth_name, arg_types, blk_type, nil)
199
+ inst_meths[meth_name] = meth_type
200
+ end
201
+
202
+ meth_info.args = args
203
+
204
+ end
205
+
206
+ # This method occurs after every "monitored" method call. It updates
207
+ # the type information.
208
+ def after_method(obj, meth_info)
209
+ mod = obj.class
210
+ # Take things out
211
+ meth_name = meth_info.meth_name
212
+ retval = meth_info.ret
213
+ args = meth_info.args
214
+ blk = meth_info.blk
215
+
216
+ Debug.msg("In module monitor_after #{meth_name}")
217
+
218
+ inst_meths = Breakable::TYPE_PLACEHOLDER_MAP[mod].inst_meths
219
+
220
+ # Compute the least upper bound
221
+ lub(obj, inst_meths,meth_name,retval,*args,&blk)
222
+
223
+ end
224
+
225
+ end
226
+ end
227
+
228
+ end
@@ -0,0 +1,45 @@
1
+ #--
2
+ # This program parses a type signature given by the Ruby programmer in the
3
+ # RubyBreaker type format.
4
+
5
+ require "treetop"
6
+ require_relative "../type"
7
+
8
+ module RubyBreaker
9
+
10
+ module Runtime
11
+
12
+ module TypeSigParser
13
+
14
+ Treetop.load "#{File.dirname(__FILE__)}/../type/type_grammar"
15
+ PARSER = TypeGrammarParser.new
16
+
17
+ public
18
+
19
+ # This is a simple redirecting method for parsing type signature. The
20
+ # only special thing about this method is that, if there are multiple
21
+ # lines in the signature, it will look at each line and construct a
22
+ # MethodListType to represent the intersection type.
23
+ def self.parse(str)
24
+ meth_types = []
25
+
26
+ # Get caller information and set the global location
27
+ my_caller = caller[1]
28
+ if my_caller
29
+ file,line,junk = my_caller.split(":")
30
+ Position.set(file,line,-1)
31
+ end
32
+
33
+ return PARSER.parse(str).value
34
+
35
+ rescue => e
36
+
37
+ puts e
38
+
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,103 @@
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
+
6
+ require_relative "runtime/overrides"
7
+ require_relative "runtime/typesig_parser"
8
+ require_relative "runtime/monitor"
9
+ require_relative "runtime/inspector"
10
+
11
+ module RubyBreaker
12
+
13
+ # This module should be included in classes or modules that you want to
14
+ # monitor during runtime. The concept is that once a Breakable module is
15
+ # monitored and its type documentation is generated, the module now becomes
16
+ # a Broken module. The actual implementation is a simple trigger that
17
+ # queues the target module into the list of modules to monitor. The queued
18
+ # modules are then modified to be monitored dynamically.
19
+ module Breakable
20
+
21
+ TYPE_PLACEHOLDER_MAP = {} # module => type_placeholder
22
+ MONITOR_MAP = {} # module => monitor
23
+
24
+ # when this module is included, simply keep track of this module so we
25
+ # can start monitoring
26
+ def self.included(mod)
27
+ BREAKABLE << mod
28
+ end
29
+
30
+ end
31
+
32
+ # This module is included for "broken" classes.
33
+ module Broken
34
+
35
+ include TypeDefs
36
+ include Runtime
37
+
38
+ TYPE_PLACEHOLDER_MAP = {} # module => type_placeholder
39
+
40
+ # This module will be "extended" to the meta class of the class that
41
+ # includes Broken module. This allows the meta class to call 'typesig'
42
+ # method to parse the type signature dynamically.
43
+ #
44
+ # Usage:
45
+ # Class A
46
+ # include RubyBreaker::Broken
47
+ #
48
+ # typesig("foo(fixnum) -> fixnum")
49
+ # def foo(x) ... end
50
+ # end
51
+ #
52
+ module BrokenMeta
53
+
54
+ include TypeDefs
55
+ include Runtime
56
+
57
+ # This method can be used at the meta level of the target module to
58
+ # specify the type of a method.
59
+ def typesig(str)
60
+ t = TypeSigParser.parse(str)
61
+ placeholder = TYPE_PLACEHOLDER_MAP[self]
62
+ if placeholder
63
+ meth_type = placeholder.inst_meths[t.meth_name]
64
+ if meth_type
65
+ # TODO: make a method list
66
+ if meth_type.instance_of?(MethodListType)
67
+ meth_type.types << t
68
+ else
69
+ # then upgrade it
70
+ placeholder.inst_meths[t.meth_name] = MethodListType.new([meth_type, t])
71
+ end
72
+ else
73
+ placeholder.inst_meths[t.meth_name] = t
74
+ end
75
+ end
76
+ return t
77
+ end
78
+
79
+ end
80
+
81
+ # This method is triggered when Broken module is included. This just
82
+ # extends BrokenMeta into the target module so "typesig" method can be
83
+ # called from the meta level of the module.
84
+ def self.included(mod)
85
+
86
+ # Add to the list of broken modules
87
+ BROKEN << mod
88
+
89
+ # This MUST BE set for self type to work in type signatures
90
+ SelfType.set_self(mod)
91
+
92
+ # Create if there is no type placeholder for this module yet
93
+ placeholder = TYPE_PLACEHOLDER_MAP[mod]
94
+ if !placeholder
95
+ placeholder = TypePlaceholder.new()
96
+ TYPE_PLACEHOLDER_MAP[mod] = placeholder
97
+ end
98
+ mod.extend(BrokenMeta)
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -0,0 +1,39 @@
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 :) ).
5
+
6
+ module RubyBreaker
7
+
8
+ # This module overrides the normal behavior of Ruby Stdlib's TestCase
9
+ # class.
10
+ module TestCase
11
+
12
+ def self.setup()
13
+ Main.setup()
14
+ end
15
+
16
+ def self.teardown()
17
+ # Main.output()
18
+ end
19
+
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::Utilities.rb_print("Running " + args[0].to_s)
29
+ RubyBreaker::TestCase.setup()
30
+ __run(*args,&blk)
31
+ RubyBreaker::TestCase.teardown()
32
+ end
33
+
34
+ EOS
35
+
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1 @@
1
+ require_relative "test/testcase"
@@ -0,0 +1,241 @@
1
+ #--
2
+ # This file contains the type structure used in RubyBreaker. Here we list
3
+ # types that are used (allowed) in RubyBreaker:
4
+ #
5
+ # AnyType represents basically any type in Ruby
6
+ # NilType represents a nil object
7
+ # SelfType represents "self"--the current object
8
+ # NominalType represents an object
9
+ # DuckType represents a partial object (a collection of methods)
10
+ # FusionType represents an object along with a set of methods
11
+ # MethodType represents a method
12
+ # BlockType represents a block
13
+ # OrType represents one of the many objects (i.e, OR)
14
+ # OptionalType represents an optional argument type
15
+ # VarLengthType represents a variable length argument type
16
+ # MethodListType represents one or more methods
17
+ #
18
+
19
+ require_relative "../util"
20
+ require_relative "../context.rb"
21
+
22
+ module RubyBreaker
23
+
24
+ # This module contains all RubyBreaker type definitions. This module has
25
+ # to be included to the module if you want to work with the type
26
+ # definitions that RubyBreaker provides (unless you want to add TypeDefs
27
+ # namespace in the module).
28
+ module TypeDefs
29
+
30
+ # This class is a catch-all. The constructor of this class must be
31
+ # called from children via super() in order to assign the position field
32
+ # variable.
33
+ #
34
+ # The optional arguments are args[0] = file name args[1] = line number
35
+ #
36
+ # args[2] = column position
37
+ #
38
+ # or
39
+ #
40
+ # args[0] = a Position, ObjectPosition, or Context object
41
+ #
42
+ class Type
43
+
44
+ # Speficies the context of the type.
45
+ attr_accessor :ctx
46
+
47
+ def initialize(*args)
48
+ case args[0]
49
+ when Context
50
+ @ctx = args[0]
51
+ when Position
52
+ @ctx = Context.new(args[0])
53
+ when ObjectPosition
54
+ @ctx = Context.new(args[0])
55
+ else
56
+ file = args[0]
57
+ line = args[1]
58
+ col = args[2]
59
+ pos = Position.new(file,line,col)
60
+ @ctx = Context.new(pos)
61
+ end
62
+ end
63
+ end
64
+
65
+ # This type can represent any object
66
+ class AnyType < Type
67
+ def initialize(*args)
68
+ super(*args)
69
+ end
70
+ end
71
+
72
+ # This type represents a nil
73
+ class NilType < Type
74
+ def initialize(*args)
75
+ super(*args)
76
+ end
77
+ end
78
+
79
+ # This class represents a concrete object like a Numeric or String. It
80
+ # stores the actual module in the instance variable @mod.
81
+ class NominalType < Type
82
+
83
+ # This accessor points to the actual module
84
+ attr_accessor :mod
85
+
86
+ def initialize(mod=nil,*args)
87
+ super(*args)
88
+ @mod = mod
89
+ end
90
+ end
91
+
92
+ # This type represents the self type. Note that this is a subclass of
93
+ # Nominal Type. It works just like nominal type except that it also points
94
+ # to the current object! See subtyping.rb for more detail on how this
95
+ # would impact typing.
96
+ class SelfType < NominalType
97
+
98
+ # This is a setter method for class variable mod.
99
+ # NOTE: It is set every time Broken module is included.
100
+ def self.set_self(mod)
101
+ @@mod = mod
102
+ end
103
+
104
+ # This is a getter method for class variable mod.
105
+ def self.get_self(mod)
106
+ @@mod = mod
107
+ end
108
+
109
+ def initialize(*args)
110
+ # NOTE: @@mod is not required in general, but for typing it is a must.
111
+ super(@@mod, *args)
112
+ end
113
+ end
114
+
115
+ # This class represents any object with certain methods
116
+ # Usage: [m1,m2,...] where m1...mn are method names
117
+ class DuckType < Type
118
+
119
+ # This accessor sets/gets method names in the duck type.
120
+ attr_accessor :meth_names
121
+
122
+ def initialize(meth_names=[],*args)
123
+ super(*args)
124
+ @meth_names = meth_names.map!{|n| n.to_sym}
125
+ end
126
+ def add_meth(meth_name)
127
+ @meth_names << meth_name.to_sym if !@meth_names.include?(meth_name)
128
+ end
129
+ end
130
+
131
+ # This class represents any object that has certain methods whose types
132
+ # are same as the given nominal type's counterparts.
133
+ # Usage: nominal_type[m1,m2,...]
134
+ class FusionType < DuckType
135
+
136
+ # This accessor sets/gets the nominal type to which the method names
137
+ # are bound.
138
+ attr_accessor :nom_type
139
+
140
+ def initialize(nom_type,meth_names=[],*args)
141
+ super(meth_names,*args)
142
+ @nom_type = nom_type
143
+ end
144
+
145
+ # This method gets the actual module of the nominal type for this
146
+ # fusion type. This is a shorthand for t1.nom_type.mod().
147
+ def mod()
148
+ return @nom_type.mod
149
+ end
150
+ end
151
+
152
+ # This class represents a block (in a method). It has zero or more argument
153
+ # types, nested block type (optional), and a return type.
154
+ class BlockType < Type
155
+
156
+ # This accessor sets/gets the argument types for this block type.
157
+ attr_accessor :arg_types
158
+
159
+ # This accessor sets/gets the block type for this block type.
160
+ attr_accessor :blk_type
161
+
162
+ # This accessor sets/gets the return type for this block type.
163
+ attr_accessor :ret_type
164
+
165
+ def initialize(arg_types=[],blk_type=nil,ret_type=nil,*args)
166
+ super(*args)
167
+ @arg_types = arg_types
168
+ @blk_type = blk_type
169
+ @ret_type = ret_type
170
+ end
171
+ end
172
+
173
+ # This class represents a method and is essentially same as block type
174
+ # except the method name.
175
+ class MethodType < BlockType
176
+
177
+ # This accessor sets/gets the method name for this method type.
178
+ attr_accessor :meth_name
179
+
180
+ def initialize(meth_name,arg_types=[],blk_type=nil,ret_type=nil,*args)
181
+ super(arg_types,blk_type,ret_type,*args)
182
+ @meth_name = meth_name.to_sym
183
+ end
184
+ end
185
+
186
+ # This class respresents an optional argument type
187
+ class OptionalType < Type
188
+
189
+ # This accessor sets/gets the inner type of this optional type.
190
+ attr_accessor :type
191
+
192
+ def initialize(type,*args)
193
+ super(*args)
194
+ @type = type
195
+ end
196
+ end
197
+
198
+ # This class represents a variable-length argument type
199
+ class VarLengthType < Type
200
+
201
+ # This accessor sets/gets the inner type of this variable length
202
+ # argument type.
203
+ attr_accessor :type
204
+
205
+ def initialize(type,*args)
206
+ super(*args)
207
+ @type = type
208
+ end
209
+ end
210
+
211
+ # This class represents one of many types
212
+ class OrType < Type
213
+
214
+ # This accessor sets/gets the inner types of this "or" type.
215
+ attr_accessor :types
216
+
217
+ def initialize(types=[],*args)
218
+ super(*args)
219
+ @types = types
220
+ end
221
+ end
222
+
223
+ # This class represents multiple method types.
224
+ class MethodListType < Type
225
+
226
+ # This accessor sets/gets the method types.
227
+ attr_accessor :types
228
+
229
+ def initialize(types=[],*args)
230
+ super(*args)
231
+ @types = types
232
+ end
233
+ end
234
+
235
+ end
236
+
237
+ # Include the module right away
238
+ include TypeDefs
239
+
240
+ end
241
+