Проблемы с вызовом данных из другого файла - PullRequest
0 голосов
/ 29 июня 2018

Я знаю, что это довольно просто, но у меня возникают проблемы с получением нужного значения из файла данных JSon.

У меня есть два файла, один называется test.rb и выглядит так:

require_relative 'suppliers_data' 

class SelectSupplier
  def self.suppliers
    suppliers.sort_by { |e| e[:advitam_grade].to_i }.reverse
  end
end

, а другие, называемые supplier_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

Я пытался осмотреться, что я сделал неправильно, но не нашел чего-то действительно интересного.

есть ли у кого-нибудь из вас решение?

Спасибо.

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Вы делаете это неправильно (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, загрузка файла и десериализация данных обратно.

0 голосов
/ 29 июня 2018

Причина исключения «слишком большой уровень стека» состоит в том, что SelectSupplier::suppliers вызывает себя вместо переменной. Это потому, что переменная находится вне области видимости. Вы можете решить это одним из двух способов.

  1. Использование определения константы.

    Чтобы превратить переменную в константу, вы должны прописать имя в регистре. Кроме того, константы обычно постоянны, как следует из названия. Чтобы предотвратить изменения, вы обычно замораживаете значения. Поскольку ваша структура данных относительно сложна для константы, процесс замораживания довольно сложен. Обычно константы используются для простых вещей, таких как дни недели или разрешенные опции. По этой причине я бы не рекомендовал использовать константу.

    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 в вашем методе.

  2. Использование глобальной переменной.

    Глобальных переменных следует избегать, но, тем не менее, это вариант. Чтобы создать глобальную переменную, вы должны префикс вашей переменной с $.

    $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
0 голосов
/ 29 июня 2018

причина этой ошибки - неограниченная рекурсия

def self.suppliers
    suppliers. # calls itself recursively
      sort_by { |e| e[:advitam_grade].to_i }.reverse

end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...