我知道这很简单,但是我很难从JSon数据文件中获得想要的值。
我有两个文件,一个叫做test.rb,看起来像这样:
require_relative 'suppliers_data'
class SelectSupplier
def self.suppliers
suppliers.sort_by { |e| e[:advitam_grade].to_i }.reverse
end
end
和另一个名为Suppliers_data的样子:
suppliers = [
{ name: "FunePlus",
advitam_grade: 3,
works: [
{ type: "embalming", price: 350 },
{type: "transport_before_casketing", price: 450} ]},
{ name: "FuneTop",
works: [
{ type: "graving", price: 10} ]},
{ name: "FuneTruc",
advitam_grade: 5,
works: [
{ type: "embalming", price: 750} ]},
{ name: "FuneCorp",
advitam_grade: 2,
works: [
{ type: "digging", price: 350} ]}
]
您可能会想像,我的def self.suppliers
无法正常工作,并且出现此错误suppliers': stack level too deep
我试图环顾四周我做错了什么,但没有发现真正有趣的东西。
你们有没有解决办法?
谢谢。
答案 0 :(得分:1)
此错误的原因是无限的递归
def self.suppliers
suppliers. # calls itself recursively
sort_by { |e| e[:advitam_grade].to_i }.reverse
end
答案 1 :(得分:0)
您所做的完全错误(ruby本机不支持将未序列化的对象从磁盘存储/加载到磁盘,或将其加载到磁盘,),但是它是ruby的,并且一切正常:
class SelectSupplier
def self.suppliers
instance_eval '@' << File.read('suppliers_data')
@suppliers.sort_by { |e| e[:advitam_grade].to_i }.reverse
end
end
此任务的正确解决方案是将数据序列化为JSON或YAML,加载文件并反序列化数据。
答案 2 :(得分:0)
发生“堆栈级别太深”异常的原因是SelectSupplier::suppliers
调用自身而不是变量。这是因为变量超出范围。您可以通过以下两种方法之一解决此问题。
使用常量定义。
要将变量变成常量,必须大写名称。此外,常数通常是常数,就象名称所暗示的那样。为了防止更改,通常会冻结这些值。由于常量的数据结构相对复杂,冻结过程非常复杂。通常,常量用于简单的事情,例如星期几或允许的选项。因此,我不建议使用常量。
SUPPLIERS = [
{
name: 'FunePlus',
advitam_grade: 3,
works: [
{type: 'embalming', price: 350},
{type: 'transport_before_casketing', price: 450},
],
}, # {
# ...
# }
].freeze.each do |supplier|
supplier.freeze.each_value(&:freeze)
supplier[:works].each(&:freeze).each { |work| work.each_value(&:freeze) }
end
然后在您的方法中使用SUPPLIERS
而不是suppliers
。
使用全局变量。
应避免使用全局变量,但这是一个选择。要创建全局变量,您必须在变量前加上$
。
$supliers = [
# ...
]
然后在您的方法中使用$suppliers
而不是suppliers
。
以上两种解决方案都不好,这是由于您的设计。如果您打算将这些值保存在内存中,则最好使用一个类。这样,您可以为实例添加一些自定义方法。以下内容可能会让您了解此类的外观:
class Supplier
@suppliers = [
# ...
]
class << self
attr_reader :suppliers
# initialize an instance with an id
def find(id)
supplier = suppliers[id]
return unless supplier
new(id: id, **suppliers)
end
# initialize an instance with an attribute
def find_by(attributes)
supplier = suppliers.find do |supplier|
attributes.all? { |attr, val| supplier[attr] == val }
end
return unless supplier
new(id: suppliers.index(supplier), **supplier)
end
end
# create getters for attributes
attr_reader :id, :name, :advitam_grade, :works
def initialize(attributes = {})
@id = attributes.delete(:id)
attributes.each { |attr, value| public_send("#{attr}=", value) }
@initialized = true
end
# create setters that update the source hash if the instance is
# initialized
%i[name advitam_grade works].each do |symbol|
define_method("#{symbol}=") do |value|
instance_variable_set("@#{symbol}", value)
# you can't use return in a block, so instead use break
break unless @initialized
update(symbol)
end
end
# return the source hash
def source
klass[id]
end
private
# update the source hash with the instance attribute value
def update(attr)
klass[id][attr] = public_send(attr)
end
def klass
self.class
end
end