A
Ara.T.Howard
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.
HISTORY
2.1.0:
- introduction of XX::Template (see samples h,i,j)
- fixed and indentation bug (too much)
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 'x' 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>
<========< samples/h.rb >========>
~ > cat samples/h.rb
require "xx"
#
# xx supports templates with grace and applomb
#
template = XX::Template::Inline.new <<-xhtml
xhtml_{
html_{
body_{
table_{ @table.each{|row| tr_{ row.each{|cell| td_ cell} }} }
b_ local_variable
}
}
}
xhtml
@table = [
%w( a b c ),
%w( x y z ),
]
local_variable = 'local_variable'
template.expand binding
~ > ruby samples/h.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>
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
<tr>
<td>x</td>
<td>y</td>
<td>z</td>
</tr>
</table>
<b>local_variable</b>
</body>
</html>
<========< samples/i.rb >========>
~ > cat samples/i.rb
require "xx"
#
# file based templates are also supported
#
xhtml = <<-xhtml
xhtml_{
html_{
body_{
table_{ @table.each{|row| tr_{ row.each{|cell| td_ cell} }} }
b_ local_variable
}
}
}
xhtml
# generate template on the fly
require "tempfile"
t = Tempfile.new Process.pid.to_s
t << xhtml
t.close
template = XX::Template::File.new t.path
@table = [
%w( a b c ),
%w( x y z ),
]
local_variable = 'local_variable'
template.expand binding
~ > ruby samples/i.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>
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
<tr>
<td>x</td>
<td>y</td>
<td>z</td>
</tr>
</table>
<b>local_variable</b>
</body>
</html>
<========< samples/j.rb >========>
~ > cat samples/j.rb
require "xx"
#
# the return type of all tag_ methods are suitable for injection into a
# doccument, so you can break apart html generation into methods. note that
# these methods are not returning strings, but REXML elements which can be
# injected into other doccuments
#
class Table < Array
include XX::XHTML
def to_html
xhtml_{ html_{ body_{ table_{ each{|row| row_html row} } } } }
end
def row_html row
tr_{ row.each{|cell| cell_html cell} }
end
def cell_html cell
td_{ cell }
end
end
t = Table[ %w( 0 1 2 ), %w( 3 4 5 ) ]
puts t.to_html
~ > ruby samples/j.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>
<table>
<tr>
<td>0</td>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</table>
</body>
</html>
AUTHORS
dan fitzpatrick <[email protected]>
ara.t.howard <[email protected]>
BUGS
please send bug reports to /dev/null. patches to addresses above. ;-)
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
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.
HISTORY
2.1.0:
- introduction of XX::Template (see samples h,i,j)
- fixed and indentation bug (too much)
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 'x' 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>
<========< samples/h.rb >========>
~ > cat samples/h.rb
require "xx"
#
# xx supports templates with grace and applomb
#
template = XX::Template::Inline.new <<-xhtml
xhtml_{
html_{
body_{
table_{ @table.each{|row| tr_{ row.each{|cell| td_ cell} }} }
b_ local_variable
}
}
}
xhtml
@table = [
%w( a b c ),
%w( x y z ),
]
local_variable = 'local_variable'
template.expand binding
~ > ruby samples/h.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>
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
<tr>
<td>x</td>
<td>y</td>
<td>z</td>
</tr>
</table>
<b>local_variable</b>
</body>
</html>
<========< samples/i.rb >========>
~ > cat samples/i.rb
require "xx"
#
# file based templates are also supported
#
xhtml = <<-xhtml
xhtml_{
html_{
body_{
table_{ @table.each{|row| tr_{ row.each{|cell| td_ cell} }} }
b_ local_variable
}
}
}
xhtml
# generate template on the fly
require "tempfile"
t = Tempfile.new Process.pid.to_s
t << xhtml
t.close
template = XX::Template::File.new t.path
@table = [
%w( a b c ),
%w( x y z ),
]
local_variable = 'local_variable'
template.expand binding
~ > ruby samples/i.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>
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
<tr>
<td>x</td>
<td>y</td>
<td>z</td>
</tr>
</table>
<b>local_variable</b>
</body>
</html>
<========< samples/j.rb >========>
~ > cat samples/j.rb
require "xx"
#
# the return type of all tag_ methods are suitable for injection into a
# doccument, so you can break apart html generation into methods. note that
# these methods are not returning strings, but REXML elements which can be
# injected into other doccuments
#
class Table < Array
include XX::XHTML
def to_html
xhtml_{ html_{ body_{ table_{ each{|row| row_html row} } } } }
end
def row_html row
tr_{ row.each{|cell| cell_html cell} }
end
def cell_html cell
td_{ cell }
end
end
t = Table[ %w( 0 1 2 ), %w( 3 4 5 ) ]
puts t.to_html
~ > ruby samples/j.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>
<table>
<tr>
<td>0</td>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</table>
</body>
</html>
AUTHORS
dan fitzpatrick <[email protected]>
ara.t.howard <[email protected]>
BUGS
please send bug reports to /dev/null. patches to addresses above. ;-)
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