test-prof 0.1.0.beta4 → 0.1.0.pre2

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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +69 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +4 -0
  7. data/README.md +2 -16
  8. data/Rakefile +8 -0
  9. data/bin/setup +8 -0
  10. data/circle.yml +11 -0
  11. data/guides/any_fixture.md +1 -1
  12. data/guides/ruby_prof.md +0 -2
  13. data/guides/stack_prof.md +1 -5
  14. data/lib/test_prof.rb +6 -31
  15. data/lib/test_prof/event_prof.rb +4 -2
  16. data/lib/test_prof/event_prof/custom_events.rb +3 -3
  17. data/lib/test_prof/event_prof/custom_events/factory_create.rb +9 -11
  18. data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +9 -11
  19. data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +11 -13
  20. data/lib/test_prof/event_prof/rspec.rb +1 -5
  21. data/lib/test_prof/factory_doctor.rb +9 -11
  22. data/lib/test_prof/factory_doctor/rspec.rb +3 -5
  23. data/lib/test_prof/ruby_prof.rb +12 -6
  24. data/lib/test_prof/stack_prof.rb +7 -14
  25. data/lib/test_prof/version.rb +1 -1
  26. data/spec/integrations/any_fixture_spec.rb +11 -0
  27. data/spec/integrations/before_all_spec.rb +11 -0
  28. data/spec/integrations/event_prof_spec.rb +100 -0
  29. data/spec/integrations/factory_doctor_spec.rb +20 -0
  30. data/spec/integrations/fixtures/rspec/any_fixture_fixture.rb +37 -0
  31. data/spec/integrations/fixtures/rspec/before_all_fixture.rb +32 -0
  32. data/spec/integrations/fixtures/rspec/event_prof_factory_create_fixture.rb +23 -0
  33. data/spec/integrations/fixtures/rspec/event_prof_fixture.rb +51 -0
  34. data/spec/integrations/fixtures/rspec/event_prof_sidekiq_fixture.rb +54 -0
  35. data/spec/integrations/fixtures/rspec/factory_doctor_fixture.rb +33 -0
  36. data/spec/spec_helper.rb +38 -0
  37. data/spec/support/ar_models.rb +43 -0
  38. data/spec/support/instrumenter_stub.rb +19 -0
  39. data/spec/support/integration_helpers.rb +13 -0
  40. data/spec/support/transactional_context.rb +11 -0
  41. data/spec/test_prof/any_fixture_spec.rb +66 -0
  42. data/spec/test_prof/event_prof_spec.rb +138 -0
  43. data/spec/test_prof/ext/float_duration_spec.rb +12 -0
  44. data/spec/test_prof/factory_doctor_spec.rb +84 -0
  45. data/spec/test_prof/ruby_prof_spec.rb +109 -0
  46. data/spec/test_prof/stack_prof_spec.rb +73 -0
  47. data/spec/test_prof_spec.rb +23 -0
  48. data/test-prof.gemspec +35 -0
  49. metadata +34 -49
  50. data/CHANGELOG.md +0 -7
  51. data/assets/flamegraph.demo.html +0 -173
  52. data/assets/flamegraph.template.html +0 -196
  53. data/assets/src/d3-tip.js +0 -352
  54. data/assets/src/d3-tip.min.js +0 -1
  55. data/assets/src/d3.flameGraph.css +0 -92
  56. data/assets/src/d3.flameGraph.js +0 -459
  57. data/assets/src/d3.flameGraph.min.css +0 -1
  58. data/assets/src/d3.flameGraph.min.js +0 -1
  59. data/assets/src/d3.v4.min.js +0 -8
  60. data/guides/factory_default.md +0 -109
  61. data/guides/factory_prof.md +0 -85
  62. data/guides/rspec_stamp.md +0 -53
  63. data/guides/rubocop.md +0 -48
  64. data/guides/tag_prof.md +0 -52
  65. data/guides/tests_sampling.md +0 -24
  66. data/lib/test_prof/cops/rspec/aggregate_failures.rb +0 -140
  67. data/lib/test_prof/factory_default.rb +0 -58
  68. data/lib/test_prof/factory_default/factory_girl_patch.rb +0 -22
  69. data/lib/test_prof/factory_prof.rb +0 -140
  70. data/lib/test_prof/factory_prof/factory_girl_patch.rb +0 -12
  71. data/lib/test_prof/factory_prof/printers/flamegraph.rb +0 -71
  72. data/lib/test_prof/factory_prof/printers/simple.rb +0 -28
  73. data/lib/test_prof/recipes/minitest/sample.rb +0 -29
  74. data/lib/test_prof/recipes/rspec/factory_default.rb +0 -9
  75. data/lib/test_prof/recipes/rspec/sample.rb +0 -13
  76. data/lib/test_prof/rspec_stamp.rb +0 -135
  77. data/lib/test_prof/rspec_stamp/parser.rb +0 -103
  78. data/lib/test_prof/rspec_stamp/rspec.rb +0 -95
  79. data/lib/test_prof/rubocop.rb +0 -3
  80. data/lib/test_prof/tag_prof.rb +0 -8
  81. data/lib/test_prof/tag_prof/rspec.rb +0 -84
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4bebeb0abae778ec18d0ec11538784b0255bd26d
4
- data.tar.gz: '098fa4a951eba03ac7fcda3e6565ca01936dd182'
3
+ metadata.gz: 528abbfd18c27537ab52c1bf580c73b4327fdbbc
4
+ data.tar.gz: dfaaa8adc9c93ec2ba4e562cf57ec3f4807ae489
5
5
  SHA512:
6
- metadata.gz: 1099d6a1805f71697cccbb555025bffba6589e87016e33d715a046368e20dda1d5d1b2df259792b144c2ba0e7f816f64e6dd745f14114b1bb4ee6446e2edbba2
7
- data.tar.gz: 4212b16b0487b6a5c4853e855a07278778cc487f0b378148d4903e180d20a935e3110542bdaf553070f499ddce220a046366b2b18049ae598b6dc36e4a54e0dc
6
+ metadata.gz: db4e05c01a501eb9e9a50d8c4d1f857437ca7c14323c7a25e739736e1139c8201c87fbefcff91c84cf0932c475e9fc2f12006f3f7feb9d6d5068d23b492bdf61
7
+ data.tar.gz: 2ba7680b870ef1acf274cabb3fd0f4bdfc73558af1d3211e2808f2e99f7864c212212fce9c7ef6f68f78d55f7d5cba1ff44674273fdb6bedfce3c135c77af2d4
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,69 @@
1
+ AllCops:
2
+ Include:
3
+ - 'lib/**/*.rb'
4
+ - 'lib/**/*.rake'
5
+ - 'spec/**/*.rb'
6
+ Exclude:
7
+ - 'bin/**/*'
8
+ - 'spec/dummy/**/*'
9
+ - 'tmp/**/*'
10
+ - 'Rakefile'
11
+ - 'Gemfile'
12
+ - '*.gemspec'
13
+ DisplayCopNames: true
14
+ StyleGuideCopsOnly: false
15
+ TargetRubyVersion: 2.3
16
+
17
+ Rails:
18
+ Enabled: false
19
+
20
+ Style/AccessorMethodName:
21
+ Enabled: false
22
+
23
+ Style/TrivialAccessors:
24
+ Enabled: false
25
+
26
+ Style/Documentation:
27
+ Exclude:
28
+ - 'spec/**/*.rb'
29
+
30
+ Style/StringLiterals:
31
+ Enabled: false
32
+
33
+ Style/RegexpLiteral:
34
+ Enabled: false
35
+
36
+ Style/SpaceInsideStringInterpolation:
37
+ EnforcedStyle: no_space
38
+
39
+ Style/ClassAndModuleChildren:
40
+ Enabled: false
41
+
42
+ Style/BlockDelimiters:
43
+ Exclude:
44
+ - 'spec/**/*.rb'
45
+
46
+ Lint/AmbiguousRegexpLiteral:
47
+ Enabled: false
48
+
49
+
50
+ Metrics/MethodLength:
51
+ Enabled: false
52
+
53
+ Metrics/AbcSize:
54
+ Enabled: false
55
+
56
+ Metrics/LineLength:
57
+ Max: 100
58
+ Exclude:
59
+ - 'spec/**/*.rb'
60
+
61
+ Metrics/BlockLength:
62
+ Exclude:
63
+ - 'spec/**/*.rb'
64
+
65
+ Rails/Date:
66
+ Enabled: false
67
+
68
+ Rails/TimeZone:
69
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.3
5
+ before_install: gem install bundler -v 1.13.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in test-prof.gemspec
4
+ gemspec
data/README.md CHANGED
@@ -31,8 +31,6 @@ See [Table of Contents](#table-of-contents) for more.
31
31
 
32
32
  - RubyConfBy, 2017, "Run Test Run" talk [[video](https://www.youtube.com/watch?v=q52n4p0wkIs), [slides](https://speakerdeck.com/palkan/rubyconfby-minsk-2017-run-test-run)]
33
33
 
34
- - [Tips to improve speed of your test suite](https://medium.com/appaloosa-store-engineering/tips-to-improve-speed-of-your-test-suite-8418b485205c) by [Benoit Tigeot](https://github.com/benoittgt)
35
-
36
34
  ## Installation
37
35
 
38
36
  Add `test-prof` gem to your application:
@@ -55,13 +53,9 @@ Checkout our guides for each specific tool:
55
53
 
56
54
  - [Instrumentation Profiler](https://github.com/palkan/test-prof/tree/master/guides/event_prof.md) (e.g. ActiveSupport notifications)
57
55
 
58
- - [Tag Profiler](https://github.com/palkan/test-prof/tree/master/guides/tag_prof.md)
59
-
60
56
  - [Factory Doctor](https://github.com/palkan/test-prof/tree/master/guides/factory_doctor.md)
61
57
 
62
- - [Factory Profiler](https://github.com/palkan/test-prof/tree/master/guides/factory_prof.md)
63
-
64
- - [Rubocop Cops](https://github.com/palkan/test-prof/tree/master/guides/rubocop.md)
58
+ - Factory Profiler
65
59
 
66
60
  ## Tips and Tricks (or _Recipes_)
67
61
 
@@ -71,12 +65,6 @@ We also want to share some small code tricks which can help you to improve your
71
65
 
72
66
  - [AnyFixture](https://github.com/palkan/test-prof/tree/master/guides/any_fixture.md)
73
67
 
74
- - [FactoryDefault](https://github.com/palkan/test-prof/tree/master/guides/factory_default.md)
75
-
76
- - [RSpec Stamp](https://github.com/palkan/test-prof/tree/master/guides/rspec_stamp.md)
77
-
78
- - [Tests Sampling](https://github.com/palkan/test-prof/tree/master/guides/tests_sampling.md)
79
-
80
68
  ## Configuration
81
69
 
82
70
  TestProf global configuration is used by most of the profilers:
@@ -100,12 +88,10 @@ Or TODO list:
100
88
 
101
89
  - Better Minitest integration (PRs welcome!)
102
90
 
103
- - Other data generation library support (e.g [Fabricator](http://fabricationgem.org/)). _Does anyone use something except from FactoryGirl?_
91
+ - Other data generation library support (e.g [Fabricator](http://fabricationgem.org/))
104
92
 
105
93
  - Improve FactoryDoctor
106
94
 
107
- - Add more Rubocop cops (e.g. `CreateListLimit`)
108
-
109
95
  ## License
110
96
 
111
97
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rubocop/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task :default => [:spec, :rubocop]
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/circle.yml ADDED
@@ -0,0 +1,11 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.4.1
4
+
5
+ database:
6
+ override:
7
+ - echo "Skipping DB section."
8
+
9
+ dependencies:
10
+ pre:
11
+ - gem install bundler -v 1.13.6
@@ -18,7 +18,7 @@ RSpec.shared_context "account", account: true do
18
18
  @account = TestProf::AnyFixture.register(:account) do
19
19
  # Do anything here, AnyFixture keeps track of affected DB tables
20
20
  # For example, you can use factories here
21
- FactoryGirl.create(:account)
21
+ create(:account)
22
22
 
23
23
  # or with Fabrication
24
24
  Fabricate(:account)
data/guides/ruby_prof.md CHANGED
@@ -58,6 +58,4 @@ end
58
58
 
59
59
  By default, we use `CallStackPrinter`.
60
60
 
61
- Also, you can specify RubyProf mode (`wall`, `cpu`, etc) through `TEST_RUBY_PROF_MODE` env variable.
62
-
63
61
  See [ruby_prof.rb](https://github.com/palkan/test-prof/tree/master/lib/test_prof/ruby_prof.rb) for all available configuration options and their usage.
data/guides/stack_prof.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Profiling with StackProf
2
2
 
3
- [StackProf](https://github.com/tmm1/stackprof) is a sampling call-stack profiler for ruby.
3
+ [StackProf](https://github.com/ruby-prof/ruby-prof) is a sampling call-stack profiler for ruby.
4
4
 
5
5
  ## Instructions
6
6
 
@@ -40,8 +40,4 @@ end
40
40
 
41
41
  ### Configuration
42
42
 
43
- You can change StackProf mode (which is `wall` by default) through `TEST_STACK_PROF_MODE` env variable.
44
-
45
- If you want to generate flame graphs you should collect _raw_ data. Turn _raw_ collection on by passing `TEST_STACK_PROF_RAW=1`.
46
-
47
43
  See [stack_prof.rb](https://github.com/palkan/test-prof/tree/master/lib/test_prof/stack_prof.rb) for all available configuration options and their usage.
data/lib/test_prof.rb CHANGED
@@ -42,42 +42,20 @@ module TestProf
42
42
  false
43
43
  end
44
44
 
45
- # Run block only if provided env var is present and
46
- # equal to the provided value (if any).
45
+ # Run block only if provided env var is present.
47
46
  # Contains workaround for applications using Spring.
48
- def activate(env_var, val = nil)
49
- if defined?(::Spring)
50
- ::Spring.after_fork { activate!(env_var, val) { yield } }
47
+ def activate(env_var)
48
+ if defined?(::Spring) && !ENV['DISABLE_SPRING']
49
+ Spring.after_fork { yield if ENV[env_var] }
51
50
  else
52
- activate!(env_var, val) { yield }
51
+ yield if ENV[env_var]
53
52
  end
54
53
  end
55
54
 
56
- # Return absolute path to asset
57
- def asset_path(filename)
58
- ::File.expand_path(filename, ::File.join(::File.dirname(__FILE__), "..", "assets"))
59
- end
60
-
61
- # Return a path to store artefact
62
- def artefact_path(filename)
63
- with_timestamps(
64
- ::File.join(
65
- config.output_dir,
66
- filename
67
- )
68
- )
69
- end
70
-
71
- private
72
-
73
- def activate!(env_var, val)
74
- yield if ENV[env_var] && (val.nil? || ENV[env_var] == val)
75
- end
76
-
77
55
  def with_timestamps(path)
78
56
  return path unless config.timestamps?
79
57
  timestamps = "-#{Time.now.to_i}"
80
- "#{path.sub(/\.\w+$/, '')}#{timestamps}#{::File.extname(path)}"
58
+ "#{path.sub(/\.\w+$/, '')}#{timestamps}#{File.extname(path)}"
81
59
  end
82
60
  end
83
61
 
@@ -109,6 +87,3 @@ require "test_prof/ruby_prof"
109
87
  require "test_prof/stack_prof"
110
88
  require "test_prof/event_prof"
111
89
  require "test_prof/factory_doctor"
112
- require "test_prof/factory_prof"
113
- require "test_prof/rspec_stamp"
114
- require "test_prof/tag_prof"
@@ -65,7 +65,9 @@ module TestProf
65
65
  def build
66
66
  Profiler.new(
67
67
  event: config.event,
68
- instrumenter: config.resolve_instrumenter
68
+ instrumenter: config.resolve_instrumenter,
69
+ rank_by: config.rank_by,
70
+ top_count: config.top_count
69
71
  )
70
72
  end
71
73
  end
@@ -75,7 +77,7 @@ module TestProf
75
77
 
76
78
  attr_reader :event, :top_count, :rank_by, :total_count, :total_time
77
79
 
78
- def initialize(event:, instrumenter:)
80
+ def initialize(event:, instrumenter:, rank_by:, top_count:)
79
81
  @event = event
80
82
 
81
83
  log :info, "EventProf enabled (#{@event})"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/event_prof/custom_events/factory_create"
4
- require "test_prof/event_prof/custom_events/sidekiq_inline"
5
- require "test_prof/event_prof/custom_events/sidekiq_jobs"
3
+ require "test_prof/event_prof/custom_events/factory_create" if ENV['EVENT_PROF'] == "factory.create"
4
+ require "test_prof/event_prof/custom_events/sidekiq_inline" if ENV['EVENT_PROF'] == "sidekiq.inline"
5
+ require "test_prof/event_prof/custom_events/sidekiq_jobs" if ENV['EVENT_PROF'] == "sidekiq.jobs"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf::EventProf::CustomEvents
4
- module FactoryCreate # :nodoc: all
4
+ module FactoryCreate
5
5
  module RunnerPatch
6
6
  def run(strategy = @strategy)
7
7
  return super unless strategy == :create
@@ -39,15 +39,13 @@ module TestProf::EventProf::CustomEvents
39
39
  end
40
40
  end
41
41
 
42
- TestProf.activate('EVENT_PROF', 'factory.create') do
43
- if TestProf.require(
44
- 'factory_girl',
45
- <<~MSG
46
- Failed to load FactoryGirl.
42
+ if TestProf.require(
43
+ 'factory_girl',
44
+ <<~MSG
45
+ Failed to load FactoryGirl.
47
46
 
48
- Make sure that "factory_girl" gem is in your Gemfile.
49
- MSG
50
- )
51
- TestProf::EventProf::CustomEvents::FactoryCreate.setup!
52
- end
47
+ Make sure that "factory_girl" gem is in your Gemfile.
48
+ MSG
49
+ )
50
+ TestProf::EventProf::CustomEvents::FactoryCreate.setup!
53
51
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf::EventProf::CustomEvents
4
- module SidekiqInline # :nodoc: all
4
+ module SidekiqInline
5
5
  module ClientPatch
6
6
  def raw_push(*)
7
7
  return super unless Sidekiq::Testing.inline?
@@ -36,15 +36,13 @@ module TestProf::EventProf::CustomEvents
36
36
  end
37
37
  end
38
38
 
39
- TestProf.activate('EVENT_PROF', 'sidekiq.inline') do
40
- if TestProf.require(
41
- 'sidekiq/testing',
42
- <<~MSG
43
- Failed to load Sidekiq.
39
+ if TestProf.require(
40
+ 'sidekiq/testing',
41
+ <<~MSG
42
+ Failed to load Sidekiq.
44
43
 
45
- Make sure that "sidekiq" gem is in your Gemfile.
46
- MSG
47
- )
48
- TestProf::EventProf::CustomEvents::SidekiqInline.setup!
49
- end
44
+ Make sure that "sidekiq" gem is in your Gemfile.
45
+ MSG
46
+ )
47
+ TestProf::EventProf::CustomEvents::SidekiqInline.setup!
50
48
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf::EventProf::CustomEvents
4
- module SidekiqJobs # :nodoc: all
4
+ module SidekiqJobs
5
5
  module ClientPatch
6
6
  def raw_push(*)
7
7
  return super unless Sidekiq::Testing.inline?
@@ -23,18 +23,16 @@ module TestProf::EventProf::CustomEvents
23
23
  end
24
24
  end
25
25
 
26
- TestProf.activate('EVENT_PROF', 'sidekiq.jobs') do
27
- if TestProf.require(
28
- 'sidekiq/testing',
29
- <<~MSG
30
- Failed to load Sidekiq.
26
+ if TestProf.require(
27
+ 'sidekiq/testing',
28
+ <<~MSG
29
+ Failed to load Sidekiq.
31
30
 
32
- Make sure that "sidekiq" gem is in your Gemfile.
33
- MSG
34
- )
35
- TestProf::EventProf::CustomEvents::SidekiqJobs.setup!
36
- TestProf::EventProf.configure do |config|
37
- config.rank_by = :count
38
- end
31
+ Make sure that "sidekiq" gem is in your Gemfile.
32
+ MSG
33
+ )
34
+ TestProf::EventProf::CustomEvents::SidekiqJobs.setup!
35
+ TestProf::EventProf.configure do |config|
36
+ config.rank_by = :count
39
37
  end
40
38
  end
@@ -87,11 +87,7 @@ TestProf.activate('EVENT_PROF') do
87
87
  RSpec.configure do |config|
88
88
  listener = TestProf::EventProf::RSpecListener.new
89
89
 
90
- config.before(:suite) do
91
- config.reporter.register_listener(
92
- listener, *TestProf::EventProf::RSpecListener::NOTIFICATIONS
93
- )
94
- end
90
+ config.reporter.register_listener(listener, *TestProf::EventProf::RSpecListener::NOTIFICATIONS)
95
91
 
96
92
  config.after(:suite) { listener.print }
97
93
  end
@@ -3,8 +3,8 @@
3
3
  require "test_prof/factory_doctor/factory_girl_patch"
4
4
 
5
5
  module TestProf
6
- # FactoryDoctor is a tool that helps you identify
7
- # tests that perform unnecessary database queries.
6
+ # FactoryDoctor is a tool that helps you identify such _bad_ tests,
7
+ # i.e. tests that perform unnecessary database queries.
8
8
  module FactoryDoctor
9
9
  class Result # :nodoc:
10
10
  attr_reader :count, :time, :queries_count
@@ -81,16 +81,14 @@ module TestProf
81
81
  def within_factory(strategy)
82
82
  return yield if ignore? || !running? || (strategy != :create)
83
83
 
84
- begin
85
- ts = Time.now if @depth.zero?
86
- @depth += 1
87
- @count += 1
88
- yield
89
- ensure
90
- @depth -= 1
84
+ ts = Time.now if @depth.zero?
85
+ @depth += 1
86
+ @count += 1
87
+ yield
88
+ ensure
89
+ @depth -= 1
91
90
 
92
- @time += (Time.now - ts) if @depth.zero?
93
- end
91
+ @time += (Time.now - ts) if @depth.zero?
94
92
  end
95
93
 
96
94
  private