AVDI:
Have you tried just having a cat catcher on your desk?
[Hosting and bandwidth provided by The Blue Box Group. Check them out at BlueBox.net.]
[This podcast is sponsored by New Relic. To track and optimize your application performance, go to RubyRogues.com/NewRelic.]
CHUCK:
Hey everybody, and welcome to Episode 103 of the Ruby Rogues podcast. Does that bother you, Josh? Or should I say a hundred and three?
JOSH:
As long as it’s a cardinal instead of an ordinal, I'm fine.
CHUCK:
Okay. [Laughter]
CHUCK:
We can't even get started. Alright. This week on our panel, we have Josh Susser.
JOSH:
Hey, good morning everyone from your unreasonably pathetic…never mind! [Laughter]
CHUCK:
We also have James Edward Gray.
JAMES:
Good morning, everyone.
CHUCK:
Avid Grimm.
AVDI:
Hello from Pennsylvania.
CHUCK:
David Brady.
DAVID:
We control the vertical and the horizontal which makes no freaking sense on a podcast.
CHUCK:
And I’m Charles Max Wood from DevChat.tv. And this week, we’re going to be talking about Ruby Gems.
JAMES:
Woohoo!
JOSH:
It’s going to be that kind of episode.
CHUCK:
So Josh, can we get a definition?
JOSH:
Oh, yeah…no.
[Laughter]
JOSH:
If you don’t know what a Ruby Gem is, I'm sorry we can't help you.
CHUCK:
[Laughs]
JAMES:
What was the old competitor, the RPA? Was it RPA?
AVDI:
Oh, man!
DAVID:
Oh! Was it RPA, the Ruby Project Archive? [Crosstalk]
DAVID:
…after Gems was up. But that was back when you actually had to ask Dave for permission to create a gem. You actually…
JOSH:
Okay. Let’s not get lost in the weeds here.
DAVID:
Yeah.
AVDI:
RAA is the one.
JAMES:
Not RAA. Not that.
JOSH:
Okay. So, Ruby Gems are the best software packaging system in the universe. That’s the definition.
CHUCK:
Yehey! [Laughter]
DAVID:
Open keyboard.
JAMES:
Well, there what we got. That’s what you mean. [Laughter]
DAVID:
Okay, that’s fair. That’s fair. They're also the worst. [Laughter]
JAMES:
Overall, I like them.
AVDI:
They are way better than what came before.
CHUCK:
What came before?
JAMES:
Yeah.
JOSH:
Okay. So, the point of this conversation, the point of this episode is bunches of people build Ruby gems to distribute their software to other Ruby developers. And many of those people know what they're doing, bet if you don’t. [Chuckles] And many people would like to know what they're doing.
So, that’s what this is about.
AVDI:
Just to be clear, we’re talking more about like the nuts and bolts of constructing a gem today rather than like how you structure your code that you distribute it by gem.
JOSH:
I think everything’s for a game. [Laughter]
AVDI:
Alrighty!
CHUCK:
If we’re talking about nuts and bolts, I swear I've used some gems where by the time I'm done putting them together, I have extra screws.
[Laughter]
JOSH:
I just use gray tape.
CHUCK:
[Chuckles] Oh, there we go.
JAMES:
Alright. So, question number one, should you build a gem?
AVDI:
Yes.
CHUCK:
Yes.
DAVID:
Maybe.
CHUCK:
[Inaudible] or gem?
JOSH:
Well, what are they good for?
JAMES:
What are these things?
DAVID:
Ab-so-lute-ly nothin’.
[Laughter]
CHUCK:
I was waiting for that.
[Laughter]
JOSH:
This isn't Java. We’re not building war files.
[Laughter]
JOSH:
Oh, it’s going to be that kind of episode.
CHUCK:
It totally is.
DAVID:
War files, what are they good for? Seven second start up, HUH! [Laughter]
JOSH:
Okay. So, I've seen Ruby Gems used to distribute some interesting kinds of software. So, everybody’s seen Ruby Gems used to distribute just like a library. You have a one class, you put up in a Ruby gem, you send it out and then people can use it. But I've also seen people distribute whole Rails applications as Ruby Gems.
JAMES:
Wow!
JOSH:
Or engines.
CHUCK:
I was going to say engines like Spooky or Refinery.
AVDI:
Or command line applications that maybe the user doesn’t care anything about Ruby but it’s a convenient way to ship them.
JAMES:
Yeah. There was something with an old version in Mac OS X where you had to do this like one or two weird steps in order to get something working. I don’t even remember what it was now. And somebody just bundled up a gem and you just install the gem and run this one command and that fixed the thing for you. It is interesting.
AVDI:
One weird trick to make your Mac work? [Crosstalk]
DAVID:
There are programs in Mac using one weird little trick. [Laughter]
JOSH:
The other thing is Ruby gem to basically install a native package.
CHUCK:
Yeah. I was going to say there's a Ruby gem out there to install leviate which is a JavaScript runtime.
JOSH:
Yeah.
JAMES:
Interesting.
JOSH:
Or like database drivers.
DAVID:
So, is Ruby gems encroaching on Homebrew? [Laughter]
JOSH:
I've actually seen stuff shifting from Ruby Gems to Homebrew recently like Vagrant.
JAMES:
Yeah, Vagrant is a good example.
JOSH:
I think they both are good for different particular things. There are some overlap.
JAMES:
Yeah, that’s a good point. What is a Ruby gem ideal for?
CHUCK:
Ruby?
[Laughter]
JOSH:
Go!
JAMES:
That covers it folks. Thanks!
DAVID:
Well, if you're a Linux, it’s a vast improvement over Homebrew. [Laughter]
JOSH:
I think I need a beer. [Laughter]
JOSH:
Okay. So, distributing Ruby software, that part’s pretty easy. And then, we have the native extensions, we have applications engines. I've only seen applications done as a Ruby gem very frequently. I think somebody had like the typo blog could be installed as a Ruby gem way once upon a time. But that may have just been an experiment. I seem to remember it, Toby Whitkey doing that.
JAMES:
Thinking at a different angle on the question, David had a great example on the pre-show of things that should not be made into a gem. Do you want to tell us about that, David?
DAVID:
Yeah. If it’s in the standard library, think real hard before making a Ruby gem for it. So, I can't take credit for this. I have to give a shout out to Daniel Huckstep. He’s one of our listeners. His Twitter handle is @darkhelmetlive. He spoke at Mount West Ruby Conf a couple of weeks ago and his whole talk was about the Ruby Standard Library. And he pointed out that there are like 15 gems for parsing command line options. I use one, it’s called trollop. I love trollop. It’s just so much better than trying to parse the argument list by hand. It turns out that Ruby has getoptlong in the standard library. It also has options parser which is an objet-oriented event based. So, you’ve got basically like the Unix style options processing, very robust, everything you need -- well, 80% of everything you need. And then, options parser which is this event based, it will generate your usage page for you just like trollop did. That was the killer feature for me. And I just suddenly realized, there's so many things that we do with gems that you don’t need to write a gem for it. Just crack open the back half of the Pickaxe book and start reading.
AVDI:
Yeah. I use optparse like 90% of the time. It’s rare that I want a feature that’s in some option parsing gem that isn't in optparse.
JAMES:
Yeah.
DAVID:
When you say ‘optparse’, are you saying that’s different from the actual option parser in the…
AVDI:
No, no, no. The library…
JAMES:
It’s what you require.
AVDI:
Yeah. The file you require is optparse.
DAVID:
Okay. But that gives you the OptionParser class, right?
AVDI:
Yeah.
JAMES:
Yes.
DAVID:
Okay. Gotcha!
JAMES:
Which, by the way, kind of brings us to a point naming things because naming is terrible, right? [Chuckles]
AVDI:
Okay. Here’s a question about naming.
CHUCK:
Don’t use underscores!
[Expression]
CHUCK:
Hulk smash!
AVDI:
Okay. Let’s say there's more than one word in your gem, like at the top of my head, I'm working on a gem called gem-love which I know is a little recursive.
CHUCK:
[Laughs]
AVDI:
But anyway, the name of it is gem-love. And that’s two words. First of all, should I use a dash or an underscore in the file name that is required? But then, do I use the same convention for listing it, for generating the name of the Ruby gem that you'll see when you put it in your Gemspec or your Bundler file, or when you just gem install it? Do I use the same convention there? I've seen a lot of gems where it was like gem-love, when you do a gem install, but then you require gem_love. And it almost seems like that’s kind of the best practice except that seems horrible.
CHUCK:
It’s horrible.
AVDI:
I'm actually kind of confused now.
JOSH:
Chuck, what is your problem with underscores?
CHUCK:
Okay. The real problem that I have really comes down to the consistency thing.
DAVID:
His shift key is broken.
CHUCK:
[Laughs]
AVDI:
I freaking hate underscores.
CHUCK:
So, the thing is I think most gems, if they separate them by a dash or an underscore, use a dash.
And so, I just wish they all would just for consistency.
JOSH:
[Expression]
CHUCK:
My major issue is what Avdi pointed out where the gem name is dash and the require is underscore, vice versa, because then I remember that they're different but I can never remember which way it is. And that makes me crazy. I mean, if it’s the same one way or the other, then I can just, in my head, remember, okay, Factory Girl is factory_girl. And Factory Girl Rails is factory_girl_rails. And I know that the library is the same. So, when I require it, I'm just requiring the same name. And then, I'm sort of okay with it even though it has underscores in it.
JAMES:
So, I'm going to get all Eric Hodel on you guys.
DAVID:
Uh-oh.
JAMES:
He has a blog post called ‘How to Name Gems’. And his word is bolded, strong recommendation on how to name gems. But actually, I think it’s got some great points and I’ll link to it in the show notes. But basically, his points are use underscores most of the time to basically match what the require statement would be, which I think is totally reasonable. It always makes me mad when I install some gem and have to change what's required. It’s also a pain in the butt for things like Bundler because then, you have to do ‘gem<gemname>,require:’ whatever you're supposed to require. So, his ‘use underscore’ idea is good. And then, we see some gems that use dashes. Eric recommends using those for things that are extensions. So like, you have autotest but then you have autotest-growl which just adds growl support to autotest.
JOSH:
Yeah, and all those things that extend rack.
JAMES:
Right, right, extend rack. So then, he recommends dashes there. And then, his other point is don’t use uppercase letters, stay lowercase because there are some case insensitive file systems out there. So, that can matter.
JOSH:
That’s good.
AVDI:
That’s good but I have one little objection. You're doing an extension. So, let’s say it’s net http foo bar. The extension name has two words in it. By these rules, it would be net-http-foo_bar which would make me crazy. [Laughter]
JOSH:
Then, we’ll just have to live with you being crazy.
JAMES:
Hang on, guys, one second. I'm making a new gem, I’ll be done. [Laughter]
DAVID:
So, there's actually two more things about the naming here that are actually -- one is slightly humorous which is that because of this, I actually try to stay away from names that have more than one word. I literally design around this fud puddle, I guess, of hyphens or underscores just by only using one word. And so, Avdi, I would have recommend that you rename your gem to ‘glove’. [Laughter]
DAVID:
However, there is a cultural thing in the Ruby community that you must give your name just a weird ass freaking name that is surprising but inevitable. It’s like, before you hear the gem name, you should have no idea how to intuit the name of the gem. No way to predict it. But once you hear it, it should make sense. It’s the opposite of intuitive. So, your gem name Sir, Isotoner. [Laughter]
JOSH:
So, this is like the opposite of that Simpson’s episode where they did the Be Sharps group and Principal Skinner says they need a name for the group that sounds funny at first but less funny the more you think about it. [Laughter]
CHUCK:
Oh, man!
JAMES:
It is a fair point, right? And a lot of languages, you have your extensions or whatever, your libraries being called something like XML::Parser, or whatever where it’s very self-destructive. In Ruby, we don’t like that. We like the creative, Nokogiri means chainsaw in Japanese name.
JOSH:
Yeah. So James, I have a great example of this. I did this gem that I named ‘Refraction’ which was a piece of Rack middleware for doing a replacement for mod_rewrite. And I thought, “Okay, great.” It’s part of Rack and it’s rewriting things and it’s also sort of like changing the direction that something’s going which is kind of like what refraction is. So, it had like pieces of all of those in there. Rack is part of the word ‘refraction’. And I thought, “Oh, this is a great name for it.” And then John Trupiano comes out with Rack::Rewrite. And everyone assumed that that was the official thing that should be used because it had the word ‘rack’ in the name. [Laughter]
JAMES:
It’s an interesting point. I mean, I am a little bit sad that our names are not so obvious at times. But at the same time, I kind of like our naming flair. It’s fun and we do have this corny names and we use them. And sometimes, it’s just downright pragmatic. For example, the postgres adaptor library is not called PostgreSQL, thank God! It’s called PG. Even the class is PG.
DAVID:
Yeah.
JOSH:
But then you got crazy stuff like Active Record. The Active_Record library has the underscore. The ActiveRecord gem doesn’t have any separation between the words. There’s no underscore, nothing.
JAMES:
Correct.
JOSH:
That’s one of the more annoying things, I think. Okay. So, I think that’s enough about names. Oh, one last thing. Avdi, if you scroll down through Eric Hodel’s blog post, the second comment addresses your issue about underscores and dashes in the same…
JAMES:
Yeah. But he is not going to like that answer. Don’t make him angry.
JOSH:
Yeah. [Chuckles] It is going to make you crazy.
AVDI:
[Expression] That’s horrible. Okay. The only thing more horrible than writing an identifier that has both underscores and dashes in it, is when people do camel case with underscores.
JAMES:
Wow!
JOSH:
[Laughs]
JAMES:
Ouch!
CHUCK:
Oh, geez!
DAVID:
I'm going to build a gem with camel case, hyphens, underscores, and a freaking tilde. [Laughter]
JOSH:
Okay. So, we now have the be all and end all of naming, moving right along.
AVDI:
Yes.
[Laughs]
JAMES:
Okay, so…
JOSH:
So, now that we know we want to build a gem and we have a good name for it that won't make Avdi crazy, what's the next step?
JAMES:
Well, how about Avdi brought up there are certain ways we organize our files than the standard?
JOSH:
Yeah, I think that’s a great thing to talk about. Do we want to start talking about tools because -- is there a tool for like generating a template for a gem project?
JAMES:
There's multiple tools.
DAVID:
[Expression] You talked about -- so, you did a votes.io on this.
JOSH:
Okay. So, that was something completely different. Well, somewhat different. [Chuckles] It’s all about gems. I did a little online poll about what tools people use to maintain their gemspec file because there's a lot of stuff around that. And we can talk about that in a few minutes. I didn’t do anything about templating the layout of your directory and all that.
DAVID:
The whole gem thing. Well, so I'm calling forward to that because I used Bundler to generate the gemspec but I used Bundler to generate the whole gem tree.
JAMES:
Yes. Bundler will generate the project rail.
DAVID:
My ‘aha’ moment was the realization that your poll limited it to gemspec, so I didn’t even think of Bones. I don’t think anybody’s using Bones anymore but Bones used to be fantastic for this.
JAMES:
And there's hoe and jeweler. Hoe being H-O-E, by the way.
DAVID:
Yeah.
JAMES:
Like a rake, but a hoe.
JOSH:
Okay. DAVID: And moving on.
JOSH:
[Chuckles] I'm sorry. I had like a flashback to Jeopardy. But you know the joke about rakes and hoes on Jeopardy? I’ll let you Google that one.
CHUCK:
[Laughs]
DAVID:
Everybody had to reprogram Watson and remove all the urban dictionary references from it.
JOSH:
[Laughs] That too.
DAVID:
Okay.
JOSH:
So, what is a good layout for a gem?
JAMES:
There are certain standards that if you follow, the Ruby Gems system knows what you're intending. So, the lib directory being where most of our code lives. If you have a !directory, then those are expected to be executables. There's other directories, test or spec, doc for documentation, although bad directories always kind of weird to me because I believe you don’t put stuff in there that can be generated, only stuff that you need. And then, there are other directories like a data directory if you need some kind of data along with your gem. Those are off the top of my head.
JOSH:
Okay. So, I have a resource here that -- there's actually Guides.RubyGems.org and there’s a ‘what is a gem’ page. And that includes their recommendation for structure for a gem. And here’s a link to that in the show notes. And yes, so you see the bin directory and the lib and the test directory. And then, you get some readme files and the gemspec. So, the readme and the Rakefile and the gemspec. And I think the most interesting thing about the directory structure is when you're in the lib directory, there's a pretty useful conventions for how you name things and how you structure the Ruby files and the subdirectories so that everything just works with how things get required and how the files get found. James, I'm just wondering how we want to talk about that because there's like three things that all interact there, like how your require things, how you manage the load path, and how the directory stuff interacts with it.
JAMES:
So, I mean, people are going to look at this link you just gave but basically, the one paragraph summary here is Ruby gems modifies your Ruby load path which controls how your Ruby code is found by the require statement. When you require a gem, you're just placing the gem’s lib directory in your load path, blah…blah…blah. And it goes on to give actual examples here of what ends up in your load path, stuff like that. I've got to say that I've kind of gotten away from knowing these details as of Ruby 1.9. I prefer to just use require_relative. And then, I don’t even need to know this. I don’t need to know what's in my load path and stuff like that. I know that I can get to that first file that I have to require, and from there, I can require_relative to get everything.
DAVID:
Now, you do the require_relatives inside your gem, right? Not from outside?
JAMES:
Yes.
DAVID:
Okay. Because if you were about to tell me that I have to load your gem and then I have to know the tree structure inside, I will just start driving right now.
JAMES:
No, no. I give a top level filing when you do require and then, that file require_relatives anything that it needs. The only thing I've run into is require_relative is a little bit persnickety. In some cases like in IOB, it doesn’t work which I think is so stupid. I don’t get why it wouldn’t use the working directory. But it doesn’t because there's no file, it’s require_relative to this file. So, the other thing that’s strange, I was using something recently, it might have been Unicorn or something like that, and however it was loading my config.org new file, it’s like it was reading it and evaling it or something like that. So, there was no file context so I couldn’t use require_relative. It was very strange. But in most cases, in gems especially, require_relative gets you around half when you know the load path.
JOSH:
Okay. So, first anti-tip here, things to avoid doing in your Ruby gem is, do not manipulate the load path.
JAMES:
Yeah.
JOSH:
So, the thing to do is not to find all of the directories in your gem that you want to require a code from. Add them to the load path and then just require them with the leaf name of the file. Don’t do that.
DAVID:
If your Ruby gem has a $:.unshift in it, that’s a stabbin’.
JOSH:
Yeah. [Chuckles]
JAMES:
Right. The problem with something like that is if you were to add a bunch of directories, then you may just have sample files in that directory named request.rb, then Rails tries to load and load its directory/directory/directory request.rb. But if yours is higher because of the gem manipulating the load path, then you just broke Rails’s ability to load.
JOSH:
Right. The straightforward way to do things is you have a top level file in your lib directory. So like, let’s say you're doing the glove gem. And so, in the lib directory, you have a glove.rb file and then you also have a glove directory. And the glove.rb file will require any of the top level files that it needs to within the glove directory. And in each one of those files, any place you have a subdirectory in there, you can have something that goes and requires the files in there for you. So, it’s a manual way of having all of the files explicitly require the things beneath them in the tree structure of the directory. Yehuda showed me how to do this for building engines to plug into Rails and it’s just like, “Okay. This makes so much sense.” Because then, you don’t have to worry about require versus require_relative versus am I putting something on my load path. And at that point, you don’t even care too much about the load path because it’s all just -- the one thing you can be sure of with the gem is that the lib directory is in the lib path.
DAVID:
Yeah.
JAMES:
There is one thing that’s kind of annoying. Some gems do this and it bugs me a little on the kind of post Bundler world where you have the gem and it has multiple different ways you can require it and that changes what it does or how it works. I'm kind of over that and I admit that I've done it myself in the past. But it’s kind of annoying in Bundler because you specify your gem and then Bundler assumes the require is the same. So, if you want to work with that, then you have to give the require [inaudible] but there may even be like now, there can even be like multiple ways you require that gem. Require this in your Rakefile, require this in your normal thing. The problem with that is then you kind of like in Bundler, you got to give the multiple ways you can require. And it seems clever like you're giving people traces but it actually turns out to be a [inaudible]. I stay skeptical.
AVDI:
I'm actually okay with it. Let me give an example and maybe you can tell me a different way of handling this. I do think that just requiring the gem name should load that gem, bring it into your load path. But I don’t think that doing that should alter anything globally. But sometimes, it’s really convenient to have some extras that do make global alterations. So, I mean, classic example, most test frameworks, you can require test unit or you can require minitest which will just bring in minitest library that you can then use. But you can also require minitest/autorun. And that’s the thing that hooks in at that exit handler so that you can just evaluate that file and it will immediately run without you having to put some extra code in to go and find the test and make them run. But obviously, I think that’s something that you don’t want to just get when you just require the library by default. But it’s handy to have the ability to just have a one-liner that does that auto-running. And you see other stuff like that like if I've got a glove library and there’s like glove RSpec library for people who want to do tests in RSpec and maybe it adds some setup and teardown steps to the global list of RSpec setup and teardown. That’s really handy. But again, it’s a global change that I don’t want if I just require glove.
CHUCK:
So, I just want to jump in here and we’re kind of going to head this way in a minute anyway, I think. But why wouldn’t you just put that into a separate gem and then just require that gem?
AVDI:
Because it’s too small for a separate gem. These are all like accessory liners.
DAVID:
Yeah. And ultimately, the key thing here, the general rule is, don’t write a library that leaks monkey patches out into the application that included it. It’s dependency infection at that point. And so, you give somebody the glove library and now, they can manipulate gloves and they can interact with everything. But if you do glove.patches or glove.uberolives or whatever, I don’t know, now every object in the system has a dot fingers method that can access gloves. And that’s a good way to do it because now, you can choose because some things we do, like active support. The whole point of active support is to infect the global environment with hundreds of monkey patches. But if your gem can run without monkey patches, or can run with them, absolutely separate them and have them be two separate requires.
JAMES:
I think I agree. I mean, it’s a complicated problem like one of the things I really miss from Perl, as weird as this is going to sound, is that import statement could take parameters.
DAVID:
Yeah.
AVDI:
Oh, yes.
JAMES:
And man! I wish our requires could do that so that we could solve problems like this, require minitest, autorun=true, and then whatever. If we had some way of passing parameters down to those libraries, then we could solve issues like this.
AVDI:
Agreed.
JAMES:
Yeah, I do agree generally with the global requiring something shouldn’t modify the global unless I know what I'm doing. Highline works that way. If you just require Highline, you get the library. If you do Highline import, then it gives you the global methods to make it easy to use from the top level. But at the same time, if you have the set of rake tasks and you have the other one, the normal library and you're using both, so that’s in Bundler, it’s ‘gem GEM_NAME, require’, then you have to give it an array of both of the things that you're going to require and then you have to do the requires manually in the right place. I mean, man! That’s a pain.
AVDI:
That’s not how I look at it because I would never put that in the gem file.
JAMES:
Interesting.
DAVID:
I would also require it separately and when I require the monkey patch version of glove, it would go get the glove library as well. So, there will still only be one, like you don’t require minitest in minitest autorun. You just require minitest autorun.
AVDI:
I would put the gem in my gem file just ordinarily with no special options. But I would want, let’s say it’s minitest autorun, I want that explicitly in the file that uses it because I want to be able to see it, I want it to be grabbable. That’s a thing that changes the way the system works in a global way and that’s something that I want to see in the code.
DAVID:
James has a good point though that by using the require in your gem file, now it’s just there.
JAMES:
No, actually the way Bundler does, I think if I remember correctly, the require line just connects the gem name to what you will actually be requiring. It doesn’t actually do the require.
DAVID:
Oh, okay.
JAMES:
Then in Bundler, and this is weird because most people know Bundler from Rails where Rails does make Bundler auto-require everything.
AVDI:
Right. It’s bundler.require.
JAMES:
But Bundler does not have that behavior by default. It just sets up the gems the way you want them and then you're expected to require them.
AVDI:
Technically speaking, it doesn’t do anything by default. You have to have Bundler in your code somehow. And so, you require Bundler and then you say either ‘bundler.require’ which is going to go through all the gems in the gem file and put them in your load path and require them all. So, it’s going to load them all up. Or you say ‘bundler.setup’ which is going to go through all those gems and it’s going to put them in the load path but it’s not going to load them.
JAMES:
That’s right. Yeah.
AVDI:
If you're building something from scratch, you're making that choice unless you're using some sort of framework that gives you like an environment file or something, a top level file that already has that in. That’s a choice you make whether to call bundler.setup or bundler.require.
JAMES:
So, if you have that thing where you have a gem and then it adds some rake task, you need to risk both requires because Bundler needs to be able to match that path into the gem that it has on this. So, it needs to be able to recognize it then you'll have to use bundler.setup as opposed to bundler.require so that in the main gem, you can require the normal thing and then, in the Rakefile, you can require the rake task.
AVDI:
I'm not sure that’s true. But I need to take it offline and test it.
CHUCK:
I need to listen to that thing again.
AVDI:
As long as the gem’s in the load path, you should be able to require optional parts of the gem.
JAMES:
Interesting.
JOSH:
Yes.
CHUCK:
So, I want to get into a question that I have that’s sort of related to this. And that is, when do you write an extension to your gem versus giving it other require options? Like what are the trade-offs?
JAMES:
I would say when you're going to have something that’s optional, so a good example that just pops in my head is autotest-growl. So, you’ve got autotest which is going to automatically run your test but maybe you would like [inaudible] and you would like to have those notifications come to growl, then that seems like an optional add-on part.
DAVID:
But maybe you're on Windows or Linux and you don’t want to drag in that code every time you install.
AVDI:
Here's the rule for me. The rule for me is based on gem dependencies. I mean, if autotest-growl also has dependencies on a growl gem which is Mac OS only, then if you bundle that growl functionality into the main autotest gem, then you'd have two choices. Either you make that growl gem a dependency even when somebody’s downloading on Linux which could cause problems or you leave the dependency off completely and you’d just have to like array in the documentation. If you want to use this other feature, you're going to have to manually install the growl gem. I think it’s all about those kind of dependencies. If your add-on has a dependency which you might not want to force to be installed on everyone, then make it an add-on, make it a gem.
JAMES:
Right. We’ve talked a lot about dependencies. It may be worth mentioning that Ruby Gems actually has a kind of notion of two different kinds of dependencies. And this came in kind of late in the Ruby Gems’s lifecycles. So, I don’t think everybody knows about it. I still see people using it incorrectly. But in the gemspec, you can have ‘add dependency’ which is your normal gem dependency that we all should be familiar with. But you also had ‘add development dependency’.
DAVID:
Yes.
JAMES:
Which is something like, “Hey, we’re using RSpec for testing or rake for this tasks,” and whatever. And when you install the gem, you can ask for the development dependencies if you want but that’s not the default behavior. So by default, you don’t drag in massive and large spec and all of its dependencies but you can choose to get them when you want them.
DAVID:
How do you turn that on, do you know, off the top of your head?
JAMES:
I think it’s a switch on the gem command line. I’ll look it up quickly.
DAVID:
Okay. Because I just realized I do that but then, I go to the gem file and I also have a group development due and I put RSpec in there. And I just realized that that’s how it’s getting into my development project not to the gemspec itself.
CHUCK:
That’s simply what I do too. I’ll put it in the gem file.
DAVID:
I mean, if you're developing on the gem, you’ve got the source code. So, you should be using the gem file -- I don’t know.
JOSH:
Okay. How should people be managing dependencies in their gems? Is this a good time for us to start talking about the gemspec? We’ve talked about the directory structure of gems. For people new to this, there's a file within the gem itself that ends in a .gemspec extension and that is some Ruby code, it’s Ruby code in that file that describes what's going on in that gem. And it talks about what are the files in it, who the author is, what is its open source license, whatever its dependencies on other gems, version information, like crazy stuff. Let’s see. This Guides.RubyGems.org site has a ton of really good information on most of the stuff we’re talking about. And they have a nice little thing about the specification in here as well. So, I guess I’ll pop that link in but I think we should just link to the top level site as well.
JAMES:
David, just to answer your question, I did look it up. GemInstall and then you can do ‘-development’ if you want the development dependencies along with the normal dependencies. Or you can do ‘--developmentall’ if you want your gem’s development dependencies and the development dependencies of anything that’s a dependency for your gem.
DAVID:
Cool!
JAMES:
So basically, development dependencies all the way down the tree.
JOSH:
Wow!
DAVID:
Cool.
JOSH:
So James, how does that interact with using Bundler to develop gems? Or do we want to hold off on that?
JAMES:
It’s actually a really great question because I've actually had quite a bit of experience with that recently. Bundler has a feature called gemspec in it. And if you use that, Bundler will use the dependencies that are specified in your gemspec as your require. So, you can make your gemspec normally, set up your dependencies and then, in the Bundler file, you can say ‘gemspec’ there and even if you wanted some specific stuff just for testing, you could go ahead and add the test group there and put some things in or whatever. But the main stuff would be handled through the gemspec. So, I think that’s a good thing.
CHUCK:
So, the gemspec option only pulls in the actual dependencies, not the development dependencies?
JAMES:
That is a good question. I actually hope that it would take the development dependencies and put them in the development group.
JOSH:
That’s what it does.
JAMES:
Yehey! Okay good, because that’s awesome.
DAVID:
That’s cool.
JOSH:
So, if you do that, when you're developing a gem, you can just use the gemspec and have the development dependencies in there or you can add a Bundler gem file at the top level of your project, say gemspec in it, and then you can use Bundler to help you while you are developing the gem. And that will take care of all of the installing your development dependencies that you need.
JAMES:
I guess I need to make this clear. The reason you would use Bundler to manage this is for all the great reasons we’ve come to love Bundler. You could quit worrying about those dependencies and stuff. But just be aware when your gem loads, you're not going to have Bundler which is the reason to use the gemspec and then in the gem file, use the gemspec command to load it from there because your gemspec will be in play. So, if you do it from the gemspec and you bring that over into Bundler, then Bundler’s managing it when you're developing in testing and your gemspec’s managing it once it’s finally installed.
DAVID:
I have an odd question about gemspec to throw out to the rest of the Rogues here. And it’s useful I think, maybe, to some of the listeners. There's a section in the gemspec where you can say ‘files=’ and then you give it a list of all the files to install. And I am torn between wanting that to be explicit and list it right there in the gemspec so that you can just read it and see right where it is and wanting it to be functionally provably accurate. In other words, have this little line that basically just says ‘glob all of my subdirectories and include all the files’. And that’s a line of code that shows that it’s going to have everything. But if you're reading the gemspec, it doesn’t tell you what they are.
You have to go back to the thing.
JOSH:
[Chuckles] And there's a third option.
DAVID:
What is the third option?
JOSH:
The third option is you use git to list all of the files that have been committed to the repo.
DAVID:
[Expression]
JAMES:
Correct.
JOSH:
And that’s what Bundler does when it generates your gemspec.
JAMES:
So, this is actually a popular debate mainly because different tools like hoe, for example, requires a manifest file which lists line by line every single item that’s included. And so, that’s one line of thinking. And then, as Josh said, there's the other line of thinking of dynamically pulling it out of something like git and the advantage from pulling it from git over something like a file glob is that the file glob might pick up some invisible files like Emacs back up files or Mac OS X directory structure files or anything like that. Whereas the git will honor the git ignores and stuff like that which will probably be those things. So, you’ll just get the files that you need.
JOSH:
Although the git thing, if you're developing a gem and you're trying to test -- okay, so if you're developing multiple gems at the same time and you're trying to test stuff and you haven't done a git commit, that can really screw with your testing.
DAVID:
Oh, yeah.
JAMES:
That’s a good point.
JOSH:
I have run into that. So, you have to make sure that you are like developing on some sort of branch where you can be just like updating the head commit over and over as you're doing the test.
CHUCK:
One other question I have on this though is if you're using git to pull everything in, aren’t you committing your tests and everything else to the gem? And if somebody’s installing the gem, do they necessarily want all of that stuff?
JAMES:
Yes, please. Include it! Please!
AVDI:
Yes. And traditionally, we’ve always done that. We’ve always included everything.
JOSH:
And in fact, Ruby Gems has a way to run the unit tests for the gem.
JAMES:
Yes.
JOSH:
So, you can install a gem on your system and test it to make sure that it works on your system.
CHUCK:
Oh, really?
DAVID:
Yes, yes.
AVDI:
This was something that CPAN, the Perl Archive actually had rolled in and it would do, by default.
When you install a Perl package, as part of the install, it runs the unit test to find out whether it’s working on your system or not.
DAVID:
Oh, man! I want to monkey patch Ruby Gems now so that when you do a gem install, it will run the test [inaudible] if it can find one. [Laughter]
AVDI:
I don’t want to monkey patch it. I just want to do a pull request for that. [Laughter]
DAVID:
Yeah. Fair enough, fair enough. It’s a legitimized monkey patch. But anyway, for those listening, I've got a gem called TourBus. It’s Github.com/DBrady/TourBus, might be
Github.com/DBrady/Tour_Bus . Or might be hyphen or tilde, I'm not sure. But in my gemspec, I have a commented out Ruby program that you just run at the bash prompt and it [inaudible] all of the files. And then, I copy them and I paste them and I run that every time I chain. And this is so tedious but it does at least let me say, “Here’s the thing that proves that everything is included. And here’s the explicit list of files so you can read them and see that they're there.” I don’t know that that’s a good solution. There's definitely some engineering habit that like, things that I do automatically in my head to make this work which means it might ought to be offloaded to a computer instead.
JAMES:
If I were going to do that, I would make a rake task that modifies the gemspec.
DAVID:
Yeah. Like a rake task like a repackage or rebuild the file list or something. Yeah.
JOSH:
You mean like jeweler?
JAMES:
Kind of like jeweler, yeah. Tell us about jeweler, Josh.
DAVID:
I have never played with jeweler. Tell me about jeweler.
JOSH:
Okay. So, we’ve been talking about using Bundler to generate the skeleton for your gems directory structure and also for generating your template gemspec file. And Bundler is really popular for that. I put up a little survey thing on what is it, votes.io? It’s a cool Rails Rumble project, and asked people what they use for doing this. And before the survey results got [inaudible] by some robot, clicking a button 600 times. It looked like Bundler was way ahead for all of this stuff. [Crosstalk]
DAVID:
Doesn’t votes.io know that it got hacked by somebody typing bundle exec hack_joshs_survey. [Laughter]
CHUCK:
Nice!
JOSH:
[Laughs] Thank you, thank you. But the other things that we’re looking at in the poll were things -so, there was hoe, and jeweler, and new gem and Ruby Gems tasks. So, there's a bunch of tools out there that people use for either building or maintaining the gemspec. And one of the ways to do that that I believe jeweler does this, I'm not sure about any of the others. Jeweler has a Rakefile that basically has all of the logic that you would put in into your gemspec in how David was just describing it as a little piece of code in there that does that. And James said, “No, I’ll put that in the rake task." Jeweler does that for you but you have to put a ton of stuff into that Rakefile that is basically the same information you would put in your gemspec file just massage it around to be able to run in a Rakefile.
CHUCK:
[Laughs]
JAMES:
So, I'm going to give my opinion here. And this is totally my opinion. Everybody’s going to disagree with me. You guys can all send me a hate mail but I'm against the manifest file of hoe because it’s just too error prone like I always add a new file then forget to put it in the hoe [inaudible].
JOSH:
I'm right with you there.
DAVID:
Yeah. That’s a DRY violation.
JAMES:
Right. It’s just I always do that. Jeweler is kind of the same way. It’s that duplication of information. I'm putting a whole thing in the rake task so it can go through this process and generate this gemspec for me which is going to have the same information that I could have just put in the gemspec. And that first link that Josh gave to ‘what’s a gem’ thing on the Ruby Gems Guide, there's a sample gemspec in there. It’s 11 lines counting the end. A gemspec is just not that complicated.
DAVID:
That gemspec will generate like 15 warnings, like missing license file, and missing…
JAMES:
I don’t know. That’s a good question.
DAVID:
[Inaudible]
JAMES:
Maybe.
JOSH:
I had a test and a gemspec is pretty simple but they can get kind of complicated.
DAVID:
Yes.
JAMES:
That’s true. There are situations where they do get pretty involved. The file this thing we’ve been discussing is one of them. I like the git trick that Bundler does that at some point, you need to reality check the file list. I do it whenever I usually just use rake’s package tasks that it has built in. And when I type ‘rake package’, it shows me which files are getting shoved into the gem so I kind of just go down that for reality check, like, “Wait. Why did they include that two gig file?” But I mean, I'm sure I can miss things, that’s true. Bundler does another cool thing along these lines where if you have it generate the gem, it will purposely make a file called version.rb under the gem name space. And the reason you do that is so that in your gemspec, you can require just that file without loading a ton of Ruby code to get the version constant for gemspec so you don’t have to always update the version in two places.
DAVID:
Thank you. You just made me stop hating that file.
JOSH:
[Laughs]
JAMES:
Well, and that file has like done an advantage in that if we all did that, then we could do that. We could load that file and load the version without loading everything.
DAVID:
My biggest beef with DRY is when you DRY something up, but then you hide the thing you DRY. You put it in some weird corner shelf that’s hard to find. And yeah, I'm used to looking for the version of the gem by opening the gemspec and there’s this include [inaudible]. But yeah, it’s become standard now. You go look into the lib version.
JAMES:
Yeah. I'm basically, I guess Bundler is totally one way with its way of doing things is what I'm trying to say, whereas it seems to try to put the knowledge where it makes the most sense to put the knowledge without having to keep track evading several places and stuff like that.
JOSH:
I think that’s true. So, let’s explain how the gemspec is used in the life cycle of gem development because I think that’s a good thing for people to walk away with. There’s, you write the gemspec, and we’ve talked about that somewhat now. But then, there’s when you create the gem. So, there's a build phase where you have your source tree of all of your files including the .gemspec and you build that. And that produces a gem file which sounds just like a gem file but is different. So, Bundler has the capital ‘G’ Gem file but Ruby Gems, when you build a gem, you get your refraction.gem file. So, that is what we used to call a gem file. But I don’t know what we call it now.
But we have another gem file.
DAVID:
[Inaudible]
JOSH:
Okay. Thank you. By the way, I’ll take 20 seconds here to rant about Bundler calling that file the Gem file. [Laughter]
JOSH:
It’s like, okay, way back when we had the Makefile on ancient systems and then Jim Weirich created the Rakefile which was the Ruby Makefile. Because that had historical precedent and it was named off the Makefile, I can't give Jim a hard time for that. But everybody else has built a file that ends in file after that, you're a terrible person and you should feel bad. [Laughter]
DAVID:
And Bundler doubly so because it should be called the Bundler File. [Laughter]
JOSH:
It’s like, do I really need the name of the file to tell me that it’s a file?
JAMES:
Foreman has a procfile.
JOSH:
It’s like everybody has a thing file now. So, it’s terrible.
CHUCK:
I'm going to start making my gems have something folder-folder. [Laughter]
JOSH:
There we go! It’s the file directory.
CHUCK:
Yeah. And then you'll have something file-files in them.
JOSH:
[Chuckles] Yeah. Okay. But so you have this .gem, this .gem file we’ll call it, and it’s a binary distributable format for your gem. I think it’s actually a zip file, the binary formatted files, it’s just a zip that has…
CHUCK:
I think it’s a zip or a tar, I don’t remember.
JOSH:
Right. So, it’s one of those archive formats. And within there, you no longer have the original .gemspec file but there’s also -- what is it? Is it YAML? The converted form of that, that it’s no longer executable Ruby code or pieces of Ruby code. It’s now this thing that’s been translated into YAML that has all the information in it. Does that sound right, guys?
JAMES:
Yes.
JOSH:
Okay. And then, you take that .gem file and then move it up to RubyGems.org or wherever you are hosting your gems. It’s entirely possible to run a local gem server within your company’s firewall. That’s a fairly common thing for people to do. And then, later on, you do either bundle install or gem install, it pulls down the .gem file, unpackages it and then Ruby Gems runs a fair amount of code to install that on your system’s file system server.
JAMES:
So yeah, the only comment I had on that is the build step can be really trivial if you’ve been doing the gemspec like we’ve discussed. I’ll link to it in the show notes the Rakefile for Highline that if you look in there, basically all I do is require the gemspec because it’s a normal Ruby file. And I always make my gemspec assigned to a constant somewhere so that I can use it elsewhere. And if you look in my rake task which I’ll put a link to, there’s a gem package task that comes with rake, I think. And you can just require that and then you can just gem package task the spec which because I assigned it to a constant, it’s available. And then, it will give you several rake tasks, rake package, rake clobber package and something else, whatever. Anyway, rake package will build the gem for you so you don’t have to do anything special.
JOSH:
That’s true.
CHUCK:
And then, you gem push it to get it up to RubyGems.org.
JOSH:
Let’s see. We’ve been all over the map here. We’re kind of talking about tools.
JAMES:
One more thing quickly on tools. It’s okay if you generate your gemspec or whatever if you do that. But do generate it, put in the directory and check that into git. And it needs to be at the top level and the name of your gem and stuff. The reason is that Bundler works with that. We can point it at a git repository and it will bring down the git repository and use that version, or you can point it at a specific commit SHA or a branch or whatever. And it’s really great in development where you're like using some library on the side or whatever and messing with that. And the way that works is Bundler looks for that gemspec to build the gem when it pulls it down.
DAVID:
Cool.
JOSH:
Yeah. It’s very useful to put a gemspec in your Github repo even if you're not like pushing it to RubyGems.org.
DAVID:
One more question for the group then and this should be a fast one. In TourBus, I've got a little shell script called Build.sh. And all it does is uninstall the TourBus gem, build the TourBus.gemspec to regenerate the .gem file and then it does a gem install on the most recent .gem file in the directory. And I use that one in developing on TourBus so that I can go start up this other Sinatra app and run it from the command line with it being installed and all that. Is that a bad practice, is it a good practice? Does jeweler or something else do that for me?
JOSH:
I always just like do this stuff manually. I haven't gotten to the point where I do that often enough that I want to have that all just be like build and I'm done. It sounds useful. So, we have a couple of other topics we probably want to hit at least a little bit before we wrap up.
JAMES:
Maybe versioning.
JOSH:
Yeah. We did a whole episode on versioning.
JAMES:
So yeah. And if you go back to that episode, we talked a lot about sun var which I think is good. But the one thing I would add from a very Ruby Gems specific perspective -- so, here’s a great example. Ryan Davis is developing minitest version 5 right now. And so, he’s getting ready to push it and it’s a 5.0 so it’s got some incompatible changes and stuff. And he went back and looked through the gem server and just did a scan of gems and made a list of all the gems that are about to break when he pushes this 5.0. And the reason they're going to break is in their gem file, they specified > or = version blah…blah…blah. So now, what's going to happen is 5.0 is > or = whatever they said. So, it’s going to pop and they're going to have incompatible changes in there. And the right way to handle that in Ruby Gems is to use the ‘twiddle-wakka’, some people call it, but it’s a tilde greater than symbol. And that means that you will take minor version changes. So like, if you said ‘twiddle-wakka 4.0’, then you are allowed to get 4.0.1 or 4.0.2 or whatever. But it would not give you 5.0 because it presumes that could be incompatible.
JOSH:
James, what you said is absolutely correct. But I think it’s a little confusing because of the number of dots in your version numbers that you talked about. The pessimistic version operator is -- you said ‘greater than 4.0’ or…
DAVID:
He said ‘4.0.0’ and 4.0 is probably better.
CHUCK:
Well, then we’ll go with that one.
JOSH:
Okay. So, James said ‘twiddle-wakka 4.0’ which will let you get 4.0.1, et cetera, but it will also let you get 4.1 but it will not let you get 5.0.
DAVID:
Yeah.
AVDI:
I think that generally you should be doing -- if you can get away with it with the gem that you're dealing with, you should be doing major and minor but not patch with your twiddle-wakka.
JOSH:
So, that’s a great point about versions. There's a couple of other little things to touch on in here open source license. So, there is in fact a place in the gemspec where you can say what the license is. And please, do that.
CHUCK:
I use the open source license. [Laughter]
JOSH:
I like that one.
JAMES:
I actually had people Email me in the past. I was lax about putting it in there. And people will Email me and they're like, “I’d love to use your gem at work but they won't let me because you don’t specify the license in the gemspec. And that’s how they pull the license and get the info.” So, it really is valuable to people if you do that.
CHUCK:
Yeah. Well then, if you don’t specify the license, then you own the intellectual property there even if it’s available for people to download and install. And so, technically, you could give them grief over it. And I think that’s why people want to see it is so that it says out there explicitly, “You can use this and I'm not going to try and claim any rights to this code.”
JOSH:
What about Signing Gems?
CHUCK:
Signing Gems?
JOSH:
Yeah. Should we just do an episode where we have Tony Arcieri back and we talk about Signing
Gems?
JAMES:
I think we should definitely talk about it. And so, as people probably know, RubyGems.org was hacked recently. And so, in order to verify the gems, they basically had to go back through every single gem and verify against the last known good state to ensure that no gem had been modified and now contain malicious junk or whatever. And that process could be greatly improved if we would adopt Signing Gems which has been available for a while but doesn’t seem to be popular at first for some reasons. And I don’t know all the details on that.
CHUCK:
I was going to say, if you can find a way, I will autograph it. [Laughter]
JOSH:
Nice! I think -- I'm going to make a prediction and I think that over the next year, that the tool chain support for Signing Gems is going to improve greatly. And that the Ruby community will shift to having sign gems.
JAMES:
I hope so.
CHUCK:
I guess we don’t want to go down this rather whole…never mind.
JOSH:
Yeah. I think that’s all. I think that’s potentially a whole other episode.
JAMES:
What about, Josh, tell us about using a packaging system as a dependency.
JOSH:
Oh, yeah! That’s a really bad thing to do in your Ruby gem. I don’t have an example off the top of my head. But if you're doing something within your gems code that is explicitly using the Ruby gem package system, that’s a no-no.
CHUCK:
What do you mean?
JOSH:
What I mean is that you can call Ruby Gems version and then do some version comparisons. Or you could be requiring Ruby Gems to go load another gem explicitly. And I could see that there would be situations where you’d want to do that. Like, you say, “Okay. I have something in my Ruby gem that is smart enough to figure out which database system is installed in my system,” and go load the driver for that database. That sounds crazy but I've seen crazier. [Chuckles] And then, that would, within that code, you could do something like, “Okay. I'm going to require Ruby Gems,” and then use Ruby Gems to go load the right version of the right gem to talk to the database that I have on my system. If you are explicitly requiring Ruby Gems in your code so that you can use the Ruby Gems feature set, you're doing it wrong. And this is a case where you can actually say, “You're doing it wrong,” because what that does is that prevents people from using other packaging systems to use your Ruby code. And just because your Ruby code is distributed within a Ruby gem or packaged within a Ruby gem, the Ruby Gems’s package format is not -- it’s a standard format, at least in the small world of standards, that can be manipulated by other packaging systems and there are several package systems that will work with it. There's Ruby Gems itself, there's Bundler, there’s -- what's the one that Seattle folks are partial to? It was Isolate.
JAMES:
Yeah, yeah.
JOSH:
And then, there’s something that Chris Wanstrath did that was based on the Python 1 pip. [Crosstalk]
JOSH:
So, if you do that, then you break those systems from being able to manage the gems the way they want to.
JAMES:
And so, just to use Josh’s example, if you're loading Ruby Gems in doing your own version matching and grabbing a specific version of something, then if I put it in my Bundler controlled app and I lock at some version of something, then when that code loads then we’ll probably just going to have some kind of conflict.
JOSH:
Yes. So, don’t ever call -- if you ever see a require Ruby Gems within any of the Ruby files in your gem, don’t do that. Figure out some other way of doing it. How about maintaining? Who gets to maintain the gem for a long time, James? [Laughter]
JAMES:
Too long, too long.
JOSH:
What are the challenges in maintaining gems as time changes?
JAMES:
Free time. [Laughs]
CHUCK:
[Laughs]
JOSH:
Okay. So, we…
CHUCK:
I should totally see that.
JAMES:
[Chuckles]
JOSH:
So, we just insert our Contributing to Open Source episode as reference?
JAMES:
Yeah. Absolutely. Some things, the Highline gem really could use any version that has just grown over time and things have been bolted on, and bolted on. Now, I can see all the patterns involved and I need to go back and clean it all up. But I can never find the time to actually go and do that change. So, yeah. I think that’s free time. And then, FasterCSV which later got moved into the standard library so, there was time maintaining that. But then, I actually wanted the FasterCSV gem to die out because it was in the standard library so, I had to actively try to kill it. There’s lots of problems with maintenance. Maintenance is hard.
JOSH:
Is there anything about maintaining Ruby gems that’s just like particular as opposed to just like generic open source projects? Is there anything about interacting with RubyGems.org or tracking changes in Bundler or Ruby Gems?
JAMES:
That’s a good question. Ruby Gems has been going through a lot of changes. But mostly, they have an effect to do too much. There was a time period when the development dependencies were introduced and you couldn’t really use those too much when they were first introduced because everybody would have a much older version of Ruby Gems that wouldn’t have that feature. So then, your gemspec will just crash; which it’s been around long enough now, I think we’re pretty much past that problem. And Ruby Gems ships with Ruby these days. That’s a good question.
Anybody else think of any other gem specific maintenance problems?
CHUCK:
Not really. I mean, the only thing that I've seen is just the version of Ruby kind of stuff and incompatibilities.
JAMES:
Don’t ever replace a gem version, Ruby’s a new version.
JOSH:
That’s crucially important.
JAMES:
The gems have mirrors and stuff like that. So, there can be many copies out there. So, if you bundle it and you release a version or whatever, and it’s bad, then your tendency might be, “Oh, I’ll just fix that version.” But don’t do that. Just release a later version that’s fixed.
JOSH:
Yeah. If you do that, Ryan Davis and Eric Hodel will come to your house and sing. [Laughter]
JOSH:
I didn’t want to threaten violence on their behalf.
DAVID:
We don’t know. We’ve never heard them sing. [Laughter]
JOSH:
Speak for yourself.
DAVID:
Okay.
JOSH:
It looks like we’ve hit everything on our list. Hitten - that’s not a word. [Laughs] Anything else?
AVDI:
Somebody just reminded me of the name of a tool for putting together gemspecs called rakegem. And this one’s interesting simply because like if you’ve ever wanted to put together a gem and you wanted to have some useful rake tasks around it but you wanted them all to be just in line in the rakefile, not like requiring some gem rakefile like the Bundler tools that you don’t know exactly what's available or how they work. Like, you just want to have the tasks right there in your rakefiles, you can just edit them and rewrite them or whatever. There’s this tool called rakegem which will just generate a zero-dependency skeleton, extremely minimal gem skeleton.
JOSH:
What about Ruby Gems Plugins that are useful for gem development?
AVDI:
Gem-open.
JOSH:
Yeah, that’s my favorite. So, if people don’t know, Ruby Gems has a plugin system and you can write essentially new commands for Ruby Gems as plugins. And yeah, gem-open is awesome.
JAMES:
Okay. Sell me on gem-open because like, I never use it.
AVDI:
It opens your gem. [Laughter]
AVDI:
It opens other people’s gems, really.
JAMES:
It has a built-in command that’s called what? I'm looking for it right now that I'm just using. It just spits the gem out into a directory for me.
DAVID:
Gem environment gemdir?
JAMES:
No, it’s way easier than that. It’s gem help commands. There it is. And you can see, I obviously don’t do this often enough to have it memorized.
AVDI:
Are you talking about unpacking it?
JAMES:
Yeah. Is that it? Yeah, unpacks the installed gem into the client directory.
AVDI:
I want to see like where it’s installed. I want to see the code where it’s installed in my system.
JAMES:
The only thing I don’t like about that and the reason I avoided it is I see tons of people that gemopen and then start editing to their hearts’ contentment. [Laughter]
JAMES:
So, they do a [inaudible] statements in there, they do whatever they change the code around. And it’s like, you know, to me, that installed gem is sacrosanct and I will not…
AVDI:
Okay. I will admit. One of the reasons I like gem-open and I almost never use gem-open for this purpose. Normally, I just want to see the code and I don’t want to wait for it to unpack. But every now and then, when all of my resorts have run out, as a last resort to figure out what the heck is going on when I'm completely stumped, I will sometimes do a gem-open and actually start putting print statements in the installed gem in my system because I'm baffled as to why something is either happening or more often, why it isn't happening.
JAMES:
So, on the opposite, I consider that ‘No Man’s Land’ and I am not allowed to go there. So, what I would do is I will gem unpack GEM_NAME which spits it out into a directory, I’ll read the code, and then I’ll go load a monkey patch in my code that modifies the gem to print what I wanted to print.
AVDI:
I'm too lazy for that.
JOSH:
Yeah, me too.
AVDI:
I've ran into too many situations where I wound up spending an inordinate amount of time getting the monkey patch wrong before eventually getting the monkey patch right. Or I discovered that I was having the monkey patch more and more because I'm just going through trying to figure out like what is the path that this code is taking or something. And so, I would have to progressively monkey patch more and more. It’s just so much faster to go in and then give myself like a ritual 20 lashes afterwards.
DAVID:
Yeah. I actually found a place where it couldn’t be monkey patched. In Ruby 1.9, minitest was a gem and Ryan, down at the array bottom of the file finds Minitest with a capital ‘M’ and a lower case ‘T’ to equal MiniTest with a capital ‘M’ capital ‘T’. And the comment is -- because I mistype this all the time. And we had something that was including that file twice and we couldn’t get that turned off. So, we were getting duplicate constant definitions all the time. And the only way to fix it was to remove Ryan Davis’s predilection for typos from the minitest gem.
JAMES:
Hey guys, we did a good job of covering both sides of that debate. [Laughter]
CHUCK:
Yeah.
JOSH:
I think we just let it sit there.
DAVID:
I agree with James. It’s sacrosanct. And sometimes, that’s the best hamburger to make your cows out of or vice versa. [Laughter]
AVDI:
What?!
JAMES:
Oh, man! Could we please do the picks?
CHUCK:
Okay. Alright, let’s do the picks. Josh, what are your picks?
JOSH:
You made me go first twice this week. Okay, I have a theme for my picks this week. My first pick is a cookbook. It’s the ‘Joy of Cooking’. And this is like one of the standard cookbooks. Okay, how many people on the show right now have the Joy of Cooking in their kitchen?
DAVID:
I think I do.
CHUCK:
I don’t think I do but I remember my mom had that.
DAVID:
That’s the actual Julia Child’s book, right?
JOSH:
No.
JAMES:
No. My wife keeps it.
JOSH:
Yeah. So, the Joy of Cooking is just like, if you need one cookbook in your kitchen, that’s the book to have, in my opinion. I don’t know. This other guy came out with How to Cook Anything or How to Pick Everything, that might be a good replacement for it. But I've never seen it.
AVDI:
Bittman’s book is quite good. I’ll pipe up for that.
JOSH:
I may have to buy that and check it out soon. But Joy of Cooking is great because not only does it give you recipes, every section, like there's a section on meat and poultry, there's a section on baking, there's a section on sauces. Every section has a lot of front material. It’s sort of like the Martin Fowler book. There’s like a discussion at the front that talks about things in the general way. And then, there's the rest of the chapter is a bunch of recipes. And I love that. It talks to you about what are safe temperatures to cook meat to and how do you want to handle stuff and how do you debone a turkey. It’s really great. And it’s like 8,000 pages long or something. It’s great. I can find almost anything in there. So, that’s cookbook number one this week. And then, cookbook number two is ‘Gather’. And I've talked before about how my niece and her fiancé published ‘Make It Paleo’. I guess that was a year or so ago. And that’s been really successful and it’s been very well received. And they have this new Paleo cookbook called ‘Gather’ which is about Paleo cooking for entertaining people. So, if you're going to have a dinner party or have lunch or something, that’s often a really challenging thing for Paleo. So, they have a bunch of really great, not just recipes, but ‘here’s your whole plan for your whole dinner party’, ‘here’s all the different dishes you can cook’. And that’s gotten released like -- well, it may be up by the time people hear this podcast. And I've seen a copy of it and it’s just great. So, those are my cookbooks this week. Go eat healthy.
DAVID:
Cool!
CHUCK:
Awesome. Avdi, what are your picks?
AVDI:
First of all, I believe ‘Make It Paleo’ is one of the Paleo cookbooks we have around. Both my wife and my daughter like to cook that way. And as far as I know, the…
JOSH:
It’s the one with the full edged photo on every page.
AVDI:
Yeah. And I think they’ve been getting some really good stuff out of there. So, there's some unbiased props for that book. It’s good stuff.
JOSH:
Have you done the Chicken with 40 Cloves of Garlic yet?
AVDI:
I think they might have done that. I can't remember. [Laughs] That sounds like something they would do because they're both garlic-themes. If they haven't, I'm sure they will. But let’s see, picks. There's a great article, actually a series of two articles that I ran across the other day. They're actually not very new articles. And I have proceeded to lose them in my browser tabs. But basically, it’s a series of two articles on the ‘Rise of the Expert Beginner’. And it’s about people in the software industry who achieve a certain level of proficiency on the Dreyfus scale of learning things. And then because of the environment they're in, assumed that they have become experts. And then, start asserting what their sort of beginner level knowledge as expertise to the rest of their team and it goes on to talk about how this tends to cause teams to rot out because the option is basically either keep support. You have people that rise up as time goes on, junior to senior to whatever ranks people have in their software engineering organizations. And it may just be because of longevity basically or job hopping a lot. And the option in teams is either to support them in the stuff that they're saying whether it’s a good idea or not, or to sort of butt heads and wind up moving on. And so, you wind up with all the people that might have good opposing opinions eventually just moving on and winding up with these teams that where the only opinion is the expert beginner’s opinion. I see that a lot. I see a lot of siloing in the industry. So, I found it a really, really insightful article or series of articles and absolutely worth reading for anybody who’s in this business.
CHUCK:
Okay. James, what are your picks?
JAMES:
I have two for a technical pick. The new PeepCode Play by Play by Ben Orenstein is fan freaking fabulous. It’s really good. I've mentioned a bunch of the Play by Plays before. If you have liked them even a little, you're going to love this one. It’s probably the best in the series. It’s a live refactoring, there was a Play by Play just before this one of Corey Haines and Aaron Patterson pair programming to solve this problem. And that one was pretty good too. But in this one, Jeffrey gave the code that Aaron and Corey produced to Ben and said, “Okay, refactor.” And so, it’s great because it has him looking to a code base he’s not familiar with and trying to understand it, it has him refactoring that code base and trying to figure out what's going on, making changes to it to improve his understanding of it and stuff like that. And then, what really makes it great is Ben is one of those cool people that really has his environment a certain way and he walks you through the logic of that as he goes and how he decides to make changes to that and stuff. Anyway, it’s totally cool. Great Play by Play, definitely watch that. And then for my non-technical pick, I too have been in the food lately. My wife and I are trying to eat healthier and we’re making a menu each week and stuff like that and keeping track of what we’re eating. And as part of that process, I try to add a new recipe to the menu every week. So, we can try out new things and it doesn’t get boring and stuff like that. So, I'm always on the lookout for new food sources. And the one I've just been absolutely loving lately is a blog called Budget Bytes. And the purpose of the blog, it’s just some lady who likes cooking and keeping track of the cost of it and stuff. So, each recipe has like a price on it and how much it costs which is really cool and not really what I care about like as far as the price stuff. So, if you heard that and you're like, “Big deal,” you should still look at it anyway because like I said, my wife and I have been trying to eat healthier and so I run all of these recipes through our particular point system. And most of them are fairly good as far as health goes. They have some vegetarian stuff, I know, and then stuff that’s not. But just lots of great recipes. I mean, tons of great ones. We’ve tried about ten now, maybe. And a large number of those are like, “We want to eat this all the time.” So, cool blog for food recipes that are budget-conscious and fairly healthy. So, those are my picks.
CHUCK:
Awesome. Avdi, what are your other picks?
AVDI:
So, you know how if you want to buy shoes online, Zappos is like the place to go. And I don’t know if you’ve even been to like a Nordstrom Store, how they have the main Nordstrom Store where everything’s super fancy and super expensive. But then, they have Nordstrom Rack on like the bottom level down in the basement where you can find all sorts of stuff that’s steeply discounted. So, 6PM.com is the Nordstrom Rack of Zappos. And you can go there and buy shoes for a lot less than they list on sites like Zappos and Amazon. And I've gotten a few pairs of shoes off of there and I'm really happy with it.
CHUCK:
Awesome. David, what are your picks?
DAVID:
Okay. So, just two today. The first one is ‘How to Survive a Ground-Up Rewrite Without Losing Your Sanity a.k.a. Screw You, Joel Spolsky. We’re Rewriting It From Scratch’. It’s a Guest Post by Dan Milstein on the OnStartups blog. And I just love this blog post because these got some non-work safe language in the post. But he says, “Prepare your self for this project for it can never freaking end.” And the reason why is migrating the data sucks beyond all belief. And I've worked on projects where you’ve had to migrate data and you end up having somebody come to you and say, “We need a whole new schema. We need to migrate the data but we need to keep the beta site and the old site live and running and accepting data at the same time.”
CHUCK:
That sounds really familiar to me. [Laughs]
DAVID:
Doesn’t it, though? Just like the project that you and I worked on. And it really does -- yeah, he’s got a really good finger on just the pains that are involved when you rewrite a project from the ground up. The post title is, because Joel Spolsky basically said, “Never ever do a total ground-up rewrite.” And Dan gives the conditions under which that absolute statement is no loner true and all of the trade-offs that you're going to have to confront if you decide to go down the road of doing a ground-up rewrite. So, that’s my first pick. The second pick, I should have picked this last week or the week before just for timeliness. But I am speaking at OpenWest which, if you are listening to this podcast on May 1st which is the day that we publish this episode, then I am speaking tomorrow at 2:00 in Salt Lake City. It’s an 11-track conference for $80 for three days. I cannot believe -- Mountain West has one track but this one goes to 11. And I cannot believe that they're putting on a three-day 11-track conference for like $80. So, go to OpenWest if you can. If there's time to get a ticket, absolutely. If you live on [inaudible] in driving distance, it’s a fantastic conference and you should go. So, those are my picks.
CHUCK:
Awesome. Alright. So, I just have one pick today and that is zip ties. I got a whole package of them there. How many are in here? Two hundred zip ties in this canister of different sizes and shapes. It’s just a super handy way of securing things, organizing cables, things like that. So, I really like them. I’ll put a link to the package that I ordered off of Amazon. And we’ll have that on the show notes. Next week, we’re going to be talking about the Rails View. We haven't really been plugging our Book Club Book. But that’s what we’re hitting next week. And so, go read the book and we’ll catch you all next week!