[Script Info] Title: [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:08.51,Default,,0000,0000,0000,,(Theme Music) Dialogue: 0,0:00:13.43,0:00:16.54,Default,,0000,0000,0000,,This talk is about how Bundler works Dialogue: 0,0:00:17.99,0:00:21.13,Default,,0000,0000,0000,,How does Bundler work? Dialogue: 0,0:00:21.80,0:00:24.78,Default,,0000,0000,0000,,This is an interesting question. Dialogue: 0,0:00:25.34,0:00:27.58,Default,,0000,0000,0000,,We'll talk about it for a while. Dialogue: 0,0:00:28.52,0:00:29.69,Default,,0000,0000,0000,,This talk is a brief history of Dialogue: 0,0:00:31.84,0:00:35.84,Default,,0000,0000,0000,,dependency management in Ruby, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a discussion of how libraries and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,shared code works now and in the past Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,because how it works now is directly a result Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,of how it used to work in the past Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and trying to fix problems that happened then. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Before we get started, let me introduce myself: Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,My name is Andre Arko, I'm @indirect on all social media Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that's my avatar, maybe you've seen me on Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a webpage somewhere. As my day job Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I work at Cloud City Development doing Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Ruby, Rails, Ember, and web consulting. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,We do web and mobile development Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and I mostly do architectural consulting Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and Senior Developer pairing and training. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Talk to me if you're company is interested. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I also founded Ruby Together, a non-profit, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it's like npm incorporate without the venture capital. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Ruby Together is a trade association that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,takes money from companies and people who Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,use Ruby and Bundler and RubyGems and all Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,of the public infrastructure that Rubyists use Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and pays for developers to work on that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,so that RubyGems.org stays up, and so Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,people can have gems, which is pretty cool. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,As part of my work for Ruby Together I work as Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,lead of the Bundler team. I've been working on Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Bundler since before 1.0 came out, and I've Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,been team lead for the last four years. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Using Ruby code written by other developers, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,nowadays this is actually really easy, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you add a line to your Gemfile, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you go to your terminal and run Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,bundle install, and you start using it. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Pretty cool, that's really easy. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The thing that I've noticed, talking to people Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,who use Bundler and think it's awesome Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,is that, it's not actually clear what just happened. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Based on the text printed out by bundle install Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it seems like something got downloaded Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and something got installed, but it's not clear. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's not clear what got downloaded or Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,installed, or where it happened. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,What exactly happened there? Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Nobody is really sure. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,How does just putting a line in your Gemfile Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,mean you can just start using somebody else's code? Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,To explain that, we'll need a little bit of history. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,We're going to back in a time. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I'm going to give you a tour from the beginning of sharing Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,code in Ruby up until now. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And hopefully by the end of it you'll understand Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,why things work the way they do now. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I'm going to start talking about require, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,which came with the very first version of Ruby ever, in 1994. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And then talk about setup.rb from 2000, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and then RubyGems from 2003, and Bundler from 2009. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And that's what we're still using today. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The require method has been around since Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,1994, with the very first version of Ruby. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,What I should say is that it's been there Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,since at least 1997, since that's Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the oldest version controlled Ruby we have. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It was probably there before that though. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Require can be broken down into even Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,smaller concepts. Using code from Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a file is basically the same as inserting Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that code and having Ruby run it Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,as if you'd just written it in the file. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's actually possible to implement it yourself, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,with a one-line function. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This function says; I have a file Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,name and I want to require it, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and you read the file in the memory Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,into a string and you pass the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,string to eval, and Ruby runs it Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and it's just like you typed that code yourself. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,There are problems with this. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Require doesn't work this way in real life. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I'm sure it's totally fine that this will Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,run that same piece of code over and over Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,if you require it over and over, you like Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,having lots and lots of constants that keep Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,getting redefined, I'm sure it's totally fine. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Working around that, is pretty straightforward. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Just keep track of what you've required in an Array Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and not require something again if it' been required. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,As you can see here, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you set up an Array, you check Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to see if the Array already contains Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the filename that just got passed in, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and if hasn't been required, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,do the same thing we did before, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,read the file in, pass it to eval, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and then add it to the array, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,so it's not required again later. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,In fact, this exactly what Ruby does, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,but written in C not in Ruby. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,There is a LOADED_FEATURES global variable, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and it's an Array, and it contains a list Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,of all the required files. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you want to know if you've required something yet, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,check the LOADED_FEATURES array. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,There is one more problem with this, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it only works when you pass in absolute paths. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I'm sure you don't mind you typing the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,full path from wherever you are to Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,exactly wherever the file you want to require is. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I'm sure that's fine too. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The easiest way to allow requires that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,aren't absolute is to just treat Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,all requires as if they're relative Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to the path where you started Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the Ruby program. And that's easy, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,but that doesn't help a lot if you Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,want to require Ruby files from different places. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Say you have a folder full of a library Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you wrote and folder full of an application you wrote Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and you want to use a library from the app, you can't, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,because writing relative paths from wherever Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you started the Ruby program would be terrible. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Instead we create an Array that holds the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,list of paths we want to load we want to load Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Ruby files from, in a burst of creativity Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I'm just going to call that variable the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,LOAD_PATH, and here's an implementation. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you put something in the LOAD_PATH Array, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you can then pass a relative path to any directory Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that's in the LOAD_PATH Array, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it will look for the file. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you require "foo", it will look for a file Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,named "foo" inside any of the LOAD_PATH directories, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and if the first one we find searching Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the LOAD_PATH in order from first to last, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,we will require that one. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Coincidentally, this is exactly what Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Ruby does, there is a global variable Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,named LOAD_PATH, and if you put Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a string that contains a path to a directory Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,in it, Ruby will look in that directory Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,whenever you require something for a file Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,with that name. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You can totally use the LOAD_PATH to require Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,files from somewhere else while you're working with them. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Of course, the LOAD{\u1}PATH, and LOADED{\u0}_FEATURES Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,can both be combined, but that didn't Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,fit on a single slide, so I'll leave that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,as an exercise to the listener. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's pretty straightforward to be honest. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Load paths are pretty cool. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,They allow us to load Ruby directories Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,even if they're spread across multiple places. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,At this point, we could even Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,have automatically, at the start of every script, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the directory that holds the standard library, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to the load path, and then all of the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,files that are pretty of the Ruby standard library, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,like Net::HTTP, Set, the cool thing that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,come with Ruby, could just be available for Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,require automatically and you wouldn't have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to worry about putting them in the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,load path yourself. That's exactly Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,what Ruby does, the standard library Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,starts on the load path when Ruby starts. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's pretty great. This was cool, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,for several years, this was enough. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,People just added things to the load path. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Or wrote scripts that added things to the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,load path before requiring things before their Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,actual script happened. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The thing that got tedius out just having Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,load paths, is that if you want to get code from Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,someone else, you have to find that code, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,download it, put it somewhere, remember where, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,put it in the load path, and then require it. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This was tedious. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Setup.rb happened next. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Around the year 2000 everyone is still Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,installing share Ruby code by hand. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,That wasn't so much fun. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,A Japanese Ruby developer, Minero Aoki, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,wrote setup.rb, and amazingly, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,even though this was created in 2000, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,setup.rb is still around on the Internet. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The website for this developer is, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,i.loveruby.net, which is pretty cool, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and you can even download setup.rb, but Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to be honest, it hasn't been updated since 2005, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,so I'm not sure it's super helpful to you. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,How did setup.rb work? Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,At it's core it mimicked the classic Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,UNIX installation pattern, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,downloading a piece of software, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,decompressing it, and then running Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,configure make, and make install, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,so setup.rb kind of copied that for Ruby. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You would run ruby setup.rb setup, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,ruby setup.rb config, ruby setup.rb install Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,setup.rb would copy all the Ruby files, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,there was a specific directory structure, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,kind of like a Gem today, with Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,library files, and bin files you could run as programs, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and support files, and setup.rb would Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,copy all of those files into a directory Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that was already in the load path called, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,site ruby, and that was the ruby files Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you had installed that were specific Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to your computer. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,After setup.rb, using Ruby libraries Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,was much easier than it had been. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You could find a library online, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,download it, you had to untar it by hand, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and run ruby setup.rb all by hand, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,but then it was all installed, and no more Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,manual copying, no more having to Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,manage all these files. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Everything was in the load path, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you could just require it after setup.rb ran. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,After a little while, some of the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,shortcomings of this scheme became apparent, too. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,There were no versions for any libraries, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and after you run setup.rb there's not even Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a way to tell what version you have, unless Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you write it down, or the library author Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,was really nice, and put the version into Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the code somehow. There was no way Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to uninstall, everything thrown into Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the same directory. You'd run setup.rb Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,for 5 different Ruby libraries and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,now all of their files are in one directory. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Good luck figuring out which ones belongs to which. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you delete the wrong one, too bad. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Upgrading was super fun, if there was Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a new version of the library, which Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,good luck finding that out, you Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,have to remember the website you got Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it from in the first place. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I hope you write all these down. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I hope you've written down every Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,website you've ever downloaded Ruby from. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You have to go back to that website, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,remember which version you have, which Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,as I said before, there's nothing there unless Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you wrote it down. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And then you have to download the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,tarball with the new version, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,decompress it, and CD into it and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,run ruby setup.rb on it all, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,hope that the new version didn't delete Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,any files because the old files are still there. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This was tedious, it was really tedious. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,People frequently had no idea what Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,was actually happening with their libraries. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It was not uncommon for people to be like Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,"Oh this doesn't work, I'll just fix it Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,in my site ruby directory, ok everything Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,is great now" Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Super awesome. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,At some point, some people were like Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,this is not great. What if you could just Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,gem install. That would be cool. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And so in 2003, RubyGems came to the rescue. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And fixed all of the problems with setup.rb Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that were known. You could check Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to see if a library existed by running gem list, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,install a gem by gem install, uninstall gems. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,RubyGems kept each of these libraries in different directories. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You knew which libraries you had, and how to uninstall Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and install new versions, all with one command. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,No having to find it on the internet somewhere, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,download, and unpack it, setup.rb it. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And RubyGems had another super cool trick Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,up it's sleeves -- versions. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,RubyGems actually kept each version of each Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,gem in a different place. You could install Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,multiple versions of the same library. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And they could all be in your Ruby Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,because they didn't all go into one giant folder, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,they went into their own separate folders. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Folders for rails 4.1, 4.2, and 5.0. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,To make this work, because require doesn't Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,support versioning, inherently, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,RubyGems added a gem method that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,let's you say, I need version 1.0 of rack, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and RubyGems will check to make sure it's Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,installed, put that directory, just the one Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,with rack 1.0 into your load path. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,So when you run require "rack" you'll Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,get rack 1.0, it's pretty cool. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Calling the gem method, told RubyGems Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you wanted to manipulate the load path to Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,load exactly the version you knew your Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,code wanted to talk to. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It was pretty useful. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,RubyGems also has a way to support Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,versioning even in commands that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,come with gems. The rack gem Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,comes with the rackup command, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,if you have multiple versions of rack installed, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the rack command could run any of those versions. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,RubyGems defaults to the newest version you have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,installed, hoping the newest is the right one. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,But if that's not, RubyGems checks the first Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,argument to the command for something Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,with underscores on either sides, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it takes that as the version number Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that you want to use. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,In the above example, we're running Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,rackup from rack version 1.2.2, and only 1.2.2. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you don't have that version installed, RubyGems will Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,make you install that version first. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,RubyGems was really, really successful. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Ruby grew in popularity a lot, but RubyGems Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,made sharing Ruby code grow a lot. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Present day we have 100,000 gems, with 1,000,000 versions. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,That's a lot of shared Ruby code. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You probably knew this was coming, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,but as cool as RubyGems is, it still had Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,some problems. If you have multiple Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,applications that all use RubyGems to load Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,their dependencies, this can be problematic. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's hard to coordinate across multiple applications Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,because, each installation of Ruby itself just has Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a set of gems. If you ran gem install, now Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,there are all these gems. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If one developer runs gem install "foo" and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,starts using "foo" in their application, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,commits that code and checks it in, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and the next person checks it out Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and tries to run the application, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it's going to explode, because it doesn't Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,know what foo is, you need to fix that. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It led to an area of pure manual dependency management. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Start a new job, hooray! Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This literally happened to me in 2008. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,New job, welcome to the team, here's Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,your cool new laptop, we Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,except you to have the application Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,running by next week. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It actually took me only 3 and a half days, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,working overtime on this. It was amazing. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,[Audience Laughs] Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,To figure out which gems to run gem install, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I looked in the README and there Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,was a list. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And I installed all of them. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,But clearly there was some that people Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,forgot to put in the README, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,then it kind of worked, but I wasn't Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,able to get images working. And then Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,some other developer was like, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you need to install imagemagick, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,this was before homebrew. It was terrifying. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,To try and fix this problem, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,of do we just put the gems in the README? Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,How do we know if we have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,written everything in the README? Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,"I don't know? Try it?" Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Of course, you'd need a new machine Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to try it on, because after 3 years Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,of using Ruby you generally have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,installed every gem, and you have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,no idea what's important and what's not. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's terrible. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,People started to work on tools to help this problem. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Rails added config.gem, this is Rails 2.3, 2.4 era. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You would put all the gems you need in application.rb Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This was super helpful if you needed Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to know for sure this was the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,master list of all the gems Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you needed in your application, but Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you could only access that list when Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Rails was already loaded. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It was pretty bad. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Because RubyGems automatically uses Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the newest version of each gem, just having Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,an older version installed, didn't mean it Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,would be used. And if you install Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,some gem a month after the other person did, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,maybe there's a new version? You would Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,just get the new version automatically. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This is also totally a real-life experience that happened to me in 2009. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Debug a production server that just randomly throws exceptions. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,For three days. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The other production servers are fine. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,We can't reproduce this problem on a single developer laptop. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,What is going on? This is so weird. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,After 3 days I finally thought to look at Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the output from the gemlist for the entire production Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,machine and I was like, oh this production Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,server has gem version 1.1.3 and every Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,other production server and developer laptop has 1.1.4. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,That was the problem. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,There was a bug and only that server Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,had this problem. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And then, like I was saying, about Rails versions, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you could gem install rails, be happy, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,make a new app, run your server, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,everything is great. And then Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you switch to another application Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that already existed, didn't get Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,written to use that version of rails, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,got writen to use some older version of rails. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You're like, "Okay, let's go!" Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,"Boom", because you didn't have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the right version of Rails. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you put your rails version in the rails config Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,rails would complain you had the wrong version, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,but rails had to be successfully started up to Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,tell you that you had the wrong version, so Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it didn't actually help. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Ultimately, it was a significant part of my job Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to figure this shit out by hand, and it sucked. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Depending on what you did on your team, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,some people on my team at the time spent Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a quarter or a third of their time Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,doing nothing but figuring out and fixing Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,dependency management issues. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And I felt really, really bad for them. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Sometimes it was me and I felt really bad for me. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Then there's one more, even after, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you've done all of this by hand management, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,there's one more problem that RubyGems has Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that is another reason why bundler was created. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Activation Errors, they happen in ruby gems Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,when you load an application and start by Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,requiring gems, ruby gems will load the newest Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,versions of those gems that it can. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Sometimes a gem's dependents need Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,other gems, that need other gems, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and you'll get the newest version of the Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,child gem. And later you'll say, I also Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,need this gem, but that gem won't work with the other. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,So how common can this be really? Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Unfortunately, it was super common. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Not like happens to you every day common, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,but like happens you two or three times a year Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and when it does you basically tear Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,all your hair out, delete your entire Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,ruby install, uninstall and reinstall all your gems, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,because figuring out exactly which combo Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,of installed gems was causing this Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,problem was a total nightmare. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This is a real-life activation error. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I salvaged this from a presentation I gave in 2010 Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,about why Bundler exists. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This is a rails app, it's loading, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,rails of course depends on ActionPack, this Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,was the Rails 2.3 era, ActionPack depends on Rack, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Rack is a gem that helps Rails talk to web servers. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And thin, which is a web server, also depends on rack. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,So, rack is how rails talks to thin, how thin Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,talks to rails, but there's a problem. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,thin is perfectly happy to use rack 1.1, which makes some Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,changes to how rack works. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,ActionPack is not happy to use rack 1.1, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,can only use rack 1.0. And so Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,when you run your server, it loads thin Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,first because thin is the server. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And thin gets to work trying to load the rails app Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and your rails app says "I can't use that rack, sorry" Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The reason this happens is runtime resolution. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,RubyGems figures out which versions Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,of which gems of which gems it should load. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,After RubyGems is already running. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You say, "Hey I need a thing", and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it's like "Okay, this version might work". Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And if later on you say, \N Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,"I need a thing that doesn't work with things you've already done" Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,RubyGems just has to be like, can't fix that. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The fix for this problem is to figure out all the versions Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,before you run your application. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You have to know the versions you're going Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to use are all versions that can work together. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Resolving things at install time, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,knowing you're installing versions that work together. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,How do we make sure all the versions we're Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,installing work together? Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,That's actually where Bundler comes in. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Before Bundler, the process of figuring out Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,which gems would work together Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,was done entirely by hand and it Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,consisted of gem uninstall, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,gem install a slighty older version, does rails start up yet? Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Repeat the process. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,When the exception stopped you knew you'd won. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Unsurprisingly, computers are faster at this than people. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Computers are also good and accurate at trying Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,many, many, many options until one works. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This is what Bundler does. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Bundler figures out the entire list of every gem Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and every version of every gem that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you need, but that also all Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,work together with one another. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This is called Dependency Graph Resolution, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and there's an entire academic literature about this. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's kind of well-known hard problem, it's Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,part of the set of problems called NP complete, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and the totally fantastic thing, and I say Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,this as a person who has to fix Bundler Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,when it doesn't work, in theory, you can construct Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a set of gems in a gemfile such that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it is not possible to find a set of gems that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,work together until after the heat death of the universe. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,[Audience Laughs] Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Most of the time we don't have that long to wait. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,We use a lot of tricks, shortcuts, and heuristics Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to figure out which gems to try first and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,hopefully finish before you've drunk Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that cup of coffee or whatever. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,We have a large built-up set of tricks over the years Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and most Gemfiles resolve in less than 10 seconds. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Which is pretty cool, considering the upper bound Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,on that is practically infinity. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,After finding versions that work together Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,because this problem was really hard, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and we don't want to do this over and over. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Bundler writes down the exact versions of every gem Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that did all work together, so they can be reused Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,by other people who are also interested in running Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,your application. That file is called Gemfile.lock. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Shows which gems to be installed, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the versions to install, and as a bonus Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the lock file is what makes it possible Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to install the exact same version of every Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,gem on every machine that's running this application. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,That means when you develop on your laptop Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,you get whatever version of the gem that was Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,newest when you were developing because run Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,bundle install and got newest version by default. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Because of the lock file, when you put Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that on your production server, you're guaranteed Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to have the same versions. And you won't Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,have to spend 3 days figuring out why Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that production server doesn't quite Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,work all of the time. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's pretty great. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Fundamentally, the core of bundler consist of two steps. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,bundle install, and bundle exec. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The steps for bundle install are simple. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,They're totally understandable in plain english Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It fits on a single slide, which is great. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I edited this slide for ten minutes deleting words. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,So the steps are: Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,1. Read the Gemfile Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,2.Ask RubyGems.org for a list of all the gems we need Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,3. Find versions of those gems both allowed by Gemfile Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,4. Once found, write all those down in lock and install them all. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And that's how bundle install works. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,BundleInstall uses RubyGems under the covers Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to the installation, and so every Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,bundle is it's own little rubygems isolated install. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Every application has it's own rubygems thanks to bundler. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The next step is bundle exec. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,This is how we use that applications dedicated ruby gems Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,instead of the one with whatever in it Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,because you ran gem install last year. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The way bundle exec works is: Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,1. Reads the Gemfile, and lock if it's there. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,2a. Use locked gems if possible OR Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,2b. Find versions that work together like install would. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,except bundle exec doesn't do any installing. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,3. Deletes any existing gems in the LOAD_PATH Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,4. Adds the exact gem at the exact version at the load path. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,That's it. That's all bundle exec does. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Once all the gems work together, and Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,there exact versions are in the load path Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,your application is happy. There is no Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,activation errors, all your requires succeed, I hope. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Everything is pretty great. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,As I think I promised in the abstract for this talk, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,here's a bundle exec removing pro tip. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I don't really like typing bundle exec, I find it Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,really annoying, but bundler provides a way Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to not have to type it all the time. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And it's to create programs that map to Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,ruby gems installation that Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,belongs to that application. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,You can use the binstubs command, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,bundle binstubs [some gem] Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and it will create, in the bin directory, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,a program for that gem, that only Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,runs the exact version that belongs to Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that application. So if you have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,rspec in your rails app, you can have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,bin/rspec that will only load the rspec Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,for your app. This way you can have Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,bin/rspec refer to rspec 3, and this application Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,can have rspec 2. Rails has started to do this. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Rails 4 ships with bin/rails bin/rake that are scoped Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,so when you run bin/rails, you get the exact Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,rails version for this application and not another one. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,When you run bin/rake you get the exact version of rake. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Pretty cool, no more bundle exec. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If everyone did this, you can check in these binstubs Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,so you can take bin/rspec, but it in git, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and it'll be mapped to that application forever, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,so no one would have bundle exec Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,ever again if everyone did this. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Now we bundle install, all our gems Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,show up. We have versions Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,dedicated for individual applications. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,But, as you probably sensed a problem Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,going through history, that wasn't actually Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the end. There are still problems Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that show up after bundler came out. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,The biggest problem that was left was Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,running bundle install, took forever. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you lived a long time from the United States Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,it took a really long time. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I talked to some developers in South Africa Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,when I went there to give a talk Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and they told me about how running Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,bundle install means they literally get Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,up to start making a cup of coffee Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that they can finish before bundle install does. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,To try and speed things up, bundler 1.1 Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,created a completely different Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,way to get information from rubygems about gems. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,And that sped things up by 50%, a big win. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,We keep working on this, bundler 1.9 just Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,came out this month. There's a bunch more Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,improvements we're working on. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you're interested in following along with that, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,the bundler websites has news annoucements Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,at bundler.io, and twitter we're also @bundlerio. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,Having said all of this, if you use Bundler, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I would totally love to have your help working on it. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's an open source project. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,We've dedicated a lot of time to making it easy Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,for people who don't know how to do open source Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,to help with Bundler, and to start working on Bundler, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and to get into open source that way. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,It's a project at Github.com/bundler/bundler. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you're interested but don't know where to start Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,email the bundler team at team@bundler.io Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and we'll get you set up. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,On the other hand, if you Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,have a job that means you have money, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,but not time, join Ruby Together, and give Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,us money, and we'll work on Bundler, and it'll be Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,better. As RubyTogether grows, we will also be Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,tackling bigger community issues. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,We want to add easy to use gem mirrors so you Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,don't have to go all the way to rubygems.org Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,for your office or data center, we want to Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,add better public benchmarks. There's a project Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,calling ruby-bench that's starting to do that, Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,and we'd really like to expand it. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,There's a bunch of other things Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,that RubyTogether is working on that are cool Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,If you want Bundler or RubyTogether stickers Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,I have a giant pile, so find me later. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,That's it. Dialogue: 0,9:59:59.99,9:59:59.99,Default,,0000,0000,0000,,[Audience Applause]