我无法将我的ruby对象序列化为json,更具体地说是数字的格式。 我已经写了一个rspec测试来更准确地说明我的问题。
expected = '{ "foo": 1.00, "bar": 4.50, "abc": 0.00, "xyz": 1.23 }'
it 'serializes as expected' do
my_hash = { "foo": 1, "bar": 4.5, "abc": 0, "xyz": 1.23}
expect(my_to_json_method(my_hash)).to eq expected
end
这是我遇到麻烦的情况。我可以使用sprintf但是如何获得字符串输出,如上例所示?
答案 0 :(得分:4)
首先,您不应该使用浮点数来表示货币价值。相反,让我们使用更合适的类型:(还有Ruby Money gem)
require 'bigdecimal'
my_hash = {
foo: BigDecimal.new('1.00'),
bar: BigDecimal.new('4.50'),
abc: BigDecimal.new('0.00'),
xyz: BigDecimal.new('1.23')
}
有几种选择来代表货币价值。根据JSON规范,所有以下JSON字符串都是有效的,并且在解析时都需要特殊处理。您可以选择最合适的。
注意:我正在实现一个自定义
to_json
方法,使用Ruby的默认JSON库将BigDecimal
实例转换为JSON。这仅用于演示目的,通常不应修补核心(或stdlib)类。
这就是你要求的。请注意,默认情况下,许多JSON库会将这些数字解析为浮点值。
class BigDecimal
def to_json(*)
'%.2f' % self
end
end
puts my_hash.to_json
输出:
{"foo":1.00,"bar":4.50,"abc":0.00,"xyz":1.23}
这将适用于所有JSON库,但将数字存储为字符串对我来说并不合适。
class BigDecimal
def to_json(*)
'"%.2f"' % self
end
end
puts my_hash.to_json
输出:
{"foo":"1.00","bar":"4.50","abc":"0.00","xyz":"1.23"}
您只需输出美分作为整数,而不是将货币值表示为小数。这就是我通常做的事情。
class BigDecimal
def to_json(*)
(self * 100).to_i.to_s
end
end
puts my_hash.to_json
输出:
{"foo":100,"bar":450,"abc":0,"xyz":123}
答案 1 :(得分:0)
用户Sprintf
sprintf('%。2f',5.5)
简单地插入您的JSON作为ERB模板。
答案 2 :(得分:0)
您可以使用sprintf
,并且可以通过提及%.(number)f
获取所需的小数点。
例如:两位小数,%.2f
这是一个真正的实现,
2.2.2 :019 > test = { "foo": (sprintf "%.2f","1.11"), "bar": (sprintf "%.2f","4.55"), "abc": (sprintf "%.2f","0.2") }
=> {:foo=>"1.11", :bar=>"4.55", :abc=>"0.20"}
答案 3 :(得分:0)
puts '{' << my_hash.map { |k, v| %Q|"#{k}": #{"%.2f" % v}| }.join(', ') << '}'
#⇒ {"foo": 1.00, "bar": 4.50, "abc": 0.00, "xyz": 1.23}