Rails загружает YAML в хеш и ссылается на символ - PullRequest
62 голосов
/ 16 августа 2011

Я загружаю файл YAML в Rails 3.0.9 следующим образом:

APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__)))

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

APP_CONFIG['mailer']['username']  # works fine
APP_CONFIG[:mailer][:username]    # doesn't

Есть мысли?

Ответы [ 9 ]

74 голосов
/ 16 августа 2011

Попробуйте использовать HashWithIndifferentAccess как

APP_CONFIG = HashWithIndifferentAccess.new(YAML.load(File.read(File.expand_path('../app.yml', __FILE__))))
33 голосов
/ 31 марта 2012

Альтернативное решение состоит в том, чтобы иметь ключи, к которым вы хотите получить доступ, в качестве символа с добавлением двоеточия.Например:

default: &default
  :symbol: "Accessed via a symbol only"
  string: "Accessed via a string only"

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default

Позже вы можете получить к ним доступ следующим образом:

APP_CONFIG[:symbol]
APP_CONFIG['string']

Обратите внимание, что я использую YAML::ENGINE.yamler = "syck".Не уверен, что это работает с psych.(Psych определенно не будет поддерживать слияние ключей, как я показал в примере.)

Об использовании HashWithIndifferentAccess: использование его имеет побочный эффект создания дублирующих ключей: один для символадоступ и один для доступа к строке.Это может быть гнусно, если вы передаете данные YAML в виде массивов.Знайте об этом, если вы идете с этим решением.

27 голосов
/ 04 мая 2012

Если вы работаете в Ruby on Rails, вы можете взглянуть на symbolize_keys () , которая делает именно то, что запрашивал OP.Если хеш глубокий, вы можете использовать deep_symbolize_keys().Используя этот подход, ответ будет

APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__))).deep_symbolize_keys
16 голосов
/ 17 февраля 2014

Это то же самое из выбранного ответа, но с лучшим синтаксисом:

YAML.load(File.read(file_path)).with_indifferent_access 
11 голосов
/ 21 августа 2011

Есть еще один потенциальный ответ, который я обнаружил, копаясь вокруг.

Вы можете отказаться от HashWithIndifferentAccess.new, добавив вместо этого в начало своих файлов YAML:

--- !map:HashWithIndifferentAccess

, а затем просто YAML.load как обычно.Единственная хитрость в том, что рельсы должны быть уже загружены, если вы делаете это в своей среде для использования в инициализаторах и т. Д. (Как я).

7 голосов
/ 17 апреля 2014
  1. В Rails есть специальный метод для обозначения ключей.
  2. Вы можете использовать метод load_file и избавиться от File.read
  3. Не уверен, что если вам нужен также файл expand_path, каталогом по умолчанию является rails root.

Я бы написал так просто:

YAML::load_file('app.yml').symbolize_keys

2 голосов
/ 14 января 2016

Если вы используете чистый Ruby (то есть без Rails), вы можете промежуточно перейти на формат JSON.Метод parse в библиотеке JSON может символизировать ключи.

http://ruby -doc.org / stdlib-2.0.0 / libdoc / json / rdoc / JSON.html # method-i-parse

Вот что я имею в виду:

JSON.parse(JSON.dump(YAML.load_file(File.expand_path('../app.yml', __FILE__))), symbolize_names: true)

Примечание : Это добавляет накладные расходы на преобразование в json и из него.

2 голосов
/ 16 августа 2011

Вы, вероятно, привыкли к хешу params в Rails, который на самом деле является HashWithIndifferentAccess, а не стандартным хэш-объектом ruby.Это позволяет вам использовать либо строки, такие как «действие», либо символы, такие как: действие, для доступа к содержимому.

С HashWithIndifferentAccess вы получите те же результаты независимо от того, что вы используете, но имейте в виду, что это работает толькодля объектов HashWithIndifferentAccess.

Итак, чтобы эта работа работала с YAML, вам нужно загрузить результат YAML.load в HashWithIndifferentAccess, например, так:

APP_CONFIG = HashWithIndifferentAccess.new(   YAML.load(File.read(File.expand_path('../app.yml', __FILE__)))   )
0 голосов
/ 05 мая 2018

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

...