Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Gemfile to Bundle

Gemfile to Bundle

Samuel E. Giddins

May 21, 2015

More Decks by Samuel E. Giddins

Other Decks in Technology


  1. From Gemfile to Bundle Samuel Giddins

  2. Samuel Giddins Realm CocoaPods Bundler RestKit

  3. how does bundler work, anyway?

  4. @indirect gave this talk: http://andre.arko.net/2015/04/28/how-does-bundler-work-anyway/

  5. But today, we’ll focus on what bundler does to transform

    your Gemfile into a full-on runtime environment
  6. So, let’s start with our humble Gemfile

  7. source "https://rubygems.org" ruby "2.2.2" gem "rails", "4.2.1" gem "devise" gem

    "fastly-rails" gem "http" gem "jquery-rails" gem "nokogiri" gem "nilify_blanks" gem "pg" gem "premailer-rails" gem "puma", "~> 2.11", ">= 2.11.2" group :development do gem "guard-livereload", "~> 2.4", require: false gem "guard-rails" gem "guard-rspec" end group :development, :test do gem "dotenv-rails", "~> 2.0" gem "pry-rails" gem "rspec-rails" end group :production do gem "rails_12factor" end group :test do gem "webmock" gem "vcr" end
  8. We now run bundle install

  9. RubyGems picks the appropriate bundler version to run

  10. bundler's CLI will dispatch to the Install command class, passing

    in any command line options we used
  11. we translate those options into settings that bundler will use

    for the lifetime of the process
  12. now starts the fun part

  13. now starts the fun part => Bundler.definition

  14. the Definition encapsulates the Gemfile & the Gemfile.lock

  15. it's what the user defines to be a part of

    the Environment
  16. Dsl.evaluate(gemfile, lockfile) => Dsl.new.instance_eval(File.read gemfile)

  17. Dsl class defines the following methods: —gemspec —gem —source —git_source

    —path —git —github —group
  18. We now perform dependency resolution with those gems, plus those

    in the lockfile
  19. Molinillo https://stripe.com/video/open-source-retreat

  20. definition.resolve => definition.specs

  21. Now it's Installer time

  22. Installer.install(Bundler.root, definition, options)

  23. ensure every one of definition.specs is installed

  24. either in parallel or sequentially

  25. spec.source.install(spec, install_options)

  26. Installation depends on the source that spec comes from

  27. Sources: —RubyGems —Path —Git

  28. aside: Sources define both how we fetch specs for resolution

    & how we install them
  29. aside: Sources have caused some security issues in the past

  30. So, we've installed all our gems. bundle install is done

  31. Next, we run bundle exec

  32. Next, we run bundle exec since we need our code

    to actually run
  33. SharedHelpers.set_bundle_environment

  34. which foo

  35. If not => Bundler.load.setup_environment

  36. Runtime.new(root, definition)

  37. Our Runtime represents....

  38. ENV["BUNDLE_BIN_PATH"] = && ENV["BUNDLE_GEMFILE"] = && SharedHelpers.set_bundle_environment

  39. Kernel.exec(@cmd, *args)

  40. This only works because we have -rbundler/setup in RUBYOPT

  41. Bundler.setup

  42. And now we just manipulate RubyGems & $LOAD_PATH

  43. Phew.

  44. Concepually simple.

  45. Unimaginable edge cases.

  46. Bundler

  47. Available now on Speaker Deck. https://speakerdeck.com/segiddins/gemfile-to-bundle

  48. self .meetup .audience .each .lazy .flat_map(&:questions) .map(&:answer)

  49. Samuel Giddins Realm @segiddins