Module: Casting::SuperDelegate
- Defined in:
- lib/casting/super_delegate.rb
Class Attribute Summary collapse
-
.casting_library_matcher ⇒ Object
Returns the value of attribute casting_library_matcher.
-
.debugging_matcher ⇒ Object
Returns the value of attribute debugging_matcher.
-
.gem_home_matcher ⇒ Object
Returns the value of attribute gem_home_matcher.
Instance Method Summary collapse
- #calling_location(call_stack) ⇒ Object
- #casting_library_matcher ⇒ Object
- #debugging_matcher ⇒ Object
- #gem_home_matcher ⇒ Object
- #method_delegate_skipping(meth, skipped) ⇒ Object
- #name_and_owner_of_calling_method(call_stack) ⇒ Object
- #name_of_calling_method(call_stack) ⇒ Object
-
#super_delegate(mod = :none, *args, **kwargs, &block) ⇒ Object
Call the method of the same name defined in the next delegate stored in your object.
- #unbound_method_from_next_delegate(method_name, *skipped) ⇒ Object
Class Attribute Details
.casting_library_matcher ⇒ Object
Returns the value of attribute casting_library_matcher.
9 10 11 |
# File 'lib/casting/super_delegate.rb', line 9 def casting_library_matcher @casting_library_matcher end |
.debugging_matcher ⇒ Object
Returns the value of attribute debugging_matcher.
9 10 11 |
# File 'lib/casting/super_delegate.rb', line 9 def debugging_matcher @debugging_matcher end |
.gem_home_matcher ⇒ Object
Returns the value of attribute gem_home_matcher.
9 10 11 |
# File 'lib/casting/super_delegate.rb', line 9 def gem_home_matcher @gem_home_matcher end |
Instance Method Details
#calling_location(call_stack) ⇒ Object
61 62 63 64 65 |
# File 'lib/casting/super_delegate.rb', line 61 def calling_location(call_stack) call_stack.reject { |line| line.to_s.match? Regexp.union(casting_library_matcher, gem_home_matcher, debugging_matcher) }.first end |
#casting_library_matcher ⇒ Object
86 87 88 |
# File 'lib/casting/super_delegate.rb', line 86 def casting_library_matcher SuperDelegate.casting_library_matcher ||= Regexp.new(Dir.pwd.to_s + "/lib") end |
#debugging_matcher ⇒ Object
94 95 96 |
# File 'lib/casting/super_delegate.rb', line 94 def debugging_matcher SuperDelegate.debugging_matcher end |
#gem_home_matcher ⇒ Object
90 91 92 |
# File 'lib/casting/super_delegate.rb', line 90 def gem_home_matcher SuperDelegate.gem_home_matcher ||= Regexp.new(ENV["GEM_HOME"]) end |
#method_delegate_skipping(meth, skipped) ⇒ Object
54 55 56 57 58 59 |
# File 'lib/casting/super_delegate.rb', line 54 def method_delegate_skipping(meth, skipped) skipped_index = __delegates__.index(skipped) __delegates__[(skipped_index + 1)..__delegates__.length].find { |attendant| attendant_methods(attendant).include?(meth) } end |
#name_and_owner_of_calling_method(call_stack) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/casting/super_delegate.rb', line 72 def name_and_owner_of_calling_method(call_stack) label = calling_location(call_stack).label # Ruby 3.4.7+ includes module name in label (e.g., "ModuleName#method_name") # Ruby 3.3 and earlier just has method name parts = label.split("#") if parts.length > 1 # Ruby 3.4.7+: has owner prefix [parts.last.to_sym, parts.first] else # Ruby 3.3 and earlier: no owner prefix [parts.first.to_sym, nil] end end |
#name_of_calling_method(call_stack) ⇒ Object
67 68 69 70 |
# File 'lib/casting/super_delegate.rb', line 67 def name_of_calling_method(call_stack) method_name, _owner = name_and_owner_of_calling_method(call_stack) method_name end |
#super_delegate(mod = :none, *args, **kwargs, &block) ⇒ Object
Call the method of the same name defined in the next delegate stored in your object
Because Casting creates an alternative method lookup path using a collection of delegates, you may use ‘super_delegate` to work like `super`.
If you use this feature, be sure that you have created a delegate collection which does have the method you need or you’ll see a NoMethodError.
Example:
module Greeter
def greet
"Hello"
end
end
module FormalGreeter
include Casting::Super
def greet
"#{super_delegate}, how do you do?"
end
end
some_object.cast_as(Greeter, FormalGreeter) some_object.greet #=> ‘Hello, how do you do?’
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/casting/super_delegate.rb', line 38 def super_delegate(mod = :none, *args, **kwargs, &block) method_name, method_owner = name_and_owner_of_calling_method(caller_locations) owner = (mod unless mod == :none) || method_delegate(method_name) super_delegate_method = unbound_method_from_next_delegate(method_name, owner) super_delegate_method.bind_call(self, *args, **kwargs, &block) rescue NameError # Use the method_owner from the call stack for consistent error messages owner_name = method_owner || owner raise NoMethodError.new("super_delegate: no delegate method `#{owner_name}##{method_name}' for #{inspect} from ") end |
#unbound_method_from_next_delegate(method_name, *skipped) ⇒ Object
50 51 52 |
# File 'lib/casting/super_delegate.rb', line 50 def unbound_method_from_next_delegate(method_name, *skipped) method_delegate_skipping(method_name, *skipped).instance_method(method_name) end |