Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a (pre/post)_install_hook to ruby gems

Tags:

ruby

gem

hook

I want to execute some code at pre install time when installing a gem from rubygems.org with a command like gem install some-gem.

The documentation states that you can use a http://docs.ruby-lang.org/en/2.2.0/Gem.html pre_install hook that looks like this:

# File lib/rubygems.rb, line 724
def self.pre_install(&hook)
  @pre_install_hooks << hook
end

The doc further states:

RubyGems defaults are stored in rubygems/defaults.rb. If you're packaging RubyGems or implementing Ruby you can change RubyGems' defaults. For RubyGems packagers, provide lib/rubygems/defaults/operating_system.rb and override any defaults from lib/rubygems/defaults.rb. For Ruby implementers, provide lib/rubygems/defaults/#{RUBY_ENGINE}.rb and override any defaults from lib/rubygems/defaults.rb. If you need RubyGems to perform extra work on install or uninstall, your defaults override file can set pre and post install and uninstall hooks. See ::pre_install, ::pre_uninstall, ::post_install, ::post_uninstall.

This sounds exactly what I want. So I created the files

  • lib/rubygems/defaults/defaults.rb
  • lib/rubygems/defaults/operating_system.rb
  • rubygems/defaults.rb

and I put the code

Gem.pre_install { puts 'pre install hook called!' }

in all of the listed files. Then I added them to require_paths in the gemspec like this:

s.require_paths = ["lib", "test", "rubygems"]

But I see no output in the terminal when installing the gem.

What am I doing wrong?

like image 285
Nikolai Tschacher Avatar asked Nov 06 '15 11:11

Nikolai Tschacher


People also ask

How do I set gem version in Gemfile?

There are several ways to specify gem versions: Use a specific version: gem "name-of-gem", "1.0" . You can find specific versions on Rubygems.org (provided that's the source you”re using) by searching for your gem and looking at the “Versions” listed. Use a version operator: gem "name-of-gem", ">1.0" .

How do I know if a Ruby gem is installed?

Using gem search -r , you can search RubyGems' repository. For instance, gem search -r rails will return a list of Rails-related gems. With the --local ( -l ) option, you would perform a local search through your installed gems.

What is a Gemfile?

A Gemfile is a file that is created to describe the gem dependencies required to run a Ruby program. A Gemfile should always be placed in the root of the project directory.

What is Gemspec?

Gemspec is the Readme for gems. It tells you about the author, version, summary, description, internal dependencies, execution - pretty much everything about the gem. You can find more useful information about these topics here.


2 Answers

You can add a native extension to the gem.

gemspec: s.extensions << 'path/to/extconf.rb'

But then the gem install command want to execute a Makefile upon installation.

So the extconf.rb must create a dummy Makefile:

dummy_make_content = "make:\n" \
                     "\t:\n" \
                     "install:\n" \
                     "\t:\n" \
                     "clean:\n" \
                     "\t:\n"
File.write('Makefile', dummy_make_content)

Alternatively you can require the mkmf package and use a predefined function:

require 'mkmf'
create_makefile ''
like image 55
Alu Avatar answered Sep 30 '22 13:09

Alu


The answer is presently (2015-11-11) NO you cannot execute arbitrary code at install time for a specific gem. The hooks mentioned in your question are for use by the RubyGem installer itself and are not gem specific. See: How can I make a Ruby gem package copy files to arbitrary locations? for additional details.

These files:

lib/rubygems/defaults/defaults.rb
lib/rubygems/defaults/operating_system.rb
rubygems/defaults.rb

Are not called from your gem directory. They are found in the RubyGems system location.

If you wish to execute the same code for every gem before any are installed then you can use the pre_install hooks by placing the code in /usr/lib64/ruby/2.2.0/rubygems/defaults.rb or wherever your version of Ruby is installed on your system. The operating_system.rb file will get loaded from the same location as well.

like image 39
James B. Byrne Avatar answered Sep 30 '22 13:09

James B. Byrne