Require local gem ruby - ruby

I have a gem that I created in Ruby on my local machine and I need to require this gem in a plain Ruby script that starts a service.
I have to require like this:
require_relative '../../../my-gem/lib/my/gem'
Is it possible to do this require without putting in the relative path?

require checks for files in $LOAD_PATH. You can put your gem in one of those directories in order to require it directly. If you don't like your load path, you can add a new directory to it in your script, or set the RUBYLIB environment variable which is added to the load path.

If you have a gem, you can install it and set the version you want (in my example 1.0.0.beta) with gem 'my-gem', '= 1.0.0.beta'.
But I think yu look for another solution:
You can extend the location where require looks:
$:.unshift('../../../my-gem/lib')
require('my/gem')
or
$LOAD_PATH.unshift('../../../my-gem/lib')
require('my/gem')
You could also use $: << '../../../my-gem/lib', but I prefer unshift. If your gem contains a file with similar names as in a gem (avoid it!), then unshift guarantees your script is loaded.

Related

How to require a Ruby gem directly from its path?

In order to work with rubyzip i installed the gems:
gem install --local rubyzip-1.1.7.gem
gem install --local zip-zip-0.3.gem
In my code i call the gems using the require method:
require 'zip/zip'
require 'zip/filesystem'
I want to use require to load the gems directly from their location on my machine.
i want somthing like this:
require 'path_to_my_zip_gem'
Where path_to_my zip_gem contains the gem files
Basically, it's because require method loads files by name from paths listed in $: or $LOAD_PATH
"If the filename does not resolve to an absolute path, it will be
searched for in the directories listed in $LOAD_PATH ($:)."
http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-require
If you want to require a gem from the "local" path then the require_relative method could help since you can specify a path relative to the requiring file’s path. Look at the official documentation for further details:
http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-require_relative
The simpliest answer is
Gem::Specification.find_by_name("GEM_NAME_HERE").full_gem_path
Example
> require File.join(Gem::Specification.find_by_name("railties").full_gem_path, "lib/rails/code_statistics.rb")
=> true

How do command line utility gems work?

How do gems like "rails", "rspec", and "cucumber" allow user to use commands that start with their gem name??
rails new project
rspec spec
cucumber features
Not all gems have this ability. For example, when I type json even though I have it installed, I get
-bash: json: command not found
Gem's .gemspec file looks like this:
Gem::Specification.new do |s|
s.name = "haml"
s.version = "3.1.8"
....
s.executables = ["haml", "html2haml"]
end
This means that when installing this Gem (haml-3.1.8 in this case) also links to executables (also called "binstubs") will be created for the files haml and html2haml which are found inside the gem's bin/ directory.
In this case, for example the file bin/haml could look like:
#!/usr/bin/env ruby
require 'rubygems'
require 'haml'
puts Haml::VERSION
From rubygems.org documentation on building Gems:
In addition to providing libraries of Ruby code, gems can also expose
one or many executable files to your shell’s PATH. Probably the best
known example of this is rake. Another very useful one is
prettify_json.rb, included with the JSON gem, which formats JSON in a
readable manner (and is included with Ruby 1.9).
[...]
Adding an executable to a gem is a simple process. You just need to
place the file in your gem’s bin directory, and then add it to the
list of executables in the gemspec. Let’s add one for the Hola gem.
[...]
The executable file itself just needs a shebang in order to figure out
what program to run it with.
[...]
All it’s doing is loading up the gem, and passing the first command
line argument as the language to say hello with.
These gems have binaries that can be executed from the CLI. Most gems do not need this functionality and only provide code extensions.
Edit: They may not be 'binaries'. They can be just executable Ruby code as well. Thanks #holger

Two gems share same require?

When I call:
require 'retryable'
These two gems clash:
https://github.com/robertsosinski/retryable
https://github.com/carlo/retryable
as they both have a 'retryable' file they ask the user to require. I'm interested in using the first gem, however this doesn't always happen.
This code is executed as a part of my own gem, and it has to be reliable across all users.
Is there a way to require specifically from a gem (as the gem names are different of course)?
How do I resolve this naming conflict?
EDIT: To clarify, this is the official repo and the gem names are actually different ("retryable-rb" and "carlo-retryable"), however they both ask their users to require the lib/retryable.rb file with require 'retryable'
You can explicitly activate a specific gem with the gem method.
In this case you want the retryable-rb gem, and not any others that may have a retryable.rb file:
gem 'retryable-rb' # activates the gem in question
# and adds its lib dir to load path
require 'retryable' # loads retryable.rb from the retryable-rb gem, as it
# is now on the load path

User-level bundler Gemfile

I'd love to have a Gemfile in Bundler that just sets my own personal Gemfiles to always be bult into bundles...
aka ruby-debug, interactive-editor, and so forth.
Any idea how to do this?
We use this technique.
Puth this in your Gemfile:
eval File.read(File.expand_path("Gemfile.personal")) if File.exists?(File.expand_path("Gemfile.personal"))
And then add your personal gems to Gemfile.personal. Of course exclude Gemfile.personal from your version control.
One way to do this is to create different evnironments
group :scott do
end
Then
bundle --with-env=scott
I'm not 100% sure what it is you are trying to achieve, but;
If you just want to specify a number of development-only gems, you can specify a development group that can be excluded from deployments:
group :development do
gem "ruby-debug"
gem "interactive-editor"
end
Then on production or test you would do:
bundle install --without development
The cleanest solution I found so far is to use a separate Gemfile.personal and use a custom Gemfile path. I like this solution because you can use it in any project without modifying project code at all.
1. Add Gemfile.personal in to project root dir
# /path/to/your_ruby_project/Gemfile.personal
eval File.read('Gemfile') # use all gems from Gemfile
gem 'personal-gem1'
gem 'personal-gem2'
2. Install gems using Gemfile.personal file
BUNDLE_GEMFILE="Gemfile.personal" bundle install
# or
bundle install --gemfile=Gemfile.personal
Just remember to specify BUNDLE_GEMFILE every time you execute commands with bundler.
I personally put BUNDLE_GEMFILE=Gemfile.personal env variable in .env file using dotenv which ensures that Gemfile.personal is always used when I execute any command with bundler so I do not need to put it manually every time.
3. Put Gemfile.personal and Gemfile.personal.lock to .gitignore
For linux users:
touch ~/.gitignore
echo "Gemfile.personal\nGemfile.personal.lock" >> ~/.gitignore
This will affect all projects, so you do not need to update each project .gitignore separately.
My proposition does not depend on Bundler. As such does not clutter Gemfile* with your private gems for the price being a bit less convenient than answer by #ScottSchulthess.
How Bundler works
There is an array stored in $LOAD_PATH global variable which is a "load path for scripts and binary modules by load or require" (see Ruby docs) and Bundler modifies this array.
If you're developing a gem, $LOAD_PATH it will contain paths to all gems in the system. You can simply write e.g. require "pry" somewhere and pry gem will be loaded properly even if it's not mentioned in gemspec nor Gemfile. You don't have to add it to dependencies. (Of course it has to be already installed with gem install pry.)
A very different strategy Bundler takes when you're developing an application. In such case most of $LOAD_PATH will be removed on require bundler/setup (Rails calls it in config/boot.rb). Only essential paths and those pointing to gems specified in Gemfile.lock will remain there. So if you want to use pry without adding it to Gemfile, you got to append it to $LOAD_PATH before requiring it.
Solution for applications
gems_root = $LOAD_PATH.detect{ |p| %r{/bundler-} =~ p}.sub(%r{/bundler-.*}, "")
additional_gems = {
"pry" => "pry-0.10.1/lib",
"pry-rails" => "pry-rails-0.3.2/lib",
}
load_paths = additional_gems.values.map{ |p| File.join gems_root, p }
$LOAD_PATH.unshift *load_paths
additional_gems.keys.each{ |r| require r }
If you're using Rails, then save it in /config/initializers/00_custom_gems.rb and that's all. Outside Rails you additionally need to require it, preferably right after require "bundler/setup":
require "path/to/it" if File.exists? "path/to/it"
Remember to mention this file in .gitignore.
Sometimes proper gem path does not end with /lib but with architecture name. The easiest way to learn it is to add it for a moment to Gemfile and do puts $LOAD_PATH in aforementioned initializer. You can also learn those dirs from gemspec.
Solution for gems
When developing gem, you don't need to enhance $LOAD_PATH, only to require gems you want. If you need custom gems in tests and you're using RSpec, it can be done somewhere in /spec/support.
Another (less sane) idea is to add a file lib/development.rb:
require_relative "my_gem_name"
require "path/to/private/requires" if File.exists? "path/to/private/requires"
and refer to this file instead of to "my_gem_name" in your tests, demo application etc..

Ruby Package Include Problems

I'm trying to use the Optiflag package in my Ruby code and whenever I try to do the necessary require optiflag.rb, my program fails with the standard no such file to load -- optiflag message. I added the directory with that library to my $PATH variable, but it's still not working. Any ideas?
is it a gem? Are you doing
require 'rubygems'
require 'optiflag'
or equivalent?
It looks like it's a gem, so you need to enable ruby gems before requiring it.
This site explains many ways of how to do it. But to have the cheat sheet here these are:
1) Require the rubygems package before using a gem.
require "rubygems"
require "optiflag" # etc
2) Add the -rubygems flag to wherever you execute ruby. I.e:
ruby -rubygems Something.rb
3) Add an environment variable called RUBYOPT, giving it an option of rubygems. I.e:
RUBYOPT=rubygems
I also keep having this problem with RubyXL, tried to use single and double quotes. Is there something else that needs to be done? Maybe putting a file somewhere? I already succesfully installed the gem with sudo gem install rubyXL (RubyXL actually din't work).

Resources