From cd989472a5248aae4f827c35347bdb871de1822a Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 8 Mar 2006 02:56:25 +0000 Subject: Added Hash#to_xml and Array#to_xml that makes it much easier to produce XML from basic structures [DHH] Moved Jim Weirich's wonderful Builder from Action Pack to Active Support (it's simply too useful to be stuck in AP) [DHH] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3812 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/lib/action_view/vendor/builder.rb | 13 - .../lib/action_view/vendor/builder/blankslate.rb | 53 ---- .../lib/action_view/vendor/builder/xmlbase.rb | 143 ---------- .../lib/action_view/vendor/builder/xmlevents.rb | 63 ----- .../lib/action_view/vendor/builder/xmlmarkup.rb | 308 --------------------- 5 files changed, 580 deletions(-) delete mode 100644 actionpack/lib/action_view/vendor/builder.rb delete mode 100644 actionpack/lib/action_view/vendor/builder/blankslate.rb delete mode 100644 actionpack/lib/action_view/vendor/builder/xmlbase.rb delete mode 100644 actionpack/lib/action_view/vendor/builder/xmlevents.rb delete mode 100644 actionpack/lib/action_view/vendor/builder/xmlmarkup.rb (limited to 'actionpack/lib/action_view') diff --git a/actionpack/lib/action_view/vendor/builder.rb b/actionpack/lib/action_view/vendor/builder.rb deleted file mode 100644 index 9719277669..0000000000 --- a/actionpack/lib/action_view/vendor/builder.rb +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env ruby - -#-- -# Copyright 2004 by Jim Weirich (jim@weirichhouse.org). -# All rights reserved. - -# Permission is granted for use, copying, modification, distribution, -# and distribution of modified versions of this work as long as the -# above copyright notice is included. -#++ - -require 'builder/xmlmarkup' -require 'builder/xmlevents' diff --git a/actionpack/lib/action_view/vendor/builder/blankslate.rb b/actionpack/lib/action_view/vendor/builder/blankslate.rb deleted file mode 100644 index 1408c872cc..0000000000 --- a/actionpack/lib/action_view/vendor/builder/blankslate.rb +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Copyright 2004 by Jim Weirich (jim@weirichhouse.org). -# All rights reserved. - -# Permission is granted for use, copying, modification, distribution, -# and distribution of modified versions of this work as long as the -# above copyright notice is included. -#++ - -module Builder #:nodoc: - - # BlankSlate provides an abstract base class with no predefined - # methods (except for \_\_send__ and \_\_id__). - # BlankSlate is useful as a base class when writing classes that - # depend upon method_missing (e.g. dynamic proxies). - class BlankSlate #:nodoc: - class << self - def hide(name) - undef_method name if - instance_methods.include?(name.to_s) and - name !~ /^(__|instance_eval)/ - end - end - - instance_methods.each { |m| hide(m) } - end -end - -# Since Ruby is very dynamic, methods added to the ancestors of -# BlankSlate after BlankSlate is defined will show up in the -# list of available BlankSlate methods. We handle this by defining a hook in the Object and Kernel classes that will hide any defined -module Kernel #:nodoc: - class << self - alias_method :blank_slate_method_added, :method_added - def method_added(name) - blank_slate_method_added(name) - return if self != Kernel - Builder::BlankSlate.hide(name) - end - end -end - -class Object #:nodoc: - class << self - alias_method :blank_slate_method_added, :method_added - def method_added(name) - blank_slate_method_added(name) - return if self != Object - Builder::BlankSlate.hide(name) - end - end -end diff --git a/actionpack/lib/action_view/vendor/builder/xmlbase.rb b/actionpack/lib/action_view/vendor/builder/xmlbase.rb deleted file mode 100644 index 7202bb2ead..0000000000 --- a/actionpack/lib/action_view/vendor/builder/xmlbase.rb +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env ruby - -require 'builder/blankslate' - -module Builder #:nodoc: - - # Generic error for builder - class IllegalBlockError < RuntimeError #:nodoc: - end - - # XmlBase is a base class for building XML builders. See - # Builder::XmlMarkup and Builder::XmlEvents for examples. - class XmlBase < BlankSlate #:nodoc: - - # Create an XML markup builder. - # - # out:: Object receiving the markup.1 +out+ must respond to - # <<. - # indent:: Number of spaces used for indentation (0 implies no - # indentation and no line breaks). - # initial:: Level of initial indentation. - # - def initialize(indent=0, initial=0) - @indent = indent - @level = initial - end - - # Create a tag named +sym+. Other than the first argument which - # is the tag name, the arguements are the same as the tags - # implemented via method_missing. - def tag!(sym, *args, &block) - self.__send__(sym, *args, &block) - end - - # Create XML markup based on the name of the method. This method - # is never invoked directly, but is called for each markup method - # in the markup block. - def method_missing(sym, *args, &block) - text = nil - attrs = nil - sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol) - args.each do |arg| - case arg - when Hash - attrs ||= {} - attrs.merge!(arg) - else - text ||= '' - text << arg.to_s - end - end - if block - unless text.nil? - raise ArgumentError, "XmlMarkup cannot mix a text argument with a block" - end - _capture_outer_self(block) if @self.nil? - _indent - _start_tag(sym, attrs) - _newline - _nested_structures(block) - _indent - _end_tag(sym) - _newline - elsif text.nil? - _indent - _start_tag(sym, attrs, true) - _newline - else - _indent - _start_tag(sym, attrs) - text! text - _end_tag(sym) - _newline - end - @target - end - - # Append text to the output target. Escape any markup. May be - # used within the markup brackets as: - # - # builder.p { br; text! "HI" } #=>


HI

- def text!(text) - _text(_escape(text)) - end - - # Append text to the output target without escaping any markup. - # May be used within the markup brackets as: - # - # builder.p { |x| x << "
HI" } #=>


HI

- # - # This is useful when using non-builder enabled software that - # generates strings. Just insert the string directly into the - # builder without changing the inserted markup. - # - # It is also useful for stacking builder objects. Builders only - # use << to append to the target, so by supporting this - # method/operation builders can use other builders as their - # targets. - def <<(text) - _text(text) - end - - # For some reason, nil? is sent to the XmlMarkup object. If nil? - # is not defined and method_missing is invoked, some strange kind - # of recursion happens. Since nil? won't ever be an XML tag, it - # is pretty safe to define it here. (Note: this is an example of - # cargo cult programming, - # cf. http://fishbowl.pastiche.org/2004/10/13/cargo_cult_programming). - def nil? - false - end - - private - - def _escape(text) - text. - gsub(%r{&}, '&'). - gsub(%r{<}, '<'). - gsub(%r{>}, '>') - end - - def _capture_outer_self(block) - @self = eval("self", block) - end - - def _newline - return if @indent == 0 - text! "\n" - end - - def _indent - return if @indent == 0 || @level == 0 - text!(" " * (@level * @indent)) - end - - def _nested_structures(block) - @level += 1 - block.call(self) - ensure - @level -= 1 - end - end -end diff --git a/actionpack/lib/action_view/vendor/builder/xmlevents.rb b/actionpack/lib/action_view/vendor/builder/xmlevents.rb deleted file mode 100644 index 15dc7b6421..0000000000 --- a/actionpack/lib/action_view/vendor/builder/xmlevents.rb +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env ruby - -#-- -# Copyright 2004 by Jim Weirich (jim@weirichhouse.org). -# All rights reserved. - -# Permission is granted for use, copying, modification, distribution, -# and distribution of modified versions of this work as long as the -# above copyright notice is included. -#++ - -require 'builder/xmlmarkup' - -module Builder - - # Create a series of SAX-like XML events (e.g. start_tag, end_tag) - # from the markup code. XmlEvent objects are used in a way similar - # to XmlMarkup objects, except that a series of events are generated - # and passed to a handler rather than generating character-based - # markup. - # - # Usage: - # xe = Builder::XmlEvents.new(hander) - # xe.title("HI") # Sends start_tag/end_tag/text messages to the handler. - # - # Indentation may also be selected by providing value for the - # indentation size and initial indentation level. - # - # xe = Builder::XmlEvents.new(handler, indent_size, initial_indent_level) - # - # == XML Event Handler - # - # The handler object must expect the following events. - # - # [start_tag(tag, attrs)] - # Announces that a new tag has been found. +tag+ is the name of - # the tag and +attrs+ is a hash of attributes for the tag. - # - # [end_tag(tag)] - # Announces that an end tag for +tag+ has been found. - # - # [text(text)] - # Announces that a string of characters (+text+) has been found. - # A series of characters may be broken up into more than one - # +text+ call, so the client cannot assume that a single - # callback contains all the text data. - # - class XmlEvents < XmlMarkup #:nodoc: - def text!(text) - @target.text(text) - end - - def _start_tag(sym, attrs, end_too=false) - @target.start_tag(sym, attrs) - _end_tag(sym) if end_too - end - - def _end_tag(sym) - @target.end_tag(sym) - end - end - -end diff --git a/actionpack/lib/action_view/vendor/builder/xmlmarkup.rb b/actionpack/lib/action_view/vendor/builder/xmlmarkup.rb deleted file mode 100644 index b7e3b2d009..0000000000 --- a/actionpack/lib/action_view/vendor/builder/xmlmarkup.rb +++ /dev/null @@ -1,308 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Copyright 2004 by Jim Weirich (jim@weirichhouse.org). -# All rights reserved. - -# Permission is granted for use, copying, modification, distribution, -# and distribution of modified versions of this work as long as the -# above copyright notice is included. -#++ - -# Provide a flexible and easy to use Builder for creating XML markup. -# See XmlBuilder for usage details. - -require 'builder/xmlbase' - -module Builder - - # Create XML markup easily. All (well, almost all) methods sent to - # an XmlMarkup object will be translated to the equivalent XML - # markup. Any method with a block will be treated as an XML markup - # tag with nested markup in the block. - # - # Examples will demonstrate this easier than words. In the - # following, +xm+ is an +XmlMarkup+ object. - # - # xm.em("emphasized") # => emphasized - # xm.em { xmm.b("emp & bold") } # => emph & bold - # xm.a("A Link", "href"=>"http://onestepback.org") - # # => A Link - # xm.div { br } # =>

- # xm.target("name"=>"compile", "option"=>"fast") - # # => - # # NOTE: order of attributes is not specified. - # - # xm.instruct! # - # xm.html { # - # xm.head { # - # xm.title("History") # History - # } # - # xm.body { # - # xm.comment! "HI" # - # xm.h1("Header") #

Header

- # xm.p("paragraph") #

paragraph

- # } # - # } # - # - # == Notes: - # - # * The order that attributes are inserted in markup tags is - # undefined. - # - # * Sometimes you wish to insert text without enclosing tags. Use - # the text! method to accomplish this. - # - # Example: - # - # xm.div { #
- # xm.text! "line"; xm.br # line
- # xm.text! "another line"; xmbr # another line
- # } #
- # - # * The special XML characters <, >, and & are converted to <, - # > and & automatically. Use the << operation to - # insert text without modification. - # - # * Sometimes tags use special characters not allowed in ruby - # identifiers. Use the tag! method to handle these - # cases. - # - # Example: - # - # xml.tag!("SOAP:Envelope") { ... } - # - # will produce ... - # - # ... " - # - # tag! will also take text and attribute arguments (after - # the tag name) like normal markup methods. (But see the next - # bullet item for a better way to handle XML namespaces). - # - # * Direct support for XML namespaces is now available. If the - # first argument to a tag call is a symbol, it will be joined to - # the tag to produce a namespace:tag combination. It is easier to - # show this than describe it. - # - # xml.SOAP :Envelope do ... end - # - # Just put a space before the colon in a namespace to produce the - # right form for builder (e.g. "SOAP:Envelope" => - # "xml.SOAP :Envelope") - # - # * XmlMarkup builds the markup in any object (called a _target_) - # that accepts the << method. If no target is given, - # then XmlMarkup defaults to a string target. - # - # Examples: - # - # xm = Builder::XmlMarkup.new - # result = xm.title("yada") - # # result is a string containing the markup. - # - # buffer = "" - # xm = Builder::XmlMarkup.new(buffer) - # # The markup is appended to buffer (using <<) - # - # xm = Builder::XmlMarkup.new(STDOUT) - # # The markup is written to STDOUT (using <<) - # - # xm = Builder::XmlMarkup.new - # x2 = Builder::XmlMarkup.new(:target=>xm) - # # Markup written to +x2+ will be send to +xm+. - # - # * Indentation is enabled by providing the number of spaces to - # indent for each level as a second argument to XmlBuilder.new. - # Initial indentation may be specified using a third parameter. - # - # Example: - # - # xm = Builder.new(:ident=>2) - # # xm will produce nicely formatted and indented XML. - # - # xm = Builder.new(:indent=>2, :margin=>4) - # # xm will produce nicely formatted and indented XML with 2 - # # spaces per indent and an over all indentation level of 4. - # - # builder = Builder::XmlMarkup.new(:target=>$stdout, :indent=>2) - # builder.name { |b| b.first("Jim"); b.last("Weirich) } - # # prints: - # # - # # Jim - # # Weirich - # # - # - # * The instance_eval implementation which forces self to refer to - # the message receiver as self is now obsolete. We now use normal - # block calls to execute the markup block. This means that all - # markup methods must now be explicitly send to the xml builder. - # For instance, instead of - # - # xml.div { strong("text") } - # - # you need to write: - # - # xml.div { xml.strong("text") } - # - # Although more verbose, the subtle change in semantics within the - # block was found to be prone to error. To make this change a - # little less cumbersome, the markup block now gets the markup - # object sent as an argument, allowing you to use a shorter alias - # within the block. - # - # For example: - # - # xml_builder = Builder::XmlMarkup.new - # xml_builder.div { |xml| - # xml.stong("text") - # } - # - class XmlMarkup < XmlBase - - # Create an XML markup builder. Parameters are specified by an - # option hash. - # - # :target=>target_object:: - # Object receiving the markup. +out+ must respond to the - # << operator. The default is a plain string target. - # :indent=>indentation:: - # Number of spaces used for indentation. The default is no - # indentation and no line breaks. - # :margin=>initial_indentation_level:: - # Amount of initial indentation (specified in levels, not - # spaces). - # - def initialize(options={}) - indent = options[:indent] || 0 - margin = options[:margin] || 0 - super(indent, margin) - @target = options[:target] || "" - end - - # Return the target of the builder. - def target! - @target - end - - def comment!(comment_text) - _ensure_no_block block_given? - _special("", comment_text, nil) - end - - # Insert an XML declaration into the XML markup. - # - # For example: - # - # xml.declare! :ELEMENT, :blah, "yada" - # # => - def declare!(inst, *args, &block) - _indent - @target << "" - _newline - end - - # Insert a processing instruction into the XML markup. E.g. - # - # For example: - # - # xml.instruct! - # #=> - # xml.instruct! :aaa, :bbb=>"ccc" - # #=> - # - def instruct!(directive_tag=:xml, attrs={}) - _ensure_no_block block_given? - if directive_tag == :xml - a = { :version=>"1.0", :encoding=>"UTF-8" } - attrs = a.merge attrs - end - _special( - "", - nil, - attrs, - [:version, :encoding, :standalone]) - end - - # Surrounds the given text with a CDATA tag - # - # For example: - # - # xml.cdata! "blah blah blah" - # # => - def cdata!(text) - _ensure_no_block block_given? - _special("", text, nil) - end - - private - - # NOTE: All private methods of a builder object are prefixed when - # a "_" character to avoid possible conflict with XML tag names. - - # Insert text directly in to the builder's target. - def _text(text) - @target << text - end - - # Insert special instruction. - def _special(open, close, data=nil, attrs=nil, order=[]) - _indent - @target << open - @target << data if data - _insert_attributes(attrs, order) if attrs - @target << close - _newline - end - - # Start an XML tag. If end_too is true, then the start - # tag is also the end tag (e.g.
- def _start_tag(sym, attrs, end_too=false) - @target << "<#{sym}" - _insert_attributes(attrs) - @target << "/" if end_too - @target << ">" - end - - # Insert an ending tag. - def _end_tag(sym) - @target << "" - end - - # Insert the attributes (given in the hash). - def _insert_attributes(attrs, order=[]) - return if attrs.nil? - order.each do |k| - v = attrs[k] - @target << %{ #{k}="#{v}"} if v - end - attrs.each do |k, v| - @target << %{ #{k}="#{v}"} unless order.member?(k) - end - end - - def _ensure_no_block(got_block) - if got_block - fail IllegalBlockError, - "Blocks are not allowed on XML instructions" - end - end - - end - -end -- cgit v1.2.3