How do I import ruby classes into the main file? - ruby

I'm trying to learn how to program with Ruby and I want to create separate files for separate classes, but when I do I get the following message:
NameError: uninitialized constant Book
const_missing at org/jruby/RubyModule.java:2677
(root) at /Users/Friso/Documents/Projects/RubyApplication1/lib/main.rb:1
However, it works if I put the class directly into the main file. How can I solve this?
Main code:
book1 = Book.new("1234", "Hello", "Ruby")
book2 = Book.new("4321", "World", "Rails")
book1.to_string
book2.to_string
Class code:
class Book
def initialize(isbn,title,author)
#book_isbn=isbn
#book_title=title
#book_author=author
end
def to_string
puts "Title: ##book_title"
puts "Author: ##book_author"
puts "ISBN: ##book_isbn"
end
end

In order to include classes, modules, etc into other files you have to use require_relative or require (require_relative is more Rubyish.) For example this module:
module Format
def green(input)
puts"\e[32m#{input}[0m\e"
end
end
Now I have this file:
require_relative "format" #<= require the file
include Format #<= include the module
def example
green("this will be green") #<= call the formatting
end
The same concept goes for classes:
class Example
attr_accessor :input
def initialize(input)
#input = input
end
def prompt
print "#{#input}: "
gets.chomp
end
end
example = Example.new(ARGV[0])
And now I have the main file:
require_relative "class_example"
example.prompt
In order to call any class, or module from another file, you have to require it.
I hope this helps, and answers your question.

You need to instruct the Ruby runtime to load the file that contains your Book class. You can do this with require or require_relative.
The latter is better in this case, because it loads the file relative to the directory in which the file containing the require is specified. Since that's probably the same directory, you can just require_relative the file name, without the .rb extension by convention.
You can google 'require vs require_relative ruby' to find out more about the differences.

Related

Ruby Template Design Pattern folder convention

I'm requesting a high-level overview of how to structure the directory of a project using the Template Design Pattern in Ruby.
I have a project directory with one venue.rb file and one folder containing base.rb. I see them used a lot in my companies Ruby on Rails project but would like to understand how to structure the project regarding the template design pattern independent of Rails.
Current Setup:
~./project
+--venue.rb
+--venue
|
+--base.rb
venue.rb
require_relative 'venue/base'
class Venue
end
puts "Loaded class Venue:"
a = Venue.new
a.base
~./project/venue/base.rb
module Base
class Venue
def base
puts "base"
end
end
end
puts "Loaded module Base:"
When I run the venue.rb I get:
#=> ruby venue.rb
Loaded module Base:
Loaded class Venue:
venue.rb:9:in `<main>': undefined method `base' for #<Venue:0x007fe77209cf20>
(NoMethodError)
I'm pretty sure I've misunderstood inheritance but I believe this should work.
The nice thing about require (and require_relative) in Ruby is that it's almost equivalent with just substituting the text of the script for the require.
So your venue.rb is pretty much
module Base
class Venue
def base
puts "base"
end
end
end
puts "Loaded module Base:"
class Venue
end
puts "Loaded class Venue:"
a = Venue.new
a.base
This declares two different classes called Venue that are in different namespaces: ::Venue and Base::Venue. When you do a = Venue.new you are referring to the ::Venue one that has no base method (or any methods, for that matter).
If you want your Base module to modify the top-level Venue, you need to specifically refer to it:
module Base
class ::Venue
def base
puts "base"
end
end
end
You're missing the module namespace in venue.rb by adding it you can fix the undefined class and also remove the class definition stub.
require_relative 'base'
puts "Loaded class Venue:"
a = Base.Venue.new
a.base

How to require file as part of a module in Ruby?

I have a file SomethingClass.rb which looks as follows:
class SomethingClass
def initialize
puts "Hello World"
end
end
I would like to require the file SomethingClass.rb, and make SomethingClass part of the module SomethingModule without changing the file.
Also, I would like to avoid making SomethingClass part of the namespace outside of that module at all. In other words, I want to require the file and the rest of my application should not change apart from the fact that SomethingModule will be defined.
This does not work (I assume because require is executed in Kernel scope):
module SomethingModule
require './SomethingClass.rb'
end
Is this possible in Ruby?
Without changing your class file, from what I've gathered, there are only kind of hacky ways to do this - see Load Ruby gem into a user-defined namespace and How to undefine class in Ruby?.
However I think if you allow yourself to modify the class file, it is a little easier. Probably the simplest thing to do would be to set the original class name to something that will surely have no name conflict, e.g.:
class PrivateSomethingClass
def initialize
puts "Hello World"
end
end
module SomethingModule
SomethingClass = PrivateSomethingClass
end
Now you have SomethingModule::SomethingClass defined but not SomethingClass on the global namespace.
Another way to do it would be to use a factory method and anonymous class:
class SomethingClassFactory
def self.build
Class.new do
def initialize
"hello world"
end
end
end
end
module SomethingModule
SomethingClass = SomethingClassFactory.build
end

How can I inherit module in ruby script?

I have a hierarchy like
ABC(Folder) ----> abc.rb, def.rb
DEF(Folder) ----> a1.rb, b1.rb
GHI(Folder) ----> x1.rb, y1.rb
I want to inherit/include def.rb, which is a module into abc.rb and then a1 should inherit abc.rb and should be able to access all methods defined in def.rb.
Right now, I am including def.rb in every script file, but I don't want to do this. I just want to inherit vertically.
It's hard to deal with ABC-like naming system )
If you want to include 10 modules in each of your classes, you can do it this way. Let's imagine you have modules ModuleTest::Files and ModuleTest::Network:
in module_test/network.rb
module ModuleTest
module Network
def network
puts 'hello from ModuleTest::Network#network'
end
end
end
in module_test/files.rb
module ModuleTest
module Files
def files
puts 'hello from ModuleTest::Files#files'
end
end
end
You can make some ModuleTest::Base class like this:
require 'module_test/files'
require 'module_test/network'
module ModuleTest
class Base
include Files
include Network
end
end
This class includes all the functionality you have, so inherit your classes from it:
require 'module_test/base'
class Foo < ModuleTest::Base
end
foo = Foo.new
foo.network
foo.files
Output:
>ruby -I. foo.rb
hello from ModuleTest::Network#network
hello from ModuleTest::Files#files
Let my first point out that I suspect that I'm misinterpreting your question, because I can't see why you'd want to do this. So if that's the case, please point it out and I'll delete this.
The process you describe works (at least for me in Ruby 1.9.3).
module Def
def method_from_def
puts "Method from Def"
end
end
class Abc
include Abc
end
class X < Abc
end
X.new.method_from_def #=> "Method from Def"
You might need to be a little specific in your require statements, but if you're already able to 'include' the script you've already got that down. (Unless by 'include' you mean copy and paste it into the source file.)

How to call or activate a class?

In my lib folder I have billede.rb:
class Billede
require 'RMagick'
#some code that creates a watermark for a image
image.write(out)
end
How do I call/activate the class? Is the only way to change it to a Rake task?
You can't call a class directly. You have to call a method on that class. For example:
class Billede
def self.foobar
# some kind of code here...
end
end
Then you can call it via Billede.foobar
Perhaps you should read some documentation on basic ruby syntax before trying to do more complex things (such as manipulating images w/ Rmagick).
Code 'inside a class' is run just like any other code. If you have a Ruby file like this:
puts "Hello from #{self}"
class Foo
puts "Hello from #{self}"
end
and you run the file (either via ruby foo.rb on the command line or require "./foo" or load "foo.rb" in a script) it then you will see the output:
Hello from main
Hello from Foo
If you want to load a utility that 'does something' that you can then invoke from a REPL like IRB or the Rails console, then do this:
module MyStuff
def self.do_it
# your code here
end
end
You can require "./mystuff" to load the code, and when you're ready to run it type MyStuff.do_it
And, as you may guess, you can also create methods that accept arguments.
If you want to define a file that can be included in others (with no immediate side effects) but which also "does its thing" whenever the file is run by itself, you can do this:
module MyStuff
def self.run!
# Go
end
end
MyStuff.run! if __FILE__==$0
Now if you require or load this file the run! method won't be invoked, but if you type ruby mystuff.rb from the command line it will.
# in /lib/billede.rb
class Billede
def self.do_something(arg)
# ...
end
def do_anotherthing(arg)
# ...
end
end
# inside a model or controller
require 'billede'
Billede::do_something("arg")
# or
billede_instance = Billede.new
billede_instance.do_anotherthing("arg")

Can't include ruby modules correctly

I'm kinda new to Ruby, so I'm not even sure if what I'm doing is best practice. Right now I am trying to define a function import that resides in a module on something.rb:
require 'rexml/document'
module MyModule
def import(file)
Document.new(File.new(file))
end
end
I have another file somethingelse.rb that calls on file something.rb that will use function import
require 'something.rb'
class MyClass
include MyModule
def initialize(file)
#myFile = import(file)
end
end
The problem only arises when I try to import the module from another file. When I use the module in the same file, everything works according to what you'd expect. The errors I get are:
usr/lib/ruby/1.8/rexml/dtd/elementdecl.rb:8: warning: already initialized constant PATTERN_RE
XMLTest.rb:9: uninitialized constant MyModule (NameError)
What am I doing wrong?
You need to require the other file you're trying to load in your first file, Ruby won't do that for you automatically. So if your module is in a file named "something.rb":
require "something"
class MyClass
include MyModule
def initialize(file)
#myFile = import(file)
end
end
try changing your rexml require to require_once.
So:
require_once 'rexml/document'
you can you use require_relative to import the file that has your module
use include to add the module in the class to access the module
class MyClass
include somethingModuleName
end

Resources