How to I load a gem from source? - ruby

I have git cloned a repo from Github, now I want to experiment with it, as in I want to poke around the code and mess with it. I've created a file test.rb that should load this gem, but I want to load my locally checked out version, what's the right way to do this?
Right now I'm just using a bunch of "require_relative 'the_gem_name/lib/file'", which feels wrong.

When you require 'foo' Ruby checks all the directories in the load path for a file foo.rb and loads the first one it finds. If no file named foo.rb is found, and you’re not using Rubygems, a LoadError is raised.
If you are using Rubygems (which is likely given that it is included in Ruby 1.9+), then instead of immediately raising a LoadError all the installed Gems are searched to see if one contains a file foo.rb. If such a Gem is found, then it is added to the load path and the file is loaded.
You can manipulate the load path yourself if you want to ensure a particular version of a library is used. Normally this isn’t something that’s recommended, but this is the kind of situation that you’d want to do it.
There are two ways of adding directories to the load path. First you can do it in the actual code, using the $LOAD_PATH (or $:) global variable:
$LOAD_PATH.unshift '/path/to/the/gems/lib/'
require 'the_gem'
Note that you normally want to add the lib dir of the gem, not the top level dir of the gem (actually this can vary depending on the actual Gem, and it’s possible to need to add more than one dir, but lib is the norm).
The other way is to use the -I command line switch to the ruby executable:
$ ruby -I/path/to/the/gems/lib/ test.rb
This way might be a bit cleaner, as normally you don’t want to be messing with the load path from inside your code, but if you’re just testing the library it probably doesn’t matter much.

Following apneadiving's suggestion in the comments, I created a Gemfile and added this line
source "http://rubygems.org"
gem 'gem_name', path: '~/path/to/gem/source/folder'
Then bundle install, and bundle exec ruby test.rb and it worked.

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.

What is a good way to see output from my ruby gem?

I want to know a good way to run code in my ruby gem (and not just through tests).
That means I want to run ruby lib/{gemname}.rb on the terminal and be able to see some output
So I have this line in my base file:
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
and then I load a file called debugger.rb by requiring it at the bottom of the base file. This file then gives me the output I need.
This works but this kind of clutters my code and I don't want to accidentally commit it and watch it break in production.
So what's a good way of doing this?
My approach for developing and debugging gems has two parts:
1) Always use require_relative to include needed "internal" gem related files. This allows the gem to be loaded up normally when installed as a gem and also in my development environment (ignoring any versions of the gem that may already be installed.)
2) Then use the following snippet of code (usually) at the bottom of the main file, to activate debugging features when the base my_gem.rb file is run explicitly on the command line.
if __FILE__ == $0
#debugging code goes here!
end
With this strategy there's no need to worry about yanking debug code before releasing the gem.

How to require ruby gem from a specific location?

I am new to ruby, and is trying to write a git hook in ruby. I want to use the rugged gem in my script. The gem is already available in /opt/gitlab/embedded/service/gem/ruby/2.1.0/ as part of GitLab installation (Files List). How can I require that gem in my script?
I have tried $LOAD_PATH.unshift "/opt/gitlab/embedded/service/gem/ruby/2.1.0/" and then require "rugged", as mentioned in another stackoverflow answer, but it did not work.
Look carefully at how $LOAD_PATH is configured for each gem after you include it. Normally it's the full path to where the base gemname.rb is located, like in your case where rugged.rb is.
The way the $LOAD_PATH works is it scans through that list looking for rugged.rb and if it doesn't find it, moves on to the next possible location. You're specifying a directory which doesn't have that, so find the right path and fill that in, and you should be good.

Creating a gem with Bundler

I'm trying to create a gem with Bundler, following this guide: http://rakeroutes.com/blog/lets-write-a-gem-part-one/. In it, it says:
I incorrectly thought after taking my first look through the gemspec
that I would need to add more require statements as I developed my
gem. That isn’t the case: the files just need to be in git.
I am trying to clean up some of my old gems to use this convention, but when I install my gem, the classes from the other files are not available. I have a couple directories nested under my /lib dir, but I wouldnt think that would be an issue. Is there anything simple to overlook that would prevent my other files from being required? Any help would be appreciated.
In the link, when he says he doesn't need to add a lot of "require" statements, he must mean adding files to the s.files, s.executables, and s.test_files arrays--these determine what files get packaged up into the gem and what files get ignored. As you can see from the gem spec, whatever's tracked by git in certain directories is going to be included in the packaged gem.
Ruby's require is a different story. Standard require rules still apply.
Ruby's gem system works by adding a bunch of different places for Ruby to look for "foo.rb" when you run require "foo". If "lib" is your only require path for your gem, when you require "my_gem" Ruby is only going to run the code in lib/my_gem.rb. If lib/my_gem.rb doesn't require any other files in your gem, then Ruby hasn't seen them and so you'll get undefined constant errors when you try to use the classes from those files.
For examples, you might take a look at two simple gems I've written; both were started with bundle gem: HashToHiddenFields and SimpleStats. In both gems, main Ruby file in lib/ requires everything that needs to be loaded for the gem to work correctly. For example, hash_to_hidden_fields.rb requires action_view/helpers/hash_to_hidden_fields so that the ActionView::Helpers::HashToHiddenFields constant+module exists so we can include it into ActionView::Base.
Hope that answers the question. I know Ruby requiring was pretty fuzzy to me for a while.

Ruby - working with `require` command

I am editing a gem in which there are the usual require commands, pointing at the loaded gem (the gem I'm talking about is called nirvana, and the files in it contain require 'nirvana', require 'nirvana/shell' and so on).
When I use the bin-file of the application (/mypath/nirvana/bin/nirvana), I want the require 'nirvana' command written inside it to point to the files in the local fork of that gem (the ones I am editing), and I want not to load the original nirvana gem, that is installed with the classic gem install.
I don't want to substitute all the require 'nirvana' commands with
require File.dirname(File.expand_path(__FILE__)) + '/../lib/nirvana.rb'
... this would resolve my problem, but it's ugly! Is there a way to do not load nirvana gem, and to make require 'nirvana' load my libraries (maybe adding them in the $LOAD_PATH...) ?
You might be running into the require vs. require_relative conundrum in 1.9+.
require is good for loading a gem that is loaded via the normal gems paths, i.e., installed into Ruby's space.
require_relative is good for loading relative to a particular file, for instance, if you're loading a module you wrote and its in the same or a sub-directory or relative directory of yours.
`require_relative 'some/sub/dir/to/file'`
You should only be 'requiring' nirvana.rb once, if you're doing so from your gems binary executable. So this line only needs to appear once. It's quite common to see it appear in these files.
Do note your example can be better written as
require File.expand_path('../lib/nirvana.rb', __FILE__)
As File::expand_path takes an optional second argument (a directory String).
A lot of authors will also shift the lib directory into the $LOAD_PATH before executing the binary so the local files are loaded before attempting to load any installed gems.
If you're using rvm, have a look at gemsets. You can create a gemset that doesn't have the nirvana gem installed, then when you require 'nirvana' you'll only get your local libraries required, as there isn't a nirvana gem to include.
(I'm assuming you're using ruby 1.9, as if you're using 1.8 you could just omit require 'rubygems'.)

Resources