添加直接在模型上调用的方法
add methods directly called on model
我想实现我自己的在 class 加载时调用的方法。
我的第一个例子来自 PaperClip
,其中行 has_attached_file
直接写在 class 上,指的是周围某处的另一个植入 (lib/Paperclip)。
我想实现一个方法,以便在 class 上调用其他方法。我希望它看起来 link 和 before_filter
但在模特身上。
这个想法是不必在您想要的每个方法上手动调用特定方法。模型开头的一行就足够了。
我尝试使用 Concern
但据我所知,我只能定义 class/instance 方法,包括一些依赖项等等。
我想为 2 个方法 go_for_it
和 do_it_again
调用方法 watch_here
。我不想这样称呼它:
def go_for_it
watch_here :go_for_it
puts "Do it!"
end
def do_it_again
watch_here :do_it_again
puts "Do it again!"
end
private
def watch_here(name)
puts "I'm watching on #{name}"
end
我宁愿有这样的东西:
watch_here :go_for_it, :do_it_again
谢谢你的帮助!
啊,元编程的乐趣!要向 class 动态添加方法或行为,您可以使用 instance_eval
and class_eval
.
请注意,这是一个非常高级的主题,您应该首先对 classes、模块和消息传递 Ruby 的工作原理有一个清晰的了解!
module Magic
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def make_awesome
# self here is the class - so we are adding class methods
self.instance_eval do
def magic_class_method
puts "I'm a metamagical class method, deal with it."
end
# you could call another class method such as
# before_save :magic_instance_method
end
self.class_eval do
def magic_instance_method
puts "I'm metamagical instance method, deal with it."
end
end
end
end
end
class Test
include Magic
make_awesome
end
Test.magic_class_method
# => "I'm a metamagical class method, deal with it."
Test.magic_instance_method
# => "I'm metamagical instance method, deal with"
这有点违反直觉,但疯狂背后是有原因的:
在 instance_eval
中,接收者是测试 class 本身。请记住,class 名称只是一个指向 class Class
实例的常量。
class_eval
是模块class的一个方法,意味着接收者将是一个模块或class。您传递给 class_eval 的块在 class 的上下文中进行评估,就像您使用 class
关键字声明 class 时一样。
补充阅读:
所以我自己测试了这个 && 进一步 @max
的回答(无论如何我有点想,但他肯定正确地指出了它)...
您可以使用许多资源:
- 回形针的
has_attached_file
- FriendlyID 的
friendly_id
- Ruby Metaprogramming: Declaratively Adding Methods to a Class
- Intend to extend
经过一些简短的研究,我发现了这个问题:
Ruby on Rails - passing a returned value of a method to has_attached_file. Do I get Ruby syntax wrong?
The problem is that you're trying to use an instance method picture_sizes_as_strings
in a declaration (has_attached_image
)
您要查找的是与声明 class 有关的内容。我在这方面的经验和你一样多,所以我写这篇文章是为了我自己的利益:
For those coming from static object oriented languages, such as C++ and Java, the concept of open classes is quite foreign. What does it mean that Ruby has open classes? It means that at run time the definition of a class can be changed. All classes in Ruby are open to be changed by the user at all times.
class Talker
def self.say(*args)
puts "Inside self.say"
puts "self = #{self}"
args.each do |arg|
method_name = ("say_" + arg.to_s).to_sym
send :define_method, method_name do
puts arg
end
end
end
end
class MyTalker < Talker
say :hello
end
m = MyTalker.new
m.say_hello
似乎如果您 delcare class,它将 运行 初始化的声明性 (?) 方法。这些方法可用于填充对象的其他部分...在 has_many :associations
的情况下,它将创建 @parent.associations
.
的实例方法
因为 ActiveRecord::Concerns
are modules, you need to treat them as such (according to the epic tutorial 我发现了):
#app/models/concerns.rb
require 'active_support/concern'
module Helper
extend ActiveSupport::Concern
module ClassMethods
def help(*args) #-> each argument represents a method
args.each do |arg|
method_name = ("say_" + arg.to_s).to_sym
send :define_method, method_name do
puts arg
end
end
end
end
end
#app/models/x.rb
class X < ActiveRecord::Base
include Helper
help :help
end
@x = X.new
@x.say_help #-> puts "help"
[[仍在研究其余部分]] -- 如何添加到实例方法;似乎 super
不太好用
我想实现我自己的在 class 加载时调用的方法。
我的第一个例子来自 PaperClip
,其中行 has_attached_file
直接写在 class 上,指的是周围某处的另一个植入 (lib/Paperclip)。
我想实现一个方法,以便在 class 上调用其他方法。我希望它看起来 link 和 before_filter
但在模特身上。
这个想法是不必在您想要的每个方法上手动调用特定方法。模型开头的一行就足够了。
我尝试使用 Concern
但据我所知,我只能定义 class/instance 方法,包括一些依赖项等等。
我想为 2 个方法 go_for_it
和 do_it_again
调用方法 watch_here
。我不想这样称呼它:
def go_for_it
watch_here :go_for_it
puts "Do it!"
end
def do_it_again
watch_here :do_it_again
puts "Do it again!"
end
private
def watch_here(name)
puts "I'm watching on #{name}"
end
我宁愿有这样的东西:
watch_here :go_for_it, :do_it_again
谢谢你的帮助!
啊,元编程的乐趣!要向 class 动态添加方法或行为,您可以使用 instance_eval
and class_eval
.
请注意,这是一个非常高级的主题,您应该首先对 classes、模块和消息传递 Ruby 的工作原理有一个清晰的了解!
module Magic
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def make_awesome
# self here is the class - so we are adding class methods
self.instance_eval do
def magic_class_method
puts "I'm a metamagical class method, deal with it."
end
# you could call another class method such as
# before_save :magic_instance_method
end
self.class_eval do
def magic_instance_method
puts "I'm metamagical instance method, deal with it."
end
end
end
end
end
class Test
include Magic
make_awesome
end
Test.magic_class_method
# => "I'm a metamagical class method, deal with it."
Test.magic_instance_method
# => "I'm metamagical instance method, deal with"
这有点违反直觉,但疯狂背后是有原因的:
在 instance_eval
中,接收者是测试 class 本身。请记住,class 名称只是一个指向 class Class
实例的常量。
class_eval
是模块class的一个方法,意味着接收者将是一个模块或class。您传递给 class_eval 的块在 class 的上下文中进行评估,就像您使用 class
关键字声明 class 时一样。
补充阅读:
所以我自己测试了这个 && 进一步 @max
的回答(无论如何我有点想,但他肯定正确地指出了它)...
您可以使用许多资源:
- 回形针的
has_attached_file
- FriendlyID 的
friendly_id
- Ruby Metaprogramming: Declaratively Adding Methods to a Class
- Intend to extend
经过一些简短的研究,我发现了这个问题: Ruby on Rails - passing a returned value of a method to has_attached_file. Do I get Ruby syntax wrong?
The problem is that you're trying to use an instance method
picture_sizes_as_strings
in a declaration (has_attached_image
)
您要查找的是与声明 class 有关的内容。我在这方面的经验和你一样多,所以我写这篇文章是为了我自己的利益:
For those coming from static object oriented languages, such as C++ and Java, the concept of open classes is quite foreign. What does it mean that Ruby has open classes? It means that at run time the definition of a class can be changed. All classes in Ruby are open to be changed by the user at all times.
class Talker
def self.say(*args)
puts "Inside self.say"
puts "self = #{self}"
args.each do |arg|
method_name = ("say_" + arg.to_s).to_sym
send :define_method, method_name do
puts arg
end
end
end
end
class MyTalker < Talker
say :hello
end
m = MyTalker.new
m.say_hello
似乎如果您 delcare class,它将 运行 初始化的声明性 (?) 方法。这些方法可用于填充对象的其他部分...在 has_many :associations
的情况下,它将创建 @parent.associations
.
因为 ActiveRecord::Concerns
are modules, you need to treat them as such (according to the epic tutorial 我发现了):
#app/models/concerns.rb
require 'active_support/concern'
module Helper
extend ActiveSupport::Concern
module ClassMethods
def help(*args) #-> each argument represents a method
args.each do |arg|
method_name = ("say_" + arg.to_s).to_sym
send :define_method, method_name do
puts arg
end
end
end
end
end
#app/models/x.rb
class X < ActiveRecord::Base
include Helper
help :help
end
@x = X.new
@x.say_help #-> puts "help"
[[仍在研究其余部分]] -- 如何添加到实例方法;似乎 super
不太好用