某段ruby元编程

可以用irb(Ruby的REPL程序)实际运行:

class A
  [:scope, :show_snippets, :search_results, :search_objects].each do |name|
    define_method name do
      search
      instance_variable_get "@#{name}"
    end
  end

  def search
    return if @searched
    @scope, @show_snippets, @search_results, @search_objects = 1,2,3,4
    @searched = true
  end

  def call(*attrs)
    attrs.map { |a| send a}
  end
end

a = A.new
[a.scope, a.show_snippets, a.search_results, a.search_objects] # [1, 2, 3, 4]
a.(:scope, :show_snippets, :search_results, :search_objects) # [1, 2, 3, 4]

解释一下:

对给定的4个属性名定义相应的getter,并且在获得属性前要先执行幂等的search方法来生成属性值。define_method接受方法名和代码块来定义方法,instance_variable_get根据名字获取对象的成员变量。 定义一个call方法来支持a.(:attr1, :attr2)这种批调用语法。对*attrs每个属性名a调用send a,相当于把方法名发送给对象(send是任何对象都拥有的方法),让它执行。

等价的普通Ruby代码如下:

class A
  def scope
    search
    @scope
  end

  def show_snippets
    search
    @show_snippets
  end

  def search_results
    search
    @search_results
  end

  def search_objects
    search
    @search_objects
  end

  def search
    return if @searched
    @scope, @show_snippets, @search_results, @search_objects = 1,2,3,4
    @searched = true
  end
end

a = A.new
[a.scope, a.show_snippets, a.search_results, a.search_objects]
最近的文章

commonjs异步模块

如何包装基础性的异步模块,有几种方案:1.包装到对象属性上var Wrapper = function(){ this.foo = "bar"; this.init();};Wrapper.prototype.init = function(){ var wrapper = this; async.function(function(response) { wrapper.foo = "foobar"; });}module.exports = new Wrapper(...…

继续阅读
更早的文章

Ruby 使用 Fiddle 调用 C 函数

写一个c函数// split.cdouble split(double num){ double ret = 0; ret = num / 2; return ret;}编译成动态库gcc -o libsplit.so -shared split.c在 split.rb 里调用 libsplit.so 里的 split 函数require 'fiddle'# Open the filelibsplit = Fiddle.dlopen('./libsplit.so')# Load th...…

继续阅读