load 'file.rb' versus require 'Module' in Ruby - ruby

I am confused about the difference between load 'file.rb' and require 'Module'. At Learn Ruby the Hard Way, the example of how to use a module is set up with two files (mystuff.rb and apple.rb):
mystuff.rb
module MyStuff
def MyStuff.apple()
puts "I AM APPLES!"
end
end
apple.rb
require 'mystuff'
MyStuff.apple()
However, when I run apple.rb, either in the Sublime Text console, or with ruby apple.rb, I get a Load Error. I have also tried require 'MyStuff', and require 'mystuff.rb', but I still get the Load Error.
So, I switched the first line of apple.rb to load 'mystuff.rb', which allows it to run. However, if I edit 'mystuff.rb' to be a definition of class MyStuff as opposed to a module MyStuff, there is no difference.
For reference, the Load Error is:
/Users/David/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in require': cannot load such file -- mystuff (LoadError)`
I've peeked into kernel_require.rb and looked at the require definition, but since I'm a Ruby Nuby (indeed, a programming newbie), it was a little overwhelming. Since Learn Ruby the Hard Way hasn't been updated since 2012-10-05, there've probably been some syntax changes for modules. Yes?

require searches a pre-defined list of directories, as discussed in What are the paths that "require" looks up by default?. It's failing because it can't find the mystuff.rb in any of those directories.
load, on the other hand, will look for files in the current directory.
As for:
However, if I edit 'mystuff.rb' to be a definition of class MyStuff as
opposed to a module MyStuff, there is no difference.
I'm not sure I understand what you mean by "no difference". If you mean that the require and load continue to fail and succeed, respectively, that makes sense, as the require failure is independent of the content of the file contents and the code you're testing behaves the same independent of whether Mystuff is a class or a vanilla module.

You can solve this easily by changing
require 'mystuff'
to
require_relative './mystuff'

Related

Odd behavior from Ruby's require

I'm writing a Ruby gem with lots of nested classes and such. I'd like to keep a huge list of require statements out of my main Ruby file in the /lib directory, so instead I used the following:
Dir[ File.join( File.dirname(__FILE__), "**", "*.rb" ) ].each {|f| require f}
which totally worked fine until this morning when I added a new file (helper module) and now the library is acting like that file isn't loaded, even though it is. I checked with
puts "loaded" if defined?(RealtimeArgHelpers)
I also duplicated the require statement to check to see if my new file is getting returned
Dir[ File.join( File.dirname(__FILE__), "**", "*.rb" ) ].each {|f| puts f}
and it is. I have to manually require this one file. Out of nowhere. I have 101 other files currently being gathered by this statement and everything works perfectly fine. But not this one file. I don't have any name conflicts besides
/path/arg_helpers.rb
/path/realtime/agents.rb
/path/realtime/queues.rb
/path/realtime.rb
/path/realtime_arg_helpers.rb
which still shouldn't be a 'conflict.' I'm completely baffled by the seemingly random behavior, unless I'm doing something illegal in the language. I tried renaming the module, renaming the file, no dice. Why is this one file not getting loaded?
The problem comes from the way require works in Ruby. Whenever a file is required (let's only consider the case of a .rb source file to keep it simple), Ruby parses the file and immediately executes the instructions that are not in methods. So if you use classes that are defined in files yet to be loaded, Ruby won't find them.
I don't really know if there is a recommended way used by the gem authors to deal with that, but coming from a C/C++ background I tend to favour explicitly requiring the dependencies in each source file, rather than trying to maintain a giant sorted list in the main.rb (or equivalent).

Delayed require - Uninitialized constant error

I have a conditional bit of code that only can be loaded under certain conditions. It's platform specific code.
module MyGem
module MyPlatformSpecificThing
#stuff
end
end
My current attempt at lazily requiring this is performed like:
module MyGem
class AClass
def DoSomething
if thing_is_true
require 'my_platform_specific_thing.rb'
MyGem::MyPlatformSpecificThing.init
#more stuff
end
#even more stuff
end
end
This seemed like a solid enough plan, unfortunately it is not working. This code results in an error:
uninitialized constant MyGem::MyPlatformSpecificThing (NameError)
The stack trace indicates the source of the error is the call to init within the DoSomething method.
I am not entirely sure why Ruby is giving me fits here. What am I doing wrong, and how should I be doing this?
edit:
For specifics, I'm referring to the Platform class located here. The above should help narrow down the details of what I'm referring to, but in case anyone wanted/needed to see the specific classes/modules I'm work with.
You've almost got it right. Remember that the require method loads relative to the load path. As you're making a gem you've added the gem lib directory to the load path. Change the require to:
require 'my_gem/bcm2835'
Or for PiPiper:
require 'pi_piper/bcm2835'
This should load only when a driver hasn't been set.
Your pseudo-code is bit incomplete and confusing, but I think this may be the problem. If I am mistaken, seeing your real code as complete as necessary could help.
Check this response as a reference.
Your example shows:
MyGem::MyPlatformSpecificThing.init
However, that format should have Module::Class.method. Your sample shows Module::Module.method.
The error message
uninitialized constant
is very specific in that it is recognizing the call as a constant, not a class.
The error you've specified...
uninitialized constant MyGem::MyPlatformSpecificThing (NameError)
... will only occur if the inner module (PiPiper::Bcm2835) is never actually defined; if the problem was with the actual call to the module function (init), you'd get a different error.
I notice you've commented out the require on line 10, platform.rb:
#require 'bcm2835.rb'
... and required the file elsewhere. Let me guess, this is solving your problem, no?
Taking another look, in its original form the require statement should have failed, unless you've already added the pi_piper directory to $LOAD_PATH. Try changing the lazy require to this:
require './bcm2835.rb'
But note that this will not work either if you change the working directory (Dir.chdir) at any point prior to executing this line.

Ruby, including module in current directory

I am currently working through the Well Grounded Rubyist. Great book so far. I am stuck on something I don't quite get with ruby. I have two files
In ModuleTester.rb
class ModuleTester
include MyFirstModule
end
mt = ModuleTester.new
mt.say_hello
In MyFirstModule.rb
module MyFirstModule
def say_hello
puts "hello"
end
end
When I run 'ruby ModuleTester.rb', I get the following message:
ModuleTester.rb:2:in <class:ModuleTester>': uninitialized constant ModuleTester::MyFirstModule (NameError)
from ModuleTester.rb:1:in'
From what I have found online, the current directory isn't in the the namespace, so it can't see the file. But, the include statement doesn't take a string to let me give the path. Since the include statement and require statements do different things, I am absolutely lost
as to how to get the include statement to recognize the module. I looked through other questions, but they all seem to be using the require statement. Any hints are greatly appreciated.
You use require to load a file, not include. :-)
First, you have to require the file containing the module you want to include. Then you can include the module.
If you're using Rails, it has some magic to automagically require the right file first. But otherwise, you have to do it yourself.
You need to require the file before you can use types defined in it. *
# my_first_module.rb
module MyFirstModule
def say_hello
puts 'hello'
end
end
Note the require at the beginning of the following:
# module_tester.rb
require 'my_first_module'
class ModuleTester
include MyFirstModule
end
mt = ModuleTester.new
mt.say_hello
The require method actually loads and executes the script specified, using the Ruby VM's load path ($: or $LOAD_PATH) to find it when the argument is not an absolute path.
The include method, on the other hand actually mixes in a Module's methods into the current class. It's closely related to extend. The Well Grounded Rubyist does a great job of covering all this, though, so I encourage you to continue plugging through it.
See the #require, #include and #extend docs for more information.
* Things work a bit differently when using Rubygems and/or Bundler, but getting into those details is likely to confuse you more than it's worth at this point.

Question about requiring files and the load path in Programming Ruby 1.9

I'm reading through "Programming Ruby 1.9". On page 208 (in a "Where to Put Tests" section), the book has the code organized as
roman
lib/
roman.rb
other files...
test/
test_roman.rb
other_tests...
other stuff
and asks how we get our test_roman.rb file to know about the roman.rb file.
It says that one option that doesn't work is to build the path into require statements in the test code:
# in test_roman.rb
require 'test/unit'
require '../lib/roman'
Instead, it says a better solution is for all other components of the application to assume that the top-level directory of the application is in Ruby's load path, so that the test code would have
# in test_roman.rb
require 'test/unit'
require '/lib/roman'
and we'd run the tests by calling ruby -I path/to/app path/to/app/test/test_roman.rb.
My question is: is this realy the best way? It seems like
If we simply replaced require '../lib/roman' in the first option with require_relative '../lib/roman', everything would work fine.
The assumption in the second option (that all components have the top-level directory in Ruby's load path) only works because we pass the -I path/to/app argument, which seems a little messy.
Am I correct that replacing require with require_relative fixes all the problems? Is there any reason to prefer the second option anyways?
Further on, that same book makes use of require_relative (Chapter 16, Organizing your source code) in the context of testing, so yes, I would say that using it is a Good Thing, since it "always loads files from a path relative to the directory of the file that invokes it".
Of course, like #christiangeek noticed, require_relative is new in the 1.9 series, but there's a gem that provides you with the same functionality.
It might be worth pointing out that the Pickaxe too provides a little method you can stick in your code in the same chapter I mentioned before.
require_relative does make the code cleaner but is only available natively on Ruby > 1.9.2. Which means if you want want your code to be portable to versions of Ruby < 1.9.2 you need to use a extension or the regular require AFAIK. The book is most likely a) written before 1.9.2 became widespread or b) providing a example for lowest common denominator.

Calling another ruby file that is not a gem

I want to create a static ruby class with a library of function. I am on Vista with ruby 1.9.2
My class is this one :
class TestClass
def say_hello
puts "say hello"
end
end
in a TestClass.rb file (I assume I am correct as all ruby tutorials on classes are a complete mess putting everything in a single magic something (file?) as if IRB was the begining and the end of all thing).
My ruby main() (yes I come from Java) or program entry or wathever it is called in ruby is :
require 'TestClass.rb'
puts "start"
say_hello
But it fails with :
C:\ruby_path_with_all_my_classes>ruby classuser.rb
<internal:lib/rubygems/custom_require>:29:in `require': no such file to load --
TestClass.rb (LoadError)
from <internal:lib/rubygems/custom_require>:29:in `require'
from classuser.rb:1:in `<main>'
How does it work? Is it possible to call other files in Ruby or are you trapped in only one file containing all your classes?
Is the TestClass file in the same dir?
Make the TestClass.rb file lowercase and load it with
require './testclass'
no need for the .rb
I'd suggest putting any classes in a lib folder.
Then you require file as follows:
require './lib/testclass'
In 99% of all cases when a computer tells you that it couldn't find a thing, it is because the thing isn't there. So, the first thing you need to check is whether there actually is a file named TestClass.rb somewhere on your filesystem.
In 99% of the rest of the cases, the computer is looking in the wrong place. (Well, actually, the computer is usually looking in the right place, but the thing it is looking for is in the wrong place). require loads a file from the $LOAD_PATH, so you have to make sure that the directory that the file TestClass.rb is in actually is on the $LOAD_PATH.
Alternatively, if you do not want to require a file from the $LOAD_PATH but rather relative to the position of the file that is doing the requireing, then you need to use require_relative.
Note, however, that your code won't work anyway, since say_hello is in instance method of instances of the TestClass class, but you are calling it on the main object, which is an instance of Object, not TestClass.
Note also that standard naming conventions of Ruby files are snake_case, in particular, the snake_case version of the primary class/module of the file. So, in your case, the file should be named test_class.rb. Also, require and require_relative figure out the correct file extension for themselves, so you should leave off the .rb. And thirdly, standard Ruby coding style is two spaces for indentation, not four.
None of these will lead to your code not working, of course, since it is purely stylistic, but it may lead to people being unwilling to answer your questions, since it shows that you don't respect their community enough to learn even the most basic rules.
Try using
require './TestClass.rb'
Related: Ruby: require vs require_relative - best practice to workaround running in both Ruby <1.9.2 and >=1.9.2

Resources