Skip to content

Instantly share code, notes, and snippets.

@leahneukirchen
Created April 9, 2010 18:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save leahneukirchen/361451 to your computer and use it in GitHub Desktop.
Save leahneukirchen/361451 to your computer and use it in GitHub Desktop.
THIS DOCUMENT MOVED TO http://chneukirchen.github.com/rps/
AND http://github.com/chneukirchen/rps
= Ruby Packaging Standard
The aim of this document is two-fold. First, to specify a common
structure of how a Ruby package distributed as source (that is, but
not limited to, development directories, version-controlled
repositories, .tar.gz, Gems, ...) should conform to.
Second, to document common and proven ways to structure Ruby packages,
and to point out certain anti-patterns that sneaked into common use.
It is by intent not to innovate.
(See RFC 2119 for use of MUST, SHOULD, SHALL.)
== Library files
Library code MUST reside in lib/.
Libraries SHOULD use a directory as namespace, e.g. lib/foo.rb and lib/foo/**.
Libraries SHOULD NOT require code of the project that are outside of lib/.
Libraries MUST not require 'rubygems' or modify the $LOAD_PATH.
Ruby library files MUST end with .rb.
Library files SHOULD be installed with mode 0644.
== Executables
Executables MUST reside in bin/.
Ruby executables SHOULD have a shebang line using env:
#!/usr/bin/env ruby
Executables SHOULD NOT require code of the project that are outside of lib/.
Executables SHOULD NOT require 'rubygems' or modify the $LOAD_PATH,
unless they are specifically made for doing that (e.g. package managers).
Executable files SHOULD NOT end with .rb.
Executable files SHOULD be installed with mode 0755.
== Extensions
Extensions are directories which contain a extconf.rb.
Extensions SHOULD reside in ext/.
Extensions SHOULD be buildable with "ruby extconf.rb; make".
XXX How to install, how to find out what was built.
== Data files
Data files and resources of the project belong to data/.
XXX Or data/<projectname>?
XXX Where to install to, how to find out that place from the program?
== Tests
Tests SHOULD reside in test/ or spec/.
== History
09apr2010: First initial draft.
10apr2010: Fix binary permissions.
10apr2010: Add data files.
@jbarnette
Copy link

@josh Absolutely, the only reason I don't have that turned on all the time is because I'm dumb and it's deeply confused me a couple of times when I've been in the root directory of a project that contributes, say, RubyGems plugins via the load path. :)

@sunaku
Copy link

sunaku commented Apr 18, 2010

@jbarnette Aliases seem like a good compromise, but they don't solve the problem completely for me: I like to use the development versions of my projects right from my source area (e.g. I run ~/src/my_project/bin/my_project directly from anywhere in the file system).

I had to write a little wrapper script (could also be a shell function if you prefer) to address this:

> cat ~/bin/rubin
#!/bin/sh -x
dir="$(dirname "$(dirname "$1")")"
ruby -rubygems -I "$dir/lib:$dir/test" "$@"

And then run it this way:

rubin ~/src/my_project/bin/my_project

I guess I can live with this. :-/

@sunaku
Copy link

sunaku commented Apr 19, 2010

@chneukirchen Your ruby-wrapper script is awesome! Totally solves my problem. Thank you.

@sunaku
Copy link

sunaku commented Apr 19, 2010

I've only ever used RubyGems for packaging my projects, so I'm kind of scared of setup.rb's style of separating my project's directories (i.e. lib/ is no longer next to bin/ and so on). In particular, I am confused about the following:

I want to run the man executable (pointing it to my project's man/ directory) from my project's executable in bin/. With RubyGems, I can rely on bin/ being next to man/. But with setup.rb I don't know how to find my project's man/ directory from my project's executable in bin/!

Any suggestions? Thanks.

@rtomayko
Copy link

Similar to josh and jbarnette, I use this rbdev shell function to activate bin, lib, and ext dirs when I'm working on a project:

# develop out of the current directory.
rbdev() {
    local useful dir
    test -d ./bin && {
        useful=yes
        PATH="$(pwd)/bin:$PATH"
        echo "./bin on \$PATH"
    }
    test -d ./ext && {
        useful=yes
        for dir in ./ext/*
        do
            test -d "$dir" || continue
            RUBYLIB="$(pwd)/$dir:$RUBYLIB"
            export RUBYLIB
            echo "$dir on \$RUBYLIB"
        done
    }
    test -d ./lib && {
        useful=yes
        RUBYLIB="$(pwd)/lib:$RUBYLIB"
        export RUBYLIB
        echo "./lib on \$RUBYLIB"
    }
    test -z "$useful" && {
        echo "no ./lib or ./bin detected. help me help you."
        return 1
    }
}

When I'm working on e.g., RDiscount, I do something like:

$ cd ~/git/rdiscount
$ rbdev
./bin on $PATH
./ext on $RUBYLIB
./lib on $RUBYLIB

Not setting up the load path from executables has been a problem, though. People assume everything is broken when they get a LoadError + backtrace after checking out a project for the first time and running an executable. I really wish these techniques for setting up development environments would become common practice. I'm thinking a template HACKING file that explained basic environment prep would probably go a long way.

@sunaku
Copy link

sunaku commented Apr 20, 2010

@chneukirchen Would you mind moving this discussion to ruby-talk? It's hard to quote and inline-reply to the various tangents here. And it's easy for questions to get lost in the noise. Also, I'm sure the vast number of Rubyists on ruby-talk would have valuable feedback on this spec. Thanks.

@leahneukirchen
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment