RailsConf 2013

A Guide to Crafting Gems

A Guide to Crafting Gems

by Pat Allen

The video titled "Crafting Gems" features Pat Allen speaking at Rails Conf 2013 about the process of creating Ruby gems, which are essential for code reuse and the open-source community in Ruby and Rails development.

Key Points Discussed:
- Introduction to Ruby Gems:

- Definition: A gem is a packaged library of Ruby code and a command line executable distributed via the RubyGems package manager.
- Purpose: Gems facilitate code reusability across different projects, helping developers avoid code duplication.

  • Historical Context:

    • Overview of the evolution of Ruby gems, starting from rubyforge.org in 2003 to the establishment of rubygems.org, which simplified the process of creating and sharing gems.
  • Constructing a Gem:

    • Central to a gem is its gemspec, which is a Ruby file that describes the gem's name, versioning, dependencies, authorship, and other metadata.
    • There are guidelines for naming gems, detailing how to format name and version numbers appropriately.
    • Inclusion of essential files such as a README, LICENSE, and CHANGELOG to enhance usability and accessibility for users.
  • Dependency Management:

    • How to specify runtime and development dependencies in the gemspec, emphasizing the importance of using version constraints effectively to ensure compatibility.
  • Testing and Publishing:

    • Recommended practices for testing gems and integrating them with Rails applications.
    • Simple commands for building and publishing a gem, with best practices on version control and handling bug fixes post-release.
  • Community and Support:

    • The importance of providing user support and being responsive to contributions from the community to foster usage and improvement of the gem.

Main Takeaways:
- Building Ruby gems is straightforward, centered around writing simple Ruby code and managing a gemspec.

- Proper version management and dependency specification are crucial to maintainability.

- Engaging with the community through support and enhancements plays a significant role in the lifecycle of a gem.

- With the right tools and practices, creating and sharing gems can significantly improve a developer's workflow and efficiency in Ruby and Rails development.

00:00:16.400 All right then, good afternoon, everyone. In case you missed it, my name's Pat.
00:00:23.279 That's me on Twitter, but don't go looking me up because we've already heard how bad the internet is. That's also my blog.
00:00:30.080 And yes, if you hadn't guessed by the accent, I am from Australia. It was not a short trip to get here.
00:00:36.719 One more thing: I'm sorry, we did change our experiments with the network.
00:00:42.320 It's not on Ales anymore; it's called Jumpstart Lab, and you can give it a try.
00:00:48.960 You should get more or less the same results we had this morning. Cool!
00:00:55.039 Yes, I traveled a long way to be here. Unfortunately, I took the long way around.
00:01:01.120 So if you catch me just staring off into space and not really focusing on what others may be saying to me, it's just the jet lag.
00:01:06.240 You're welcome to just, you know, punch me in the arm to wake me up. But hopefully, I'll be cogent for at least this talk.
00:01:11.520 Now, I just made the point on Twitter yesterday that there are a lot of people here, and I think we all think Ruby is pretty cool.
00:01:24.080 We may not know a lot of other people, so this is just an open invitation to say hi to those around you.
00:01:38.240 If you see me around the conference over the next day or so, you're very welcome to come up, introduce yourself, and tell me what you do. I'd love to have a chat.
00:01:50.079 Now, building Ruby gems... Look, this is going to take five minutes. We're going to be through this so quickly that you can all go grab a coffee.
00:02:00.960 All you need to do is just use the Ruby gem command to publish your gem to RubyGems.
00:02:07.360 All right, well, maybe that's a little recursive. Let me try this again: you just use the `gem` command to publish your gem to RubyGems.org.
00:02:21.520 That's perhaps a little clearer. Or at least, I'm not using the exact same term more than once.
00:02:35.120 But I understand that it can get a little confusing using some of these words again and again in different contexts.
00:02:46.800 So, I've got a couple of definitions here. A gem, for anybody outside of this conference, is a packaged library of code written in Ruby.
00:02:52.959 It's also a command line executable that is distributed with the RubyGems package manager.
00:03:06.239 The RubyGems package manager is one definition of RubyGems, but there's also the website that stores all these published versions of our gems.
00:03:17.920 Hopefully, as I go through this talk, it will be obvious when I'm using these terms which one I'm referring to.
00:03:29.200 If it's not, please put up your hand, yell at me, heckle me—let's figure it out as we go along.
00:03:38.400 I'm guessing everyone in this room has some idea of why they want to create Ruby gems, but just in case they don't... Writing a gem is a great way to reuse your own code.
00:03:51.120 You could be writing something in one Rails app and think, 'Oh, that'd be really useful in this app too!' You don't want to duplicate things.
00:04:03.680 If you realize there's a bug, you've got to change all your different apps in exactly the same way.
00:04:10.080 So writing it as a gem—or extracting it out into a gem later on—gives you a much easier way to manage changes and keep everything under control.
00:04:22.079 They're also pretty easy to install, at least when the Wi-Fi works, and they're quite easy to share as well.
00:04:30.639 This means that not only do you get to benefit from your gems, but others can benefit from them as well.
00:04:38.160 While it was really easy to create gems now, it wasn't so easy a while ago.
00:04:43.440 Let me just run you through how this has all come to be: in 2003, the website RubyForge.org was launched. At that point, there was no concept of gems; it was just a place to put your code, and people had to figure out how to install it manually.
00:05:11.919 It was a step forward, but we were after something a little better. A year later, RubyGems, the package manager, was created, and this is where gems as a concept came into being. It hooked into RubyForge, and you could package your gem there, allowing others to download it using `gem install`.
00:05:41.680 This was great, except that if you were writing gems, you had to actually email the source code to Rich or Chad—maybe not quite as streamlined as we were hoping. Because of all this, the process of creating gems felt a little magical.
00:06:12.960 It wasn't immediately obvious, and there wasn't much documentation on how to do it. When you were creating your gem project, you had to register that on RubyForge, and there was a manual approval process, which could take 24 hours or longer.
00:06:43.680 Nick Quaranto, who works at 37 Signals and is around at this conference, created a project called GemCutter in 2009. GemCutter was a much simpler, cleaner, and faster way of creating and sharing gems.
00:07:07.919 Anyone could publish a gem by just signing up, and away you went—no manual interaction required. It became so loved that it became RubyGems.org, our default gem source, and everyone rejoiced.
00:07:40.800 The thing to know about how to build a gem is that it's all just basic Ruby code. There are tools out there which abstract some of that away for you, but there isn't really that much to abstract, so I'm going to talk about doing it just using Ruby.
00:07:52.560 Then you will all understand how to do that, and if you want to use those tools later on, feel free. A gem fundamentally depends on its gem specification, or gem spec.
00:08:19.280 A gem spec is just a piece of Ruby code. You would name it something like `gem_name.gemspec` in your project directory, and this is roughly what it would look like—it’s a very simple gem spec.
00:08:39.920 Each gem has to have a unique name. If someone else has already come up with a gem with the same name, then you're out of luck—you'll have to think of something else.
00:08:50.720 There aren't strict rules for naming gems, but there are some guidelines. An underscore in a name indicates separation between words so it stays the same when you require that gem, and each word gets its first letter capitalized when you refer to it as a constant within your gem.
00:09:13.360 If it's a hyphen, though, that's generally used for namespacing the gem. For example, in the case of Cucumber Rails, it relates to Cucumber and is a subclass of the Rails-specific code.
00:09:29.680 When requiring with a hyphen, it usually becomes a slash, and as a constant, it has a double colon named spacing.
00:09:42.160 These aren't strict rules—I have personally failed to follow them when naming some of my gems. But hopefully, you won't make the same mistakes I did.
00:09:54.560 The gem version is straightforward—almost every gem follows the major.minor.release format when it comes to versions.
00:10:10.560 The major number should change only if your gem has changed so dramatically that it affects the way people use it. Your changes have to be significant enough that it's going to create a bit of work for the users.
00:10:25.760 The minor version number should be incremented when you've added new features that won't break existing features, and the release version number should be bumped when there are small features or bug fixes.
00:10:42.080 Sometimes, certain gem tools allow you to reference your version number somewhere else in your gem code, as opposed to your gem spec. It's often better to put it in a separate file in your gem and ensure that you don't end up with circular dependencies.
00:11:01.839 This has the advantage of allowing people to check what version they're using of your gem, but usually, you won't need this level of detail.
00:11:11.760 Most gems aren't so dominant that you need to write code that changes your app's behavior based on which version of a gem you're using.
00:11:22.320 If you want to release a beta version or pre-release version, RubyGems just treats them all under the heading of pre-release.
00:11:33.440 You just need to add something that isn’t a number or a period in your version. It doesn't have to be the word beta or rc, it can be anything as long as it's letters.
00:11:48.560 This means that people can upgrade to your beta versions if they want to, but those who wish to stick to standard releases do not need to worry.
00:12:03.520 Authors' email addresses and home pages are quite obvious—be sure to fill each of them out.
00:12:08.320 You don't have to have a fancy site dedicated to your gem; a simple GitHub URL will suffice, giving people somewhere to go for more information.
00:12:17.440 Summary and description are not quite the same thing in the case of a Ruby gem. The summary should just be a few words long—a short, clear description of what your gem does.
00:12:37.760 The description, on the other hand, can be as long as you like, really—you could write several paragraphs if you're that keen. But a sentence or two explaining what your gem does at a high level is often enough.
00:12:57.040 In the past, if you put these two as the exact same string, RubyGems would actually complain, preferring that these settings remain different.
00:13:06.240 The files section lists the files that make up your Ruby gem—this is where your gem's logic resides.
00:13:12.320 You'll usually put all your code under the `lib` directory within your project. You can customize the section name, but it's not recommended.
00:13:25.760 Every gem I've ever seen puts everything under `lib`, and I think that's fine—it's just a principle of least surprise.
00:13:44.600 If you have other files within your gem, namespace them under a directory with your gem's name. This is because the lib directory in every gem is added to Ruby's load path.
00:14:03.200 If you don't namespace properly and somebody else has named a gem the same as yours, you could run into issues.
00:14:18.000 You definitely want a README file, which can be in plain text, Markdown, or Textile. GitHub does a nice job of auto-parsing these files.
00:14:25.600 This is a great place to inform people about how to install your gem, how to use it, and details about contributions.
00:14:39.200 There should also be a license file included. You can put in any license you like, but most gems are released under an MIT or BSD license.
00:14:52.000 This enables anyone to use it anywhere. If you want to release it under a new license, I find that a bit annoying personally, but it's your choice.
00:15:07.679 You may also want to include a history file or a changelog to track what's changed over time, especially as your gem grows.
00:15:21.760 These files can be particularly useful when gems are larger and have been around for a while—to track when changes were made.
00:15:36.320 If your gem is small, you might not need this, but it's good to evaluate as you go along.
00:15:49.840 Test files should also be included—any test that you've written for your gem should go in the test files list.
00:16:02.880 You usually want to put your entire test suite, except if you've got large files, which should almost never be the case.
00:16:19.520 Once you've written your tests, you can put your gem on Travis, and every time you make changes, Travis can run tests for you.
00:16:32.320 Some gems have executable files that you run from the command line. Rails has one of these, and many other gems do, too.
00:16:52.000 You would list this in your gem specification, putting all the files under the `bin` directory.
00:17:00.400 Again, this is just what everyone else does, so it's best to stick to it. You shouldn't add a file extension to these executable files.
00:17:15.760 You don't need a file extension like `.rb`—we don't always type `rails.rb new project name`; we just type `rails`.
00:17:28.160 Executable files should tell it to evaluate using Ruby, require your gem, and call something to run the executable's logic.
00:17:49.120 Don't put all your logic in this file, as it makes testing harder. Keep that in classes and modules, write tests for those, and keep your executable files small.
00:18:07.840 Most of the settings in a gem spec are straightforward. I hope you haven't found any of that too scary.
00:18:27.680 Sometimes our gems rely on other gems, and we need to specify that. You can specify runtime dependencies for something your gem needs to work.
00:18:45.680 You can specify development dependencies for things that are useful when you're developing your gem—this gem doesn't need Aspect to work, but you need it to run the tests.
00:19:06.960 With each of these dependencies, you can specify a version, and that's where things can get a little tricky. The symbol here has several names—the pessimistic version constraint is a lengthy name but specific.
00:19:50.640 It means my gem needs that gem, but it might not always work with the latest version. For practical purposes, the last number specified can go up.
00:20:13.280 This is a way of saying you can allow some flexibility, but not too much. Development dependencies are up to you because you may be the only person dealing with this.
00:20:25.680 When writing your gem, you may want to run Rake tasks for testing or generating documentation. You just put these task definitions in a Rakefile in the base of your project.
00:20:41.040 I'd recommend setting the default task to run your tests when you call Rake without arguments.
00:20:51.840 If your gem has Rake tasks you want available within the context of Rails, you'll want to define a Railtie. Here's an example: we're defining our Railtie as a class that subclasses Rails' Railtie.
00:21:07.280 If you're writing gems that have controllers, views, routes, and migrations, then you are really talking about an engine—that's like a Railtie, but with even more features.
00:21:31.520 You define an engine similarly, and anything in your gem that resides under standard Rails paths will be picked up automatically.
00:21:51.680 Let’s discuss configuring your gem, testing your gem, and integrating it with other libraries. Now it's time to publish it, which has become so simple in the last few years.
00:22:18.640 All you need to do is run two commands: first build your gem file using `gem build` followed by the gem spec.
00:22:34.080 This generates a file using your gem name and current version with a `.gem` extension that contains everything specified in the gem spec, including code and test files.
00:23:00.120 Now that we've built our gem file, we can publish it by running `gem push` and specifying the path to the generated gem file.
00:23:17.760 This will prompt you for your username and password on RubyGems.org the first time you run it. After that, it remembers your details, and future publishing will be smooth.
00:23:55.680 However, once you've published a version of a gem, it's permanent; you cannot edit a published version. RubyGems will not allow you to do this for good reason.
00:24:15.679 One person shouldn't have version 1.0 while another has a different version because it leads to confusion.
00:24:35.680 If you find bugs, just release another version—that's the purpose of versioning. You can remove existing versions using the yank command, but that should only be done for catastrophic issues.
00:24:55.280 I'm telling you this just so you're aware of it, but most bugs probably aren’t that severe. Just leave your gem out there and release another version.
00:25:22.080 In the past, there were issues with people still using Ruby 1.8; if you published a gem using 1.9, version errors occurred for those still on 1.8.
00:25:41.440 If you are still publishing gems that need to run on 1.8, consider using `gem push` and `gem build` on 1.8 for compatibility.
00:26:02.320 Once it's deployed, people can install it, and you might find yourself with a community surrounding your gem or trying to push it out.
00:26:26.560 If you want people to use your gem, make it easy for them to get started and be responsive to their questions.
00:26:40.480 Whether you set up a Google group, track Stack Overflow, or use GitHub Issues, it's up to you; GitHub is particularly helpful for contributions.
00:27:02.560 Be attentive to any pull requests, accept the ones you like, and be polite about any rejections.
00:27:15.680 It's no requirement to accept every contribution, but be honest yet friendly in your communication.
00:27:30.560 There's no golden rule about how often to release updates to your gem.
00:27:42.480 If you have several bug fixes piling up and haven’t released a new version, it’s probably time to publish something.
00:27:55.280 Now that’s the core idea—it’s all about the Ruby commands and your gem code. You now know how to do it from scratch.
00:28:14.080 Unless you walked in late, in which case I apologize, but there are tools out there that make things a little easier.
00:28:27.440 I don’t get too carried away with them, but they can be helpful. One I do use is Bundler—it can generate the initial directory structure for your gem.
00:28:44.320 I think the command is `bundle gem` followed by the gem name—it’s quite helpful, so I recommend it.
00:29:00.080 If you’re using Bundler, you’ll also want a Gemfile to capture your dependencies clearly.
00:29:20.080 You don’t need to specify everything—just put the gem spec line in, and Bundler understands you've already set dependencies.
00:29:41.120 This is particularly useful if you're building gems requiring different libraries depending on the Ruby version, such as JDBC for JRuby.
00:30:00.480 The one thing I really use from Bundler in gem development is the `rake release` task—it builds a new version of your gem, publishes it, and creates a git tag.
00:30:19.440 You can add this line to your Rakefile, and it simplifies the process for you.
00:30:36.640 There are other tools out there if you wish to explore them. Hoe has been around for a long time, but I find it does a lot more than I need.
00:30:48.760 Jeweler is a bit slimmer and can generate directory structures for your gems. You may want to try it out, but you can do everything in plain Ruby.
00:31:04.480 If you need examples, every gem you’ve ever installed is on your machine, so you can look at the source code.
00:31:21.840 The specs are all there. If you're in a Rails project, you can use the command `bundle open gem_name` to look at the gem's source code.
00:31:35.760 There’s even a gem called `gem open`—install it, and you can do `gem open gem_name` to see its code.
00:31:53.280 If you've seen something work in another gem and want to do the same, you can look at their implementation.
00:32:10.880 That's the first half of this discussion and workshop. That's the talk we will have.
00:32:27.920 Now, if people want to work through building a gem themselves, I've got some instructions here. The URL is up on the screen; hopefully, the internet works.
00:32:51.440 If it's not working, I have all the gems you need packaged up in a zip file, or I can find them on my machine to share with you.
00:33:08.080 Feel free to grab a drink or go to the bathroom and come back to follow the tutorial on the website at your own pace.
00:33:29.680 If you have questions as you go, I’ll be here, and you can ask me anything. Cool, thanks everyone!