class Babl::Nodes::Merge

Constants

AS_OBJECT_MAPPING

Public Instance Methods

dependencies() click to toggle source
# File lib/babl/nodes/merge.rb, line 10
        def dependencies
    Babl::Utils::Hash.deep_merge(nodes.map(&:dependencies))
end
optimize() click to toggle source
# File lib/babl/nodes/merge.rb, line 22
        def optimize
    optimize_empty ||
        optimize_single ||
        optimize_nested_merges ||
        optimize_merged_objects ||
        optimize_premergeable_objects ||
        self
end
pinned_dependencies() click to toggle source
# File lib/babl/nodes/merge.rb, line 14
        def pinned_dependencies
    Babl::Utils::Hash.deep_merge(nodes.map(&:pinned_dependencies))
end
render(frame) click to toggle source
# File lib/babl/nodes/merge.rb, line 31
def render(frame)
    nodes.map { |node| node.render(frame) }.compact.reduce({}) { |acc, val|
        raise Errors::RenderingError, "Only objects can be merged\n" +
            frame.formatted_stack unless ::Hash === val
        acc.merge!(val)
    }
end
schema() click to toggle source
# File lib/babl/nodes/merge.rb, line 18
        def schema
    nodes.map(&:schema).reduce(Schema::Object::EMPTY) { |a, b| merge_doc(a, b) }
end

Private Instance Methods

anything_property(property) click to toggle source

Rewrite a property to allow Schema::Anything as value

# File lib/babl/nodes/merge.rb, line 143
def anything_property(property)
    Schema::Object::Property.new(property.name, Schema::Anything.instance, property.required)
end
constant_to_object(constant) click to toggle source
# File lib/babl/nodes/merge.rb, line 88
def constant_to_object(constant)
    case constant.schema
    when Schema::Object
        Object.new(constant.schema.property_set.map { |property|
            [property.name, Constant.new(constant.value[property.name], property.value)]
        }.to_h)
    when Schema::Primitive::NULL
        Object::EMPTY
    end
end
merge_doc(doc1, doc2) click to toggle source

Merge two documentations together

# File lib/babl/nodes/merge.rb, line 105
def merge_doc(doc1, doc2)
    doc1 = AS_OBJECT_MAPPING[doc1] || doc1
    doc2 = AS_OBJECT_MAPPING[doc2] || doc2

    case
    when Schema::AnyOf === doc1
        Schema::AnyOf.canonicalized(doc1.choice_set.map { |c| merge_doc(c, doc2) })
    when Schema::AnyOf === doc2
        Schema::AnyOf.canonicalized(doc2.choice_set.map { |c| merge_doc(doc1, c) })
    when Schema::Object === doc1 && Schema::Object === doc2
        merge_object(doc1, doc2)
    else raise Errors::InvalidTemplate, 'Only objects can be merged'
    end
end
merge_object(doc1, doc2) click to toggle source

Merge two Schema::Object

# File lib/babl/nodes/merge.rb, line 121
def merge_object(doc1, doc2)
    additional = doc1.additional || doc2.additional

    properties = (
        doc1.property_set.map { |property| doc2.additional ? anything_property(property) : property } +
        doc2.property_set.to_a
    ).each_with_object({}) { |property, acc|
        if property.required
            acc[property.name] = property
        else
            acc[property.name] = Schema::Object::Property.new(
                property.name,
                Schema::AnyOf.canonicalized([property.value, acc[property.name]&.value].compact),
                acc[property.name]&.required || false
            )
        end
    }.values

    Schema::Object.new(properties, additional)
end
optimize_empty() click to toggle source
# File lib/babl/nodes/merge.rb, line 41
def optimize_empty
    Constant.new(Utils::Hash::EMPTY, Schema::Object::EMPTY) if nodes.empty?
end
optimize_merged_objects() click to toggle source
# File lib/babl/nodes/merge.rb, line 60
def optimize_merged_objects
    optimized_nodes = nodes.map(&:optimize)
    return if optimized_nodes == nodes

    Merge.new(optimized_nodes).optimize
end
optimize_nested_merges() click to toggle source
# File lib/babl/nodes/merge.rb, line 67
def optimize_nested_merges
    return unless nodes.any? { |node| Merge === node }

    Merge.new(nodes.flat_map { |node| Merge === node ? node.nodes : [node] }).optimize
end
optimize_premergeable_objects() click to toggle source
# File lib/babl/nodes/merge.rb, line 73
def optimize_premergeable_objects
    nodes.each_cons(2).each_with_index do |(obj1, obj2), idx|
        obj1 = constant_to_object(obj1) if Constant === obj1
        obj2 = constant_to_object(obj2) if Constant === obj2

        next unless Object === obj1 && Object === obj2

        new_nodes = nodes.dup
        new_nodes[idx] = Object.new(obj1.nodes.merge(obj2.nodes))
        new_nodes[idx + 1] = nil
        return Merge.new(new_nodes.compact).optimize
    end
    nil
end
optimize_single() click to toggle source
# File lib/babl/nodes/merge.rb, line 45
def optimize_single
    return unless nodes.size == 1

    optimized = nodes.first.optimize

    case optimized
    when Object then optimized
    when Constant
        case optimized.value
        when ::Hash then optimized
        when ::NilClass then Object::EMPTY
        end
    end
end