红宝石中的元/动态/泛型编程 [英] meta/dynamic/generic programming in ruby
问题描述
我正在尝试制作一个通用方法:
I am trying to make a generic method:
class Foo
attr_reader
def add(object)
item = @item.find { |item| item.(#the method is calling object.class) == object if item.is_a?(object.class)}
end
end
我想创建一个通用方法,该方法根据参数类比较数组的元素.
I want to create a generic method which compares the element of an array depending the parameter class.
示例:
item.method1 == method1 if item.is_a?(method1.class)
其中method1是类的名称.
where method1 is the name of class.
此外,我还需要有关元编程和动态/泛型编程的完整教程.
Also, I need a complete tutorial about metaprogramming and dynamic/generic programming.
推荐答案
我不确定您要从示例中尝试做什么.通常,在Ruby中,您无需检查类型.它是动态键入的,这是有原因的:您可以编写适用于碰巧支持您的代码调用的方法的任何对象的代码.
I am unsure of what you are trying to do from your example. As a general rule, in Ruby, you don't check for types. It is dynamically typed for a reason: you can write code that works for any objects that happen to support the methods your code calls on them.
根据我的评论,我想扩展类 Array
,因此,当您在 an_array.pack
之类的数组上调用方法时,该数组在 Pack
的实例中搜索并返回.每当发现不存在的方法时,Ruby都会调用一种方法,称为 Module#method_missing
.例如,如果我随机决定调用 4.to_dragon(magic:4,height:700)
,则Ruby解释器将尝试查找 to_dragon
作为在上定义的公共方法 Fixnum
(数字类型)继承链中的某些类或模块.如果您没有对该链做任何奇怪的事情,我们将使用以下参数调用对象 4
上的 method_missing
: [:to_dragon,{magic:4,高度:700}]
.基本上,这是附加在参数前面的名称,应该给出一个块.
From what I can tell from your comments, you want to extend the class Array
so, when you call a method on an array like an_array.pack
, the array is searched for an instance of Pack
and returned. Ruby has a method called whenever a method is found not to exist called Module#method_missing
. For example, if I randomly decide to call 4.to_dragon(magic: 4, height: 700)
, the Ruby interpreter will attempt to find to_dragon
as a public method defined on some class or module in the Fixnum
(type of numbers) inheritance chain. Provided you have not done something strange to that chain, we get a call to method_missing
on the object 4
with these arguments: [:to_dragon, { magic: 4, height: 700 }]
. Basically, that's the name appended to the front of the arguments, and a block should one be given.
使用此技术,您可以覆盖 method_missing
以获得此代码作为解决方案:
Using this technique, you can override method_missing
to get this code as a solution:
class String
def method_to_class
split('_').map(&:capitalize).join
end
end
class Array
def method_missing(method_name, *arguments, &block)
find do |element|
element.class.name == method_name.to_s.method_to_class
end || super
end
end
您将方法添加到 String
,以将方法名称转换为类名称.然后,您在 Array
上重新定义 method_missing
,以检查每个元素,以查看类名是否与给定的类名匹配.如果找到一个,则返回该值.否则(我们使用Ruby的 |||
运算符进行此操作),该函数返回的值为 nil
,第二个操作数为 |||
返回.这恰好是 method_missing
的默认实现(我们通过 super
关键字获得),并返回调用应得到的错误.
You add a method to String
to convert a method name to a class name. Then, you redefine method_missing
on Array
to check each element to see if the class name matches the given class name. If one is found, then that is returned. Otherwise (and we do this using Ruby's fancy ||
operator), the value returned from that function is nil
and the second operand to ||
is returned. This happens to be the default implementation for method_missing
(which we get by the super
keyword) and returns the error the call deserves.
唯一的潜在问题是,如果元素的类名与数组中已定义的方法名相同,则将调用这些元素,而不是调用此特殊技术.例如,调用 an_array.hash
将为您提供数组的哈希码,而不是哈希的第一个实例.
The only potential issue with that is, if you have elements that have class names identical to method names that are already defined on arrays, then those will be called instead rather than this special technique. For example, calling an_array.hash
will give you the hash code of the array rather than the first instance of a hash.
在这方面更安全的技术与我认为您要尝试的技术更相似.它实际上使用了类对象,您可以使用它来覆盖其他方法:
A safer technique in this respect is more similar to what I think you were trying to do. It actually uses class objects, and you can use it to override other methods:
class Array
def add(class_object)
class << self
define_method class_object.name do
find do |element|
element.is_a? class_object
end
end
end
end
end
这直接在数组的实例上定义了新方法.例如:
This defines new methods directly on an instance of an array. For example:
an_array = [Array, Hash, Dragon].map &:new
an_array.add Hash
an_array.hash #=> {}
如果此答案不包含解决方案,则至少应指导您更紧密!
If this answer does not include a solution, it should at least guide you closer!
这篇关于红宝石中的元/动态/泛型编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!