├── pry-debundle.gemspec ├── LICENSE.MIT ├── README.md └── lib └── pry-debundle.rb /pry-debundle.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = "pry-debundle" 3 | s.version = "0.8" 4 | s.platform = Gem::Platform::RUBY 5 | s.author = "Conrad Irwin" 6 | s.email = "conrad.irwin@gmail.com" 7 | s.license = "MIT" 8 | s.homepage = "http://github.com/ConradIrwin/pry-debundle" 9 | s.summary = "Allows you to use gems not in your Gemfile from Pry." 10 | s.description = "Hooks into Pry and removes the restrictions on loading gems imposed by Bundler only when you're running in interactive mode." 11 | s.files = `git ls-files`.split("\n") 12 | s.require_path = "lib" 13 | s.add_dependency 'pry' 14 | end 15 | -------------------------------------------------------------------------------- /LICENSE.MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Conrad Irwin 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `pry-debundle` allows you to require gems that are not in your `Gemfile` when inspecting 2 | programs that are run with Bundler. 3 | 4 | Usage 5 | ===== 6 | 7 | Use the `pry` command, or `binding.pry` as normal. Watch how you can require any gem, even if it's not in your `Gemfile` and celebrate! Avoid getting confused by that fact when trying to debug `'require'` statements. 8 | 9 | 10 | Installation 11 | ============ 12 | 13 | Add `pry` and `pry-debundle` to the Gemfile. These are both required, and have few (if 14 | any) ill effects for developers who don't wish to use them. 15 | 16 | ```ruby 17 | group :development do 18 | gem 'pry' 19 | gem 'pry-debundle' 20 | # other development gems everyone needs go here. 21 | end 22 | ``` 23 | 24 | If you need to install these gems without buy-in from the rest of your team (sad panda) 25 | there are instructions under Personal Installation. 26 | 27 | 28 | Long-winded Explanation 29 | ======================= 30 | 31 | Bundler is an awesome gem that gives you a good degree of confidence that "if it works in 32 | development, it works in production". It can do this by being vicious about gem 33 | dependencies: if it's not in the `Gemfile`, it's not getting required. It also ensures 34 | that everyone's development environment is identical, no more does "it works on my 35 | machine" cut it as an excuse. 36 | 37 | There are circumstances when this dogmatic dedication to duty can get in the way. In 38 | particular all good developers have set up their development environment very personally. 39 | Obviously, it's not important that my local tools work in production, and it's positively 40 | bad for productivity if everyone is forced to have an identicial development setup. 41 | 42 | So how do you reconcile these two points of view: "it should work the same everywhere", 43 | and "it should be ideal for me"? 44 | 45 | The obvious answer is to compromise; mostly "it should work the same everywhere", but when 46 | I'm actively working on it (i.e. I have my `Pry` open) "it should be ideal for me". 47 | 48 | To this end, `pry-debundle` will do nothing (I mean absolutely nothing) until you start 49 | pry. At that point, the chains locking you into the Bundler jail are hacked asunder, and 50 | immediately your precious pry plugins load, and all of those random gems you've 51 | collected will be available to `require` as normal. 52 | 53 | Before you rush off to try this, a word of warning: you will waste debugging time because 54 | of this. Why? Because running a `require 'ampex'` inside Pry works, but running a `require 55 | 'ampex'` outside Pry doesn't. "XOMGWTF? Ohhhh! GAH!!" I hear your future self cry as you 56 | forget this warning, and then painfully recall it. 57 | 58 | As the adage goes: "No gain, without pain". 59 | 60 | 61 | Personal Installation 62 | ===================== 63 | 64 | So let's say everyone on your team wants to use pry, but some of them are too scared to 65 | use `pry-debundle`. This is pretty easy to support. Just add Pry to the Gemfile as 66 | before, and then copy the implementation of the gem into your ~/.pryrc 67 | 68 | ```ruby 69 | group :development do 70 | gem 'pry' 71 | # other development gems everyone needs go here. 72 | end 73 | ``` 74 | 75 | ```bash 76 | curl https://raw.githubusercontent.com/ConradIrwin/pry-debundle/master/lib/pry-debundle.rb >> ~/.pryrc 77 | ``` 78 | 79 | If you can't even persuade people to allow you to add Pry to the Gemfile, then you can 80 | write a little wrapper script to run your app to make sure Pry is loaded before Bundler, 81 | and install `pry-debundle` into your ~/.pryrc as above. 82 | 83 | Meta-fu 84 | ======= 85 | 86 | Licensed under the MIT license (see `LICENSE.MIT`). Bug reports and pull requests are 87 | welcome. 88 | 89 | It's possible that Bundler will solve this issue themselves, in which case I expect to 90 | deprecate this gem. See https://github.com/carlhuda/bundler/issues/183 for some 91 | discussion. 92 | -------------------------------------------------------------------------------- /lib/pry-debundle.rb: -------------------------------------------------------------------------------- 1 | # Copyright (c) Conrad Irwin -- MIT License 2 | # Source: https://github.com/ConradIrwin/pry-debundle 3 | # 4 | # To install and use this: 5 | # 6 | # 1. Recommended 7 | # Add 'pry' to your Gemfile (in the development group) 8 | # Add 'pry-debundle' to your Gemfile (in the development group) 9 | # 10 | # 2. OK, if colleagues are wary of pry-debundle: 11 | # Add 'pry' to your Gemfile (in the development group) 12 | # Copy this file into ~/.pryrc 13 | # 14 | # 3. Meh, if colleagues don't like Pry at all: 15 | # Copy this file into ~/.pryrc 16 | # Create a wrapper script that runs `pry -r` 17 | # 18 | # 4. Pants, if you don't like Pry: 19 | # Copy the definition of the debundle! method into your ~/.irbrc 20 | # Call 'debundle!' from IRB when you need to. 21 | # 22 | class << Pry 23 | 24 | # Break out of the Bundler jail. 25 | # 26 | # This can be used to load files in development that are not in your Gemfile (for 27 | # example if you want to test something with a tool that you have locally). 28 | # 29 | # @example 30 | # Pry.debundle! 31 | # require 'all_the_things' 32 | # 33 | # Normally you don't need to cal this directly though, as it is called for you when Pry 34 | # starts. 35 | # 36 | # See https://github.com/carlhuda/bundler/issues/183 for some background. 37 | # 38 | def debundle! 39 | return unless defined?(Bundler) 40 | loaded = false 41 | 42 | if rubygems_18_or_better? 43 | if Gem.post_reset_hooks.reject!{ |hook| hook.source_location.first =~ %r{/bundler/} } 44 | Bundler.preserve_gem_path 45 | Gem.clear_paths 46 | Gem::Specification.reset 47 | remove_bundler_monkeypatches 48 | loaded = true 49 | end 50 | 51 | # Rubygems 1.6 — TODO might be quite slow. 52 | elsif Gem.source_index && Gem.send(:class_variable_get, :@@source_index) 53 | Gem.source_index.refresh! 54 | remove_bundler_monkeypatches 55 | loaded = true 56 | 57 | else 58 | raise "No hacks found :(" 59 | end 60 | rescue => e 61 | puts "Debundling failed: #{e.message}" 62 | puts "When reporting bugs to https://github.com/ConradIrwin/pry-debundle, please include:" 63 | puts "* gem version: #{Gem::VERSION rescue 'undefined'}" 64 | puts "* bundler version: #{Bundler::VERSION rescue 'undefined'}" 65 | puts "* pry version: #{Pry::VERSION rescue 'undefined'}" 66 | puts "* ruby version: #{RUBY_VERSION rescue 'undefined'}" 67 | puts "* ruby engine: #{RUBY_ENGINE rescue 'undefined'}" 68 | else 69 | load_additional_plugins if loaded 70 | end 71 | 72 | # After we've escaped from Bundler we want to look around and find any plugins the user 73 | # has installed locally but not added to their Gemfile. 74 | # 75 | def load_additional_plugins 76 | old_plugins = Pry.plugins.values 77 | Pry.locate_plugins 78 | new_plugins = Pry.plugins.values - old_plugins 79 | 80 | new_plugins.each(&:activate!) 81 | end 82 | 83 | private 84 | 85 | def rubygems_18_or_better? 86 | defined?(Gem.post_reset_hooks) 87 | end 88 | 89 | def rubygems_20_or_better? 90 | Gem::VERSION.to_i >= 2 91 | end 92 | 93 | # Ugh, this stuff is quite vile. 94 | def remove_bundler_monkeypatches 95 | if rubygems_20_or_better? 96 | load 'rubygems/core_ext/kernel_require.rb' 97 | else 98 | load 'rubygems/custom_require.rb' 99 | end 100 | 101 | if rubygems_18_or_better? 102 | Kernel.module_eval do 103 | def gem(gem_name, *requirements) # :doc: 104 | skip_list = (ENV['GEM_SKIP'] || "").split(/:/) 105 | raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name 106 | spec = Gem::Dependency.new(gem_name, *requirements).to_spec 107 | spec.activate if spec 108 | end 109 | end 110 | else 111 | Kernel.module_eval do 112 | def gem(gem_name, *requirements) # :doc: 113 | skip_list = (ENV['GEM_SKIP'] || "").split(/:/) 114 | raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name 115 | Gem.activate(gem_name, *requirements) 116 | end 117 | end 118 | end 119 | end 120 | end 121 | 122 | # Run just after a binding.pry, before you get dumped in the REPL. 123 | # This handles the case where Bundler is loaded before Pry. 124 | # NOTE: This hook happens *before* :before_session 125 | Pry.config.hooks.add_hook(:when_started, :debundle){ Pry.debundle! } 126 | 127 | # Run after every line of code typed. 128 | # This handles the case where you load something that loads bundler 129 | # into your Pry. 130 | Pry.config.hooks.add_hook(:after_eval, :debundle){ Pry.debundle! } 131 | --------------------------------------------------------------------------------