45


17

hash ['key']をRubyのhash.keyに

私はハッシュを持っています

foo = {'bar'=>'baz'}

`foo.bar#⇒ 'baz'`を呼び出したい

私の動機は、ActiveRecordクエリを生のSQLクエリに書き換えることです(Model#find_by_sqlを使用)。 これは、SELECT句の値をキーとして持つハッシュを返します。 ただし、既存のコードは、object.methodドット表記に依存しています。 最小限のコード書き換えを行いたいです。 ありがとう。

編集:Luaには次の機能があるようです:

point = { x = 10, y = 20 }   -- Create new table
print(point["x"])            -- Prints 10
print(point.x)               -- Has exactly the same meaning as line above

5 Answer


81


>> require 'ostruct'
=> []
>> foo = {'bar'=>'baz'}
=> {"bar"=>"baz"}
>> foo_obj = OpenStruct.new foo
=> #
>> foo_obj.bar
=> "baz"
>>


35


探しているものはhttp://ruby-doc.org/stdlib/libdoc/ostruct/rdoc/classes/OpenStruct.html[OpenStruct]と呼ばれています。 これは標準ライブラリの一部です。


22


良い解決策:

class Hash
  def method_missing(method, *opts)
    m = method.to_s
    if self.has_key?(m)
      return self[m]
    elsif self.has_key?(m.to_sym)
      return self[m.to_sym]
    end
    super
  end
end

注:この実装には既知のバグが1つしかありません。

x = { 'test' => 'aValue', :test => 'bar'}
x.test # => 'aValue'

文字列検索よりもシンボル検索を好む場合は、2つの「if」条件を交換します


6


ハッシュからすべてのものをコピーするのではなく、ハッシュにいくつかの動作を追加するだけで検索を実行できます。

この定義を追加する場合は、ハッシュを拡張して、未知のすべてのメソッドをハッシュルックアップとして処理します。

class Hash
  def method_missing(n)
    self[n.to_s]
  end
end

これは、ハッシュで間違ったメソッドを呼び出してもエラーが表示されないことを意味することに注意してください。対応するハッシュルックアップが返すものは何でも取得できます。

特定のハッシュにのみメソッドを置く-または必要な数のハッシュによって、これが引き起こす可能性のあるデバッグの問題を大幅に減らすことができます:

a={'foo'=>5, 'goo'=>6}
def a.method_missing(n)
   self[n.to_s]
end

もう一つの観察は、 method_missing`がシステムによって呼び出されると、 Symbol`引数を与えるということです。 私のコードはそれを `String`に変換しました。 ハッシュキーが文字列でない場合、このコードはそれらの値を決して返しません。文字列の代わりにシンボルでキーを入力する場合、上記の「n.to_s」を「n」に置き換えてください。


4


これにはいくつかの宝石があります。 私の最近の宝石、https://github.com/adsteel/hash_dot [hash_dot]と、RubyGemsで鉱山をリリースしたときに発見した似たような名前の宝石がいくつかあります。https://github.com/3den/dot_hash [ dot_hash]。

HashDotでは、ドット表記構文を使用できますが、@ avdiによって対処されるNoMethodErrorsに関する懸念に対処します。 これは、OpenStructで作成されたオブジェクトよりも高速で、通過可能です。

require 'hash_dot'
a = {b: {c: {d: 1}}}.to_dot
a.b.c.d => 1

require 'open_struct'
os = OpenStruct.new(a)
os.b => {c: {d: 1}}
os.b.c.d => NoMethodError

また、非メソッドが呼び出されたときに期待される動作を維持します。

a.non_method => NoMethodError

HashDotに改善点やバグを送信してください。