How to move classes into their own file - ruby

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.

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

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

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

Including the same module file within itself in Ruby?

I am learning ruby and about modules and mixins..
I tried the following code. The name of the ruby file test.rb.
module Mod1
def Mod1.sayHello()
puts "Hello Mod1"
end
end
module Mod2
def Mod2.sayHello()
puts "Hello Mod2"
end
end
class TestMod
require 'file'
Mod1.sayHello
end
t = TestMod.new
I am suprised to the output:
Hello Mod1
Hello Mod1 (twice)
I am don't have an explanation for this, can somebody help?
You did not define your initialize method for your class (the constructor). You are simply executing Mod1.sayHello inside the class definition (it is even executed before creating the instance). Try to comment out your t = TestMod.new statement. The output will still stay visible.
Since you include the exact same file, this ends up being executed twice (the file does not get included another time afterwards; ruby prevents this). The class should look like this:
class TestMod
def initialize
Mod1.sayHello
end
end
Why did you include the file anyway? This does not make sense to me.
EDIT: Removed a mistake.
I would recommend to replace the Mod1 and Mod2 inside your module definitions with self. This way you wont have to change the name everywhere if it changes some time.

Resources