Rails 将 YAML 加载到散列并按符号引用
Posted
技术标签:
【中文标题】Rails 将 YAML 加载到散列并按符号引用【英文标题】:Rails load YAML to hash and reference by symbol 【发布时间】:2011-10-27 17:30:36 【问题描述】:我在 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
有什么想法吗?
【问题讨论】:
【参考方案1】:Psych(又名 YAML)提供关键字参数 :symbolize_names
以将键加载为符号。 See method reference
file_path = File.expand_path('../app.yml', __FILE__)
yaml_contents = File.read(file_path)
APP_CONFIG = YAML.safe_load(yaml_contents, symbolize_names: true)
【讨论】:
【参考方案2】:只需在您的 YAML 解析器中使用适当的选项。例如,Psych 中的symbolize_names
:
APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__)), symbolize_names: true)
参见 RDoc:https://ruby-doc.org/stdlib-2.6.1/libdoc/psych/rdoc/Psych.html#method-c-load。
【讨论】:
【参考方案3】:我通常不使用HashWithIndifferentAccess
,只是为了避免混淆并防止访问方式不一致,所以我要做的是添加.deep_symbolize_keys
,以符号键形式获取整个内容。
【讨论】:
【参考方案4】:如果您正在使用 Ruby on Rails,您可能想看看 symbolize_keys(),它完全符合 OP 的要求。如果哈希很深,您可以使用deep_symbolize_keys()
。使用这种方法,答案是
APP_CONFIG = YAML.load(File.read(File.expand_path('../app.yml', __FILE__))).deep_symbolize_keys
【讨论】:
deep_symbolize_keys()
应该处理嵌套属性。
很好的解决方案,但它是 ActiveSupport 的一部分。但它适用于使用 Rails 的情况【参考方案5】:
如果您使用的是纯 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 之间的转换开销。
【讨论】:
【参考方案6】:-
Rails 有一种特殊的方法来符号化键。
您可以使用 load_file 方法并摆脱 File.read
不确定是否还需要expand_path,默认目录是rails root。
我会这么简单地写:
YAML::load_file('app.yml').symbolize_keys
【讨论】:
【参考方案7】:这与所选答案相同,但语法更好:
YAML.load(File.read(file_path)).with_indifferent_access
【讨论】:
【参考方案8】:尝试使用HashWithIndifferentAccess 点赞
APP_CONFIG = HashWithIndifferentAccess.new(YAML.load(File.read(File.expand_path('../app.yml', __FILE__))))
【讨论】:
感谢一百万个罗布。唯一的技巧是确保 Rails 已经加载。 看起来不错,但我不使用 ActiveSupport【参考方案9】:另一种解决方案是将您希望访问的键作为符号附加一个冒号。例如:
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 数据作为数组传递,这可能是有害的。如果您使用该解决方案,请注意这一点。
【讨论】:
这应该是正确的答案。默认情况下,YAML 属性不会被解析为符号,这对任何人来说可能并不明显。【参考方案10】:我在四处挖掘时发现了另一个可能的答案。
您可以放弃 HashWithIndifferentAccess.new,而是将其添加到 YAML 文件的顶部:
--- !map:HashWithIndifferentAccess
然后像往常一样简单地 YAML.load。唯一的技巧是,如果您在环境中执行此操作以用于初始化程序等,则需要已经加载 rails(就像我一样)。
【讨论】:
【参考方案11】:你可能已经习惯了 Rails 中的 params 哈希,它实际上是一个 HashWithIndifferentAccess 而不是标准的 ruby Hash 对象。这允许您使用像 'action' 这样的字符串或像 :action 这样的符号来访问内容。
使用 HashWithIndifferentAccess,无论您使用什么,您都将获得相同的结果,但请记住,这仅适用于 HashWithIndifferentAccess 对象。
因此,要使用 YAML,您必须将 YAML.load 的结果加载到 HashWithIndifferentAccess 中,如下所示:
APP_CONFIG = HashWithIndifferentAccess.new( YAML.load(File.read(File.expand_path('../app.yml', __FILE__))) )
【讨论】:
以上是关于Rails 将 YAML 加载到散列并按符号引用的主要内容,如果未能解决你的问题,请参考以下文章
下列代码的功能是利用散列函数hash将一个元素插入到散列表ht[]中。其中list类型的结点包含element类型的项item以及一个next指针。如果插入成功,则函数返回1,否则返回0。