Ruby中的JS样式对象引用

时间:2011-08-30 00:39:33

标签: javascript ruby coding-style syntax

鉴于Ruby的表现力如何,我想知道是否有人试图创建一个模仿JS对象语法的类或模块。例如,在JS中,我当然可以这样做:

[1]  var obj = {a: 'b'};
[2]  obj.c = 'd';
[3]  obj.a = 123
[4]  obj['e'] = 'f';
[5]  obj.e = obj['a']

在Ruby中,我现在可以拥有允许我这样做的代码:

[1]  obj = {'a' => 'b'}.to_js
[2]  # obj.c = 'd' << This is what I can't solve, 'c' is first defined here.
[3]  obj.a = 123;
[4]  obj['e'] = 'f'
[5]  obj.e = obj['a']

只要我通过方括号或初始化获得符号,我就可以轻松存储K / V对并为设置者和getter创建instance methods

然而,我还没有弄清楚如何创建一个会响应'c'的对象,如果它没有定义,那么就做一些魔术。例如,

  • 我可以迭代进入的哈希,并设置访问者
  • 我可以使用[]=(k, v)作为括号表示法并执行相同的操作。

到目前为止,我在第二种风格方面取得了进展。

有一个非常具体的Object#respond_to_missing?,可以在其中加上特定的符号;但在一般情况下无法回应。

有三种可能的方法可以解决注释掉的第二种调用方式:

  • 始终使对象不是类的实例,而是使用Method。例如,以下工作:
class A
  def b; puts 'c'; end
end
def always
  A.new
end

c = always
c.b

鉴于此,可能有一种方法可以执行某种错误捕获,然后相应地挂钩对象。

  • 利用我从未听说过的一些奇妙的红宝石功能。 Ruby是如此丰富的语言,这可能已经相当容易了。

  • 以某种方式覆盖错误处理机制。我不知道有人会在大型的一般情况下如何做到这一点,但基本上你会告诉ruby,如果某个类的任何实例未能响应某个方法,你就会有一些通用的处理程序来处理的东西。

无论如何,如果有人在这里有任何想法,我认为这将是一个非常有趣的练习。谢谢!

2 个答案:

答案 0 :(得分:2)

可能更好的方法:

class Hash
  def method_missing(symbol, opts = nil)
    string = symbol.to_s
    self[string[0..-2].to_sym] = opts if string[-1..-1] == '=' and opts
    self[symbol]
  end
end

如果你想要进行子类化,那么你可以这样做:

class JSHash < Hash
  def method_missing(symbol, opts = nil)
    string = symbol.to_s
    self[string[0..-2].to_sym] = opts if string[-1..-1] == '=' and opts
    self[symbol]
  end
end

class Hash
  def to_js
    JSHash.new.merge! self
  end
end

我会暂时保持这种状态,以防其他人想到更好的方法。

答案 1 :(得分:1)

几年后我偶然发现了这些问题,但仍有人觉得这很有用。

Hashie::Mash gem提供了这种行为。

require 'hashie/mash'

obj = Hashie::Mash.new ({'a' => 'b'})
obj.c = 'd'
obj.a = 123
obj['e'] = 'f'
obj.e = obj['a']

p obj # #<Hashie::Mash a=123 c="d" e=123>

p obj.to_hash # {"a"=>123, "c"=>"d", "e"=>123}

在分配嵌套哈希并将它们转换为蒙版时,它也具有魔力:

require 'hashie/mash'

obj = Hashie::Mash.new ({'a' => 'b'})
obj.c = 3
obj.d =  { e: { f: {g: { h:  5 } } } }

puts obj.d.e.f.g.h # 5

puts obj.to_hash # {"a"=>"b", "c"=>3, "d"=>{"e"=>{"f"=>{"g"={"h"=>5}}}}}

这里的价格是性能。在简单的测量中,Hashie :: Mash是app。比Hash慢10倍:

require 'benchmark'
require 'hashie/mash'

n = 1000000
time = Benchmark.measure do
  hash = {}
  (0..n).each do |key|
    hash[key] = key.to_s
  end
end
puts 'Standard Hash'
puts time

n = 1000000
time = Benchmark.measure do
  hash = Hashie::Mash.new
  (0..n).each do |key|
    hash[key] = key.to_s
  end
end
puts 'Hashie::Mash'
puts time

在我的机器上,结果是:

Standard Hash
  0.330000   0.030000   0.360000 (  0.367405)
Hashie::Mash
  3.350000   0.040000   3.390000 (  3.394001)