lib/orange/resources/radius.rb in orange-0.0.5 vs lib/orange/resources/radius.rb in orange-0.0.6
- old
+ new
@@ -14,10 +14,84 @@
def parse(packet)
content = packet[:content, false]
unless content.blank?
parser = ::Radius::Parser.new(context, :tag_prefix => 'o')
- packet[:content] = parser.parse(content)
+ packet[:content] = parser.parse(content, packet)
end
end
end
-end
\ No newline at end of file
+end
+
+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
+ def parse(string, packet = false)
+ @stack = [ParseContainerTag.new { |t| t.contents.to_s }]
+ tokenize(string)
+ stack_up(packet)
+ @stack.last.to_s
+ end
+
+ protected
+
+ def stack_up(packet = false)
+ @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], packet)}
+ 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, packet) { b.contents.to_s } }
+ @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
+ end
+ class Context
+
+ # Returns the value of a rendered tag. Used internally by Parser#parse.
+ def render_tag(name, attributes = {}, packet = false, &block)
+ if name =~ /^(.+?):(.+)$/
+ render_tag($1) { render_tag($2, attributes, packet, &block) }
+ else
+ tag_definition_block = @definitions[qualified_tag_name(name.to_s)]
+ if tag_definition_block
+ stack(name, attributes, packet, block) do |tag|
+ tag_definition_block.call(tag).to_s
+ end
+ else
+ tag_missing(name, attributes, &block)
+ end
+ end
+ end
+ # A convienence method for managing the various parts of the
+ # tag binding stack.
+ def stack(name, attributes, packet, block)
+ previous = @tag_binding_stack.last
+ previous_locals = previous.nil? ? @globals : previous.locals
+ locals = DelegatingOpenStruct.new(previous_locals)
+ locals.packet = packet
+ binding = TagBinding.new(self, locals, name, attributes, block)
+ @tag_binding_stack.push(binding)
+ result = yield(binding)
+ @tag_binding_stack.pop
+ result
+ end
+ end
+end