Cut & Polish: A Guide to Crafting Gems

29f82ebe1801087f04de6aaae92e19ea?s=47 Pat Allan
November 06, 2011

Cut & Polish: A Guide to Crafting Gems

Gems underpin almost every piece of Ruby code we write – and so, being able to write your own gems is not only incredibly useful, it provides an avenue for code reuse and open source sharing.

During this session, Pat will talk about the ecosystem around gems and the knowledge required to write your own gems. He’ll also cover some of the tools available to assist with this, along with ideal approaches and best practices for gem development.

29f82ebe1801087f04de6aaae92e19ea?s=128

Pat Allan

November 06, 2011
Tweet

Transcript

  1. Cut and Polish A Guide to Crafting Gems Good afternoon

    everyone - I hope you’re all ready to learn about how to write gems!
  2. Pat Allan @pat freelancing-gods.com My name’s Pat, yes, I’m from

    Australia as well - hopefully you can understand me through my accent. Here’s my twitter handle and blog, if you’re interested.
  3. “Use rubygems to publish your gem to rubygems” Now really,

    it’s pretty simple... you just use rubygems to publish your gem to rubygems. Oh wait, that’s almost recursive... let me try again.
  4. “Use rubygems to publish your gem to rubygems” Now really,

    it’s pretty simple... you just use rubygems to publish your gem to rubygems. Oh wait, that’s almost recursive... let me try again.
  5. “Use gem to publish your gem to rubygems” You use

    gem to publish your gem to rubygems. Wait, no, that isn’t quite clear either...
  6. “Use gem to publish your gem to rubygems” You use

    gem to publish your gem to rubygems. Wait, no, that isn’t quite clear either...
  7. “Use the gem command to publish your gem to rubygems.org”

    You use the gem command to publish your gem to rubygems.org. Okay, that’s a bit better, but it’s still not ideal... this isn’t looking quite so simple any more, is it. Let’s try to clarify things.
  8. noun a precious or semiprecious stone, esp. when cut and

    polished or engraved. |jem| gem First, what’s a gem? Well, this is the definition anyone who isn’t a developer would expect...
  9. noun a packaged code library written in the Ruby programming

    language. |jem| gem But we’re talking about bytes and electrons - so for us, a gem is library of Ruby code.
  10. noun a command line executable distributed with the RubyGems package

    manager. |jem| gem Of course, it’s *also* a command line tool installed as part of rubygems. And what’s rubygems?
  11. noun a package manager for Ruby libraries. |ˈro͞obējemz| rubygems Well,

    it’s essentially a package manager for gems.
  12. noun a website that stores published versions of Ruby gems.

    |ˈro͞obējemz| rubygems But it’s also the site that hosts all published versions of gems. If you get confused between these definitions during this talk, please let me know. I’ll try to be as clear as possible.
  13. Why? But first - why should we even care about

    creating gems?
  14. Why? re-use code Well, they let us re-use our own

    code easily between projects - and you can let others use them as well.
  15. Why? easy to install They’re also pretty easy to install

    - at least, in most cases.
  16. Why? easy to share And thanks to rubygems, they’re really

    easy to share! And shared code is happy code.
  17. History When did this all begin? Let’s run through a

    quick history lesson.
  18. History 2003 rubyforge.org rubyforge began in 2003 - before there

    was the concept of gems.
  19. History 2004 rubygems But that soon followed, the following year,

    with the release of the rubygems package manager for distributing gems.
  20. “If you have libraries you would like to include, please

    send the gem les to either myself or Rich Kilmer” Chad Fowler, 15 March 2004 Back then, though, the way to get a gem published was to email Chad or Rich - not ideal.
  21. History gems were magical And there was still some mystery

    about constructing gems.
  22. History permission was required Even when they moved beyond email

    to something a little more automated, you still needed permission to publish a new gem - though they weren’t too fussy about allowing people to do this.
  23. History 2009 gemcutter.org But two years ago, gemcutter hit the

    scene - initially as an alternative gem source.
  24. History anyone can publish It made publishing gems easy -

    a simple shell command - and anyone was allowed to publish gems.
  25. History rubygems.org And so it was adopted as the default

    gem source, and migrated to rubygems.org. And Rubyists rejoiced!
  26. Gemspecs That’s all well and good, but I’m supposed to

    be telling you about how to write gems - and every gem revolves around a gemspec.
  27. Gemspecs kyiv.gemspec Every gem has a gemspec - with the

    gem’s name. This file holds all the settings for your gem, and has a list of every file and dependency.
  28. # kyiv.gemspec Gem::Specification.new do |s| s.name = ‘kyiv’ s.version =

    ‘0.0.1’ s.authors = [‘Pat Allan’] s.email = [‘pat@kyiv.com’] s.homepage = ‘’ s.summary = ‘RubyC Kyiv Gem’ s.description = ‘’ s.files = [...] s.test_files = [...] s.executables = [...] end Here’s an example gemspec. There’s nothing too scary here, it’s standard Ruby, and we’re just going through setting some options.
  29. s.name = ‘kyiv’ Naming At the top we’ve got the

    name. You can call your gem whatever you like, but it must be unique. If someone else has already released a gem of the same name, bad luck, find something else to call yours.
  30. Naming # name ‘will_paginate’ # requiring require ‘will_paginate’ # Class/Module

    WillPaginate Also: keep it lowercase, and as a general rule, use underscores for word separation...
  31. Naming # name ‘cucumber-rails’ # requiring require ‘cucumber/rails’ # Class/Module

    Cucumber::Rails ... and hyphens for namespacing. These are not rules, just recommendations - I’ve failed to follow them in the past, as have many others.
  32. Versions s.version = ‘0.0.1’ Next is the version number of

    your gem.
  33. Versions s.version = ‘Major.Minor.Release’ You can choose any numbering system

    you like, but the vast majority of gems follow the standard Major/Minor/Release system.
  34. Versions Major Versions Major version numbers indicate major changes -

    if your gem changes its external behaviour or main class and method structure. If people upgrade, are they going to have to change their code that’s using your code? If the answer is definitely yes, that would warrant bumping up the major version number.
  35. Versions Minor Versions Minor version numbers are useful to indicate

    new features and minor changes to behaviour - things which are useful, but won’t require changes for existing usage.
  36. Versions Release Versions And finally the release number - you

    want to change this for bug fixes and very small changes.
  37. Versions Reference I would recommend separating the gem version out

    into a separate ruby file, so developers can check which version of your gem - within their code - they are using.
  38. Versions # lib/kyiv/version.rb module Kyiv VERSION = ‘0.0.1’ end Such

    a file would look something like this - with a constant containing our version number.
  39. Versions # kyiv.gemspec require ‘kyiv/version’ # ... s.version = Kyiv::VERSION

    And then the gemspec would look like this. Note that we’re only requiring the version file, not the entire library - we don’t want to load our entire gem just to determine the version number and generate our gemspec.
  40. Versions VERSION = ‘1.0.0.beta1’ Here’s an example of releasing a

    beta version of a gem - if your gem version has any alphabetical characters, then it’s considered a pre-release - whether that’s a beta, release candidate or something else. This means it won’t be installed by default, only when explicitly requested.
  41. Authors, Emails & Homepage s.authors = [‘Pat Allan’] s.email =

    [‘pat@kyiv.com’] s.homepage = ‘http:// github.com/pat/kyiv’ These settings are pretty self-explanatory - the gem authors’ names and email addresses. Both of these settings accept arrays, so you can list all of the authors. And you can also provide the home page for the gem - at the very least, put the Github repository here.
  42. Summary & Description s.summary = ‘RubyC Kyiv Gem’ s.description =

    ‘Extended detail’ The gemspec expects both a summary and description - and it complains if they’re the same. The summary should be a very short description of your gem - and the description should be much more detailed.
  43. Files s.files = [ ‘lib/kyiv.rb’, ‘lib/kyiv/version.rb’, ‘README.textile’, ‘LICENCE’ ] Now

    we get to the core of a gem - a listing of the relevant files. You want to have all files listed here that are required for the gem to work and be used - so, all ruby files, but also the README, LICENCE, and a HISTORY file if you have one too.
  44. Files lib/kyiv.rb All files that can be required should exist

    under the lib directory. You can put them elsewhere, but I’ve never seen a good reason to do that. So just put them in lib. And you want a file there that matches the name of your gem.
  45. Files Kyiv::Tourist lib/kyiv/tourist.rb Kyiv::Translator lib/kyiv/translator.rb All other relevant files should

    be placed within a gem’s project directory in lib, and namespaced accordingly - you want to avoid conflicts with any other gems.
  46. Files # Don’t do this lib/kyiv.rb lib/tourist.rb lib/translator.rb You don’t

    want to do anything like this - because what happens if there’s also a gem named ‘tourist’?
  47. Information Files README Always have a README file in your

    gem, with some information on how to install and use the gem. You can write it as a plain text file, or Textile or Markdown or RDoc - that’s up to you - but just make sure it’s there and helpful.
  48. Information Files LICENCE Don’t forget to have a file with

    your open source licence of choice, too. You’ll find most gems are released under MIT or BSD licences - very few opt for the GPL, which can make it harder for developers to use your gem.
  49. Information Files HISTORY This - or a change log -

    is optional, but recommended. It’s a great way for you and those who use your gem to see what’s changed in each release - and once your gem has been around a while, having that information becomes even more helpful.
  50. Test Files s.test_files = [ ‘spec/kyiv_spec.rb’, ‘spec/spec_helper.rb’ ] And of

    course you’re writing tests for your gem, right? You can list your test files in your gemspec as well - again, best to follow standard practices here and put them in test or spec directories.
  51. Test Files Beware Large Test Suites Now, if your gem’s

    test suite gets rather large - perhaps you’ve got a stack of fixture files - then it’s better not to include those files in your gem at all - otherwise you’re going to increase the gem size dramatically. That said, this is rare, so in most cases, include your tests.
  52. Test Files Travis CI I highly recommend using Travis CI

    for continuous integration - it allows you to easily test across different versions of Ruby, including JRuby and Rubinius.
  53. Executables s.executables = [ ‘bin/kyiv’ ] Not all gems will

    have executables, but some will - and you need to list them in your gemspec accordingly. They should live in the bin directory, and have executable permissions - and no file extension.
  54. Executables #!/usr/bin/env ruby require ‘kyiv’ Kyiv::CLI.run Here’s an example of

    what could go in an executable file - you’ve got your shebang at the top, and then the ruby code that handles the command line interface. I highly recommend keeping this file very small and putting all the logic in a class in your lib directory. This makes your gem code much easier to test, maintain and re-use.
  55. # kyiv.gemspec Gem::Specification.new do |s| s.name = ‘kyiv’ s.version =

    ‘0.0.1’ s.authors = [‘Pat Allan’] s.email = [‘pat@kyiv.com’] s.homepage = ‘’ s.summary = ‘RubyC Kyiv Gem’ s.description = ‘’ s.files = [...] s.test_files = [...] s.executables = [...] end So, going back to our gemspec, that’s our core settings all covered. There are others though - and the most important of these are our dependencies on other gems.
  56. Dependencies s.add_runtime_dependency ‘rails’, ‘>= 3.0.0’ Gemspecs have a distinction between

    runtime dependencies - things your gem needs when it is running and being used by others - and development dependencies, which are required to develop the gem. So, your gem may need Rails to work - so you’d add a line like this to your gemspec.
  57. Dependencies s.add_development_dependency ‘rspec’, ‘>= 2.6.0’ And given I’m using RSpec

    to test my gem, then I want to have it as a dependency as well - but only a development dependency. It doesn’t need to be installed for users of my gem.
  58. Dependencies Dependency Versions It can be a little tricky to

    determine which version you want your dependencies to require - you don’t want it too restrictive, but you also don’t want it to break in the future.
  59. Dependencies s.add_runtime_dependency ‘rails’, ‘~> 3.1’ This ensures any release of

    Rails that is equal to or greater than 3.1 can be used, but not Rails 4 - and going by our major/minor/release version number approach, this should hopefully be safe enough, because Rails shouldn’t go making any dramatic changes until 4.0. Of course, that’s not always true, but you can’t account for everything!
  60. Dependencies ~> I’m guessing most of you have seen this

    version constraint before - but does everyone understand what it means? I know this is a slight tangent, but just quickly - it’s known as the pessimistic version constraint.
  61. Dependencies ~> 3.1 == [>= 3.1 && < 4.0] ~>

    3.0.3 == [>= 3.0.3 && < 3.1] You can see here that how specific you are is taken into account - it allows for an increase in the last digit specified, but not any before that. Anyway, you can read more about that online - back to dependencies!
  62. Dependencies s.add_development_dependency ‘rspec’, ‘= 2.6.0’ It doesn’t hurt to be

    a bit more exact with your development dependencies - as this will allow other contributors to easily get a local copy set up.
  63. Rake Tasks To assist development of your gem, you’re probably

    going to have a Rakefile in the root of your project with some tasks defined.
  64. # run tests rake spec # generate documentation rake yard

    # default task should run tests rake These tasks may be for running tests and generating documentation - and perhaps helping with managing releases of the gem as well. It’s generally expected that the default task - which runs when you invoke rake with no argument - should run your entire test suite.
  65. Publishing So, you’ve got the first version of your gem

    ready to go, the tests are all green, and now it’s time to share it with the world! How do you do that?
  66. Publishing gem build kyiv.gemspec #=> kyiv-0.0.1.gem First things first: let’s

    generate the actual gem file - which is done by passing our gemspec into the ‘gem build’ command. This packages our gem together - into a file that includes the current version number.
  67. Gem Files .gem == .tar If you’re curious, a gem

    file is just a tar file - and inside that is a compressed copy of your code, and the metadata from the gemspec.
  68. Publishing gem push kyiv-0.0.1.gem Getting that gem file up onto

    rubygems.org is a single command - ‘gem push’. You’ll need to have signed up for an account on rubygems.org, and it’ll prompt you for your details once, and then remember them. But it really is just a matter of typing out that command, and that’ll upload the file!
  69. Publishing Permanent It’ll take a few seconds for that gem

    version to be available to everyone - but once it’s up there, that’s it. You can’t change an existing version of a gem - if you made a mistake, bad luck, fix things and release a new version.
  70. Publishing (Don’t) Yank However, if you’ve really screwed up -

    perhaps released some code that deletes files off of someone’s machine, or has an extremely serious security flaw - then you may want to yank it - which just means no one will be able to install that version of the gem any more. Yanking gems is only for emergencies - it’s unlikely you should ever need to do it.
  71. Publishing MRI 1.9 Caution For the most part, developing and

    deploying on Ruby 1.9 is a smooth experience - and I recommend it - but there can be issues with building gems, because of the different way YAML is parsed. So it’s best to use MRI 1.8 when building the gem at the moment - hopefully soon this won’t be the case.
  72. Community And once your gem is out there available for

    everyone to use, you may want to consider a few things...
  73. Community Support Firstly, if you do want others to use

    your gem, then you’re probably going to need to offer some support - whether that’s via GitHub issues, or a mailing list, or some other way.
  74. Community GitHub Speaking of GitHub, keep an eye out for

    pull requests - and encourage others to contribute. Perhaps have some guidelines on this in your README. Don’t be afraid to curate the patches, as well - accept ones you like, and provide feedback on ones you don’t want to merge in immediately. Be honest but friendly.
  75. Community Releases And as your gem evolves, you can release

    new versions. It’s up to you on how often this happens - but try not to go overboard, and try not to break things.
  76. Bundler Now, you may want to use Bundler locally to

    outline the gems you’re using to develop your gem.
  77. Bundler Recommended I certainly recommend this - Bundler is certainly

    a great way of managing dependencies for any Ruby project.
  78. Bundler Not Required That said, it’s not required - you

    can manage these things however you like. Bundler, after all, is a development tool - it will not have any impact on how people use your gem.
  79. Bundler # Gemfile source :rubygems gemspec There’s no need to

    double up on gem dependency lists though - given we’re documenting that in our gemspec, Bundler can look at that instead - here’s a Gemfile example.
  80. Bundler # Gemfile gemspec gem ‘mysql2’, :platform => :ruby gem

    ‘jdbc-mysql’, :platform => :jruby Sometimes, though, it’s necessary to be more specific than a gemspec allows - at least, for development dependencies. One example is different libraries for different rubies. If you’re doing this, then best to not list your development dependencies in the gemspec - after all, if anyone’s modifying your gem source, they’ll be using Bundler too.
  81. Bundler rake release One last thing to note about Bundler

    is that it can provide a few helper rake tasks - the most useful of these being release, which builds and pushes a new gem version and tags the release in your git repo and pushes that tag to Github. It’s the tagging that’s particularly useful - the rest is easy enough to do manually.
  82. Bundler # Rakefile Bundler::GemHelper. install_tasks To get those rake tasks,

    just add this line to your Rakefile.
  83. Tools Of course, Bundler’s not the only tool around to

    help you manage and develop gems.
  84. Tools Hoe Hoe has been around for years, and provides

    plugins to manage releasing your gem, as well as testing and documentation and I’m sure a few other bits and pieces as well.
  85. Tools newgem newgem has also been around a while, and

    is built on top of hoe. It can even generate a website for your gem if you wish.
  86. Tools Jeweler Jeweler’s not quite as heavy as either hoe

    or newgem - it just provides a generator for creating the essential gem project files, and some rake tasks to help manage releases. But you don’t need to use any of these - I recommend starting with a vanilla gemspec and see how far you can get.
  87. Examples And examples of gemspecs - and gems - are

    everywhere. Look at the gems you’ve installed on your computer, or at code on Github. Don’t be afraid to read other peoples’ code - it’ll make you a better developer, whether or not you’re writing gems.
  88. Examples bundle open kyiv A quick way to view gems

    is to use the `bundle open` command, which can open up any gem in your bundle in your preferred text editor.
  89. Thank You Questions? Anyway, I think that’s enough from me

    - you can all start writing your own gems now! Does anyone have any questions?