#135
Nov 10, 2008

Making a Gem

Want to create a Ruby Gem instead of a Rails plugin? In this episode I will walk you through creating a gem to extend Rails.
Download (18.2 MB, 9:08)
alternative download for iPod & Apple TV (12.1 MB, 9:08)

Resources

sudo gem install echoe
mkdir -p uniquify/lib
touch README.rdoc Rakefile lib/uniquify.rb
rake -T
rake manifest
rake install
rake build_gemspec
git init
git add .
git commit -m "initial commit"
git remote add origin git@github.com:ryanb/uniquify.git
git push
touch CHANGELOG
touch init.rb
# Rakefile
require 'rubygems'
require 'rake'
require 'echoe'

Echoe.new('uniquify', '0.1.0') do |p|
  p.description    = "Generate a unique token with Active Record."
  p.url            = "http://github.com/ryanb/uniquify"
  p.author         = "Ryan Bates"
  p.email          = "ryan@railscasts.com"
  p.ignore_pattern = ["tmp/*", "script/*"]
  p.development_dependencies = []
end

Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }

# lib/uniquify.rb
module Uniquify
  def self.included(base)
    base.extend ClassMethods
  end
  
  def ensure_unique(name)
    begin
      self[name] = yield
    end while self.class.exists?(name => self[name])
  end
  
  module ClassMethods
    
    def uniquify(*args, &block)
      options = { :length => 8, :chars => ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a }
      options.merge!(args.pop) if args.last.kind_of? Hash
      args.each do |name|
        before_create do |record|
          if block
            record.ensure_unique(name, &block)
          else
            record.ensure_unique(name) do
              Array.new(options[:length]) { options[:chars].to_a[rand(options[:chars].to_a.size)] }.join
            end
          end
        end
      end
    end
    
  end
end

class ActiveRecord::Base
  include Uniquify
end

# init.rb
require 'uniquify'

RSS Feed for Episode Comments 26 comments

1. Josh Nov 10, 2008 at 00:18

Another great railscast, I've been wondering how to make a gem and this was really straight forward! Thanks!


2. Morten Nov 10, 2008 at 03:34

Full circle! Great as usual..


3. Dr Nic Nov 10, 2008 at 04:14

Watching you 'just paste in some code' made me remember why generators are cool :)

Protip: if you want to distribute command-line executables with your gem, like the "rake" or "rails" command, then put them in <code>bin/</code> folder. Hoe, and I think Echoe, automatically package them up as executables, which is sexy.


4. sintaxi Nov 10, 2008 at 13:05

there has never been enough talk about publishing gems. Thanks ryan for adding to a lacking topic. btw - I sure like how echoe is not required as a dependency.


5. Ryan Bates Nov 10, 2008 at 17:25

@drnic good point about generators, and thanks for the protip. I did paste a lot of code in this episode, but the majority of it is specific to the project. The only thing I feel needs generating is the Rakefile, and even that has a lot of project-specific settings in it.

A generator is very much a personal preference, but I encourage everyone to try the existing ones out there or make your own as needed. For me copy & pasting the Rakefile content from an existing one is easy enough.


6. Bryce Nov 11, 2008 at 02:35

Thankyou for this tutorial, I just made my first Ruby Gem - a gem for accessing the Google Translation API, currently hosted @ github: http://github.com/bdude/rosettastone/tree/master


7. Ryan Bates Nov 12, 2008 at 10:41

@David, there already is spam protection in place behind the scenes which has been working really well (it's blocking an amazing amount of spam). As far as I can tell, the spam you were seeing (now deleted) was from an actual human and not a spam bot.


8. Laurent Farcy Nov 13, 2008 at 06:34

Ryan. Thx for your great screencasts.

Your plugin has a clear (hard) dependency on ActiveRecord. But you do not declare anything in your gem. Can you do that with echoe ? (so uniquify cannot be installed unless activerecord is already installed on the host). Do you recommend to explicit dependencies in gems ?


9. Cassiano Nov 13, 2008 at 08:53

@Ryan,

Thanks for this very useful screencast.

Should Rakefile really be uploaded to github, as it seems like it wont' be used by either github or the final user of the gem?

Shouldn't your gem be named "ryanb-uniquify" instead, as this will be the final folder in "ruby\lib\ruby\gems\1.8\gems" (plus version, of course)?


10. Cassiano Nov 14, 2008 at 03:04

Clarifying my previous post: after generating the gem, if you install it locally by running "gem install pkg\<gem-name>-<version>.gem", you end up with a distinct folder name in "...\ruby\lib\ruby\gems\1.8\gems" when compared to installing it from the git repository (as github always seems to add an owner prefix to the gem name provided in .gemspec file).

But of course adding the owner prefix yourself doesn't solve the issue, as github will still add the owner prefix to whatever gem name you supply to it.


11. Ryan Bates Nov 14, 2008 at 10:08

@Laurent, good question, I prefer to only use dependencies where I have a "require" statement which loads that gem. Here there is no "require 'activerecord'" line because I expect the developer to load this environment how he desires. He may have edge rails frozen, in that case ActiveRecord is not loaded from a gem and there's really no gem dependency.

If I had other gem dependencies outside of Rails then I would likely add those.

@Cassiano, it's important the Rakefile be in the git repository so anyone else who clones/forks the repo can regenerate the gem after making changes.

Also the gem name should not contain your username prefix as GitHub will add this when it generates the gem using your gemspec.


12. Cassiano Nov 14, 2008 at 11:20

@Ryan,

Thanks for the Rakefile explanation.

Regarding the naming problem, my intent is to have a local gem that installs exactly the same as the remote (gihub's) one, such that running:

gem install pkg\ryanb-uniquify-0.1.0.gem

or

gem install ryanb-uniquify --source http://gems.github.com

would yield the same installation.

But the only way I can do it is by manually adding the username prefix to my *local* copy of Rakefile and regenerating the gem via the "rake install" task.

The Rakefile would then be restored to its original state before running the "rake build_gemspec" task and committing it to git.


13. Tim Matheson Nov 17, 2008 at 21:28

What is the benefit of using gems as opposed to plugins?


14. Amos King Nov 25, 2008 at 19:57

I don't think you are supposed to ignore the Manifest file on github.


15. softprops Dec 05, 2008 at 16:31

Ryan B. You make the world a better place. I can always find great content here and for your main focus to be sharing info rather than promoting info, it shows you have lot of character. Your mom should be proud.


16. redvex Aug 11, 2009 at 06:21

load my gem in github but...

ERROR: could not find gem redvex-ar_cache locally or in a repository

can you help me?


17. redvex Aug 11, 2009 at 06:23

This is the url on github

http://github.com/redvex/ar_cache/tree/master


18. redvex Aug 11, 2009 at 06:43

Ok... github told me that my gem mill Manifest file, maybe you should correct the post, becouse in it you told us to add Manifest file in .gitignore


19. daria Jan 13, 2010 at 05:25

thanks


20. Angela Feb 16, 2010 at 23:43

Super !


21. Artemidka Mar 02, 2010 at 09:35

!!!!!!!!!!!!!!!!!!!!!


22. Bodybuilding & sports nutrition Mar 04, 2010 at 08:10

Cool I tried it and it works.


23. vacation rentals hawaii Mar 06, 2010 at 18:39

Try Hawaii this coming summer and i will assure everyone will enjoy it.


24. fjejf Mar 18, 2010 at 22:54

thlfjeojf


25. jungle force boots May 07, 2010 at 19:23

Another reason that I would regard joining a political party to be such a valuable thing is that dramatically positive and liberating experience.


26. check up May 17, 2010 at 08:53

High quality Cisco, HP, IBM, Oracle and other Certification exmas training materials are provided here at Pass4sure Pass4sure helps you on your way to your certifications


27. No copy May 21, 2010 at 02:35

Your plugin has a clear (hard) dependency on ActiveRecord. But you do not declare anything in your gem. Can you do that with echoe ? (so uniquify cannot be installed unless activerecord is already installed on the host). Do you recommend to explicit dependencies in gems ?

<a href="http://www.xspyz.com">Torrent downloads</a>


28. discount AF1 cap May 25, 2010 at 04:49

oh,it is so nice of you,and thanks for your sharing.


29. discount Affliction cap May 25, 2010 at 04:51

I really appreciate it,thanks for your wonderful post.


30. discount A-cap May 25, 2010 at 04:51

Thanks for your sharing.
It's so kind of you.I have got a useful information from you.
There are something that i found a long time ago.


31. rapidshare Jul 25, 2010 at 16:26

I have looking for like this resource. finally i got from your site. thanks alot


32. hotfile download Jul 27, 2010 at 23:45

thankful for your nice nice information. i really waiting for this resource.


33. valya Jul 30, 2010 at 21:32

Thanks for sharing it.


35. WTSYERY Aug 05, 2010 at 08:48

shgtrfjxzdyhtrh


36. Coach Outlet Aug 12, 2010 at 03:51

Here we have new style Coach Handbags.All the Coach purses are good quality and lower price.A fashion Coach Outlet is dreamed by the fashion females.Welcome to our store discountbagshop.com.I am sure you will find one for yourself.


37. p90 workout Aug 12, 2010 at 09:15

I want to say that I dont think Ive read anything so true in a long time. Youve got a lot of great ideas, a great deal of perspective. I think that you definitely have something important to say and Im gonna back it 110%, man. Good job keeping this subject alive and interesting!


38. Jordan basketball shoes Aug 14, 2010 at 02:15

Here we have new style Coach Handbags.All the Coach purses are good quality and lower price.A fashion Coach Outlet is dreamed by the fashion females. Cool I tried it and it works.


39. Wholesale baseball hats Aug 20, 2010 at 20:54

Took me awhile to read all the comments, but I really love the article. It proved to be very useful to me and I am sure to all the commenters here! It's always nice when you can not only be informed, but also entertained! I'm sure you had fun writing this article. Comfortably, the article is really the sweetest on this precious topic.


40. louis vuitton shoes Aug 26, 2010 at 21:10

Thanks for sharing your article. I really enjoyed it. I put a link to my site to here so other people can read it. My readers have about the same interets


41. Wholesale Electronics Aug 27, 2010 at 00:27

Discount Wholesale Electronics, Wholesale Cell Phones, Electronic Gadgets and More from the Best Dropship Wholesaler


42. diana Aug 29, 2010 at 18:30

this [url=http://www.auto-ok-erlangen.com]P90x extreme home fitness program[/url] can give you perfect shape and transform your life
this [url=http://www.rosetta-stone-shop.org]Rosetta Stone Spanish (Latin America)[/url]can improve yourself and highten your languages level
[url=http://www.itunes-gift-card.org]itunes gift card,itunes code[/url]


43. snow boots Aug 30, 2010 at 21:20

A generator is very much a personal preference, but I encourage everyone to try the existing ones out there or make your own as needed. For me copy & pasting the Rakefile content from an existing one is easy enough.


44. louis vuitton sunglasses Sep 01, 2010 at 21:21

Thanks for sharing your article. I really enjoyed it. I put a link to my site to here so other people can read it. My readers have about the same interets

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player
Give Back to Open Source