casting 0.7.1 → 0.7.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b2c87cd8917d7140a16d55d487f4f0999ee44824
4
- data.tar.gz: 2ffb23af2a79836b0705efe5aa8ac00df0144881
3
+ metadata.gz: c87234df3ca2237a6d2e9d0d6de0f4beb8808cae
4
+ data.tar.gz: 114ccf9e9984a2323288b66982465ef7068a4dd0
5
5
  SHA512:
6
- metadata.gz: 82e5c33d84c41df11ead6966456bd8b42d0f665c0ba50345ba9b5fa3241dd4b42eaf74a9cd6c08b6212007b7ca1d009f8fe4a6c41a76a1a81ace87e2800be759
7
- data.tar.gz: 502e4254feb758ddff742e3296eed05282b7690d5dda8ab530475da871603db0f3926a31150edcc4140120035ac1f06e059c000b8dbff4eda9337fa81a132bea
6
+ metadata.gz: cc11494446dad4f1b1cd367d9fbd485ad78cf961884348344d076ff9456e1e8235af7be0d8547c1db84c0f953d79428da99d1a649702aa61d7b397d00b776fb9
7
+ data.tar.gz: e3d49bea1aaa35a9c08220cd3c07407fcf34657cdd02934ea2f9bd37adb999e3130e37690eebd21b44c884e5a542381b135f207eaaffe3919583877bee70fee4
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/saturnflyer/casting.png?branch=master)](https://travis-ci.org/saturnflyer/casting)
4
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)
5
+ [![Test Coverage](https://codeclimate.com/github/saturnflyer/casting/badges/coverage.svg)](https://codeclimate.com/github/saturnflyer/casting/coverage)
6
6
  [![Gem Version](https://badge.fury.io/rb/casting.png)](http://badge.fury.io/rb/casting)
7
7
 
8
8
  ## Add behavior to your objects without using extend
@@ -18,7 +18,7 @@ Here's a quick example that you might try in a Rails project:
18
18
  # implement a module that contains information for the request response
19
19
  # and apply it to an object in your system.
20
20
  def show
21
- respond_with user.cast_as(UserRepresenter)
21
+ @user = user.cast_as(UserRepresenter)
22
22
  end
23
23
  ```
24
24
 
@@ -293,22 +293,14 @@ Person.instance_method(:hello) #=> #<UnboundMethod: Person#hello>
293
293
  But if you attempt to use that `UnboundMethod` on an object that is not a `Person` you'll get
294
294
  an error about a type mismatch.
295
295
 
296
- Casting will bind an unbound method to a client object and execute the method as though it is
296
+ Casting will bind an UnboundMethod method to a client object and execute the method as though it is
297
297
  defined on the client object. Any reference to `self` from the method block will refer to the
298
298
  client object.
299
299
 
300
- This behavior is different in Ruby 1.9 vs. 2.x.
301
-
302
- 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.
303
-
304
- 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.
305
-
306
- 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.
307
-
308
- For example, this fails in 1.9, but works in 2.0:
300
+ Rather than define methods on classes, you may take any method from a module and apply it to any object regardless of its class.
309
301
 
310
302
  ```ruby
311
- GreetingModule.instance_method(:hello_world).bind(actor).call
303
+ GreetingModule.instance_method(:hello).bind(actor).call
312
304
  ```
313
305
 
314
306
  Casting provides a convenience for doing this.
@@ -350,12 +342,6 @@ If you are using Bundler, add this line to your application's Gemfile:
350
342
  gem 'casting'
351
343
  ```
352
344
 
353
- If you're using Ruby 1.9, be sure to use a version lower than 0.7
354
-
355
- ```ruby
356
- gem 'casting', '~> 0.6.9'
357
- ```
358
-
359
345
  And then execute:
360
346
 
361
347
  $ bundle
@@ -0,0 +1,125 @@
1
+ # This is an experimental implementation of allowing contextual use of behaviors.
2
+ #
3
+ # This relies on versions of Ruby supporting refinements.
4
+ #
5
+ # You *must* include the following module and use it for refinements, and
6
+ # you *must* set the current context for the thread:
7
+ #
8
+ # class SomeContext
9
+ # using Casting::Context
10
+ # include Casting::Context
11
+ #
12
+ # initialize(:some, :thing)
13
+ # # doing that defines your constructor but would cause it too look for
14
+ # # modules named Some and Thing
15
+ # module Some; end
16
+ # module Thing; end
17
+ #
18
+ # # if you want different module names (why would you?) then you'd need
19
+ # # to do all this:
20
+ # def initialize(some, thing)
21
+ # @assignments = []
22
+ # assign [some, SomeRole], [thing, OtherRole]
23
+ # Thread.current[:context] = self
24
+ # end
25
+ # attr_reader :some, :thing, :assignments
26
+ #
27
+ # module SomeRole; end
28
+ # module OtherRole; end
29
+ # end
30
+ #
31
+ # In order to use this the objects sent into the context contstructor *must*
32
+ # `include Casting::Client` so that the `cast` method is available to them
33
+ #
34
+ module Casting
35
+ module Context
36
+
37
+ def self.extended(base)
38
+ base.send(:include, InstanceMethods)
39
+ end
40
+
41
+ def initialize(*setup_args)
42
+ attr_reader(*setup_args)
43
+ private(*setup_args)
44
+
45
+ mod = Module.new
46
+ line = __LINE__; string = %<
47
+ def initialize(#{setup_args.map{|name| "#{name}:" }.join(',')})
48
+ @assignments = []
49
+ #{setup_args.map do |name|
50
+ ["assign(",name,", '",name,"')"].join
51
+ end.join("\n")}
52
+ Thread.current[:context] = self
53
+ end
54
+ attr_reader :assignments
55
+ >
56
+ mod.class_eval string, __FILE__, line
57
+ const_set('Initializer', mod)
58
+ include mod
59
+ end
60
+
61
+ module InstanceMethods
62
+ def context
63
+ self
64
+ end
65
+
66
+ # Keep track of objects and their behaviors
67
+ def assign(object, role_name)
68
+ instance_variable_set("@#{role_name}", object)
69
+ self.assignments << [object, self.role_for(role_name)]
70
+ end
71
+
72
+ def contains?(obj)
73
+ assignments.map(&:first).include?(obj)
74
+ end
75
+
76
+ # Execute the behavior from the role on the specifed object
77
+ def dispatch(object, method_name, *args, &block)
78
+ object.cast(method_name, context.role_implementing(object, method_name), *args, &block)
79
+ end
80
+
81
+ # Find the first assigned role which implements a response for the given method name
82
+ def role_implementing(object, method_name)
83
+ assigned_roles(object).find{|role| role.method_defined?(method_name) } || raise(NoMethodError, "unknown method '#{method_name}' expected for #{object}")
84
+ end
85
+
86
+ # Get the roles for the given object
87
+ def assigned_roles(object)
88
+ assignments.select{|pair|
89
+ pair.first == object
90
+ }.map(&:last)
91
+ end
92
+
93
+ # Get the behavior module for the named role.
94
+ # This role constant for special_person is SpecialPerson.
95
+ def role_for(name)
96
+ role_name = name.to_s.gsub(/(?:^|_)([a-z])/) { $1.upcase }
97
+ self.class.const_get(role_name)
98
+ rescue NameError
99
+ Module
100
+ end
101
+ end
102
+
103
+ refine Object do
104
+ def context
105
+ Thread.current[:context]
106
+ end
107
+
108
+ def context=(obj)
109
+ Thread.current[:context] = obj
110
+ end
111
+
112
+ # Get the object playing a particular role
113
+ def role(role_name)
114
+ context.send(role_name)
115
+ end
116
+
117
+ # Execute the named method on the object plaing the name role
118
+ def tell(role_name, method_name, *args, &block)
119
+ if context == self || context.contains?(self)
120
+ context.dispatch(role(role_name), method_name, *args, &block)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -7,7 +7,7 @@ module Casting
7
7
  private :prepared_delegation
8
8
 
9
9
  def initialize(delegated_method_name, client)
10
- @prepared_delegation = PreparedDelegation.new(:delegated_method_name => delegated_method_name, :client => client)
10
+ @prepared_delegation = PreparedDelegation.new(delegated_method_name: delegated_method_name, client: client)
11
11
  end
12
12
 
13
13
  def client
@@ -47,7 +47,12 @@ module Casting
47
47
  private
48
48
 
49
49
  def __delegates__
50
- @__delegates__ ||= []
50
+ return @__delegates__ if defined?(@__delegates__)
51
+ if frozen?
52
+ []
53
+ else
54
+ @__delegates__ = []
55
+ end
51
56
  end
52
57
 
53
58
  def method_missing(meth, *args, &block)
@@ -1,24 +1,24 @@
1
1
  module Casting
2
2
  module Null
3
- def self.instance_method(name)
3
+ def self.instance_method(_)
4
4
  Empty.instance_method(:null)
5
5
  end
6
- def self.method_defined?(meth)
6
+ def self.method_defined?(_)
7
7
  true
8
8
  end
9
9
  end
10
10
  module Blank
11
- def self.instance_method(name)
11
+ def self.instance_method(_)
12
12
  Empty.instance_method(:blank)
13
13
  end
14
- def self.method_defined?(meth)
14
+ def self.method_defined?(_)
15
15
  true
16
16
  end
17
17
  end
18
18
  module Empty
19
- def null(*args, &block); end
20
- def blank(*args, &block)
19
+ def null(*, &_block); end
20
+ def blank(*, &_block)
21
21
  ""
22
22
  end
23
23
  end
24
- end
24
+ end
@@ -10,15 +10,15 @@ module Casting
10
10
 
11
11
  class PreparedDelegation
12
12
 
13
- attr_reader :client
14
- attr_reader :delegated_method_name, :attendant, :arguments, :block
15
- private :delegated_method_name, :attendant, :arguments, :block
13
+ attr_accessor :client, :delegated_method_name, :attendant, :arguments, :block
14
+ private :block
16
15
 
17
- def initialize(settings)
16
+ def initialize(**settings, &block)
18
17
  @delegated_method_name = settings[:delegated_method_name]
19
18
  @client = settings[:client]
20
19
  @attendant = settings[:attendant]
21
20
  @arguments = settings[:arguments]
21
+ @block = block
22
22
  end
23
23
 
24
24
  def to(object_or_module)
@@ -59,7 +59,10 @@ module Casting
59
59
  end
60
60
 
61
61
  def method_module
62
- delegated_method.owner unless delegated_method.owner.is_a?(Class)
62
+ mod = delegated_method.owner
63
+ unless mod.is_a?(Class)
64
+ mod
65
+ end
63
66
  end
64
67
 
65
68
  def delegated_method
@@ -1,3 +1,3 @@
1
1
  module Casting
2
- VERSION = '0.7.1'
2
+ VERSION = '0.7.2'
3
3
  end
@@ -1,12 +1,5 @@
1
- require 'simplecov'
2
- SimpleCov.start do
3
- add_filter 'test'
4
- end
5
-
6
- require 'coveralls'
7
- if ENV['COVERALLS']
8
- Coveralls.wear!
9
- end
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
10
3
 
11
4
  require 'minitest/autorun'
12
5
  require 'casting'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: casting
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Gay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-27 00:00:00.000000000 Z
11
+ date: 2016-07-28 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  Casting assists in method delegation which preserves the binding of 'self' to the object receiving a message.
@@ -20,8 +20,12 @@ executables: []
20
20
  extensions: []
21
21
  extra_rdoc_files: []
22
22
  files:
23
+ - LICENSE
24
+ - README.md
25
+ - Rakefile
23
26
  - lib/casting.rb
24
27
  - lib/casting/client.rb
28
+ - lib/casting/context.rb
25
29
  - lib/casting/delegation.rb
26
30
  - lib/casting/method_consolidator.rb
27
31
  - lib/casting/missing_method_client.rb
@@ -30,10 +34,6 @@ files:
30
34
  - lib/casting/prepared_delegation.rb
31
35
  - lib/casting/super_delegate.rb
32
36
  - lib/casting/version.rb
33
- - LICENSE
34
- - Rakefile
35
- - README.md
36
- - test/test_helper.rb
37
37
  - test/casting_19_test.rb
38
38
  - test/casting_20_test.rb
39
39
  - test/casting_test.rb
@@ -42,9 +42,10 @@ files:
42
42
  - test/delegation_test.rb
43
43
  - test/method_consolidator_test.rb
44
44
  - test/missing_method_client_test.rb
45
- - test/null_module_test.rb
46
45
  - test/module_cleanup_test.rb
46
+ - test/null_module_test.rb
47
47
  - test/super_test.rb
48
+ - test/test_helper.rb
48
49
  homepage: http://github.com/saturnflyer/casting
49
50
  licenses:
50
51
  - MIT
@@ -55,17 +56,17 @@ require_paths:
55
56
  - lib
56
57
  required_ruby_version: !ruby/object:Gem::Requirement
57
58
  requirements:
58
- - - '>='
59
+ - - ">="
59
60
  - !ruby/object:Gem::Version
60
61
  version: '0'
61
62
  required_rubygems_version: !ruby/object:Gem::Requirement
62
63
  requirements:
63
- - - '>='
64
+ - - ">="
64
65
  - !ruby/object:Gem::Version
65
66
  version: '0'
66
67
  requirements: []
67
68
  rubyforge_project:
68
- rubygems_version: 2.0.14
69
+ rubygems_version: 2.6.6
69
70
  signing_key:
70
71
  specification_version: 4
71
72
  summary: Proper method delegation.