80 lines
2.6 KiB
Ruby
80 lines
2.6 KiB
Ruby
module Radius
|
|
#
|
|
# The Radius parser. Initialize a parser with a Context object that
|
|
# defines how tags should be expanded. See the QUICKSTART[link:files/QUICKSTART.html]
|
|
# for a detailed explaination of its usage.
|
|
#
|
|
class Parser
|
|
# The Context object used to expand template tags.
|
|
attr_accessor :context
|
|
|
|
# The string that prefixes all tags that are expanded by a parser
|
|
# (the part in the tag name before the first colon).
|
|
attr_accessor :tag_prefix
|
|
|
|
# The class that performs tokenization of the input string
|
|
attr_accessor :scanner
|
|
|
|
# Creates a new parser object initialized with a Context.
|
|
def initialize(context = Context.new, options = {})
|
|
if context.kind_of?(Hash) and options.empty?
|
|
options, context = context, (context[:context] || context['context'])
|
|
end
|
|
options = Utility.symbolize_keys(options)
|
|
self.context = context ? context.dup : Context.new
|
|
self.tag_prefix = options[:tag_prefix] || 'radius'
|
|
self.scanner = options[:scanner] || default_scanner
|
|
end
|
|
|
|
# Parses string for tags, expands them, and returns the result.
|
|
def parse(string)
|
|
@stack = [ ParseContainerTag.new { |t| Utility.array_to_s(t.contents) } ]
|
|
tokenize(string)
|
|
stack_up
|
|
@stack.last.to_s
|
|
end
|
|
|
|
protected
|
|
# Convert the string into a list of text blocks and scanners (tokens)
|
|
def tokenize(string)
|
|
@tokens = scanner.operate(tag_prefix, string)
|
|
end
|
|
|
|
def stack_up
|
|
@tokens.each do |t|
|
|
if t.is_a? String
|
|
@stack.last.contents << t
|
|
next
|
|
end
|
|
case t[:flavor]
|
|
when :open
|
|
@stack.push(ParseContainerTag.new(t[:name], t[:attrs]))
|
|
when :self
|
|
@stack.last.contents << ParseTag.new {@context.render_tag(t[:name], t[:attrs])}
|
|
when :close
|
|
popped = @stack.pop
|
|
raise WrongEndTagError.new(popped.name, t[:name], @stack) if popped.name != t[:name]
|
|
popped.on_parse { |b| @context.render_tag(popped.name, popped.attributes) { Utility.array_to_s(b.contents) } }
|
|
@stack.last.contents << popped
|
|
when :tasteless
|
|
raise TastelessTagError.new(t, @stack)
|
|
else
|
|
raise UndefinedFlavorError.new(t, @stack)
|
|
end
|
|
end
|
|
raise MissingEndTagError.new(@stack.last.name, @stack) if @stack.length != 1
|
|
end
|
|
|
|
def default_scanner
|
|
if RUBY_PLATFORM == 'java'
|
|
require 'java'
|
|
require 'radius/parser/java_scanner.jar'
|
|
::Radius.send(:include_package, 'radius.parser')
|
|
Radius::JavaScanner.new(JRuby.runtime)
|
|
else
|
|
Radius::Scanner.new
|
|
end
|
|
end
|
|
end
|
|
end
|