Install a Ruby gem to an arbitrary prefix - ruby

I'd like to install a Ruby gem to an arbitrary prefix. For the sake of exposition, I'm trying to install github-markup; though, I suspect I'm encountering a general issue rather than anything particular to this package.
In the package's source distribution directory, I've done this:
$ gem install --install-dir $HOME/github-markup/lib/ruby/gems --bindir $HOME/github-markup/bin github-markup
And, of course, I've added $HOME/github-markup/bin to the PATH; and I've added $HOME/github-markup/lib/ruby/gems to RUBYLIB.
But, when I try to run the executable, this happens:
$ github-markup my.md
-bash: /usr/local/bin/github-markup: No such file or directory
Clearly I'm missing a piece of the puzzle.

Related

How to find out what executables came from a particular gem?

I am using gem through the terminal CLI.
I know $ gem list lists the installed gems.
But how do I find the names of the actual executables associated with a particular gem?
For example, CocoaPods.
The gem is called cocoapods. (I installed it using $ sudo gem install cocoapods).
But the actual executable is called pod.
At the moment the best thing I found was $ gem contents <gemName> and then looking through the list, specifically any files inside .../bin/ that don't have an extension. But this method does not seem ideal...
Is there a better way?
Ok, I found what I needed:
To list all the executables for a particular gem:
$ gem specification <gemName> executables
(this basically reads the gemspec file)
If you want to list all the executables for all the installed gems, here is the above command in a loop:
gem list --no-versions | while read -r gemName ; do
echo "Executables for $gemName:"
gem specification $gemName executables
done
(Note 1: I copy-pasted this directly in my terminal and hit enter)
(Note 2: This ran for a while, in my case ~30 seconds for ~100 gems)

How to install gem via Makefile if it doesn't exist

I'm creating a Makefile for my project:
build:
sudo gem install sass
Any time I build it's asking me for my superuser password. If I remove sudo it will not install at all, but throw an error instead, as I don't have permissions to install a gem.
So I came up with an idea, that I want to check whether the gem already exists, and run installing command only when it doesn't.
So the question is how to perform this check inside Makefile.
From the command line you can see if a gem is installed with gem list <gemname>. This prints out a list of installed gems that match <gemname>:
$ gem list sass
*** LOCAL GEMS ***
sass (3.4.13, 3.4.1, 3.2.19)
sass-rails (5.0.1, 4.0.3)
The argument is actually a regex, so you can be more specific, checking e.g. only the Sass gem itself:
$ gem list \^sass\$
*** LOCAL GEMS ***
sass (3.4.13, 3.4.1, 3.2.19)
The -i flag to list makes it produce output more usable in scripts, printing true or false, and having a suitable exit status:
$ gem list \^sass\$ -i
true
$ echo $?
0
$ gem list \^notsass\$ -i
false
$ echo $?
1
You can combine this with Make’s conditionals, and the shell function (assuming GNU make) to check if a gem is installed from your makefile:
ifeq ($(shell gem list \^sass\$$ -i), false)
gem install sass
endif
(The extra $ is needed to prevent make trying to expand it as a variable.)
It's now traditional in the Ruby community to use Bundler to manage / install dependencies. This will install Gems without you having sudo privs, and also will keep different Ruby project's gems separate.
If you must install the gem raw, look into RVM or rbenv which both install Ruby and any future gems in your home directory. There' some logic you'd have to add to your Makefile to get it to use the new Ruby in your home folder (rbenv may make this easier than rvm, although Idon't know for sure)... but it's not hard.
One quick way to accomplish the task is writing an .rb script and execute it from a Makefile. The simplest script I came up with goes as follows:
#!/usr/bin/env ruby
if !Gem::Specification::find_all_by_name('sass').any?
exec("sudo gem install sass")
end
find_all_by_name is always returning an array and doesn't raise an error when it can't find anything (as find_by_name does).
Makefile:
default:
./install.rb
Make sure install.rb is executable:
chmod +x install.rb
Run it using make.

How to contribute to a Ruby Gem

I am trying to contribute to a Ruby gem and I don't understand how to test a local gem without using a globally installed gem.
The gem I want to contribute to is a command line interface gem. I clone the gem into a directory then cd into that directory. However, when I run commands in the terminal when I'm in the cloned project directory it still uses the global gem. I've even run
gem uninstall gemname
then while inside the newly cloned gem directory I redo
gem install gemname.
No matter what changes I make to the gem, I can't see the results or what my contributions are doing because it's always running the global gem.
When I do try to type a command line command that is supposed to interact with the gem while in the cloned gem directory I get:
-bash: ~/.gem/ruby/2.1.0/bin/githubrepo: No such file or directory
I've done a ton of research but I'm just not getting it. Help?
gem install gemname will look for a .gem file in the current directory. If not found it will look for it on the web.
gem install --local /path/to/your/gemname.gem will allow you to target a particular directory. You may need to gem build gemname.gemspec first, so it has your changes.
Instead of doing this, I would write tests in the gem directory itself. It's likely that when running code in there, you can simply require 'gemname' in Ruby to get the gem functionality.
If it's a well-written gem, it should have tests already. They will most likely be in a directory called test or spec. Have a look at these tests and try to carry on in that style to test your changes. This will make your code changes far far more likely to be accepted as a pull request.

Ruby gem names with appended ruby version

Ruby gem names are really throwing me off. For example if install a gem called jade, a wrapper script is placed at /usr/bin/jade1.9 on some systems and at /usr/bin/jade on others. I'm curious if anyone has a recommendation on how I can use jade in scripts without writing some hackish code that guesses the correct gem name. The naming also makes it difficult to write documentation for less savvy users. Is there a simple way of making gems install with same name on all systems?
To elaborate a bit:
gem install jade #jade is something I made up
ls /usr/bin/|grep "jade"
> jade1.9
When I want to execute:
jade --dosomething
I actually have to run
jade1.9 --dosomething
I've noticed certain gems such as rake are installed at both /usr/bin/rake and /usr/bin/rake1.9 with neither being a symlink and both files having the same md5sum.
I am trying to understand why gems get the ruby version appended on some systems and how I can make install without the trailing version number.
A list of some example of gems that install an executable:
ls /usr/bin/|grep "1.9"
amalgalite-pack1.9
bundle1.9
crate1.9
erb1.9
gem1.9
irb1.9
minitar1.9
rake1.9
rdoc1.9
ri1.9
rlock1.9
ruby1.9
rubyscript2exe1.9
testrb1.9

Using a gem without installing it

I need to run a bunch of ruby scripts that I have written on a server that I don't have sudo access to.
On my own machine, I have installed a bunch of gems using 'sudo gem install ..' and used them in my code..
Is there any mechanism which would let me use these gems without formally installing them on a remote machine?
You can, but it's tricky.
First, install them using the --install-dir option, i.e.:
gem install gem_name --install-dir /some/directory/you/can/write/to
Second, make sure you have a .gemrc file in your home directory that looks something like this:
gemhome: /some/directory/you/can/write/to
gempath:
- /some/directory/you/can/write/to
- /usr/local/lib/ruby/gems/1.8
gemhome is where gems should look first when seeking a gem. gempath is all the paths it should check in when seeking a gem. So in the .gemrc above, I'm telling my code to look first in the local directory, and if not found, check the system gem directory.
Third, be aware that some code - even code within gems - can make assumptions about where gems are located. Some code may programmatically alter gempath or gemhome. You may need to "alter it back" in your own code.
There's not a lot (read: no) documentation on how to do that - the best way to figure it out is to read the tests that are included with the RubyGems source. Here's how I hack the gem paths in a rake task to point to my frozen version of capistrano:
Gem.use_paths(Gem.dir, ["#{RAILS_ROOT}/vendor/gems"])
Gem.refresh # picks up path changes

Resources