caricature 0.3.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/.gitignore +4 -0
  2. data/Rakefile +100 -0
  3. data/VERSION +1 -0
  4. data/caricature.gemspec +177 -0
  5. data/doc/Array.html +251 -0
  6. data/doc/Caricature/ArgumentRecording.html +366 -0
  7. data/doc/Caricature/ClrClassDescriptor.html +303 -0
  8. data/doc/Caricature/ClrClassMessenger.html +263 -0
  9. data/doc/Caricature/ClrInterfaceDescriptor.html +295 -0
  10. data/doc/Caricature/ClrInterfaceIsolator.html +365 -0
  11. data/doc/Caricature/ClrInterfaceMessenger.html +260 -0
  12. data/doc/Caricature/ClrIsolator.html +424 -0
  13. data/doc/Caricature/Expectation.html +549 -0
  14. data/doc/Caricature/ExpectationBuilder.html +308 -0
  15. data/doc/Caricature/ExpectationSyntax.html +438 -0
  16. data/doc/Caricature/Expectations.html +344 -0
  17. data/doc/Caricature/Interception/ClassMethods.html +246 -0
  18. data/doc/Caricature/Interception.html +416 -0
  19. data/doc/Caricature/Isolation.html +578 -0
  20. data/doc/Caricature/Isolator.html +519 -0
  21. data/doc/Caricature/MemberDescriptor.html +335 -0
  22. data/doc/Caricature/Messenger.html +335 -0
  23. data/doc/Caricature/MethodCallRecorder.html +440 -0
  24. data/doc/Caricature/MethodCallRecording.html +493 -0
  25. data/doc/Caricature/RubyIsolator.html +416 -0
  26. data/doc/Caricature/RubyMessenger.html +260 -0
  27. data/doc/Caricature/RubyObjectDescriptor.html +289 -0
  28. data/doc/Caricature/TypeDescriptor.html +378 -0
  29. data/doc/Caricature/Verification.html +443 -0
  30. data/doc/Caricature.html +358 -0
  31. data/doc/Class.html +287 -0
  32. data/doc/Hash.html +255 -0
  33. data/doc/Module.html +287 -0
  34. data/doc/Object.html +322 -0
  35. data/doc/README_markdown.html +241 -0
  36. data/doc/String.html +289 -0
  37. data/doc/System/String.html +289 -0
  38. data/doc/System/Type.html +289 -0
  39. data/doc/System.html +207 -0
  40. data/doc/created.rid +1 -0
  41. data/doc/images/brick.png +0 -0
  42. data/doc/images/brick_link.png +0 -0
  43. data/doc/images/bug.png +0 -0
  44. data/doc/images/bullet_black.png +0 -0
  45. data/doc/images/bullet_toggle_minus.png +0 -0
  46. data/doc/images/bullet_toggle_plus.png +0 -0
  47. data/doc/images/date.png +0 -0
  48. data/doc/images/find.png +0 -0
  49. data/doc/images/loadingAnimation.gif +0 -0
  50. data/doc/images/macFFBgHack.png +0 -0
  51. data/doc/images/package.png +0 -0
  52. data/doc/images/page_green.png +0 -0
  53. data/doc/images/page_white_text.png +0 -0
  54. data/doc/images/page_white_width.png +0 -0
  55. data/doc/images/plugin.png +0 -0
  56. data/doc/images/ruby.png +0 -0
  57. data/doc/images/tag_green.png +0 -0
  58. data/doc/images/wrench.png +0 -0
  59. data/doc/images/wrench_orange.png +0 -0
  60. data/doc/images/zoom.png +0 -0
  61. data/doc/index.html +312 -0
  62. data/doc/js/darkfish.js +116 -0
  63. data/doc/js/jquery.js +32 -0
  64. data/doc/js/quicksearch.js +114 -0
  65. data/doc/js/thickbox-compressed.js +10 -0
  66. data/doc/lib/caricature/clr/descriptor_rb.html +52 -0
  67. data/doc/lib/caricature/clr/isolation_rb.html +52 -0
  68. data/doc/lib/caricature/clr/isolator_rb.html +52 -0
  69. data/doc/lib/caricature/clr/messenger_rb.html +52 -0
  70. data/doc/lib/caricature/clr_rb.html +52 -0
  71. data/doc/lib/caricature/descriptor_rb.html +52 -0
  72. data/doc/lib/caricature/expectation_rb.html +52 -0
  73. data/doc/lib/caricature/isolation_rb.html +52 -0
  74. data/doc/lib/caricature/isolator_rb.html +52 -0
  75. data/doc/lib/caricature/messaging_rb.html +52 -0
  76. data/doc/lib/caricature/method_call_recorder_rb.html +52 -0
  77. data/doc/lib/caricature/verification_rb.html +52 -0
  78. data/doc/lib/caricature_rb.html +52 -0
  79. data/doc/lib/core_ext/array_rb.html +52 -0
  80. data/doc/lib/core_ext/class_rb.html +52 -0
  81. data/doc/lib/core_ext/core_ext_rb.html +52 -0
  82. data/doc/lib/core_ext/hash_rb.html +52 -0
  83. data/doc/lib/core_ext/module_rb.html +52 -0
  84. data/doc/lib/core_ext/object_rb.html +52 -0
  85. data/doc/lib/core_ext/string_rb.html +52 -0
  86. data/doc/lib/core_ext/system/string_rb.html +52 -0
  87. data/doc/lib/core_ext/system/type_rb.html +52 -0
  88. data/doc/rdoc.css +696 -0
  89. data/irb_init.rb +9 -0
  90. data/lib/bin/Workarounds.dll +0 -0
  91. data/lib/bin/Workarounds.pdb +0 -0
  92. data/lib/caricature/clr/descriptor.rb +55 -0
  93. data/lib/caricature/clr/isolation.rb +33 -0
  94. data/lib/caricature/clr/isolator.rb +112 -0
  95. data/lib/caricature/clr/messenger.rb +46 -0
  96. data/lib/caricature/clr.rb +6 -0
  97. data/lib/caricature/descriptor.rb +74 -0
  98. data/lib/caricature/expectation.rb +159 -0
  99. data/lib/caricature/isolation.rb +146 -0
  100. data/lib/caricature/isolator.rb +287 -0
  101. data/lib/caricature/messenger.rb +57 -0
  102. data/lib/caricature/method_call_recorder.rb +130 -0
  103. data/lib/caricature/verification.rb +43 -0
  104. data/lib/caricature.rb +11 -0
  105. data/lib/core_ext/array.rb +10 -0
  106. data/lib/core_ext/class.rb +15 -0
  107. data/lib/core_ext/core_ext.rb +8 -0
  108. data/lib/core_ext/hash.rb +13 -0
  109. data/lib/core_ext/module.rb +15 -0
  110. data/lib/core_ext/object.rb +19 -0
  111. data/lib/core_ext/string.rb +17 -0
  112. data/lib/core_ext/system/string.rb +21 -0
  113. data/lib/core_ext/system/type.rb +21 -0
  114. data/pkg/.gitignore +0 -0
  115. data/pkg/caricature-0.1.0.gem +0 -0
  116. data/spec/bacon_helper.rb +49 -3
  117. data/spec/bin/.gitignore +0 -0
  118. data/spec/core_ext_spec.rb +9 -0
  119. data/spec/descriptor_spec.rb +142 -0
  120. data/spec/expectation_spec.rb +11 -7
  121. data/spec/integration_spec.rb +94 -2
  122. data/spec/isolation_spec.rb +0 -42
  123. data/spec/isolator_spec.rb +72 -66
  124. data/spec/messaging_spec.rb +172 -0
  125. data/spec/method_call_spec.rb +21 -21
  126. data/spec/models/ClrModels.cs +185 -0
  127. data/spec/verification_spec.rb +1 -1
  128. data/workarounds/ReflectionHelper.cs +30 -0
  129. metadata +133 -2
@@ -0,0 +1,287 @@
1
+ require File.dirname(__FILE__) + '/messenger'
2
+ require File.dirname(__FILE__) + '/descriptor'
3
+
4
+ module Caricature
5
+
6
+ # Groups the methods for interception together
7
+ # this is a mix-in for the created isolations for classes
8
+ module Interception
9
+
10
+ # the class methods of this intercepting object
11
+ module ClassMethods
12
+
13
+ # the context of this isolation instance.
14
+ # this context takes care of responding to method calls etc.
15
+ def isolation_context
16
+ @___context___
17
+ end
18
+
19
+ # Replaces the call to the proxy with the one you create with this method.
20
+ # You can specify more specific criteria in the block to configure the expectation.
21
+ #
22
+ # Example:
23
+ #
24
+ # an_isolation.class.when_receiving(:a_method) do |method_call|
25
+ # method_call.with(3, "a").return(5)
26
+ # end
27
+ #
28
+ # is equivalent to:
29
+ #
30
+ # an_isolation.class.when_receiving(:a_method).with(3, "a").return(5)
31
+ #
32
+ # You will most likely use this method when you want your stubs to return something else than +nil+
33
+ # when they get called during the run of the test they are defined in.
34
+ def when_receiving(method_name, &block)
35
+ isolation_context.create_class_override method_name, &block
36
+ end
37
+
38
+ # Verifies whether the specified method has been called
39
+ # You can specify constraints in the block
40
+ #
41
+ # The most complex configuration you can make currently is one that is constrained by arguments.
42
+ # This is most likely to be extended in the future to allow for more complex verifications.
43
+ #
44
+ # Example:
45
+ #
46
+ # an_isolation.class.did_receive?(:a_method) do |method_call|
47
+ # method_call.with(3, "a")
48
+ # end.should.be.successful
49
+ #
50
+ # is equivalent to:
51
+ #
52
+ # an_isolation.class.did_receive?(:a_method).with(3, "a").should.be.successful
53
+ #
54
+ # You will probably be using this method only when you're interested in whether a method has been called
55
+ # during the course of the test you're running.
56
+ def did_receive?(method_name, &block)
57
+ isolation_context.class_verify method_name
58
+ end
59
+
60
+ end
61
+
62
+ # mixes in the class methods of this module when it gets included in a class.
63
+ def self.included(base)
64
+ base.extend ClassMethods
65
+ end
66
+
67
+ # the context of this isolation instance.
68
+ # this context takes care of responding to method calls etc.
69
+ def isolation_context
70
+ self.class.isolation_context
71
+ end
72
+
73
+ # Replaces the call to the proxy with the one you create with this method.
74
+ # You can specify more specific criteria in the block to configure the expectation.
75
+ #
76
+ # Example:
77
+ #
78
+ # an_isolation.when_receiving(:a_method) do |method_call|
79
+ # method_call.with(3, "a").return(5)
80
+ # end
81
+ #
82
+ # is equivalent to:
83
+ #
84
+ # an_isolation.when_receiving(:a_method).with(3, "a").return(5)
85
+ #
86
+ # You will most likely use this method when you want your stubs to return something else than +nil+
87
+ # when they get called during the run of the test they are defined in.
88
+ def when_receiving(method_name, &block)
89
+ isolation_context.create_override method_name, &block
90
+ end
91
+
92
+ # Replaces the call to the class of the proxy with the one you create with this method.
93
+ # You can specify more specific criteria in the block to configure the expectation.
94
+ #
95
+ # Example:
96
+ #
97
+ # an_isolation.when_class_receives(:a_method) do |method_call|
98
+ # method_call.with(3, "a").return(5)
99
+ # end
100
+ #
101
+ # is equivalent to:
102
+ #
103
+ # an_isolation.when_class_receives(:a_method).with(3, "a").return(5)
104
+ #
105
+ # You will most likely use this method when you want your stubs to return something else than +nil+
106
+ # when they get called during the run of the test they are defined in.
107
+ def when_class_receives(method_name, &block)
108
+ self.class.when_receiving method_name, &block
109
+ end
110
+
111
+ # Verifies whether the specified method has been called
112
+ # You can specify constraints in the block
113
+ #
114
+ # The most complex configuration you can make currently is one that is constrained by arguments.
115
+ # This is most likely to be extended in the future to allow for more complex verifications.
116
+ #
117
+ # Example:
118
+ #
119
+ # an_isolation.did_receive?(:a_method) do |method_call|
120
+ # method_call.with(3, "a")
121
+ # end.should.be.successful
122
+ #
123
+ # is equivalent to:
124
+ #
125
+ # an_isolation.did_receive?(:a_method).with(3, "a").should.be.successful
126
+ #
127
+ # You will probably be using this method only when you're interested in whether a method has been called
128
+ # during the course of the test you're running.
129
+ def did_receive?(method_name, &block)
130
+ isolation_context.verify method_name
131
+ end
132
+
133
+ # Verifies whether the specified class method has been called
134
+ # You can specify constraints in the block
135
+ #
136
+ # The most complex configuration you can make currently is one that is constrained by arguments.
137
+ # This is most likely to be extended in the future to allow for more complex verifications.
138
+ #
139
+ # Example:
140
+ #
141
+ # an_isolation.did_class_receive?(:a_method) do |method_call|
142
+ # method_call.with(3, "a")
143
+ # end.should.be.successful
144
+ #
145
+ # is equivalent to:
146
+ #
147
+ # an_isolation.did_class_receive?(:a_method).with(3, "a").should.be.successful
148
+ #
149
+ # You will probably be using this method only when you're interested in whether a method has been called
150
+ # during the course of the test you're running.
151
+ def did_class_receive?(method_name, &block)
152
+ self.class.did_receive?(method_name, &block)
153
+ end
154
+
155
+ end
156
+
157
+ # A base class for +Isolator+ objects
158
+ # to stick with the +Isolation+ nomenclature the strategies for creating isolations
159
+ # are called isolators.
160
+ # An isolator functions as a barrier between the code in your test and the
161
+ # underlying type/instance. It allows you to take control over the value
162
+ # that is returned from a specific method, if you want to pass the method call along to
163
+ # the underlying instance etc. It also contains the ability to verify if a method
164
+ # was called, with which arguments etc.
165
+ class Isolator
166
+
167
+ # holds the isolation created by this isolator
168
+ attr_reader :isolation
169
+
170
+ # holds the subject of this isolator
171
+ attr_reader :subject
172
+
173
+ # holds the descriptor for this type of object
174
+ attr_reader :descriptor
175
+
176
+ # creates a new instance of an isolator
177
+ def initialize(context)
178
+ @context = context
179
+ end
180
+
181
+ # builds up the isolation class instance
182
+ def build_isolation(klass, inst=nil)
183
+ pxy = create_isolation_for klass
184
+ @isolation = pxy.new
185
+ @subject = inst
186
+ initialize_messenger
187
+ end
188
+
189
+ # initializes the messaging strategy for the isolator
190
+ def initialize_messenger
191
+ raise NotImplementedError
192
+ end
193
+
194
+ # Creates the new class name for the isolation
195
+ def class_name(subj)
196
+ nm = subj.respond_to?(:class_eval) ? subj.demodulize : subj.class.demodulize
197
+ @class_name = "#{nm}#{System::Guid.new_guid.to_string('n')}"
198
+ @class_name
199
+ end
200
+
201
+ # Sets up the necessary instance variables for the isolation
202
+ def initialize_isolation(klass, context)
203
+ pxy = klass.new
204
+ pxy.instance_variable_set("@___context___", context)
205
+ pxy
206
+ end
207
+
208
+ class << self
209
+
210
+ # Creates the actual proxy object for the +subject+ and initializes it with a
211
+ # +recorder+ and +expectations+
212
+ # This is the actual isolation that will be used to in your tests.
213
+ # It implements all the methods of the +subject+ so as long as you're in Ruby
214
+ # and just need to isolate out some classes defined in a statically compiled language
215
+ # it should get you all the way there for public instance methods at this point.
216
+ # when you're going to isolation for usage within a statically compiled language type
217
+ # then you're bound to most of their rules. So you need to either isolate interfaces
218
+ # or mark the methods you want to isolate as virtual in your implementing classes.
219
+ def for(context)
220
+ context.recorder ||= MethodCallRecorder.new
221
+ context.expectations ||= Expectations.new
222
+ new(context)
223
+ end
224
+ end
225
+ end
226
+
227
+ # A proxy to Ruby objects that records method calls
228
+ # this implements all the instance methods that are defined on the class.
229
+ class RubyIsolator < Isolator
230
+
231
+ # implemented template method for creating Ruby isolations
232
+ def initialize(context)
233
+ super
234
+ klass = @context.subject.respond_to?(:class_eval) ? @context.subject : @context.subject.class
235
+ inst = @context.subject.respond_to?(:class_eval) ? @context.subject.new : @context.subject
236
+ @descriptor = RubyObjectDescriptor.new klass
237
+ build_isolation klass, inst
238
+ end
239
+
240
+ # initializes the messaging strategy for the isolator
241
+ def initialize_messenger
242
+ @context.messenger = RubyMessenger.new @context.expectations, @subject
243
+ end
244
+
245
+ # creates the ruby isolator for the specified subject
246
+ def create_isolation_for(subj)
247
+ imembers = @descriptor.instance_members
248
+ cmembers = @descriptor.class_members
249
+
250
+ klass = Object.const_set(class_name(subj), Class.new(subj))
251
+ klass.class_eval do
252
+
253
+ include Interception
254
+
255
+ # access to the proxied subject
256
+ def ___super___
257
+ isolation_context.instance
258
+ end
259
+
260
+ imembers.each do |mn|
261
+ mn = mn.name.to_s.to_sym
262
+ define_method mn do |*args|
263
+ b = nil
264
+ b = Proc.new { yield } if block_given?
265
+ isolation_context.send_message(mn, nil, *args, &b)
266
+ end
267
+ end
268
+
269
+ cmembers.each do |mn|
270
+ mn = mn.name.to_s.to_sym
271
+ define_cmethod mn do |*args|
272
+ b = nil
273
+ b = Proc.new { yield } if block_given?
274
+ isolation_context.send_class_message(mn, nil, *args, &b)
275
+ end
276
+ end
277
+
278
+
279
+ end
280
+
281
+ klass
282
+ end
283
+
284
+
285
+ end
286
+
287
+ end
@@ -0,0 +1,57 @@
1
+ module Caricature
2
+
3
+ # A base class to encapsulate method invocation
4
+ class Messenger
5
+
6
+ # the real instance of the isolated subject
7
+ # used to forward calls in partial mocks
8
+ attr_reader :instance
9
+
10
+ # the expecations that have been set for the isolation
11
+ attr_reader :expectations
12
+
13
+ # creates a new instance of this messaging strategy
14
+ def initialize(expectations, instance=nil)
15
+ @instance, @expectations = instance, expectations
16
+ end
17
+
18
+ # deliver the message to the receiving isolation
19
+ def deliver(method_name, return_type, *args, &b)
20
+ internal_deliver(:instance, method_name, return_type, *args, &b)
21
+ end
22
+
23
+ # deliver the message to class of the receiving isolation
24
+ def deliver_to_class(method_name, return_type, *args, &b)
25
+ internal_deliver(:class, method_name, return_type, *args, &b)
26
+ end
27
+
28
+ protected
29
+
30
+ # template method for looking up the expectation and/or returning a value
31
+ def internal_deliver(mode, method_name, return_type, *args, &b)
32
+ raise NotImplementedError.new("Override in an implementing class")
33
+ end
34
+
35
+ end
36
+
37
+ # Encapsulates sending messages to Ruby isolations
38
+ class RubyMessenger < Messenger
39
+
40
+ protected
41
+
42
+ # implementation of the template method for looking up the expectation and/or returning a value
43
+ def internal_deliver(mode, method_name, return_type, *args, &b)
44
+ exp = expectations.find(method_name, mode, *args)
45
+ if exp
46
+ res = instance.__send__(method_name, *args, &b) if exp.super_before?
47
+ res = exp.execute *args
48
+ res = instance.__send__(method_name, *args, &b) if !exp.super_before? and exp.call_super?
49
+ res
50
+ else
51
+ nil
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,130 @@
1
+ module Caricature
2
+
3
+ # A recording of an argument variation.
4
+ # Every time a method is called with different arguments
5
+ # the method call recorder will create an ArgumentVariation
6
+ # these variations are used later in the assertion
7
+ # to verify against specific argument values
8
+ class ArgumentRecording
9
+
10
+ # contains the arguments of the recorded parameters
11
+ attr_accessor :args
12
+
13
+ # contains the block for the recorded parameters
14
+ attr_accessor :block
15
+
16
+ # the number of the call that has the following parameters
17
+ attr_accessor :call_number
18
+
19
+ # initializes a new instance of an argument recording.
20
+ # configures it with 1 call count and the args as an +Array+
21
+ def initialize(args=[], call_number=1, block=nil)
22
+ @args = args
23
+ @block = block
24
+ @call_number = call_number
25
+ end
26
+
27
+ # compares one argument variation to another.
28
+ # Also takes an array as an argument
29
+ def ==(other)
30
+ other = self.class.new(other) if other.respond_to?(:each)
31
+ return true if other.args.first == :any
32
+ other.args == args
33
+ end
34
+ end
35
+
36
+ # A recording that represents a method call
37
+ # it contains argument variations that can be matched too
38
+ class MethodCallRecording
39
+
40
+ # gets or sets the method name
41
+ attr_accessor :method_name
42
+
43
+ # gets or sets the amount of times the method was called
44
+ attr_accessor :count
45
+
46
+ # gets or sets the arguments for this method call
47
+ attr_accessor :args
48
+
49
+ # gets or sets the block for this method call
50
+ attr_accessor :block
51
+
52
+ # Initializes a new instance of a method call recording
53
+ # every time a method gets called in an isolated object
54
+ # this gets stored in the method call recorder
55
+ # It expects a +method_name+ at the very least.
56
+ def initialize(method_name, count=0)
57
+ @method_name = method_name
58
+ @count = count
59
+ @variations = []
60
+ end
61
+
62
+ # add args
63
+ def args
64
+ @variations
65
+ end
66
+
67
+ # indicates if it has an argument variation
68
+ def has_argument_variations?
69
+ @variations.size > 1
70
+ end
71
+
72
+ # add an argument variation
73
+ def add_argument_variation(args, block)
74
+ variation = find_argument_variations args
75
+ @variations << ArgumentRecording.new(args, @variations.size+1, block) if variation == []
76
+ end
77
+
78
+ # finds an argument variation that matches the provided +args+
79
+ def find_argument_variations(args)
80
+ return @variations if args.first == :any
81
+ @variations.select { |ar| ar.args == args }
82
+ end
83
+ end
84
+
85
+ # The recorder that will collect method calls and provides an interface for finding those recordings
86
+ class MethodCallRecorder
87
+
88
+ # gets the collection of method calls. This is a hash with the method name as key
89
+ attr_reader :method_calls
90
+
91
+
92
+ # Initializes a new instance of a method call recorder
93
+ # every time a method gets called in an isolated object
94
+ # this gets stored in the method call recorder
95
+ def initialize
96
+ @method_calls = {:instance => {}, :class => {} }
97
+ end
98
+
99
+ # records a method call or increments the count of how many times this method was called.
100
+ def record_call(method_name, mode=:instance, *args, &block)
101
+ mn_sym = method_name.to_s.to_sym
102
+ method_calls[mode][mn_sym] ||= MethodCallRecording.new method_name
103
+ mc = method_calls[mode][mn_sym]
104
+ mc.count += 1
105
+ mc.add_argument_variation args, block
106
+ end
107
+
108
+ # returns whether the method was actually called with the specified constraints
109
+ def was_called?(method_name, mode=:instance, *args)
110
+ mc = method_calls[mode][method_name.to_s.to_sym]
111
+ if mc
112
+ return mc.find_argument_variations(args).first == args
113
+ else
114
+ return !!mc
115
+ end
116
+ end
117
+
118
+ # # indexer that gives you access to the recorded method by method name
119
+ # def [](method_name)
120
+ # method_calls[:instance][method_name.to_s.to_sym]
121
+ # end
122
+
123
+ # returns the number of different methods that has been recorderd
124
+ def size
125
+ @method_calls.size
126
+ end
127
+ end
128
+
129
+
130
+ end
@@ -0,0 +1,43 @@
1
+ module Caricature
2
+
3
+ # Describes a verification of a method call.
4
+ # This corresponds kind of to an assertion
5
+ class Verification
6
+
7
+ # Initializes a new instance of a +Verification+
8
+ def initialize(method_name, recorder, mode=:instance)
9
+ @method_name, @args, @any_args, @recorder, @mode = method_name, [], true, recorder, mode
10
+ end
11
+
12
+ # indicates whether this verification can be for any arguments
13
+ def any_args?
14
+ @any_args
15
+ end
16
+
17
+ # constrain this verification to the provided arguments
18
+ def with(*args)
19
+ @any_args = false unless args.first == :any
20
+ @args = args
21
+ self
22
+ end
23
+
24
+ # allow any arguments ignore the argument constraint
25
+ def allow_any_arguments
26
+ @any_args = true
27
+ self
28
+ end
29
+
30
+ # figure out if this argument variation matches the provided args.
31
+ def matches?(method_name, *args)
32
+ @method_name == method_name and any_args? or @args == args
33
+ end
34
+
35
+ # indicate that this method verification is successful
36
+ def successful?
37
+ a = any_args? ? [:any] : @args
38
+ @recorder.was_called?(@method_name, @mode, *a)
39
+ end
40
+
41
+ end
42
+
43
+ end
data/lib/caricature.rb ADDED
@@ -0,0 +1,11 @@
1
+ $: << File.dirname(__FILE__) + "/bin"
2
+ #module Caricature
3
+ #
4
+ # module Interception
5
+ #
6
+ # end
7
+ #
8
+ #end
9
+
10
+ require File.dirname(__FILE__) + '/core_ext/core_ext'
11
+ require File.dirname(__FILE__) + '/caricature/isolation'
@@ -0,0 +1,10 @@
1
+ class Array
2
+
3
+ # Converts an array of values to a hash.
4
+ # the even indexes are the hash keys
5
+ # the odd indexes are the hash values
6
+ def to_h
7
+ h = Hash[*self]
8
+ h.symbolize_keys!
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ class Class
2
+
3
+ # removes all the modules from this class name
4
+ def demodulize
5
+ self.to_s.gsub(/^.*::/, '')
6
+ end
7
+
8
+ # indicates whether this type has a CLR type in its ancestors
9
+ def is_clr_type?
10
+ !self.to_clr_type.nil? ||
11
+ self.included_modules.any? {|mod| !mod.to_clr_type.nil? } ||
12
+ self.ancestors.reject {|mod| mod == Object }.any? { |mod| !mod.to_clr_type.nil? }
13
+ end
14
+
15
+ end
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + '/string'
2
+ require File.dirname(__FILE__) + '/system/string'
3
+ require File.dirname(__FILE__) + '/system/type'
4
+ require File.dirname(__FILE__) + '/class'
5
+ require File.dirname(__FILE__) + '/module'
6
+ require File.dirname(__FILE__) + '/object'
7
+ require File.dirname(__FILE__) + '/array'
8
+ require File.dirname(__FILE__) + '/hash'
@@ -0,0 +1,13 @@
1
+ class Hash
2
+
3
+ # Destructively convert all keys which respond_to?(:to_sym) to symbols. Works recursively if given nested hashes.
4
+ def symbolize_keys!
5
+ each do |k,v|
6
+ sym = k.respond_to?(:to_sym) ? k.to_sym : k
7
+ self[sym] = Hash === v ? v.symbolize_keys! : v
8
+ delete(k) unless k == sym
9
+ end
10
+ self
11
+ end
12
+
13
+ end
@@ -0,0 +1,15 @@
1
+ class Module
2
+
3
+ # Removes all but the containing modules from this module's name
4
+ def demodulize
5
+ self.to_s.gsub(/^.*::/, '')
6
+ end
7
+
8
+ # indicates whether this type has a CLR type in its ancestors
9
+ def is_clr_type?
10
+ !self.to_clr_type.nil? ||
11
+ self.included_modules.any? {|mod| !mod.to_clr_type.nil? } ||
12
+ self.ancestors.any? { |mod| !mod.to_clr_type.nil? }
13
+ end
14
+
15
+ end
@@ -0,0 +1,19 @@
1
+ class Object
2
+
3
+ # returns whether this object is a clr_type.
4
+ # if it has a CLR type in one of its ancestors
5
+ def is_clr_type?
6
+ self.class.is_clr_type?
7
+ end
8
+
9
+ # returns the clr type of this object if any
10
+ def to_clr_type
11
+ self.class.to_clr_type
12
+ end
13
+
14
+ # defines a class method on an object
15
+ def define_cmethod(name, &blk)
16
+ (class << self; self; end).instance_eval { define_method name, &blk }
17
+ end
18
+
19
+ end
@@ -0,0 +1,17 @@
1
+ class String
2
+
3
+ # converts a camel cased word to an underscored word
4
+ def underscore
5
+ self.gsub(/::/, '/').
6
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
7
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
8
+ tr("-", "_").
9
+ downcase
10
+ end
11
+
12
+ # Gets the constant when it is defined that corresponds to this string
13
+ def classify
14
+ Object.const_get self
15
+ end
16
+
17
+ end
@@ -0,0 +1,21 @@
1
+ module System
2
+
3
+ class String
4
+
5
+ # converts a camel cased word to an underscored word
6
+ def underscore
7
+ self.gsub(/::/, '/').
8
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
9
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
10
+ tr("-", "_").
11
+ downcase
12
+ end
13
+
14
+ # Gets the constant when it is defined that corresponds to this string
15
+ def classify
16
+ Object.const_get self
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ module System
2
+
3
+ class Type
4
+
5
+ # collects all the methods defined on an interface and its parents
6
+ def collect_interface_methods
7
+ iface_methods = []
8
+ iface_methods += self.get_interfaces.collect { |t| t.collect_interface_methods }
9
+ self.get_methods + iface_methods.flatten
10
+ end
11
+
12
+ # collects the properties defined on an interface an its parents
13
+ def collect_interface_properties
14
+ iface_properties = []
15
+ iface_properties += self.get_interfaces.collect { |t| t.collect_interface_properties }
16
+ self.get_properties + iface_properties.flatten
17
+ end
18
+
19
+ end
20
+
21
+ end
data/pkg/.gitignore ADDED
File without changes
Binary file