class Zen::Query

Constants

GuardViolationError
UndefinedSubjectError
VERSION

Attributes

attrs[R]
block[RW]
params[RW]
subject[W]
violation[R]

Public Class Methods

inherited(subclass) click to toggle source
Calls superclass method
# File lib/zen/query.rb, line 19
def self.inherited(subclass) # rubocop:disable Metrics/AbcSize
  subclass.raise_on_guard_violation(raise_on_guard_violation?)
  subclass.query_blocks.replace(query_blocks.dup)
  subclass.sift_blocks.replace(sift_blocks.dup)
  subclass.guard_blocks.replace(guard_blocks.dup)
  subclass.subject(&subject)
  subclass.defaults(&defaults) unless defaults.nil?
  super
end
new(params: {}, **attrs) click to toggle source
Calls superclass method Zen::Query::Attributes::new
# File lib/zen/query.rb, line 29
def initialize(params: {}, **attrs)
  @params  = klass.fetch_defaults.merge(params)
  @subject = attrs.delete(self.class.subject_name)
  @base_params = @params
  super
end

Public Instance Methods

base_subject() click to toggle source
# File lib/zen/query.rb, line 40
def base_subject
  subject =
    klass
      .ancestors
      .select { |mod| mod.respond_to?(:subject) }
      .map(&:subject)
      .compact
      .first
      &.call

  raise UndefinedSubjectError, "failed to build subject. Have you missed subject definition?" if subject.nil?

  subject
end
klass() click to toggle source
# File lib/zen/query.rb, line 66
def klass
  sifted? ? singleton_class : self.class
end
resolve(*args) click to toggle source
# File lib/zen/query.rb, line 55
def resolve(*args)
  @violation = nil
  arg_params = args.pop if args.last.is_a?(Hash)
  return sifted_instance.resolve! if arg_params.nil? && args.empty?

  clone_with_params(trues(args).merge(arg_params || {})).resolve
rescue GuardViolationError => e
  @violation = e.message
  raise if self.class.raise_on_guard_violation?
end
subject() click to toggle source
# File lib/zen/query.rb, line 36
def subject
  @subject ||= base_subject
end

Protected Instance Methods

apply_block!() click to toggle source
# File lib/zen/query.rb, line 89
def apply_block!
  if block&.fits?(self)
    subject  = instance_exec(*block.values_for(params), &block.block)
    @subject = subject unless subject.nil?
  end
  self
end
clone_sifted_with(blocks) click to toggle source
# File lib/zen/query.rb, line 127
def clone_sifted_with(blocks)
  dup.tap do |query|
    query.sifted!(self, blocks)
  end
end
clone_with_params(other_params) click to toggle source
# File lib/zen/query.rb, line 119
def clone_with_params(other_params)
  dup.tap do |query|
    query.params = @base_params.merge(other_params)
    query.remove_instance_variable("@sifted") if query.instance_variable_defined?("@sifted")
    query.remove_instance_variable("@subject") if query.instance_variable_defined?("@subject")
  end
end
clone_with_subject(subject, block = nil) click to toggle source
# File lib/zen/query.rb, line 112
def clone_with_subject(subject, block = nil)
  clone.tap do |query|
    query.subject = subject
    query.block = block
  end
end
resolve!() click to toggle source
# File lib/zen/query.rb, line 82
def resolve!
  guard_all
  klass.sorted_query_blocks.reduce(subject) do |subject, block|
    clone_with_subject(subject, block).apply_block!.subject
  end
end
sifted!(query, blocks) click to toggle source
# File lib/zen/query.rb, line 97
def sifted!(query, blocks) # rubocop:disable Metrics/AbcSize
  singleton_class.query_blocks.replace(query.klass.query_blocks.dup)
  singleton_class.guard_blocks.replace(query.klass.guard_blocks.dup)
  singleton_class.subject(&query.klass.subject)
  blocks.each do |block|
    singleton_class.instance_exec(*block.values_for(params), &block.block)
  end
  params.replace(singleton_class.fetch_defaults.merge(params))
  @sifted = true
end
sifted?() click to toggle source
# File lib/zen/query.rb, line 108
def sifted?
  !!@sifted
end
sifted_instance() click to toggle source
# File lib/zen/query.rb, line 76
def sifted_instance
  blocks = klass.sift_blocks.select { |block| block.fits?(self) }

  blocks.empty? ? self : sifted_instance_for(blocks)
end

Private Instance Methods

guard(message = nil, &block) click to toggle source
# File lib/zen/query.rb, line 139
def guard(message = nil, &block)
  return if instance_exec(&block)

  violation = message || "guard block violated on #{block.source_location.join(':')}"

  raise GuardViolationError, violation
end
guard_all() click to toggle source
# File lib/zen/query.rb, line 135
def guard_all
  klass.guard_blocks.each { |message, block| guard(message, &block) }
end
sifted_instance_for(blocks) click to toggle source
# File lib/zen/query.rb, line 147
def sifted_instance_for(blocks)
  clone_sifted_with(blocks).sifted_instance
end
trues(keys) click to toggle source
# File lib/zen/query.rb, line 151
def trues(keys)
  keys.each_with_object({}) do |key, hash|
    hash[key] = true
  end
end