What Are the Steps Needed to Create and Publish a Rubygem of Your Own

What are the steps needed to create and publish a rubygem of your own?

There are several tools to help you build your own gems. hoe and newgem are the best-known, and have a lot of good qualities. However, hoe adds itself as a dependency to your gem, and newgem has become a very large tool, one that I find unwieldy when I want to create and deploy a gem quickly.

My favorite tool is Mr Bones by Tim Pease. It’s lightweight, featureful, and does not add dependencies to your project. To create a project with it, you just run bones <my_project_name> on the command line, and a skeleton is built for you, complete with a lib directory for your code, a bin directory for your tools, and a test directory. The configuration is in a Rakefile, and it’s clear and concise. Here's the configuration for a project I did a few months ago:

load 'tasks/setup.rb'

ensure_in_path 'lib'
require 'friend-feed'

task :default => 'test'

PROJ.name = 'friend-feed'
PROJ.authors = 'Clinton R. Nixon'
PROJ.email = 'crnixon@gmail.com'
PROJ.url = 'friend-feed.rubyforge.org'
PROJ.rubyforge_name = 'friend-feed'
PROJ.dependencies = ['json']
PROJ.version = FriendFeed::VERSION
PROJ.exclude = %w(.git pkg)

Mr Bones has the standard set of features you’d expect: you can use it to package up gems and tarfiles of your library, as well as release it on RubyForge and deploy your documentation there. Its killer feature, though, is its ability to freeze its skeleton in your home directory. When you run bones --freeze, a directory named .mrbones is copied into your home directory. You can edit the files in there to make a skeleton for your gems that works the way you work, and from then on, when you run bones to create a new gem, it will use your personal gem skeleton. You can unfreeze Mr Bones by running bones --unfreeze and your skeleton will be backed up, and the default skeleton will be used again.

(Editorial note: I wrote a blog post about this several months ago, and most of this is copied from it.)

how can i create and publish a rubygem which relies on forked rubygems?

As you can read about in this article, putting your gem's dependencies in its Gemfile is not the right way. Rather, you should put the gemspec line in the Gemfile which directs it to read from the gemspec file. Think about the Gemfile as being for development only - when you push the gem, the gemspec alone becomes the specification for dependencies.

And, as you can read here, it is not possible to put a git source in the gemspec.

In light of this, my recommendation would be to move the forked gem's source code into your file and add it's dependencies to your gemspec. Usurp it, in other words - make it part of your project.

You could also specify in your README that users should add this separate gem to their Gemfile, sourced from git. That's easier for you but adds another step to the installation process.

How to create a new Ruby gem?

Use Bundler

From the command line:

bundle gem your_new_gem

This will create a directory called your_new_gem with just a basic set of files and directory structure that are now considered best-practice. It's quick, easy, and a great place to start.

In depth Ruby Gem development resources (book, video, sites)

Rubygems aren't related to distributed programming.

Can you please provide more details about what you're after, if you aren't asking a duplicate question? Related questions within Stack Overflow include:

  • Gotchas for writing rubygems
  • Ruby : How to write a gem ?
  • What are the steps needed to create and publish a rubygem of your own?
  • What is the modern way to structure a ruby gem?

(I know this is more of a comment than an answer, but it's too big to fit in the comments section)

Gotchas for writing rubygems

Gem Packaging: Best Practices gives a lot of advice, some of which include

  • Don't pollute the global load path. Ideally, only have foo.rb in your lib directory, and put all your other files in lib/foo.

  • Don't require files using __FILE__.

  • Don't rely on anything outside the load path. Folders may not have the same structure as in your original version. For example, don't use something like

    VERSION = ::File.read(::File.join(::File.dirname(FILE), "..", "..", "VERSION")).strip

  • Don't manage $LOAD_PATH within lib.

  • Provide a VERSION constant.

  • Don't depend on rubygems. The person using your code may not be using rubygems, but some other packaging system (or no packaging system). Similarly, don't mention version dependencies in the code itself, or rescue Gem::LoadError.

Rubygems dependencies. Please... argues that you shouldn't list optional runtime dependencies, and should separate developer from runtime dependencies.

From my own experience: if nothing else, try building and installing your gem locally before releasing it into the wild. It avoids brown paper bag releases.

Ruby : How to write a gem?

Rubygems.org's Guides is one of the best resources for writing your own gem.

If you're using Bundler in your app, you might want to look at Ryan Bigg's guide to Developing a RubyGem using Bundler and the Railscast on creating gems with Bundler.

If you're interested in tools to help you write gems:

  • Jeweler - Opinionated tool for creating and managing Rubygem projects. There's also a Gemcutter and Jeweler Railscast.
  • Hoe - From the guys at seattlrb.
  • gem-this adds a bunch of helpful rake tasks.

Some tutorials/guides:

  • Creating Your First Gem
  • Using bundler and rvm to build a rubygem - Using bundler and rvm to create a gem
  • Gem Packaging: Best Practices
  • Ruby Gem Recipe - Intro guide to creating a gem using bundler and jeweler
  • How to build a ruby gem and host it on gemcutter - tutorial using echoe and gemcutter
  • The Truth About Gemspecs - goes over gemspecs and tips for dealing with them
  • Packaging with RubyGems - a quickstart guide for Jeweler
  • gem that - James Adam - reviews tools that help build gems (hoe, newgem, echoe, gemhub, jeweler, gem this)
  • Using Gemcutter's Api from the Commandline
  • New Gem with Bundler – Sample Rakefile - Useful rakefile for deploying and publishing a gem
  • Let's Write a Gem
  • How To Build A Ruby Gem With Bundler, Test-Driven Development, Travis CI And Coveralls, Oh My!

How should I structure my ruby gem command line service?

Largely, RubyGems will take care of this for you. You'll need to include your executable in the files list, and put it in the executables in your gemspec. It's common to put your executable in bin in your directory, e.g.:

$ ls
bin/ myapp.gemspec lib/ Rakefile
$ ls bin
bin/myapp

Your gemspec would then look like:

Gem::Specification.new do |s|
s.name = 'myapp'

# whatever else is in your gemspec

s.files = ["bin/myapp","lib/myapp.rb"] # or whatever other files you want
s.executables = ["bin/todo"]
end

At this point, when users install your app via RubyGems, myapp will be in their path, and lib will be in your app's loadpath, so your executable can simply start off with:

#!/usr/bin/env ruby

require 'myapp'
# whatever other requires

The only issue with this is that, during development, you cannot just do bin/myapp and have your app run. Some devs manipulate the load path via $: or $LOAD_PATH, but this is considered bad form.

If you are using bundler, it's easiest to just run your app locally with bundle exec, e.g. bundle exec bin/myapp. You can alternately use the RUBYLIB environment variable, e.g. RUBYLIB=lib bin/myapp, which will put lib in the load path.

How to execute a published Ruby Gem CLI app

I see some problems with this. But first, let me address your original question.

To test it on the command line (terminal):

$ gem install phl-covid-testing
$ which run
$ run

To test it in your Bundler project, add phl-covid-testing to your Gemspec/Gemfile. Then do this:

$ bundle install
$ bundle exec run

Now for the problems. The first problem you can see above is that you named your script run. This will be put on the user's path. It'd be better to rename your bin/run script to bin/phl-covid-testing or something else.

Next, I don't know if you did chmod +x on your script file in bin/, but I'll assume you did. However looking at the contents of the file, you have this:

#!/usr/bin/env ruby

require "bundler/setup"
require "./lib/environment"

PHLCovidTesting::CLI.new.call

You shouldn't use ./lib/environment, instead just do require 'environment'. You also don't need require "bundler/setup". If you're testing locally, just use bundle exec bin/run.

Next, don't use the name environment.rb. I suggest renaming this file to the name of your Gem, so it would be phl-covid-testing.rb.

Lastly, your repo has a lot of unnecessary files. Remove .DS_Store and phl-covid-testing-0.1.0.gem and also add these to .gitignore:

# .gitignore
.DS_Store
*.gem

There might be more files that you need to ignore or more problems, but these are the major ones that I see at a glance.

EDIT:

I decided to add how you can test this without uploading to RubyGems.org.

If you're using bundler and rake and you have require 'bundler/gem_tasks' in your Rakefile, then you can do this:

$ bundle exec rake install:local

This will build and install the Gem locally.

Else, you can also do this using the gem command manually:

## Remove old gems (optional).
$ rm -v *.gem

$ gem build phl_covid_testing.gemspec
$ gem install *.gem

See the official doc for more information.

Then try to run the script as I mentioned earlier:

$ phl_covid_testing
## Or with bundler:
$ bundle exec phl_covid_testing


Related Topics



Leave a reply



Submit