Ruby: Can I 'require' a file which contains only a class? - ruby

I have a file /project/lib/invaccessor.rb with the following content
class InvAccessor
def initialize
#browser = "browser"
end
end
and a spec file project/spec/invaccessor_spec.rb which requires it
require_relative '../lib/invaccessor'
describe Invaccessor do
it {expect(2).to be_even}
end
When I run rspec spec/invaccessor.rb I get an uninitialized constant error for Invaccessor. Do I have to put all file contents in a module in order to access them?
I'm using Ruby 2.2.2.

Yes, you can.
Try this inside the directory where your classfile.rb lies:
>> require './classfile'
=> true
>> A
=> A
You definitely don't have to put a class into a module to require it.

Related

Using inheritance with multiple files in Ruby

I am new to Ruby . I have a question with respect to using Inheritence in Ruby .
I have a class called as Doggy inside a file named Doggy.rb
class Doggy
def bark
puts "Vicky is barking"
end
end
I have written another class named Puppy in another file named puppy.rb
class Puppy < Doggy
end
puts Doggy.new.bark
I am getting this Error:
Puppy.rb:1:in `<main>': uninitialized constant Doggy (NameError)
Is it mandatory to have these classes (Doggy and Puppy ) inside a single file only?
Edited
As per the suggestions , i have tried using require and require_relative as shown , but still i am getting below Error
Puppy.rb:1:in `<main>': uninitialized constant Doggy (NameError)
class Puppy < Doggy
end
require_relative 'Doggy.rb'
puts Doggy.new.bark
Changes to be done in puppy.rb file
Assuming both files are in the same directory, you're expected to require the file in the following way:
doggy.rb
class Doggy
def bark
puts "Vicky is barking"
end
end
puppy.rb
require File.expand_path('../doggy.rb', __FILE__)
class Puppy < Doggy
end
puts Doggy.new.bark
You should require file with Doggy class in it from file where Puppy is. Put
require './doggy'
or, if you are on ruby-1.9:
require_relative 'doggy'
in puppy.rb (assuming file names are doggy.rb and puppy.rb).
Also, in addition to what everyone else has said, puts Dog.new.bark will always fail, because your class is not called Dog, it's Doggy. Beware.
Not necessary, you have to require the file where Doggy is declared. You can use require or require_relative.
Then, anyway make sure you use the name you declared: Doggy and not Dog.
You are loading the file containing the definition of Doggy, after you inherit from Doggy. Of course, that cannot possibly work. How can you inherit from Doggy on line 1 if you only load the file containing the definition of Doggy on line 3?
You have to include Doggy.rb in you Puppy class

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)

How to share variables across my .rb files?

I have a few .rb files and I want to use the same variables in all of them. Let's say variable test_variable = "test" should be accessible from all my .rb files. How can I achieve that?
I created settings.rb file with test_variable = "test" then used require 'settings' in another .rb file, but it didn't work. I would like to use require not load.
I tried to make the variable global by prefixing the variable name with $, but I am still getting undefined local variable or method 'test_variable' for main:Object (NameError).
Constants (which include modules and classes) are added to the shared global environment:
phrogz$ cat constants1.rb
TEST_VARIABLE = "test"
phrogz$ cat constants2.rb
require_relative 'constants1'
p TEST_VARIABLE
phrogz$ ruby constants2.rb
"test"
Instance variables declared in main are all part of the same main:
phrogz$ cat instance1.rb
#test_variable = "test"
phrogz$ cat instance2.rb
require_relative 'instance1'
p #test_variable
phrogz$ ruby instance2.rb
"test"
Global variables are also all part of the same environment (tested in 1.8.6, 1.8.7, and 1.9.2):
phrogz$ cat global1.rb
$test_variable = "test"
phrogz$ cat global2.rb
require_relative 'global1'
p $test_variable, RUBY_DESCRIPTION
phrogz$ ruby global2.rb
"test"
"ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.7.0]"
Ruby will never share local variables between files. You can wrap them in a Module though:
module SharedVaribles
#test_var="Hello, World"
def self.test_var
return #test_var
end
def self.test_var=(val)
#test_val=val;
end
end
Put that in settings.rb, require it into all your files, and use SharedVaribles.test_var and SharedVaribles.test_var= to access the variable. Remember, Ruby's require is nothing like C's #include, it is much more complex. It executes the file, then imports all constants, modules, and classes to the requireer.
module Foo
attr_accessor :test_var
def initialize
#test_var = "hello world"
end
end
Create the module with your variable or variables in your config file and then include the module in whatever class you intend to use.
require_relative 'foomod.rb'
class Bar
include Foo
end
foobar = Bar.new
foobar.test_var = "goodbye"
puts foobar.test_var
Each instance of the class will initialize with whatever value you would like.
You shouldn't need to wrap these variables in a module.
Simply adding them to another_file.rb and using require_relative 'another_file' (if it's in the same directory) or require 'path/to/another_file' should be sufficient to share those variables across files.

Require file without executing code?

Here I have two files:
file.rb
def method
puts "This won't be outputted."
end
puts "This will be outputted."
main.rb
require "./file"
When running main.rb it will load all the code inside file.rb so I will get "This will be outputted." on the screen.
Is it possible to load a file without having it to run the code?
Cause I want to load all the methods (in modules and classes too) without having to execute code outside these scopes.
Is it possible to load a file without having it to run the code?
No, everything in a ruby file is executable code, including class and method definitions (you can see this when you try to define a method inside an if-statement for example, which works just fine). So if you wouldn't execute anything in the file, nothing would be defined.
You can however tell ruby that certain code shall only execute if the file is run directly - not if it is required. For this simply put the code in question inside an if __FILE__ == $0 block. So for your example, this would work:
file.rb
def method
puts "This won't be outputted."
end
if __FILE__ == $0
puts "This will not be outputted."
end
main.rb
require "./file"
the if __FILE__ == $0 is nice, but a way more in keeping with ruby's Object Oriented approach is to put all the methods you want access to in a class (as class methods), and then call them from main.rb.
e.g.
file.rb
class MyUtils
def self.method
puts "this won't be outputted"
end
end
and then in main.rb
require "/.file.rb"
and when you want to use your utility methods:
MyUtils.method
I don't think modifying file is good idea - there are could be a lot of files like this one or these files belong to customer and a ton of another reasons.
Ruby is good at metaprogramming so why don't use this feature?
It could be like this.
Create file with fake module and put here the file.
File.open("mfile.rb","w") do |f|
f.write "module FakeModule
"
f.write File.open("file.rb").read
f.write "
end"
end
Then load this file:
require "/.mfile.rb
and accessing to the method:
FakeModule::method

Rspec, mapping spec files to ruby files under test

What I want is a way of not having to 'require' the class under test in each spec file.
So hoping there is a means of setting the root of the source code under test and rspec automatically mapping my tests, or any other means of automatically mapping specs to ruby files.
In Rspec for rails this happens magically, but this is not a rails project and I can't find any useful information.
I am assuming you have a lib folder and a spec folder within your project where you have code and specs respectively. Create a spec/spec_helper.rb and add
# project_name/spec/spec_helper.rb
$: << File.join(File.dirname(__FILE__), "/../lib")
require 'spec'
require 'main_file_within_lib_folder_that_requires_other_files'
Now within your individual spec files now you just need to add the following line like rails
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
What you have to do is to redefine Object.const_missing.
Found this basic example, modify it to fit your needs (set the right path, etc.):
def Object.const_missing(name)
#looked_for ||= {}
str_name = name.to_s
raise "Class not found: #{name}" if #looked_for[str_name]
#looked_for[str_name] = 1
file = str_name.downcase
require file
klass = const_get(name)
return klass if klass
raise "Class not found: #{name}"
end

Resources