casting 0.6.7 → 0.6.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/saturnflyer/casting.png?branch=master)](https://travis-ci.org/saturnflyer/casting)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/saturnflyer/casting.png)](https://codeclimate.com/github/saturnflyer/casting)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/saturnflyer/casting/badge.png)](https://coveralls.io/r/saturnflyer/casting)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/casting.png)](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
|