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
<html>
  <title><%= @title %></title>
  <h1>Hello, <%= @name %>!</h1>
  <p>How are you today?</p>
</html>

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/.