class PositionalGenerator::Builder
def build
-
(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
-
(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)
-
(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)
- 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)
-
(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)
-
(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)
-
(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)
- 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'])
- 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)
-
(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)
- 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