bumbler 0.1.0
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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +33 -0
- data/Rakefile +2 -0
- data/bumbler.gemspec +21 -0
- data/lib/bumbler.rb +21 -0
- data/lib/bumbler/bundler.rb +45 -0
- data/lib/bumbler/hooks.rb +67 -0
- data/lib/bumbler/progress.rb +60 -0
- data/lib/bumbler/version.rb +3 -0
- metadata +66 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Bumbler
|
2
|
+
Why stare blankly at your terminal window when you can clutter it up with awesome progress bars?
|
3
|
+
|
4
|
+
Use Bumbler to track the load progress of your [Bundler](http://gembundler.com/)-based projects! Maybe you'll find a slow gem or two.
|
5
|
+
|
6
|
+
|
7
|
+
## Using Bumbler
|
8
|
+
### Step 1:
|
9
|
+
|
10
|
+
gem install bumbler
|
11
|
+
|
12
|
+
### Step 1.5:
|
13
|
+
Add bumbler to your Gemfile if you want to use `bundle exec`
|
14
|
+
|
15
|
+
gem 'bumbler'
|
16
|
+
|
17
|
+
### Step 2:
|
18
|
+
Add the following to your .profile, .bash_profile, .zshrc, .wtfrc or whatever shell config you use
|
19
|
+
|
20
|
+
export RUBYOPT=-rbumbler
|
21
|
+
|
22
|
+
### Step 3:
|
23
|
+
Restart your terminal
|
24
|
+
|
25
|
+
|
26
|
+
## Blammo, you're bumbling with bundler and bumbler!
|
27
|
+
Run a Bundler-based command, and you should see a spiffy progress bar, such as:
|
28
|
+
|
29
|
+
> rails c
|
30
|
+
[######### ]
|
31
|
+
( 7/59) 492.04ms loaded data_mapper
|
32
|
+
|
33
|
+
And then maybe you'll also want to contribute some patches to make your favorite gems load faster.
|
data/Rakefile
ADDED
data/bumbler.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bumbler/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "bumbler"
|
7
|
+
s.version = Bumbler::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ian MacLeod"]
|
10
|
+
s.email = ["ian@nevir.net"]
|
11
|
+
s.homepage = "https://github.com/nevir/Bumbler"
|
12
|
+
s.summary = %q{Track the load progress of your Bundler-based projects}
|
13
|
+
s.description = %q{Why stare blankly at your terminal window when you can clutter it up with awesome progress bars?}
|
14
|
+
|
15
|
+
s.rubyforge_project = "bumbler"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
data/lib/bumbler.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Do nothing unless we're in a bundle
|
2
|
+
begin
|
3
|
+
require 'bundler'
|
4
|
+
# This raises if there isn't a gemfile in our root
|
5
|
+
Bundler.default_gemfile
|
6
|
+
|
7
|
+
module Bumbler
|
8
|
+
autoload :Hooks, 'bumbler/hooks'
|
9
|
+
autoload :Bundler, 'bumbler/bundler'
|
10
|
+
autoload :Progress, 'bumbler/progress'
|
11
|
+
|
12
|
+
Hooks.hook_require!
|
13
|
+
Hooks.watch_require!
|
14
|
+
|
15
|
+
Bundler.start!
|
16
|
+
Progress.start!
|
17
|
+
end
|
18
|
+
|
19
|
+
rescue
|
20
|
+
# Welp, if we fail, we fail.
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Bumbler
|
2
|
+
module Bundler
|
3
|
+
# Returns which gem a require maps to, or nil.
|
4
|
+
def self.gem_for_require(path)
|
5
|
+
self.read_bundler_environment if @require_map.nil?
|
6
|
+
|
7
|
+
return @require_map[path]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.require_finished(path, load_time)
|
11
|
+
self.read_bundler_environment if @gem_state.nil?
|
12
|
+
|
13
|
+
# Tick it off for the gem.
|
14
|
+
gem_name = self.gem_for_require(path)
|
15
|
+
return unless gem_name
|
16
|
+
|
17
|
+
@gem_state[gem_name][path] = true
|
18
|
+
|
19
|
+
if @gem_state[gem_name].values.all?
|
20
|
+
Bumbler::Progress.item_finished(:bundler, gem_name, load_time)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.start!
|
25
|
+
self.read_bundler_environment
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def self.read_bundler_environment
|
30
|
+
@require_map = {}
|
31
|
+
@gem_state = {}
|
32
|
+
|
33
|
+
::Bundler.environment.current_dependencies.each do |spec|
|
34
|
+
@gem_state[spec.name] = {}
|
35
|
+
|
36
|
+
Array(spec.autorequire || spec.name).each do |path|
|
37
|
+
@require_map[path] = spec.name
|
38
|
+
@gem_state[spec.name][path] = false
|
39
|
+
end
|
40
|
+
|
41
|
+
Bumbler::Progress.register_item(:bundler, spec.name)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Bumbler
|
2
|
+
module Hooks
|
3
|
+
# Inject our custom handling of require into the Kernel.
|
4
|
+
def self.hook_require!
|
5
|
+
@hooking_require = true
|
6
|
+
|
7
|
+
# There are two independent require methods. Joy!
|
8
|
+
::Kernel.module_eval do
|
9
|
+
class << self
|
10
|
+
orig_public_require = Kernel.public_method(:require)
|
11
|
+
define_method(:require) do |path, *args|
|
12
|
+
::Bumbler::Hooks.handle_require(path) do
|
13
|
+
orig_public_require.call(path, *args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
orig_instance_require = self.instance_method(:require)
|
19
|
+
define_method(:require) do |path, *args|
|
20
|
+
::Bumbler::Hooks.handle_require(path) do
|
21
|
+
orig_instance_require.bind(self).call(path, *args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
@hooking_require = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
# Even better: Other gems hook require as well. The instance method one at least.
|
30
|
+
def self.watch_require!
|
31
|
+
::Kernel.module_eval do
|
32
|
+
# It isn't previously defined in Kernel. This could be a bit dangerous, though.
|
33
|
+
def self.method_added(method_name, *args)
|
34
|
+
if method_name == :require && !::Bumbler::Hooks.hooking_require?
|
35
|
+
# Fix those hooks.
|
36
|
+
::Bumbler::Hooks.hook_require!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def self.hooking_require?
|
44
|
+
@hooking_require
|
45
|
+
end
|
46
|
+
|
47
|
+
# Actually do something about a require here.
|
48
|
+
def self.handle_require(path)
|
49
|
+
# break out early if we're already handling this
|
50
|
+
return yield if path == @previous_require
|
51
|
+
@previous_require = path
|
52
|
+
|
53
|
+
# Shortcut unless we're tracking the gem
|
54
|
+
gem_name = Bumbler::Bundler.gem_for_require(path)
|
55
|
+
return yield unless gem_name
|
56
|
+
|
57
|
+
# Let's time them
|
58
|
+
start = Time.now.to_f
|
59
|
+
result = yield
|
60
|
+
require_time = (Time.now.to_f - start) * 1000 # ms
|
61
|
+
|
62
|
+
Bumbler::Bundler.require_finished(path, require_time) if result
|
63
|
+
|
64
|
+
return result
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Bumbler
|
2
|
+
# Singletons are fun, yay!
|
3
|
+
module Progress
|
4
|
+
def self.register_item(type, name)
|
5
|
+
# Build a blank key for the item
|
6
|
+
unless self.registry[type][name]
|
7
|
+
@item_count ||= 0
|
8
|
+
@item_count += 1
|
9
|
+
end
|
10
|
+
|
11
|
+
self.registry[type][name] = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.item_finished(type, name, time)
|
15
|
+
self.registry[type][name] = {:time => time}
|
16
|
+
|
17
|
+
@loaded_items ||= 0
|
18
|
+
@loaded_items += 1
|
19
|
+
|
20
|
+
time_str = ('%.2fms' % time).rjust(9)
|
21
|
+
self.render_progress('%s loaded %s ' % [time_str, name])
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.start!
|
25
|
+
@loaded_items ||= 0
|
26
|
+
@item_count ||= 0
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
# registry[item_type][item_name] = {:time => 123.45}
|
31
|
+
def self.registry
|
32
|
+
@registry ||= Hash.new { |h,k| h[k] = {} }
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.tty_width
|
36
|
+
`tput cols`.to_i || 80
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.bar
|
40
|
+
inner_size = self.tty_width - 2
|
41
|
+
|
42
|
+
fill_size = ((@loaded_items.to_f / @item_count.to_f) * inner_size).to_i
|
43
|
+
fill = '#' * fill_size
|
44
|
+
empty = ' ' * (inner_size - fill_size)
|
45
|
+
|
46
|
+
return "[#{fill}#{empty}]"
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.render_progress(message)
|
50
|
+
if $stdout.tty?
|
51
|
+
print "\r\e[A\r\e[K\r\e[A" if @outputted_once
|
52
|
+
@outputted_once = true
|
53
|
+
|
54
|
+
puts self.bar
|
55
|
+
end
|
56
|
+
|
57
|
+
puts '(%s/%d) %s' % [@loaded_items.to_s.rjust(@item_count.to_s.size), @item_count, message]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bumbler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ian MacLeod
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-04-21 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: Why stare blankly at your terminal window when you can clutter it up with awesome progress bars?
|
18
|
+
email:
|
19
|
+
- ian@nevir.net
|
20
|
+
executables: []
|
21
|
+
|
22
|
+
extensions: []
|
23
|
+
|
24
|
+
extra_rdoc_files: []
|
25
|
+
|
26
|
+
files:
|
27
|
+
- .gitignore
|
28
|
+
- Gemfile
|
29
|
+
- README.md
|
30
|
+
- Rakefile
|
31
|
+
- bumbler.gemspec
|
32
|
+
- lib/bumbler.rb
|
33
|
+
- lib/bumbler/bundler.rb
|
34
|
+
- lib/bumbler/hooks.rb
|
35
|
+
- lib/bumbler/progress.rb
|
36
|
+
- lib/bumbler/version.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: https://github.com/nevir/Bumbler
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project: bumbler
|
61
|
+
rubygems_version: 1.6.2
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Track the load progress of your Bundler-based projects
|
65
|
+
test_files: []
|
66
|
+
|