class PositionalGenerator::Builder

def build

Returns:
  • (String) - if +as_type+ is +:string+
def build
  graph = build_graph
  stack = build_stack(graph)
  values = generate_values(stack)
  convert(values)
end

def build_graph

Returns:
  • (Array<(Integer, Integer)>) -
def build_graph
  graph = []
  # rubocop:disable Style/CombinableLoops
  @components.each do |component|
    component.deps.each do |dep|
      dep_component = @components.detect { |c| c.name == dep }
      raise if dep_component.nil?
      graph.push([dep_component.position, component.position])
    end
  end
  @components.each do |component|
    graph.push([component.position, nil]) if graph.none? { |(from, _to)| from == component.position }
  end
  # rubocop:enable Style/CombinableLoops
  graph
end

def build_stack(graph)

Returns:
  • (Array>) -

Parameters:
  • graph (Array<(Integer, Integer)>) --
def build_stack(graph)
  require 'set'
  terminals = graph.filter_map { |(from, to)| to.nil? && from }
  stack = [terminals]
  seen = Set.new(terminals)
  deps = []
  loop do
    stack[-1].each do |e|
      deps = graph.select { |(from, to)| to == e && !seen.include?(from) }.map do |from, _to|
        seen << from
        from
      end
      stack << deps if deps.any?
    end
    break if deps.empty?
  end
  stack
end

def computed(name: nil, deps: [], &block)

Other tags:
    Example: A check digit -
    Example: Today's date -

Returns:
  • (void) -

Parameters:
  • block (Method) -- the block that yields the arbitrary value. Its
  • deps (Array) -- the name of other fields that this one depends on
  • name (Symbol) -- the name for this node in the group
def computed(name: nil, deps: [], &block)
  @components << Component.new(@components.count, name, deps, Computed.new(block))
end

def convert(values)

Raises:
  • (ArgumentError) - if +@as_type+ is unsupported

Returns:
  • (String) - if +@as_type+ is +:string+

Parameters:
  • values (Array) --
    def convert(values)
      case @as_type
      when :string
        values.inject('') do |acc, (_, _, v)|
          "#{acc}#{v}"
        end
      else
        raise ArgumentError, "unknown return type: #{@as_type}"
      end
    end

    def generate_values(stack)

    Returns:
    • (Array) - values sorted by desired order
      Parameters:
      • stack (Array>) --
      def generate_values(stack)
        result = []
        while (top = stack.pop)
          top.each do |component_id|
            component = @components[component_id]
            raise if component.nil?
            values = result.filter_map do |(_id, name, value)|
              value if component.deps.include?(name)
            end
            result << [component.position, component.name, component.generator.generate(values)]
          end
        end
        result.sort_by do |component_position, _, _|
          component_position
        end
      end

      def group(name: nil, &block)

      Returns:
      • (void) -

      Parameters:
      • block (Method) -- a subgenerator block
      • name (Symbol) -- the name for this node in the group
      def group(name: nil, &block)
        @components << Component.new(@components.count, name, [], Group.new(@as_type, block))
      end

      def initialize(as_type)

      def initialize(as_type)
        @components = []
        @as_type = as_type
      end

      def int(name: nil, length: 1, ranges: nil)

      Other tags:
        Example: digits of any length between 4 to 10 -
        Example: five digits named :a -
        Example: a digit -

      Returns:
      • (void) -

      Parameters:
      • ranges (Array) -- an array of limitations on the
      • length (Integer) -- how many digits to generate
      • name (Symbol) -- the name for this node in the group
      def int(name: nil, length: 1, ranges: nil)
        @components << Component.new(@components.count, name, [], Int.new(length, ranges))
      end

      def letter(name: nil, length: 1, ranges: ['a'..'z', 'A'..'Z'])

      Other tags:
        Example: Generate three-letter strings from within specific values -
        Example: Generate five uppercase letters named :b -
        Example: Generate a letter -

      Returns:
      • (void) -

      Parameters:
      • ranges (Array) -- an array of limitations on the
      • length (Integer, Range) -- how many letters to generate
      • name (Symbol) -- the name for this node in the group
      def letter(name: nil, length: 1, ranges: ['a'..'z', 'A'..'Z'])
        @components << Component.new(@components.count, name, [], Letter.new(length, ranges))
      end

      def lit(value, name: nil)

      Returns:
      • (void) -

      Parameters:
      • name (Symbol) -- the name for this node in the group
      • value (String) --
      def lit(value, name: nil)
        @components << Component.new(@components.count, name, [], Literal.new(value))
      end

      def oneof(name: nil, &block)

      Other tags:
        Example: Either one letter; or a slash, five digits, then a slash. -
        Example: Either five digits, or two letters -

      Returns:
      • (void) -

      Parameters:
      • block (Method) -- subgenerator block
      • name (Symbol) -- the name for this node in the group
      def oneof(name: nil, &block)
        @components << Component.new(@components.count, name, [], Oneof.new(self, block))
      end