Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 调用基于超级的被调用方值_Ruby On Rails_Ruby_Super - Fatal编程技术网

Ruby on rails 调用基于超级的被调用方值

Ruby on rails 调用基于超级的被调用方值,ruby-on-rails,ruby,super,Ruby On Rails,Ruby,Super,方法super基于\uuuuu方法\uuuu调用父方法。 如何基于被调用方调用父方法 class SomeLogic DICTIONARY = { new_method_1: 'dictionary value 1', new_method_2: 'dictionary value 2' } def initialize(method_name) @method_name = method_name end def call DICTION

方法
super
基于
\uuuuu方法\uuuu
调用父方法。 如何基于被调用方调用父方法

class SomeLogic
  DICTIONARY = {
    new_method_1: 'dictionary value 1',
    new_method_2: 'dictionary value 2'
  }

  def initialize(method_name)
    @method_name = method_name
  end

  def call
    DICTIONARY[@method_name]
  end

end

module M

  extend ActiveSupport::Concern

  def base_method
    logic = SomeLogic.new(__callee__).call

    if logic
      logic
    elsif defined?(__callee__)
      super # here analogue of super needed
    else
      {}
    end
  end

  alias_method :new_method_1, :base_method
  alias_method :new_method_2, :base_method
  alias_method :new_method_3, :base_method
end


class A

  prepend M

  def new_method_3
    'foo'
  end

end
预期成果:

A.new.new_method_1 # dictionary value 1
A.new.new_method_2 # dictionary value 2
A.new.new_method_3 # foo
目前的结果:

A.new.new_method_1 # dictionary value 1
A.new.new_method_2 # dictionary value 2
A.new.new_method_3 # no superclass method `base_method' for A
如果你改变

class A
  prepend M


您将获得所需的输出

好的,因此这非常复杂,但它将按要求工作

class SomeLogic
  DICTIONARY = {
    new_method_1: 'dictionary value 1',
    new_method_2: 'dictionary value 2'
  }

  def initialize(method_name)
    @method_name = method_name
  end

  def call
    DICTIONARY[@method_name]
  end

end
module M

  def self.prepended(base)
    base.extend(ClassMethods)
  end

  def base_method(&block)
    SomeLogic.new(__callee__).call || 
    block&.call || # ruby < 2.3 block && block.call
    {}
  end

  module ClassMethods
    def method_added(method_name)
      if M.instance_methods.include?(method_name)
        orig = M.instance_method(method_name)
        M.remove_method(method_name)
        new = self.instance_method(method_name)
        self.prepend(Module.new do 
          define_method(method_name) do
            result = orig.bind(self).call(&new.bind(self))
          end   
        end)
        M.define_method(method_name, &orig.bind(M))  
      end
    end
  end

  alias_method :new_method_1, :base_method
  alias_method :new_method_2, :base_method
  alias_method :new_method_3, :base_method
  alias_method :new_method_4, :base_method
end

class A
  prepend M
  def new_method_3
    'foo'
  end
end

class B 
  prepend M 
end
如果您更喜欢
include
而不是
prepend
,那么
M
可能看起来像

module M 
  def self.included(base)
    super
    base.extend(ClassMethods)
  end

  def base_method
    if logic = SomeLogic.new(__callee__).call
      logic
    elsif self.class.instance_methods(false).include?(__callee__)
      send(__callee__,true)
    else
      {}
    end
  end
  module ClassMethods
    def method_added(method_name)
      return if @_adding_method # avoid stack level issues
      if M.instance_methods.include?(method_name)
        new = instance_method(method_name)
        @_adding_method = true # avoid stack level issues
        define_method(method_name) do |bypass_parent=false|
          return super() unless bypass_parent
          new.bind(self).call
        end   
        @_adding_method = false
      end
    end
  end
end

如果
SomeLogic::DICTIONARY
具有
:new\u method\u 3
的键,则包含
将不起作用,因为此逻辑似乎需要优先于已定义的方法调用
p A.new.new_method_1 
#=> 'dictionary value 1'
p A.new.new_method_2 
#=> 'dictionary value 2'
p A.new.new_method_3 
#=> 'foo'
p A.new.new_method_4
#=> {}
p B.new.new_method_3
#=> {}
module M 
  def self.included(base)
    super
    base.extend(ClassMethods)
  end

  def base_method
    if logic = SomeLogic.new(__callee__).call
      logic
    elsif self.class.instance_methods(false).include?(__callee__)
      send(__callee__,true)
    else
      {}
    end
  end
  module ClassMethods
    def method_added(method_name)
      return if @_adding_method # avoid stack level issues
      if M.instance_methods.include?(method_name)
        new = instance_method(method_name)
        @_adding_method = true # avoid stack level issues
        define_method(method_name) do |bypass_parent=false|
          return super() unless bypass_parent
          new.bind(self).call
        end   
        @_adding_method = false
      end
    end
  end
end