# frozen_string_literal: true # This should be a kind of factory that creates complex objects # from simple ones. It should use torirori to create objects. # It also enriches objects with some methods that make them more # like linked lists. module Nina # Generates module that adds support for objects creation class Builder attr_reader :name, :abstract_factory, :def_block, :callbacks # Definaes support methods and variables for concrete builder module ClassMethods def build_order_list @build_order_list ||= [] end def build_order_list=(other) @build_order_list = other.dup.freeze end def inherited(subclass) super subclass.build_order_list = build_order_list.dup.freeze end def factory(name, *args, **kwargs, &block) build_order_list << name super define_singleton_method(name) do |klass = nil, &definition| factories[__method__].subclass(produces: klass, &definition) end end end def initialize(name, abstract_factory: nil, callbacks: nil, &def_block) @name = name @def_block = def_block @abstract_factory = abstract_factory.include(Toritori).extend(ClassMethods) @abstract_factory.class_eval(&def_block) if def_block @abstract_factory.build_order_list.freeze @assembler = Assembler.new(@abstract_factory, callbacks) @assembler.add_observer(self) @observers = [] end def add_observer(observer) @observers << observer end def copy new_builder = self.class.new(name, abstract_factory: abstract_factory, callbacks: @assembler.callbacks) @observers.each { |observer| new_builder.add_observer(observer) } new_builder end def with_callbacks(&block) yield @assembler.callbacks if block copy end def wrap(delegate: false, &block) yield @assembler.initialization if block @assembler.inject(@abstract_factory.build_order_list, delegate: delegate) end def nest(delegate: false, &block) yield @assembler.initialization if block @assembler.inject(@abstract_factory.build_order_list.reverse, delegate: delegate) end def subclass(&def_block) return unless def_block @abstract_factory = Class.new(abstract_factory) @abstract_factory.class_eval(&def_block) @abstract_factory.build_order_list.freeze @assembler = Assembler.new(@abstract_factory, @assembler.callbacks) end def update(name, object) @observers.each do |observer| observer.public_send(:"on_#{name}_created", object) if observer.respond_to?(:"on_#{name}_created") end end end end