module BuilderPattern

BuilderPattern module

Public Class Methods

attr_mandatory(*fields) click to toggle source
# File lib/builder_pattern.rb, line 10
def self.attr_mandatory(*fields)
  @__attr_mandatory ||= []
  @__attr_mandatory |= fields.map { |field| "@#{field}".to_sym }
end
attr_optional(*fields) click to toggle source
# File lib/builder_pattern.rb, line 15
def self.attr_optional(*fields)
  @__attr_optional ||= []
  @__attr_optional |= fields.map { |field| "@#{field}".to_sym }
end
build(&block) click to toggle source
# File lib/builder_pattern.rb, line 20
def self.build(&block)
  new.build(&block)
end
included(klass) click to toggle source

rubocop:disable Metrics/MethodLength because of class_eval

# File lib/builder_pattern.rb, line 6
def self.included(klass)
  klass.class_eval do
    private_class_method :new

    def self.attr_mandatory(*fields)
      @__attr_mandatory ||= []
      @__attr_mandatory |= fields.map { |field| "@#{field}".to_sym }
    end

    def self.attr_optional(*fields)
      @__attr_optional ||= []
      @__attr_optional |= fields.map { |field| "@#{field}".to_sym }
    end

    def self.build(&block)
      new.build(&block)
    end
  end
end

Public Instance Methods

build() { |collector| ... } click to toggle source

rubocop:disable Metrics/MethodLength desired single method, readable enough rubocop:disable Metrics/AbcSize desired single method, readable enough

# File lib/builder_pattern.rb, line 29
def build
  collector = OpenStruct.new
  yield collector
  mandatory = self.class.ancestors.map do |level|
    level.instance_variable_get(:@__attr_mandatory)
  end
                  .compact.flatten.uniq
  allowed = self.class.ancestors.map do |level|
    level.instance_variable_get(:@__attr_optional)
  end
                .compact.flatten | mandatory
  # Migrate the state to instance variables
  collector.each_pair do |key, val|
    key = "@#{key}".to_sym
    unless allowed.include?(key)
      raise ArgumentError, "Unknown field #{key} used in build"
    end
    instance_variable_set(key, val)
  end
  fields = mandatory - instance_variables
  return self if fields.empty?
  raise ArgumentError, "Mandatory fields #{fields.join(', ')} not set"
end