Make Sinatra Helpers Available in Modules everywhere? - ruby

How can I make my Sinatra helpers available everywhere?
Sometimes I can't access them (e.g. from modules, see below). I'd like them to be tied to the 'global namespace' s.t. they can be invoked by their name, from anywhere.
Below is a working Sinatra app demonstrating the problem.
require 'sinatra'
helpers do
def bar
"bar"
end
end
get '/helper' do
bar #works
end
get '/module_and_helper' do
Foo.foo #crashes. How can I fix this?
end
module Foo
extend self
def foo
bar
end
end
Thanks!

Thanks to #engineersmnky. Instead of using 'helpers do' you can define a separate Module and include it in the app, apparently rendering it available everywhere.
require 'sinatra'
module Helpers
extend self
def barrio
"barrio"
end
end
include Helpers
get '/helper' do
barrio #works
end
get '/module_and_helper' do
Foo.foo #works!
end
module Foo
extend self
def foo
barrio
end
end

Related

How do I require a file without defining it's constants on Object in Ruby?

I would like to require a file in Ruby without defining that file's constants on Object. Instead I would like to include them only in a module in the requiring file. For instance if I have a file foo.rb that looks like this:
module Foo
def self.hello_world
puts 'Hello, World.'
end
end
A representation of the result I hope to achieve looks something like this:
module Bar
require_relative './foo.rb'
end
Foo.hello_world
# NameError: uninitialized constant Foo
Bar::Foo.hello_world
# Hello, World.
It seems like the way things are required in Ruby, anything defined at the top level of another file will be defined as a constant on Object and thus globally available. I'm having a problem because I need something from a file that conflicts with a constant in the global namespace.
I recognize that this problem may be fundamental to Ruby, but is it possible there's some metaprogramming technique to overcome this issue?
It looks like the following snippet works for what I'm trying to do:
module Bar
class_eval File.open('./foo.rb').read
end
It may be that I'm still missing something though.
If you don't need to access the ancestor, what you're looking for is extend
module Foo
def hello_world
puts 'Hello, World.'
end
end
module Bar
extend Foo
end
Bar.hello_world

How to move classes into their own file

I have a structure like this in file foo.rb:
module Foo
def self.bar
Bar.new
end
class Bar
...
end
end
I want to extract the Bar class, and put it in a separate file, ideally in a folder. I'm struggling to extract the classes from the module into separate files. It is difficult to understand the difference between modules and classes, and where they should reside. I get the error uninitialized constant in my attempts.
Is there some naming convention to follow to make this work?
At the interpreter level, modules are similar to classes. Following rails conventions, you would have a separate file called bar.rb and require it at the top of module foo.
bar.rb:
class Bar
end
foo.rb:
require 'bar'
module Foo
def self.bar
Bar.new
end
end
If you want to put the bar file in a different folder, see info about require_relative which allows you to require a file from a path relative to the current file.

Make module method available without scoping

I am trying to do something very similar to rspec's describe.
Say I have a module in my_mod.rb
module MyMod
def say_hello(name)
puts "hello #{name}"
end
end
And I use it in another file foo.rb
include MyMod # without the include it cannot find say_hello
say_hello "world"
My question is - how do I get this to work like rspec, i.e. require-ing the module should make the methods available, without having to do MyMod.say_hello.
Change your original foo.rb, replacing include with extend.
This way, you can use say_hello "world"
But, if you really want to use require, define the method without the module:
my_mod.rb:
def say_hello(name)
puts "hello #{name}"
end
then, in foo.rb:
require 'my_mod'
say_hello "world"

Pull specific methods from a module into the global namespace in ruby

Is it possible to pull in functions from a module to the global namespace in ruby with specifically naming the functions (aka not the entire module)?
I have a module that didn't use a module originally, and I want to move the classes/methods into a module, but still keep around a module that will have everything at the global level for compatibility. So far I have this.
# graph.rb
require 'foo_graph'
include foo
# foo_graph.rb
module foo
# contents of the old graph.rb
end
But module foo is also in use in completely unrelated files and calling include could pull more stuff into the global namespace than I intend.
Is there a way for me to specify which functions I want to pull in with include or is there an alternative to do what I want?
Use submodules.
module Foo
module Bar
def bar_method; end
end
include Bar
module Baz
def baz_method; end
end
include Baz
end
# only include methods from Bar
include Foo::Bar
bar_method
#=> nil
baz_method
#=> NameError: undefined local variable or method `baz_method' for main:Object
include Foo
# include all methods from Foo and submodules
baz_method
#=> nil

ruby module inside module

I have a ruby module which includes many other modules. Here's a quick example:
module Foo
module Bar
end
module Baz
end
end
except, I have like 6-7 modules inside Foo module. Is there a way I can put Bar/Baz in separate file but still get the same behavior? Right now all my code is inside 1 file, very unorganized.
You can define them like this, each in a separate file:
# foo.rb
module Foo
end
# foo_bar.rb
module Foo::Bar
end
# foo_baz.rb
module Foo::Baz
end
NB. You will need to define the Foo module before being able to define modules such as Foo::Bar with this notation.
Or you could just put them in differently named files in the format they're currently in and it should still work:
# foo_bar.rb
module Foo
module Bar
end
end
# foo_baz.rb
module Foo
module Baz
end
end

Resources