Validated XML Output with Method Generation
# A DSL for validated XML outputclass XMLGrammar# Create an instance of this class, specifying a stream or object to# hold the output. This can be any object that responds to <<(String).def initialize(out) @out = out# Remember where to send our outputend# Invoke the block in an instance that outputs to the specified stream.def self.generate(out, &block) new(out).instance_eval(&block)end# Define an allowed element (or tag) in the grammar.# This class method is the grammar-specification DSL# and defines the methods that constitute the XML-output DSL.def self.element(tagname, attributes={}) @allowed_attributes ||= {} @allowed_attributes = attributes class_eval %Q{ def #{tagname}(attributes={}, &block) tag(:#{tagname},attributes,&block) end }end# These are constants used when defining attribute values.OPT = :opt # for optional attributesREQ = :req # for required attributesBOOL = :bool # for attributes whose value is their own namedef self.allowed_attributes @allowed_attributesend# Output the specified object as CDATA, return nil.def content(text) @out << text.to_s nilend# Output the specified object as a comment, return nil.def comment(text) @out << "<!-- #{text} -->" nilend# Output a tag with the specified name and attribute.# If there is a block, invoke it to output or return content.# Return nil.def tag(tagname, attributes={}) # Output the tag name @out << "<#{tagname}" # Get the allowed attributes for this tag. allowed = self.class.allowed_attributes # First, make sure that each of the attributes is allowed. # Assuming they are allowed, output all of the specified ones. attributes.each_pair do |key,value| raise "unknown attribute: #{key}" unless allowed.include?(key) @out << " #{key}='#{value}'" end # Now look through the allowed attributes, checking for # required attributes that were omitted and for attributes with # default values that we can output. allowed.each_pair do |key,value| # If this attribute was already output, do nothing. next if attributes.has_key? key if (value == REQ) raise "required attribute '#{key}' missing in <#{tagname}>" elsif value.is_a? String @out << " #{key}='#{value}'" end end if block_given? # This block has content @out << '>' # End the opening tag content = yield # Invoke the block to output or return content if content # If any content returned @out << content.to_s# Output it as a string end @out << "</#{tagname}>" # Close the tag else # Otherwise, this is an empty tag, so just close it. @out << '/>' end nil # Tags output themselves, so they don't return any content.endend
class HTMLForm < XMLGrammarelement :form, :action => REQ, :method => "GET", :enctype => "application/x-www-form-urlencoded", :name => OPTelement :input, :type => "text", :name => OPT, :value => OPT, :maxlength => OPT, :size => OPT, :src => OPT, :checked => BOOL, :disabled => BOOL, :readonly => BOOLelement :textarea, :rows => REQ, :cols => REQ, :name => OPT, :disabled => BOOL, :readonly => BOOLelement :button, :name => OPT, :value => OPT, :type => "submit", :disabled => OPTend
HTMLForm.generate(STDOUT) docomment "This is a simple HTML form"form :name => "registration", :action => "http://www.example.com/register.cgi" do content "Name:" input :name => "name" content "Address:" textarea :name => "address", :rows=>6, :cols=>40 do "Please enter your mailing address here" end button { "Submit" }endend#<!-- This is a simple HTML form --><form name='registration' action='http://www.example.com/register.cgi' enctype='application/x-www-form-urlencoded' method='GET'>Name:<input name='name' type='text'/>Address:<textarea rows='6' cols='40' name='address'>Please enter your mailing address here</textarea><button type='submit'>Submit</button></form>>Exit code: 0
页:
[1]