ruby require not working - ruby

I'm new to ruby, but I'm working on my first ruby program. It currently has two files, one is a library of functions (xgync.rb stored in lib) the other is the executable xgync stored in 'bin'. (Project visible here https://bitbucket.org/jeffreycwitt/xgync/src) I've also created a symlink to my /usr/local/bin/xgync so that I can write the command xgync {arguments} from anywhere in the terminal.
The problem seems to be that bin/xgync depends on the library lib/xgync.rb. I've written this dependency in bin/xgync as follows:
$:.unshift(File.dirname(__FILE__) + '/../lib')
require "xgync"
However, i keep getting the following error:
/Users/JCWitt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- xgync (LoadError)
from /Users/JCWitt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /usr/local/bin/xgync:4:in `<main>'
can you see anything wrong with what I've written? Could the symlink be somehow messing things up?
Thanks for your help :)

When using ruby 1.9.x you don't usually alter the path with the $:.unshift when requiring other files in your project.
Instead the best practice is to use require_relative instead.
require_relative '../lib/xgync.rb'
require_relative requires files relative to the file you are currently editing.
But the error you experience appears, because you require a file, which does not exist:
bin/xgync
lib/xgync.rb
These are the files in your project according to your question, and the code-excerpt is from bin/xgync you extended the path to look for files in lib/ but you try to require 'xgync' which is a file, that is not present in lib/, so if you wanted to use this method (instead of require_relative you would have to use require 'xgync.rb'.

Related

Ruby: require works in gem, fails when running from source

Try creating a gem based on bundler's official guide on developing a Ruby gem.
Running bundle gem foodie will create a structure and generate files in the lib directory:
foodie
version.rb
foodie.rb
foodie.rb reads
require "foodie/version"
module Foodie
# Your code goes here...
end
Running ruby lib/foodie.rb (or also from different directories) will result in
C:/Ruby23-x64/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- foodie/versio
n (LoadError)
from C:/Ruby23-x64/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from foodie.rb:1:in `<main>'
On the other hand installing the gem via rake install and then requiring the gem works just fine.
It works from source if require "foodie/version" is changed to require_relative "foodie/version" in foodie.rb. As I understand
require works based on modules
require_relative works based on directory structure
To me the latter looks like a hack. It'd no longer make sense to structure your code via modules as it wouldn't be enforced (maybe it'd still make sense but you could make mistakes and never notice).
My questions are:
Is it possible to test a gem from source without installing it while following the bundler convention (using require instead of require_relative)?
Why does the gem work after installed?
Is there any best practice for the usage of require, require_relative, modules, files and general structure?
Thank you.
You need to add your lib dir to Ruby’s load path. The load path is a list of directories that Ruby searches for files in when you call require. Rubygems also manages the load path when you are using gems, which is why your code works when installed as a gem.
You say “as I understand ... require works based on modules”, this is not correct. require works with files, it’s just convention that a class or module is defined in a file with a matching name, e.g. MyModule might be in my_module.rb.
There are a few ways to add a dir to the load path. From the command line you can use the -I option:
$ ruby -I lib lib/foodie.rb
If you wanted to avoid typing -I lib you could use the RUBYLIB environment variable. Ruby adds the contents of this to the load path:
$ export RUBYLIB=lib
$ ruby lib/foodie.rb
(On Windows I think you will need to use set rather than export.)
You can also manipulate the load path from withing the program itself. It is stored in the global variable $LOAD_PATH, aliased as :$. This is how Rubygems and Bundler manage your gems.

Why doesn't Ruby 'require' allow relative paths?

This SO post sort of answers the question by claiming that require will only search relative to the path that the script was run in. But this really does not appear to be true. I will elaborate.
I created a quick C extension and compiled it to mytest.so. Then, in the same directory I fired up irb.
irb(main):009:0> require 'mytest.so'
LoadError: cannot load such file -- mytest.so
This is expected because the claim in the other answer is that require is searching relative to where irb was run from. In my case that would be /usr/bin/irb. So I tried the required_relative solution from the other question:
irb(main):006:0> require_relative './mytest.so'
LoadError: cannot infer basepath
No luck. And FYI - mytest.so is tab-completing here so irb is clearly aware it is in the current working directory. Furthermore, I can easily prove this:
irb(main):004:0> system("pwd")
/home/mike/Documents/ruby_test
# => true
irb(main):005:0> File.expand_path("./")
# => "/home/mike/Documents/ruby_test"
Okay final test, I will assume that irb is being executed in /usr/bin despite the evidence pointing against that.
irb(main):011:0> require '../../home/mike/Documents/ruby_test/mytest.so'
LoadError: cannot load such file -- ../../home/mike/Documents/ruby_test/mytest.so
I would greatly appreciate if anyone can shed some light on what is going on with require?
BTW, I am aware I can solve this issue by giving the exact file path. This question is about trying understand what is happening beneath the surface.
require '/home/mike/Documents/ruby_test/mytest.so' # this works
tl;dr: IRB is special and has some odd rules. Ruby in general works just fine with relative paths.
require will search the load path (which you can see by inspecting $: or $LOAD_PATH). This will not include the directory that you launched IRB from:
> $:
=> ["/usr/local/rvm/rubies/jruby-head/lib/ruby/2.2/site_ruby", "/usr/local/rvm/rubies/jruby-head/lib/ruby/stdlib"]
So there's no joy there, unless you explicitly add your directory to the load path. This is what Rubygems and Bundler spends most of their time doing - they manage the load paths for gems so you don't have to worry about it. However, this doesn't help you with single files.
Additionally, require_relative will search from the directory that __FILE__ is in, but in IRB, this is a non-directory (irb) value! This is why you get the "can't infer basepath" issue when trying require_relative from IRB; since the currently executing file, __FILE__, isn't a proper path, require_relative can't figure out where to start from.
When you are not running from IRB, this isn't really an issue; require_relative 'mytest.so' should work just fine when you execute it in a script, since the currently-executing script will populate __FILE__. That is, if you have loader.rb and mytest.so and execute loader via ruby loader.rb, require_relative should work just fine.
If you want to run this in IRB, consider something like:
require "#{__dir__}/mytest.so"
which will expand out to the current working directory, which should by default be the directory you've launched it from. I would recommend that you not do this in a script, though, since it depends on __dir__ not having been changed, and that may be difficult to guarantee.
From the documentation:
Loads the given name, returning true if successful and false if the
feature is already loaded.
If the filename does not resolve to an absolute path, it will be
searched for in the directories listed in $LOAD_PATH ($:).
If the filename has the extension “.rb”, it is loaded as a source
file; if the extension is “.so”, “.o”, or “.dll”, or the default
shared library extension on the current platform, Ruby loads the
shared library as a Ruby extension. Otherwise, Ruby tries adding
“.rb”, “.so”, and so on to the name until found. If the file named
cannot be found, a LoadError will be raised.
For Ruby extensions the filename given may use any shared library
extension. For example, on Linux the socket extension is “socket.so”
and require 'socket.dll' will load the socket extension.
The absolute path of the loaded file is added to $LOADED_FEATURES
($"). A file will not be loaded again if its path already appears in
$". For example, require 'a'; require './a' will not load a.rb again.
The answer to your question is that it simply isn't designed to.
You could use require_relative if you want to require files relative to your files' path.
You could add your projects library folder to the $LOAD_PATH to get the functionality you are asking for, that is, require 'my_library'
In IRB for loading local files, you may want to use load instead, as it gives you the ability to load file/library multiple times, where require will load the file/library only once. The __FILE__ variable works in IRB just like it should. It is the identification of the file (in this case the open process) in which the variable is invoked.

LoadError occurs when directly running Ruby source code in existing projects

I'm new to Ruby/JRuby and has been disturbed by the error "LoadError: no such file to load" for many weeks, when I try to directly run the Ruby source code of certain projects.
I downloaded the source code of many Ruby projects from GitHub. Yes only the source code, I didn't install them because my task is more on analyzing the code itself.
Let's take an example, say the project "rqrcode" has the following (simplified) structure:
rqrcode
lib (folder)
rqrcode (folder)
core_ext (folder, with some files inside)
core_ext.rb
qrcode (folder, with some files inside)
qrcode.rb
rqrcode.rb
test (folder)
data.rb
test_rqrcode.rb
So if I run "jruby test_rqrcode.rb" inside the test folder, it throws LoadError at this line inside the file:
require_relative "../lib/rqrcode"
And it also throws LoadError at here, the rqrcode.rb file in lib folder:
require "rqrcode/core_ext"
The error message is
LoadError: no such file to load -- rqrcode/core_ext
require at org/jruby/RubyKernel.java:1054
require at /Users/x5lai/.rvm/rubies/jruby-1.7.4/lib/ruby/shared/rubygems/custom_require.rb:36
(root) at /Users/x5lai/Downloads/rqrcode-master/lib/rqrcode.rb:12
require at org/jruby/RubyKernel.java:1054
(root) at /Users/x5lai/.rvm/rubies/jruby-1.7.4/lib/ruby/shared/rubygems/custom_require.rb:1
require at /Users/x5lai/.rvm/rubies/jruby-1.7.4/lib/ruby/shared/rubygems/custom_require.rb:36
(root) at test_rqrcode.rb:12
I really don't understand why it says it cannot find "rqrcode/core_ext" because that folder does exist there!
Such error doesn't always occur. Sometimes, when I download the source code of other Ruby projects which have similar structure as above, it runs successfully with all the "require", "require_relative" statements.
My friend says it is a Ruby default load path problem. I therefore went to look at what's inside my Ruby load path. It's full of many Ruby files. But, those Ruby projects that run successfully do not have their Ruby files in these load path as well (and they do not use ".unshift" to modify their load path inside their code). So I don't think this is the cause of those failing projects.
Hope there's someone who could clarify my doubts. Maybe it's because of my JRuby configuration? I'm using a Mac. My JRuby version is 1.7.4.
Firstly, ruby load path doesn't include current directory.
You can verify this by running jruby -e "$:" in cmd.
Secondly, when you do require_relative "../lib/rqrcode" in test_rqrcode.rb, you are saying "please find the file at a path relative to myself". Okay, it can find rqrcode.rb right away. However, rqrcode.rb doesn't know where to find its own required files, so it goes to global load path, which is the $:. Since $: doesn't include the lib folder, it cannot find any file residing inside its lib folder, thus return a exception.
Knowing this, you should add local lib directory to the load path in your main script, so every subsequent file will use the same load path environment.
$:.unshift "path_to_the_folder_need_to_include"
On the command line, you can add a folder to the $LOAD_PATH by using the -I switch. For example:
ruby -I lib test/test_qrcode.rb
It is common for ruby projects to add their lib folder to the $LOAD_PATH on their test setup, typically on a file called test_helper.rb or spec_helper.rb (depending on the framework).

Can't get RSpec to work -- 'require': cannot load such file

I just spent three days of my life banging my head against the wall trying to figure out why a simple 'rake' would not pass my spec file.
If this happens to you: Do not have a space in any folder path!. Seriously. In fact do not have a space in anything you name from here on out.
Here is my console output:
(in /Users/*****/Desktop/Learning Ruby/learn_ruby)
$ rake
/Users/*******/Desktop/Learning Ruby/learn_ruby/00_hello/hello_spec.rb:116:
in `require': cannot load such file -- hello (LoadError)
The failure is caused by the line: require "hello"
This line tells Ruby that it needs to search the load path for a file named hello.rb. However, when it looks at the load path, it can't find that file. You should either remove that line and define your code directly in the spec file, or create a hello.rb file.
Newer versions of RSpec (2.11+ I believe) automatically add subdirectory lib to the load path. Based on your Rakefile it seems you are also loading the current lab directory and the subdirectory solution.
I'm guessing you're expected to put your solution in solution/hello.rb.
What worked for me was changing the require statement to a require_relative
I am using windows and an IDE

Compile ruby script with dependencies on other classes

have a problem with compressing my script.
I have a main.rb and some classes in subfolders like Subfolder/Class.rb
In my main.rb, I have the Classes declared like that:
require './Subfolder/Class.rb'
When I just run my main script, it works. Also my exe works, when it is in the same place as the main.rb.
But when I put the exe somewhere else I get this error:
C:/Users/MLEING~1/AppData/Local/Temp/ocr53C2.tmp/lib/ruby/site_ruby/1.9.1/rubyge
ms/custom_require.rb:36:in `require': cannot load such file -- ./Parsing/Calibra
tionState (LoadError) from C:/Users/MLEING~1/AppData/Local/Temp/ocr53C2.tmp/lib/ruby/site_ruby
/1.9.1/rubygems/custom_require.rb:36:in `require'
from C:/Users/MLEING~1/AppData/Local/Temp/ocr53C2.tmp/src/main.rb:9:in `
<main>'
Can I somehow put the dependencies into my exe?
I also tried to include them like that:
ocra main.rb Subfolder/*.rb
But it doesn't help.
Have you tried making a ruby gem out of your project? http://guides.rubygems.org/make-your-own-gem/
Gems define their own dependencies.
Your require is using a relative path from the current directory (which you can see because it starts with "./"
Instead, try:
require 'Subfolder/Class.rb'
And make sure $LOAD_PATH includes the location where all of your ruby code is unpacked (which you can look at by examining $0 (or figure out the full path from $0 and require the .rb with a full path)

Resources