Can't include ruby modules correctly - ruby

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

Related

Use a class instance inside a module

I'm trying to do this:
example_module.rb
module ExampleModule
def example_method
...
ExampleClass.new.do_something(arg_one, arg_two)
end
end
example_class.rb
class ExampleClass
def initialize()
...
end
def do_something(arg_first, arg_second)
...
end
end
#>> Runtime error - uninitialized constant ExampleModule::ExampleClass
Is it possible to use a class instance inside a module? I found examples that do the opposite; they use a module to extend a class. What am I missing? Is there an article that explains this better?
Add this on top of your example_module.rb file.
require ./example_class'

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 to autoload a class in ruby

I have a module as follows
-path of class MyClass lib/a/b/myclass.rb
module A
module B
class MyClass
puts 'inside myclass'
end
end
end
Now i want to autoload the above class from a file in root directory.
File name : dostuff
def main
autoload A::B:MyClass,'a/b/myclass.rb' #path is correct , getting error here
c = A::B:MyClass.new
end
main
Am getting error: uninitialized constant A::B::MyClass (NameError)
If i use require as follows and delete autoload code everything works fins.
require 'a/b/myclass'
You're asking too much of the auto-loader. It can really only deal with one level at a time. That means you need this by expressing each module or class in a separate file:
# a.rb
module A
autoload(:B, 'a/b')
end
# a/b.rb
module A::B
autoload(:MyClass, 'a/b/my_class')
end
# a/b/my_class.rb
class A::B::MyClass
end
Then you can auto-load A:
autoload(:A, 'a')
A::B::MyClass.new
It's also highly unconventional to have a main function in Ruby. Normally you just put code at the top level in a context that is already called main.

How do I import ruby classes into the main file?

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.

How can I refer to a module method without referring to the entire namespace?

I have a module defined as:
module MyApp
module Utility
def Utility.my_method
I want to use that method in several other classes. But I don't want to have to call:
MyApp::Utility.my_method
I would rather just call:
Utility.my_method
Is that reasonable? I've tried include MyApp::Utility and include MyApp to no avail.
Well, just assign any alias you want, e.g.:
ShortNameGoesHere = MyApp::Utility
ShortNameGoesHere.my_method
Here is an example of mixing in my_method to a class:
#myapp.rb
module MyApp
module Utility
def my_method
"called my_method"
end
end
end
#test.rb
require './myapp'
class MyClass
include MyApp::Utility
end
if __FILE__ == $0 then
m = MyClass.new
puts m.my_method
end
It sounds like you want to maintain the namespace of the module on the mixed-in method. I have seen attempts to do so (https://stackoverflow.com/a/7575460/149212) but it seems pretty messy.
If you need my_method to be namespaced, you could simply include a module identifier in the method name:
module MyApp
module Utility
def util_my_method
"called my_method"
end
end
end

Resources