casting 0.6.7 → 0.6.8
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.
- checksums.yaml +4 -4
- data/LICENSE +22 -0
- data/README.md +331 -0
- data/Rakefile +12 -0
- data/lib/casting/super_delegate.rb +68 -0
- data/lib/casting/version.rb +1 -1
- data/test/module_cleanup_test.rb +43 -0
- data/test/super_test.rb +32 -0
- metadata +9 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02fe7c29c8da27adba6036307ab658548bf6a20a
|
4
|
+
data.tar.gz: 1b674c20260d1e89830e088f0db5fe2dbee43639
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c86a535a9ae96e3e6b1034488cda5b487c76e51a028b7fce0f907ce96b580adb46d748f0b1a8231fc287b9a164f3d71171184d80776c7bba571dca60e0b59c36
|
7
|
+
data.tar.gz: 031bfc7f0989891cb12c48097e5990bbae8d95cb2e348e8b652fa4b84f652bca2b0cfab07ea34ec49c5506cc0ac45d96e6891ace776b52cf4f35feac1593797c
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012-2014 Jim Gay
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,331 @@
|
|
1
|
+
# Casting
|
2
|
+
|
3
|
+
[](https://travis-ci.org/saturnflyer/casting)
|
4
|
+
[](https://codeclimate.com/github/saturnflyer/casting)
|
5
|
+
[](https://coveralls.io/r/saturnflyer/casting)
|
6
|
+
[](http://badge.fury.io/rb/casting)
|
7
|
+
|
8
|
+
## Add behavior to your objects without using extend
|
9
|
+
Do it for the life of the object or only for the life of a block of code.
|
10
|
+
|
11
|
+
Casting gives you real delegation that flattens your object structure compared to libraries
|
12
|
+
like Delegate or Forwardable. With casting, you can implement your own decorators that
|
13
|
+
will be so much simpler than using wrappers.
|
14
|
+
|
15
|
+
Here's a quick example that you might try in a Rails project:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# implement a module that contains information for the request response
|
19
|
+
# and apply it to an object in your system.
|
20
|
+
def show
|
21
|
+
respond_with user.cast_as(UserRepresenter)
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
To use proper delegation, your approach should preserve `self` as a reference
|
26
|
+
to the original object receiving a method. When the object receiving the forwarded
|
27
|
+
message has its own and separate notion of `self`, you're working with a wrapper (also called
|
28
|
+
consultation) and not using delegation.
|
29
|
+
|
30
|
+
The Ruby standard library includes a library called "delegate", but it is
|
31
|
+
a consultation approach. With that "delegate", all messages are forwarded to
|
32
|
+
another object, but the attendant object maintains its own identity.
|
33
|
+
|
34
|
+
With Casting, your defined methods may reference `self` and during
|
35
|
+
execution it will refer to the original client object.
|
36
|
+
|
37
|
+
Casting was created while exploring ideas for [cleaning up ruby programs](http://clean-ruby.com).
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
To use Casting, you must first extend an object as the delegation client:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
actor = Object.new
|
45
|
+
actor.extend(Casting::Client)
|
46
|
+
```
|
47
|
+
|
48
|
+
Or you may include the module in a particular class:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
class Actor
|
52
|
+
include Casting::Client
|
53
|
+
end
|
54
|
+
actor = Actor.new
|
55
|
+
```
|
56
|
+
|
57
|
+
Your objects will have a few additional methods: `delegation`, `cast`, and if you do not *already* have it defined (from another library, for example): `delegate`. The `delegate` method is aliased to `cast`.
|
58
|
+
|
59
|
+
Then you may delegate a method to an attendant object:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
actor.delegate(:hello_world, other_actor)
|
63
|
+
```
|
64
|
+
|
65
|
+
Or you may create an object to manage the delegation of methods to an attendant object:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
actor.delegation(:hello_world).to(other_actor).call
|
69
|
+
```
|
70
|
+
|
71
|
+
You may also delegate methods without an explicit attendant instance, but provide
|
72
|
+
a module containing the behavior you need to use:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
actor.delegate(:hello_world, GreetingModule)
|
76
|
+
# or
|
77
|
+
actor.delegation(:hello_world).to(GreetingModule).call
|
78
|
+
```
|
79
|
+
|
80
|
+
Pass arguments to your delegated method:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
actor.delegate(:verbose_method, another_actor, arg1, arg2)
|
84
|
+
|
85
|
+
actor.delegation(:verbose_method).to(another_actor).with(arg1, arg2).call
|
86
|
+
|
87
|
+
actor.delegation(:verbose_method).to(another_actor).call(arg1, arg2)
|
88
|
+
```
|
89
|
+
|
90
|
+
_That's great, but why do I need to do these extra steps? I just want to run the method._
|
91
|
+
|
92
|
+
Casting gives you the option to do what you want. You can run just a single method once, or alter your object to always delegate. Even better, you can alter your object to delegate temporarily...
|
93
|
+
|
94
|
+
## Temporary Behavior
|
95
|
+
|
96
|
+
Casting also provides an option to temporarily apply behaviors to an object.
|
97
|
+
|
98
|
+
Once your class or object is a `Casting::Client` you may send the `delegate_missing_methods` message to it and your object will use `method_missing` to delegate methods to a stored attendant.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
actor.hello_world #=> NoMethodError
|
102
|
+
|
103
|
+
Casting.delegating(actor => GreetingModule) do
|
104
|
+
actor.hello_world #=> output the value / perform the method
|
105
|
+
end
|
106
|
+
|
107
|
+
actor.hello_world #=> NoMethodError
|
108
|
+
```
|
109
|
+
|
110
|
+
The use of `method_missing` is opt-in. If you don't want that mucking up your method calls, just don't tell it to `delegate_missing_methods`.
|
111
|
+
|
112
|
+
Before the block is run in `Casting.delegating`, a collection of delegate objects is set on the object to the provided attendant. Then the block yields, and an `ensure` block cleans up the stored attendant.
|
113
|
+
|
114
|
+
This allows you to nest your `delegating` blocks as well:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
actor.hello_world #=> NoMethodError
|
118
|
+
|
119
|
+
Casting.delegating(actor => GreetingModule) do
|
120
|
+
actor.hello_world #=> output the value / perform the method
|
121
|
+
|
122
|
+
Casting.delegating(actor => OtherModule) do
|
123
|
+
actor.hello_world #=> still works!
|
124
|
+
actor.other_method # values/operations from the OtherModule
|
125
|
+
end
|
126
|
+
|
127
|
+
actor.other_method #=> NoMethodError
|
128
|
+
actor.hello_world #=> still works!
|
129
|
+
end
|
130
|
+
|
131
|
+
actor.hello_world #=> NoMethodError
|
132
|
+
```
|
133
|
+
|
134
|
+
Currently, by using `delegate_missing_methods` you forever mark that object or class to use `method_missing`. This may change in the future.
|
135
|
+
|
136
|
+
### Manual Delegate Management
|
137
|
+
|
138
|
+
If you'd rather not wrap things in the `delegating` block, you can control the delegation yourself.
|
139
|
+
For example, you can `cast_as` and `uncast` an object with a given module:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
actor.cast_as(GreetingModule)
|
143
|
+
actor.hello_world # all subsequent calls to this method run from the module
|
144
|
+
actor.uncast # manually cleanup the delegate
|
145
|
+
actor.hello_world # => NoMethodError
|
146
|
+
```
|
147
|
+
|
148
|
+
These methods are only defined on your `Casting::Client` object when you tell it to `delegate_missing_methods`. Because these require `method_missing`, they do not exist until you opt-in.
|
149
|
+
|
150
|
+
## I have a Rails app, how does this help me?
|
151
|
+
|
152
|
+
Well, a common use for this behavior would be in using decorators.
|
153
|
+
|
154
|
+
When using a wrapper, your forms can behave unexpectedly
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
class UsersController
|
158
|
+
def edit
|
159
|
+
@user = UserDecorator.new(User.find(params[:id]))
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
<%= form_for(@user) do |f| %> #=> <form action="/user_decorators/1">
|
164
|
+
```
|
165
|
+
|
166
|
+
Ruby allows you to hack this by defining the `class` method:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
class UserDecorator
|
170
|
+
def class
|
171
|
+
User
|
172
|
+
end
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
176
|
+
That would solve the problem, and it works! But having an object report that
|
177
|
+
its class is something other than what it actually is can be confusing
|
178
|
+
when you're debugging.
|
179
|
+
|
180
|
+
Instead, you could cast the object as a module and your form will generate properly:
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
class UsersController
|
184
|
+
def edit
|
185
|
+
@user = User.find(params[:id]).cast_as(UserDecorator) # as a module
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
<%= form_for(@user) do |f| %> #=> <form action="/users/1">
|
190
|
+
```
|
191
|
+
|
192
|
+
This keeps your code focused on the object you care about.
|
193
|
+
|
194
|
+
## Oh, my! Could this be used to add behavior like refinements?
|
195
|
+
|
196
|
+
You can apply methods from a delegate to all instances of a class.
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
person.hello_world #=> NoMethodError
|
200
|
+
|
201
|
+
Casting.delegating(Person => GreetingModule) do
|
202
|
+
person.hello_world #=> output the value / perform the method
|
203
|
+
end
|
204
|
+
|
205
|
+
person.hello_world #=> NoMethodError
|
206
|
+
```
|
207
|
+
|
208
|
+
By default, the `delegate_missing_methods` method will set delegates on instances so you'll need to opt-in for this.
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
class Person
|
212
|
+
include Casting::Client
|
213
|
+
delegate_missing_methods :class
|
214
|
+
end
|
215
|
+
```
|
216
|
+
|
217
|
+
_But what happens when you have method clashes or want a specific instance to behave differently?_
|
218
|
+
|
219
|
+
You can have your objects look to their instance delegates, their class delegates, or in a particular order:
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
class Person
|
223
|
+
include Casting::Client
|
224
|
+
# default delegation to instances
|
225
|
+
delegate_missing_methods
|
226
|
+
|
227
|
+
# delegate methods to those defined on the class
|
228
|
+
delegate_missing_methods :class
|
229
|
+
|
230
|
+
# delegate methods to those defined on the class, then those defined on the instance
|
231
|
+
delegate_missing_methods :class, :instance
|
232
|
+
|
233
|
+
# delegate methods to those defined on the instance, then those defined on the class
|
234
|
+
delegate_missing_methods :instance, :class
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
## What's happening when I use this?
|
239
|
+
|
240
|
+
Ruby allows you to access methods as objects and pass them around just like any other object.
|
241
|
+
|
242
|
+
For example, if you want a method from a class you may do this:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
class Person
|
246
|
+
def hello
|
247
|
+
"hello"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
Person.new.method(:hello).unbind #=> #<UnboundMethod: Person#hello>
|
251
|
+
# or
|
252
|
+
Person.instance_method(:hello) #=> #<UnboundMethod: Person#hello>
|
253
|
+
```
|
254
|
+
|
255
|
+
But if you attempt to use that `UnboundMethod` on an object that is not a `Person` you'll get
|
256
|
+
an error about a type mismatch.
|
257
|
+
|
258
|
+
Casting will bind an unbound method to a client object and execute the method as though it is
|
259
|
+
defined on the client object. Any reference to `self` from the method block will refer to the
|
260
|
+
client object.
|
261
|
+
|
262
|
+
This behavior is different in Ruby 1.9 vs. 2.x.
|
263
|
+
|
264
|
+
According to [http://rubyspec.org](http://rubyspec.org) the behavior in MRI in 1.9 that allows this to happen is incorrect. In MRI (and JRuby) 1.9 you may unbind methods from an object that has been extended with a module, and bind them to another object of the same type that has *not* been extended with that module.
|
265
|
+
|
266
|
+
Casting uses this as a way to trick the interpreter into using the method where we want it and avoid forever extending the object of concern.
|
267
|
+
|
268
|
+
This changed in Ruby 2.0 and does not work. What does work (and is so much better) in 2.0 is that you may take any method from a module and apply it to any object. This means that Casting doesn't have to perform any tricks to temporarily apply behavior to an object.
|
269
|
+
|
270
|
+
For example, this fails in 1.9, but works in 2.0:
|
271
|
+
|
272
|
+
```ruby
|
273
|
+
GreetingModule.instance_method(:hello_world).bind(actor).call
|
274
|
+
```
|
275
|
+
|
276
|
+
Casting provides a convenience for doing this.
|
277
|
+
|
278
|
+
## What if my modules create instance variables on the object? Can I clean them up?
|
279
|
+
|
280
|
+
Yup.
|
281
|
+
|
282
|
+
If you need to set some variables so that your module can access them, it's as easy as defining `cast_object` and `uncast_object` on your module. Here's an example:
|
283
|
+
|
284
|
+
```ruby
|
285
|
+
module Special
|
286
|
+
def self.cast_object(obj)
|
287
|
+
obj.instance_variable_set(:@special_value, 'this is special!')
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.uncast_object(obj)
|
291
|
+
obj.remove_instance_variable(:@special_value)
|
292
|
+
end
|
293
|
+
|
294
|
+
def special_behavior
|
295
|
+
"#{self.name} thinks... #{@special_value}"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
object.cast_as(Special)
|
300
|
+
object.special_method
|
301
|
+
object.uncast
|
302
|
+
# object no longer has the @special_value instance variable
|
303
|
+
```
|
304
|
+
|
305
|
+
You'll be able to leave your objects as if they were never touched by the module where you defined your behavior.
|
306
|
+
|
307
|
+
## Installation
|
308
|
+
|
309
|
+
If you are using Bundler, add this line to your application's Gemfile:
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
gem 'casting'
|
313
|
+
```
|
314
|
+
|
315
|
+
And then execute:
|
316
|
+
|
317
|
+
$ bundle
|
318
|
+
|
319
|
+
Or install it yourself as:
|
320
|
+
|
321
|
+
$ gem install casting
|
322
|
+
|
323
|
+
## Contributing
|
324
|
+
|
325
|
+
1. Fork it
|
326
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
327
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
328
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
329
|
+
5. Create new Pull Request
|
330
|
+
|
331
|
+
Built by Jim Gay at [Saturn Flyer](http://www.saturnflyer.com)
|
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module Casting
|
2
|
+
module SuperDelegate
|
3
|
+
|
4
|
+
# Call the method of the same name defined in the next delegate stored in your object
|
5
|
+
#
|
6
|
+
# Because Casting creates an alternative method lookup path using a collection of delegates,
|
7
|
+
# you may use `super_delegate` to work like `super`.
|
8
|
+
#
|
9
|
+
# If you use this feature, be sure that you have created a delegate collection which does
|
10
|
+
# have the method you need or you'll see a NoMethodError.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
#
|
14
|
+
# module Greeter
|
15
|
+
# def greet
|
16
|
+
# "Hello"
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# module FormalGreeter
|
21
|
+
# include Casting::Super
|
22
|
+
#
|
23
|
+
# def greet
|
24
|
+
# "#{super_delegate}, how do you do?"
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# some_object.cast_as(Greeter, FormalGreeter)
|
29
|
+
# some_object.greet #=> 'Hello, how do you do?'
|
30
|
+
#
|
31
|
+
def super_delegate(*args, &block)
|
32
|
+
method_name = name_of_calling_method(caller)
|
33
|
+
owner = args.first || method_delegate(method_name)
|
34
|
+
|
35
|
+
super_delegate_method = unbound_method_from_next_delegate(method_name, owner)
|
36
|
+
|
37
|
+
if super_delegate_method.arity == 0
|
38
|
+
super_delegate_method.bind(self).call
|
39
|
+
else
|
40
|
+
super_delegate_method.bind(self).call(*args, &block)
|
41
|
+
end
|
42
|
+
rescue NameError
|
43
|
+
raise NoMethodError.new("super_delegate: no delegate method `#{method_name}' for #{self.inspect} from #{owner}")
|
44
|
+
end
|
45
|
+
|
46
|
+
def unbound_method_from_next_delegate(method_name, *skipped)
|
47
|
+
method_delegate_skipping(method_name, *skipped).instance_method(method_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_delegate_skipping(meth, skipped)
|
51
|
+
skipped_index = __delegates__.index(skipped)
|
52
|
+
__delegates__.find{|attendant|
|
53
|
+
attendant_methods(attendant).include?(meth) &&
|
54
|
+
skipped_index < __delegates__.index(attendant)
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def name_of_calling_method(call_stack)
|
59
|
+
call_stack.reject{|line|
|
60
|
+
line.to_s =~ casting_library_matcher
|
61
|
+
}.first.split('`').last.sub("'","").to_sym
|
62
|
+
end
|
63
|
+
|
64
|
+
def casting_library_matcher
|
65
|
+
Regexp.new(Dir.pwd.to_s + '/lib')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/casting/version.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Cleaner
|
4
|
+
def self.uncast_object(object)
|
5
|
+
object.send(:remove_instance_variable, :@cleaner_message)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.cast_object(object)
|
9
|
+
object.instance_variable_set(:@cleaner_message, "#{object.name} will be cleaned up")
|
10
|
+
end
|
11
|
+
|
12
|
+
def cleaner_message
|
13
|
+
@cleaner_message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class CleanupPerson
|
18
|
+
include Casting::Client
|
19
|
+
delegate_missing_methods
|
20
|
+
attr_accessor :name
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'modules with setup tasks' do
|
24
|
+
it 'allows modules to setup an object when cast_as' do
|
25
|
+
jim = CleanupPerson.new
|
26
|
+
jim.name = 'Jim'
|
27
|
+
jim.cast_as(Cleaner)
|
28
|
+
assert_equal "Jim will be cleaned up", jim.cleaner_message
|
29
|
+
assert_equal "Jim will be cleaned up", jim.instance_variable_get(:@cleaner_message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'modules with cleanup tasks' do
|
34
|
+
it 'allows modules to cleanup their required attributes when uncast' do
|
35
|
+
jim = CleanupPerson.new
|
36
|
+
jim.name = 'Jim'
|
37
|
+
jim.cast_as(Cleaner)
|
38
|
+
assert_equal "Jim will be cleaned up", jim.cleaner_message
|
39
|
+
assert_equal "Jim will be cleaned up", jim.instance_variable_get(:@cleaner_message)
|
40
|
+
jim.uncast
|
41
|
+
refute jim.instance_variable_defined?(:@cleaner_message)
|
42
|
+
end
|
43
|
+
end
|
data/test/super_test.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module AnyWay
|
4
|
+
def which_way
|
5
|
+
"any way"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module ThisWay
|
10
|
+
include Casting::SuperDelegate
|
11
|
+
def which_way
|
12
|
+
"this way or #{super_delegate(ThisWay)}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ThatWay
|
17
|
+
include Casting::SuperDelegate
|
18
|
+
def which_way
|
19
|
+
"#{ super_delegate } and that way!"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Casting, 'modules using delegate_super' do
|
24
|
+
it 'call the method from the next delegate with the same arguments' do
|
25
|
+
skip 'extending objects not used in this version of Ruby' unless test_rebinding_methods?
|
26
|
+
client = TestPerson.new.extend(Casting::Client)
|
27
|
+
client.delegate_missing_methods
|
28
|
+
client.cast_as(AnyWay, ThisWay, ThatWay)
|
29
|
+
|
30
|
+
assert_equal 'this way or any way and that way!', client.which_way
|
31
|
+
end
|
32
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: casting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Gay
|
@@ -27,7 +27,11 @@ files:
|
|
27
27
|
- lib/casting/missing_method_client.rb
|
28
28
|
- lib/casting/missing_method_client_class.rb
|
29
29
|
- lib/casting/prepared_delegation.rb
|
30
|
+
- lib/casting/super_delegate.rb
|
30
31
|
- lib/casting/version.rb
|
32
|
+
- LICENSE
|
33
|
+
- Rakefile
|
34
|
+
- README.md
|
31
35
|
- test/test_helper.rb
|
32
36
|
- test/casting_19_test.rb
|
33
37
|
- test/casting_20_test.rb
|
@@ -37,6 +41,8 @@ files:
|
|
37
41
|
- test/delegation_test.rb
|
38
42
|
- test/method_consolidator_test.rb
|
39
43
|
- test/missing_method_client_test.rb
|
44
|
+
- test/module_cleanup_test.rb
|
45
|
+
- test/super_test.rb
|
40
46
|
homepage: http://github.com/saturnflyer/casting
|
41
47
|
licenses:
|
42
48
|
- MIT
|
@@ -71,3 +77,5 @@ test_files:
|
|
71
77
|
- test/delegation_test.rb
|
72
78
|
- test/method_consolidator_test.rb
|
73
79
|
- test/missing_method_client_test.rb
|
80
|
+
- test/module_cleanup_test.rb
|
81
|
+
- test/super_test.rb
|