Inventory keeps track of the contents of your Ruby projects.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



  Inventory keeps track of the contents of your Ruby¹ projects.  Such an
  inventory can be used to load the project, create gem specifications and
  gems, run unit tests, compile extensions, and verify that the project’s
  content is what you think it is.

¹ See

§ Usage

    Let’s begin by discussing the project structure that Inventory expects you
    to use.  It’s pretty much exactly the same as the standard Ruby project

      ├── README
      ├── Rakefile
      ├── lib
      │   ├── foo-1.0
      │   │   ├── bar.rb
      │   │   └── version.rb
      │   └── foo-1.0.rb
      └── test
          └── unit
              ├── foo-1.0
              │   ├── bar.rb
              │   └── version.rb
              └── foo-1.0.rb

    Here you see a simplified version of a project called “Foo”’s project
    structure.  The only real difference from the standard is that the main
    entry point into the library is named “foo-1.0.rb” instead of “foo.rb” and
    that the root sub-directory of “lib” is similarly named “foo-1.0” instead
    of “foo”.  The difference is the inclusion of the API version.  This must
    be the major version of the project followed by a constant “.0”.  The
    reason for this is that it allows concurrent installations of different
    major versions of the project and means that the wrong version will never
    accidentally be loaded with require.

    There’s a bigger difference in the content of the files.
    ‹Lib/foo-1.0/version.rb› will contain our inventory instead of a String:

      require 'inventory-1.0'

      class Foo
        Version =, 4, 0){
            author 'A. U. Thor', ''

          homepage ''

            license 'LGPLv3+',
                    'GNU Lesser General Public License, version 3 or later',

          def dependencies
            super +{
              development 'baz', 1, 3, 0
              runtime 'goo', 2, 0, 0
              optional 'roo-loo', 3, 0, 0, :feature => 'roo-loo'

          def package_libs

    We’re introducing quite a few concepts at once, and we’ll look into each in
    greater detail, but we begin by setting the ‹Version› constant to a new
    instance of an Inventory with major, minor, and patch version atoms 1, 4,
    and 0.  Then we add a couple of dependencies and list the library files
    that are included in this project.

    The version numbers shouldn’t come as a surprise.  These track the version
    of the API that we’re shipping using {semantic versioning}².  They also
    allow the Inventory#to_s method to act as if you’d defined Version as

    Next follows information about the authors of the project, the project’s
    homepage, and the project’s licenses.  Each author has a name and an email
    address.  The homepage is simply a string URL.  Licenses have an
    abbreviation, a name, and a URL where the license text can be found.

    We then extend the definition of ‹dependencies› by adding another set of
    dependencies to ‹super›.  ‹Super› includes a dependency on the version of
    the inventory project that’s being used with this project, so you’ll never
    have to list that yourself.  The other three dependencies are all of
    different kinds: development, runtime, and optional.  A development
    dependency is one that’s required while developing the project, for
    example, a unit-testing framework, a documentation generator, and so on.
    Runtime dependencies are requirements of the project to be able to run,
    both during development and when installed.  Finally, optional dependencies
    are runtime dependencies that may or may not be required during execution.
    The difference between runtime and optional is that the inventory won’t try
    to automatically load an optional dependency, instead leaving that up to
    you to do when and if it becomes necessary.  By that logic, runtime
    dependencies will be automatically loaded, which is a good reason for
    having dependency information available at runtime.

    The version numbers of dependencies also use semantic versioning, but note
    that the patch atom is ignored unless the major atom is 0.  You should
    always only depend on the major and minor atoms.

    As mentioned, runtime dependencies will be automatically loaded and the
    feature they try to load is based on the name of the dependency with a
    “-X.0” tacked on the end, where ‘X’ is the major version of the dependency.
    Sometimes, this isn’t correct, in which case the :feature option may be
    given to specify the name of the feature.

    You may also override other parts of a dependency by passing in a block to
    the dependency, much like we’re doing for inventories.

    The rest of an inventory will list the various files included in the
    project.  This project only consists of one additional file to those that
    an inventory automatically include (Rakefile, README, the main entry point,
    and the version.rb file that defines the inventory itself), namely the
    library file ‹bar.rb›.  Library files will be loaded automatically when the
    main entry point file loads the inventory.  Library files that shouldn’t be
    loaded may be listed under a different heading, namely “additional_libs”.
    Both these sets of files will be used to generate a list of unit test files
    automatically, so each library file will have a corresponding unit test
    file in the inventory.  We’ll discuss the different headings of an
    inventory in more detail later on.

    Now that we’ve written our inventory, let’s set it up so that it’s content
    gets loaded when our main entry point gets loaded.  We add the following
    piece of code to ‹lib/foo-1.0.rb›:

      module Foo
        load File.expand_path('../foo-1.0/version.rb', __FILE__)

    That’s all there’s to it.

    The inventory can also be used to great effect from a Rakefile using a
    separate project called Inventory-Rake³.  Using it’ll give us tasks for
    cleaning up our project, compiling extensions, installing dependencies,
    installing and uninstalling the project itself, and creating and pushing
    distribution files to distribution points.

      require 'inventory-rake-1.0'

      load File.expand_path('../lib/foo-1.0/version.rb', __FILE__)

      Inventory::Rake::Tasks.define Foo::Version

      Inventory::Rake::Tasks.unless_installing_dependencies do
        require 'lookout-rake-3.0'

    It’s ‹Inventory::Rake::Tasks.define› that does the heavy lifting.  It takes
    our inventory and sets up the tasks mentioned above.

    As we want to be able to use our Rakefile to install our dependencies for
    us, the rest of the Rakefile is inside the conditional
    #unless_installing_dependencies, which, as the name certainly implies,
    executes its block unless the task being run is the one that installs our
    dependencies.  This becomes relevant when we set up Travis⁴ integration
    next.  The only conditional set-up we do in our Rakefile is creating our
    test task via Lookout-Rake⁵, which also uses our inventory to find the unit
    tests to run when executed.

    Travis integration is straightforward.  Simply put

        - gem install inventory-rake -v '~> VERSION' --no-rdoc --no-ri
        - rake gem:deps:install

    in the project’s ‹.travis.yml› file, replacing ‹VERSION› with the version
    of Inventory-Rake that you require.  This’ll make sure that Travis installs
    all development, runtime, and optional dependencies that you’ve listed in
    your inventory before running any tests.

    You might also need to put

        - RUBYOPT=rubygems

    in your ‹.travis.yml› file, depending on how things are set up.

¹ Ruby project structure:
² Semantic versioning:
³ Inventory-Rake:
⁴ Travis:
⁵ Lookout-Rake:


    If the guide above doesn’t provide you with all the answers you seek, you
    may refer to the API¹ for more answers.

¹ See

§ Financing

    Currently, most of my time is spent at my day job and in my rather busy
    private life.  Please motivate me to spend time on this piece of software
    by donating some of your money to this project.  Yeah, I realize that
    requesting money to develop software is a bit, well, capitalistic of me.
    But please realize that I live in a capitalistic society and I need money
    to have other people give me the things that I need to continue living
    under the rules of said society.  So, if you feel that this piece of
    software has helped you out enough to warrant a reward, please PayPal a
    donation to now@disu.se¹.  Thanks!  Your support won’t go unnoticed!

¹ Send a donation:

§ Reporting Bugs

    Please report any bugs that you encounter to the {issue tracker}¹.

  ¹ See

§ Authors

    Nikolai Weibull wrote the code, the tests, the documentation, and this

§ Licensing

    Inventory is free software: you may redistribute it and/or modify it under
    the terms of the {GNU Lesser General Public License, version 3}¹ or later²,
    as published by the {Free Software Foundation}³.

¹ See
² See
³ See