From: Chris Eskow Date: 2006-08-08T10:08:03+09:00 Subject: Extracting instance variables from a block? Hello fellow Rubyists, I am writing a tiny custom web framework, similar in nature to web.py (http://webpy.org/). However, I'd like someone with better metaprogramming-foo to help me clean up some syntax a bit. Here's a _very_ basic abbreviated version of the framework: class Web def initialize @pages = {} @vars = {} end # Associates a URI regular expression with a block of code. def page(regexp, &action) @pages[/^#{regexp}$/] = action end # Sets a variable for use in the template. See the example below. def []=(var, val) @vars[var] = val end # Renders the given ERB template file. def render(template) o = Object.new def o.b; binding; end @vars.each { |var, val| o.instance_variable_set("@#{var}", val) } print CGI.new.header('text/html') ERB.new(File.read(template)).run(o.b) end # Compares each regexp in @pages to ENV['REQUEST_URI']. If a match # is found, calls the associated action block, passing in the match # results as arguments. def run for regexp, action in @pages if ENV['REQUEST_URI'] =~ regexp action[*$~.to_a[1..-1]] return end end # Oh noes! 404 error handling stuff goes here. end end A simple application would look something like this: web = Web.new web.page '/hello/(\w+)' do |name| web[:title] = 'Hello' web[:name] = name web.render 'hello.rhtml' end web.run # Contents of hello.rhtml <%= @title %>

Hello, <%= @name %>!

How are you today?

The Web#run method reads the request URI, and sees if it matches with any of your defined regexps. If it does, it runs the block of code you associated that URL with (passing in any needed parameters). So when you visit http://example.com/hello/_why, it displays a nice welcome message to _why. As you can see, you can use web[:foo] = 'bar' to set an instance variable, @foo, in the template's binding. This is all nice and great, but the syntax is a bit... crusty. I'd love to do something like this instead: web.page '/hello/(\w+)' do |name| @title = 'Hello' @name = name web.render 'hello.rhtml' end So, my question: is there any way to capture the instance variables set in the block, and use them for a template binding elsewhere? Or at least do something else that gives me my desired results? Thanks, Chris -- Posted via http://www.ruby-forum.com/.