test-prof 0.3.0.beta3 → 0.3.0.pre

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: 6f2516ff090c97feae6be50fe1edc765aa495337
4
- data.tar.gz: d6c4aba8cd0ace60d4c80898a8cfc1b22015a32c
3
+ metadata.gz: b81e0cb37ac0120a12a8497dc9de6fe7d14c4c53
4
+ data.tar.gz: b5f060c7d0ce985e5e4508be8cc2f161efe9389b
5
5
  SHA512:
6
- metadata.gz: ddf6a60d44432bc56b253b7c667f40efedee36f7f37a4710c826ef5625dcb5c6768416e2c8fea681843894dfd8e39d78ba53ea48fb7ff6ee382eb24b807e8afa
7
- data.tar.gz: 5fadec4649c715e2fcd93ab5ec6fc4b3e55c6b2cfeba877659431cb6894d3dcc9ed9a5b6bef5b46b36f28cfd34d928a2618b89f195808cc4ef95d9b0f6935f50
6
+ metadata.gz: c12c578c836c7553655925489fce0bdc1509b930f6f9170976e9b1d8eb4ba75fd60644e1f84eba92162cb9b365030d9a978b559635ce9b665c162fedf696b074
7
+ data.tar.gz: f81248b95f3320095878ad45288766d5646dd6f3dab53ecae844cc3fe12fa6e7f31ce3ec1502105aa00e02fee04fa64fc458e14e43e78dca0eff7bac5f7ff79a
data/CHANGELOG.md CHANGED
@@ -4,20 +4,6 @@
4
4
 
5
5
  Features:
6
6
 
7
- - Combine RSpecStamp with FactoryDoctor. ([@palkan][])
8
-
9
- Automatically mark _bad_ examples with custom tags.
10
-
11
- - [#17](https://github.com/palkan/test-prof/pull/17) Combine RSpecStamp with EventProf and RSpecDissect. ([@palkan][])
12
-
13
- It is possible now to automatically mark _slow_ examples and groups with custom tags. For example:
14
-
15
- ```sh
16
- EVENT_PROF="sql.active_record" EVENT_PROF_STAMP="slow:sql" rspec ...
17
- ```
18
-
19
- After running the command above the top 5 slowest example groups would be marked with `slow: :sql` tag.
20
-
21
7
  - [#14](https://github.com/palkan/test-prof/pull/14) RSpecDissect profiler. ([@palkan][])
22
8
 
23
9
  RSpecDissect tracks how much time do you spend in `before` hooks
@@ -27,16 +13,6 @@ and memoization helpers (i.e. `let`) in your tests.
27
13
 
28
14
  Just like `let`, but persist the result for the whole group (i.e. `let` + `before_all`).
29
15
 
30
- ## 0.2.5
31
-
32
- - [#16](https://github.com/palkan/test-prof/pull/16) Support Ruby >= 2.2.0 (was >= 2.3.0). ([@palkan][])
33
-
34
- ## 0.2.4
35
-
36
- - EventProf: Fix regression bug with examples profiling. ([@palkan][])
37
-
38
- There was a bug when an event occurs before the example has started (e.g. in `before(:context)` hook).
39
-
40
16
  ## 0.2.3
41
17
 
42
18
  - Minor improvements. ([@palkan][])
data/README.md CHANGED
@@ -24,12 +24,6 @@ Of course, we have some [solutions](#tips-and-tricks) for common performance iss
24
24
 
25
25
  See [Table of Contents](#table-of-contents) for more.
26
26
 
27
- Supported Ruby versions:
28
-
29
- - Ruby (MRI) >= 2.2.0
30
-
31
- - JRuby >= 9.1.0.0
32
-
33
27
  <a href="https://evilmartians.com/">
34
28
  <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
35
29
 
data/guides/event_prof.md CHANGED
@@ -66,16 +66,6 @@ EVENT_PROF_RANK=count EVENT_PROF='instantiation.active_record' be rspec
66
66
 
67
67
  See [event_prof.rb](https://github.com/palkan/test-prof/tree/master/lib/test_prof/event_prof.rb) for all available configuration options and their usage.
68
68
 
69
- ## Using with RSpecStamp
70
-
71
- EventProf can be used with [RSpec Stamp](https://github.com/palkan/test-prof/tree/master/guides/rspec_stamp.md) to automatically mark _slow_ examples with custom tags. For example:
72
-
73
- ```sh
74
- EVENT_PROF="sql.active_record" EVENT_PROF_STAMP="slow:sql" rspec ...
75
- ```
76
-
77
- After running the command above the slowest example groups (and examples if configured) would be marked with the `slow: :sql` tag.
78
-
79
69
  ## Custom Instrumentation
80
70
 
81
71
  To use EventProf with your instrumentation engine just complete the two following steps:
@@ -62,13 +62,3 @@ To activate FactoryDoctor use `FDOC` environment variable:
62
62
  ```sh
63
63
  FDOC=1 rspec ...
64
64
  ```
65
-
66
- ## Using with RSpecStamp
67
-
68
- FactoryDoctor can be used with [RSpec Stamp](https://github.com/palkan/test-prof/tree/master/guides/rspec_stamp.md) to automatically mark _bad_ examples with custom tags. For example:
69
-
70
- ```sh
71
- FDOC=1 FDOC_STAMP="fdoc:consider" rspec ...
72
- ```
73
-
74
- After running the command above all _potentially_ bad examples would be marked with the `fdoc: :consider` tag.
@@ -47,12 +47,3 @@ You can also specify the number of top slow groups through `RD_TOP` variable:
47
47
  RD=1 RD_TOP=10 rspec ...
48
48
  ```
49
49
 
50
- ## Using with RSpecStamp
51
-
52
- RSpecDissect can be used with [RSpec Stamp](https://github.com/palkan/test-prof/tree/master/guides/rspec_stamp.md) to automatically mark _slow_ examples with custom tags. For example:
53
-
54
- ```sh
55
- RD=1 RD_STAMP="slow" rspec ...
56
- ```
57
-
58
- After running the command above the slowest example groups would be marked with the `:slow` tag.
@@ -39,7 +39,7 @@ module RuboCop
39
39
 
40
40
  def on_block(node)
41
41
  method, _args, body = *node
42
- return unless body && body.begin_type?
42
+ return unless body&.begin_type?
43
43
 
44
44
  _receiver, method_name, _object = *method
45
45
  return unless GROUP_BLOCKS.include?(method_name)
@@ -109,7 +109,7 @@ module RuboCop
109
109
  end
110
110
 
111
111
  def oneliner?(node)
112
- node && node.block_type? &&
112
+ node&.block_type? &&
113
113
  (node.source.lines.size == 1) &&
114
114
  example_node?(node)
115
115
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/rspec_stamp"
4
3
  require "test_prof/event_prof/instrumentations/active_support"
5
4
  require "test_prof/utils/sized_ordered_set"
6
5
 
@@ -40,13 +39,6 @@ module TestProf
40
39
  @top_count = (ENV['EVENT_PROF_TOP'] || 5).to_i
41
40
  @per_example = ENV['EVENT_PROF_EXAMPLES'] == '1'
42
41
  @rank_by = (ENV['EVENT_PROF_RANK'] || :time).to_sym
43
- @stamp = ENV['EVENT_PROF_STAMP']
44
-
45
- RSpecStamp.config.tags = @stamp if stamp?
46
- end
47
-
48
- def stamp?
49
- !@stamp.nil?
50
42
  end
51
43
 
52
44
  def per_example?
@@ -113,7 +105,7 @@ module TestProf
113
105
  @time += time
114
106
  @count += 1
115
107
 
116
- return if @current_example.nil?
108
+ return unless config.per_example?
117
109
 
118
110
  @example_time += time
119
111
  @example_count += 1
@@ -132,10 +124,8 @@ module TestProf
132
124
  @current_group = nil
133
125
  end
134
126
 
135
- def example_started(id)
136
- return unless config.per_example?
137
- reset_example!
138
- @current_example = id
127
+ def example_started(_id)
128
+ reset_example! if config.per_example?
139
129
  end
140
130
 
141
131
  def example_finished(id)
@@ -144,7 +134,6 @@ module TestProf
144
134
 
145
135
  data = { id: id, time: @example_time, count: @example_count }
146
136
  @examples << data unless data[rank_by].zero?
147
- @current_example = nil
148
137
  end
149
138
 
150
139
  def results
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
- using TestProf::StringStripHeredoc
6
-
7
3
  module TestProf::EventProf::CustomEvents
8
4
  module FactoryCreate # :nodoc: all
9
5
  module RunnerPatch
@@ -46,7 +42,7 @@ end
46
42
  TestProf.activate('EVENT_PROF', 'factory.create') do
47
43
  if TestProf.require(
48
44
  'factory_girl',
49
- <<-MSG.strip_heredoc
45
+ <<~MSG
50
46
  Failed to load FactoryGirl.
51
47
 
52
48
  Make sure that "factory_girl" gem is in your Gemfile.
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
- using TestProf::StringStripHeredoc
6
-
7
3
  module TestProf::EventProf::CustomEvents
8
4
  module SidekiqInline # :nodoc: all
9
5
  module ClientPatch
@@ -43,7 +39,7 @@ end
43
39
  TestProf.activate('EVENT_PROF', 'sidekiq.inline') do
44
40
  if TestProf.require(
45
41
  'sidekiq/testing',
46
- <<-MSG.strip_heredoc
42
+ <<~MSG
47
43
  Failed to load Sidekiq.
48
44
 
49
45
  Make sure that "sidekiq" gem is in your Gemfile.
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
- using TestProf::StringStripHeredoc
6
-
7
3
  module TestProf::EventProf::CustomEvents
8
4
  module SidekiqJobs # :nodoc: all
9
5
  module ClientPatch
@@ -30,7 +26,7 @@ end
30
26
  TestProf.activate('EVENT_PROF', 'sidekiq.jobs') do
31
27
  if TestProf.require(
32
28
  'sidekiq/testing',
33
- <<-MSG.strip_heredoc
29
+ <<~MSG
34
30
  Failed to load Sidekiq.
35
31
 
36
32
  Make sure that "sidekiq" gem is in your Gemfile.
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
4
  require "test_prof/ext/string_truncate"
5
- require "test_prof/ext/string_strip_heredoc"
6
5
 
7
6
  module TestProf
8
7
  module EventProf
@@ -10,7 +9,6 @@ module TestProf
10
9
  include Logging
11
10
  using FloatDuration
12
11
  using StringTruncate
13
- using StringStripHeredoc
14
12
 
15
13
  NOTIFICATIONS = %i[
16
14
  example_group_started
@@ -47,7 +45,7 @@ module TestProf
47
45
  msgs = []
48
46
 
49
47
  msgs <<
50
- <<-MSG.strip_heredoc
48
+ <<~MSG
51
49
  EventProf results for #{@profiler.event}
52
50
 
53
51
  Total time: #{@profiler.total_time.duration}
@@ -62,7 +60,7 @@ module TestProf
62
60
  location = group[:id].metadata[:location]
63
61
 
64
62
  msgs <<
65
- <<-GROUP.strip_heredoc
63
+ <<~GROUP
66
64
  #{description.truncate} (#{location}) – #{group[:time].duration} (#{group[:count]} / #{group[:examples]})
67
65
  GROUP
68
66
  end
@@ -74,48 +72,13 @@ module TestProf
74
72
  description = example[:id].description
75
73
  location = example[:id].metadata[:location]
76
74
  msgs <<
77
- <<-GROUP.strip_heredoc
75
+ <<~GROUP
78
76
  #{description.truncate} (#{location}) – #{example[:time].duration} (#{example[:count]})
79
77
  GROUP
80
78
  end
81
79
  end
82
80
 
83
81
  log :info, msgs.join
84
-
85
- stamp! if EventProf.config.stamp?
86
- end
87
-
88
- def stamp!
89
- result = @profiler.results
90
-
91
- stamper = RSpecStamp::Stamper.new
92
-
93
- examples = Hash.new { |h, k| h[k] = [] }
94
-
95
- (result[:groups].to_a + result.fetch(:examples, []).to_a)
96
- .map { |obj| obj[:id].metadata[:location] }.each do |location|
97
- file, line = location.split(":")
98
- examples[file] << line.to_i
99
- end
100
-
101
- examples.each do |file, lines|
102
- stamper.stamp_file(file, lines.uniq)
103
- end
104
-
105
- msgs = []
106
-
107
- msgs <<
108
- <<-MSG.strip_heredoc
109
- RSpec Stamp results
110
-
111
- Total patches: #{stamper.total}
112
- Total files: #{examples.keys.size}
113
-
114
- Failed patches: #{stamper.failed}
115
- Ignored files: #{stamper.ignored}
116
- MSG
117
-
118
- log :info, msgs.join
119
82
  end
120
83
  end
121
84
  end
@@ -16,7 +16,7 @@ module TestProf
16
16
  end
17
17
 
18
18
  def bad?
19
- count > 0 && queries_count.zero?
19
+ count.positive? && queries_count.zero?
20
20
  end
21
21
  end
22
22
 
@@ -54,14 +54,6 @@ module TestProf
54
54
  defined?(::FactoryGirl)
55
55
 
56
56
  subscribe!
57
-
58
- @stamp = ENV['FDOC_STAMP']
59
-
60
- RSpecStamp.config.tags = @stamp if stamp?
61
- end
62
-
63
- def stamp?
64
- !@stamp.nil?
65
57
  end
66
58
 
67
59
  def start
@@ -119,7 +111,7 @@ module TestProf
119
111
  end
120
112
 
121
113
  def within_factory?
122
- @depth > 0
114
+ @depth.positive?
123
115
  end
124
116
 
125
117
  def ignore?
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
- require "test_prof/ext/string_strip_heredoc"
5
4
 
6
5
  module TestProf
7
6
  module FactoryDoctor
8
7
  class RSpecListener # :nodoc:
9
8
  include Logging
10
9
  using FloatDuration
11
- using StringStripHeredoc
12
10
 
13
- SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'.freeze
11
+ SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'
14
12
 
15
13
  NOTIFICATIONS = %i[
16
14
  example_started
@@ -51,7 +49,7 @@ module TestProf
51
49
  msgs = []
52
50
 
53
51
  msgs <<
54
- <<-MSG.strip_heredoc
52
+ <<~MSG
55
53
  FactoryDoctor report
56
54
 
57
55
  Total (potentially) bad examples: #{@count}
@@ -70,40 +68,6 @@ module TestProf
70
68
  end
71
69
 
72
70
  log :info, msgs.join
73
-
74
- stamp! if FactoryDoctor.stamp?
75
- end
76
-
77
- def stamp!
78
- stamper = RSpecStamp::Stamper.new
79
-
80
- examples = Hash.new { |h, k| h[k] = [] }
81
-
82
- @example_groups.each do |_group, bad_examples|
83
- bad_examples.each do |example|
84
- file, line = example.metadata[:location].split(":")
85
- examples[file] << line.to_i
86
- end
87
- end
88
-
89
- examples.each do |file, lines|
90
- stamper.stamp_file(file, lines.uniq)
91
- end
92
-
93
- msgs = []
94
-
95
- msgs <<
96
- <<-MSG.strip_heredoc
97
- RSpec Stamp results
98
-
99
- Total patches: #{stamper.total}
100
- Total files: #{examples.keys.size}
101
-
102
- Failed patches: #{stamper.failed}
103
- Ignored files: #{stamper.ignored}
104
- MSG
105
-
106
- log :info, msgs.join
107
71
  end
108
72
 
109
73
  private
@@ -1,19 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf::FactoryProf
6
4
  module Printers
7
5
  module Simple # :nodoc: all
8
6
  class << self
9
7
  include TestProf::Logging
10
- using TestProf::StringStripHeredoc
11
8
 
12
9
  def dump(result)
13
10
  msgs = []
14
11
 
15
12
  msgs <<
16
- <<-MSG.strip_heredoc
13
+ <<~MSG
17
14
  Factories usage
18
15
 
19
16
  total top-level name
@@ -12,7 +12,7 @@ RSpec.shared_context "any_fixture:clean", with_clean_fixture: true do
12
12
 
13
13
  def open_transaction?
14
14
  pool = ActiveRecord::Base.connection_pool
15
- pool.active_connection? && pool.connection.open_transactions > 0
15
+ pool.active_connection? && pool.connection.open_transactions.positive?
16
16
  end
17
17
  end
18
18
 
@@ -6,27 +6,18 @@ module TestProf
6
6
  # Just like `let`, but persist the result for the whole group.
7
7
  # NOTE: Experimental and magical, for more control use `before_all`.
8
8
  module LetItBe
9
- class << self
10
- def module_for(group)
11
- modules.fetch(group) do
12
- Module.new.tap { |mod| group.prepend(mod) }
13
- end
14
- end
15
-
16
- private
17
-
18
- def modules
19
- @modules ||= {}
20
- end
21
- end
22
9
  # Use uniq prefix for instance variables to avoid collisions
23
10
  # We want to use the power of Ruby's unicode support)
24
11
  # And we love cats!)
25
- PREFIX = RUBY_ENGINE == 'jruby' ? "@__jruby_is_not_cat_friendly__".freeze : "@😸".freeze
12
+ PREFIX = "@😸"
13
+
14
+ def let_it_be(identifier, reload: false, refind: false, &block)
15
+ raise ArgumentError, "Block is required!" unless block_given?
16
+
17
+ this = self
26
18
 
27
- def let_it_be(identifier, **options, &block)
28
19
  initializer = proc do
29
- instance_variable_set(:"#{PREFIX}#{identifier}", instance_exec(&block))
20
+ this.instance_variable_set(:"#{PREFIX}#{identifier}", this.instance_exec(&block))
30
21
  end
31
22
 
32
23
  if within_before_all?
@@ -35,41 +26,20 @@ module TestProf
35
26
  before_all(&initializer)
36
27
  end
37
28
 
38
- define_let_it_be_methods(identifier, **options)
39
- end
29
+ let_accessor = accessor = -> { this.instance_variable_get(:"#{PREFIX}#{identifier}") }
40
30
 
41
- def define_let_it_be_methods(identifier, reload: false, refind: false)
42
- let_accessor = -> { instance_variable_get(:"#{PREFIX}#{identifier}") }
43
-
44
- if reload
45
- let_accessor = lambda do
46
- record = instance_variable_get(:"#{PREFIX}#{identifier}")
47
- next unless record.is_a?(::ActiveRecord::Base)
48
- record.reload
49
- end
50
- end
31
+ let_accessor = -> { this.instance_variable_get(:"#{PREFIX}#{identifier}")&.reload } if reload
51
32
 
52
33
  if refind
53
34
  let_accessor = lambda do
54
- record = instance_variable_get(:"#{PREFIX}#{identifier}")
35
+ record = this.instance_variable_get(:"#{PREFIX}#{identifier}")
55
36
  next unless record.is_a?(::ActiveRecord::Base)
56
37
 
57
38
  record.class.find(record.send(record.class.primary_key))
58
39
  end
59
40
  end
60
41
 
61
- LetItBe.module_for(self).module_eval do
62
- define_method(identifier) do
63
- # Trying to detect the context (couldn't find other way so far)
64
- if @__inspect_output =~ /\(:context\)/
65
- instance_variable_get(:"#{PREFIX}#{identifier}")
66
- else
67
- # Fallback to let definition
68
- super()
69
- end
70
- end
71
- end
72
-
42
+ define_singleton_method(identifier, &accessor)
73
43
  let(identifier, &let_accessor)
74
44
  end
75
45
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/rspec_stamp"
4
3
  require "test_prof/logging"
5
4
 
6
5
  module TestProf
@@ -37,13 +36,6 @@ module TestProf
37
36
 
38
37
  def initialize
39
38
  @top_count = (ENV['RD_TOP'] || 5).to_i
40
- @stamp = ENV['RD_STAMP']
41
-
42
- RSpecStamp.config.tags = @stamp if stamp?
43
- end
44
-
45
- def stamp?
46
- !@stamp.nil?
47
39
  end
48
40
  end
49
41
 
@@ -3,7 +3,6 @@
3
3
  require "test_prof/ext/float_duration"
4
4
  require "test_prof/ext/string_truncate"
5
5
  require "test_prof/utils/sized_ordered_set"
6
- require "test_prof/ext/string_strip_heredoc"
7
6
 
8
7
  module TestProf
9
8
  module RSpecDissect
@@ -11,7 +10,6 @@ module TestProf
11
10
  include Logging
12
11
  using FloatDuration
13
12
  using StringTruncate
14
- using StringStripHeredoc
15
13
 
16
14
  NOTIFICATIONS = %i[
17
15
  example_finished
@@ -60,7 +58,7 @@ module TestProf
60
58
  msgs = []
61
59
 
62
60
  msgs <<
63
- <<-MSG.strip_heredoc
61
+ <<~MSG
64
62
  RSpecDissect report
65
63
 
66
64
  Total time: #{@total_examples_time.duration}
@@ -70,65 +68,32 @@ module TestProf
70
68
  MSG
71
69
 
72
70
  msgs <<
73
- <<-MSG.strip_heredoc
71
+ <<~MSG
74
72
  Top #{top_count} slowest suites (by `before(:each)` time):
75
73
 
76
74
  MSG
77
75
 
78
76
  @before_results.each do |group|
79
77
  msgs <<
80
- <<-GROUP.strip_heredoc
78
+ <<~GROUP
81
79
  #{group[:desc].truncate} (#{group[:loc]}) – #{group[:before].duration} of #{group[:total].duration} (#{group[:count]})
82
80
  GROUP
83
81
  end
84
82
 
85
83
  msgs <<
86
- <<-MSG.strip_heredoc
84
+ <<~MSG
87
85
  Top #{top_count} slowest suites (by `let` time):
88
86
 
89
87
  MSG
90
88
 
91
89
  @memo_results.each do |group|
92
90
  msgs <<
93
- <<-GROUP.strip_heredoc
91
+ <<~GROUP
94
92
  #{group[:desc].truncate} (#{group[:loc]}) – #{group[:memo].duration} of #{group[:total].duration} (#{group[:count]})
95
93
  GROUP
96
94
  end
97
95
 
98
96
  log :info, msgs.join
99
-
100
- stamp! if RSpecDissect.config.stamp?
101
- end
102
-
103
- def stamp!
104
- stamper = RSpecStamp::Stamper.new
105
-
106
- examples = Hash.new { |h, k| h[k] = [] }
107
-
108
- (@before_results.to_a + @memo_results.to_a)
109
- .map { |obj| obj[:loc] }.each do |location|
110
- file, line = location.split(":")
111
- examples[file] << line.to_i
112
- end
113
-
114
- examples.each do |file, lines|
115
- stamper.stamp_file(file, lines.uniq)
116
- end
117
-
118
- msgs = []
119
-
120
- msgs <<
121
- <<-MSG.strip_heredoc
122
- RSpec Stamp results
123
-
124
- Total patches: #{stamper.total}
125
- Total files: #{examples.keys.size}
126
-
127
- Failed patches: #{stamper.failed}
128
- Ignored files: #{stamper.ignored}
129
- MSG
130
-
131
- log :info, msgs.join
132
97
  end
133
98
 
134
99
  private
@@ -44,49 +44,6 @@ module TestProf
44
44
  end
45
45
  end
46
46
 
47
- # Stamper collects statistics about applying tags
48
- # to examples.
49
- class Stamper
50
- include TestProf::Logging
51
-
52
- attr_reader :total, :failed, :ignored
53
-
54
- def initialize
55
- @total = 0
56
- @failed = 0
57
- @ignored = 0
58
- end
59
-
60
- def stamp_file(file, lines)
61
- @total += lines.size
62
- return if ignored?(file)
63
-
64
- log :info, "(dry-run) Patching #{file}" if dry_run?
65
-
66
- code = File.readlines(file)
67
-
68
- @failed += RSpecStamp.apply_tags(code, lines, RSpecStamp.config.tags)
69
-
70
- File.write(file, code.join) unless dry_run?
71
- end
72
-
73
- private
74
-
75
- def ignored?(file)
76
- ignored = RSpecStamp.config.ignore_files.find do |pattern|
77
- file =~ pattern
78
- end
79
-
80
- return unless ignored
81
- log :warn, "Ignore stamping file: #{file}"
82
- @ignored += 1
83
- end
84
-
85
- def dry_run?
86
- RSpecStamp.config.dry_run?
87
- end
88
- end
89
-
90
47
  class << self
91
48
  include TestProf::Logging
92
49
 
@@ -127,7 +84,7 @@ module TestProf
127
84
  parsed = Parser.parse(code)
128
85
  return false unless parsed
129
86
 
130
- desc = parsed.desc_const || quote(parsed.desc || 'works')
87
+ parsed.desc ||= 'works'
131
88
 
132
89
  tags.each do |t|
133
90
  if t.is_a?(Hash)
@@ -144,9 +101,9 @@ module TestProf
144
101
  need_parens = block == "{"
145
102
 
146
103
  tags_str = parsed.tags.map { |t| t.is_a?(Symbol) ? ":#{t}" : t }.join(", ") unless
147
- parsed.tags.nil? || parsed.tags.empty?
104
+ parsed.tags.nil?
148
105
 
149
- unless parsed.htags.nil? || parsed.htags.empty?
106
+ unless parsed.htags.nil?
150
107
  htags_str = parsed.htags.map do |(k, v)|
151
108
  vstr = v.is_a?(Symbol) ? ":#{v}" : quote(v)
152
109
 
@@ -155,7 +112,7 @@ module TestProf
155
112
  end
156
113
 
157
114
  replacement = "\\1#{parsed.fname}#{need_parens ? '(' : ' '}"\
158
- "#{[desc, tags_str, htags_str].compact.join(', ')}"\
115
+ "#{[quote(parsed.desc), tags_str, htags_str].compact.join(', ')}"\
159
116
  "#{need_parens ? ') ' : ' '}\\3"
160
117
 
161
118
  if config.dry_run?
@@ -169,7 +126,6 @@ module TestProf
169
126
  # rubocop: enable Metrics/PerceivedComplexity
170
127
 
171
128
  def quote(str)
172
- return str unless str.is_a?(String)
173
129
  if str.include?("'")
174
130
  "\"#{str}\""
175
131
  else
@@ -2,13 +2,15 @@
2
2
 
3
3
  require "ripper"
4
4
 
5
+ # rubocop: disable Metrics/CyclomaticComplexity
6
+
5
7
  module TestProf
6
8
  module RSpecStamp
7
9
  # Parse examples headers
8
10
  module Parser
9
11
  # Contains the result of parsing
10
12
  class Result
11
- attr_accessor :fname, :desc, :desc_const
13
+ attr_accessor :fname, :desc
12
14
  attr_reader :tags, :htags
13
15
 
14
16
  def add_tag(v)
@@ -22,14 +24,12 @@ module TestProf
22
24
  end
23
25
 
24
26
  def remove_tag(tag)
25
- @tags.delete(tag) if @tags
26
- @htags.delete_if { |(k, _v)| k == tag } if @htags
27
+ @tags&.delete(tag)
28
+ @htags&.delete_if { |(k, _v)| k == tag }
27
29
  end
28
30
  end
29
31
 
30
32
  class << self
31
- # rubocop: disable Metrics/CyclomaticComplexity
32
- # rubocop: disable Metrics/PerceivedComplexity
33
33
  def parse(code)
34
34
  sexp = Ripper.sexp(code)
35
35
  return unless sexp
@@ -58,16 +58,10 @@ module TestProf
58
58
  res = Result.new
59
59
 
60
60
  fcall = sexp[1][0][1]
61
- args_block = sexp[1][0][2]
62
-
63
- if fcall.first == :fcall
64
- fcall = fcall[1]
65
- elsif fcall.first == :var_ref
66
- res.fname = [parse_const(fcall), sexp[1][0][3][1]].join(".")
67
- args_block = sexp[1][0][4]
68
- end
61
+ fcall = fcall[1] if fcall.first == :fcall
62
+ res.fname = fcall[1]
69
63
 
70
- res.fname ||= fcall[1]
64
+ args_block = sexp[1][0][2]
71
65
 
72
66
  return res if args_block.nil?
73
67
 
@@ -77,16 +71,12 @@ module TestProf
77
71
 
78
72
  if args.first.first == :string_literal
79
73
  res.desc = parse_literal(args.shift)
80
- elsif args.first.first == :var_ref || args.first.first == :const_path_ref
81
- res.desc_const = parse_const(args.shift)
82
74
  end
83
75
 
84
76
  parse_arg(res, args.shift) until args.empty?
85
77
 
86
78
  res
87
79
  end
88
- # rubocop: enable Metrics/CyclomaticComplexity
89
- # rubocop: enable Metrics/PerceivedComplexity
90
80
 
91
81
  private
92
82
 
@@ -100,24 +90,7 @@ module TestProf
100
90
 
101
91
  def parse_hash(res, hash_arg)
102
92
  hash_arg.each do |(_, label, val)|
103
- res.add_htag label[1][0..-2].to_sym, parse_value(val)
104
- end
105
- end
106
-
107
- # Expr of the form:
108
- # bool - [:var_ref, [:@kw, "true", [1, 24]]]
109
- # string - [:string_literal, [:string_content, [...]]]
110
- # int - [:@int, "3", [1, 52]]]]
111
- def parse_value(expr)
112
- case expr.first
113
- when :var_ref
114
- expr[1][1] == "true"
115
- when :@int
116
- expr[1].to_i
117
- when :@float
118
- expr[1].to_f
119
- else
120
- parse_literal(expr)
93
+ res.add_htag label[1][0..-2].to_sym, parse_literal(val)
121
94
  end
122
95
  end
123
96
 
@@ -129,25 +102,6 @@ module TestProf
129
102
  expr[0] == :assoc_new
130
103
  val
131
104
  end
132
-
133
- # Expr of the form:
134
- # [:var_ref, [:@const, "User", [1, 9]]]
135
- #
136
- # or
137
- #
138
- # [:const_path_ref, [:const_path_ref, [:var_ref,
139
- # [:@const, "User", [1, 17]]],
140
- # [:@const, "Guest", [1, 23]]],
141
- # [:@const, "Collection", [1, 30]]
142
- def parse_const(expr)
143
- if expr.first == :var_ref
144
- expr[1][1]
145
- elsif expr.first == :@const
146
- expr[1]
147
- elsif expr.first == :const_path_ref
148
- expr[1..-1].map(&method(:parse_const)).join("::")
149
- end
150
- end
151
105
  end
152
106
  end
153
107
  end
@@ -1,12 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf
6
4
  module RSpecStamp
7
5
  class RSpecListener # :nodoc:
8
6
  include Logging
9
- using StringStripHeredoc
10
7
 
11
8
  NOTIFICATIONS = %i[
12
9
  example_failed
@@ -30,27 +27,54 @@ module TestProf
30
27
  end
31
28
 
32
29
  def stamp!
33
- stamper = Stamper.new
34
-
35
30
  @examples.each do |file, lines|
36
- stamper.stamp_file(file, lines.uniq)
31
+ stamp_file(file, lines.uniq)
37
32
  end
38
33
 
39
34
  msgs = []
40
35
 
41
36
  msgs <<
42
- <<-MSG.strip_heredoc
37
+ <<~MSG
43
38
  RSpec Stamp results
44
39
 
45
- Total patches: #{stamper.total}
40
+ Total patches: #{@total}
46
41
  Total files: #{@examples.keys.size}
47
42
 
48
- Failed patches: #{stamper.failed}
49
- Ignored files: #{stamper.ignored}
43
+ Failed patches: #{@failed}
44
+ Ignored files: #{@ignored}
50
45
  MSG
51
46
 
52
47
  log :info, msgs.join
53
48
  end
49
+
50
+ private
51
+
52
+ def stamp_file(file, lines)
53
+ @total += lines.size
54
+ return if ignored?(file)
55
+
56
+ log :info, "(dry-run) Patching #{file}" if dry_run?
57
+
58
+ code = File.readlines(file)
59
+
60
+ @failed += RSpecStamp.apply_tags(code, lines, RSpecStamp.config.tags)
61
+
62
+ File.write(file, code.join) unless dry_run?
63
+ end
64
+
65
+ def ignored?(file)
66
+ ignored = RSpecStamp.config.ignore_files.find do |pattern|
67
+ file =~ pattern
68
+ end
69
+
70
+ return unless ignored
71
+ log :warn, "Ignore stamping file: #{file}"
72
+ @ignored += 1
73
+ end
74
+
75
+ def dry_run?
76
+ RSpecStamp.config.dry_run?
77
+ end
54
78
  end
55
79
  end
56
80
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf
6
4
  # RubyProf wrapper.
7
5
  #
@@ -121,7 +119,6 @@ module TestProf
121
119
 
122
120
  class << self
123
121
  include Logging
124
- using StringStripHeredoc
125
122
 
126
123
  def config
127
124
  @config ||= Configuration.new
@@ -175,7 +172,7 @@ module TestProf
175
172
  ENV["RUBY_PROF_MEASURE_MODE"] = config.mode.to_s
176
173
  @initialized = TestProf.require(
177
174
  'ruby-prof',
178
- <<-MSG.strip_heredoc
175
+ <<~MSG
179
176
  Please, install 'ruby-prof' first:
180
177
  # Gemfile
181
178
  gem 'ruby-prof', '>= 0.16.0', require: false
@@ -187,7 +184,7 @@ module TestProf
187
184
  if Utils.verify_gem_version('ruby-prof', at_least: '0.16.0')
188
185
  true
189
186
  else
190
- log :error, <<-MGS.strip_heredoc
187
+ log :error, <<~MGS
191
188
  Please, upgrade 'ruby-prof' to version >= 0.16.0.
192
189
  MGS
193
190
  false
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf
6
4
  # StackProf wrapper.
7
5
  #
@@ -34,7 +32,6 @@ module TestProf
34
32
 
35
33
  class << self
36
34
  include Logging
37
- using StringStripHeredoc
38
35
 
39
36
  def config
40
37
  @config ||= Configuration.new
@@ -91,7 +88,7 @@ module TestProf
91
88
 
92
89
  html_path = path.gsub(/\.dump$/, '.html')
93
90
 
94
- log :info, <<-MSG.strip_heredoc
91
+ log :info, <<~MSG
95
92
  Run the following command to generate a flame graph report:
96
93
 
97
94
  stackprof --flamegraph #{path} > #{html_path} && stackprof --flamegraph-viewer=#{html_path}
@@ -114,7 +111,7 @@ module TestProf
114
111
  return @initialized if instance_variable_defined?(:@initialized)
115
112
  @initialized = TestProf.require(
116
113
  'stackprof',
117
- <<-MSG.strip_heredoc
114
+ <<~MSG
118
115
  Please, install 'stackprof' first:
119
116
  # Gemfile
120
117
  gem 'stackprof', '>= 0.2.9', require: false
@@ -126,9 +123,9 @@ module TestProf
126
123
  if Utils.verify_gem_version('stackprof', at_least: '0.2.9')
127
124
  true
128
125
  else
129
- log :error, <<-MSG.strip_heredoc
126
+ log :error, <<~MGS
130
127
  Please, upgrade 'stackprof' to version >= 0.2.9.
131
- MSG
128
+ MGS
132
129
  false
133
130
  end
134
131
  end
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
- require "test_prof/ext/string_strip_heredoc"
5
4
 
6
5
  module TestProf
7
6
  module TagProf
8
7
  class RSpecListener # :nodoc:
9
8
  include Logging
10
9
  using FloatDuration
11
- using StringStripHeredoc
12
10
 
13
11
  NOTIFICATIONS = %i[
14
12
  example_started
@@ -39,7 +37,7 @@ module TestProf
39
37
  msgs = []
40
38
 
41
39
  msgs <<
42
- <<-MSG.strip_heredoc
40
+ <<~MSG
43
41
  TagProf report for #{@tag}
44
42
  MSG
45
43
 
@@ -4,11 +4,6 @@ module TestProf
4
4
  module Utils
5
5
  # Ordered set with capacity
6
6
  class SizedOrderedSet
7
- unless [].respond_to?(:bsearch_index)
8
- require "test_prof/ext/array_bsearch_index"
9
- using ArrayBSearchIndex
10
- end
11
-
12
7
  include Enumerable
13
8
 
14
9
  def initialize(max_size, sort_by: nil)
@@ -54,7 +49,7 @@ module TestProf
54
49
  end
55
50
 
56
51
  def to_a
57
- data.dup
52
+ data
58
53
  end
59
54
 
60
55
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "0.3.0.beta3".freeze
4
+ VERSION = "0.3.0.pre"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-prof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0.beta3
4
+ version: 0.3.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-05 00:00:00.000000000 Z
11
+ date: 2017-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.49'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: "\n Ruby applications tests profiling tools.\n\n Contains tools
84
98
  to anylyze factories usage, integrate with Ruby profilers,\n profile your examples
85
99
  using ActiveSupport notifications (if any) and\n statically analyze your code
@@ -128,9 +142,7 @@ files:
128
142
  - lib/test_prof/event_prof/instrumentations/active_support.rb
129
143
  - lib/test_prof/event_prof/minitest.rb
130
144
  - lib/test_prof/event_prof/rspec.rb
131
- - lib/test_prof/ext/array_bsearch_index.rb
132
145
  - lib/test_prof/ext/float_duration.rb
133
- - lib/test_prof/ext/string_strip_heredoc.rb
134
146
  - lib/test_prof/ext/string_truncate.rb
135
147
  - lib/test_prof/factory_default.rb
136
148
  - lib/test_prof/factory_default/factory_girl_patch.rb
@@ -176,7 +188,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
176
188
  requirements:
177
189
  - - ">="
178
190
  - !ruby/object:Gem::Version
179
- version: 2.2.0
191
+ version: 2.3.0
180
192
  required_rubygems_version: !ruby/object:Gem::Requirement
181
193
  requirements:
182
194
  - - ">"
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TestProf
4
- # Ruby 2.3 #bsearch_index method (for usage with older Rubies)
5
- # Straighforward and non-optimal implementation,
6
- # just for compatiblity
7
- module ArrayBSearchIndex
8
- refine Array do
9
- def bsearch_index(&block)
10
- el = bsearch(&block)
11
- index(el)
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TestProf
4
- # Add #strip_heredoc method to use instead of
5
- # squiggly docs (to support older Rubies)
6
- module StringStripHeredoc
7
- refine String do
8
- def strip_heredoc
9
- min = scan(/^[ \t]*(?=\S)/).min
10
- indent = min ? min.size : 0
11
- gsub(/^[ \t]{#{indent}}/, '')
12
- end
13
- end
14
- end
15
- end