Convert your Ruby Script to a Ruby-Gem
What is a gem?
Gem is basically a library of reusable ruby codes or simply ruby plugins. One should be thinking of creating ruby gems for some of the reasons
Want to make generic solutions quickly achievable to public or within organization Share newer functionality with others Organize reusable codes in larger projects
Introduction to gem development
Gems has actually no size limitations, it can go to any extent. For beginners, a gem could be a small code library that adds some helper methods into the existing ruby classes such as String class. In this tutorial we will try to add some helper methods in String class so that this methods could be used in testing or in Models of Rails framework.
GEM NAME | REQUIRE STATEMENT | MAIN CLASS OR MODULE |
---|---|---|
ruby_parser |
require 'ruby_parser' |
RubyParser |
rdoc-data |
require 'rdoc/data' |
RDoc::Data |
net-http-persistent |
require 'net/http/persistent' |
Net::HTTP::Persistent |
net-http-digest_auth |
require 'net/http/digest_auth' |
Net::HTTP::DigestAuth |
Generating a New Gem
There are four ways to create a new gem
- Create the directory tree with required files in proper way (not recommended)
- Rubymine's new 'Ruby gem' project
- Using Bundler in terminal
- Using available frameworks such as
newgem
,hoe
,echoe
,gemhub
,bones
Using Bundler
Making it a gem, you will make it easier to install and use. Any body can benefit from your scripts.
We will use the famous tool bundler
to generate a new gem
project. This will generate files necessary.
bundle gem erika
will generate the files and dir like:-
~/projects/erika(master) tree
.
├── CODE_OF_CONDUCT.md
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── bin
│ ├── console
│ └── setup
├── erika.gemspec
├── lib
│ ├── erika
│ │ └── version.rb
│ └── erika.rb
└── spec
├── erika_spec.rb
└── spec_helper.rb
4 directories, 12 files
Update GemSpec file
lib = File.expand_path("lib", __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "erika/version"
Gem::Specification.new do |spec|
spec.name = "erika"
spec.version = Erika::VERSION
spec.authors = ["Shiva Bhusal"]
spec.email = ["youremail@gmail.com"]
spec.summary = %q{TODO: Write a short summary, because RubyGems requires one.}
spec.description = %q{TODO: Write a longer description or delete this line.}
spec.homepage = "https://shivab.com"
spec.license = "MIT"
spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 2.0"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", "~> 3.0"
end
add production
/ runtime
dependencies like
spec.add_runtime_dependency 'example', '~> 1.1', '>= 1.1.4'
gems mentioned with add_development_dependency
method are only installed in development; I mean
using bundle install
in development mode of this gem-project.
Gem consumers will execute gem install erika
or bundle install
in other app; which will only
install runtime dependencies
.
spec.bindir
By default exe
will be your home for your executable script files. If your gem is a CLI tool then
only you need to create any script in exe
folder.
What is the use of Gemfile in gem?
# Gemfile
source "https://rubygems.org"
# Specify your gem's dependencies in erika.gemspec
gemspec
Well, it makes possible to run bundle install
command to install gem dependencies mentioned in
erika.gemspec
file. You can see gemspec
method used in Gemfile
. It will get the list of
all gems mentioned in gemspec
file.
Useful commands
rake build # Build rubytutor-0.1.0.gem into the pkg
directory
rake clean # Remove any temporary products
rake clobber # Remove any generated files
rake install # Build and install rubytutor-0.1.0.gem into
system gems
rake install:local # Build and install rubytutor-0.1.0.gem into
system gems withou...
rake release[remote] # Create tag v0.1.0 and build and push
erika.gem to RubyGems
rake test # Run tests
Moving your scripts to Gem
My lib dir
lib> (master) tree
.
├── erika
│ ├── audio.rb
│ ├── config.rb
│ ├── image.rb
│ ├── runner.rb
│ └── video.rb
├── erika.rb
├── hash.rb
└── string.rb
1 directory, 8 files
- move your
lib
directory tolib
dir of your new gem. - move your
config
files - setup your
Gemfile
- create an executable
the
exe
folder is where you wish to put scripts which users will like to use via CLI. If your gem is not going to be used via CLI, no need to create anything inexe
folder.
Build Script executible from anywhere
I create exe/erika
file with following content
#!/usr/bin/env ruby
require File.absolute_path('../lib/erika', __dir__)
Erika::Slideshow.new
then installed the gem locally
rake install
------------
erika 0.1.0 built to pkg/erika-0.1.0.gem.
erika (0.1.0) installed.
then tried
erika
Traceback (most recent call last):
4: from /Users/john/.rvm/gems/ruby-2.6.3/bin/erika:23:in `<main>'
3: from /Users/john/.rvm/gems/ruby-2.6.3/bin/erika:23:in `load'
2: from /Users/john/.rvm/gems/ruby-2.6.3/gems/erika-0.1.0/exe/erika:3:in `<top (required)>'
1: from /Users/john/.rvm/rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
/Users/john/.rvm/rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- /Users/john/projects/lib/erika (LoadError)
Reason
Since the script file erika
is bin-stubbed in some bin
directory by bundler/installer,
so ruby
cannot properly locate the ruby file like ../erika/config
, so we need to modify the
ruby load-path.
Solution
#!/usr/bin/env ruby
require 'pry'
# Adding the lib directory to the Load Path of Ruby
$:.unshift File.expand_path("../../lib", __FILE__)
require 'erika'
erika = Erika::SlideShow.new
erika.start
Build CLI option handlers
You also want to support CLI options like
erika g -s happy -S=5 -t=4 -o=opt/mymovie.mp4
We will use Thor
support CLI options
#!/usr/bin/env ruby
require 'pry'
require 'thor'
# Adding the lib directory to the Load Path of Ruby
$:.unshift File.expand_path("../../lib", __FILE__)
require 'overrides/hash'
$erika_options = {}
class Options < Thor
desc "g", "Generate movie"
method_option :output,
:aliases => "-o",
:desc => "Output path; where to generate output movie"
method_option :source,
:aliases => "-s",
:desc => "Input path; folder path where the images are located"
method_option :audio,
:aliases => "-a",
:desc => "Audio path; the path to bg audio"
method_option :transition_duration,
:aliases => "-t",
:desc => "Transition animation duration between two images"
method_option :slide_duration,
:aliases => "-S",
:desc => "Slide duration between two images"
def g
# $erika_options.merge({output_dir: File.expand_path(options[:o])}) if options[:o]
# $erika_options.merge({source_dir: File.expand_path(options[:s]),
# source_files: ''}) if options[:s]
# $erika_options.merge({audio: File.expand_path(options[:a])}) if options[:a]
$erika_options = options.to_o
require 'erika'
erika = Erika::SlideShow.new
erika.start
end
end
Options.start(ARGV)
this will build beautiful CLI API. Try
$ exe/erika help g
Usage:
erika g
Options:
-o, [--output=OUTPUT] # Output path; where to generate output movie
-s, [--source=SOURCE] # Input path; folder path where the images are located
-a, [--audio=AUDIO] # Audio path; the path to bg audio
-t, [--transition-duration=TRANSITION_DURATION] # Transition animation duration between two images
-S, [--slide-duration=SLIDE_DURATION] # Slide duration between two images
Generate movie
Publishing Gem
First you need to signup @ https://rubygems.org. Then
you need to signin from CLI
$ gem signin
Enter your RubyGems.org credentials.
Don't have an account yet? Create one at https://rubygems.org/sign_up
Email: hotline.shiva@gmail.com
Password:
Enter password and you are in.
Then, build and release
$ rake release
erika 0.1.0 built to pkg/erika-0.1.0.gem.
Tag v0.1.0 has already been created.
Pushing gem to https://rubygems.org...
Successfully registered gem: erika (0.1.0)
Pushed erika 0.1.0 to https://rubygems.org
Summary
- either you can generate a skeleton gem using
bundle gem
command or move exising ruby project to it. - You then, refactor the library so that files can be required my
ruby
properly. - Build a CLI interface if required
- configure your gemspec properly
- signup to
rubygems.org
- publish/release your gem.