Wednesday, December 7, 2011

Ruby :: Gem :: Jeweler

Write a gem in Ruby using Jeweler

Steps.
- Install gem called jeweler
$ gem install jeweler
Fetching: jeweler-1.6.4.gem (100%)
Successfully installed jeweler-1.6.4
1 gem installed
Installing ri documentation for jeweler-1.6.4...
Installing RDoc documentation for jeweler-1.6.4...

To execute the command, first checkout the options
$ jeweler --help

Now generate a new project using the command jeweler.
$ jeweler hello_gem
No github.user found in ~/.gitconfig. Please tell git about your GitHub account (see http://github.com/blog/180-local-github-config for details). For example: git config --global github.user defunkt

ERROR: The above command came up with an error. 

To fix the user
$ git config --global github.user defunkt
$ git config --global github.token 6ef8395fecf207165f1a82178ae1b984
- replace defunkt and 6ef8395fecf207165f1a82178ae1b984
with your user and token respectively.
- To get the token from the Github
On Github > Account Seetings > Account Admin > API token: Your token is ***********

Rerun the jeweler command to create a new project
- By default the test script are generated for shoulda
- I am familiar with Rspec so I chose Rspec for my testing.
$ jeweler hello_gem --rspec
create .gitignore
create Rakefile
create Gemfile
create LICENSE.txt
create README.rdoc
create .document
create lib
create lib/hello_gem.rb
create spec
create spec/spec_helper.rb
create spec/hello_gem_spec.rb
create .rspec
Jeweler has prepared your gem in ./hello_gem

The structure of the directories are
$ tree
.
└── hello_gem
    ├── Gemfile
    ├── lib
    │   └── hello_gem.rb
    ├── LICENSE.txt
    ├── Rakefile
    ├── README.rdoc
    └── spec
        ├── hello_gem_spec.rb
        └── spec_helper.rb

3 directories, 7 files

hello_gem doesnt have the rspec gem yet, so in the Gemfile
group :test do
gem 'rspec', "~> 2.3.0" 
end

Run the bundle install command to install the rspec gem
$ bundle install

To know all the rake commands that can run, 
$ rake -T
rake build               # Build gem into pkg/
rake clobber_rdoc        # Remove rdoc products
rake console[script]     # Start IRB with all runtime dependencies loaded
rake gemcutter:release   # Release gem to Gemcutter
rake gemspec             # Generate and validate gemspec
rake gemspec:debug       # Display the gemspec for debugging purposes, as jeweler knows it (not from the filesystem)
rake gemspec:generate    # Regenerate the gemspec on the filesystem
rake gemspec:release     # Regenerate and validate gemspec, and then commits and pushes to git
rake gemspec:validate    # Validates the gemspec on the filesystem
rake git:release         # Tag and push release to git.
rake install             # Build and install gem using `gem install`
rake rcov                # Run RSpec code examples
rake rdoc                # Build the rdoc HTML Files
rake release             # Release gem
rake rerdoc              # Force a rebuild of the RDOC files
rake spec                # Run RSpec code examples
rake version             # Displays the current version
rake version:bump:major  # Bump the major version by 1
rake version:bump:minor  # Bump the a minor version by 1
rake version:bump:patch  # Bump the patch version by 1
rake version:write       # Writes out an explicit version.

Before we start with the gem we need a version to it.
$ rake version:write MAJOR=0 MINOR=1 PATCH=0
Updated version: 0.1.0

To know the current version
$ rake version
Current version: 0.1.0

Now install the gem 
$ rake install
rake aborted!
"FIXME" or "TODO" is not a description

Tasks: TOP => install => build
(See full trace by running task with --trace)

NOTE: If you get this error, then open the Rakefile
Change the lines from 
  gem.summary = %Q{TODO: one-line summary of your gem}
  gem.description = %Q{longer description of your gem}
to
  gem.summary = "one-line summary of your gem"
  gem.description = "longer description of your gem"

Now try again
$ rake install
  Successfully built RubyGem
  Name: hello_gem
  Version: 0.1.0
  File: hello_gem-0.1.0.gem
Executing "ruby -S gem install ./pkg/hello_gem-0.1.0.gem":
ruby -S gem install ./pkg/hello_gem-0.1.0.gem
Successfully installed hello_gem-0.1.0
1 gem installed
Installing ri documentation for hello_gem-0.1.0...
Installing RDoc documentation for hello_gem-0.1.0...

Now you can push the gem to Github and Rubygems.org
First commit all the changes to Git
$ git add .
$ git commit -am "inital setup"

Second create an repository at github, and call it hello_gem
This will create a repository called hello_gem.git

Run the command
$ rake release
Committing hello_gem.gemspec
Pushing master to origin
Generated: hello_gem.gemspec
hello_gem.gemspec is valid.
  Successfully built RubyGem
  Name: hello_gem
  Version: 0.1.0
  File: hello_gem-0.1.0.gem
Executing "gem push ./pkg/hello_gem-0.1.0.gem":
gem push ./pkg/hello_gem-0.1.0.gem
Pushing gem to https://rubygems.org...
You do not have permission to push to this gem.
rake aborted!
Command failed with status (1): [gem push ./pkg/hello_gem-0.1.0.gem...]

- It generated the gemspec file
- validates the hello_gem.spec
- It pushes the gem to GIT
- ERROR: It fails to push the gem to rubygems.org

Gems are no longer hosted by Github, It has moved to Rubygems.org
- To move gems to Rubygems, use Gemcutter
- To install gemcutter
$ gem update --system

Now install the gem
$ gem install gemcutter

Now stay in the hello_gem folder, and build the gem
$ gem build hello_gem.gemspec 
  Successfully built RubyGem
  Name: hello_gem
  Version: 0.1.0
  File: hello_gem-0.1.0.gem

Now push the gem to rubygems.org
$ gem push hello_gem-0.1.0.gem 
Enter your Gemcutter credentials. Don't have an account yet? Create one at http://gemcutter.org/sign_up
Email:   user@example.com
Password:   
Signed in. Your api key has been stored in ~/.gemrc
Pushing gem to Gemcutter...
Successfully registered gem: hello_gem (0.1.0)

Now gem is part of the Rubygems.

To add Gemcutter support to Jeweler
In the Rakefile, enter the line
Jeweler::GemcutterTasks.new
- This line has to added after the require 'jeweler'

Now check if we have the gemcutter functionality in Jeweler
$ rake -T
rake gemcutter:release   # Release gem to Gemcutter

Now execute the rake command to send the gem to rubygems.org
$ rake gemcutter:release
- This is exactly the same as 'gem push hello_gem-0.1.0.gem'

Now lets look at the current directory
$ tree
.
├── Gemfile
├── Gemfile.lock
├── hello_gem.gemspec
├── lib
│   └── hello_gem.rb
├── LICENSE.txt
├── pkg
│   └── hello_gem-0.1.0.gem
├── Rakefile
├── README.rdoc
├── spec
│   ├── hello_gem_spec.rb
│   └── spec_helper.rb
└── VERSION


3 directories, 11 files

So far the gem is empty so lets write something to it.
Let start writing to it, in the lib/hello_gem.rb
$ cat lib/hello_gem.rb
class HelloGem
  def self.hi
    puts "Hello World!"
  end
end

Now bump the version to a minor release
$ rake version:bump:minor
Current version: 0.1.0
Updated version: 0.2.0

Update the gem in ur local machine
$ rake install
  Successfully built RubyGem
  Name: hello_gem
  Version: 0.2.0
  File: hello_gem-0.2.0.gem
Executing "ruby -S gem install ./pkg/hello_gem-0.2.0.gem":
ruby -S gem install ./pkg/hello_gem-0.2.0.gem
Successfully installed hello_gem-0.2.0
1 gem installed
Installing ri documentation for hello_gem-0.2.0...
Installing RDoc documentation for hello_gem-0.2.0...

Check if the gem is updated.
$ irb
ruby-1.9.2-p290 :001 > require 'hello_gem'
 => true 
ruby-1.9.2-p290 :002 > HelloGem.hi
Hello World!
 => nil 

Modify the gem file to require another file.
- create a directory in the lib with the same name 'hello_gem'
$ mkdir lib/hello_gem

- create a file called translator.rb and write the following
$ cat lib/hello_gem/translator.rb
class Translator
  def initialize(language)
    @language = language
  end


  def hi
    case @language
      when 'spanish'
        "Hola Mundo!"
      when 'english'
        "Hello World!"
      else
        "ERROR !!!"
    end
  end
end


- Modify the gemfile to include this translator
$ cat lib/hello_gem.rb
require 'hello_gem/translator'

class HelloGem
  def self.hi(language = 'english')
    translator = Translator.new(language)
    translator.hi
  end
end

Now update the git repository
$ git add .
$ git commit -am "hello_gem/translator added"
$ rake version:bump:minor
$ rake install
$ irb
> require 'hello_gem'
 => true 
> HelloGem.hi
 => "Hello World!" 
> HelloGem.hi('english')
 => "Hello World!" 
> HelloGem.hi('spanish')
 => "Hola Mundo!" 
> HelloGem.hi('hindi')
 => "ERROR !!!" 

To make the executable
$ mkdir bin
$ touch bin/hello_gem
$ chmod a+x bin/hello_gem

Edit the bin/hello_gem
$ cat bin/hello_gem
#!/usr/bin/env ruby


require 'hello_gem'
puts HelloGem.hi(ARGV[0])

To make this executable, we have include the following line in the gemspec
$ cat hello_gem.gemspec
Gem::Specification.new do |s|
  :
  s.executables << 'hello_gem'
end

Update the git repository and reinstall the gem
On the command line
$ hello_gem english
Hello World!
$ hello_gem spanish
Hola Mundo!

Testing, In the spec folder, edit hello_gem_spec.rb
$ cat spec/hello_gem_spec.rb

require File.expand_path(File.dirname(__FILE__) + '/spec_helper')


describe "HelloGem" do
  it "should return Hello World" do
    HelloGem.hi.should == 'Hello World!'
  end
  it "should return Hello World" do
    HelloGem.hi('english').should == 'Hello World!'
  end
  it "should return Hola mundo" do
    HelloGem.hi('spanish').should == 'Hola Mundo!'
  end
  it "should return error" do
   HelloGem.hi('french').should == 'ERROR !!!'
  end


end

Execute the tests to make sure it passes
$ rspec spec/
....

Finished in 0.0005 seconds
4 examples, 0 failures

Documentation of work.
In the hello_gem.rb
$ cat lib/hello_gem.rb
# The main HelloGem class
class HelloGem
  # Say Hi to the world.
  #
  # Example:
  #   >> HelloGem.hi('spanish')
  #   => Hola Mundo!
  #
  # Arguments:
  #   language: (string)
  
  def self.hi(language = 'english')
  :


Resouces: 
http://guides.rubygems.org/make-your-own-gem/
http://asciicasts.com/episodes/183-gemcutter-jeweler

1 comment:

  1. very informative blog and useful article thank you for sharing with us , keep posting
    Ruby on Rails Online Training Hyderabad

    ReplyDelete