class Infoboxer::WikiPath
@private
Constants
- ParseError
Public Class Methods
_parse(string)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 9 def _parse(string) scanner = StringScanner.new(string) res = [] loop do res << scan_step(scanner) break if scanner.eos? end res end
new(path)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 71 def initialize(path) @path = path end
parse(string)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 19 def parse(string) new(_parse(string)) end
Private Class Methods
process_type(type)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 56 def process_type(type) type.gsub(/(?:^|_)([a-z])/, &:upcase).tr('_', '').to_sym .tap { |t| valid_type?(t) or fail(ParseError, "Unrecognized node type: #{type}") } end
process_value(value)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 45 def process_value(value) case value when /^'(.*)'$/, /^"(.*)"$/ Regexp.last_match(1) when %r{^/(.+)/$} Regexp.new(Regexp.last_match(1)) else value end end
scan_step(scanner)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 25 def scan_step(scanner) # rubocop:disable Metrics/PerceivedComplexity op = scanner.scan(%r{//?}) or unexpected(scanner, '/') type = scanner.scan(/[A-Za-z_]*/) attrs = {} while scanner.scan(/\[/) attr = scanner.scan(/[-a-z_0-9]+/) or unexpected(scanner, 'attribute name') if scanner.scan(/\]/) (attrs[:predicates] ||= []) << "#{attr}?".to_sym next end scanner.scan(/\s*=\s*/) or unexpected(scanner, '= or ]') value = scanner.scan(/[^\]]+/) # TODO: probably, should do a proper [] counting?.. scanner.scan(/\]/) or unexpected(scanner, ']') attrs[attr.to_sym] = process_value(value) end res = op == '//' ? {op: :lookup} : {} res[:type] = process_type(type) unless type.empty? res.merge(attrs) # TODO: raise if empty selector end
unexpected(scanner, expected)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 65 def unexpected(scanner, expected) place = scanner.eos? ? 'end of pattern' : scanner.rest.inspect fail ParseError, "Unexpected #{place}, expecting #{expected}" end
valid_type?(t)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 61 def valid_type?(t) t == :Section || Infoboxer::Tree.const_defined?(t) end
Public Instance Methods
call(node)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 75 def call(node) @path.inject(node) { |res, step| apply_step(res, step) } end
Private Instance Methods
apply_step(node, step)
click to toggle source
# File lib/infoboxer/wiki_path.rb, line 81 def apply_step(node, step) # TODO: "compile" the op/args sequences at WikiPath initialization step = step.dup op = step.delete(:op) || :lookup_children args = [] if (t = step.delete(:type)) args << t end if (pred = step.delete(:predicates)) args.concat(pred) end args << step unless step.empty? node.send(op, *args) end