1

In Sinatra/Padrino where is a sensible place to add constants for use inside routes?

I'm using Padrino to mount multiple apps so I want the constants available to all apps. (All apps inherit from a base class.)

I've used Sinatra.helpers to add methods for use inside routes.

I was hoping for a similar approach for constants.

Update

This appears to be a scoping issue, but I can't figure out what's wrong in this scenario.

Here is a stripped down padrino app which demonstrates the problem:

app.rb

class MyProject < Padrino::Application
  register Padrino::Rendering
  register Padrino::Mailer
  register Padrino::Helpers

  MY_CONST = 123
end

controllers.rb

MyProject.controller do
  get "/" do
    p self.class            # => MyProject
    p self.class.constants  # => [:DATA_ATTRIBUTES, ... <snip>..., :MY_CONST, ... <snip>... ]
    p MyProject::MY_CONST   # => 123
    p MY_CONST              # => NameError - uninitialized constant MY_CONST
  end
end
stubotnik
  • 1,952
  • 2
  • 17
  • 31
  • you could add a class constant they should be available everywhere just like class vars. – three Sep 19 '12 at 13:19
  • in the app class? constants added to app classes which extend Padrino::Application are not available inside routes. – stubotnik Sep 19 '12 at 13:34

2 Answers2

1

OK, so apparently I'm hitting an issue with how Ruby handles constant lookups within a proc that is instance_evaled.

Here is a Padrino-free way to recreate the error:

class Thing

  MY_CONST = 123

  def doStuff (&block)
    p "doStuff: #{self.class}"        # => "doStuff: Thing"
    p "doStuff: #{MY_CONST}"          # => "doStuff: 123"

    instance_eval &block
  end

  def doOtherStuff (&block)
    p "doOtherStuff: #{self.class}"   # => "doOtherStuff: Thing"
    p "doOtherStuff: #{MY_CONST}"     # => "doOtherStuff: 123"

    yield 
  end
end

t = Thing.new

t.doStuff do 
  doOtherStuff do
    p self.class             # => Thing
    p self.class.constants   # => [:MY_CONST]
    p Thing::MY_CONST        # => 123
    p MY_CONST               # => NameError: uninitialized constant MY_CONST
  end
end

Related question: Constant Lookup with instance_eval in Ruby 1.9

Related blog post: http://jfire.io/blog/2011/01/21/making-sense-of-constant-lookup-in-ruby/

So it looks like my options are limited to:

  1. Use a global constant
  2. Fully specify the constant (eg: Thing::MY_CONST in the example above)
  3. Use a method instead
Community
  • 1
  • 1
stubotnik
  • 1,952
  • 2
  • 17
  • 31
0

Mmm, maybe I didn't understand but you could use apps.rb

Padrino.configure do
   set :foo, :bar
end

Then you should be able in all your apps to retrieve your var.

Or In boot or apps.rb add some like:

MY_CONST = 1
MyConst = 1
DAddYE
  • 1,719
  • 11
  • 16
  • OK cool. I can now use "settings.foo" in my route. That's progress :-) I am still hoping that my routes can use constants as if they were local (ie: unscoped). Is that not possible? – stubotnik Sep 20 '12 at 07:50
  • thanks again. I also assumed that adding the constant to app.rb would work fine. but I'm still having problems. I've updated the question with example code. thanks. – stubotnik Sep 21 '12 at 12:50
  • If you want use it in a global env keep it outside class, otherwise look the final part of the `NameError` it will show you `uninitialized constant MY_CONST for ...` – DAddYE Sep 21 '12 at 16:42