bumbler 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []