Exercise 46: A Project Skeleton

This will be where you start learning how to set up a good project "skeleton" directory. This skeleton directory will have all the basics you need to get a new project up and running. It will have your project layout, automated tests, modules, and install scripts. When you go to make a new project, just copy this directory to a new name and edit the files to get started.

Creating the Skeleton Project Directory

First, create the structure of your skeleton directory with these commands:

$ mkdir projects
$ cd projects
$ mkdir skeleton
$ cd skeleton
$ mkdir bin data doc ext lib tests lib/NAME

I use a directory named projects to store all the various things I'm working on. Inside that directory I have my skeleton directory that I put the basis of my projects into.

Next we need to set up some initial files. Here's how you do that on Linux/OSX:

$ touch bin/NAME
$ touch lib/NAME.rb

Here's the same thing on Windows PowerShell:

$ new-item -type file  bin/NAME
$ new-item -type file  lib/NAME.rb

That creates an empty Ruby module directories we can put our code in. Then we need to create a sample gemspec file name NAME.gemspec that will describe our project:

# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)

Gem::Specification.new do |spec|
  spec.name          = "NAME"
  spec.version       = '1.0'
  spec.authors       = ["Your Name Here"]
  spec.email         = ["youremail@yourdomain.com"]
  spec.summary       = %q{Short summary of your project}
  spec.description   = %q{Longer description of your project.}
  spec.homepage      = "http://domainforproject.com/"
  spec.license       = "MIT"

  spec.files         = ['lib/NAME.rb']
  spec.executables   = ['bin/NAME']
  spec.test_files    = ['tests/test_NAME.rb']
  spec.require_paths = ["lib"]
end

Edit this file so that it has your contat information and is ready to go for when you copy it.

Next you want to create a Rakefile file that will help you automate common tasks when working with Ruby. Write this code for you Rakefile to make it run your tests for you:

1
2
3
4
5
6
7
require 'rake/testtask'

Rake::TestTask.new do |t|
  t.libs << "tests"
  t.test_files = FileList['tests/test*.rb']
  t.verbose = true
end

Finally you will want a simple skeleton file for tests named tests/test_NAME.rb:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
require "./lib/NAME.rb"
require "test/unit"

class TestNAME < Test::Unit::TestCase

  def test_sample
    assert_equal(4, 2+2)
  end

end

Final Directory Structure

When you are done setting all this up, your directory should look like mine here:

skeleton/
    NAME.gemspec
    Rakefile
    data
    ext/
    tests/
    bin/
        NAME
    doc/
    lib/
        NAME
        NAME.rb
    lib/NAME
    tests/
        test_NAME.rb

From now on, you should run your commands from that work with this directory from this point. If you can't do ls -R and see this same structure, then you are in the wrong place. For example, people commonly go into the tests/ directory to try to run files there, which won't work. To run your application's tests, you would need to be above tests/ and this location I have above. So, if you try this:

$ cd tests/   # WRONG! WRONG! WRONG!
$ rake test

Then that is wrong! You have to be above tests, in the skeleton/ directory itself, not in directories below skeleton/. If you made this mistake just do this:

$ cd ..  # get out of tests/
$ ls     # CORRECT!~ you are now in the right spot
NAME.gemspec        data            ext             tests
bin         doc             lib
$ rake test
Loaded suite tests/test_NAME
Started
.
Finished in 0.000226 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

Testing Your Setup

After you get all this installed you should be able to do this:

$ rake test
# A bunch of load junk here, ignore it.
Loaded suite tests/test_NAME
Started
.
Finished in 0.000226 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

Warning

If you get an error about Test::Unit you'll need to run gem install 'test-unit' to install the testing gems you need.

I'll explain Ruby's Test::Unit in the next exercise, but for now if you don't see that or get syntax errors then you made a mistake in one of the files or you are in the wrong place:

Using the Skeleton

You are now done with most of your yak shaving. Whenever you want to start a new project, just do this:

  1. Make a copy of your skeleton directory. Name it after your new project.
  2. Rename (move) the lib/NAME.rb file and lib/NAME/ directory to be the name of your project or whatever you want to call your root module.
  3. Edit your Gemspec to have all the information for your project.
  4. Rename tests/test_NAME.rb to also have your module name.
  5. Double check it's all working by using ruby tests/test_yourproject.rb again.
  6. Start coding.

Required Quiz

This exercise doesn't have Study Drills but a quiz you should complete:

  1. Read about how to use all of the things you installed.
  2. Read about the NAME.gemspec file, commonly called a "Gemspec", and all it has to offer.
  3. Make a project put code into the module, then get the module working. This means you have to change all the files, directories, and modules with NAME in them to the name of your project. If you get stuck, watch the video for this exercise to see how I did it.
  4. Put a script in the bin directory that you can run. Read about how you can make a Ruby script that's runnable for your system.
  5. Mention the bin script you created in your Gemspec so that it gets installed.
  6. Use your Gemspec to install your own module and make sure it works, then use gem to uninstall it.

Common Student Questions

Do these instructions work on Windows?
They should, but depending on the version of Windows you may need to struggle with the setup a bit to get it working. Just keep researching and trying it until you get it, or see if you can ask a more experienced Ruby+Windows friend to help out.
Why do we need a bin/ folder?
This is just a standard place to put scripts that are run on the command line, not a place to put modules.
Do you have a real world example project?
There are many projects written in Ruby that do this, but try this simple one I created https://rubygems.org/gems/mongrel with source at https://github.com/mongrel/mongrel for you to browse.
My ruby tests/test_NAME.rb run shows one test being run. Is that right?
Yes, that's what my output shows too.

Video