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.
Related
I want to setup gem from rubygems.org to some subfolder of my project like "/gems" and then use it from script via require. Please help me resolve it.
The preferred way is to go with a standard scenario: you build a gem, with binaries, pack it and when used it will download all the dependencies itself, according to gemspec. If the above is for some reason non-acceptable for you, one of the options would be:
• You create a gem for your script;
• You specify a path where to install dependencies:
bundle install --path=vendor/gems
• Instead of require you use require_relative in your script because on destination machines there won’t be local bundle’s config file, pointing to the right folder;
• As your script is finished, you pack everything including gems.
The normal way to go in a ruby project is to setup a Gemfile and use bundler (see link for more info) to handle the gems your project requires, without having to think of where they are stored
However, if there really is no way around shipping an own gem-directory, e.g. because your productive system has absolutely no way to access the internet, you could make it this way:
Create a directory in the root of your project (e.g. 'gems').
Download and unpack the gems to that directory (or use the appropriate options of gem install to redirect the installation into that directory)
Create a ruby file in the root directory of your project with following constants:
PROJECT_DIR = __dir__
GEMS_DIR = File.join(PROJECT_DIR, 'gems')
Now you can require your gems link require File.join(GEMS_DIR, <gem_name>)
Nonetheless, you should really think about using bundler, if possible in any way.
EDIT: to install gem via gem install
Delete the PG data from your project's gems directory
uninstall global gem gem uninstall pg
Install pg again, but into your project's directory: gem install -i <path_to_projects_gems_dir> pg
Run you script again with the require pointing to the gem stated above
I solved it like this:
gem install -i ./ pg
ROOT = File.expand_path('..', __FILE__)
ENV['GEM_PATH'] = File.join(ROOT, './')
require 'pg'
puts 'Version of libpg: ' + PG.library_version.to_s
I forked a gem I use a lot in order to code some enhancements on it. I want it to be installed in a subfolder called ~/codebase/ruby, where I keep all my Ruby projects, arranged in subdirectories.
To do that, I built and installed the gem with the following commands:
gem build my_gem.gemspec
gem install mygem-x.x.gem -i./mygem
mygem is installed in ~/codebase/ruby/mygem. I can't get my client code (which is in another directory) to grab mygem from there.
I've tried all of the following without success:
Running ruby with argument -I<path_to_mygem>.
Adding <path_to_mygem> to PATH.
Putting :gempath: <path_to_mygem> into ~/.gemrc.
I know I could put the gem in ~/.gem/ruby/<version> (since it appears in gem env) and that would probably work, but that would break my existing directory structure of Ruby code, forcing me to code in a different directory only for mygem, which is something I want to avoid unless it's the only option.
Thoughts?
Hopefully you are using Bundler to load the required gems. Then you just specify the path to the gem file in your Gemfile:
gem 'my_gem', :path => '~/codebase/ruby/mygem'
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
I can use gems like RSpec or Rails or Pry by calling their respective gem names, e.g. rspec, rails, pry on the commandline. How can I achieve this with gems I create? I'm using bundler for the basic gem creation.
I actually had my executable in the /bin folder.
Turns out my issue was that bundler's gem template is too smart for it's own good, and only includes files that have been committed to git. I hadn't actually committed the executable yet, so it wasn't picking it up:
# gemname.gemspec
gem.files = `git ls-files`.split($\)
According to documentation of Gemspec file you must put your executable in bin/ folder.
To make your gem executable in CLI, you should set the followings up.
Place your executable file the bin folder, like bin/hello
Make that executable by set permissions (chmod u+x bin/hello)
Set up gemspec configuration accordingly (hello.gemspec)
spec.files = `git ls-files -Z`.split("\x0")
spec.bindir = 'bin'
spec.executables << 'hello'
spec.executables considers bin as default folder for binaries and executables, though you can change it.
You can find documentation about this here: Gemspec#executables.
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.