mutant 0.7.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/.travis.yml +3 -2
  4. data/Changelog.md +7 -2
  5. data/Gemfile +0 -1
  6. data/Gemfile.devtools +9 -37
  7. data/README.md +1 -1
  8. data/circle.yml +1 -1
  9. data/config/flay.yml +1 -1
  10. data/config/reek.yml +6 -19
  11. data/config/rubocop.yml +58 -63
  12. data/lib/mutant.rb +8 -4
  13. data/lib/mutant/ast.rb +1 -1
  14. data/lib/mutant/cli.rb +12 -6
  15. data/lib/mutant/env.rb +17 -1
  16. data/lib/mutant/isolation.rb +4 -2
  17. data/lib/mutant/loader.rb +4 -0
  18. data/lib/mutant/matcher/compiler.rb +2 -0
  19. data/lib/mutant/mutation.rb +2 -0
  20. data/lib/mutant/mutator/node/const.rb +1 -1
  21. data/lib/mutant/mutator/node/generic.rb +1 -1
  22. data/lib/mutant/mutator/node/if.rb +2 -0
  23. data/lib/mutant/parallel.rb +93 -0
  24. data/lib/mutant/{runner → parallel}/master.rb +90 -45
  25. data/lib/mutant/parallel/source.rb +73 -0
  26. data/lib/mutant/{runner → parallel}/worker.rb +13 -30
  27. data/lib/mutant/reporter/cli.rb +8 -11
  28. data/lib/mutant/reporter/cli/printer.rb +14 -8
  29. data/lib/mutant/result.rb +0 -10
  30. data/lib/mutant/runner.rb +49 -43
  31. data/lib/mutant/runner/{scheduler.rb → sink.rb} +9 -68
  32. data/lib/mutant/version.rb +1 -1
  33. data/lib/mutant/zombifier/file.rb +28 -9
  34. data/meta/if.rb +8 -0
  35. data/meta/match_current_line.rb +1 -0
  36. data/spec/integration/mutant/corpus_spec.rb +1 -1
  37. data/spec/integration/mutant/null_spec.rb +1 -1
  38. data/spec/integration/mutant/rspec_spec.rb +1 -1
  39. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -1
  40. data/spec/integration/mutant/zombie_spec.rb +1 -1
  41. data/spec/support/corpus.rb +2 -0
  42. data/spec/support/fake_actor.rb +20 -10
  43. data/spec/support/mutation_verifier.rb +2 -0
  44. data/spec/support/shared_context.rb +12 -19
  45. data/spec/unit/mutant/env_spec.rb +20 -2
  46. data/spec/unit/mutant/expression_spec.rb +4 -1
  47. data/spec/unit/mutant/parallel/master_spec.rb +339 -0
  48. data/spec/unit/mutant/parallel/source/array_spec.rb +47 -0
  49. data/spec/unit/mutant/{runner → parallel}/worker_spec.rb +23 -26
  50. data/spec/unit/mutant/parallel_spec.rb +16 -0
  51. data/spec/unit/mutant/reporter/cli_spec.rb +1 -1
  52. data/spec/unit/mutant/reporter/trace_spec.rb +9 -0
  53. data/spec/unit/mutant/result/env_spec.rb +0 -55
  54. data/spec/unit/mutant/runner/driver_spec.rb +26 -0
  55. data/spec/unit/mutant/runner/sink_spec.rb +162 -0
  56. data/spec/unit/mutant/runner_spec.rb +60 -63
  57. data/spec/unit/mutant/warning_filter_spec.rb +2 -1
  58. data/test_app/Gemfile.devtools +9 -37
  59. metadata +21 -11
  60. data/spec/unit/mutant/runner/master_spec.rb +0 -199
  61. data/spec/unit/mutant/runner/scheduler_spec.rb +0 -161
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ac2711065200d50b919a3e0856632db7dc1fa0f
4
- data.tar.gz: 251207d0d61bb193bb431efd2f4ef4fb771bde09
3
+ metadata.gz: 064e05498cecb534a1466bfe3ff858ff0487acf3
4
+ data.tar.gz: 585a00d32574fdabf20943a96d4ee48c6ec9408f
5
5
  SHA512:
6
- metadata.gz: ddbdc1636dd452296e90a2ccc2ccbe29910782e95bfb3560d21b93501ec499cfa0b5d0fbb722a650ec57edd021cbbfc0afdbc6ca1f434c7f33069575e3343efd
7
- data.tar.gz: 5f371e23cc9676661cb58ae10cd78bce3176a1fe23e01d741a6b0833eb3d3e908f7bfecd93032ac6ed84ac3dd1c962d725156b731e9c6b4480a657d450012033
6
+ metadata.gz: 97ffbc8174e5027a924037359084af1f49bf9fe8c14f8408ba25b28444a9822d145f59c8d90255c27fabfe744d6b609db12cf3e201fa460c955fca5c7e60ecbb
7
+ data.tar.gz: 2d0bdcd5a5c974d6a9504cd6f8bbfa6b45bdef56526ce054cded8b98f1e53071063afe05e7a72cf68bee9752ba7b24be827365d28390985658ba099023f0009b
@@ -5,4 +5,6 @@ AllCops:
5
5
  - 'Gemfile.devtools'
6
6
  - 'vendor/**/*'
7
7
  - 'tmp/**/*'
8
+ - 'test_app/**/*'
8
9
  - 'benchmarks/**/*'
10
+ - 'bin/mutant'
@@ -1,10 +1,11 @@
1
+ sudo: false
1
2
  language: ruby
2
3
  script: "bundle exec rake ci"
3
4
  env:
4
5
  - TRAVIS=true
5
6
  rvm:
6
- - 2.0.0
7
- - 2.1.4
7
+ - '2.0'
8
+ - '2.1'
8
9
  - rbx-2
9
10
  matrix:
10
11
  allow_failures:
@@ -1,6 +1,11 @@
1
+ # v0.7.4 2014-12-22
2
+
3
+ * Fix rspec example visibility on duplicate metadata examples
4
+ * Add naked if/else body emitter
5
+
1
6
  # v0.7.3 2014-12-09
2
7
 
3
- * Fix communication between workers and killworks to work for all binaries.
8
+ * Fix communication between workers and killforks to work for all binaries.
4
9
 
5
10
  # v0.7.2 2014-12-08
6
11
 
@@ -15,7 +20,7 @@
15
20
 
16
21
  * Use homegrown actor based parallelization
17
22
  * Fix redundant spec execution in rspec integration
18
- * Add mutation from #send to #__send__ (the canonical form).
23
+ * Add mutation from `#send` to `#__send__` (the canonical form).
19
24
 
20
25
  # v0.6.7 2014-11-17
21
26
 
data/Gemfile CHANGED
@@ -5,4 +5,3 @@ source 'https://rubygems.org'
5
5
  gemspec name: 'mutant'
6
6
 
7
7
  gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
8
- eval_gemfile 'Gemfile.devtools'
@@ -1,65 +1,37 @@
1
- # encoding: utf-8
2
-
3
1
  group :development do
4
- gem 'rake', '~> 10.3.2'
5
- gem 'rspec', '~> 3.1.0'
6
- gem 'rspec-its', '~> 1.0.1'
7
- gem 'yard', '~> 0.8.7.4'
8
-
9
2
  platform :rbx do
10
3
  gem 'rubysl-singleton', '~> 2.0.0'
11
- gem 'rubinius-coverage', '~> 2.0.1'
12
4
  end
13
5
  end
14
6
 
15
- group :yard do
16
- gem 'kramdown', '~> 1.3.3'
17
- end
18
-
19
7
  group :guard do
20
- gem 'guard', '~> 2.6.1'
21
- gem 'guard-bundler', '~> 2.0.0'
22
- gem 'guard-rspec', '~> 4.2.9'
23
- gem 'guard-rubocop', '~> 1.1.0'
8
+ gem 'guard', '~> 2.10.3'
9
+ gem 'guard-bundler', '~> 2.1.0'
10
+ gem 'guard-rspec', '~> 4.5.0'
11
+ gem 'guard-rubocop', '~> 1.2.0'
24
12
 
25
13
  # file system change event handling
26
- gem 'listen', '~> 2.7.7'
14
+ gem 'listen', '~> 2.8.4'
27
15
  gem 'rb-fchange', '~> 0.0.6', require: false
28
16
  gem 'rb-fsevent', '~> 0.9.4', require: false
29
17
  gem 'rb-inotify', '~> 0.9.5', require: false
30
18
 
31
19
  # notification handling
32
- gem 'libnotify', '~> 0.8.3', require: false
20
+ gem 'libnotify', '~> 0.9.0', require: false
33
21
  gem 'rb-notifu', '~> 0.0.4', require: false
34
- gem 'terminal-notifier-guard', '~> 1.5.3', require: false
22
+ gem 'terminal-notifier-guard', '~> 1.6.4', require: false
35
23
  end
36
24
 
37
25
  group :metrics do
38
- gem 'coveralls', '~> 0.7.0'
39
- gem 'flay', '~> 2.5.0'
40
- gem 'flog', '~> 4.2.1'
41
- gem 'reek', '~> 1.3.7'
42
- gem 'rubocop', '~> 0.26.0'
43
- gem 'simplecov', '~> 0.7.1'
44
- gem 'yardstick', '~> 0.9.9'
45
-
46
- platforms :ruby_19, :ruby_20 do
47
- gem 'yard-spellcheck', '~> 0.1.5'
48
- end
49
-
50
26
  platform :rbx do
51
27
  gem 'json', '~> 1.8.1'
52
- gem 'racc', '~> 1.4.11'
53
- gem 'rubysl-logger', '~> 2.0.0'
28
+ gem 'racc', '~> 1.4.12'
29
+ gem 'rubysl-logger', '~> 2.1.0'
54
30
  gem 'rubysl-open-uri', '~> 2.0.0'
55
31
  gem 'rubysl-prettyprint', '~> 2.0.3'
56
32
  end
57
33
  end
58
34
 
59
- group :benchmarks do
60
- gem 'rbench', '~> 0.2.3'
61
- end
62
-
63
35
  platform :jruby do
64
36
  group :jruby do
65
37
  gem 'jruby-openssl', '~> 0.9.4'
data/README.md CHANGED
@@ -13,7 +13,7 @@ Mutant is a mutation testing tool for Ruby.
13
13
  The idea is that if code can be changed and your tests do not notice, either that code isn't being covered
14
14
  or it does not have a speced side effect.
15
15
 
16
- Mutant supports MRI and RBX 1.9, 2.0 and 2.1, while support for JRuby is planned.
16
+ Mutant supports MRI and RBX 2.0 and 2.1, while support for JRuby is planned.
17
17
  It should also work under any Ruby engine that supports POSIX-fork(2) semantics.
18
18
 
19
19
  Mutant uses a pure Ruby [parser](https://github.com/whitequark/parser) and an [unparser](https://github.com/mbj/unparser)
data/circle.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  machine:
3
3
  ruby:
4
- version: 2.1.4
4
+ version: '2.1'
5
5
  test:
6
6
  override:
7
7
  - bundle exec rake ci
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 18
3
- total_score: 1200
3
+ total_score: 1198
@@ -23,21 +23,7 @@ DuplicateMethodCall:
23
23
  max_calls: 1
24
24
  allow_calls: []
25
25
  FeatureEnvy:
26
- enabled: true
27
- exclude:
28
- - Mutant::Env#scope_name
29
- - Mutant::Diff#minimized_hunks
30
- - Mutant::Integration::Rspec#parse_example
31
- - Mutant::Matcher::Method::Instance#match?
32
- - Mutant::Matcher::Method::Singleton#receiver?
33
- - Mutant::Mutator::Node#children_indices
34
- - Mutant::Meta::Example::Verification#format_mutation # False positive, its a utility
35
- - Mutant::Reporter::CLI#subject_results
36
- - Mutant::Runner#finish
37
- - Mutant::Runner::Master#stop_worker
38
- - Mutant::Runner::Worker#run_mutation
39
- - Mutant::Runner::Worker#handle
40
- - Mutant::Subject#source_lines
26
+ enabled: false
41
27
  IrresponsibleModule:
42
28
  enabled: true
43
29
  exclude: []
@@ -62,6 +48,7 @@ NestedIterators:
62
48
  - Mutant::RequireHighjack#infect
63
49
  - Mutant::RequireHighjack#disinfect
64
50
  - Mutant::Subject#tests
51
+ - Mutant::Parallel::Master#run
65
52
  - Parser::Lexer#self.new
66
53
  max_allowed_nesting: 1
67
54
  ignore_iterators: []
@@ -72,14 +59,12 @@ RepeatedConditional:
72
59
  exclude:
73
60
  - Mutant::Mutator
74
61
  - Mutant::Meta::Example::DSL
75
- - Mutant::Runner::Master
76
62
  max_ifs: 1
77
63
  TooManyInstanceVariables:
78
64
  enabled: true
79
65
  exclude:
80
66
  - Mutant::Mutator # 4 vars
81
- - Mutant::Runner::Master # 4 vars
82
- - Mutant::Runner::Scheduler # 4 vars
67
+ - Mutant::Parallel::Master # 4 vars
83
68
  max_instance_variables: 3
84
69
  TooManyMethods:
85
70
  enabled: true
@@ -87,6 +72,7 @@ TooManyMethods:
87
72
  - Mutant::CLI
88
73
  - Mutant::Mutator::Node
89
74
  - Mutant::Meta::Example::Verification
75
+ - Mutant::Parallel::Master
90
76
  max_methods: 10
91
77
  TooManyStatements:
92
78
  enabled: true
@@ -94,9 +80,10 @@ TooManyStatements:
94
80
  - Mutant::Isolation::Fork#self.call
95
81
  - Mutant::Reporter::CLI::Printer::EnvProgress#run
96
82
  - Mutant::Reporter::CLI::Printer::Config#run
97
- - Mutant::Runner#initialize
98
83
  - Mutant::Zombifier::File#self.find
99
84
  - Mutant::CLI#add_environment_options
85
+ - Mutant::CLI#add_debug_options
86
+ - Mutant::Runner#run_driver
100
87
  max_statements: 7
101
88
  UncommunicativeMethodName:
102
89
  enabled: true
@@ -1,18 +1,5 @@
1
1
  inherit_from: ../.rubocop.yml
2
2
 
3
- # General note about rubocop.
4
- # It does NOT allow to silence a specific rule violation.
5
- # For that reason I sometimes have to disable a whole cop where
6
- # I just tried to whitelist a specific occurrence.
7
-
8
-
9
- AllCops:
10
- Include:
11
- - '../**/*.rake'
12
- - 'Gemfile'
13
- - 'Gemfile.triage'
14
- - 'mutant.gemspec'
15
-
16
3
  # Avoid parameter lists longer than five parameters.
17
4
  ParameterLists:
18
5
  Max: 3
@@ -30,51 +17,29 @@ CollectionMethods:
30
17
  find: 'detect'
31
18
  find_all: 'select'
32
19
 
33
- # Use square brackets for literal Array objects
34
- PercentLiteralDelimiters:
35
- PreferredDelimiters:
36
- '%': ()
37
- '%i': '[]'
38
- '%q': ()
39
- '%Q': ()
40
- '%r': '{}'
41
- '%s': ()
42
- '%w': '[]'
43
- '%W': '[]'
44
- '%x': ()
45
-
46
- MethodLength:
47
- CountComments: false
48
- Max: 17 # TODO: Bring down to 10
49
-
50
- RegexpLiteral: # I do not agree %r(\A) is more readable than /\A/
20
+ # Do not force public/protected/private keyword to be indented at the same
21
+ # level as the def keyword. My personal preference is to outdent these keywords
22
+ # because I think when scanning code it makes it easier to identify the
23
+ # sections of code and visually separate them. When the keyword is at the same
24
+ # level I think it sort of blends in with the def keywords and makes it harder
25
+ # to scan the code and see where the sections are.
26
+ AccessModifierIndentation:
51
27
  Enabled: false
52
28
 
53
- Eval:
54
- Enabled: false # Mutant must use Kernel#eval to inject mutated source
55
-
56
29
  # Limit line length
57
30
  LineLength:
58
- Max: 124 # TODO: lower to 79
31
+ Max: 120
59
32
 
60
33
  # Disable documentation checking until a class needs to be documented once
61
34
  Documentation:
62
35
  Enabled: false
63
36
 
64
- # Do not favor modifier if/unless usage when you have a single-line body
65
- IfUnlessModifier:
66
- Enabled: false
67
-
68
- # Mutant needs to define methods like def bar; end in specs
69
- Semicolon:
70
- Enabled: false
71
-
72
- # Mutant needs to define multiple methods on same line in specs
73
- EmptyLineBetweenDefs:
37
+ # Do not always use &&/|| instead of and/or.
38
+ AndOr:
74
39
  Enabled: false
75
40
 
76
- # Mutant needs to define singleton methods like Foo.bar in specs
77
- ClassMethods:
41
+ # Do not favor modifier if/unless usage when you have a single-line body
42
+ IfUnlessModifier:
78
43
  Enabled: false
79
44
 
80
45
  # Allow case equality operator (in limited use within the specs)
@@ -89,33 +54,63 @@ ConstantName:
89
54
  TrivialAccessors:
90
55
  Enabled: false
91
56
 
92
- # And also have a different opinion here
93
- AndOr:
57
+ # Allow empty lines around class body
58
+ EmptyLinesAroundClassBody:
94
59
  Enabled: false
95
60
 
96
- # I like my raise
97
- SignalException:
61
+ # Allow empty lines around module body
62
+ EmptyLinesAroundModuleBody:
98
63
  Enabled: false
99
64
 
100
- # I need to chain optparse builder, else it is more ugly
101
- MultilineBlockChain:
65
+ # Allow empty lines around block body
66
+ EmptyLinesAroundBlockBody:
102
67
  Enabled: false
103
68
 
104
- ClassLength:
105
- Max: 119
69
+ # Allow multiple line operations to not require indentation
70
+ MultilineOperationIndentation:
71
+ Enabled: false
106
72
 
107
- # I align private keywords with class body
108
- IndentationWidth:
73
+ # Prefer String#% over Kernel#sprintf
74
+ FormatString:
109
75
  Enabled: false
110
76
 
111
- # I like to have an empty line before closing the currently opened body
112
- EmptyLinesAroundBody:
77
+ # Use square brackets for literal Array objects
78
+ PercentLiteralDelimiters:
79
+ PreferredDelimiters:
80
+ '%': '{}'
81
+ '%i': '[]'
82
+ '%q': ()
83
+ '%Q': ()
84
+ '%r': '{}'
85
+ '%s': ()
86
+ '%w': '[]'
87
+ '%W': '[]'
88
+ '%x': ()
89
+
90
+ # Align if/else blocks with the variable assignment
91
+ EndAlignment:
92
+ AlignWith: variable
93
+
94
+ # Do not always align parameters when it is easier to read
95
+ AlignParameters:
96
+ Exclude:
97
+ - spec/**/*_spec.rb
98
+
99
+ # Prefer #kind_of? over #is_a?
100
+ ClassCheck:
101
+ EnforcedStyle: kind_of?
102
+
103
+ # Do not prefer double quotes to be used when %q or %Q is more appropriate
104
+ UnneededPercentQ:
113
105
  Enabled: false
114
106
 
115
- # I test this style for a while
107
+ # Allow a maximum ABC score
108
+ Metrics/AbcSize:
109
+ Max: 18.00
110
+
111
+ # Do not prefer lambda.call(...) over lambda.(...)
116
112
  LambdaCall:
117
113
  Enabled: false
118
114
 
119
- # I like my style more
120
- AccessModifierIndentation:
121
- Enabled: false
115
+ Style/RegexpLiteral:
116
+ MaxSlashes: 0
@@ -74,6 +74,8 @@ module Mutant
74
74
  #
75
75
  # @api private
76
76
  #
77
+ # rubocop:disable MethodLength
78
+ #
77
79
  def self.singleton_subclass_instance(name, superclass, &block)
78
80
  klass = Class.new(superclass) do
79
81
  def inspect
@@ -105,6 +107,10 @@ require 'mutant/actor/receiver'
105
107
  require 'mutant/actor/sender'
106
108
  require 'mutant/actor/mailbox'
107
109
  require 'mutant/actor/env'
110
+ require 'mutant/parallel'
111
+ require 'mutant/parallel/master'
112
+ require 'mutant/parallel/worker'
113
+ require 'mutant/parallel/source'
108
114
  require 'mutant/cache'
109
115
  require 'mutant/delegator'
110
116
  require 'mutant/warning_filter'
@@ -200,9 +206,7 @@ require 'mutant/cli'
200
206
  require 'mutant/color'
201
207
  require 'mutant/diff'
202
208
  require 'mutant/runner'
203
- require 'mutant/runner/scheduler'
204
- require 'mutant/runner/master'
205
- require 'mutant/runner/worker'
209
+ require 'mutant/runner/sink'
206
210
  require 'mutant/result'
207
211
  require 'mutant/reporter'
208
212
  require 'mutant/reporter/null'
@@ -230,7 +234,7 @@ module Mutant
230
234
  isolation: Mutant::Isolation::Fork,
231
235
  reporter: Reporter::CLI.build($stdout),
232
236
  zombie: false,
233
- jobs: Mutant.ci? ? CI_DEFAULT_PROCESSOR_COUNT : Parallel.processor_count,
237
+ jobs: Mutant.ci? ? CI_DEFAULT_PROCESSOR_COUNT : ::Parallel.processor_count,
234
238
  actor_env: Mutant::Actor::Env.new(Thread),
235
239
  expected_coverage: 100.0
236
240
  )
@@ -15,7 +15,7 @@ module Mutant
15
15
  # @api private
16
16
  #
17
17
  def self.walk(node, stack, &block)
18
- raise ArgumentError, 'block expected' unless block_given?
18
+ fail ArgumentError, 'block expected' unless block_given?
19
19
 
20
20
  block.call(node, stack)
21
21
  node.children.grep(Parser::AST::Node).each do |child|
@@ -74,7 +74,7 @@ module Mutant
74
74
 
75
75
  parse_match_expressions(opts.parse!(arguments))
76
76
  rescue OptionParser::ParseError => error
77
- fail(Error, error.message, error.backtrace)
77
+ raise(Error, error.message, error.backtrace)
78
78
  end
79
79
 
80
80
  # Parse matchers
@@ -101,6 +101,8 @@ module Mutant
101
101
  #
102
102
  # @api private
103
103
  #
104
+ # rubocop:disable MethodLength
105
+ #
104
106
  def add_environment_options(opts)
105
107
  opts.separator('Environment:')
106
108
  opts.on('--zombie', 'Run mutant zombified') do
@@ -129,7 +131,7 @@ module Mutant
129
131
  require "mutant/integration/#{name}"
130
132
  update(integration: Integration.lookup(name))
131
133
  rescue LoadError
132
- fail Error, "Could not load integration #{name.inspect} (you may want to try installing the gem mutant-#{name})"
134
+ raise Error, "Could not load integration #{name.inspect} (you may want to try installing the gem mutant-#{name})"
133
135
  end
134
136
 
135
137
  # Add options
@@ -146,7 +148,8 @@ module Mutant
146
148
 
147
149
  opts.on('--score COVERAGE', 'Fail unless COVERAGE is not reached exactly') do |coverage|
148
150
  update(expected_coverage: Float(coverage))
149
- end.on('--use STRATEGY', 'Use STRATEGY for killing mutations', &method(:setup_integration))
151
+ end
152
+ opts.on('--use STRATEGY', 'Use STRATEGY for killing mutations', &method(:setup_integration))
150
153
  end
151
154
 
152
155
  # Add filter options
@@ -177,12 +180,15 @@ module Mutant
177
180
  def add_debug_options(opts)
178
181
  opts.on('--fail-fast', 'Fail fast') do
179
182
  update(fail_fast: true)
180
- end.on('--version', 'Print mutants version') do
183
+ end
184
+ opts.on('--version', 'Print mutants version') do
181
185
  puts("mutant-#{Mutant::VERSION}")
182
186
  Kernel.exit(EXIT_SUCCESS)
183
- end.on('-d', '--debug', 'Enable debugging output') do
187
+ end
188
+ opts.on('-d', '--debug', 'Enable debugging output') do
184
189
  update(debug: true)
185
- end.on_tail('-h', '--help', 'Show this message') do
190
+ end
191
+ opts.on_tail('-h', '--help', 'Show this message') do
186
192
  puts(opts.to_s)
187
193
  Kernel.exit(EXIT_SUCCESS)
188
194
  end