browser-prof 1.2.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.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ rails_test/*
2
+ pkg/*
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Revolution Health Group LLC. All rights reserved.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,41 @@
1
+ = Browser-prof
2
+
3
+ This is a simple tool to profile single web requests in Rails using the power or ruby-prof.
4
+ This gem is a based on the discontinued Browser Profiler (http://rubyforge.org/projects/browser-prof).
5
+
6
+ * Easy walking through complex changes
7
+ * Low overhead in development mode
8
+ * MIT licensed
9
+
10
+ == Installation & basic usage
11
+
12
+ Installing browser-prof as a Ruby gem is currently broken, so you need to use it as a plugin:
13
+
14
+ $ ./script/plugin install http://github.com/barttenbrinke/browser-prof.git
15
+
16
+ == Profiling
17
+
18
+ Add ruby-prof to your Gemfile, run bundle install and start op your server environment.
19
+ To profile, just open any url:
20
+
21
+ $ http://0.0.0.0:3000/some/action?browser_profile!
22
+
23
+ On the botton of your page a html ruby-prof trace will be appended.
24
+ Please note that the action will take lot longer, as it will be passed through ruby-prof.
25
+
26
+ If you want to profile PDF, Json or post actions, just run the following command:
27
+ $ http://0.0.0.0:3000/some/action.js?file_profile!
28
+
29
+ This will write the results to /log/. You can take a look at this through any browser.
30
+ $ open log/profile_out.html
31
+
32
+ == Additional information
33
+
34
+ Browser-profile was originally designed and built by Aaron Batalion (aaron@hungrymachine.com)
35
+ and is now maintained by Bart ten Brinke.
36
+
37
+ Do you have a rails application that is not performing as it should? If you need
38
+ an expert to analyze your application, feel free to contact either Willem van
39
+ Bergen (willem@railsdoctors.com) or Bart ten Brinke (bart@railsdoctors.com).
40
+
41
+ * railsdoctors homepage: http://railsdoctors.com
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ Dir[File.dirname(__FILE__) + "/tasks/*.rake"].each { |file| load(file) }
2
+
3
+ # Register the gem release tasks in the gem namespace
4
+ GithubGem::RakeTasks.new(:gem)
5
+
6
+ # Set the RSpec runner with specdoc output as default task.
7
+ task :default => "spec:specdoc"
8
+
@@ -0,0 +1,30 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "browser-prof"
3
+
4
+ # Do not set the version and date field manually, this is done by the release script
5
+ s.version = "1.2.3"
6
+ s.date = "2011-02-17"
7
+
8
+ s.summary = "Rails tool to to profile single requests using ruby-prof."
9
+ s.description = <<-eos
10
+ This is a simple tool to profile single web requests in Rails using the power or ruby-prof.
11
+ eos
12
+
13
+ s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
14
+ s.extra_rdoc_files = ['README.rdoc']
15
+
16
+ s.requirements << "ruby-prof gem is required."
17
+
18
+ s.add_development_dependency('rake')
19
+ s.add_development_dependency('rspec', '~> 2.0')
20
+ s.add_development_dependency('ruby-prof')
21
+
22
+ s.authors = ['Willem van Bergen', 'Bart ten Brinke']
23
+ s.email = ['willem@railsdoctors.com', 'bart@railsdoctors.com']
24
+ s.homepage = 'http://railsdoctors.com'
25
+
26
+ # The files and test_files directives are set automatically by the release script.
27
+ # Do not change them by hand, but make sure to add the files to the git repository.
28
+ s.files = %w(.gitignore MIT-LICENSE README.rdoc Rakefile browser-prof.gemspec init.rb lib/browser-prof.rb lib/ruby-prof/graph_html_printer_enhanced.rb lib/ruby-prof/template.rhtml pkg/browser_profiler-1.2.0.gem tasks/github-gem.rake test/functional/slow_controller_test.rb test/test_helper.rb)
29
+ s.test_files = %w(test/functional/slow_controller_test.rb)
30
+ end
data/init.rb ADDED
@@ -0,0 +1,7 @@
1
+ class ActiveRecord::Base
2
+ def self.inspect
3
+ "#<#{name}#>"
4
+ end
5
+ end
6
+
7
+ require 'browser-prof'
@@ -0,0 +1,37 @@
1
+ module ActionController
2
+ class Base
3
+ def process_with_browser_profiling(request, response, method = :perform_action, *arguments)
4
+ browser_output = request.parameters.key?('browser_profile!') || request.parameters[:params].key?('browser_profile!') || ENV["BROWSER_PROFILE"]
5
+ file_output = request.parameters.key?('file_profile') || request.parameters[:params].key?('file_profile!') || ENV["FILE_PROFILE"]
6
+
7
+ if (browser_output or file_output)
8
+ # Only require these files in needed
9
+ require 'ruby-prof'
10
+ require 'ruby-prof/graph_html_printer_enhanced'
11
+
12
+ #run the process through a profile block
13
+ profile_results = RubyProf.profile {
14
+ response = process_without_browser_profiling(request,response, method, *arguments);
15
+ }
16
+
17
+ #Use the enhanced html printer to get better results
18
+ printer = RubyProf::GraphHtmlPrinterEnhanced.new(profile_results)
19
+
20
+ #determine output location
21
+ if file_output
22
+ printer.print(File.new("#{RAILS_ROOT}/log/profile_out.html","w"))
23
+ else
24
+ response.body << printer.print("",0)
25
+ end
26
+
27
+ #reset the content length so the profiling data is included in the response
28
+ response.send("set_content_length!")
29
+
30
+ response
31
+ else
32
+ process_without_browser_profiling(request, response, method, *arguments)
33
+ end
34
+ end
35
+ alias_method_chain :process, :browser_profiling
36
+ end
37
+ end
@@ -0,0 +1,123 @@
1
+ # This is a modified version from the rubyprof project rubyprof.rubyforge.org
2
+ require 'ruby-prof/abstract_printer'
3
+ require "erb"
4
+
5
+ module RubyProf
6
+ # Generates graph[link:files/examples/graph_html.html] profile reports as html.
7
+ # To use the grap html printer:
8
+ #
9
+ # result = RubyProf.profile do
10
+ # [code to profile]
11
+ # end
12
+ #
13
+ # printer = RubyProf::GraphHtmlPrinter.new(result, 5)
14
+ # printer.print(STDOUT, 0)
15
+ #
16
+ # The constructor takes two arguments. The first is
17
+ # a RubyProf::Result object generated from a profiling
18
+ # run. The second is the minimum %total (the methods
19
+ # total time divided by the overall total time) that
20
+ # a method must take for it to be printed out in
21
+ # the report. Use this parameter to eliminate methods
22
+ # that are not important to the overall profiling results.
23
+ #
24
+ # This is mostly from ruby_forge, with some optimization changes.
25
+
26
+ class GraphHtmlPrinterEnhanced < AbstractPrinter
27
+ include ERB::Util
28
+
29
+ MIN_TIME = 0.01
30
+ MIN_THREAD_TIME = 0.0
31
+ PERCENTAGE_WIDTH = 8
32
+ TIME_WIDTH = 10
33
+ CALL_WIDTH = 20
34
+
35
+ # Create a GraphPrinter. Result is a RubyProf::Result
36
+ # object generated from a profiling run.
37
+ def initialize(result)
38
+ super(result)
39
+ @thread_times = Hash.new
40
+ calculate_thread_times
41
+ end
42
+
43
+ # Print a graph html report to the provided output.
44
+ #
45
+ # output - Any IO oject, including STDOUT or a file.
46
+ # The default value is STDOUT.
47
+ #
48
+ # options - Hash of print options. See #setup_options
49
+ # for more information.
50
+ #
51
+ def print(output = STDOUT, options = {})
52
+ @output = output
53
+ setup_options(options)
54
+
55
+ _erbout = @output
56
+ erb = ERB.new(template, nil, nil)
57
+ @output << erb.result(binding)
58
+ end
59
+
60
+ # These methods should be private but then ERB doesn't
61
+ # work. Turn off RDOC though
62
+ #--
63
+ def calculate_thread_times
64
+ # Cache thread times since this is an expensive
65
+ # operation with the required sorting
66
+ @result.threads.each do |thread_id, methods|
67
+ top = methods.sort.last
68
+
69
+ thread_time = 0.01
70
+ thread_time = top.total_time if top.total_time > 0
71
+
72
+ @thread_times[thread_id] = thread_time
73
+ end
74
+ end
75
+
76
+ def thread_time(thread_id)
77
+ @thread_times[thread_id]
78
+ end
79
+
80
+ def select_methods(methods)
81
+ return [] unless methods
82
+ methods.select {|method| method.total_time >= MIN_TIME }
83
+ end
84
+
85
+ def select_threads(threads)
86
+ threads.select {|thread_id, methods| thread_time(thread_id) >= MIN_THREAD_TIME }
87
+ end
88
+
89
+ def total_percent(thread_id, method)
90
+ overall_time = self.thread_time(thread_id)
91
+ (method.total_time/overall_time) * 100
92
+ end
93
+
94
+ def self_percent(method)
95
+ overall_time = self.thread_time(method.thread_id)
96
+ (method.self_time/overall_time) * 100
97
+ end
98
+
99
+ # Creates a link to a method. Note that we do not create
100
+ # links to methods which are under the min_perecent
101
+ # specified by the user, since they will not be
102
+ # printed out.
103
+ def create_link(thread_id, method)
104
+ if self.total_percent(thread_id, method) < min_percent
105
+ # Just return name
106
+ h method.full_name
107
+ else
108
+ href = '#' + method_href(thread_id, method)
109
+ "<a href=\"#{href}\">#{h method.full_name}</a>"
110
+ end
111
+ end
112
+
113
+ def method_href(thread_id, method)
114
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread_id.to_s)
115
+ end
116
+
117
+ def template
118
+ return IO.read(File.dirname(__FILE__) + "/template.rhtml")
119
+ end
120
+
121
+ end
122
+ end
123
+
@@ -0,0 +1,156 @@
1
+ <style media="all" type="text/css">
2
+ table {
3
+ border-collapse: collapse;
4
+ border: 1px solid #CCC;
5
+ font-family: Verdana, Arial, Helvetica, sans-serif;
6
+ font-size: 9pt;
7
+ line-height: normal;
8
+ width: 900px;
9
+ }
10
+
11
+ th {
12
+ text-align: center;
13
+ border-top: 1px solid #FB7A31;
14
+ border-bottom: 1px solid #FB7A31;
15
+ background: #FFC;
16
+ padding: 0.3em;
17
+ border-left: 1px solid silver;
18
+ }
19
+
20
+ tr.break td {
21
+ border: 0;
22
+ border-top: 1px solid #FB7A31;
23
+ padding: 0;
24
+ margin: 0;
25
+ }
26
+
27
+ tr.method td {
28
+ font-weight: bold;
29
+ }
30
+ td.method_name {
31
+ width: 200px;
32
+ }
33
+
34
+ td {
35
+ padding: 0.3em;
36
+ }
37
+
38
+ td:first-child {
39
+ width: 190px;
40
+ }
41
+
42
+ td {
43
+ border-left: 1px solid #CCC;
44
+ text-align: center;
45
+ }
46
+ #browser_profile {
47
+ width: 920px;
48
+ margin: 0 auto;
49
+ }
50
+
51
+ </style>
52
+ <div id="browser_profile">
53
+ <h1>Profile Report</h1>
54
+ <br/><br/>
55
+ <table>
56
+ <tr><th>Column</th><th>Description</th></tr>
57
+ <tr><td>%self</td><td>The percentage of time spent in this method, derived from self_time/total_time</td></tr>
58
+ <tr><td>cumulative</td><td>The sum of the time spent in this method and all the methods listed above it.</td></tr>
59
+ <tr><td>total</td><td>The time spent in this method and its children.</td></tr>
60
+ <tr><td>self</td><td>The time spent in this method.</td></tr>
61
+ <tr><td>children</td><td>The time spent in this method's children.</td></tr>
62
+ <tr><td>calls</td><td>The number of times this method was called.</td></tr>
63
+ <tr><td>self/call</td><td>The average time spent per call in this method.</td></tr>
64
+ <tr><td>total/call</td><td>The average time spent per call in this method and its children.</td></tr>
65
+ <tr><td>name</td><td>The name of the method.</td></tr>
66
+ </table>
67
+ <br/><br/>
68
+ <!-- Threads Table -->
69
+ <table>
70
+ <tr>
71
+ <th>Thread ID</th>
72
+ <th>Total Time</th>
73
+ </tr>
74
+ <% for thread_id, methods in @result.threads %>
75
+ <tr>
76
+ <td><a href="#<%= thread_id %>"><%= thread_id %></a></td>
77
+ <td><%= thread_time(thread_id) %></td>
78
+ </tr>
79
+ <% end %>
80
+ </table>
81
+
82
+ <!-- Methods Tables -->
83
+ <% for thread_id, methods in @result.threads
84
+ total_time = thread_time(thread_id) %>
85
+ <h2><a name="<%= thread_id %>">Thread <%= thread_id %></a></h2>
86
+
87
+ <table>
88
+ <tr>
89
+ <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Total") %></th>
90
+ <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Self") %></th>
91
+ <th><%= sprintf("%#{TIME_WIDTH}s", "Total") %></th>
92
+ <th><%= sprintf("%#{TIME_WIDTH}s", "Self") %></th>
93
+ <th><%= sprintf("%#{TIME_WIDTH}s", "Wait") %></th>
94
+ <th><%= sprintf("%#{TIME_WIDTH+2}s", "Child") %></th>
95
+ <th><%= sprintf("%#{CALL_WIDTH}s", "Calls") %></th>
96
+ <th>Name</th>
97
+ <th>Line</th>
98
+ </tr>
99
+
100
+ <% select_methods(methods).sort.reverse_each do |method|
101
+ total_percentage = (method.total_time/total_time) * 100
102
+ next if total_percentage < min_percent
103
+ self_percentage = (method.self_time/total_time) * 100
104
+ %>
105
+
106
+ <!-- Parents -->
107
+ <% for caller in select_methods(method.aggregate_parents) %>
108
+ <tr>
109
+ <td>&nbsp;</td>
110
+ <td>&nbsp;</td>
111
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.total_time) %></td>
112
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.self_time) %></td>
113
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.wait_time) %></td>
114
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.children_time) %></td>
115
+ <% called = "#{caller.called}/#{method.called}" %>
116
+ <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
117
+ <td><%= create_link(thread_id, caller.target) %></td>
118
+ <td><a href="file://<%= File.expand_path(caller.target.source_file) %>#line=<%= caller.line %>"><%= caller.line %></a></td>
119
+ </tr>
120
+ <% end %>
121
+
122
+ <tr class="method">
123
+ <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage) %></td>
124
+ <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage) %></td>
125
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %></td>
126
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %></td>
127
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.wait_time) %></td>
128
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %></td>
129
+ <td><%= sprintf("%#{CALL_WIDTH}i", method.called) %></td>
130
+ <td><a name="<%= method_href(thread_id, method) %>"><%= h method.full_name %></a></td>
131
+ <td><a href="file://<%= File.expand_path(method.source_file) %>#line=<%= method.line %>"><%= method.line %></a></td>
132
+ </tr>
133
+
134
+ <!-- Children -->
135
+ <% for callee in select_methods(method.children) %>
136
+ <tr>
137
+ <td>&nbsp;</td>
138
+ <td>&nbsp;</td>
139
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.total_time) %></td>
140
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.self_time) %></td>
141
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.wait_time) %></td>
142
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.children_time) %></td>
143
+ <% called = "#{callee.called}/#{callee.target.called}" %>
144
+ <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
145
+ <td><%= create_link(thread_id, callee.target) %></td>
146
+ <td><a href="file://<%= File.expand_path(method.source_file) %>#line=<%= callee.line %>"><%= callee.line %></a></td>
147
+ </tr>
148
+ <% end %>
149
+ <!-- Create divider row -->
150
+ <tr class="break"><td colspan="8"></td></tr>
151
+ <% end %>
152
+ </table>
153
+
154
+ <% end %>
155
+ </div>
156
+
Binary file
@@ -0,0 +1,365 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/tasklib'
4
+ require 'date'
5
+ require 'set'
6
+
7
+ module GithubGem
8
+
9
+ # Detects the gemspc file of this project using heuristics.
10
+ def self.detect_gemspec_file
11
+ FileList['*.gemspec'].first
12
+ end
13
+
14
+ # Detects the main include file of this project using heuristics
15
+ def self.detect_main_include
16
+ if detect_gemspec_file =~ /^(\.*)\.gemspec$/ && File.exist?("lib/#{$1}.rb")
17
+ "lib/#{$1}.rb"
18
+ elsif FileList['lib/*.rb'].length == 1
19
+ FileList['lib/*.rb'].first
20
+ else
21
+ nil
22
+ end
23
+ end
24
+
25
+ class RakeTasks
26
+
27
+ attr_reader :gemspec, :modified_files
28
+ attr_accessor :gemspec_file, :task_namespace, :main_include, :root_dir, :spec_pattern, :test_pattern, :remote, :remote_branch, :local_branch
29
+
30
+ # Initializes the settings, yields itself for configuration
31
+ # and defines the rake tasks based on the gemspec file.
32
+ def initialize(task_namespace = :gem)
33
+ @gemspec_file = GithubGem.detect_gemspec_file
34
+ @task_namespace = task_namespace
35
+ @main_include = GithubGem.detect_main_include
36
+ @modified_files = Set.new
37
+ @root_dir = Dir.pwd
38
+ @test_pattern = 'test/**/*_test.rb'
39
+ @spec_pattern = 'spec/**/*_spec.rb'
40
+ @local_branch = 'master'
41
+ @remote = 'origin'
42
+ @remote_branch = 'master'
43
+
44
+ yield(self) if block_given?
45
+
46
+ load_gemspec!
47
+ define_tasks!
48
+ end
49
+
50
+ protected
51
+
52
+ def git
53
+ @git ||= ENV['GIT'] || 'git'
54
+ end
55
+
56
+ # Define Unit test tasks
57
+ def define_test_tasks!
58
+ require 'rake/testtask'
59
+
60
+ namespace(:test) do
61
+ Rake::TestTask.new(:basic) do |t|
62
+ t.pattern = test_pattern
63
+ t.verbose = true
64
+ t.libs << 'test'
65
+ end
66
+ end
67
+
68
+ desc "Run all unit tests for #{gemspec.name}"
69
+ task(:test => ['test:basic'])
70
+ end
71
+
72
+ # Defines RSpec tasks
73
+ def define_rspec_tasks!
74
+ require 'rspec/core/rake_task'
75
+
76
+ namespace(:spec) do
77
+ desc "Verify all RSpec examples for #{gemspec.name}"
78
+ RSpec::Core::RakeTask.new(:basic) do |t|
79
+ t.pattern = spec_pattern
80
+ end
81
+
82
+ desc "Verify all RSpec examples for #{gemspec.name} and output specdoc"
83
+ RSpec::Core::RakeTask.new(:specdoc) do |t|
84
+ t.pattern = spec_pattern
85
+ t.rspec_opts = ['--format', 'documentation', '--color']
86
+ end
87
+
88
+ desc "Run RCov on specs for #{gemspec.name}"
89
+ RSpec::Core::RakeTask.new(:rcov) do |t|
90
+ t.pattern = spec_pattern
91
+ t.rcov = true
92
+ t.rcov_opts = ['--exclude', '"spec/*,gems/*"', '--rails']
93
+ end
94
+ end
95
+
96
+ desc "Verify all RSpec examples for #{gemspec.name} and output specdoc"
97
+ task(:spec => ['spec:specdoc'])
98
+ end
99
+
100
+ # Defines the rake tasks
101
+ def define_tasks!
102
+
103
+ define_test_tasks! if has_tests?
104
+ define_rspec_tasks! if has_specs?
105
+
106
+ namespace(@task_namespace) do
107
+ desc "Updates the filelist in the gemspec file"
108
+ task(:manifest) { manifest_task }
109
+
110
+ desc "Builds the .gem package"
111
+ task(:build => :manifest) { build_task }
112
+
113
+ desc "Sets the version of the gem in the gemspec"
114
+ task(:set_version => [:check_version, :check_current_branch]) { version_task }
115
+ task(:check_version => :fetch_origin) { check_version_task }
116
+
117
+ task(:fetch_origin) { fetch_origin_task }
118
+ task(:check_current_branch) { check_current_branch_task }
119
+ task(:check_clean_status) { check_clean_status_task }
120
+ task(:check_not_diverged => :fetch_origin) { check_not_diverged_task }
121
+
122
+ checks = [:check_current_branch, :check_clean_status, :check_not_diverged, :check_version]
123
+ checks.unshift('spec:basic') if has_specs?
124
+ checks.unshift('test:basic') if has_tests?
125
+ # checks.push << [:check_rubyforge] if gemspec.rubyforge_project
126
+
127
+ desc "Perform all checks that would occur before a release"
128
+ task(:release_checks => checks)
129
+
130
+ release_tasks = [:release_checks, :set_version, :build, :github_release, :gemcutter_release]
131
+ # release_tasks << [:rubyforge_release] if gemspec.rubyforge_project
132
+
133
+ desc "Release a new version of the gem using the VERSION environment variable"
134
+ task(:release => release_tasks) { release_task }
135
+
136
+ namespace(:release) do
137
+ desc "Release the next version of the gem, by incrementing the last version segment by 1"
138
+ task(:next => [:next_version] + release_tasks) { release_task }
139
+
140
+ desc "Release the next version of the gem, using a patch increment (0.0.1)"
141
+ task(:patch => [:next_patch_version] + release_tasks) { release_task }
142
+
143
+ desc "Release the next version of the gem, using a minor increment (0.1.0)"
144
+ task(:minor => [:next_minor_version] + release_tasks) { release_task }
145
+
146
+ desc "Release the next version of the gem, using a major increment (1.0.0)"
147
+ task(:major => [:next_major_version] + release_tasks) { release_task }
148
+ end
149
+
150
+ # task(:check_rubyforge) { check_rubyforge_task }
151
+ # task(:rubyforge_release) { rubyforge_release_task }
152
+ task(:gemcutter_release) { gemcutter_release_task }
153
+ task(:github_release => [:commit_modified_files, :tag_version]) { github_release_task }
154
+ task(:tag_version) { tag_version_task }
155
+ task(:commit_modified_files) { commit_modified_files_task }
156
+
157
+ task(:next_version) { next_version_task }
158
+ task(:next_patch_version) { next_version_task(:patch) }
159
+ task(:next_minor_version) { next_version_task(:minor) }
160
+ task(:next_major_version) { next_version_task(:major) }
161
+
162
+ desc "Updates the gem release tasks with the latest version on Github"
163
+ task(:update_tasks) { update_tasks_task }
164
+ end
165
+ end
166
+
167
+ # Updates the files list and test_files list in the gemspec file using the list of files
168
+ # in the repository and the spec/test file pattern.
169
+ def manifest_task
170
+ # Load all the gem's files using "git ls-files"
171
+ repository_files = `#{git} ls-files`.split("\n")
172
+ test_files = Dir[test_pattern] + Dir[spec_pattern]
173
+
174
+ update_gemspec(:files, repository_files)
175
+ update_gemspec(:test_files, repository_files & test_files)
176
+ end
177
+
178
+ # Builds the gem
179
+ def build_task
180
+ sh "gem build -q #{gemspec_file}"
181
+ Dir.mkdir('pkg') unless File.exist?('pkg')
182
+ sh "mv #{gemspec.name}-#{gemspec.version}.gem pkg/#{gemspec.name}-#{gemspec.version}.gem"
183
+ end
184
+
185
+ def newest_version
186
+ `#{git} tag`.split("\n").map { |tag| tag.split('-').last }.compact.map { |v| Gem::Version.new(v) }.max || Gem::Version.new('0.0.0')
187
+ end
188
+
189
+ def next_version(increment = nil)
190
+ next_version = newest_version.segments
191
+ increment_index = case increment
192
+ when :micro then 3
193
+ when :patch then 2
194
+ when :minor then 1
195
+ when :major then 0
196
+ else next_version.length - 1
197
+ end
198
+
199
+ next_version[increment_index] ||= 0
200
+ next_version[increment_index] = next_version[increment_index].succ
201
+ ((increment_index + 1)...next_version.length).each { |i| next_version[i] = 0 }
202
+
203
+ Gem::Version.new(next_version.join('.'))
204
+ end
205
+
206
+ def next_version_task(increment = nil)
207
+ ENV['VERSION'] = next_version(increment).version
208
+ puts "Releasing version #{ENV['VERSION']}..."
209
+ end
210
+
211
+ # Updates the version number in the gemspec file, the VERSION constant in the main
212
+ # include file and the contents of the VERSION file.
213
+ def version_task
214
+ update_gemspec(:version, ENV['VERSION']) if ENV['VERSION']
215
+ update_gemspec(:date, Date.today)
216
+
217
+ update_version_file(gemspec.version)
218
+ update_version_constant(gemspec.version)
219
+ end
220
+
221
+ def check_version_task
222
+ raise "#{ENV['VERSION']} is not a valid version number!" if ENV['VERSION'] && !Gem::Version.correct?(ENV['VERSION'])
223
+ proposed_version = Gem::Version.new((ENV['VERSION'] || gemspec.version).dup)
224
+ raise "This version (#{proposed_version}) is not higher than the highest tagged version (#{newest_version})" if newest_version >= proposed_version
225
+ end
226
+
227
+ # Checks whether the current branch is not diverged from the remote branch
228
+ def check_not_diverged_task
229
+ raise "The current branch is diverged from the remote branch!" if `#{git} rev-list HEAD..#{remote}/#{remote_branch}`.split("\n").any?
230
+ end
231
+
232
+ # Checks whether the repository status ic clean
233
+ def check_clean_status_task
234
+ raise "The current working copy contains modifications" if `#{git} ls-files -m`.split("\n").any?
235
+ end
236
+
237
+ # Checks whether the current branch is correct
238
+ def check_current_branch_task
239
+ raise "Currently not on #{local_branch} branch!" unless `#{git} branch`.split("\n").detect { |b| /^\* / =~ b } == "* #{local_branch}"
240
+ end
241
+
242
+ # Fetches the latest updates from Github
243
+ def fetch_origin_task
244
+ sh git, 'fetch', remote
245
+ end
246
+
247
+ # Commits every file that has been changed by the release task.
248
+ def commit_modified_files_task
249
+ really_modified = `#{git} ls-files -m #{modified_files.entries.join(' ')}`.split("\n")
250
+ if really_modified.any?
251
+ really_modified.each { |file| sh git, 'add', file }
252
+ sh git, 'commit', '-m', "Released #{gemspec.name} gem version #{gemspec.version}."
253
+ end
254
+ end
255
+
256
+ # Adds a tag for the released version
257
+ def tag_version_task
258
+ sh git, 'tag', '-a', "#{gemspec.name}-#{gemspec.version}", '-m', "Released #{gemspec.name} gem version #{gemspec.version}."
259
+ end
260
+
261
+ # Pushes the changes and tag to github
262
+ def github_release_task
263
+ sh git, 'push', '--tags', remote, remote_branch
264
+ end
265
+
266
+ def gemcutter_release_task
267
+ sh "gem", 'push', "pkg/#{gemspec.name}-#{gemspec.version}.gem"
268
+ end
269
+
270
+ # Gem release task.
271
+ # All work is done by the task's dependencies, so just display a release completed message.
272
+ def release_task
273
+ puts
274
+ puts "Release successful."
275
+ end
276
+
277
+ private
278
+
279
+ # Checks whether this project has any RSpec files
280
+ def has_specs?
281
+ FileList[spec_pattern].any?
282
+ end
283
+
284
+ # Checks whether this project has any unit test files
285
+ def has_tests?
286
+ FileList[test_pattern].any?
287
+ end
288
+
289
+ # Loads the gemspec file
290
+ def load_gemspec!
291
+ @gemspec = eval(File.read(@gemspec_file))
292
+ end
293
+
294
+ # Updates the VERSION file with the new version
295
+ def update_version_file(version)
296
+ if File.exists?('VERSION')
297
+ File.open('VERSION', 'w') { |f| f << version.to_s }
298
+ modified_files << 'VERSION'
299
+ end
300
+ end
301
+
302
+ # Updates the VERSION constant in the main include file if it exists
303
+ def update_version_constant(version)
304
+ if main_include && File.exist?(main_include)
305
+ file_contents = File.read(main_include)
306
+ if file_contents.sub!(/^(\s+VERSION\s*=\s*)[^\s].*$/) { $1 + version.to_s.inspect }
307
+ File.open(main_include, 'w') { |f| f << file_contents }
308
+ modified_files << main_include
309
+ end
310
+ end
311
+ end
312
+
313
+ # Updates an attribute of the gemspec file.
314
+ # This function will open the file, and search/replace the attribute using a regular expression.
315
+ def update_gemspec(attribute, new_value, literal = false)
316
+
317
+ unless literal
318
+ new_value = case new_value
319
+ when Array then "%w(#{new_value.join(' ')})"
320
+ when Hash, String then new_value.inspect
321
+ when Date then new_value.strftime('%Y-%m-%d').inspect
322
+ else raise "Cannot write value #{new_value.inspect} to gemspec file!"
323
+ end
324
+ end
325
+
326
+ spec = File.read(gemspec_file)
327
+ regexp = Regexp.new('^(\s+\w+\.' + Regexp.quote(attribute.to_s) + '\s*=\s*)[^\s].*$')
328
+ if spec.sub!(regexp) { $1 + new_value }
329
+ File.open(gemspec_file, 'w') { |f| f << spec }
330
+ modified_files << gemspec_file
331
+
332
+ # Reload the gemspec so the changes are incorporated
333
+ load_gemspec!
334
+
335
+ # Also mark the Gemfile.lock file as changed because of the new version.
336
+ modified_files << 'Gemfile.lock' if File.exist?(File.join(root_dir, 'Gemfile.lock'))
337
+ end
338
+ end
339
+
340
+ # Updates the tasks file using the latest file found on Github
341
+ def update_tasks_task
342
+ require 'net/https'
343
+ require 'uri'
344
+
345
+ uri = URI.parse('https://github.com/wvanbergen/github-gem/raw/master/tasks/github-gem.rake')
346
+ http = Net::HTTP.new(uri.host, uri.port)
347
+ http.use_ssl = true
348
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
349
+ response = http.request(Net::HTTP::Get.new(uri.path))
350
+
351
+ if Net::HTTPSuccess === response
352
+ open(__FILE__, "w") { |file| file.write(response.body) }
353
+ relative_file = File.expand_path(__FILE__).sub(%r[^#{@root_dir}/], '')
354
+ if `#{git} ls-files -m #{relative_file}`.split("\n").any?
355
+ sh git, 'add', relative_file
356
+ sh git, 'commit', '-m', "Updated to latest gem release management tasks."
357
+ else
358
+ puts "Release managament tasks already are at the latest version."
359
+ end
360
+ else
361
+ raise "Download failed with HTTP status #{response.code}!"
362
+ end
363
+ end
364
+ end
365
+ end
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ class SlowControllerTest < ActionController::TestCase
4
+ test "should profile" do
5
+ get :profile_me, :params => {}
6
+ assert_response :success
7
+ assert_equal "slow action", @response.body
8
+ end
9
+
10
+ test "should have mixin" do
11
+ assert @controller.respond_to?(:process_with_browser_profiling)
12
+ end
13
+
14
+ test "should profile param adds profile" do
15
+ get :profile_me, :params => {"browser_profile!" => ""}
16
+ assert_response :success
17
+
18
+ assert profiled?(@response.body)
19
+ end
20
+
21
+ test "should output to file" do
22
+ clean_outfile
23
+
24
+ get :profile_me, :params => {"file_profile!" => ""}
25
+ assert_response :success
26
+
27
+ assert ! profiled?(@response.body)
28
+ assert File.exists?(profile_out_file)
29
+ assert profiled?(File.read(profile_out_file))
30
+
31
+ clean_outfile
32
+ end
33
+
34
+ end
@@ -0,0 +1,34 @@
1
+ # Bootstrap rails
2
+ ENV["RAILS_ENV"] = "test"
3
+ rails_path = File.expand_path(File.dirname(__FILE__) + "/../rails_test/config/environment.rb")
4
+
5
+ unless File.exists?(rails_path)
6
+ p 'Rails not found, please run:'
7
+ p '$ rails rails_test'
8
+ exit
9
+ end
10
+ require rails_path
11
+
12
+ require 'test_help'
13
+ require 'pp'
14
+ require File.expand_path(File.dirname(__FILE__) +'/../init.rb') # Load browser=prof into rails_env
15
+
16
+ class SlowController < ActionController::Base
17
+ def profile_me
18
+ sleep 1
19
+ render :text => "slow action"
20
+ end
21
+ end
22
+
23
+ # Helpers
24
+ def clean_outfile
25
+ FileUtils.rm_rf(profile_out_file)
26
+ end
27
+
28
+ def profiled?(body)
29
+ (body =~ /browser_profile/) && (body =~ /Profile Report/)
30
+ end
31
+
32
+ def profile_out_file
33
+ "#{RAILS_ROOT}/log/profile_out.html"
34
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: browser-prof
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 2
9
+ - 3
10
+ version: 1.2.3
11
+ platform: ruby
12
+ authors:
13
+ - Willem van Bergen
14
+ - Bart ten Brinke
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-02-17 00:00:00 +01:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rake
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 2
47
+ - 0
48
+ version: "2.0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: ruby-prof
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ type: :development
64
+ version_requirements: *id003
65
+ description: " This is a simple tool to profile single web requests in Rails using the power or ruby-prof.\n"
66
+ email:
67
+ - willem@railsdoctors.com
68
+ - bart@railsdoctors.com
69
+ executables: []
70
+
71
+ extensions: []
72
+
73
+ extra_rdoc_files:
74
+ - README.rdoc
75
+ files:
76
+ - .gitignore
77
+ - MIT-LICENSE
78
+ - README.rdoc
79
+ - Rakefile
80
+ - browser-prof.gemspec
81
+ - init.rb
82
+ - lib/browser-prof.rb
83
+ - lib/ruby-prof/graph_html_printer_enhanced.rb
84
+ - lib/ruby-prof/template.rhtml
85
+ - pkg/browser_profiler-1.2.0.gem
86
+ - tasks/github-gem.rake
87
+ - test/functional/slow_controller_test.rb
88
+ - test/test_helper.rb
89
+ has_rdoc: true
90
+ homepage: http://railsdoctors.com
91
+ licenses: []
92
+
93
+ post_install_message:
94
+ rdoc_options:
95
+ - --title
96
+ - browser-prof
97
+ - --main
98
+ - README.rdoc
99
+ - --line-numbers
100
+ - --inline-source
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ requirements:
122
+ - ruby-prof gem is required.
123
+ rubyforge_project:
124
+ rubygems_version: 1.3.7
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Rails tool to to profile single requests using ruby-prof.
128
+ test_files:
129
+ - test/functional/slow_controller_test.rb