0

如果我有一个 OpenStruct:

require 'ostruct'
open_struct = OpenStruct.new

我可以覆盖[]在某些情况下有效的

open_struct.define_singleton_method(:[]) do |*args|
  puts args.map(&:class)
  puts args
end

open_struct.a = 1
open_struct[:a]
# => Symbol
#    a

但是[]使用点方法语法时不会调用此方法:

open_struct.a
# => 1

我正在尝试创建一个继承自 OpenStruct 并且更像 Javascript 对象的类(基本上我试图消除在call存储为值的 proc 上运行的必要性)

4

1 回答 1

1

首先 - OpenStruct 的功能已经非常像 JavaScript(假设它#[]是 的同义词#call):

JS:

foo = {}
foo.bar = function() { console.log("Hello, world!"); };
foo.bar();
// => Hello, world!

红宝石:

foo = OpenStruct.new
foo.bar = proc { puts "Hello, world!" }
foo.bar[]
# => Hello, world!

如果你的意思是更像Ruby的函数......你可以覆盖new_ostruct_member

require 'ostruct'

class AutoCallableOpenStruct < OpenStruct
  protected def new_ostruct_member(name)
    name = name.to_sym
    unless respond_to?(name)
      define_singleton_method(name) {
        val = @table[name]
        if Proc === val && val.arity == 0
          val.call
        else
          val
        end
      }
      define_singleton_method("#{name}=") { |x| modifiable[name] = x }
    end
    name
  end
end

a = AutoCallableOpenStruct.new
a.name = "max"
a.helloworld = proc { puts "Hello, world!" }
a.hello = proc { |name| puts "Hello, #{name}!" }

a.name              # non-Proc, retrieve
# => max
a.helloworld        # nullary proc, autocall
# => Hello, world!
a.hello[a.name]     # non-nullary Proc, retrieve (#[] invokes)
# => Hello, max!

请注意,OpenStruct在 Ruby 中会减慢您的程序,如果可以避免,则不应使用它。

于 2016-10-24T04:13:23.247 回答