Как получить доступ к вложенным элементам хэша с помощью одного строкового ключа? - PullRequest
9 голосов
/ 13 июля 2011

Я дурачусь с Руби, и в основном у меня есть

@trans = { :links => {
    :quick_notes => "aaaaaaa"
  }
}

Я хочу назвать что-то вроде

def t
  #...something
end
t('links.quick_notes')

, чтобы получить доступ

trans[:links][:quick_notes]

IЯ в основном пытаюсь достичь той же функциональности, что и при использовании интернационализации

I18n.t('something.other.foo') 

sofar Я придумал такой подход

 def t(key)
   a=''
   key.to_s.split('.').each{|key|  a+="[:#{key}]" } 
   #now a == "[:links][:quick_notes]"
   #but I cant figure out how can I call it on  @trans variable

 end

 t('links.quick_notes')

Есть идеи?спасибо

Ответы [ 5 ]

13 голосов
/ 13 июля 2011

Вы можете попасть туда с inject:

def t(key)
    key.to_s.split('.').inject(@trans) { |h, k| h[k.to_sym] }
end

Проверка ошибок и проверка «нет такой записи» оставлена ​​в качестве упражнения.

1 голос
/ 08 января 2016

Поскольку в Ruby 2.3 Hash есть метод dig. встроена проверка «нет такой записи»: если какой-либо из ключей отсутствует, то все выражение возвращает nil. Использование:

@trans = { :links => {
    :quick_notes => "aaaaaaa"
  }
}

def t (str)
  syms = str.split(".").map(&:to_sym)
  @trans.dig(*syms)
end
p t('links.quick_notes')  # => "aaaaaaa"
1 голос
/ 08 января 2016

Если вы ищете что-то, что интерполирует %{variable}, включая поддержку массива, я использовал это:

def interpolate(string, hash)
  string.gsub(/%\{([^\}]*)\}/).each { |match| match[/^%{(.*)}$/, 1].split('.').inject(hash) { |h, k| h[(k.to_s == k.to_i.to_s) ? k.to_i : k.to_sym] } }
end
1 голос
/ 13 июля 2011

Для чего-то стоит вот какой-то хитрый код, который показывает использование рекурсии .

def getKeyChain (obj, parts)
  if !obj || parts.size == 0
    # this is the base case
    obj
  else
    # this is the recursive case
    key = parts[0]
    if key.match(/^:/)
      key = key[1..key.size].to_sym
    end
    # each time recursing, pass a new state.
    # in this case, the value for the "key" and the remaining parts
    # that need resolving
    getKeyChain(obj[key], parts[1..parts.size])
  end
end

def getCompoundKey (obj, compound)
  # helper makes it easier to call while not making the
  # recursive function more complex.
  getKeyChain(obj, compound.split("."))
end

h0 = {:x => "hello"}
h1 = {"a" => {:b => "world"}}
puts getCompoundKey(h0, ":x")   # => hello
puts getCompoundKey(h1, "a.:b") # => world

Многие улучшения могут быть сделаны ... "использовать на свой страх и риск".

Счастливого кодирования.

0 голосов
/ 06 марта 2013

Еще одно дополнение - если у вас есть json или хеш, который включает в себя массивы и хэши - возможно, что-то вроде этого:

@trans = { :links => [ {
    :quick_notes => "aaaaaaa"
  },
  {
    :quick_notes => "bbbbbbb"
  } ],
  :page => 1
}

Вы можете включить тест позиции в массиве, вы можете сделать этотакого рода вещи.

def t(key)
  key.split('.').inject(@trans) { |h,v| h.send('[]',v.to_i.to_s.eql?(v) ? v.to_i : v) }
end

Это позволит вам передать ключ, подобный этому

t('links.1.quick_notes')

и получить ответ 'bbbbbb'

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...