Module: BuildingBlocks::Builders::BuilderBuilder::ClassInstanceMethods

Includes:
Forwardable
Defined in:
lib/building_blocks/builders/builder_builder.rb

Overview

Methods available to classes generated by BuilderBuilder. Provides a generic, declarative DSL for describing custom builder classes.

Constant Summary collapse

DEFAULT_INITIALIZE_WITH =

The default means by which a new instance of the resource class is initialized.

See Also:

  • BuildingBlocks::Builders::BuilderBuilder::ClassInstanceMethods.{ClassInstanceMethods{ClassInstanceMethods#initialize_with)
lambda { |instance| resource_class.new }

Instance Method Summary collapse

Instance Method Details

#attribute(attr_name, receiver_method = :"#{attr_name}=", receiver = nil) ⇒ Symbol

Declares a delegate method that will be available to instances of the generated builder class that describes a simple attribute that can be delegated directly to an existing method affiliated with the object instance being built.

Though the underlying use of delegate gives this method an enormous amount of potential power, the attribute method is intended for use in fairly simple situations where delegation is required and the attribute descriptor provides some semantic value. More complex interactions should consider using the delegate method directly to give library users some insight into the intention for more complex behavior.

Parameters:

  • attr_name (String, Symbol)

    The name of the method that will be available to instances of the generated builder class that when invoked will trigger the receiver_method on the receiver.

  • receiver_method (String, Symbol) (defaults to: :"#{attr_name}=")

    The name of the method that should be invoked on the receiver object when the attr_name method is invoked. Defaults to a setter form of attr_name.

  • receiver (String, Symbol) (defaults to: nil)

    The object or method of the generated builder instance that should receive invocations of receiver_method when the attr_name method is called. Defaults to the object instance being built.

    If a String or Symbol value is provided for receiver, the value provided is resolved against the object instance being built at runtime to determine the appropriate receiver.

    For example if a value of :foo were provided for the receiver argument, at runtime, the receiver would be resolved to the object returned by invoking :foo on the object instance being built. Once resolved, the receiver_method would then be invoked on the receiver with any approprate arguments.

Returns:

  • (Symbol)

    The Symbol identifier form of attr_name identifying the method that will be available to instances of the generated builder class.

See Also:


76
77
78
79
# File 'lib/building_blocks/builders/builder_builder.rb', line 76

def attribute(attr_name, receiver_method = :"#{attr_name}=", receiver = nil)
  delegate(attr_name, receiver_method, receiver)
  return attr_name.to_sym
end

#buildObject

By default, builds a new instance of the configured resource class. This is achieved by evaluating the configured #initialize_with proc in the context of an instance of the generated builder class to generate a new object that will be used by the builder instance. If a block is given, the block is evaluated in the context of the builder instance after initialization.

Parameters:

  • block (Proc)

    Optional block evaluated by the generated builder class instance after the object instance being built has been initialized.

Returns:

See Also:


93
94
95
96
97
98
# File 'lib/building_blocks/builders/builder_builder.rb', line 93

def build
  instance = instance_eval(&self.initialize_with)
  builder = new(instance)
  builder.instance_eval(&Proc.new) if block_given?
  instance
end

#builder(attr_name, receiver_method = "#{attr_name}=", builder_class = nil, receiver = nil) ⇒ Symbol

Declares a method, attr_name, available to instances of the generated builder class, that when called delegates to a builder_class to generate an object that is then passed to the receiver_method of the receiver.

If a builder_class is given, the provided builder_class is used to generate the object for the receiver. If no builder_class is given and instead a block is provided, the given block is treated as an anonymous builder definition that is passed to BuildingBlocks.build to generate a new builder class that will be used later when attr_name is invoked on an instance of the generated builder class.

See InstanceMethods#example_builder_attr for details of the method invoked when attr_name is called on an instance of the generated builder class.

Parameters:

  • attr_name (String, Symbol)

    The name that will be used to define the method that will be available to instances of the generated builder class that when invoked will trigger the builder_class.

  • receiver_method (String, Symbol) (defaults to: "#{attr_name}=")

    The name of the method that should be invoked upon the receiver object when the attr_name method is invoked. Defaults to a setter form of attr_name.

  • builder_class (Class) (defaults to: nil)

    The builder class that should be used to generate new objects when the attr_name method is invoked. Cannot be used in conjunction with a given block.

  • receiver (Proc, String, Symbol) (defaults to: nil)

    The object or method of the generated builder instance that should receive invocations of receiver_method when the attr_name method is called. Defaults to the object instance being built.

    If a String or Symbol value is provided for receiver, the value provided is resolved against the object instance being built at runtime to determine the appropriate receiver.

    For example if a value of :foo were provided for the receiver argument, at runtime, the receiver would be resolved to the object returned by invoking :foo on the object instance being built. Once resolved, the receiver_method would then be invoked on the receiver with any approprate arguments.

    If a Proc is provided for the receiver argument, the Proc will be evaluated at runtime in the context of the object instance being built and should return the intended receiver object.

  • block (Proc)

    A block may be provided in place of a predefined builder_class. If such a block is provided, the given block is evaluated by BuildingBlocks.build to generate a new anonymous builder class. Cannot be used in conjunction with a predefined builder_class.

Returns:

  • (Symbol)

    The Symbol identifier form of attr_name identifying the method that will be available to instances of the generated builder class.

Raises:

  • (ArgumentError)

    Raised if both a builder_class and a block are given or neither a builder_class nor block are given.

See Also:


163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/building_blocks/builders/builder_builder.rb', line 163

def builder(attr_name, receiver_method = "#{attr_name}=", builder_class = nil, receiver = nil)
  if block_given? ^ builder_class.nil?
    raise ArgumentError, 'Either a builder class or a builder definition is required'
  elsif block_given?
    builder_class = BuildingBlocks.build(&Proc.new)
  end

  if receiver.is_a?(Proc)
    receiver_proc = receiver
  elsif receiver.is_a?(Symbol) || receiver.is_a?(String)
    receiver_proc = instance_eval("lambda { |i| @instance.#{receiver} }")
  else
    receiver_proc = lambda { |i| @instance }
  end

  define_builder_method(attr_name, receiver_method, builder_class, receiver_proc)
  attr_name.to_sym
end

#define_builder_method(attr_name, receiver_method, builder_class, receiver_proc) ⇒ Object (private)

Handles the wiring required to invoke a builder when attr_name is invoked.


276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/building_blocks/builders/builder_builder.rb', line 276

def define_builder_method(attr_name, receiver_method, builder_class, receiver_proc)
  define_method(attr_name) do |existing_object = nil, &block|
    begin
      if block.nil? ^ !!existing_object
        raise ArgumentError, 'Either a static instance or a builder proc is required'
      end
      receiver = instance_eval(&receiver_proc)
      instance = block.nil? ? existing_object : builder_class.build(&block)
      receiver.send(receiver_method, instance)
      instance
    rescue Exception
      $@.delete_if{|s| %r"#{Regexp.quote(__FILE__)}"o =~ s}
      ::Kernel::raise
    end
  end
end

#delegate(attr_name, receiver_method = attr_name, receiver = nil) ⇒ Symbol

Declares a delegate method that will be available to instances of the generated builder class that describes a behavior that should be delegated from the builder instance to the receiver_method of the derived receiver.

Parameters:

  • attr_name (String, Symbol)

    An identifer that will be used to name the delegate method defined on the builder instance.

  • receiver_method (String, Symbol) (defaults to: attr_name)

    The method that should be invoked on the receiver when the delegate method is invoked. Defaults to the same value provided for attr_name.

  • receiver (String, Symbol) (defaults to: nil)

    The object or method of the generated builder instance that should receive invocations of receiver_method when the attr_name method is called. Defaults to the object instance being built.

    If a String or Symbol value is provided for receiver, the value provided is resolved against the object instance being built at runtime to determine the appropriate receiver.

    For example if a value of :foo were provided for the receiver argument, at runtime, the receiver would be resolved to the object returned by invoking :foo on the object instance being built. Once resolved, the receiver_method would then be invoked on the receiver with any approprate arguments.

Returns:

  • (Symbol)

    The Symbol identifier form of attr_name identifying the method that will be available to instances of the generated builder class.


212
213
214
215
216
# File 'lib/building_blocks/builders/builder_builder.rb', line 212

def delegate(attr_name, receiver_method = attr_name, receiver = nil)
  receiver = receiver.nil? || receiver.empty? ? :@instance : :"@instance.#{receiver}"
  def_delegator(receiver, receiver_method, attr_name)
  attr_name.to_sym
end

#initialize_withProc

When no block is given, returns the proc currently configured to be invoked when a new instance of resource class is needed. If a custom proc has not been configured, returns the default initialization proc.

When a block is given, the method acts as a setter and the provided block is preserved and later used to initialize new instances of resource class as they are required.

Returns:

  • (Proc)

    The proc that will be used to initialize new instances of resource class.


228
229
230
231
# File 'lib/building_blocks/builders/builder_builder.rb', line 228

def initialize_with
  @initialize_with = Proc.new if block_given?
  @initialize_with || DEFAULT_INITIALIZE_WITH
end

#initialize_with=(initializer) ⇒ Proc

Sets a custom proc to be used when initializing new instances of resource class.

Parameters:

  • initializer (Proc)

    The proc to be used to initialize new instances or resource class.

Returns:

  • (Proc)

    The initializer argument provided is returned.

Raises:

  • (ArgumentError)

    Raised if the provided initializer is missing or is not a proc.


240
241
242
243
244
245
# File 'lib/building_blocks/builders/builder_builder.rb', line 240

def initialize_with=(initializer)
  unless initializer.is_a?(Proc)
    raise ArgumentError, "Expected proc initializer, got #{initializer.class.name}"
  end
  @initialize_with = initializer
end

#resource_class(klass = nil) ⇒ Object

The class that the generated builder class should generate instances of. When no value is passed for the klass argument, returns the currently configured resource class. If a value is provided for klass, the method acts as a setter and the provided klass argument is preserved and later used for the resource class of the generated builder class. For further information on how instances of the resource class are built, see #initialize_with.

Returns:

  • (Object)

    The class that the generated builder class will generate instances of.

See Also:


257
258
259
260
# File 'lib/building_blocks/builders/builder_builder.rb', line 257

def resource_class(klass = nil)
  @resource_class = klass unless klass.nil?
  @resource_class
end

#resource_class=(klass) ⇒ Object

Sets the class that the generated builder class will generate instances of. For further information on how instances of the resource class are built, see #initialize_with.

Returns:

  • (Object)

    The value given for the klass argument is returned.

See Also:


268
269
270
# File 'lib/building_blocks/builders/builder_builder.rb', line 268

def resource_class=(klass)
  @resource_class = klass
end