class Parascope::Query

Attributes

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

Public Class Methods

build(**attrs) click to toggle source
# File lib/parascope/query.rb, line 21
def self.build(**attrs)
  new({}, **attrs)
end
inherited(subclass) click to toggle source
# File lib/parascope/query.rb, line 12
def self.inherited(subclass)
  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.base_scope(&base_scope)
  subclass.defaults(defaults)
end
new(params, scope: nil, dataset: nil, **attrs) click to toggle source
# File lib/parascope/query.rb, line 33
def initialize(params, scope: nil, dataset: nil, **attrs)
  @params = Hashie::Mash.new(klass.fetch_defaults).merge(params || {})
  @scope  = scope || dataset unless scope.nil? && dataset.nil?
  @attrs  = attrs.freeze
  @base_params = @params
  define_attr_readers
end
raise_on_guard_violation(value) click to toggle source
# File lib/parascope/query.rb, line 25
def self.raise_on_guard_violation(value)
  @raise_on_guard_violation = !!value
end
raise_on_guard_violation?() click to toggle source
# File lib/parascope/query.rb, line 29
def self.raise_on_guard_violation?
  @raise_on_guard_violation
end

Public Instance Methods

base_dataset()
Alias for: base_scope
base_scope() click to toggle source
# File lib/parascope/query.rb, line 46
def base_scope
  scope = klass.ancestors
    .select{ |klass| klass < Query }
    .reverse
    .map(&:base_scope)
    .compact
    .reduce(nil){ |scope, block| instance_exec(scope, &block) }

  if scope.nil?
    fail UndefinedScopeError, "failed to build scope. Have you missed base_scope definition?"
  end

  scope
end
Also aliased as: base_dataset
dataset()
Alias for: scope
klass() click to toggle source
# File lib/parascope/query.rb, line 75
def klass
  sifted? ? singleton_class : self.class
end
resolve(*args)
Alias for: resolved_scope
resolved_dataset(*args)
Alias for: resolved_scope
resolved_scope(*args) click to toggle source
# File lib/parascope/query.rb, line 62
def resolved_scope(*args)
  @violation = nil
  arg_params = args.pop if args.last.is_a?(Hash)
  return sifted_instance.resolved_scope! if arg_params.nil? && args.empty?

  clone_with_params(trues(args).merge(arg_params || {})).resolved_scope
rescue GuardViolationError => error
  @violation = error.message
  raise if self.class.raise_on_guard_violation?
end
Also aliased as: resolved_dataset, resolve
scope() click to toggle source
# File lib/parascope/query.rb, line 41
def scope
  @scope ||= base_scope
end
Also aliased as: dataset

Protected Instance Methods

apply_block!() click to toggle source
# File lib/parascope/query.rb, line 98
def apply_block!
  if block && block.fits?(self)
    scope  = instance_exec(*block.values_for(params), &block.block)
    @scope = scope unless scope.nil?
  end
  self
end
clone_sifted_with(blocks) click to toggle source
# File lib/parascope/query.rb, line 139
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/parascope/query.rb, line 130
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('@scope') if query.instance_variable_defined?('@scope')
    query.define_attr_readers
  end
end
clone_with_scope(scope, block = nil) click to toggle source
# File lib/parascope/query.rb, line 123
def clone_with_scope(scope, block = nil)
  clone.tap do |query|
    query.scope = scope
    query.block = block
  end
end
define_attr_readers() click to toggle source
# File lib/parascope/query.rb, line 145
def define_attr_readers
  @attrs.each do |name, value|
    define_singleton_method(name){ value }
  end
end
resolved_scope!() click to toggle source
# File lib/parascope/query.rb, line 91
def resolved_scope!
  guard_all
  klass.sorted_query_blocks.reduce(scope) do |scope, block|
    clone_with_scope(scope, block).apply_block!.scope
  end
end
sifted!(query, blocks) click to toggle source
# File lib/parascope/query.rb, line 106
def sifted!(query, blocks)
  @attrs = query.attrs
  define_attr_readers
  singleton_class.query_blocks.replace(query.klass.query_blocks.dup)
  singleton_class.guard_blocks.replace(query.klass.guard_blocks.dup)
  singleton_class.base_scope(&query.klass.base_scope)
  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/parascope/query.rb, line 119
def sifted?
  !!@sifted
end
sifted_instance() click to toggle source
# File lib/parascope/query.rb, line 85
def sifted_instance
  blocks = klass.sift_blocks.select{ |block| block.fits?(self) }

  blocks.size > 0 ? sifted_instance_for(blocks) : self
end

Private Instance Methods

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

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

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