我如何删除 Ruby DSL 中的重复部分

How could I remove duplicated sections in Ruby DSL

我目前的配置格式似乎太多余了。我怎样才能将它转换成下一个预期的配置格式?

我的预期配置是:

MoneyRails.configure do |config|

    register_currency("TWD", 100)
    register_currency("USD", 100)
    ....
end

我当前的配置是:

MoneyRails.configure do |config|

  config.register_currency = {
    :priority            => 1,
    :iso_code            => "TWD",
    :name                => "TWD",
    :symbol              => "NT$ ",
    :symbol_first        => true,
    :subunit             => "Subcent",
    :subunit_to_unit     => 100,
    :thousands_separator => ",",
    :decimal_mark        => "."
  }

  config.register_currency = {
    :priority            => 1,
    :iso_code            => "USD",
    :name                => "USD",
    :symbol              => "$ ",
    :symbol_first        => true,
    :subunit             => "Subcent",
    :subunit_to_unit     => 100,
    :thousands_separator => ",",
    :decimal_mark        => "."
  }

  config.register_currency = {
    :priority            => 1,
    :iso_code            => "SGD",
    :name                => "SGD",
    :symbol              => "$ ",
    :symbol_first        => true,
    :subunit             => "Subcent",
    :subunit_to_unit     => 100,
    :thousands_separator => ",",
    :decimal_mark        => "."
  }

  config.register_currency = {
    :priority            => 1,
    :iso_code            => "THB",
    :name                => "THB",
    :symbol              => "$ ",
    :symbol_first        => true,
    :subunit             => "Subcent",
    :subunit_to_unit     => 100,
    :thousands_separator => ",",
    :decimal_mark        => "."
  }

  config.register_currency = {
    :priority            => 1,
    :iso_code            => "AUD",
    :name                => "AUD",
    :symbol              => "$ ",
    :symbol_first        => true,
    :subunit             => "Subcent",
    :subunit_to_unit     => 100,
    :thousands_separator => ",",
    :decimal_mark        => "."
  }

  config.register_currency = {
    :priority            => 1,
    :iso_code            => "KRW",
    :name                => "KRW",
    :symbol              => "$ ",
    :symbol_first        => true,
    :subunit             => "Subcent",
    :subunit_to_unit     => 100,
    :thousands_separator => ",",
    :decimal_mark        => "."
  }

  ...

end

创建这个小模块怎么样?您只需要在配置对象中添加一个额外的属性:

module MoneyRails
  module MyApp
    def register_currency(config, name, subunit_to_unit)
      config.register_currency(options_hash(name, subunit_to_unit))
    end

    private

    def options_hash(name, subunit_to_unit)
      {
        :priority            => 1,
        :iso_code            => name,
        :name                => name,
        :symbol              => "$ ",
        :symbol_first        => true,
        :subunit             => "Subcent",
        :subunit_to_unit     => subunit_to_unit,
        :thousands_separator => ",",
        :decimal_mark        => "."
      }
    end
  end
end

请注意,我对其命名空间是为了不污染基本命名空间。将其更改为您的休闲。

然后:

include MoneyRails::MyApp

MoneyRails.configure do |config|

    register_currency(config, "TWD", 100)
    register_currency(config, "USD", 100)
    ....
end
default_options = {
    :priority            => 1,
    :iso_code            => 'USD',
    :name                => 'USD',
    :symbol              => "$ ",
    :symbol_first        => true,
    :subunit             => "Subcent",
    :subunit_to_unit     => 100,
    :thousands_separator => ",",
    :decimal_mark        => "."
}

MoneyRails.configure do |config|
  config.register_currency = default_options
  config.register_currency = default_options.merge(name: 'TWD', iso_code: 'TWD', symbol: 'NT$')
  config.register_currency = default_options.merge(name: 'THB', iso_code: 'THB')
  config.register_currency = default_options.merge(name: 'SGD')
end

merge 方法合并两个 Hash 实例和 returns 一个 Hash 对象。如果第二个 Hash 对象有一些键与第一个匹配,那么第二个 Hash 的 key => value replaces/overrides 前一个。

例外情况相对较少,所以我倾向于将它们放在一个文件中,每种货币一行,连同货币名称缩写。例如,一行可能是:

TWD SYM:"NT$ "

(或 TWD SYM:NT$ 如果 :symbol 的所有值最后都有一个 space)。

大多数行只有货币缩写,例如:

USD

然后您将读取该文件并将其解析为如下数组:

specific_bits = [
  ["TWD", { symbol: "NT$ " }],
  ["USD", {}],
  ["SGD", {} ],
  ["THB", { subunit_to_unit: 999 }],
  ["AUD", {}],
  ["KRW", {}],
  ["XYZ", { symbol: "XT$ ", subunit_to_unit: -5 }],
]

然后定义:

BASE_HASH = {
  priority:            1,
  symbol:              "$ ",
  symbol_first:        true,
  subunit:             "Subcent",
  subunit_to_unit:     100,
  thousands_separator: ",",
  decimal_mark:        "."
}

这使您可以非常简单地构建哈希:

specific_bits.map do |name, exceptions|
  h = { :iso_code => name, :name => name }
  exceptions.each { |k,v| h[k] = v }
  BASE_HASH.merge h
end
  #=> [{:priority=>1, :symbol=>"NT$ ", :symbol_first=>true,    :subunit=>"Subcent",
  #    :subunit_to_unit=>100, :thousands_separator=>",", :decimal_mark=>".",
  #    :iso_code=>"TWD", :name=>"TWD"},
  #    {...
  #    ...]

如果您希望按键按特定顺序排列,这是一个小调整。