Chapter 1
Introduction
Inochi is an infrastructure for RubyGems-based software projects that encourages good documentation, reduces programming effort, and automates common tasks.
Inochi is exciting because:-
It encourages good documentation:
- Provides a comprehensive user manual that integrates release notes, setup and usage instructions, and more.
- Automates the display of help, version, and usage information for your project’s main executable.
-
It reduces programming effort:
- Provides a single point of entry to your project’s libraries.
- Keeps your project’s configuration in one place.
- Parses command-line options using the Trollop library.
-
It automates common tasks:
- Generates project scaffolds while merging changes from previous ones.
- Provides Rake tasks for packaging, publishing, and announcing your project.
These features distinguish Inochi from the competition:
Etymology
In the past, software development was thought to be like mathematical modeling or building construction: the assembly of inanimate objects. Nowadays, it is thought to be more like gardening: the cultivation of life!
In this manner, I consider this project not as a generator of skeletons or as a builder of scaffolds, but as a giver of life. That is why I named this project “inochi”, the Japanese word for life.
Happy gardening!
1.1 Logistics
- Release notes — history of project releases.
- Source code — obtain via Git or browse online.
- API reference — documentation for source code.
- Project home — the Inochi project home page.
To get help or provide feedback, simply contact the author(s).
Version numbers
Inochi releases are numbered in major.minor.patch form according to the RubyGems rational versioning policy, which can be summarized thus:
What increased in the version number? | The increase indicates that the release: | ||
Is backward compatible? | Has new features? | Has bug fixes? | |
---|---|---|---|
major | No | Yes | Yes |
minor | Yes | Yes | Yes |
patch | Yes | No | Yes |
1.2 License
Copyright 2008 Suraj N. Kurapati sunaku@gmail.com
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.3 Credits
The “inochi.png” image and its “inochi.svg” source utilize the “3 flowers” graphic, which was created and released into the public domain by Peileppe Production on June 25, 2008.
Chapter 2
Setup
2.1 Requirements
Your system needs the following software to run Inochi.
Software | Description | Notes |
---|---|---|
Ruby | Ruby language interpreter | Version 1.8.6 or 1.8.7 is required. |
RubyGems | Ruby packaging system | Version 1.0.0 or newer is required. |
Lynx | Text-mode web browser | Version 2.8.6 or newer is required to convert HTML into plain text. |
2.2 Installation
You can install Inochi by running this command:
gem install inochi
To check whether the installation was sucessful, run this command:
inochi --version
If the installation was successful, you will see output like this:
project: Inochi version: 0.0.0 release: 2009-01-19 website: http://snk.tuxfamily.org/lib/inochi install: /home/sun/src/inochi
If you do not see such output, you may ask the author(s) for help.
2.3 Manifest
You will see the following items inside Inochi’s installation directory, whose path you can determine by running this command:
inochi --version
-
bin/
- inochi — the main Inochi executable.
-
lib/
- inochi.rb — the main Inochi library.
-
doc/
-
api/ — API reference documentation.
-
index.erb — source of this user manual.
-
-
LICENSE — copyright notice and legal conditions.
Part 3
Usage
3.1 Command-line interface
When you run this command:
inochi --help
You will see this output:
Inochi - Gives life to RubyGems-based software Progress indicators: create: A file is being created because it does not exist. skip: A file is being skipped because it is already up to date. update: A file will be updated because it is out of date. A text merging tool (see the "--merger" option) will be launched to transfer content from the old file (*.old) and the new file (*.new) to the out of date file. If a text merging tool is not specified, then you will have to do the merging by hand. Usage: inochi [Option...] ModuleName --merger, -m <s>: A command that invokes a text merging tool with three arguments: (1) old file, (2) new file, (3) output file. The command should write the result of merging the old file and the new file to the output file. The command may only modify the output file; it must NOT modify the old file or the new file. --manual, -a: Show the user manual --version, -v: Print version and exit --help, -h: Show this message
Tip 1. Merging files with kdiff3
Instead of merging files by hand, you can transfer wanted changes between files semi-automatically using kdiff3. Simply follow these instructions:
-
Create a file named merge2 with the following content:
#!/bin/sh old_file=$1 shift new_file=$1 shift output_file=$1 shift kdiff3 --auto "$old_file" "$new_file" --output "$output_file"
-
Make the file executable:
chmod +x merge2
-
Place the file in a directory that is listed in your
PATH
environment variable. -
Run Inochi like this:
inochi -m merge2
Now kdiff3 will be invoked to help you transfer your changes. When you are finished transferring changes, save the file and quit kdiff3. If you do not want to transfer any changes, simply quit kdiff3 without saving the file.
3.2 Ruby library interface
The Inochi
module has several class methods which provide a common configuration for various aspects of your project. These aspects, and their interactions with the Inochi
module, are as follows:
- Your project’s main library invokes the
Inochi.init()
method. - Your project’s main executable invokes the
Inochi.main()
method. - Your project’s Rakefile invokes the
Inochi.rake()
method. - Your project’s user manual invokes the
Inochi.book()
method.
3.3 Tutorial
This tutorial shows how Inochi is used to manage a hypothetical WordCount
project throughout the various stages of its life.
3.3.1 Have a brilliant idea
It is 4am on Sunday morning. Unwilling to sleep, you have spent the past few hours programming obsessively.. Though your eyes grow heavy and your stomach churns from hunger, your mind charges forth with haste.
Push on! Keep on!
Until at last, pushed far beyond its limit, your body overpowers your will and drags you into black unconsciousness.
BEEP BEEP B—
Half-asleep and violent from the sudden disturbance, you silence the bleeting alarm clock with vengeance. It is 2pm on Sunday afternoon.
Red beams of sunlight slip through the gaps in your curtains. It is a beautiful day, outside. Outside— you think,
What am I doing to myself?
I’ve got to get outside.
I’ve got to get away…
Away from this computer… this… mental prison in which I toil night after night, like a souless machine.
Venturing into the courtyard outside your quarters, you find peace. A warm breeze graces you, sweeping your hair gently as a mother would. The bright sunlight penetrates your mind’s eye as your thoughts fade…
Thoughts of tests to write, units to refactor, bugs to fix, options to document. They melt and mix and flow into nothingness.
All is clear. No thoughts. No more.
No!
You collapse heavily onto the grassy earth beneath you. Breathing deeply, you sink into yourself and whisper
It’s okay.
Just, let go.
and fall asleep.
You awaken that evening relaxed and refreshed. A brilliant idea for a new project enters your mind: the project will be a tool that counts the number of words in text file. And, the project can be accessed from Ruby via the WordCount
module.
However, you must go to work the next morning, so there isn’t much time. What can you do? Let’s see how Inochi can help us meet this challenge.
3.3.2 Generate your project
Give life to your new project:
# inochi WordCount create word_count/LICENSE create word_count/Rakefile create word_count/bin/word_count create word_count/lib/word_count.rb create word_count/doc/index.erb create word_count/doc/intro.erb create word_count/doc/setup.erb create word_count/doc/theory.erb create word_count/doc/usage.erb create word_count/doc/history.erb
Enter the word_count directory:
# cd word_count
View the available Rake tasks:
# rake -T (in /tmp/Inochi20090119-16887-1m6j3hx-0/word_count) rake ann # Build all release announcements. rake ann:feed # Build RSS announcement: doc/ann.xml rake ann:html # Build HTML announcement: ANN.html rake ann:mail # Build e-mail announcement: ANN.eml rake ann:text # Build plain text announcement: ANN.txt rake clean # Remove any temporary products. rake clobber # Remove any generated file. rake doc # Build all documentation. rake doc:api # Build API reference. rake doc:man # Build the user manual. rake pak # Build a release. rake pub # Publish a release. rake pub:ann # Publish all announcements. rake pub:ann:forge # Announce to RubyForge news. rake pub:ann:raa # Announce to RAA (Ruby Application Archive). rake pub:ann:talk # Announce to ruby-talk mailing list. rake pub:doc # Publish documentation to project website. rake pub:pak # Publish release packages to RubyForge.
Try the main project executable:
# ruby bin/word_count Command-line options: {:help=>false, :version=>false, :manual=>false} Command-line arguments: []
See usage information:
# ruby bin/word_count --help WordCount - TODO: put a single line description of your project here. TODO: Explain the command-line usage of this program here. Usage: word_count [Option...] Arg1 Arg2 Arg3... --manual, -m: Show the user manual --version, -v: Print version and exit --help, -h: Show this message
See project & version information:
# ruby bin/word_count --version project: WordCount version: 0.0.0 release: 2009-01-19 website: http://word_count.rubyforge.org install: /tmp/Inochi20090119-16887-1m6j3hx-0/word_count
See the user manual:
# rake doc:man 2>/dev/null # ruby bin/word_count --manual
The manual will now appear in your default web browser.
3.3.3 Configure your project
Section 3.2. Ruby library interface lists and documents the interactions between your project and Inochi. These points of interaction are illustrated in the following sections.
3.3.3.1 Project information
Open the LICENSE file, which contains the open source ISC license by default, and add a copyright notice with your name and (optional) email address:
Copyright 2009 Your Name <your@email.here> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Open the main project library file lib/word_count.rb and fill in the blanks:
require 'rubygems' gem 'inochi', '~> 0' require 'inochi' Inochi.init :WordCount, :project => 'WordCount', :version => '0.0.0', :release => '2009-01-19', :website => 'http://word_count.rubyforge.org', :tagline => 'TODO: put a single line description of your project here.', :require => { # TODO: list gems required by your project here. # NOTE: this is completely optional! # # example: if your project needs version 9.9.9 of the 'foo' gem: # 'foo' => '9.9.9', # # example: if any version of a gem is acceptable then: # 'foo' => nil, }
3.3.3.2 Project executable
Open the bin/word_count file and fill in the blanks:
#!/usr/bin/ruby -w # # TODO: Explain the command-line usage of this program here. # # Usage: # # word_count [Option...] Arg1 Arg2 Arg3... # require 'rubygems' gem 'inochi', '~> 0' require 'inochi' options = Inochi.main :WordCount do # TODO: define command-line options here. # see http://trollop.rubyforge.org/ # # NOTE: this is completely optional! end # TODO: add the body of your program here puts "Command-line options: #{options.inspect}" puts "Command-line arguments: #{ARGV.inspect}"
3.3.3.3 Rake tasks
Open the Rakefile and fill in the blanks:
require 'rubygems' gem 'inochi', '~> 0' require 'inochi' Inochi.rake :WordCount do |gem| # TODO: additional gem configuration. # NOTE: this is completely optional! # # gem.extensions = ['foo.so'] # gem.files += ['other', 'files'] end
3.3.3.4 User manual
The user manual’s source file doc/index.erb subdivides its content into several smaller files, according to topic, for easier editing and maintenance. These files are processed by the ERBook program’s XHTML format to produce the doc/index.xhtml file.
Open these source files and fill in the blanks:
doc/index.erb
<% Inochi.book :WordCount, self %>
<%# include intro.erb #%>
<%# include setup.erb #%>
<%# include theory.erb #%>
<%# include usage.erb #%>
<%# include history.erb #%>
doc/intro.erb
<% chapter "Introduction" do %>
<% project_summary do %>
> TODO: explain the purpose of your project
****<%= $project %>**** is a __________ that __________.
<% end %>
> TODO: explain why your project is important
**<%= $project %>** is exciting because:
* It lets you __________.
* Its core contains less than __________ lines of code.
* It __________.
> TODO: explain why your project is better than its competitors
These features distinguish **<%= $project %>** from the competition:
* [competitor 1](http://)
* [competitor 2](http://)
* [competitor 3](http://)
<% paragraph "Etymology" do %>
> TODO: explain the meaning of the name of your project
<% end %>
<% section "Logistics" do %>
* <%= xref "History", "Release notes" %> --- history of project releases.
* [Source code](http://github.com/sun/<%= $program %>) --- obtain via [Git](http://git.or.cz) or browse online.
* [API reference](api/index.html) --- documentation for source code.
To get help or provide feedback, simply
<%= xref "License", "contact the author(s)" %>.
<% paragraph "Version numbers" do %>
**<%= $project %>** releases are numbered in *major.minor.patch*
form according to the [RubyGems rational versioning
policy](http://www.rubygems.org/read/chapter/7), which
can be summarized thus:
<table markdown="1">
<thead>
<tr>
<td rowspan="2">What increased in the version number?</td>
<td colspan="3">The increase indicates that the release:</td>
</tr>
<tr>
<th>Is backward compatible?</th>
<th>Has new features?</th>
<th>Has bug fixes?</th>
</tr>
</thead>
<tbody>
<tr>
<th>major</th>
<td style="background-color: #FFE4E1;">No</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<th>minor</th>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<th>patch</th>
<td>Yes</td>
<td style="background-color: #FFE4E1;">No</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<% end %>
<% end %>
<% section "License" do %>
<%# include ../LICENSE #%>
<% end %>
<% section "Credits" do %>
> TODO: give attribution to your predecessors and contributors
<% end %>
<% end %>
doc/setup.erb
<% chapter "Setup" do %>
<% section "Requirements" do %>
Your system needs the following software to run **<%= $project %>**.
| Software | Description | Notes |
| -------- | ----------- | ----- |
| [Ruby](http://ruby-lang.org) | Ruby language interpreter | Version 1.8.7 is required. |
| [RubyGems](http://rubygems.org) | Ruby packaging system | Version 1.3.1 is required. |
<% end %>
<% section "Installation" do %>
You can install **<%= $project %>** by running this command:
gem install <%= $program %>
To check whether the installation was sucessful, run this command:
<%= $program %> --version
If the installation was successful, you will see output like this:
<pre><%= verbatim `ruby bin/#{$program} --version` %></pre>
If you do not see such output, you may
<%= xref "License", "ask the author(s)" %> for help.
<% end %>
<% section "Manifest" do %>
You will see the following items inside **<%= $project %>**'s installation
directory, whose path you can determine by running this command:
<%= $program %> --version
> TODO: list important files your project provides here
* <tt>bin/</tt>
* <tt><%= $program %></tt> --- the main **<%= $project %>** executable.
* <tt>lib/</tt>
* <tt><%= $program %>.rb</tt> --- the main **<%= $project %>** library.
* <tt><%= $program %>/</tt>
> TODO: list sub-libraries your project provides here
* <tt>doc/</tt>
* <tt>api/</tt> --- API reference documentation.
* <tt>index.erb</tt> --- source of this user manual.
* <tt>LICENSE</tt> --- copyright notice and legal conditions.
<% end %>
<% end %>
doc/theory.erb
<% chapter "Theory of operation" do %>
> TODO: explain how your project does what it does
<% end %>
doc/usage.erb
<% chapter "Usage" do %>
<% section "Command-line interface" do %>
When you run this command:
<%= $program %> --help
You will see this output:
<pre><%= verbatim `ruby bin/#{$program} --help` %></pre>
> TODO: explain the command-line arguments
<% end %>
<% section "Ruby library interface" do %>
> TODO: explain how to use your project's Ruby library
> from inside another Ruby program or library
<% end %>
<% section "Tutorial" do %>
This tutorial shows how **<%= $project %>** is used to __________.
> TODO: give examples for doing common tasks
<% end %>
> TODO: explain how to do more (advanced) things
<% end %>
doc/history.erb
<% chapter "History" do %>
> TODO: put a brief history about your project here
<% project_history do %>
> TODO: put release notes for your project
> here -- newest first, oldest last.
<% section "Version 0.0.0 (2009-01-19)" do %>
> TODO: write a short summary of the changes in this release
This release changes __________, adds __________, and fixes __________.
<% paragraph "Contributor kudos" do %>
> TODO: list everyone who contributed to this
> release and what their contribution was
* __________ contributed __________ which __________.
* __________ fixed __________ which __________.
* __________ added __________ which __________.
<% end %>
<% paragraph "Incompatible changes" do %>
> TODO: list all backward-incompatible changes in this release
* __________ has been __________ to __________.
* __________.
* __________.
<% end %>
<% paragraph "New features" do %>
> TODO: list new features added in this release
* __________.
* __________.
* __________.
<% end %>
<% paragraph "Bug fixes" do %>
> TODO: describe all bugs that are fixed in this release
* __________ was __________.
* __________ were __________.
* __________ did __________.
<% end %>
<% paragraph "Housekeeping" do %>
> TODO: list the refactorings, clean ups, and other
> improvements that were done for this release
* __________.
* __________.
* __________.
<% end %>
<% end %>
<% end %>
<% end %>
3.3.4 Implement your project
Add the following code to the bottom of the main project library:
module WordCount # Returns the number of words in the given input. def WordCount.count input input.to_s.split(/\W+/).length end end
Add the following code to the bottom of the main project executable:
input = ARGF.read total = WordCount.count(input) puts "There are #{total} words in the input."
Goodbye $LOAD_PATH
, hello require()
Notice that, in the Ruby files that you modified so far, there were no $LOAD_PATH
manipulations and no explicit require()
statements to pull in the various parts of your project. That is because Inochi does this for you automatically.
Furthermore, you can always require()
a sub-library anywhere in your project using its canonical path because Inochi puts your main project libraries on the Ruby load path.
For example, if your project has a sub-library, say, lib/word_count/odf/text.rb that counts the number of words in an OpenDocument Text document, then it would be loaded into the main project executable like this:
require 'word_count/odf/text'
Regardless of whether a sub-library is used within your project itself or from within an external application, we always require()
the sub-library using the same canonical path.
3.3.5 Test your project
TODO: show how to write a unit test for the code
TODO: integrate minitest tasks into Inochi.rake()
3.3.6 Publish your project
This command performs all of the automated steps described in the following sections:
# rake pub
3.3.6.1 Build a RubyGem
Build a RubyGem by running:
# rake pak (in /tmp/Inochi20090119-16887-1m6j3hx-0/word_count) (in /tmp/Inochi20090119-16887-1m6j3hx-0/word_count) Successfully built RubyGem Name: word_count Version: 0.0.0 File: word_count-0.0.0.gem
See the RubyGem contents:
# gem spec pkg/*.gem--- !ruby/object:Gem::Specification name: word_count version: !ruby/object:Gem::Version version: 0.0.0 platform: ruby authors: - Your Name autorequire: bindir: bin cert_chain: [] date: 2009-01-19 00:00:00 -08:00 default_executable: dependencies: - !ruby/object:Gem::Dependency name: inochi type: :runtime version_requirement: version_requirements: !ruby/object:Gem::Requirement requirements: - - "=" - !ruby/object:Gem::Version version: 0.0.0 version: description: "TODO: put a single line description of your project here." email: your@email.here executables: - word_count extensions: [] extra_rdoc_files: [] files: - lib - lib/word_count.rb - bin - bin/word_count - Rakefile - LICENSE - doc - doc/usage.erb - doc/index.erb - doc/history.erb - doc/intro.erb - doc/index.xhtml - doc/setup.erb - doc/api - doc/api/index.html - doc/api/all-methods.html - doc/api/app.js - doc/api/syntax_highlight.css - doc/api/readme.html - doc/api/style.css - doc/api/jquery.js - doc/api/all-namespaces.html - doc/theory.erb has_rdoc: true homepage: http://word_count.rubyforge.org post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: "0" version: required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: "0" version: requirements: [] rubyforge_project: word_count rubygems_version: 1.3.1 signing_key: specification_version: 2 summary: "TODO: put a single line description of your project here." test_files: []
3.3.6.2 Publish a RubyGem
You must first register your project on RubyForge before you can publish a RubyGem. If your RubyForge project name is different from your actual project name, then you should pass the :rubyforge_project
and :rubyforge_section
options to the Inochi.rake()
method).
Publish a RubyGem by running:
# rake pub:pak
3.3.6.3 Announce a release
You must first provide your Paragraph. Login information to Inochi. If you do not want to do this, then see Section 3.3.6.3.1. Manual release announcement.
Announce a release by running:
# rake pub:ann
Login information
In order to automate the announcement of releases, Inochi needs to know your login information for the RAA (Ruby Application Archive) and RubyForum, which serves as a gateway to the ruby-talk mailing list.
This information is expected to be stored in a ~/.config/inochi/logins.yaml file (this location can be overridden by passing the :logins_file
option to the Inochi.rake()
method), where ~ denotes the path to your home directory. This file is a YAML document containing the following parameters:
www.ruby-forum.com:
user: YOUR_USERNAME_HERE
pass: YOUR_PASSWORD_HERE
raa.ruby-lang.org:
pass: YOUR_PASSWORD_HERE
For better security, you should ensure that this file is only readable and writable by you and is not accessible by anyone else. In a UNIX environment, this can be accomplished by running the following command:
# chmod 0600 ~/.config/inochi/logins.yaml
3.3.6.4 Publish the documentation
Publish the user manual and API documentation by running:
# rake pub:doc
If your documentation website (see the :docsite
option for the Inochi.init()
method) is hosted on RubyForge, then the above command will automatically upload your project’s documentation to the correct place.