lib/cql/map_reduce.rb
require 'cql/dsl'
require 'cql/feature_filters'
require 'cql/sso_filters'
require 'cql/dsl'
module CQL
# Not a part of the public API. Subject to change at any time.
class MapReduce
extend Dsl
# Recursively gathers all models that match the given targets and filters
def self.gather_objects(current_object, target_classes, filters)
gathered_objects = [].tap { |objects| collect_all_in(target_classes, current_object, objects) }
if filters
filters.each do |filter|
negate = filter[:negate]
filter = filter[:filter]
# Non-targeted filter, will apply to all objects
if filter.is_a?(Proc)
gathered_objects = filter_with_proc(gathered_objects, filter, negate)
# Targeted filter, will only apply to certain objects
elsif filter.is_a?(Hash)
filter.each_key do |filtered_class|
clazz = determine_class(filtered_class)
gathered_objects = gathered_objects.select do |object|
# A class that is targeted by the filter, so proceed with determination
if object.is_a?(clazz)
# Block filter
if filter[filtered_class].is_a?(Proc)
filter[filtered_class].call(object) && !negate
# Must be a predefined filter otherwise
else
!filter_with_predefined([object], filter[filtered_class], negate).empty?
end
# Not a class that is targeted by the filter, so include it
else
true
end
end
end
# Must be a predefined filter otherwise
else
gathered_objects = filter_with_predefined(gathered_objects, filter, negate)
end
end
end
gathered_objects
end
class << self
private
def filter_with_proc(objects, filter, negate)
if negate
objects.reject(&filter)
else
objects.select(&filter)
end
end
def filter_with_predefined(objects, filter, negate)
filter.execute(objects, negate)
end
# Recursively gathers all objects of the given class(es) found in the passed object (including itself).
def collect_all_in(targeted_classes, current_object, accumulated_objects)
accumulated_objects << current_object if targeted_classes.any? { |targeted_class| (targeted_class == :all) || current_object.is_a?(targeted_class) }
method_for_children = Gem.loaded_specs['cuke_modeler'].version.version[/^0/] ? :contains : :children
return unless current_object.respond_to?(method_for_children)
current_object.send(method_for_children).each do |child_object|
collect_all_in(targeted_classes, child_object, accumulated_objects)
end
end
end
end
end