Search code examples
rubyhomebrewoptparsethorload-path

how to distribute a ruby script via homebrew


How can I deploy a simple ruby script via homebrew?

Here's what I tried

Wrote formula in a GitHub repo named homebrew-foo

# file https://github.com/foo/homebrew-foo/blob/master/foo.rb
class Foo < Formula
  desc "A command line tool"
  url "https://github.com/foo/foo/archive/master.zip"
  version "5.0.1"

  def install
    bin.install "foo"
    lib.install Dir["lib/*"]
  end
end

The other repository contains the ruby script. These are the files

./foo
./lib/libfile1.rb

here's what the script does

#!/usr/bin/env ruby
require './lib/libfile1.rb'
puts "came here"

The problem is that the require fails.

$ brew install foo/foo/foo
$ foo

results in this error

/Users/user1/.rbenv/versions/2.4.1/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in require': cannot load such file -- ./lib/libfile1.rb (LoadError) from /Users/user1/.rbenv/versions/2.4.1/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in require' from /usr/local/bin/foo

$ which foo
/usr/local/bin/foo

I suspect it's because the .rb file is not there at /usr/local/bin/foo/lib/libfile1.rb

Any ideas whats the proper way to do this?


Solution

  • There are two issues with your script:

    The first one is you try to require some file relatively to the current directory; i.e. the one from which the script is run, not the one it’s located in. That issue can be fixed by using Ruby’s require_relative:

    #!/usr/bin/env ruby
    require_relative './lib/libfile1.rb'
    puts "came here"
    

    The second issue is the script assumes the lib/ directory is located in its directory; which it’s not because your formula installs the script under <prefix>/bin/ and the library files under <prefix>/lib/. Homebrew has a helper for that use-case called Pathname#write_exec_script. It lets you install everything you need under one single directory, then create an executable under bin/ that calls your script.

    Your formula now looks like this:

    class Foo < Formula
      desc "A command line tool"
      url "https://github.com/foo/foo/archive/master.zip"
      version "5.0.1"
    
      def install
        libexec.install Dir["*"]
        bin.write_exec_script (libexec/"foo")
      end
    end
    

    It installs everything under libexec/ (lib/ is usually reserved for lib files), then add an executable under bin/ that calls your libexec/foo script.