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。

熊猫使用正则表达式选择列并按值除

添加列并按类别分隔

有没有办法用rails引用yaml中的常量?

ruby 使用Rails ENV VARS加载YAML文件

合并两列并按 asc 排序