hairballs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4d0f86e9c3d02f22b832c4b3edce907001d0db2f
4
+ data.tar.gz: 7ddc281fd14c1d9c673b59bd6ca1f218e1722f2a
5
+ SHA512:
6
+ metadata.gz: 0ed4bf7812d457c37d006c4b6b065a6a05df37aba2991f77fa261aa2939bc51ef1df35a55d861a75b5fc93ffe556d4a102a618f99f84dc4126a174679fa4311b
7
+ data.tar.gz: 11bf1690a4fd0c528223c4608bbc757a17720f64dfdc137ffe58abae6e505499c790e32c711203f2d768fabfe09900b6c0f6b9872dbb5da9539e50164f211c53
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hairballs.gemspec
4
+ gemspec
data/History.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2014-12-19
2
+
3
+ * Happy Birthday!
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Steve Loveless
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,250 @@
1
+ hairballs
2
+ =========
3
+
4
+ Aka, "haIRBalls". Like [oh-my-zsh](http://ohmyz.sh), but for IRB.
5
+
6
+ wat
7
+ ---
8
+
9
+ haIRBalls is a framework for managing your IRB configuration.
10
+
11
+ Installation
12
+ ------------
13
+
14
+ For non-Bundlered apps, install it yourself as:
15
+
16
+ $ gem install hairballs
17
+
18
+ For Bundlered apps, you have a couple options:
19
+
20
+ 1. Add `gem 'hairballs'` to your Gemfile.
21
+ 1. Manually add `hairballs` to the load path:
22
+
23
+ ```ruby
24
+ hairballs_path = Dir.glob("#{Gem.dir}/gems/hairballs-*/lib")
25
+ $LOAD_PATH.unshift(hairballs_path.first) unless hairballs_path.empty?
26
+ require 'hairballs'
27
+ ```
28
+
29
+ Usage
30
+ -----
31
+
32
+ Hairballs provides you with methods and such for creating "themes" and "plugins"
33
+ that you add in to your IRB sessions.
34
+
35
+ ### Themes ###
36
+
37
+ Initially *themes* are for defining an IRB prompt using a cleaner API than the
38
+ one provide by IRB. They are a) reusable and b) can be switched on the fly,
39
+ without requiring a reload of IRB. Hairballs also provides methods for dealing
40
+ with dependencies and getting those dependencies to play nice with Bundler.
41
+
42
+ **Example: A Rails Theme**
43
+
44
+ This:
45
+
46
+ ```ruby
47
+ # ~/.irbrc
48
+
49
+ # Specify dependencies.
50
+ libraries = %w[irb/completion awesome_print wirble looksee]
51
+
52
+ libraries += case RUBY_PLATFORM
53
+ when /mswin32|mingw32/
54
+ %w[win32console]
55
+ when /darwin/
56
+ %w[terminal-notifier]
57
+ else
58
+ []
59
+
60
+ # Only setup prompt if Rails.
61
+ if ENV['RAILS_ENV'] || defined? Rails
62
+ # Allow non-Gemfile deps to work with Rails.
63
+ if defined?(::Bundler)
64
+ all_global_gem_paths = Dir.glob("#{Gem.dir}/gems/*")
65
+
66
+ all_global_gem_paths.each do |p|
67
+ gem_path = "#{p}/lib"
68
+ $:.unshift(gem_path)
69
+ end
70
+ end
71
+
72
+ # Setup the prompt.
73
+ rails_root = File.basename(Dir.pwd)
74
+
75
+ IRB.conf[:PROMPT][:RAILS] = {
76
+ AUTO_INDENT: true,
77
+ PROMPT_I: "#{rails_root}> ",
78
+ PROMPT_S: "#{rails_root}❊%l> ",
79
+ PROMPT_C: "#{rails_root}⇥ %i> ",
80
+ PROMPT_N: "#{rails_root}⇥ %i> ",
81
+ RETURN: "➥ %s\n"
82
+ }
83
+ IRB.conf[:PROMPT_MODE] = :RAILS
84
+ end
85
+
86
+ # Require/install dependencies.
87
+ libraries.each do |lib|
88
+ retry_count = 0
89
+
90
+ begin
91
+ break if retry_count == 2
92
+ puts "Requiring library: #{lib}"
93
+ require lib
94
+ rescue LoadError
95
+ puts "#{lib} not installed; installing now..."
96
+ Gem.install lib
97
+ retry_count += 1
98
+ retry
99
+ end
100
+ end
101
+ ```
102
+
103
+ ...becomes this:
104
+
105
+ ```ruby
106
+ # hairballs/themes/turboladen_rails.rb
107
+ Hairballs.add_theme(:turboladen_rails) do |theme|
108
+ theme.libraries do
109
+ libs_to_require = %w(irb/completion looksee wirble awesome_print)
110
+
111
+ libs_to_require +
112
+ case RUBY_PLATFORM
113
+ when /mswin32|mingw32/
114
+ %w(win32console)
115
+ when /darwin/
116
+ %w(terminal-notifier)
117
+ else
118
+ []
119
+ end
120
+ end
121
+
122
+ theme.extend_bundler = true
123
+
124
+ theme.prompt do |prompt|
125
+ preface = Hairballs.project_name
126
+
127
+ prompt.auto_indent = true
128
+ prompt.normal = "#{preface}> "
129
+ prompt.continued_string = "#{preface}❊%l> "
130
+ prompt.continued_statement = "#{preface}⇥ %i> "
131
+ prompt.indented_code = "#{preface}⇥ %i> "
132
+ prompt.return_format = "➥ %s\n"
133
+ end
134
+ end
135
+
136
+ # ~/.irbrc
137
+ require 'hairballs/themes/turboladen_rails'
138
+
139
+ if Hairballs.rails?
140
+ Hairballs.use_theme(:turboladen_rails)
141
+ end
142
+ ```
143
+
144
+ In the end, your .irbrc is cleaned up and the theme used there can be reused and
145
+ maintained separately. Check out the `Hairballs::Theme` docs and existing
146
+ themes under lib/hairballs/themes/ for more details and ideas.
147
+
148
+ ### Plugins ###
149
+
150
+ *Plugins* are similar to *themes* in that they let you abstract away some code
151
+ from your .irbrc, thus making it cleaner and more maintainable. The essence of
152
+ plugins, however, is to allow you to change the behavior of or add behavior to
153
+ IRB; this could mean things like:
154
+
155
+ * Installing and configuring dependencies for IRB use.
156
+ * Adding helper methods to your IRB session.
157
+ * Adding methods to certain objects, say, for debugging.
158
+ * Changing how certain objects are displayed when returned from methods.
159
+
160
+ **Example: Wirble**
161
+
162
+ Wirble has been around for years and I still like it for colorizing returned
163
+ objects in IRB. Using a Hairballs plugin for wrapping this a) ensures wirble
164
+ is installed any time I want to use it, and b) runs the initializing of wirble
165
+ but keeps the code for doing so outside of my .irbrc.
166
+
167
+ ```ruby
168
+ # hairballs/plugins/wirble.rb
169
+ Hairballs.add_plugin(:wirble) do |plugin|
170
+ plugin.libraries %w(wirble)
171
+
172
+ plugin.on_load do
173
+ Wirble.init
174
+ Wirble.colorize
175
+ end
176
+ end
177
+
178
+ # ~/.irbrc
179
+ require 'hairballs/plugins/wirble'
180
+
181
+ Hairballs.load_plugin(:wirble)
182
+ ```
183
+
184
+ Check out the Hairballs::Plugin docs and existing plugins under
185
+ lib/hairballs/plugins/ for more details and ideas.
186
+
187
+ I've got my `.irbrc` (using Hairballs) stored on the interwebs
188
+ [here](https://github.com/turboladen/config_files/blob/master/.irbrc) if
189
+ that's of any help or interest.
190
+
191
+ But whyyyy?
192
+ --------
193
+
194
+ There's some similar tools out there, but they seemed overly complicated. IRB
195
+ is a tool for doing development and those, in my opinion, should be as simple
196
+ and straightforward as possible.
197
+
198
+ **tl:dr**
199
+
200
+ I wanted to...
201
+
202
+ * abstract away some of IRB's weirdness.
203
+ * manage IRB dependencies based on my preferences.
204
+ * for Bundler apps, use gems in IRB without having to add them to your Gemfile.
205
+ * keep `.irbrc` clean. Make helpers reusable.
206
+
207
+ **Moar explain.**
208
+
209
+ Some problems I faced:
210
+
211
+ * Rails console loads ~/.irbrc. If you have gem dependencies in there, you
212
+ have to add them to your Gemfile to add them to the bundle.
213
+ * This doesn't make sense to me. You shouldn't make the others that are
214
+ developing that app with you use gems for *your* IRB configuration.
215
+ * *Solution:* `Hairballs::LibraryHelpers#libraries` and
216
+ `Hairballs::LibraryHelpers#require_libraries`, which are available to *Themes*
217
+ and *Plugins*.
218
+ * I want different prompt styles for regular ol' IRB vs Rails console.
219
+ * *Solution:* `Hairballs::Theme`s.
220
+ * Customizing my prompt(s) felt so clunky!
221
+ * *Solution:* `Hairballs::Theme`s.
222
+ * Installing and using new Rubies then running IRB meant I had to exit out and
223
+ manually install them all.
224
+ * zzzzzzzz...
225
+ * *Solution:* `Hairballs::LibraryHelpers#libraries` and
226
+ `Hairballs::LibraryHelpers#require_libraries`.
227
+ * I kept having problems with IRB and history getting all out of order--usually
228
+ with Rails. I was using `'irb/history'`, but trying to figure out what was
229
+ wrong was difficult since my .irbrc had become a sprawling mass of one-off
230
+ methods and blocks.
231
+ * *Solution:* `hairballs/plugins/irb_history`. This sets up IRB to use its
232
+ `*HISTORY*` settings properly and cleanly.
233
+ * Specifying gems as IRB dependencies for different Ruby interpreters is simple
234
+ but can clutter up your .irbrc.
235
+ * Putting the deps with the plugin or theme that needs them keeps everything
236
+ together and out of the .irbrc.
237
+ * *Solution:* *Themes* and *Plugins* let you specify only the gems you need
238
+ for those items. Logic surrounding that (ex. platform-specific) is kept
239
+ out of your .irbrc.
240
+
241
+ Contributing
242
+ ------------
243
+
244
+ Your themes and plugins are welcome!
245
+
246
+ 1. Fork it ( https://github.com/turboladen/hairballs/fork )
247
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
248
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
249
+ 4. Push to the branch (`git push origin my-new-feature`)
250
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new
data/hairballs.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hairballs/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'hairballs'
8
+ spec.version = Hairballs::VERSION
9
+ spec.authors = ['Steve Loveless']
10
+ spec.email = ['steve.loveless@gmail.com']
11
+ spec.summary = 'Like oh-my-zsh, but for IRB.'
12
+ spec.description = 'Some tools for making customizing your IRB sessions a little easier.'
13
+ spec.homepage = 'https://github.com/turboladen/hairballs'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(spec)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.7'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'rspec', '~> 3.1'
24
+ end
@@ -0,0 +1,22 @@
1
+ class Hairballs
2
+ class PluginNotFound < RuntimeError
3
+ def initialize(plugin_name)
4
+ message = "Plugin not found: :#{plugin_name}."
5
+ super(message)
6
+ end
7
+ end
8
+
9
+ class PluginLoadFailure < RuntimeError
10
+ def initialize(plugin_name)
11
+ message = "Unable to load plugin: :#{plugin_name}."
12
+ super(message)
13
+ end
14
+ end
15
+
16
+ class ThemeUseFailure < RuntimeError
17
+ def initialize(theme_name)
18
+ message = "Theme not found: :#{theme_name}."
19
+ super(message)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ module Kernel
2
+ # Does a puts only if IRB is in verbose mode.
3
+ def vputs(*messages)
4
+ messages.map! { |m| "[Hairballs] #{m}" }
5
+ puts(*messages) if defined?(::IRB) && ::IRB.conf[:VERBOSE]
6
+ end
7
+ end
@@ -0,0 +1,85 @@
1
+ class Hairballs
2
+ # Helpers specifying and requiring dependencies for Themes and Plugins.
3
+ module LibraryHelpers
4
+ # @param libs [Array<String>]
5
+ def libraries(libs=nil)
6
+ return @libraries if @libraries && libs.nil?
7
+
8
+ @libraries = block_given? ? yield : libs
9
+
10
+ unless @libraries.is_a?(Array)
11
+ fail ArgumentError,
12
+ "Block must return an Array but returned #{@libraries}."
13
+ end
14
+
15
+ @libraries
16
+ end
17
+
18
+ # Requires #libraries on load. If they're not installed, install them. If
19
+ # it can't be installed, move on to the next.
20
+ def require_libraries
21
+ return if @libraries.nil?
22
+
23
+ @libraries.each do |lib|
24
+ retry_count = 0
25
+
26
+ begin
27
+ next if retry_count == 2
28
+ vputs "Requiring library: #{lib}"
29
+ require lib
30
+ rescue LoadError
31
+ puts "#{lib} not installed; installing now..."
32
+ Gem.install lib
33
+
34
+ if Hairballs.rails?
35
+ installed_gem = find_latest_gem(lib)
36
+ $LOAD_PATH.unshift("#{installed_gem}/lib")
37
+ end
38
+
39
+ require lib
40
+ retry_count += 1
41
+ retry
42
+ end
43
+ end
44
+ end
45
+
46
+ def find_latest_gem(gem_name)
47
+ the_gem = Dir.glob("#{Gem.dir}/gems/#{gem_name}-*")
48
+
49
+ the_gem.empty? ? nil : the_gem.first
50
+ end
51
+
52
+ # Add all gems in the global gemset to the $LOAD_PATH so they can be used
53
+ # even in places like 'rails console'.
54
+ #
55
+ # TODO: Use #find_latest_gem for each of #libraries.
56
+ def do_bundler_extending
57
+ if defined?(::Bundler)
58
+ all_global_gem_paths = Dir.glob("#{Gem.dir}/gems/*")
59
+
60
+ all_global_gem_paths.each do |p|
61
+ gem_path = "#{p}/lib"
62
+ $LOAD_PATH.unshift(gem_path)
63
+ end
64
+ else
65
+ vputs 'Bundler not defined. Skipping.'
66
+ end
67
+ end
68
+
69
+ # Undo the stuff that was done in #do_bundler_extending.
70
+ #
71
+ # TODO: Use #find_latest_gem for each of #libraries.
72
+ def undo_bundler_extending
73
+ if defined?(::Bundler)
74
+ all_global_gem_paths = Dir.glob("#{Gem.dir}/gems/*")
75
+
76
+ all_global_gem_paths.each do |p|
77
+ gem_path = "#{p}/lib"
78
+ $LOAD_PATH.delete(gem_path)
79
+ end
80
+ else
81
+ vputs 'Bundler not defined. Skipping.'
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,75 @@
1
+ require_relative 'library_helpers'
2
+
3
+ class Hairballs
4
+ # Plugins provide means for adding functionality to your IRB sessions. They
5
+ # can be as simple as requiring other gems, or as complex as you want them to
6
+ # be.
7
+ #
8
+ # One benefit of making a simple plugin for requiring other deps is
9
+ # Hairballs::LibraryHelpers#require_libraries method. When used in conjunction with
10
+ # Hairballs::LibraryHelpers#libraries, you don't have to worry about installing the
11
+ # gems before using IRB. This is particularly helpful when using a Ruby
12
+ # manager (RVM, rbenv, etc) and you install a new Ruby; if you don't think
13
+ # ahead to install your IRB deps, your IRB session won't behave like you
14
+ # want; well, not until you `exit` and fix the problem. This simple pattern
15
+ # helps alleviate that small headache.
16
+ #
17
+ # Next, Hairballs Plugins are lazily loaded; `require`ing their source files
18
+ # doesn't mean the methods and such that you add there will do anything; it's
19
+ # not until you `Hairballs.load_plugin(:blargh)` that the code that defines
20
+ # your plugin will get executed.
21
+ class Plugin
22
+ include LibraryHelpers
23
+
24
+ # @return [Symbol]
25
+ attr_reader :name
26
+
27
+ # @param name [Symbol]
28
+ # @param attributes [Hash] These become attributes (with reader and writer
29
+ # methods) of the Plugin. It's really just a mechanism for defining
30
+ # available attributes and their default values.
31
+ def initialize(name, **attributes)
32
+ @name = name
33
+ @irb_configuration = nil
34
+
35
+ attributes.each do |k, v|
36
+ define_singleton_method(k) do
37
+ instance_variable_get("@#{k}".to_sym)
38
+ end
39
+
40
+ define_singleton_method("#{k}=") do |new_value|
41
+ instance_variable_set("@#{k}".to_sym, new_value)
42
+ end
43
+
44
+ instance_variable_set("@#{k}".to_sym, v)
45
+ end
46
+ end
47
+
48
+ # Everything in the +block+ given here will be the last code to get
49
+ # evaluated when #load! is called. This is where you define code that makes
50
+ # up your plugin.
51
+ def on_load(&block)
52
+ @on_load = block
53
+ end
54
+
55
+ # Loads the plugin using the +attributes+ values. The keys in +attributes+
56
+ # must match attributes that were given when the Plugin was defined.
57
+ # Attribute values given here will override the defaults that were given
58
+ # when the Plugin was defined.
59
+ def load!(**attributes)
60
+ attributes.each do |k, v|
61
+ send("#{k}=".to_sym, v)
62
+ end
63
+
64
+ require_libraries
65
+
66
+ if @on_load
67
+ if @on_load.kind_of?(Proc)
68
+ @on_load.call
69
+ else
70
+ fail PluginLoadFailure, self.name
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,9 @@
1
+ require_relative '../../hairballs'
2
+
3
+ Hairballs.add_plugin(:awesome_print) do |plugin|
4
+ plugin.libraries %w(awesome_print)
5
+
6
+ plugin.on_load do
7
+ AwesomePrint.irb!
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ require_relative '../../hairballs'
2
+
3
+ # When any value is returned by evaluating some Ruby, this will check if it is
4
+ # JSON (by parsing it). If it's JSON-like, it will get formatted prettily and
5
+ # using the +color+ given when calling +Hairballs.load_plugin(:colorize_json)+.
6
+ #
7
+ # This *must* get used/loaded after the :wirble plugin to work.
8
+ #
9
+ # TODO: fix to work with using/loading before Wirble.
10
+ Hairballs.add_plugin(:colorize_json, color: :blue) do |plugin|
11
+ plugin.libraries %w(json colorize)
12
+
13
+ plugin.on_load do
14
+ IRB::Irb.class_eval do
15
+ alias_method :old_output_value, :output_value
16
+
17
+ define_method :output_value do
18
+ is_json = JSON.parse(@context.last_value) rescue nil
19
+
20
+ if is_json
21
+ vputs "[#{plugin.name}] Return value is JSON-like"
22
+ printf @context.return_format,
23
+ JSON.pretty_generate(JSON.parse(@context.last_value)).colorize(plugin.color)
24
+ else
25
+ old_output_value
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ require_relative '../../hairballs'
2
+
3
+ # Returns only the methods not present on basic Objects.
4
+ #
5
+ # @see http://stackoverflow.com/a/873371/172106
6
+ Hairballs.add_plugin(:interesting_methods) do |plugin|
7
+ plugin.on_load do
8
+ Object.class_eval do
9
+ # @return [Array<Symbol>]
10
+ def interesting_methods
11
+ case self.class
12
+ when Class
13
+ public_methods.sort - Object.public_methods
14
+ when Module
15
+ public_methods.sort - Module.public_methods
16
+ else
17
+ public_methods.sort - Object.new.public_methods
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ require_relative '../../hairballs'
2
+
3
+ Hairballs.add_plugin(:irb_history, save_history: 1000, eval_history: 20, global_history_file: true) do |plugin|
4
+ plugin.libraries %w(irb/ext/save-history)
5
+
6
+ plugin.on_load do
7
+ IRB.conf[:SAVE_HISTORY] = plugin.save_history
8
+ IRB.conf[:EVAL_HISTORY] = plugin.eval_history
9
+
10
+ unless plugin.global_history_file
11
+ IRB.conf[:HISTORY_FILE] = "#{Dir.home}/.irb_history-#{Hairballs.project_name}"
12
+ end
13
+
14
+ Object.class_eval do
15
+ # All of the ruby lines of code that have been executed.
16
+ def history
17
+ 0.upto(Readline::HISTORY.size - 1) do |i|
18
+ printf "%5d %s\n", i, Readline::HISTORY[i]
19
+ end
20
+ end
21
+
22
+ # Execute one or many lines of Ruby from +history+.
23
+ #
24
+ # @param command_numbers [Fixnum,Range]
25
+ def _!(command_numbers)
26
+ cmds =
27
+ if command_numbers.is_a? Range
28
+ command_numbers.to_a.map { |i| Readline::HISTORY[i] }
29
+ else
30
+ [Readline::HISTORY[command_numbers]]
31
+ end
32
+
33
+ cmds.each { |cmd| send(cmd) }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../../hairballs'
2
+
3
+ # Directly lifted from rbates/dotfiles! Adds +#ri+ to all Objects, letting you
4
+ # get ri docs from within your IRB session.
5
+ Hairballs.add_plugin(:object_ri) do |plugin|
6
+ plugin.libraries %w(rdoc)
7
+
8
+ plugin.on_load do
9
+ Object.class_eval do
10
+ def ri(method=nil)
11
+ unless method && method =~ /^[A-Z]/ # if class isn't specified
12
+ klass = self.kind_of?(Class) ? name : self.class.name
13
+ method = [klass, method].compact.join('#')
14
+ end
15
+
16
+ system 'ri', method.to_s
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ require_relative '../../hairballs'
2
+
3
+ # Quick and dirty benchmarking of whatever block you pass to the method.
4
+ #
5
+ # @see http://stackoverflow.com/a/123834/172106
6
+ Hairballs.add_plugin(:quick_benchmark) do |plugin|
7
+ plugin.libraries %w(benchmark)
8
+
9
+ plugin.on_load do
10
+ Kernel.module_eval do
11
+ def quick_benchmark(repetitions=100, &block)
12
+ Benchmark.bmbm do |b|
13
+ b.report { repetitions.times(&block) }
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end