[ANN] xx-2.0.0

NAME

   xx

SYNOPSIS

   xhtml and xml generation => twice as dirty!

USAGE

   require "xx"

   include XX::XHTML

   doc = xhtml_{
     html_{
       head_{ title_{ " go xx! " } }
       body_{ " one more and it would be illegal " }
     }
   }

   puts doc

INSTALL

   harp:~ > gem install "double x"

URIS

   http://rubyforge.org/projects/codeforpeople/
   hhtp://codeforpeople.com/xx/

DESCRIPTION

   xx is a library designed to extend ruby objects with html, xhtml, and xml
   generation methods. the syntax provided by xx aims to make the generation
   of xml or xhtml as clean looking and natural as ruby itself, while still
   being entirely robust and safe.

   the approach taken, that of extending objects, allows natural document
   generation while preserving access to instance data. in essence it provides
   ruby objects (including the top level 'main' object) mixin ability to
   generate various markup views of their data in a way that is correct and
   elegant.

   xx is brought to you by the good folks at http://eparklabs.com.

SAMPLES

   <========< samples/a.rb >========>

   ~ > cat samples/a.rb

     require "xx"
     include XX::XHTML

···

#
     # xx modules extend any object with natural document markup methods. the
     # special 'tag_name_(attributes){ block }' is a bit odd first but, as you will
     # see, has many important properties
     #

     puts xhtml_{
       html_{
         head_{ title_{ " go xx! " } }
         body_{ " one more 'x' and it would be illegal " }
       }
     }

   ~ > ruby samples/a.rb

         <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
         <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
           <head>
             <title> go xx! </title>
           </head>
           <body> one more &apos;x&apos; and it would be illegal </body>
         </html>

   <========< samples/b.rb >========>

   ~ > cat samples/b.rb

     require "xx"
     #
     # xx doesn't name clash
     #
     class C
       include XX::XHTML

       attr 'body'

       def initialize
         @body = 'body'
       end

       def to_html
         xhtml_{ html_{ body_{ body } } }
       end
     end

     puts C.new.to_html

   ~ > ruby samples/b.rb

         <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
         <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
           <body>body</body>
         </html>

   <========< samples/c.rb >========>

   ~ > cat samples/c.rb

     require "xx"
     #
     # no reserved words prohibiting tags - oh, and xml too. also note the
     # blockless form of tag generation which is also supported
     #
     class C
       include XX::XML

       attr 'table'

       def initialize
         @table = %w( a b c ), %w( 1 2 3 )
       end

       def to_xml
         xml_{
           class_{ self.class }
           object_id_{ 42 }
           send_ 'send'
           exit_ 'exit'

           table_{
             table.each do |row|
               tr_{
                 row.each do |cell|
                   td_ cell
                 end
               }
             end
           }
         }
       end
     end

     puts C.new.to_xml.pretty # auto indentation with 'pretty'

   ~ > ruby samples/c.rb

         <?xml version='1.0'?>
         <class>C<object_id>42</object_id>
           <send>send</send>
           <exit>exit</exit>
           <table>
             <tr>
               <td>a</td>
               <td>b</td>
               <td>c</td>
             </tr>
             <tr>
               <td>1</td>
               <td>2</td>
               <td>3</td>
             </tr>
           </table>
         </class>

   <========< samples/d.rb >========>

   ~ > cat samples/d.rb

     require "xx"
     #
     # the brackets make it dang easy to bounce on the '%' key (or whatever key
     # matches braces in your editor) to balance tags. and the phrase '_{' is very
     # useful for searching huge doccuments for tag generation methods
     #
     class C
       include XX::XML

       def to_xml
         xml_{ a_{ b_{ c_{ d_{ e_{ f_{ ' but am i balanced? ' }}}}}}} # vim will tell you!
       end
     end

     puts C.new.to_xml

   ~ > ruby samples/d.rb

     <?xml version='1.0'?><a><b><c><d><e><f> but am i balanced? </f></e></d></c></b></a>

   <========< samples/e.rb >========>

   ~ > cat samples/e.rb

     require "xx"
     #
     # the handy '_' method can bail you out when your tags aren't valid ruby
     # syntax
     #

     include XX::XML

     puts xml_{ _('mething missing is cool'){ 'but not always the best fit' } }

   ~ > ruby samples/e.rb

     <?xml version='1.0'?><mething missing is cool>but not always the best fit</mething missing is cool>

   <========< samples/f.rb >========>

   ~ > cat samples/f.rb

     require "xx"
     #
     # '_' really bails you out for namespaces
     #
     module Furniture
       class Table
         include XX::XML

         attr 'legs'

         def initialize
           @legs = %w[ 1 2 3 4 ]
         end

         def to_xml
           xml_{
             _('furniture:table', 'xmlns:f' => 'http://www.w3schools.com/furniture'){
               legs.each{|leg|
                 _('furniture:leg'){ "leg #{ leg }" }
               }
             }
           }
         end
       end
     end

     #
     # xml types don't get formatted by default - use pretty for that
     #
     puts Furniture::Table.new.to_xml.pretty

   ~ > ruby samples/f.rb

         <?xml version='1.0'?>
         <furniture:table xmlns:f='http://www.w3schools.com/furniture'>
           <furniture:leg>leg 1</furniture:leg>
           <furniture:leg>leg 2</furniture:leg>
           <furniture:leg>leg 3</furniture:leg>
           <furniture:leg>leg 4</furniture:leg>
         </furniture:table>

   <========< samples/g.rb >========>

   ~ > cat samples/g.rb

     require "xx"
     #
     # there are bunch of shorthand methods - each is 'escaped' via a double
     # underscore
     #
     include XX::XHTML
     include XX::XML

     puts xml_{ t__{ 'this is text data' } }
     puts xml_{ x__{ '<xml> in raw form, nothing is auto-escaped </xml>' } }
     puts xml_{ h__{ '<html> entities like & are ignored </html>' } }
     puts xml_{ c__{ 'cdata' } }
     puts xml_{ tag_(a__('k=v, x=y')){ 'a__ is a handy attribute parser' } }
     puts xml_{ tag_(y__('k: v, a: b')){ 'y__ is too - yaml style' } }

   ~ > ruby samples/g.rb

     <?xml version='1.0'?>this is text data
     <?xml version='1.0'?><xml> in raw form, nothing is auto-escaped </xml>
     <?xml version='1.0'?><html> entities like & are ignored </html>
     <?xml version='1.0'?><![CDATA[cdata]]>
     <?xml version='1.0'?><tag k='v' x='y'>a__ is a handy attribute parser</tag>
     <?xml version='1.0'?><tag k='v' a='b'>y__ is too - yaml style</tag>

HISTORY

   2.0.0:

     - !!!!!!! NOT BACKWARD COMPATIBLE WITH 1.X.X VERSIONS !!!!!!!

     _ the special method '_' can now be used to generate any tag

         _(:td, :width => 600, :height => 400){ 'content' }

       this enables xml namespaces!

         xml_{

           _('furniture:table', 'xmlns:f' => 'http://www.w3schools.com/furniture'){
             ...
           }

         }

     - all the special escaping class of methods have been changed from one to
       two underscores

         g_ => g__ ## tag generator, now same as '_'
         t_ => t__ ## xml text node generator
         x_ => x__ ## raw xml, no escaping
         h_ => h__ ## escaped only html entities
         c_ => c__ ## cdata
         a_ => a__ ## parse attribute string
         y_ => y__ ## parse yaml attribute string

       as you can see, this is consistent with the new '_' tag generation: any
       method ending with one underscord is a generator. all methods ending in
       two are special methods.

       this is the major compatibilty breaker. sorry, but the new method is
       much more consistent and less typing.

     - fixed bug with rexml changes in 1.8.5 regarding order of sending doc
       preamble

   0.1.0:
     - added the "g_" method, which generates any tag
                                                    ^
         g_("anytag", "key" => "value"){ b_{ "bold" } }

     - added at_ and att_ methods to parse yaml and k=v strings as hashes.

         at_("src : image.jpg, width : 100%")

           #=> {"src"=>"image.jpg", "width"=> "100%"}

   0.0.0:
     - initial version

AUTHORS

   dan fitzpatrick <dan@eparklabs.com>
   ara.t.howard <ara.t.howard@eparklabs.com>

BUGS

   please send bug reports to /dev/null. patches to addresses above. :wink:

LICENSE

   ePark Labs Public License version 1 Copyright (c) 2005, ePark Labs, Inc. and
   contributors All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

     1. Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.

     2. Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.

     3. Neither the name of ePark Labs nor the names of its contributors may be
     used to endorse or promote products derived from this software without
     specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-a
--
we can deny everything, except that we have the possibility of being better.
simply reflect on that.
- the dalai lama

For some reason I want a Mexican beer at lunch now :wink:

Clever use of method missing, though. Can this package generate XML
tags that contain a dash '-' character?

TwP

···

On 2/16/07, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

NAME

   xx

Sort of reminds me of Markaby:
http://markaby.rubyforge.org/

harp:~ > cat a.rb
require "xx"
include XX::XML

legs = 1,2,3,4

doc = xml_{
   _('furniture:table'){
     legs.each do |leg|
       _ "furniture:leg-#{ leg }", leg
     end
   }
}

puts doc.pretty

harp:~ > ruby a.rb
     <?xml version='1.0'?>
     <furniture:table>
       <furniture:leg-1>1</furniture:leg-1>
       <furniture:leg-2>2</furniture:leg-2>
       <furniture:leg-3>3</furniture:leg-3>
       <furniture:leg-4>4</furniture:leg-4>
     </furniture:table>

cheers.

-a

···

On Sat, 17 Feb 2007, Tim Pease wrote:

On 2/16/07, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

NAME

   xx

For some reason I want a Mexican beer at lunch now :wink:

Clever use of method missing, though. Can this package generate XML
tags that contain a dash '-' character?

TwP

--
we can deny everything, except that we have the possibility of being better.
simply reflect on that.
- the dalai lama

Or Builder:

http://raa.ruby-lang.org/project/builder/

James Edward Gray II

···

On Feb 16, 2007, at 11:11 AM, Tim Becker wrote:

Sort of reminds me of Markaby:
http://markaby.rubyforge.org/

safer than the first, easier than the second, and does both :wink:

-a

···

On Sat, 17 Feb 2007, James Edward Gray II wrote:

On Feb 16, 2007, at 11:11 AM, Tim Becker wrote:

Sort of reminds me of Markaby:
http://markaby.rubyforge.org/

Or Builder:

http://raa.ruby-lang.org/project/builder/

--
we can deny everything, except that we have the possibility of being better.
simply reflect on that.
- the dalai lama

So simple! The XML namespace example should have clued me in -- need
more coffee.

As Tim Becker mentioned, this is a lot like Markaby, but it fixes some
of Markaby's shortcomings -- mainly support for valid XML tag
characters not currently allowed in method_missing and/or symbols.

Thanks Ara. Thanks Dan.

TwP

···

On 2/16/07, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

On Sat, 17 Feb 2007, Tim Pease wrote:

> On 2/16/07, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
>>
>> NAME
>>
>> xx
>>
>
> For some reason I want a Mexican beer at lunch now :wink:
>
> Clever use of method missing, though. Can this package generate XML
> tags that contain a dash '-' character?
>
> TwP
>

harp:~ > cat a.rb
require "xx"
include XX::XML

legs = 1,2,3,4

doc = xml_{
   _('furniture:table'){
     legs.each do |leg|
       _ "furniture:leg-#{ leg }", leg
     end
   }
}

puts doc.pretty

harp:~ > ruby a.rb
     <?xml version='1.0'?>
     <furniture:table>
       <furniture:leg-1>1</furniture:leg-1>
       <furniture:leg-2>2</furniture:leg-2>
       <furniture:leg-3>3</furniture:leg-3>
       <furniture:leg-4>4</furniture:leg-4>
     </furniture:table>

cheers.

markaby has #tag! which is same as #_ however (AFAICT) markaby does
html, not xml.

the builder pattern is pretty common now. Facets has a class one can
use to build any kind you'd like called BuildingBlock. you simply
apply a helper object for specially defined "tags" and the method to
use as the default. Very basic example:

  require 'facets/more/buildingblock'

  module BasicXMLMarkup
    extend self

    def element( tag, body=nil, atts={} )
      atts = atts.collect{ |k,v| %{ #{k}="#{v}"} }.join('')
      if body
        "<#{tag}#{atts}>#{body}</#{tag}>"
      else
        "<#{tag}#{atts} />"
      end
    end
  end

  builder = BuildingBlock.new(BasicXMLMarkup, :element)

  builder.html do
    h1 "Hello World", :class=>"big"
  end

produces

  "<html><h1 class=\"big\">Hello World</h1></html>"

BuildingBlock is not limited to XML type markups. you can use
BuildingBlock to make other types of builders too. an Outline bulder
for instance should be pretty easy (you can use the to_roman method :wink:

T.

···

On Feb 16, 12:34 pm, "Tim Pease" <tim.pe...@gmail.com> wrote:

On 2/16/07, ara.t.how...@noaa.gov <ara.t.how...@noaa.gov> wrote:

> On Sat, 17 Feb 2007, Tim Pease wrote:

> > On 2/16/07, ara.t.how...@noaa.gov <ara.t.how...@noaa.gov> wrote:

> >> NAME

> >> xx

> > For some reason I want a Mexican beer at lunch now :wink:

> > Clever use of method missing, though. Can this package generate XML
> > tags that contain a dash '-' character?

> > TwP

> harp:~ > cat a.rb
> require "xx"
> include XX::XML

> legs = 1,2,3,4

> doc = xml_{
> _('furniture:table'){
> legs.each do |leg|
> _ "furniture:leg-#{ leg }", leg
> end
> }
> }

> puts doc.pretty

> harp:~ > ruby a.rb
> <?xml version='1.0'?>
> <furniture:table>
> <furniture:leg-1>1</furniture:leg-1>
> <furniture:leg-2>2</furniture:leg-2>
> <furniture:leg-3>3</furniture:leg-3>
> <furniture:leg-4>4</furniture:leg-4>
> </furniture:table>

> cheers.

So simple! The XML namespace example should have clued me in -- need
more coffee.

As Tim Becker mentioned, this is a lot like Markaby, but it fixes some
of Markaby's shortcomings -- mainly support for valid XML tag
characters not currently allowed in method_missing and/or symbols.

right, but with that approach, or that of markaby, tags like 'p', 'id',
'size', et all are clobbered. with builder they've solved this by making the
user pass the builder to all blocks, but that's a lot of typing!

-a

···

On Sat, 17 Feb 2007, Trans wrote:

So simple! The XML namespace example should have clued me in -- need
more coffee.

As Tim Becker mentioned, this is a lot like Markaby, but it fixes some
of Markaby's shortcomings -- mainly support for valid XML tag
characters not currently allowed in method_missing and/or symbols.

markaby has #tag! which is same as #_ however (AFAICT) markaby does
html, not xml.

the builder pattern is pretty common now. Facets has a class one can
use to build any kind you'd like called BuildingBlock. you simply
apply a helper object for specially defined "tags" and the method to
use as the default. Very basic example:

require 'facets/more/buildingblock'

module BasicXMLMarkup
   extend self

   def element( tag, body=nil, atts={} )
     atts = atts.collect{ |k,v| %{ #{k}="#{v}"} }.join('')
     if body
       "<#{tag}#{atts}>#{body}</#{tag}>"
     else
       "<#{tag}#{atts} />"
     end
   end
end

builder = BuildingBlock.new(BasicXMLMarkup, :element)

builder.html do
   h1 "Hello World", :class=>"big"
end

produces

"<html><h1 class=\"big\">Hello World</h1></html>"

--
we can deny everything, except that we have the possibility of being better.
simply reflect on that.
- the dalai lama

Well, that's partly true. BuildingBlock removes all but a few methods,
so 'p', 'id', and 'size' are fine. In any case, while the underscore
notation you present is the least clobbering of all of them, in the
end there are always some cases that one must use the special call for
(eg, #_ or #tag!). it's just a matter of little more or a little less,
and a few extra feautres along the way (for example, markaby can
calsses added more easily: h1.big "Hello World"). btw, i think markaby
is built ontop of builder too, oddly enough.

anyway, i'm not trying to be argumentative or anything. i'm just
saying that I think, on the whole, each of these solutions about as
good as any other.

T.

···

On Feb 16, 2:06 pm, ara.t.how...@noaa.gov wrote:

On Sat, 17 Feb 2007, Trans wrote:

>> So simple! The XML namespace example should have clued me in -- need
>> more coffee.

>> As Tim Becker mentioned, this is a lot like Markaby, but it fixes some
>> of Markaby's shortcomings -- mainly support for valid XML tag
>> characters not currently allowed in method_missing and/or symbols.

> markaby has #tag! which is same as #_ however (AFAICT) markaby does
> html, not xml.

> the builder pattern is pretty common now. Facets has a class one can
> use to build any kind you'd like called BuildingBlock. you simply
> apply a helper object for specially defined "tags" and the method to
> use as the default. Very basic example:

> require 'facets/more/buildingblock'

> module BasicXMLMarkup
> extend self

> def element( tag, body=nil, atts={} )
> atts = atts.collect{ |k,v| %{ #{k}="#{v}"} }.join('')
> if body
> "<#{tag}#{atts}>#{body}</#{tag}>"
> else
> "<#{tag}#{atts} />"
> end
> end
> end

> builder = BuildingBlock.new(BasicXMLMarkup, :element)

> builder.html do
> h1 "Hello World", :class=>"big"
> end

> produces

> "<html><h1 class=\"big\">Hello World</h1></html>"

right, but with that approach, or that of markaby, tags like 'p', 'id',
'size', et all are clobbered. with builder they've solved this by making the
user pass the builder to all blocks, but that's a lot of typing!

abosolutely! i'm just stating the reasons __i__ went ahead and did something
slight different so people have the context to make choices.

cheers.

-a

···

On Sat, 17 Feb 2007, Trans wrote:

Well, that's partly true. BuildingBlock removes all but a few methods, so
'p', 'id', and 'size' are fine. In any case, while the underscore notation
you present is the least clobbering of all of them, in the end there are
always some cases that one must use the special call for (eg, #_ or #tag!).
it's just a matter of little more or a little less, and a few extra feautres
along the way (for example, markaby can calsses added more easily: h1.big
"Hello World"). btw, i think markaby is built ontop of builder too, oddly
enough.

anyway, i'm not trying to be argumentative or anything. i'm just saying that
I think, on the whole, each of these solutions about as good as any other.

--
we can deny everything, except that we have the possibility of being better.
simply reflect on that.
- the dalai lama