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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in bumbler.gemspec
4
+ gemspec
@@ -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.
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Bumbler
2
+ VERSION = "0.1.0"
3
+ 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
+