Requiring files in executables in a gem - ruby

I am building a gem using ruby 1.9.3 and bundler 1.1.3. In my gemspec, I use the executables method to specify that `bin/curd" is executable:
Gem::Specification.new do |gem|
...
gem.executables = ["curd"]
...
end
The gem source directory has a bin and a lib directory:
bin/
curd
lib/
curd.rb
The bin/curd file uses code defined in lib/curd, but I haven't been able to properly require it.
How can I require the lib/curd file so that when the gem is installed, bin/curd can see it?

Add to bin/curd:
require 'curd'
This will require curd gem after installation.

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

Building gem, executable not found

I'm in the process of writing my first ruby gem and I'm a little new at the whole structure of setting up gems. My understanding from reading this guide is that in order to create an executable for my gem I need to do the following:
Add a line to my gemspec specifiying the name of the executable like this:
s.executables << 'gemname'
Build the gem with
gem build gemname.gemspec
Install the gem locally (if you try to install by pushing to rubygems each time you'll end up having to change versions constantly) with
gem install gemname-0.0.1.pre.gem
Then test it out with
gemname foo-arguments, --bar-options
If I go through all these steps then on #4 I get the following error:
$ gemname
zsh: command not found: gemname
Assuming that the executable a file starting with a shebang and located at gemname/bin/gemname
Everything works just fine if I navigate to the root of the gem folder and run bin/gemname to test out the executable.
Here is a gist of my current gemspec and the gem source is available on github here.
You need to add all the files that need be included with the gem in spec.files. You missed to add the files that you have in the bin directory.
For example, I have the following configuration from one of my gems:
Gem::Specification.new do |spec|
spec.files = Dir["{bin,lib}/**/*", "LICENSE", "README.md"]
spec.test_files = Dir["spec/**/*"]
spec.require_paths = ["lib"]
spec.executables = ["yarr"]
end
Your gemspec is trying to change the load path. I would suggest fixing that first, because what you're reporting seems to be consistent with a gem not being able to find its files.
Look at your gemspec for this code:
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
Then see http://guides.rubygems.org/patterns/
"Gems should not change the $LOAD_PATH variable. RubyGems manages this for you. Code like this should not be necessary ..."
See http://guides.rubygems.org/patterns/ for various solutions to load using the existing load path, and helpers such as require_relative.
In addition you need to ensure your executable is, well, executable.
$ chmod a+x bin/gemname
Otherwise the command won't be available after building the gem.

ruby adds no path to gems

I use:
rvm 1.25.19 (stable)
ruby 1.9.3p545
I install gem rake command
gem install rake
I understand that $LOAD_PATH should contain the paths:
~/.rvm/rubies/ruby1.9/gems/rake/lib
~/.rvm/rubies/ruby1.9/gems/rake/bin
I execute command:
ruby -e 'puts $LOAD_PATH'
output:
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/site_ruby/1.9.1
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/site_ruby/1.9.1/x86_64-linux
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/site_ruby
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/vendor_ruby/1.9.1
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/vendor_ruby/1.9.1/x86_64-linux
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/vendor_ruby
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/1.9.1
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/1.9.1/x86_64-linux
why path to gem 'rake' don't add?
Installing a gem in Ruby doesn’t automatically add that gem’s files to the load path. When you require a file, first the existing load path is searched and if no matching file is found then Rubygems searches the installed gems for the file. If such a gem is found, then it is activated, which is when the gem’s lib directory is added to the load path.
Here’s an example using the Haml gem:
puts "Before:"
puts $LOAD_PATH
puts
require 'haml'
puts "After:"
puts $LOAD_PATH
This produces:
Before:
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/x86_64-darwin10.8.0
After:
/Users/matt/.rvm/gems/ruby-1.9.3-p448/gems/tilt-1.4.1/lib
/Users/matt/.rvm/gems/ruby-1.9.3-p448/gems/haml-4.0.5/lib
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/x86_64-darwin10.8.0
See how the lib directories for Tilt (which is a dependency of Haml) and Haml have been added to the start of the load path.
In the case of some gems, such as Rake, this is complicated by the fact they are part of the standard library and so are already on the load path. If you changed the example above to use require 'rake' then you wouldn’t see any change in the load path. In this situation you can specify you want to use the gem version with the gem method. This activates the gem in question, placing its lib directory at the start of the load path so when you later call require you will load the correct version.
For example, this script
require 'rake'
puts Rake::VERSION
produces 0.9.2.2 with Ruby 1.9.3, as that is the version of Rake included in the standard library. However this script:
gem 'rake'
require 'rake'
puts Rake::VERSION
produces 10.1.1, since that is the current highest version of the Rake gem installed on my system. You can also specify a particular gem version by providing a second argument to gem (this is the same syntax as used in Gemfiles). Note that the gem method doesn’t require any files, you have to do that as a separate step.

Execute without `bundle exec` via rubygems-bundler

I have a standard gem scaffold, and in inside the bin directory I have a simple executable (bin/do_things.rb):
#!/usr/bin/env ruby
require 'my_gem'
MyGem::doThings()
The gem hasn't been installed via gem install, so running bin/do_things.rb without bundle exec fails (my Gemfile has the gemspec line in it).
Is there a simple way to have rubygems-bundler execute my script in the bundler context? Should I just modify the $LOAD_PATH in my executable instead?
I could create a wrapper script to execute under Bundler as well, but I'd rather leverage rubygems-bundler somehow.
Or should I just type bundle exec?
try:
bundle exec bash -l
it will set you into bundler context - it's an extra shell so running exit will get you back to bundler less context.
Change the file permission
chmod a+x bin/do_things.rb
and resolve bin path, ignoring symlinks
require "pathname"
bin_file = Pathname.new(__FILE__).realpath
post, add self to libpath
$:.unshift File.expand_path("../../lib", bin_file)
Generating binstubs via bundle install --binstubs creates a wrapper script for all executables listed in my gemspec.
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'do_things.rb' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('my_gem', 'do_things.rb')
However, by default, the binstubs path is bin, which conflicts with gem's executable path, and will overwrite files in bin.
Running bundle install --binstubs=SOME_DIR and then adding SOME_DIR to .gitignore seem to be the most maintainable way.
Then, I can simple execute SOME_DIR/do_things or any other project-specific executable I add down the line.

Created a simple gem, but irb can't see it

I created a simple gem by doing:
testgem.gemspec
Gem::Specification.new do |s|
s.name = 'testgem'
s.version = '0.0.1'
s.summary = "code generation"
s.authors = ['asdf']
end
created the following file layout:
testgem.gemspec
Gemfile
lib/
lib/testgem.rb
lib/testgem/other.rb
ran the following:
gem build testgem.gemspec
WARNING: no description specified
WARNING: no email specified
WARNING: no homepage specified
Successfully built RubyGem
Name: testgem
Version: 0.0.1
File: testgem-0.0.1.gem
installed it:
gem install ./testgem-0.0.1.gem
Successfully installed testgem-0.0.1
1 gem installed
tested to see if irb can see it:
irb
require 'testgem'
oadError: cannot load such file -- testgem
I'm using Ruby 1.9.3-p194
It seems to be installed if I do:
gem list
..
testgem (0.0.1)
..
What could be the issue?
You need to add your lib to the search path. Just add
$:.push File.expand_path("../lib", __FILE__)
on top of your .gemspec
When you use require in Ruby, you are trying to load a file, not a gem. The file could of course be contained in a gem, and by convention a gem will have a file with the same name as the gem itself so that if you wanted to use the gem foo you would use require 'foo'. This isn’t always the case though, for example to use the bcrypt-ruby gem you need to require 'bcrypt'.
Additionally a gem doesn’t necessarily have to contain any filles at all. An example of this is the rails gem, which doesn’t contain any files itself (at least in version 3.2), but has dependencies to the various Rails components, so that you can install them all in one step.
In your case, although you have a lib/testgem.rb file in your gems project directory, you are not including it in your gem. You need to specify which files should be included, the default is to not include anything.
To simply include all the files in your project directory, you can add something like:
s.files = Dir.glob '**/*'
to your gemspec.
You need to require 'rubygems' first.

Resources