rack-profiler 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f67856e0027806b21c8fa11c400055049be97e5f
4
- data.tar.gz: 50a680263ec4263e64cf53f63ff991bed6d6bd8e
3
+ metadata.gz: 10111d8a7faa32f82444b864868a3364a4c557b3
4
+ data.tar.gz: b77adab1e71c584c5075da95b8eb60f737c84d79
5
5
  SHA512:
6
- metadata.gz: 8df8668240edd5c83482b5f9c67efd68c191af79fc279eb6f704af00139ad98a1b219f4cfa8c481ec557b6761be64f8891d1b09cdb754a1833fa442653c03875
7
- data.tar.gz: 18c2d0048b5bc978d7937ca24b8d727ef2b815f00e1a097cbfca81538c33ecf5ef799ef86435e0728ab828fe41a6c61c3e5f9a1a8c58a69a375c7540eaf1910d
6
+ metadata.gz: 3306764da5aa9f681a1025ce5a0c43ea7cd08d210b8813e0a8e9ff7ab93ab7551ffdf11305479a28f7889e2641a0207170e32ed21e84b6c27117580529494514
7
+ data.tar.gz: 0647b6ba8a86a09f3d45e2d71c3c71164d494637364cdfdb8af90865ab1a488affc1fe115c9d2530f39f18af3ae53e638bf9b15f3a3e950a594a9d4d8d290fde
data/README.md CHANGED
@@ -1,6 +1,21 @@
1
1
  # Rack::Profiler
2
2
 
3
- Simple profiler for Rack applications
3
+ Simple profiler for Rack applications (Sinatra and Ruby on Rails for example).
4
+
5
+ `Rack::Profiler` uses the [Active Support Instrumentation API](http://guides.rubyonrails.org/active_support_instrumentation.html)
6
+ and subscribes to the following hooks:
7
+
8
+ * [sql.active_record](http://guides.rubyonrails.org/active_support_instrumentation.html#sql-active-record)
9
+ * [render_template.action_view](http://guides.rubyonrails.org/active_support_instrumentation.html#render_template.action_view)
10
+ * [render_partial.action_view](http://guides.rubyonrails.org/active_support_instrumentation.html#render_partial.action_view)
11
+ * [process_action.action_controller](http://guides.rubyonrails.org/active_support_instrumentation.html#process_action.action_controller)
12
+
13
+ You can also define your own events, by wrapping your code with the
14
+ [`Rack::Profiler.step`](#custom-steps).
15
+
16
+ `Rack::Profiler` is easy to integrate in any Rack application and it produces a
17
+ JSON response with the results. It also exposes a simple web dashboard to directly
18
+ issue HTTP requests to your application and see the results of the profiling.
4
19
 
5
20
  ## Installation
6
21
 
@@ -10,6 +25,8 @@ Add this line to your application's Gemfile:
10
25
  gem 'rack-profiler'
11
26
  ```
12
27
 
28
+ *You might want to put the gem in the development group if you are using Rails.*
29
+
13
30
  And then execute:
14
31
 
15
32
  $ bundle
@@ -18,7 +35,7 @@ Or install it yourself as:
18
35
 
19
36
  $ gem install rack-profiler
20
37
 
21
- ## Usage
38
+ ### Rack/Sinatra
22
39
 
23
40
  In your `config.ru` use the `Rack::Profiler` middleware at the beginning of your
24
41
  middleware stack:
@@ -28,21 +45,31 @@ require 'rack/profiler'
28
45
  use Rack::Profiler
29
46
  ```
30
47
 
31
- By default `Rack::Profiler` will subscribe to `ActiveRecord` SQL queries and to
32
- steps you define in your code with:
48
+ ### Rails
49
+
50
+ You can add the `Rack::Profiler` middleware at the beginning of your `config.ru`
51
+ like in the Rack/Sinatra installation or insert it in the middlewares stack configuration
52
+ in the `application.rb`:
33
53
 
34
54
  ```ruby
35
- Rack::Profiler.step('your-step-name') do
36
- # Do stuff. The profiler will tell you how long it took to perform this step
55
+ module YourApp
56
+ class Application < Rails::Application
57
+
58
+ # ...
59
+ config.middleware.insert_before Rack::Runtime, Rack::Profiler
60
+
61
+ end
37
62
  end
38
63
  ```
39
64
 
40
- You can also subscribe to more notifications:
65
+ ## Configuration
66
+
67
+ You can configure `Rack::Profiler` to subscribe to more notifications:
41
68
 
42
69
  ```ruby
43
- Rack::Profiler.configure do |profiler|
44
- # Subscribe to template rendering in a Rails app
45
- profiler.subscribe('render_template.action_view')
70
+ Rack::Profiler.configure do |config|
71
+ # Subscribe to email delivery in a Rails app
72
+ config.subscribe('deliver.action_mailer')
46
73
  end
47
74
  ```
48
75
 
@@ -50,12 +77,52 @@ You can also specify a backtrace filter to exclude lines that are not
50
77
  interesting:
51
78
 
52
79
  ```ruby
53
- Rack::Profiler.configure do |profiler|
80
+ Rack::Profiler.configure do |config|
54
81
  # Exclude gems from the backtrace
55
- profiler.filter_backtrace { |line| !line.include? '/gems/' }
82
+ config.filter_backtrace { |line| !line.include? '/gems/' }
56
83
  end
57
84
  ```
58
85
 
86
+ You can put these configurations in your `config.ru` for a Rack/Sinatra application
87
+ or in an initializer `config/rack_profiler.rb` for Rails apps.
88
+
89
+ ## Usage
90
+
91
+ ### Custom steps
92
+
93
+ By default `Rack::Profiler` will subscribe to `ActiveRecord` SQL queries,
94
+ `ActionView` rendering events (templates and partials), `ActionController`
95
+ actions and to steps you define in your code with:
96
+
97
+ ```ruby
98
+ Rack::Profiler.step('your-step-name') do
99
+ # Do stuff. The profiler will tell you how long it took to perform this step
100
+ end
101
+ ```
102
+
103
+ ### Web Dashboard
104
+
105
+ A graphical interface to profile your application pages/endpoints and display the
106
+ results is automatically mounted at this route:
107
+
108
+ http://<your-app-url>/rack-profiler
109
+
110
+ Just select the HTTP verb, insert the relative path to your app and add some
111
+ optional parameters like POST/PUT data: `Rack::Profiler` automatically send
112
+ the request to your app with the `rack-profiler` param and display the
113
+ results in a nice graphical way.
114
+
115
+
116
+ ### Raw JSON result
117
+
118
+ If you want to access the results of the profiling as raw JSON data, you can just
119
+ add the `rack-profiler` parameter (it can be null) to any HTTP request
120
+ to your app (GET, POST, PUT, PATCH, DELETE): `Rack::Profiler` will execute the
121
+ request and return a JSON response containing the results along with the
122
+ original response.
123
+
124
+ http://<your-app-url>/<path>?rack-profiler
125
+
59
126
  ## Contributing
60
127
 
61
128
  1. Fork it ( https://github.com/dawanda/rack-profiler/fork )
@@ -1,3 +1,5 @@
1
+ require "rack"
2
+ require "rack/request"
1
3
  require "rack/profiler/version"
2
4
  require "active_support/notifications"
3
5
 
@@ -6,22 +8,12 @@ module Rack
6
8
  class DummyError < StandardError; end
7
9
 
8
10
  module ClassMethods
9
- attr_reader :backtrace_filter
10
-
11
11
  def configure(&block)
12
- instance_exec(self, &block)
13
- end
14
-
15
- def filter_backtrace(&block)
16
- @backtrace_filter = block
12
+ block.call(config)
17
13
  end
18
14
 
19
- def dashboard_path=(path)
20
- @dashboard_path = path
21
- end
22
-
23
- def dashboard_path
24
- @dashboard_path || '/rack-profiler'
15
+ def config
16
+ @config ||= Configuration.new
25
17
  end
26
18
 
27
19
  def step(name, payload = {})
@@ -29,37 +21,42 @@ module Rack
29
21
  yield
30
22
  end
31
23
  end
24
+ end
25
+
26
+ class Configuration
27
+ attr_reader :subscriptions, :backtrace_filter
28
+ attr_accessor :dashboard_path
29
+
30
+ DEFAULT_SUBSCRIPTIONS = ['sql.active_record',
31
+ 'render_template.action_view',
32
+ 'render_partial.action_view',
33
+ 'process_action.action_controller',
34
+ 'rack-profiler.total_time',
35
+ 'rack-profiler.step']
32
36
 
33
- def render_dashboard
34
- dashboard = ::File.expand_path( '../../public/rack-profiler.html', ::File.dirname( __FILE__ ) )
35
- body = ::File.open(dashboard, ::File::RDONLY)
36
- [200, { 'Content-Type' => 'text/html' }, body]
37
+ def initialize
38
+ @subscriptions = DEFAULT_SUBSCRIPTIONS.clone
39
+ @dashboard_path = '/rack-profiler'
37
40
  end
38
41
 
39
- def subscribe(name)
40
- (@subscriptions ||= []) << name
42
+ def subscribe(*names)
43
+ names.each { |name| @subscriptions << name }
41
44
  @subscriptions.uniq!
42
45
  end
43
46
 
44
- def subscriptions
45
- @subscriptions || []
47
+ def filter_backtrace(&block)
48
+ @backtrace_filter = block
46
49
  end
47
50
  end
48
51
 
49
52
  extend ClassMethods
50
53
 
51
- # Subscribe to interesting events
52
- subscribe('sql.active_record')
53
- subscribe('render_template.action_view')
54
- subscribe('render_partial.action_view')
55
- subscribe('process_action.action_controller')
56
- subscribe('rack-profiler.step')
57
-
58
54
  attr_reader :events
59
55
 
60
56
  def initialize(app)
61
- subscribe_all_events
62
- @app = app
57
+ subscribe_to_all
58
+ @events = []
59
+ @app = app
63
60
  end
64
61
 
65
62
  def call(env)
@@ -67,13 +64,22 @@ module Rack
67
64
  status, headers, body = [nil, nil, nil]
68
65
  req = Rack::Request.new(env)
69
66
 
70
- if req.path == Profiler.dashboard_path
71
- Profiler.render_dashboard
67
+ if req.path == config.dashboard_path
68
+ render_dashboard
72
69
  elsif req.params.has_key?('rack-profiler')
73
- Profiler.step('total_time') do
70
+ ActiveSupport::Notifications.instrument('rack-profiler.total_time') do
74
71
  status, headers, body = @app.call(env)
75
72
  end
76
- [200, { 'Content-Type' => 'application/json' }, [{ events: nested_events, response: { status: status, headers: headers, body: stringify_body(body) } }.to_json]]
73
+ [ 200,
74
+ { 'Content-Type' => 'application/json' },
75
+ [ { events: events.sort_by { |event| event[:start] },
76
+ response: {
77
+ status: status,
78
+ headers: headers,
79
+ body: stringify_body(body)
80
+ }
81
+ }.to_json ]
82
+ ]
77
83
  else
78
84
  @status, @headers, @body = @app.call(env)
79
85
  end
@@ -95,28 +101,23 @@ module Rack
95
101
  end
96
102
  end
97
103
 
98
- def nested_events
99
- events.sort_by { |evt| evt[:start] }.reduce([]) do |list, evt|
100
- nest_event(list, list, evt)
101
- end
104
+ def config
105
+ self.class.config
102
106
  end
103
107
 
104
108
  private
105
109
 
106
- def subscribe_all_events
107
- self.class.subscriptions.each do |event|
108
- subscribe(event)
109
- end
110
+ def render_dashboard
111
+ dashboard = ::File.expand_path( '../../public/rack-profiler.html', ::File.dirname( __FILE__ ) )
112
+ body = ::File.open(dashboard, ::File::RDONLY)
113
+ [200, { 'Content-Type' => 'text/html' }, body]
110
114
  end
111
115
 
112
- def nest_event(list, children, evt)
113
- previous = children.last
114
- if previous && evt[:finish] <= previous[:finish]
115
- nest_event(list, previous[:children] ||= [], evt)
116
- else
117
- children << evt
116
+ def subscribe_to_all
117
+ # Subscribe to interesting events
118
+ config.subscriptions.each do |event|
119
+ subscribe(event)
118
120
  end
119
- list
120
121
  end
121
122
 
122
123
  def tap_backtrace
@@ -128,17 +129,17 @@ module Rack
128
129
  end
129
130
 
130
131
  def filtered_backtrace(backtrace)
131
- if self.class.backtrace_filter.nil?
132
+ if config.backtrace_filter.nil?
132
133
  backtrace
133
134
  else
134
- backtrace.select(&self.class.backtrace_filter)
135
+ backtrace.select(&config.backtrace_filter)
135
136
  end
136
137
  end
137
138
 
138
139
  def stringify_body(body)
139
140
  body.close if body.respond_to?(:close)
140
141
  str = ""
141
- body.each {|part| str << part }
142
+ body.each { |part| str << part }
142
143
  str
143
144
  end
144
145
  end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Profiler
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
5
5
  end
@@ -16,6 +16,9 @@
16
16
  .response-info {
17
17
  margin-bottom: 1em;
18
18
  }
19
+ .response-info pre {
20
+ max-height: 350px;
21
+ }
19
22
 
20
23
  .pr-steps td:first-child {
21
24
  width: 800px;
@@ -23,7 +26,7 @@
23
26
 
24
27
  .step-bar {
25
28
  display: inline-block;
26
- background: #5bc0de;
29
+ background: #777;
27
30
  position: relative;
28
31
  box-sizing: border-box;
29
32
  margin-top: 0.2em;
@@ -31,6 +34,10 @@
31
34
  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15)
32
35
  }
33
36
 
37
+ .step-bar.step-type-step {
38
+ background: #5bc0de;
39
+ }
40
+
34
41
  .step-bar.step-type-sql {
35
42
  background: #f0ad4e;
36
43
  }
@@ -51,6 +58,7 @@
51
58
  background-color: #f5f5f5;
52
59
  border: 1px solid #ccc;
53
60
  border-radius: 4px;
61
+ overflow-wrap: break-word;
54
62
  }
55
63
 
56
64
  .key-value-list li {
@@ -237,8 +245,11 @@
237
245
  .done(function( data, status, xhr ) {
238
246
  $(".stats").show()
239
247
 
240
- var rootEvent = data.events[0],
241
- queryCount = 0,
248
+ var rootEvent = data.events.filter(function(event) {
249
+ return event.name == 'rack-profiler.total_time'
250
+ })[0]
251
+
252
+ var queryCount = 0,
242
253
  headersKeyVal = exposeKeyValues( data.response.headers ),
243
254
  responseWrap = $.extend( {}, data.response, { headers: headersKeyVal } )
244
255
 
@@ -270,6 +281,7 @@
270
281
  case 'render_template.action_view': eventType = 'render-template'; break;
271
282
  case 'process_action.action_controller': eventType = 'process-action'; break;
272
283
  case 'rack-profiler.step': eventType = 'step'; break;
284
+ case 'rack-profiler.total_time': eventType = 'total-time'; break;
273
285
  default: eventType = 'other'
274
286
  }
275
287
 
@@ -285,10 +297,6 @@
285
297
  }
286
298
  $(".pr-steps tbody").append( Mustache.render( stepTmpl, stepEvent ) )
287
299
 
288
- // Recurse on children
289
- if ( event.children ) {
290
- renderEvents( event.children )
291
- }
292
300
  })
293
301
  }
294
302
 
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "rack"
21
22
  spec.add_dependency "activesupport", ">= 3.0.0"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.7"
@@ -1,55 +1,50 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
+ require 'json'
3
+
4
+ def trigger_dummy_event(name, payload = {})
5
+ ActiveSupport::Notifications.instrument(name, payload) do
6
+ "do stuff"
7
+ end
8
+ end
2
9
 
3
10
  describe Rack::Profiler do
4
11
  let(:profiler) { Rack::Profiler.new(nil) }
5
12
 
6
- def trigger_dummy_event(name, payload = {})
7
- ActiveSupport::Notifications.instrument(name, payload) do
8
- "do stuff"
9
- end
13
+ it "has a version number" do
14
+ expect(Rack::Profiler::VERSION).not_to be_nil
10
15
  end
11
16
 
12
- it 'has a version number' do
13
- expect(Rack::Profiler::VERSION).not_to be nil
14
- end
17
+ describe :initialize do
18
+ it "subscribes to all subscriptions" do
19
+ config = Rack::Profiler::Configuration.new
20
+ config.subscribe("bar")
21
+ allow(Rack::Profiler).to receive(:config).and_return(config)
15
22
 
16
- describe :nested_events do
17
- it "returns events properly nested" do
18
- evt1 = { start: 1, finish: 10 }
19
- evt2 = { start: 2, finish: 3 }
20
- evt3 = { start: 4, finish: 8 }
21
- evt4 = { start: 5, finish: 8 }
22
- evt5 = { start: 9, finish: 10 }
23
- evts = [evt1, evt2, evt3, evt4, evt5]
24
- allow(profiler).to receive(:events).and_return(evts)
25
- nested = profiler.nested_events
26
- expect(nested.first).to be(evt1)
27
- expect(evt1[:children].first).to be(evt2)
28
- expect(evt1[:children][1]).to be(evt3)
29
- expect(evt3[:children].first).to be(evt4)
30
- expect(evt1[:children].last).to be(evt5)
23
+ profiler = Rack::Profiler.new(nil)
24
+ trigger_dummy_event("bar")
25
+ expect(profiler.events.last[:name]).to eq("bar")
31
26
  end
32
27
  end
33
28
 
34
29
  describe :subscribe do
35
30
  before do
36
- profiler.subscribe('foo')
31
+ profiler.subscribe("foo")
37
32
  end
38
33
 
39
- it "subscribe to event populating the event list" do
40
- trigger_dummy_event('foo')
34
+ it "subscribes to event populating the event list" do
35
+ trigger_dummy_event("foo")
41
36
  event = profiler.events.last
42
- expect(event[:name]).to eq('foo')
37
+ expect(event[:name]).to eq("foo")
43
38
  end
44
39
 
45
- it "populate event with the proper keys" do
46
- trigger_dummy_event('foo')
40
+ it "populates event with the proper keys" do
41
+ trigger_dummy_event("foo")
47
42
  event = profiler.events.last
48
43
  expect(event.keys).to include(:id, :name, :start, :finish, :duration, :payload, :backtrace)
49
44
  end
50
45
 
51
46
  it "adds the backtrace" do
52
- trigger_dummy_event('foo')
47
+ trigger_dummy_event("foo")
53
48
  event = profiler.events.last
54
49
  expect(event[:backtrace].any? do |line|
55
50
  line.include?("trigger_dummy_event")
@@ -57,10 +52,10 @@ describe Rack::Profiler do
57
52
  end
58
53
 
59
54
  it "filters the backtrace if a filter was provided" do
60
- Rack::Profiler.filter_backtrace do |line|
55
+ Rack::Profiler.config.filter_backtrace do |line|
61
56
  !line.include?("trigger_dummy_event")
62
57
  end
63
- trigger_dummy_event('foo')
58
+ trigger_dummy_event("foo")
64
59
  event = profiler.events.last
65
60
  expect(event[:backtrace].any? do |line|
66
61
  line.include?("trigger_dummy_event")
@@ -71,37 +66,175 @@ describe Rack::Profiler do
71
66
  end
72
67
 
73
68
  it "adds the payload" do
74
- trigger_dummy_event('foo', bar: 'baz')
69
+ trigger_dummy_event("foo", bar: "baz")
75
70
  event = profiler.events.last
76
- expect(event[:payload]).to eq(bar: 'baz')
71
+ expect(event[:payload]).to eq(bar: "baz")
77
72
  end
78
73
  end
79
74
 
80
- describe ".subscribe" do
81
- it "causes any newly created instance to subscribe to the given event" do
82
- Rack::Profiler.subscribe('bar')
83
- profiler = Rack::Profiler.new(nil)
84
- trigger_dummy_event('bar')
85
- event = profiler.events.last
86
- expect(event[:name]).to eq('bar')
75
+ describe :call do
76
+ let(:app) do
77
+ Proc.new { |env|
78
+ Rack::Profiler.step 'foo' do
79
+ [200, { 'X-My-Header' => 'foo' }, ['hello hello']]
80
+ end
81
+ }
82
+ end
83
+
84
+ let(:profiler) do
85
+ Rack::Profiler.new(app)
86
+ end
87
+
88
+ let(:env) do
89
+ {
90
+ "PATH_INFO" => "/",
91
+ "QUERY_STRING" => "",
92
+ "REMOTE_HOST" => "localhost",
93
+ "REQUEST_METHOD" => "GET",
94
+ "REQUEST_URI" => "http://localhost:3000/",
95
+ "SCRIPT_NAME" => "",
96
+ "SERVER_NAME" => "localhost",
97
+ "SERVER_PORT" => "3000",
98
+ "SERVER_PROTOCOL" => "HTTP/1.1",
99
+ "HTTP_HOST" => "localhost:3000",
100
+ "rack.version" => [1, 2],
101
+ "rack.input" => StringIO.new,
102
+ "rack.errors" => StringIO.new,
103
+ "rack.multithread" => true,
104
+ "rack.multiprocess" => false,
105
+ "rack.run_once" => false,
106
+ "rack.url_scheme" => "http",
107
+ "HTTP_VERSION" => "HTTP/1.1",
108
+ "REQUEST_PATH" => "/"
109
+ }
110
+ end
111
+
112
+ it "clears events" do
113
+ profiler.events << 'xxx'
114
+ profiler.call(env)
115
+ expect(profiler.events).not_to include('xxx')
116
+ end
117
+
118
+ context "when the path is config.dashboard_path" do
119
+ it "renders dashboard" do
120
+ expect(profiler).to receive(:render_dashboard)
121
+ profiler.call env.merge(
122
+ "PATH_INFO" => profiler.config.dashboard_path,
123
+ "REQUEST_PATH" => profiler.config.dashboard_path
124
+ )
125
+ end
126
+ end
127
+
128
+ context "when the rack-profiler parameter is not present" do
129
+ it "transparently returns the original response" do
130
+ expect(profiler.call(env)).to eq(app.call(env))
131
+ end
132
+ end
133
+
134
+ context "when the rack-profiler parameter is present" do
135
+ let(:env_with_param) {
136
+ env.merge('QUERY_STRING' => 'rack-profiler')
137
+ }
138
+
139
+ it "returns a JSON response" do
140
+ status, headers, body = profiler.call(env_with_param)
141
+ expect(headers).to match('Content-Type' => 'application/json')
142
+ expect { JSON.parse(body.join) }.not_to raise_error
143
+ end
144
+
145
+ it "puts the original response in the JSON payload" do
146
+ status, headers, body = profiler.call(env_with_param)
147
+ parsed_body = JSON.parse(body.join)
148
+ expect(parsed_body['response']).to eq(
149
+ 'status' => 200,
150
+ 'headers' => { 'X-My-Header' => 'foo' },
151
+ 'body' => 'hello hello'
152
+ )
153
+ end
154
+
155
+ it "puts the received events in the JSON payload" do
156
+ status, headers, body = profiler.call(env_with_param)
157
+ parsed_body = JSON.parse(body.join)
158
+ expect(
159
+ parsed_body['events'].map { |e| e['name'] }
160
+ ).to include('rack-profiler.total_time', 'rack-profiler.step')
161
+ end
87
162
  end
88
163
  end
89
164
 
90
165
  describe ".step" do
91
- it "calls ActiveSupport::Notifications.instrument with the right arguments" do
166
+ it "calls ActiveSupport::Notifications.instrument with the right args" do
92
167
  expect(ActiveSupport::Notifications).to receive(:instrument).with(
93
- 'rack-profiler.step', { step_name: 'xxx' })
94
- Rack::Profiler.step('xxx') do
168
+ "rack-profiler.step", { step_name: "xxx" })
169
+ Rack::Profiler.step("xxx") do
95
170
  "do stuff"
96
171
  end
97
172
  end
98
173
 
99
174
  it "mixes data in the payload if provided" do
100
175
  expect(ActiveSupport::Notifications).to receive(:instrument).with(
101
- 'rack-profiler.step', { step_name: 'xxx', foo: 'bar' })
102
- Rack::Profiler.step('xxx', foo: 'bar') do
176
+ "rack-profiler.step", { step_name: "xxx", foo: "bar" })
177
+ Rack::Profiler.step("xxx", foo: "bar") do
103
178
  "do stuff"
104
179
  end
105
180
  end
106
181
  end
182
+
183
+ describe ".configure" do
184
+ it "executes the given block passing the configuration object" do
185
+ config_inside_block = nil
186
+ Rack::Profiler.configure do |c|
187
+ config_inside_block = c
188
+ end
189
+ expect(config_inside_block).to be(Rack::Profiler.config)
190
+ end
191
+ end
192
+
193
+ describe ".config" do
194
+ it "instantiates a Configuration object if there is none" do
195
+ Rack::Profiler.send(:instance_variable_set, :@config, nil)
196
+ expect(Rack::Profiler.config).to be_a(Rack::Profiler::Configuration)
197
+ end
198
+ end
199
+ end
200
+
201
+ describe Rack::Profiler::Configuration do
202
+ let(:config) { Rack::Profiler::Configuration.new }
203
+
204
+ it "has the correct defaults" do
205
+ expect(config.dashboard_path).to eq('/rack-profiler')
206
+ expect(config.backtrace_filter).to be_nil
207
+ expect(config.subscriptions).to include(
208
+ *Rack::Profiler::Configuration::DEFAULT_SUBSCRIPTIONS
209
+ )
210
+ end
211
+
212
+ describe :subscribe do
213
+ it "adds entries to subscriptions" do
214
+ config.subscribe('bar')
215
+ expect(config.subscriptions).to include('bar')
216
+ end
217
+
218
+ it "accepts more than one subscription" do
219
+ config.subscribe('bar', 'baz')
220
+ expect(config.subscriptions).to include('bar', 'baz')
221
+ end
222
+
223
+ it "does not add duplicates" do
224
+ config.subscribe('bar', 'bar')
225
+ expect(
226
+ config.subscriptions.count { |s| s == 'bar' }
227
+ ).to eq(1)
228
+ end
229
+ end
230
+
231
+ describe :filter_backtrace do
232
+ it "sets the backtrace_filter" do
233
+ config.filter_backtrace do |line|
234
+ line.include? 'foo'
235
+ end
236
+ filtered = ['foo', 'foobar', 'baz'].select(&config.backtrace_filter)
237
+ expect(filtered).to eq(['foo', 'foobar'])
238
+ end
239
+ end
107
240
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Ongaro
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-01-26 00:00:00.000000000 Z
12
+ date: 2015-01-27 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: activesupport
16
30
  requirement: !ruby/object:Gem::Requirement