Подтвердить что ты не робот

Как преобразовать хеш-ключи в имена методов?

Это мой хэш:

tempData = {"a" => 100, "here" => 200, "c" => "hello"}

Мне нужно получить доступ к хеш-ключам в качестве метода, например:

tempData.a #100
tempData.here # 200
4b9b3361

Ответ 1

Вы можете просто обернуть свой хэш в OpenStruct:

require 'ostruct'
tempData = {"a" => 100, "here" => 200, "c" => "hello"}
os = OpenStruct.new tempData
os.a #=> 100
os.here #=> 200

Если вы действительно этого захотите, вы можете также обезвредить класс Hash, но я бы посоветовал это:

class Hash
  def method_missing(m, *args, &blk)
    fetch(m) { fetch(m.to_s) { super } }
  end
end

tempData = {"a" => 100, "here" => 200, "c" => "hello"}
tempData.a #=> 100

Обновление: В моей личной библиотеке расширений я добавил Hash # to_ostruct. Это рекурсивно преобразует хэш в OpenStruct, включая все вложенные хэши.

Ответ 2

В качестве альтернативы, если его просто небольшой script, было бы удобнее просто расширить Hash

class Hash
  def method_missing sym,*
    fetch(sym){fetch(sym.to_s){super}}
  end
end

method_missing - это волшебный метод, который вызывается всякий раз, когда ваш код пытается вызвать метод, который не существует. Ruby перехватит неудачный вызов во время выполнения и позволит вам обрабатывать его, чтобы ваша программа могла изящно восстанавливаться. Вышеприведенная реализация пытается получить доступ к хешу, используя имя метода в качестве символа, используя имя метода в виде строки и, в конечном счете, не удается с ошибкой встроенного метода Ruby.

NB для более сложного script, где добавление этого поведения может сломать другие сторонние драгоценные камни, вы можете в качестве альтернативы использовать модуль и расширять каждый экземпляр

module H
  def method_missing sym,*
    fetch(sym){fetch(sym.to_s){super}}
  end
end

the = { answer: 42 }
the.extend(H)
the.answer # => 42

и для большего удобства вы можете даже распространять модуль до вложенные хеши

module H
  def method_missing sym,*
    r = fetch(sym){fetch(sym.to_s){super}}
    Hash === r ? r.extend(H) : r
  end
end 

the = { answer: { is: 42 } }
the.extend(H)
the.answer.is # => 42

Ответ 3

Если хеш находится внутри модуля, вы можете динамически определять методы на этом модуле (или классе) с помощью define_method. Например:

module Version
  module_function

  HASH = { 
    major: 1,
    minor: 2,
    patch: 3,
  }

  HASH.each do |name, value|
    define_method(name) do
      return value
    end
  end
end

Это будет определять модуль Version с методами major, minor и patch, которые возвращают 1, 2 и 3 соответственно.

Ответ 4

вы можете расширить класс Hash следующим образом.

class Hash
      # return nil whenever the key doesn't exist
      def method_missing(m, *opts)
        if self.has_key?(m.to_s)
          return self[m.to_s]
        elsif self.has_key?(m.to_sym)
          return self[m.to_sym]
        end
        return nil

        # comment out above line and replace with line below if you want to return an error
        # super
      end
end

Ответ 5

Есть и другой способ сделать это.

JSON.parse(tempData.to_json, object_class: OpenStruct)

который даст объект #<OpenStruct a=100, here=200, c="hello">

Таким образом, вложенный hash также будет преобразован в OpenStruct Object

tempData = {a: { b: { c: 3}}, foo: 200, msg: 'test msg'}
obj = JSON.parse(tempData.to_json, object_class: OpenStruct)

Теперь мы можем вызвать

obj.a.b.c # 3
obj.foo # 200
obj.msg # 'test msg'

Надеюсь, это поможет кому-то.