[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Store erb block and alter scope of erb block eval?

Steve V

4/18/2005 9:55:00 PM

I tried posting this in the Rails list, and didn't get any responses, so
maybe there's someone here that can help me with my problem.

I'm trying to modularize some display functionality within my Rails app. I
need to be able to store an erb block, and then evaluate it 1 or more times
at a later point in time. Two questions here, which are driving me crazy!

1) How can I store an erb block captured using do for later use? Regular
variable assignment doesn't appear to work.

def content(&block)
@raw_content = block
end

The above does not work. However, if I evaluate 'block' within the content
method call, then the evaluation works. If I try to evaluate @raw_content at
a later point through another function it just returns nothing. So how
exactly do I store 'block' for later use?

2) When evaluating 'block', how can I get it to use the variables present
within the scope of the calling function, or at least within the calling
class? As it stands now, it will only take variables that have been defined
in the controller, and not my class.

rhtml file
<%r = Renderer.new()
r.content do%>
<%=@sometext%>
<%end%>
<%=r.render()%>

rb file
class SomeController < ApplicationController
def blah()
@sometext = "blah"
end
end

class Renderer
def content(&block)
@sometext = "content"
buffer = eval("_erbout", block.binding);
pos = buffer.length
block.call

@data = buffer[pos..-1]

buffer[pos..-1] = ""
end

def render()
@data
end
end

The above will render "blah", and not "content", even if the definition of
@sometext is removed from the controller, the eval will not take from the
class.

Any help would be greatly appreciated.

Thanks,
Steve




6 Answers

Gavin Kistner

4/19/2005 1:25:00 AM

0

On Apr 18, 2005, at 3:54 PM, Steve V wrote:
> 1) How can I store an erb block captured using do for later use?
> Regular
> variable assignment doesn't appear to work.

Works for me:

class Foo
def set_block( &block ); @meth = block; end
def call_block( *args ); @meth.call( *args ); end
end

f = Foo.new
f.set_block { |x,y| p x,y }
f.call_block 3,4
#=>3
#=>4


> 2) When evaluating 'block', how can I get it to use the variables
> present
> within the scope of the calling function, or at least within the
> calling
> class?

require 'erb'

class Foo
def rhtml=( str )
@rhtml = ERB.new( str )
end
def run1
localvar = 'run1'
@rhtml.result( binding )
end
def run2
localvar = 'run2'
@rhtml.result( binding )
end
end

f = Foo.new
f.rhtml = '<p><%= localvar %></p>'
p f.run1
#=> "<p>run1</p>"
p f.run2
#=> "<p>run2</p>"



Steve V

4/19/2005 2:57:00 AM

0


> Works for me:
>
> class Foo
> def set_block( &block ); @meth = block; end
> def call_block( *args ); @meth.call( *args ); end
> end
>
> f = Foo.new
> f.set_block { |x,y| p x,y }
> f.call_block 3,4
> #=>3
> #=>4

>
> > 2) When evaluating 'block', how can I get it to use the variables
> > present
> > within the scope of the calling function, or at least within the
> > calling
> > class?
>
> require 'erb'
>
> class Foo
> def rhtml=( str )
> @rhtml = ERB.new( str )
> end
> def run1
> localvar = 'run1'
> @rhtml.result( binding )
> end
> def run2
> localvar = 'run2'
> @rhtml.result( binding )
> end
> end
>
> f = Foo.new
> f.rhtml = '<p><%= localvar %></p>'
> p f.run1
> #=> "<p>run1</p>"
> p f.run2
> #=> "<p>run2</p>"
>

Is there something special erb does when you capture a block from an rhtml
page? I tried passing my own variable values to the block within my
class(separate from the controller), and the values are ignored. I think the
heart of the problem is that you're calling ERB.new on a regular string. I
need to capture this information from an rhtml page. The only way I have
found to do that is by using a "do" block.

r.content do%>
Test <%=@sometext%>
<%end%>

This gives me a block, and not a string. Is there a way to turn the contents
of the returned proc as a string? to_s just gives me the memory location(?)
of the proc object.

The other question is why aren't my variables used for the block call when
I'm in the class? Does it have something to do with the existing scope of
the proc object? Can I change the scope? The only place I can get that
@sometext value to be used from is within the controller. I have tried
defining @sometext within my separate class, and passing that into the call,
but nothing happens.

def content(&block)
@sometext = "sometext"
@data = block.call(@sometext)
end

def render()
return @data
end

The above will just render "Test ", and not use the specified value for
@sometext.

Steve




Steve V

4/19/2005 5:24:00 PM

0


> Is there something special erb does when you capture a block from an rhtml
> page? I tried passing my own variable values to the block within my
> class(separate from the controller), and the values are ignored.
> I think the
> heart of the problem is that you're calling ERB.new on a regular string. I
> need to capture this information from an rhtml page. The only way I have
> found to do that is by using a "do" block.
>
> r.content do%>
> Test <%=@sometext%>
> <%end%>
>
> This gives me a block, and not a string. Is there a way to turn
> the contents
> of the returned proc as a string? to_s just gives me the memory
> location(?)
> of the proc object.
>
> The other question is why aren't my variables used for the block call when
> I'm in the class? Does it have something to do with the existing scope of
> the proc object? Can I change the scope? The only place I can get that
> @sometext value to be used from is within the controller. I have tried
> defining @sometext within my separate class, and passing that
> into the call,
> but nothing happens.
>
> def content(&block)
> @sometext = "sometext"
> @data = block.call(@sometext)
> end
>
> def render()
> return @data
> end
>
> The above will just render "Test ", and not use the specified value for
> @sometext.

After some more experimenting, I have made a little more progress, but I'm
still not able to use a compiled ERB template.

<%r.data = %q{%>
So close! <%=blah%>
<%}%>

The above rhtml code will get me a string into my class, but it isn't
"\t\tSo close! <%=blah%>\n\t" as expected. Instead it is what appears to be
some type of parsed string: "; _erbout.concat "\n" _erbout.concat "\t\tSo
close! "; _erbout.concat((@blah).to_s); _erbout.concat "\n" _erbout.concat
"\t"; "

I can use eval() on the above, with the binding of the working class which
sort of solves the problem. Can anyone tell me what piece I'm missing here
to keep the code suitable for loading into an ERB template?

Thanks,
Steve




Gavin Kistner

4/20/2005 2:13:00 PM

0

On Apr 18, 2005, at 8:56 PM, Steve V wrote:
> Is there something special erb does when you capture a block from an
> rhtml
> page? I tried passing my own variable values to the block within my
> class(separate from the controller), and the values are ignored. I
> think the
> heart of the problem is that you're calling ERB.new on a regular
> string. I
> need to capture this information from an rhtml page.

Can you be more specific about what you are doing? I don't understand
what you mean by "capture a block from an rhtml page".

Could you provide your full code showing the problem you are having?

(I'm not an ERb expert, so I'm probably missing some way of using it
that I've not seen before.)
--
"When I am working on a problem I never think about beauty. I only
think about how to solve the problem. But when I have finished, if the
solution is not beautiful, I know it is wrong."
- R. Buckminster Fuller



Steve V

4/20/2005 9:05:00 PM

0


>
> Can you be more specific about what you are doing? I don't understand
> what you mean by "capture a block from an rhtml page".
>
> Could you provide your full code showing the problem you are having?
>
> (I'm not an ERb expert, so I'm probably missing some way of using it
> that I've not seen before.)

Hmm, okay. As you will see from using the below. The <%=@title%> value will
only be taken from the value in the TestController. No matter what I do, I
cannot get the @title variable set in the TableBuilder class to be the one
that is used.

Steve

test.rhtml:
<%tb = TableBuilder.new("Table Title")
tb.header_template do%>
This is the header template <%=@title%>
<%end%>
<%=tb.render()%>

test_controller.rb:
class TestController < ApplicationController
def test()
#uncomment, and the title variable will
# be used in the template
#@title = "controller title"
end
end

class TableBuilder

def initialize(title = "")
@title = title
end

def header_template(&block)
@headerTemplate = block

end

def render()
out = ""

#do table building stuff.
_erbout = ""
#the below is taken from capture_helper.rb in
# rails action_view\helpers
buffer = eval("_erbout", @headerTemplate)
pos = buffer.length
@headerTemplate.call(binding)

out << buffer[pos..-1]
buffer[pos..-1] = ""

#do other table building stuff

return out
end
end




Steve V

4/20/2005 9:26:00 PM

0

> Hmm, okay. As you will see from using the below. The <%=@title%>
> value will
> only be taken from the value in the TestController. No matter what I do, I
> cannot get the @title variable set in the TableBuilder class to be the one
> that is used.

The primary goal of this all is to be able to use the variable from the
object scope other than the controller. The secondary goal is to be able to
cache a precompiled template. The method above gets me a proc object(I
think). If that is the case, are procs already compiled, or do they need to
be compiled at the time of execution? I wanted to store these as ERB
templates so that I could take advantage of caching them in a compiled
state. But if the procs are already compiled and there is a way to cache
them, then that would work as well.

Steve