红宝石中的元/动态/泛型编程 [英] meta/dynamic/generic programming in ruby

查看:33
本文介绍了红宝石中的元/动态/泛型编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个通用方法:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆