【问题标题】:JS Style Object Referencing in RubyRuby 中的 JS 样式对象引用
【发布时间】:2011-08-30 00:39:33
【问题描述】:

鉴于 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 对并为 setter 和 getter 创建 instance methods

但是,我无法弄清楚如何创建一个对象,如果它没有定义,它将响应“c”,然后做一些魔术。例如,

  • 我可以遍历传入的哈希,并设置访问器
  • 我可以使用[]=(k, v) 表示括号并做同样的事情。

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

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

我可以想到三种可能的方法来解决注释掉的第二种调用样式:

  • 始终使对象不是类的实例,而是方法。例如,以下工作:
A级 定义 b;放'c';结尾 结尾 总是定义 重新 结尾 c = 总是 c.b

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

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

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

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

【问题讨论】:

  • 其实我想通了......我会尽快发布。

标签: javascript ruby coding-style syntax


【解决方案1】:

这样做可能更好的方法:

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

我会保持这个开放一段时间,以防其他人在这里有更好的方法。

【讨论】:

    【解决方案2】:

    多年后我偶然发现了这个问题,但仍然有人可能会觉得这很有用。

    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 是应用程序。比 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-28
      • 2017-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多