bumbler 0.1.2 → 0.1.3

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.
@@ -1,20 +1,24 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path("../lib/bumbler.rb", __FILE__)
2
+
3
+ # Bumbler may be already required due to the RUBYOPT=-rbumbler/go that we use to activate. Clear it
4
+ # if so to get rid of our warning, and then load it. We just need the version number
5
+ Bumbler.send(:remove_const, :VERSION) if Object.const_defined? :Bumbler
6
+ load File.expand_path('../lib/bumbler.rb', __FILE__)
3
7
 
4
8
  Gem::Specification.new do |s|
5
- s.name = "bumbler"
9
+ s.name = 'bumbler'
6
10
  s.version = Bumbler::VERSION
7
11
  s.platform = Gem::Platform::RUBY
8
- s.authors = ["Ian MacLeod"]
9
- s.email = ["ian@nevir.net"]
10
- s.homepage = "https://github.com/nevir/Bumbler"
12
+ s.authors = ['Ian MacLeod']
13
+ s.email = ['ian@nevir.net']
14
+ s.homepage = 'https://github.com/nevir/Bumbler'
11
15
  s.summary = %q{Track the load progress of your Bundler-based projects}
12
16
  s.description = %q{Why stare blankly at your terminal window when you can clutter it up with awesome progress bars?}
13
17
 
14
- s.rubyforge_project = "bumbler"
18
+ s.rubyforge_project = 'bumbler'
15
19
 
16
20
  s.files = `git ls-files`.split("\n")
17
21
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
22
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ["lib"]
23
+ s.require_paths = ['lib']
20
24
  end
@@ -1,8 +1,9 @@
1
1
  module Bumbler
2
2
  # We can be required twice due to the command line require
3
- VERSION = '0.1.2' unless self.const_defined? :VERSION
3
+ VERSION = '0.1.3' unless self.const_defined? :VERSION
4
4
 
5
- autoload :Hooks, 'bumbler/hooks'
6
5
  autoload :Bundler, 'bumbler/bundler'
6
+ autoload :Hooks, 'bumbler/hooks'
7
7
  autoload :Progress, 'bumbler/progress'
8
+ autoload :Stats, 'bumbler/stats'
8
9
  end
@@ -1,51 +1,52 @@
1
1
  module Bumbler
2
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_started(path)
11
- gem_name = self.gem_for_require(path)
12
- return unless gem_name
13
-
14
- Bumbler::Progress.item_started(:bundler, gem_name)
15
- end
16
-
17
- def self.require_finished(path, load_time)
18
- self.read_bundler_environment if @gem_state.nil?
3
+ class << self
4
+ # Returns which gem a require maps to, or nil.
5
+ def gem_for_require(path)
6
+ self.read_bundler_environment if @require_map.nil?
7
+
8
+ return @require_map[path]
9
+ end
19
10
 
20
- # Tick it off for the gem.
21
- gem_name = self.gem_for_require(path)
22
- return unless gem_name
11
+ def require_started(path)
12
+ gem_name = self.gem_for_require(path)
13
+ return unless gem_name
14
+
15
+ Bumbler::Progress.item_started(:bundler, gem_name)
16
+ end
23
17
 
24
- @gem_state[gem_name][path] = true
18
+ def require_finished(path, load_time)
19
+ self.read_bundler_environment if @gem_state.nil?
20
+
21
+ # Tick it off for the gem.
22
+ gem_name = self.gem_for_require(path)
23
+ return unless gem_name
24
+
25
+ @gem_state[gem_name][path] = true
26
+
27
+ if @gem_state[gem_name].values.all?
28
+ Bumbler::Progress.item_finished(:bundler, gem_name, load_time)
29
+ end
30
+ end
25
31
 
26
- if @gem_state[gem_name].values.all?
27
- Bumbler::Progress.item_finished(:bundler, gem_name, load_time)
32
+ def start!
33
+ self.read_bundler_environment
28
34
  end
29
- end
30
-
31
- def self.start!
32
- self.read_bundler_environment
33
- end
34
-
35
- private
36
- def self.read_bundler_environment
37
- @require_map = {}
38
- @gem_state = {}
39
35
 
40
- ::Bundler.environment.current_dependencies.each do |spec|
41
- @gem_state[spec.name] = {}
36
+ def read_bundler_environment
37
+ @require_map = {}
38
+ @gem_state = {}
42
39
 
43
- Array(spec.autorequire || spec.name).each do |path|
44
- @require_map[path] = spec.name
45
- @gem_state[spec.name][path] = false
40
+ ::Bundler.environment.current_dependencies.each do |spec|
41
+ @gem_state[spec.name] = {}
42
+
43
+ Array(spec.autorequire || spec.name).each do |path|
44
+ @require_map[path] = spec.name
45
+ @gem_state[spec.name][path] = false
46
+ end
47
+
48
+ Bumbler::Progress.register_item(:bundler, spec.name)
46
49
  end
47
-
48
- Bumbler::Progress.register_item(:bundler, spec.name)
49
50
  end
50
51
  end
51
52
  end
@@ -1,72 +1,83 @@
1
1
  module Bumbler
2
2
  module Hooks
3
- # Inject our custom handling of require into the Kernel.
4
- def self.hook_require!
5
- @hooking_require = true
3
+ SLOW_REQUIRE_THRESHOLD = 100.0
4
+ @previous_gems = {}
5
+ @slow_requires = {}
6
+
7
+ # Everything's a class method (we're a singleton)
8
+ class << self
9
+ def slow_requires
10
+ @slow_requires
11
+ end
6
12
 
7
- # There are two independent require methods. Joy!
8
- ::Kernel.module_eval do
9
- class << self
10
- orig_public_require = Kernel.public_method(:require)
13
+ # Inject our custom handling of require into the Kernel.
14
+ def hook_require!
15
+ @hooking_require = true
16
+
17
+ # There are two independent require methods. Joy!
18
+ ::Kernel.module_eval do
19
+ class << self
20
+ orig_public_require = Kernel.public_method(:require)
21
+ define_method(:require) do |path, *args|
22
+ ::Bumbler::Hooks.handle_require(path) do
23
+ orig_public_require.call(path, *args)
24
+ end
25
+ end
26
+ end
27
+
28
+ orig_instance_require = self.instance_method(:require)
11
29
  define_method(:require) do |path, *args|
12
30
  ::Bumbler::Hooks.handle_require(path) do
13
- orig_public_require.call(path, *args)
31
+ orig_instance_require.bind(self).call(path, *args)
14
32
  end
15
33
  end
16
34
  end
17
35
 
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
36
+ @hooking_require = nil
24
37
  end
25
38
 
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!
39
+ # Even better: Other gems hook require as well. The instance method one at least.
40
+ def watch_require!
41
+ ::Kernel.module_eval do
42
+ # It isn't previously defined in Kernel. This could be a bit dangerous, though.
43
+ def self.method_added(method_name, *args)
44
+ if method_name == :require && !::Bumbler::Hooks.hooking_require?
45
+ # Fix those hooks.
46
+ ::Bumbler::Hooks.hook_require!
47
+ end
37
48
  end
38
49
  end
39
50
  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
- # Track load starts
58
- @previous_gems ||= {}
59
- Bumbler::Bundler.require_started(path) unless @previous_gems[gem_name]
60
- @previous_gems[gem_name] = true
61
51
 
62
- # Let's time them
63
- start = Time.now.to_f
64
- result = yield
65
- require_time = (Time.now.to_f - start) * 1000 # ms
66
-
67
- Bumbler::Bundler.require_finished(path, require_time) if result
52
+ def hooking_require?
53
+ @hooking_require
54
+ end
68
55
 
69
- return result
56
+ # Actually do something about a require here.
57
+ def handle_require(path)
58
+ # break out early if we're already handling this
59
+ return yield if path == @previous_require
60
+ @previous_require = path
61
+
62
+ # Shortcut unless we're tracking the gem
63
+ gem_name = Bumbler::Bundler.gem_for_require(path)
64
+ return yield unless gem_name
65
+
66
+ # Track load starts
67
+ Bumbler::Bundler.require_started(path) unless @previous_gems[gem_name]
68
+ @previous_gems[gem_name] = true
69
+
70
+ # Let's time them
71
+ start = Time.now.to_f
72
+ result = yield
73
+ require_time = (Time.now.to_f - start) * 1000 # ms
74
+
75
+ @slow_requires[path] = require_time if require_time > SLOW_REQUIRE_THRESHOLD
76
+
77
+ Bumbler::Bundler.require_finished(path, require_time) if result
78
+
79
+ return result
80
+ end
70
81
  end
71
82
  end
72
83
  end
@@ -1,94 +1,94 @@
1
1
  module Bumbler
2
- # Singletons are fun, yay!
3
2
  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_started(type, name)
15
- @curr_item = {:type => type, :name => name}
16
-
17
- self.render_progress
18
- end
19
-
20
- def self.item_finished(type, name, time)
21
- self.registry[type][name] = {:time => time}
22
-
23
- @loaded_items ||= 0
24
- @loaded_items += 1
25
-
26
- @prev_item = {:type => type, :name => name, :time => time}
27
- @curr_item = nil if @curr_item && @curr_item[:name] == @prev_item[:name] && @curr_item[:type] == @prev_item[:type]
28
-
29
- self.render_progress
30
- end
31
-
32
- def self.start!
33
- # No-op for now.
34
- end
3
+ @item_count = 0
4
+ @loaded_items = 0
35
5
 
36
- private
37
6
  # registry[item_type][item_name] = {:time => 123.45}
38
- def self.registry
39
- @registry ||= Hash.new { |h,k| h[k] = {} }
40
- end
41
-
42
- def self.tty_width
43
- `tput cols`.to_i || 80
44
- end
7
+ @registry = Hash.new { |h,k| h[k] = {} }
45
8
 
46
- def self.bar(width)
47
- inner_size = width - 2
48
-
49
- fill_size = ((@loaded_items.to_f / @item_count.to_f) * inner_size).to_i
50
- fill = '#' * fill_size
51
- empty = ' ' * (inner_size - fill_size)
52
-
53
- return "[#{fill}#{empty}]"
54
- end
55
-
56
- def self.render_progress
57
- unless $stdout.tty?
58
- puts '(%s/%d) %s' % [@loaded_items.to_s.rjust(@item_count.to_s.size), @item_count, message]
59
- return
9
+ class << self
10
+ def registry
11
+ @registry
60
12
  end
61
13
 
62
- # Do nothing if we don't have any items to load
63
- return if @item_count == 0
64
-
65
- width = self.tty_width
66
-
67
- print "\r\e[A\r\e[A" if @outputted_once
68
- @outputted_once = true
69
-
70
- @loaded_items ||= 0
71
- @item_count ||= 0
14
+ def register_item(type, name)
15
+ # Build a blank key for the item
16
+ unless @registry[type][name]
17
+ @item_count += 1
18
+ end
19
+
20
+ @registry[type][name] = {}
21
+ end
72
22
 
73
- # Output components:
74
- # [#######################################]
75
- # (##/##) <current>... <prev> (####.##ms)
76
- #
77
- # Skip the current if there isn't enough room
78
- count = '(%s/%d) ' % [@loaded_items.to_s.rjust(@item_count.to_s.size), @item_count]
79
- current = @curr_item ? "#{@curr_item[:name]}... " : ''
80
- prev = @prev_item ? '%s (%sms)' % [@prev_item[:name], ('%.2f' % @prev_item[:time]).rjust(7)] : ''
23
+ def item_started(type, name)
24
+ @curr_item = {:type => type, :name => name}
25
+
26
+ self.render_progress
27
+ end
81
28
 
82
- # Align the bottom row
83
- space_for_current = width - (count.length + prev.length)
29
+ def item_finished(type, name, time)
30
+ @registry[type][name] = {:time => time}
31
+
32
+ @loaded_items += 1
33
+
34
+ @prev_item = {:type => type, :name => name, :time => time}
35
+ @curr_item = nil if @curr_item && @curr_item[:name] == @prev_item[:name] && @curr_item[:type] == @prev_item[:type]
36
+
37
+ self.render_progress
38
+ end
84
39
 
85
- # Render the progress
86
- puts self.bar(width)
40
+ def start!
41
+ # No-op for now.
42
+ end
87
43
 
88
- if space_for_current >= current.length
89
- puts count + current + prev.rjust(width - count.length - current.length)
90
- else
91
- puts count + prev.rjust(width - count.length)
44
+ def tty_width
45
+ `tput cols`.to_i || 80
46
+ end
47
+
48
+ def bar(width)
49
+ inner_size = width - 2
50
+
51
+ fill_size = ((@loaded_items.to_f / @item_count.to_f) * inner_size).to_i
52
+ fill = '#' * fill_size
53
+ empty = ' ' * (inner_size - fill_size)
54
+
55
+ return "[#{fill}#{empty}]"
56
+ end
57
+
58
+ def render_progress
59
+ unless $stdout.tty?
60
+ puts '(%s/%d) %s' % [@loaded_items.to_s.rjust(@item_count.to_s.size), @item_count, message]
61
+ return
62
+ end
63
+
64
+ # Do nothing if we don't have any items to load
65
+ return if @item_count == 0
66
+
67
+ width = self.tty_width
68
+
69
+ print "\r\e[A\r\e[A" if @outputted_once
70
+ @outputted_once = true
71
+
72
+ # Output components:
73
+ # [#######################################]
74
+ # (##/##) <current>... <prev> (####.##ms)
75
+ #
76
+ # Skip the current if there isn't enough room
77
+ count = '(%s/%d) ' % [@loaded_items.to_s.rjust(@item_count.to_s.size), @item_count]
78
+ current = @curr_item ? "#{@curr_item[:name]}... " : ''
79
+ prev = @prev_item ? '%s (%sms)' % [@prev_item[:name], ('%.2f' % @prev_item[:time]).rjust(7)] : ''
80
+
81
+ # Align the bottom row
82
+ space_for_current = width - (count.length + prev.length)
83
+
84
+ # Render the progress
85
+ puts self.bar(width)
86
+
87
+ if space_for_current >= current.length
88
+ puts count + current + prev.rjust(width - count.length - current.length)
89
+ else
90
+ puts count + prev.rjust(width - count.length)
91
+ end
92
92
  end
93
93
  end
94
94
  end
@@ -0,0 +1,30 @@
1
+ module Bumbler
2
+ module Stats
3
+ class << self
4
+ def tracked_items
5
+ Bumbler::Progress.registry.each do |type, items|
6
+ puts "Stats for #{type} items:"
7
+
8
+ items.to_a.sort_by! {|n,d| d[:time].to_f}.each do |name, info|
9
+ if info[:time]
10
+ puts ' %s %s' % [('%.2f' % info[:time]).rjust(8), name]
11
+ else
12
+ puts " pending: #{name}"
13
+ end
14
+ end
15
+ end
16
+
17
+ self
18
+ end
19
+
20
+ def all_slow_items
21
+ puts "Slow requires:"
22
+ Bumbler::Hooks.slow_requires.to_a.sort_by! {|n,t| t}.each do |name, time|
23
+ puts ' %s %s' % [('%.2f' % time).rjust(8), name]
24
+ end
25
+
26
+ self
27
+ end
28
+ end
29
+ end
30
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: bumbler
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.2
5
+ version: 0.1.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ian MacLeod
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-04-22 00:00:00 -07:00
13
+ date: 2011-04-23 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -34,6 +34,7 @@ files:
34
34
  - lib/bumbler/go.rb
35
35
  - lib/bumbler/hooks.rb
36
36
  - lib/bumbler/progress.rb
37
+ - lib/bumbler/stats.rb
37
38
  has_rdoc: true
38
39
  homepage: https://github.com/nevir/Bumbler
39
40
  licenses: []