Rails加载YAML进行散列和符号引用
我在Rails 3.0.9中加载一个YAML文件,如下所示:
APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__)))
它加载所有的内容像分层哈希,没问题。 我不喜欢的部分是只能用单引号或双引号访问哈希,而不能使用符号。
APP_CONFIG['mailer']['username'] # works fine APP_CONFIG[:mailer][:username] # doesn't
有什么想法吗?
尝试使用HashWithIndifferentAccess之类的
APP_CONFIG = HashWithIndifferentAccess.new(YAML.load(File.read(File.expand_path('../app.yml', __FILE__))))
另一种解决scheme是将你想要访问的键作为一个符号前缀冒号。 例如:
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
。 (尽pipe我在这个例子中展示了心理,但是肯定不会支持关键合并。)
关于使用HashWithIndifferentAccess
:使用它具有创build重复键的副作用:一个用于符号访问,一个用于string访问。 如果您将YAML数据作为数组传递,这可能是邪恶的。 如果你使用这个解决scheme,请注意这一点。
如果您正在使用Ruby on Rails,则可能需要查看symbolize_keys() ,而这正是OP所要求的。 如果散列很深,可以使用deep_symbolize_keys()
。 使用这种方法,答案是
APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__))).deep_symbolize_keys
这与选定的答案是一样的,但语法更好:
YAML.load(File.read(file_path)).with_indifferent_access
我在挖掘时发现了另一个可能的答案。
您可以放弃HashWithIndifferentAccess.new,而是将其添加到您的YAML文件的顶部:
--- !map:HashWithIndifferentAccess
然后简单的YAML.load像正常。 唯一的诀窍就是如果你在你的环境中使用初始化工具等等(就像我)那样需要加载rails。
- Rails有一个特殊的方法来表示键。
- 您可以使用load_file方法并摆脱File.read
- 不知道你是否也需要expand_path,默认目录是rails的根目录。
我会写这么简单:
YAML::load_file('app.yml').symbolize_keys
你可能习惯了Rails中的params哈希,这实际上是一个HashWithIndifferentAccess而不是一个标准的ruby哈希对象。 这允许你使用像“action”这样的string或像action这样的符号来访问内容。
使用HashWithIndifferentAccess,无论使用什么,您都将得到相同的结果,但请记住,这只适用于HashWithIndifferentAccess对象。
所以为了使这个工作与YAML,你将不得不加载到HashWithIndifferentAccess的YAML.load的结果,如下所示:
APP_CONFIG = HashWithIndifferentAccess.new( YAML.load(File.read(File.expand_path('../app.yml', __FILE__))) )
如果你使用纯Ruby(即没有Rails),你可以中间更改为JSON格式。 JSON库的parse
方法可以表示键。
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转换的开销。