browser-prof 1.2.3

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