Sunder
Sunder

Reputation: 1513

Sinatra, DRY and scoping

I'm looking for ways to DRY my Sinatra app and have run into some scoping issues -- in particular, helpers and Sinatra functions are not available inside my handlers. Can someone please tell me if there's a way to fix this code and more importantly, what is going on?

Thank you.

require 'sinatra'
require 'pp'

helpers do
  def h(txt)
    "<h1>#{txt}</h1>"
  end
end

before do
  puts request.path
end


def r(url, get_handler, post_handler = nil)
  get(url){ get_handler.call } if get_handler
  post(url){ post_handler.call } if post_handler
end


routes_composite_hash = {
    '/' => lambda{ h('index page'); pp params }, #can't access h nor params!!!
    '/login' => [lambda{'login page'}, lambda{'login processing'}],
    '/postonly' => [nil, lambda{'postonly processing'}],
}

routes_composite_hash.each_pair do |k,v|
  r(k, *v)
end

Upvotes: 2

Views: 288

Answers (2)

shime
shime

Reputation: 9008

Interesting!

Do this:

def r(url, get_handler, post_handler = nil) 
  get(url, &get_handler) if get_handler
  post(url, &post_handler) if post_handler
end


routes_composite_hash = {
    '/' => lambda{ h('index page'); pp params },
    '/login' => [lambda{'login page'}, lambda{'login processing'}],
    '/postonly' => [nil, lambda{'postonly processing'}],
}

routes_composite_hash.each_pair do |k,v|
  r(k, *v)
end

As Kashyap explains, you were calling your get and post handlers inside the main context. This just converts sent lambda to a block and passes it to the desired method.

Upvotes: 2

Kashyap
Kashyap

Reputation: 4796

The methods you define inside helpers do .. end blocks are available only inside routes and filters and views contexts and thus, since you are not using them inside any of those, it won't work. Lambdas preserve the execution context which means that in the hash {'/' => lambda { h }..}, the context is main but inside the get method, the context changes and the helpers are available only in this context.

To achieve what you want to do though, (although I would suggest you avoid doing this), you can just define the helpers as lambdas inside your app file itself. In your case, it would be:

def h(txt) 
  "<h1>#{txt}</h1>"
end

# And then the rest of the methods and the routes hash

This way, the h method is in the context of the main object and thus will be visible all over.

Upvotes: 1

Related Questions