Вернуть массив элементов, удовлетворяющих указанному правилу c - PullRequest
1 голос
/ 09 января 2020

У меня есть пример класса, который действует как правило, как показано ниже, и они будут больше правил в будущем. В этом случае он проверяет, является ли предмет страховкой, и если это так, то в игру вступает метод satisfied?:

class ItemAvailabilityRule
  def applicable?(item:)
    item.name == Item::INSURANCE
  end

  def satisfied?(bookable:, item:)
    applicable?(item) && bookable.duration_in_days < 365
  end
end

У меня есть другой класс, который применяет правила к предметам, как показано ниже:

class ItemsAvailabilityPolicy
  def initialize(rules: [])
    @rules = rules
  end

  def apply(bookable:, items:)
    items.map do |item|
      applicable_rules = rules.select { |rule| rule&.applicable?(item: item) && rule&.applicable?(bookable: bookable, item: item) }
      applicable_rules.detect { |rule| !rule.satisfied?(bookable: bookable, item: item) }
    end
  end
end

Мой метод применения не совсем правильный, я думаю ..

Что я хочу достичь с помощью этого метода применения, так это то, что для отдельного элемента, использующего это: applicable_rules = rules.select { |rule| rule.applicable?(item: item) } даст мне все правила, которые применяются к этому пункту. Затем я хочу проверить, есть ли хотя бы одно неудовлетворенное правило, для которого я сделал: applicable_rules.detect { |rule| !rule.satisfied?(bookable: bookable, item: item) }

Затем я хочу удалить из массива элементы, которые не удовлетворяют всем применимым правилам, и возвращает массив с только те, которые удовлетворяют правилу .. Как я могу этого достичь?

Ответы [ 2 ]

1 голос
/ 09 января 2020

Если я правильно вас понял (как спросил Стефан), вы хотите вернуть все товары, удовлетворяющие всем применимым правилам? И у вас есть «бронируемый» объект, который вы хотите проверить по всем элементам в коллекции. Это предполагает, что каждое правило будет применяться одинаково (то есть с одинаковыми переменными и т. Д. c)

Вам не нужно здесь использовать какие-либо локальные переменные, поскольку Array#select - это то, что вам нужно (для элементы), и вы можете снова использовать select для применимых правил и цепочку, которая с помощью Array#all? гарантирует, что элемент (который вы, возможно, выбираете) проходит все (применимые) правила ....

Вот код (легче понять, чем объяснение!)

class ItemsAvailabilityPolicy
  def initialize(rules: [])
    @rules = rules
  end

  def apply(bookable:, items:)
    items.select do |item|
      @rules.select { |rule| rule.applicable?(item: item) }.all? do |rule|
        rule.satisfied?(bookable: bookable, item: item)
      end
    end
  end
end

Примечание: я использовал @rules, потому что вы использовали экземпляр var, а не attr_reader или attr_accessor

Надеюсь, что это поможет

1 голос
/ 09 января 2020

У вас почти было это:

class ItemsAvailabilityPolicy
  def initialize(rules: [])
    @rules = rules
  end

  def apply(bookable:, items:)
    items.select do |item|
      applicable_rules = rules.select { |rule| rule&.applicable?(item: item) && rule&.applicable?(bookable: bookable,
 item: item) }
      non_satisfactory = applicable_rules.detect { |rule| !rule.satisfied?(bookable: bookable, item: item) }
      non_satisfactory.blank?
    end
  end
end

Изменения минимальны, сначала измените map на select, поэтому вы выбираете только те элементы, которые возвращают true из вашего блока. Enumerable#select нужен верный или ложный возврат от каждого элемента в блоке, поэтому мы используем blank?.

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