[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[ANN] tagz-5.0.0

ara.t.howard

3/24/2009 4:30:00 AM


NAME

tagz.rb

SYNOPSIS

require Tagz

include Tagz.globally

a_(:href => "/foo"){ "bar" } #=> <a href="/foo">bar</a>

DESCRIPTION

tagz.rb is generates html, xml, or any sgml variant like a small
ninja
running across the backs of a herd of giraffes swatting of heads
like a
mark-up weedwacker. weighing in at less than 300 lines of code
tagz.rb adds
an html/xml/sgml syntax to ruby that is both unobtrusive, safe, and
available
globally to objects without the need for any builder or superfluous
objects.
tagz.rb is designed for applications that generate html to be able
to do so
easily in any context without heavyweight syntax or scoping issues,
like a
ninja sword through butter.

FEATURES

- use as a library or mixin

- simple, clean and consistent mark-up that is easy to visually
distinguish from other ruby methods

- auto-compatibility with rails/actionview

- ability to independently open and close tagz in markup

- intelligent auto-escaping of both attributes and content for both
html
and xml

- validate your html/xml with 'ruby -c' syntax check

- generally bitchin

- no lame method_missing approach that prevents tagz like 'type'
from being
generated

RAILS

in config/environment.rb

require 'tagz'

in a helper

def list_of_users
ul_(:class => 'users'){
@users.each{|user| li_{ user }}
}
end

in a view

<%=
table_{
rows.each do |row|
tr_{
row.each do |cell|
td_{ cell }
end
}
end
}
%>

in a controller

def ajax_responder
text =
tagz{
table_{
rows.each do |row|
tr_{
row.each do |cell|
td_{ cell }
end
}
end
}
}

render :text => text
end

INSTALL

gem install tagz

HISTORY
5.0.0
- introduce better escaping for attributes using xchar.rb approach
- indroduce smart escaping for content
- make Tagz.globally kick ass more hard
- note that this version is not backward compatibile if you were
relying
on tagz never escaping any content should be an ok upgrade for
most
applications

4.6.0
- fix a bug with self closing tagz that had crept in 1.0.0 ->
4.2.0. thx
jeremy hinegardner

- added tests from 1.0.0 back into svn

4.4.0
- remove dependancy on cgi lib, tagz is now completely standalone

4.3.0
- detect rails and auto-include into ActionController::Base and
include
globally into ActionView::Base

4.2.0
- general lib cleanup
- introduction of dual-mixin technique (Tagz.globally)
- few small bug fixes
- ninja tales

SAMPLES

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

~ > cat samples/a.rb

#
# in the simplest case tagz generates html using a syntax which
safely mixes
# in to any object
#

require 'tagz'
include Tagz.globally

class GiraffeModel
def link
a_(:href => "/giraffe/neck/42"){ "whack!" }
end
end

puts GiraffeModel.new.link

~ > ruby samples/a.rb

<a href="/giraffe/neck/42">whack!</a>


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

~ > cat samples/b.rb

#
# tagz.rb mixes quite easily with your favourite templating
engine, avoiding
# the need for '<% rows.each do |row| %> ... <% row.each do |
cell| %> '
# madness and other types of logic to be coded in the templating
language,
# leaving templating to template engines and logic and looping to
ruby -
# unencumbered by extra funky syntax. in rails tagz will
automatically be
# available in your erb templates.
#

require 'tagz'
include Tagz.globally

require 'erb'

rows = %w( a b c ), %w( 1 2 3 )

template = ERB.new <<-ERB
<html>
<body>
<%=
table_{
rows.each do |row|
tr_{
row.each do |cell|
td_{ cell }
end
}
end
}
%>
</body>
</html>
ERB

puts template.result(binding)


~ > ruby samples/b.rb

<html>
<body>
<table><tr><td>a</td><td>b</td><td>c</td></tr><tr><td>1</
td><td>2</td><td>3</td></tr></table>
</body>
</html>


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

~ > cat samples/c.rb

#
# once you've learned to generate html using tagz you're primed
to generate
# xml too
#

require 'tagz'
include Tagz.globally

doc =
xml_{
giraffe_{ 'large' }
ninja_{ 'small' }
}

puts doc

~ > ruby samples/c.rb

<xml><giraffe>large</giraffe><ninja>small</ninja></xml>


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

~ > cat samples/d.rb

#
# tagz.rb doesn't cramp your style, allowing even invalid html to
be
# generated. note the use of the 'tagz' method, which can be
used both to
# capture output and to append content to the top of the stack.
#

require 'tagz'
include Tagz.globally

def header
tagz{
html_
body_(:class => 'ninja-like', :id => 'giraffe-slayer')

___ "<!-- this is the header -->"
}
end

def footer
tagz{
___ "<!-- this is the footer -->"

body_
html_
}
end

puts header, footer

~ > ruby samples/d.rb

<html><body class="ninja-like" id="giraffe-slayer">
<!-- this is the header -->

<!-- this is the footer -->
<body><html>


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

~ > cat samples/e.rb

#
# tagz.rb allows a safer method of mixin which requires any tagz
methods to be
# insider a tagz block - tagz generating methods outside a tagz
block with
# raise an error if tagz is included this way. also notice that
the error is
# reported from where it was raised - not from the bowels of the
the tagz.rb
# lib.
#

require 'tagz'
include Tagz

puts tagz{
html_{ 'works only in here' }
}

begin
html_{ 'not out here' }
rescue Object => e
p :backtrace => e.backtrace
end


~ > ruby samples/e.rb

<html>works only in here</html>
{:backtrace=>["samples/e.rb:17"]}


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

~ > cat samples/f.rb

#
# tagz.rb can generate really compact html. this is great to
save bandwidth
# but can sometimes make reading the generated html a bit rough.
of course
# using tidy or the dom inspector in firebug obviates the issue;
nevertheless
# it's sometime nice to break things up a little. you can use
'tagz << "\n"'
# or the special shorthand '__' or '___' to accomplish this
#

require 'tagz'
include Tagz.globally

html =
div_{
span_{ true }
__
span_{ false } # hey ryan, i fixed this ;-)
___

___ 'foo & escaped bar'
}

puts html

~ > ruby samples/f.rb

<div><span>true</span>
<span>false</span>

foo & escaped bar
</div>


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

~ > cat samples/g.rb

# tagz gives you low-level control of the output and makes even
dashersized
# xml tagz easy enough to work with
#

require 'tagz'
include Tagz.globally

xml =
root_{
tagz__('foo-bar', :key => 'foo&bar'){ 'content' }

tagz__('bar-foo')
tagz.concat 'content'
tagz.concat tagz.escape('foo&bar')
__tagz('bar-foo')
}

puts xml


~ > ruby samples/g.rb

<root><foo-bar key="foo&amp;bar">content</foo-bar><bar-
foo>contentfoo&amp;bar</bar-foo></root>




a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




54 Answers

Trans

3/24/2009 4:49:00 AM

0



On Mar 24, 12:30=A0am, "ara.t.howard" <ara.t.how...@gmail.com> wrote:

> =A0 =A0- no lame method_missing approach that prevents tagz like 'type' =
=A0
> from being
> =A0 =A0 =A0generated

If you are not using method_missing than I take it one can't use it to
generate arbitrary XML?

T.

ara.t.howard

3/24/2009 4:58:00 AM

0


On Mar 23, 2009, at 10:48 PM, trans wrote:

>
>
> On Mar 24, 12:30 am, "ara.t.howard" <ara.t.how...@gmail.com> wrote:
>
>> - no lame method_missing approach that prevents tagz like 'type'
>> from being
>> generated
>
> If you are not using method_missing than I take it one can't use it to
> generate arbitrary XML?



it uses method_missing, just not in a lame way ;-)

cfp:~ > ruby -r tagz -e' include Tagz.globally; puts
anything_{ you_{ want_{ "can be generated" } } } '
<anything><you><want>can be generated</want></you></anything>


cfp:~ > ruby -r tagz -e' include Tagz.globally; raises_an_error{} '
-e:1: undefined method `raises_an_error' for main:Object (NoMethodError)



it is also very clever


cfp:~ > cat a.rb
require 'tagz'
include Tagz.globally

a = this_{ is_{ '<escaped>' } }
puts a

b = this_{ is_not_double_escaped_{ a } }
puts b



cfp:~ > ruby a.rb
<this><is>&lt;escaped&gt;</is></this>
<this><is_not_double_escaped><this><is>&lt;escaped&gt;</is></this></
is_not_double_escaped></this>


cheers.



a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




Brian Candler

3/24/2009 10:40:00 AM

0

Ara Howard wrote:
> tagz.rb is generates html, xml, or any sgml variant like a small
> ninja
> running across the backs of a herd of giraffes swatting of heads
> like a
> mark-up weedwacker.

Looks interesting.

Aside: people looking at this might also be interested in HAML. Several
of your examples look very similar to how I use HAML with Sinatra.

> in a helper
>
> def list_of_users
> ul_(:class => 'users'){
> @users.each{|user| li_{ user }}
> }
> end

def list_of_users
haml :_list_of_users
end

...
@@ _list_of_users
%ul{:class=>'users'}
- @users.each do |user|
%li&= user

Alternatively it can be done inline:

def list_of_users
haml <<HAML
%ul{:class=>'users'}
- @users.each do |user|
%li&= user
HAML
end

> in a view
>
> <%=
> table_{
> rows.each do |row|
> tr_{
> row.each do |cell|
> td_{ cell }
> end
> }
> end
> }
> %>

%table
- rows.each do |row|
%tr
- row.each do |cell|
%td&= cell

> in a controller
>
> def ajax_responder
> text =
> tagz{
> table_{
> rows.each do |row|
> tr_{
> row.each do |cell|
> td_{ cell }
> end
> }
> end
> }
> }
>
> render :text => text
> end

def ajax_responder
haml :_ajax_table
end

...
@@ _ajax_table
%table
- rows.each do |row|
%tr
- row.each do |cell|
%td&= cell

I can see that tagz works particularly well where you want to generate
HTML snippets directly inline with your code. The inline form of HAML is
a bit icky because it needs to align with the left-hand edge. You could
fix this with a helper, but I prefer partials because they are easily
precompiled and cached.

Regards,

Brian.
--
Posted via http://www.ruby-....

ara.t.howard

3/24/2009 2:55:00 PM

0


On Mar 24, 2009, at 4:40 AM, Brian Candler wrote:

> Ara Howard wrote:
>> tagz.rb is generates html, xml, or any sgml variant like a small
>> ninja
>> running across the backs of a herd of giraffes swatting of heads
>> like a
>> mark-up weedwacker.
>
> Looks interesting.
>
> Aside: people looking at this might also be interested in HAML.
> Several
> of your examples look very similar to how I use HAML with Sinatra.

you mean combining erb with the dsl i assume?

>>
> def ajax_responder
> haml :_ajax_table
> end
>
> ...
> @@ _ajax_table
> %table
> - rows.each do |row|
> %tr
> - row.each do |cell|
> %td&= cell
>
> I can see that tagz works particularly well where you want to generate
> HTML snippets directly inline with your code. The inline form of
> HAML is
> a bit icky because it needs to align with the left-hand edge. You
> could
> fix this with a helper, but I prefer partials because they are easily
> precompiled and cached.



i've used this

def unindent! s
indent = nil
s.each do |line|
next if line =~ %r/^\s*$/
indent = line[%r/^\s*/] and break
end
s.gsub! %r/^#{ indent }/, "" if indent
s
end

def unindent s
unindent! "#{ s }"
end


to get around that 'left hand side' issue.

cheers!

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




Brian Candler

3/24/2009 3:44:00 PM

0

Ara Howard wrote:
> you mean combining erb with the dsl i assume?

At a lower level, the use of hashes to represent attributes is
strikingly similar. e.g.

a_(:href => "/foo"){ "bar" }

compared to HAML:

%a{:href => "/foo"} bar
or
%a{:href => "/foo"}= "bar"

HAML lets you put any Ruby expression inside %a{...} which returns a
hash. Of course, tagz is real Ruby code, whereas HAML is its own
language.

The other thing which struck me was your use of nesting to build tables.
HAML really excels here, and the indentation-driven syntax means you
don't have to balance the closing parts. Somehow I find this more
natural for web page templates than for code.

> i've used this
>
> def unindent! s

Yes, that's the sort of thing I was thinking of. HAML like this would
still need to go via a compilation phase each time it is executed,
whereas tagz is just run. Hence the benefit to keeping HAML snippets
separate and cached.

Regards,

Brian.
--
Posted via http://www.ruby-....

matt

3/24/2009 4:58:00 PM

0

ara.t.howard <ara.t.howard@gmail.com> wrote:

> On Mar 23, 2009, at 10:48 PM, trans wrote:
>
> >
> >
> > On Mar 24, 12:30 am, "ara.t.howard" <ara.t.how...@gmail.com> wrote:
> >
> >> - no lame method_missing approach that prevents tagz like 'type'
> >> from being
> >> generated
> >
> > If you are not using method_missing than I take it one can't use it to
> > generate arbitrary XML?
>
> it uses method_missing, just not in a lame way ;-)

Not in a lame way, but in a way that means it can't be used in some
architectures. This is a very simplified version of what I'm really
doing, but it shows the problem. I'm using Builder like this:

require 'rubygems'
require 'builder'
require 'erb'

class BindingMaker
def get_binding; binding; end
def do_your_thing
s = ""
Builder::XmlMarkup.new(:target => s).div(testing)
puts s
end
def testing
"it worked"
end
end

ERB.new("<% do_your_thing %>").result(BindingMaker.new.get_binding)
#=><div>it worked</div>

I'd like to switch to Tagz here but its method_missing isn't coming back
to my BindingMaker to resolve unrecognized terminology:

require 'rubygems'
require 'tagz'
require 'erb'

class BindingMaker
def get_binding; binding; end
def do_your_thing
puts Tagz {div_ {testing()}}
end
def testing
"it worked"
end
end

ERB.new("<% do_your_thing %>").result(BindingMaker.new.get_binding)
#=> NoMethodError: undefined method 'testing' for Tagz:Module

m.
--
matt neuburg, phd = matt@tidbits.com, http://www.tidbits...
Leopard - http://www.takecontrolbooks.com/leopard-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

ara.t.howard

3/24/2009 5:02:00 PM

0


On Mar 24, 2009, at 9:43 AM, Brian Candler wrote:

> Ara Howard wrote:
>> you mean combining erb with the dsl i assume?
>
> At a lower level, the use of hashes to represent attributes is
> strikingly similar. e.g.
>
> a_(:href => "/foo"){ "bar" }
>
> compared to HAML:
>
> %a{:href => "/foo"} bar
> or
> %a{:href => "/foo"}= "bar"
>
> HAML lets you put any Ruby expression inside %a{...} which returns a
> hash. Of course, tagz is real Ruby code, whereas HAML is its own
> language.
>
> The other thing which struck me was your use of nesting to build
> tables.
> HAML really excels here, and the indentation-driven syntax means you
> don't have to balance the closing parts. Somehow I find this more
> natural for web page templates than for code.


gotcha.

one thing i *really* like about tagz, for real mark-up coding, is that
i can use % in vim to match open/close tags in vim (or whatever your
fav is) and also can use 'ruby -c' to validate my markup. because it
is valid ruby code you get all the ruby goodness and ruby editor
goodness for free. it was a side effect i hadn't intended when
writing it but have grown to rely on - sorta like tab completion: i
just can't go back to visually scanning to make sure xml is balanced
and correct ;-) my goal is generally to factor out enough tagz so my
erb templates fit on one screen and then i just trust tagz/ruby for
the rest.

cheers.

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




Martin DeMello

3/24/2009 5:09:00 PM

0

On Tue, Mar 24, 2009 at 10:32 PM, ara.t.howard <ara.t.howard@gmail.com> wro=
te:
> sorta like tab completion: i just can't go back to visually scanning to m=
ake
> sure xml is balanced and correct ;-) =A0my goal is generally to factor ou=
t

matchit.vim :)

martin

ara.t.howard

3/24/2009 5:13:00 PM

0


On Mar 24, 2009, at 10:56 AM, matt neuburg wrote:

> I'd like to switch to Tagz here but its method_missing isn't coming
> back
> to my BindingMaker to resolve unrecognized terminology:

you are trying too hard ;-)


cfp:~ > cat a.rb
require 'rubygems'
require 'tagz'
require 'erb'

class BindingMaker
include Tagz.globally

def get_binding; binding; end

def do_your_thing
puts div_{ testing }
end

def testing
"it worked"
end
end

ERB.new("<% do_your_thing %>").result(BindingMaker.new.get_binding)
# <div>it worked</div>


cfp:~ > ruby a.rb
<div>it worked</div>



tagz can be used as a library, like you were using it, but in that
case you need to be explicit about the receiver. tagz is much simpler
to use in it's primary capacity - as mix-in - it is in this way that
completely POLS sgml generation and context/binding sensitivity can be
had. the binding hack traditional builders use is there precisely to
disambiguate between contexts - tagz simply avoids the issue
altogether. that's what i meant by 'lame': it's totally open, and yet
in a separate context with the builder pattern.


kind regards.



a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




ara.t.howard

3/24/2009 5:14:00 PM

0


On Mar 24, 2009, at 11:09 AM, Martin DeMello wrote:

> matchit.vim :)

i use that actually - but it really really crawls on large xml docs
with syntax hl off. with tagz you just need a { another } and then to
bounce on the % key.

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama