ruby 私有 class 方法助手
ruby private class method helper
您好,我正在尝试创建一个帮助程序,用于将 ruby 方法定义为私有 class 方法。通常,可以通过使用 private_class_method 键工作将方法定义为私有 class 方法。但我想创建一个以下样式的助手:
class Person
define_private_class_methods do
def method_one
end
def method_two
end
end
end
我计划动态定义它的方式如下,根本不起作用:
class Object
def self.define_private_class_methods &block
instance_eval do
private
&block
end
end
end
有什么我可能出错的想法吗?
$ cat /tmp/a.rb
class Object
def self.define_private_class_methods &cb
existing = methods(false)
instance_eval &cb
(methods(false) - existing).each { |m| singleton_class.send :private, m }
end
end
class Person
define_private_class_methods do
def method_one
puts "¡Yay!"
end
end
end
Person.send(:method_one)
Person.public_send(:method_one)
$ ruby /tmp/a.rb
¡Yay!
/tmp/a.rb:18:in `public_send': private method `method_one'
called for Person:Class (NoMethodError)
Did you mean? method
from /tmp/a.rb:18:in `<main>'
请注意,很难理解您要实现的目标,可能有更好、更简洁、更可靠的方法来实现此功能。
与@mudasobwa 的回答相似但不同(语义上更正确恕我直言):
class Class
def define_private_class_methods(&definition)
class_methods_prior = methods
singleton_class.class_eval(&definition)
(methods - class_methods_prior).each do |method_name|
private_class_method method_name
end
end
end
class Person
define_private_class_methods do
def method_one
1
end
end
end
Person.method_one # !> NoMethodError: private method `method_one' called for Person:Class
Person.send :method_one # => 1
注意:它不会改变您当前覆盖的class方法的可访问性。
您可以通过将块传递给 Module.new
, make each instance method in the module private
and extend
您的 class 模块来定义匿名模块中的方法:
class Class
def define_private_class_methods(&block)
mod = Module.new(&block)
mod.instance_methods.each { |m| mod.send(:private, m) }
extend(mod)
end
end
这有预期的结果:
class Person
define_private_class_methods do
def method_one
123
end
end
end
Person.send(:method_one)
#=> 123
Person.method_one
#=> private method `method_one' called for Person:Class (NoMethodError)
... 作为奖励,它还提供了一个 super
方法:(可能用处不大)
class Person
def self.method_one
super * 2
end
end
Person.method_one
#=> 456
当然,你不必使用extend
,你也可以手动定义方法:
class Class
def define_private_class_methods(&block)
mod = Module.new(&block)
mod.instance_methods.each do |m|
define_singleton_method(m, mod.instance_method(m))
private_class_method(m)
end
end
end
基本组件是匿名模块,因此您有一个(临时)容器来定义其中的方法。
您好,我正在尝试创建一个帮助程序,用于将 ruby 方法定义为私有 class 方法。通常,可以通过使用 private_class_method 键工作将方法定义为私有 class 方法。但我想创建一个以下样式的助手:
class Person
define_private_class_methods do
def method_one
end
def method_two
end
end
end
我计划动态定义它的方式如下,根本不起作用:
class Object
def self.define_private_class_methods &block
instance_eval do
private
&block
end
end
end
有什么我可能出错的想法吗?
$ cat /tmp/a.rb
class Object
def self.define_private_class_methods &cb
existing = methods(false)
instance_eval &cb
(methods(false) - existing).each { |m| singleton_class.send :private, m }
end
end
class Person
define_private_class_methods do
def method_one
puts "¡Yay!"
end
end
end
Person.send(:method_one)
Person.public_send(:method_one)
$ ruby /tmp/a.rb
¡Yay!
/tmp/a.rb:18:in `public_send': private method `method_one'
called for Person:Class (NoMethodError)
Did you mean? method
from /tmp/a.rb:18:in `<main>'
请注意,很难理解您要实现的目标,可能有更好、更简洁、更可靠的方法来实现此功能。
与@mudasobwa 的回答相似但不同(语义上更正确恕我直言):
class Class
def define_private_class_methods(&definition)
class_methods_prior = methods
singleton_class.class_eval(&definition)
(methods - class_methods_prior).each do |method_name|
private_class_method method_name
end
end
end
class Person
define_private_class_methods do
def method_one
1
end
end
end
Person.method_one # !> NoMethodError: private method `method_one' called for Person:Class
Person.send :method_one # => 1
注意:它不会改变您当前覆盖的class方法的可访问性。
您可以通过将块传递给 Module.new
, make each instance method in the module private
and extend
您的 class 模块来定义匿名模块中的方法:
class Class
def define_private_class_methods(&block)
mod = Module.new(&block)
mod.instance_methods.each { |m| mod.send(:private, m) }
extend(mod)
end
end
这有预期的结果:
class Person
define_private_class_methods do
def method_one
123
end
end
end
Person.send(:method_one)
#=> 123
Person.method_one
#=> private method `method_one' called for Person:Class (NoMethodError)
... 作为奖励,它还提供了一个 super
方法:(可能用处不大)
class Person
def self.method_one
super * 2
end
end
Person.method_one
#=> 456
当然,你不必使用extend
,你也可以手动定义方法:
class Class
def define_private_class_methods(&block)
mod = Module.new(&block)
mod.instance_methods.each do |m|
define_singleton_method(m, mod.instance_method(m))
private_class_method(m)
end
end
end
基本组件是匿名模块,因此您有一个(临时)容器来定义其中的方法。