ruby 发送不调用类或模块中的私有方法

pbossiut  于 12个月前  发布在  Ruby
关注(0)|答案(3)|浏览(110)

不知道我做错了什么。我试图创建一个类或模块,然后我可以使用它来调用该类/模块中的私有方法。
我得到这个错误:NoMethodError (undefined method 'call' for MixPanelService:Class)
当我试着做MixPanelService.call(shop, "install")的时候
下面是我的简化代码:

class MixPanelService

  def call(shop, event_type)
    send(event_type, shop)
  end

  private

  def install
    ap "do something"
  end

end

然后我尝试了一个模块,得到了以下错误:NoMethodError (undefined method 'install' for MixPanelService:Module)
当我基本上尝试相同的:MixPanelService.call(shop, "install")
代码如下:

module MixPanelService
  module_function

  def call(shop, event_type)
    send(event_type, shop)
  end

  private

  def install
    ap "do something"
  end

end

我做错了什么?

eqzww0vc

eqzww0vc1#

在类中,您已经将call定义为一个示例方法,但您将其作为类方法调用。你可以使用def self.call将它变成一个类方法:

class MixPanelService
  def self.call(shop, event_type)
    send(event_type, shop)
  end

  def self.install(shop)
    # do something
  end
  private_class_method :install # ugly :(
end

# Call it like this:
MixPanelService.call(shop, 'install')

但这并不是最好的设计。使用类方法和传递参数很麻烦。你可以使用示例,但仍然有一个类方法来运行一切。看看这个模式:

class MixPanelService
  def self.call(shop, event_type)
    new(shop).call(event_type)
  end

  def initialize(shop)
    @shop = shop
  end

  def call(event_type)
    send(event_type)
  end

  private

  def install
    # Install something on `@shop`. Since it's an instance variable,
    # we don't need to pass it around via params! :)
  end
end

# Call it the same way as before:
MixPanelService.call(shop, 'install')
gcxthw6b

gcxthw6b2#

这是因为module_function不支持这样的私有方法。它将公共示例方法复制为self模块方法,并将其作为私有示例
也许它是更好地比较这种行为在行动中,它取决于你选择你需要什么

# With module_function
module MyModule
  module_function

  def my_public_method
    puts "Hi from public"
    my_private_method
  end

  private

  def my_private_method
    puts "Hi from private"
  end
end

class MyIncludeClass
  include MyModule
end

class MyExtendClass
  extend MyModule
end

MyModule.my_public_method
# Hi from public
# undefined local variable or method `my_private_method' for MyModule:Module (NameError)

MyModule.my_private_method
# undefined method `my_private_method' for MyModule:Module (NoMethodError)

MyIncludeClass.new.my_public_method
# private method `my_public_method' called for #<MyIncludeClass:0x0000000104d766f8> (NoMethodError)

MyIncludeClass.new.my_private_method
# private method `my_private_method' called for #<MyIncludeClass:0x0000000104eb17c0> (NoMethodError)

MyExtendClass.my_public_method
# private method `my_public_method' called for MyExtendClass:Class (NoMethodError)

MyExtendClass.my_private_method
# private method `my_private_method' called for MyExtendClass:Class (NoMethodError)
# With extend self
module MyModule
  extend self

  def my_public_method
    puts "Hi from public"
    my_private_method
  end

  private

  def my_private_method
    puts "Hi from private"
  end
end

class MyIncludeClass
  include MyModule
end

class MyExtendClass
  extend MyModule
end

MyModule.my_public_method
# Hi from public
# Hi from private

MyModule.my_private_method
# private method `my_private_method' called for MyModule:Module (NoMethodError)

MyIncludeClass.new.my_public_method
# Hi from public
# Hi from private

MyIncludeClass.new.my_private_method
# private method `my_private_method' called for #<MyIncludeClass:0x0000000108afa790> (NoMethodError)

MyExtendClass.my_public_method
# Hi from public
# Hi from private

MyExtendClass.my_private_method
# private method `my_private_method' called for MyExtendClass:Class (NoMethodError)
# With class << self syntax
module MyModule
  class << self
    def my_public_method
      puts "Hi from public"
      my_private_method
    end

    private

    def my_private_method
      puts "Hi from private"
    end
  end
end

class MyIncludeClass
  include MyModule
end

class MyExtendClass
  extend MyModule
end

MyModule.my_public_method
# Hi from public
# Hi from private

MyModule.my_private_method
# private method `my_private_method' called for MyModule:Module (NoMethodError)

MyIncludeClass.new.my_public_method
# undefined method `my_public_method' for #<MyIncludeClass:0x0000000103fec6b8> (NoMethodError)

MyIncludeClass.new.my_private_method
# undefined method `my_private_method' for #<MyIncludeClass:0x00000001041929e0> (NoMethodError)

MyExtendClass.my_public_method
# undefined method `my_public_method' for MyExtendClass:Class (NoMethodError)

MyExtendClass.my_private_method
# undefined method `my_private_method' for MyExtendClass:Class (NoMethodError)
# With private_class_method
module MyModule
  def self.my_public_method
    puts "Hi from public"
    my_private_method
  end

  def self.my_private_method
    puts "Hi from private"
  end

  private_class_method :my_private_method
end

class MyIncludeClass
  include MyModule
end

class MyExtendClass
  extend MyModule
end

MyModule.my_public_method
# Hi from public
# Hi from private

MyModule.my_private_method
# private method `my_private_method' called for MyModule:Module (NoMethodError)

MyIncludeClass.new.my_public_method
# undefined method `my_public_method' for #<MyIncludeClass:0x00000001044f1870> (NoMethodError)

MyIncludeClass.new.my_private_method
# undefined method `my_private_method' for #<MyIncludeClass:0x000000010449bfb0> (NoMethodError)

MyExtendClass.my_public_method
# undefined method `my_public_method' for MyExtendClass:Class (NoMethodError)

MyExtendClass.my_private_method
# undefined method `my_private_method' for MyExtendClass:Class (NoMethodError)
zdwk9cvp

zdwk9cvp3#

这就是我遇到的问题的解决方案。现在一切正常我最终使用了moduleself,如下所示:

module MixPanelService
  module_function

  def self.call(shop, event_type)
    send(event_type, shop)
  end

  private

  def self.install(shop)
    # do something
  end

end

相关问题