class Mustermann::AST::Expander

Looks at an AST, remembers the important bits of information to do an ultra fast expansion.

@!visibility private

Public Instance Methods

add(ast) click to toggle source

add a tree for expansion @!visibility private

# File lib/mustermann/ast/expander.rb, line 80
def add(ast)
  translate(ast).each do |keys, pattern, filter|
    self.keys.concat(keys).uniq!
    mappings[keys.sort] ||= [keys, pattern, filter]
  end
end
add_to(list, result) click to toggle source

Creates the product of two of our secret internal data structures. @!visibility private

# File lib/mustermann/ast/expander.rb, line 139
def add_to(list, result)
  list << [[], ""] if list.empty?
  list.inject([]) { |l, (k1, p1, f1)| l + result.map { |k2, p2, f2| [k1+k2, p1+p2, f1.merge(f2)] } }
end
error_for(values) click to toggle source

helper method for raising an error for unexpandable values @!visibility private

# File lib/mustermann/ast/expander.rb, line 119
def error_for(values)
  expansions = mappings.keys.map(&:inspect).join(" or ")
  raise error_class, "cannot expand with keys %p, possible expansions: %s" % [values.keys.sort, expansions]
end
escape(string, *args) click to toggle source
Calls superclass method
# File lib/mustermann/ast/expander.rb, line 126
               def escape(string, *args)
  # URI::Parser is pretty slow, let's not send every string to it, even if it's unnecessary
  string =~ /\A\w*\Z/ ? string : super
end
expand(values) click to toggle source

@see Mustermann::Pattern#expand @!visibility private

# File lib/mustermann/ast/expander.rb, line 95
def expand(values)
  adjusted = values.each_with_object({}){ |(key, value), new_hash|
    new_hash[value.instance_of?(Array) ? [key] * value.length : key] = value }
  keys, pattern, filters = mappings.fetch(adjusted.keys.flatten.sort) { error_for(values) }
  filters.each { |key, filter| adjusted[key] &&= escape(adjusted[key], also_escape: filter) }
  pattern % (adjusted[keys] || adjusted.values_at(*keys))
end
expandable?(values) click to toggle source

@see Mustermann::Pattern#expandable? @!visibility private

# File lib/mustermann/ast/expander.rb, line 105
def expandable?(values)
  values = values.keys if values.respond_to? :keys
  values = values.sort if values.respond_to? :sort
  mappings.include? values
end
expandable_keys(keys) click to toggle source

@see Mustermann::Expander#with_rest @!visibility private

# File lib/mustermann/ast/expander.rb, line 113
def expandable_keys(keys)
  mappings.keys.select { |k| (k - keys).empty? }.max_by(&:size) || keys
end
for_capture(node, **options) click to toggle source

helper method for captures @!visibility private

# File lib/mustermann/ast/expander.rb, line 61
def for_capture(node, **options)
  name = node.name.to_sym
  pattern('%s', name, name => /(?!#{pattern_for(node, **options)})./)
end
keys() click to toggle source

all the known keys @!visibility private

# File lib/mustermann/ast/expander.rb, line 74
def keys
  @keys ||= []
end
mappings() click to toggle source

maps sorted key list to sprintf patterns and filters @!visibility private

# File lib/mustermann/ast/expander.rb, line 68
def mappings
  @mappings ||= {}
end
pattern(string = "", *keys, **filters) click to toggle source

Turns a sprintf pattern into our secret internal data structure. @!visibility private

# File lib/mustermann/ast/expander.rb, line 133
def pattern(string = "", *keys, **filters)
  [[keys, string, filters]]
end
pattern_for(node, **options) click to toggle source

helper method for getting a capture's pattern. @!visibility private

# File lib/mustermann/ast/expander.rb, line 89
def pattern_for(node, **options)
  Compiler.new.decorator_for(node).pattern(**options)
end