Pull specific methods from a module into the global namespace in ruby - 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

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 Sinatra Helpers Available in Modules everywhere?

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

How to call a method from a module of an other ruby file

I have to Ruby files: one contains a module with some methods for statistical calculation, in the other file I want to call one of the methods in the module.
How can I do that in Ruby?
Is that the right way?
require 'name of the file with the module'
a=[1,2,3,4]
a.method1
Require needs the absolute path to the file unless the file is located in one of Ruby's load paths. You can view the default load paths with puts $:. It is common to do one of the following to load a file:
Add the main file's directory to the load path and then use relative paths with require:
$: << File.dirname(__FILE__)
require "my_module"
Ruby 1.8 code that only loads a single file will often contain a one-liner like:
require File.expand_path("../my_module", __FILE__)
Ruby 1.9 added require_relative:
require_relative "my_module"
In the module you will need to define the methods as class methods, or use Module#module_function:
module MyModule
def self.method1 ary
...
end
def method2
...
end
module_function :method2
end
a = [1,2,3,4]
MyModule.method1(a)
Your way is correct if your module file is in the require search path.
If your module provide methods to be used by the object itself, you must do:
require 'name of the file with the module'
a=[1,2,3,4]
a.extend MyModule # here "a" can use the methods of MyModule
a.method1
See Object#extend.
Otherwise, if you'll use the methods directly by the module, you'll use:
MyModule.method1(a)

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