mnogootex 0.2.1 → 2.0.0

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 (47) hide show
  1. checksums.yaml +5 -5
  2. data/.github/actions/setup-ruby/action.yml +34 -0
  3. data/.github/workflows/main.yml +44 -0
  4. data/.gitignore +3 -0
  5. data/.rspec +0 -2
  6. data/.rubocop.yml +15 -0
  7. data/CHANGELOG.md +55 -0
  8. data/CODE_OF_CONDUCT.md +1 -1
  9. data/Gemfile +4 -3
  10. data/Guardfile +56 -0
  11. data/README.md +260 -20
  12. data/Rakefile +25 -4
  13. data/demo/.mnogootexrc +4 -0
  14. data/demo/demo.asciicast +114 -0
  15. data/demo/demo.gif +0 -0
  16. data/demo/main.tex +5 -0
  17. data/exe/mnogootex +2 -92
  18. data/lib/mnogootex/cfg.rb +72 -0
  19. data/lib/mnogootex/cli.rb +63 -0
  20. data/lib/mnogootex/job/logger.rb +53 -0
  21. data/lib/mnogootex/job/porter.rb +63 -0
  22. data/lib/mnogootex/job/runner.rb +60 -0
  23. data/lib/mnogootex/job/warden.rb +104 -0
  24. data/lib/mnogootex/log/level.rb +17 -0
  25. data/lib/mnogootex/log/levels.yml +29 -0
  26. data/lib/mnogootex/log/line.rb +14 -0
  27. data/lib/mnogootex/log/matcher.rb +17 -0
  28. data/lib/mnogootex/log/matchers.yml +205 -0
  29. data/lib/mnogootex/log/processor.rb +115 -0
  30. data/lib/mnogootex/log.rb +23 -0
  31. data/lib/mnogootex/utils.rb +27 -0
  32. data/lib/mnogootex/version.rb +3 -1
  33. data/lib/mnogootex.rb +4 -4
  34. data/mnogootex.gemspec +43 -18
  35. data/spec/mnogootex/cfg_spec.rb +54 -0
  36. data/spec/mnogootex/job/porter_spec.rb +140 -0
  37. data/spec/mnogootex/job/runner_spec.rb +74 -0
  38. data/spec/mnogootex/log/processor_spec.rb +203 -0
  39. data/spec/mnogootex/utils_spec.rb +52 -0
  40. data/spec/spec_helper.rb +124 -0
  41. metadata +150 -29
  42. data/.gitmodules +0 -3
  43. data/.travis.yml +0 -5
  44. data/bin/console +0 -14
  45. data/bin/setup +0 -8
  46. data/lib/mnogootex/configuration.rb +0 -46
  47. data/lib/mnogootex/job.rb +0 -75
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'mnogootex/job/porter'
5
+
6
+ require 'mnogootex/utils'
7
+
8
+ describe Mnogootex::Job::Porter do
9
+ # NOTE: using mktmpdir instead of tmpdir allows parallelization
10
+ let(:test_dir) { Pathname.new(Dir.mktmpdir).join('mnogootex-test') }
11
+ before { test_dir.mkpath }
12
+ after { test_dir.rmtree }
13
+
14
+ describe '.new' do
15
+ it 'requires a source' do
16
+ expect { described_class.new hid: '1', source_path: nil }.to raise_exception(TypeError)
17
+ end
18
+
19
+ it 'requires source to exist' do
20
+ expect { described_class.new hid: '1', source_path: 'foobar' }.to raise_exception(Errno::ENOENT)
21
+ end
22
+
23
+ it 'accepts string as source' do
24
+ expect { described_class.new hid: '1', source_path: test_dir.to_s }.to_not raise_exception
25
+ end
26
+
27
+ it 'accepts pathname as source' do
28
+ expect { described_class.new hid: '1', source_path: test_dir }.to_not raise_exception
29
+ end
30
+ end
31
+
32
+ describe '#target_dir' do
33
+ before do
34
+ test_dir.join('a').mkpath
35
+ test_dir.join('b').mkpath
36
+ test_dir.join('a', 'main.file').write('')
37
+ test_dir.join('b', 'main.file').write('')
38
+ end
39
+ let(:porter_a1) { described_class.new hid: '1', source_path: test_dir.join('a', 'main.file') }
40
+ let(:porter_a2) { described_class.new hid: '2', source_path: test_dir.join('a', 'main.file') }
41
+ let(:porter_b1) { described_class.new hid: '1', source_path: test_dir.join('b', 'main.file') }
42
+
43
+ it 'has a deterministic location' do
44
+ hash = Mnogootex::Utils.short_md5(test_dir.join('a', 'main.file').realpath.to_s)
45
+ expect(porter_a1.target_dir.to_s).
46
+ to match(%r{\A.+/mnogootex/#{hash}/1\z})
47
+ end
48
+
49
+ it 'discriminates by hid' do
50
+ expect(porter_a1.target_dir).to_not eq(porter_a2.target_dir)
51
+ end
52
+
53
+ it 'discriminates by source' do
54
+ expect(porter_a1.target_dir).to_not eq(porter_b1.target_dir)
55
+ end
56
+ end
57
+
58
+ describe '#target_path' do
59
+ let(:source_path) { test_dir.join('a', 'main.file') }
60
+ let(:porter) { described_class.new hid: '1', source_path: source_path }
61
+
62
+ before do
63
+ source_path.dirname.mkpath
64
+ source_path.write('')
65
+ end
66
+
67
+ it 'rescopes source basename into target dirname' do
68
+ expect(porter.target_path.basename).to eq(source_path.basename)
69
+ expect(porter.target_path.dirname).to eq(porter.target_dir)
70
+ end
71
+ end
72
+
73
+ describe '#provide' do
74
+ let(:source_path) { test_dir.join('A', 'main.file') }
75
+
76
+ before do
77
+ test_dir.join('A', 'B').mkpath
78
+ test_dir.join('A', 'main.file').write('')
79
+ test_dir.join('A', '.mnogootexrc').write('')
80
+ test_dir.join('A', '.dotfile').write('')
81
+ test_dir.join('A', 'B', 'ancillary.file').write('')
82
+ end
83
+
84
+ subject { described_class.new hid: 'job_id', source_path: source_path }
85
+
86
+ it 'creates target directory' do
87
+ subject.provide
88
+ expect(subject.target_dir).to be_directory
89
+ end
90
+
91
+ it 'ignores configuration file' do
92
+ test_dir.join('A', '.mnogootexrc').unlink
93
+ subject.provide
94
+ expect(subject.target_dir.join('.mnogootexrc')).to_not exist
95
+ end
96
+
97
+ it 'creates link to source' do
98
+ subject.provide
99
+ expect(subject.target_dir.join('.mnogootex.src').readlink).to eq(source_path.realpath)
100
+ end
101
+
102
+ def relative_subtree(pathname)
103
+ Pathname.glob(pathname.join('**', '{.*,*}')).map do |child|
104
+ child.relative_path_from(pathname)
105
+ end.sort
106
+ end
107
+
108
+ it 'copies all source files' do
109
+ subject.provide
110
+ subject.target_dir.join('.mnogootex.src').unlink
111
+ source_path.dirname.join('.mnogootexrc').unlink
112
+ # NOTE: unlinking so comparison is easier to write
113
+ expect(relative_subtree(source_path.dirname)).
114
+ to eq(relative_subtree(subject.target_dir))
115
+ end
116
+ end
117
+
118
+ describe '#clobber' do
119
+ let(:source_path) { test_dir.join('A', 'main.file') }
120
+
121
+ before do
122
+ test_dir.join('A', 'B').mkpath
123
+ test_dir.join('A', 'main.file').write('')
124
+ end
125
+
126
+ subject { described_class.new hid: 'job_id', source_path: source_path }
127
+
128
+ it 'cleans up target dir if it exists' do
129
+ subject.provide
130
+ expect(subject.target_dir).to exist
131
+ subject.clobber
132
+ expect(subject.target_dir).to_not exist
133
+ end
134
+
135
+ it 'does nothing if target dir does not exist' do
136
+ expect(subject.target_dir).to_not exist
137
+ expect { subject.clobber }.to_not raise_exception
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'mnogootex/job/runner'
5
+
6
+ require 'tmpdir'
7
+
8
+ describe Mnogootex::Job::Runner do
9
+ let(:test_dir) { Pathname.new(Dir.mktmpdir) }
10
+ before { test_dir.mkpath }
11
+ after { test_dir.rmtree }
12
+
13
+ it 'executes commandline in given dir' do
14
+ runner = described_class.new(cmd: 'pwd', chdir: test_dir)
15
+ expect(runner).to be_successful
16
+ expect(runner.log_lines.join.chomp).to eq(test_dir.realpath.to_s)
17
+ end
18
+
19
+ describe '#alive?' do
20
+ it 'is true if thread is running' do
21
+ runner = described_class.new(cmd: 'sleep 0.05', chdir: test_dir)
22
+ expect(runner).to be_alive
23
+ end
24
+
25
+ it 'is false if thread is dead' do
26
+ runner = described_class.new(cmd: ':', chdir: test_dir)
27
+ sleep 0.05
28
+ expect(runner).to_not be_alive
29
+ end
30
+ end
31
+
32
+ describe '#successful?' do
33
+ it 'is true on zero exit status' do
34
+ runner = described_class.new(cmd: 'exit 0', chdir: test_dir)
35
+ expect(runner).to be_successful
36
+ end
37
+
38
+ it 'is false on nonzero exit status' do
39
+ runner = described_class.new(cmd: 'exit 1', chdir: test_dir)
40
+ expect(runner).to_not be_successful
41
+ end
42
+ end
43
+
44
+ describe '#count_lines' do
45
+ let!(:lns) { <<~SHELL }
46
+ lns () { i=1; while [ "$i" -le $1 ]; do echo $i; i=$(( i + 1 )); done };
47
+ SHELL
48
+
49
+ context 'dead process' do
50
+ subject { described_class.new(cmd: "#{lns} lns 3", chdir: test_dir) }
51
+
52
+ before do
53
+ subject.successful? # waits on threads
54
+ end
55
+
56
+ it 'plateaus immediately at log lines count' do
57
+ [3, 3].each { |n| expect(subject.count_lines).to eq(n) }
58
+ end
59
+ end
60
+
61
+ context 'alive process' do
62
+ subject { described_class.new(cmd: "#{lns} lns 3; sleep 0.20", chdir: test_dir) }
63
+
64
+ before do
65
+ subject
66
+ sleep 0.02
67
+ end
68
+
69
+ it 'unitarily increases from zero then plateaus at current line count' do
70
+ [0, 1, 2, 3, 3, 3].each { |n| expect(subject.count_lines).to eq(n) }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'yaml'
6
+
7
+ require 'mnogootex/log/processor'
8
+
9
+ describe Mnogootex::Log::Processor do
10
+ describe '.strings_to_lines!' do
11
+ it 'converts strings into lines' do
12
+ strings = "foo\nbar\n".lines
13
+
14
+ described_class.strings_to_lines! strings
15
+
16
+ expect(strings).to eq [
17
+ Mnogootex::Log::Line.new('foo'),
18
+ Mnogootex::Log::Line.new('bar')
19
+ ]
20
+ end
21
+ end
22
+
23
+ describe '.tag_lines!' do
24
+ it 'tags using short matchers' do
25
+ lines = [Mnogootex::Log::Line.new,
26
+ Mnogootex::Log::Line.new('foo'),
27
+ Mnogootex::Log::Line.new]
28
+
29
+ matchers = [Mnogootex::Log::Matcher.new(/foo/, :foo)]
30
+
31
+ described_class.tag_lines! lines, matchers: matchers
32
+
33
+ expect(lines.map(&:level)).to eq([nil, :foo, nil])
34
+ end
35
+
36
+ it 'tags using long matchers' do
37
+ lines = [Mnogootex::Log::Line.new,
38
+ Mnogootex::Log::Line.new,
39
+ Mnogootex::Log::Line.new('foo'),
40
+ Mnogootex::Log::Line.new,
41
+ Mnogootex::Log::Line.new,
42
+ Mnogootex::Log::Line.new,
43
+ Mnogootex::Log::Line.new]
44
+
45
+ matchers = [Mnogootex::Log::Matcher.new(/foo/, :foo, 3)]
46
+
47
+ described_class.tag_lines! lines, matchers: matchers
48
+
49
+ expect(lines.map(&:level)).to eq([nil, nil, :foo, :foo, :foo, nil, nil])
50
+ end
51
+
52
+ it 'tags abiding to matchers order' do
53
+ lines = [Mnogootex::Log::Line.new('foo'),
54
+ Mnogootex::Log::Line.new('something')]
55
+
56
+ matchers = [Mnogootex::Log::Matcher.new(/foo/, :winner, 1),
57
+ Mnogootex::Log::Matcher.new(/foo/, :loser, 1),
58
+ Mnogootex::Log::Matcher.new(//, :anything, 1)]
59
+
60
+ described_class.tag_lines! lines, matchers: matchers
61
+
62
+ expect(lines.map(&:level)).to eq(%i[winner anything])
63
+ end
64
+ end
65
+
66
+ describe '.filter_lines!' do
67
+ it 'raises on line with unknown level' do
68
+ lines = [Mnogootex::Log::Line.new('foo', :bar)]
69
+
70
+ levels = { foo: Mnogootex::Log::Level.new(0) }
71
+
72
+ expect do
73
+ described_class.filter_lines! lines,
74
+ levels: levels,
75
+ min_level: :foo
76
+ end.to raise_exception KeyError
77
+ end
78
+
79
+ it 'raises on unknown min level' do
80
+ lines = [Mnogootex::Log::Line.new('foo', :foo)]
81
+
82
+ levels = { foo: Mnogootex::Log::Level.new(0) }
83
+
84
+ expect do
85
+ described_class.filter_lines! lines,
86
+ levels: levels,
87
+ min_level: :bar
88
+ end.to raise_exception KeyError
89
+ end
90
+
91
+ it 'filters tagged lines by minimum level' do
92
+ lines = [Mnogootex::Log::Line.new('foo', :foo),
93
+ Mnogootex::Log::Line.new('bar', :bar),
94
+ Mnogootex::Log::Line.new('baz', :baz)]
95
+
96
+ levels = { foo: Mnogootex::Log::Level.new(0),
97
+ bar: Mnogootex::Log::Level.new(1),
98
+ baz: Mnogootex::Log::Level.new(2) }
99
+
100
+ described_class.filter_lines! lines,
101
+ levels: levels,
102
+ min_level: :bar
103
+
104
+ expect(lines.map(&:text)).to eq(%w[bar baz])
105
+ end
106
+ end
107
+
108
+ describe '.colorize_lines!' do
109
+ it 'raises on unknown min level' do
110
+ lines = [Mnogootex::Log::Line.new('foo', :foo)]
111
+
112
+ levels = { bar: Mnogootex::Log::Level.new(0) }
113
+
114
+ expect do
115
+ described_class.colorize_lines! lines, levels: levels
116
+ end.to raise_exception KeyError
117
+ end
118
+
119
+ it 'colorizes tagged lines' do
120
+ lines = [Mnogootex::Log::Line.new('foo', :foo),
121
+ Mnogootex::Log::Line.new('bar', :bar),
122
+ Mnogootex::Log::Line.new('baz', :baz)]
123
+
124
+ levels = { foo: Mnogootex::Log::Level.new(0, :foo, :red),
125
+ bar: Mnogootex::Log::Level.new(1, :bar, :green),
126
+ baz: Mnogootex::Log::Level.new(2, :baz, :blue) }
127
+
128
+ described_class.colorize_lines! lines, levels: levels
129
+
130
+ expect(lines.map(&:text)).to eq %W{\e[0;31;49mfoo\e[0m
131
+ \e[0;32;49mbar\e[0m
132
+ \e[0;34;49mbaz\e[0m}
133
+ end
134
+ end
135
+
136
+ describe '.render_lines!' do
137
+ it 'renders lines to indented terminated strings' do
138
+ lines = [Mnogootex::Log::Line.new('foo'),
139
+ Mnogootex::Log::Line.new('bar'),
140
+ Mnogootex::Log::Line.new('baz')]
141
+
142
+ described_class.render_lines! lines, indent_width: 2
143
+
144
+ expect(lines).to eq [" foo\n", " bar\n", " baz\n"]
145
+ end
146
+ end
147
+
148
+ describe '#run' do
149
+ log = <<~LOG
150
+ This is generic irrelevant information.
151
+ Hey, I'm warning you, dude. Stuff is gonna get bad.
152
+ This is also a known irrelevant information flood...
153
+ ... telling you that you'd better pay attention to warnings.
154
+ I warned you, dude. Here's an ERROR. :(
155
+ LOG
156
+
157
+ levels = { trace: Mnogootex::Log::Level.new(0, :trace),
158
+ warning: Mnogootex::Log::Level.new(1, :warning, :yellow),
159
+ error: Mnogootex::Log::Level.new(2, :error, :red) }
160
+
161
+ matchers = [Mnogootex::Log::Matcher.new(/error/i, :error, 1),
162
+ Mnogootex::Log::Matcher.new(/warning/i, :warning, 1),
163
+ Mnogootex::Log::Matcher.new(/flood/, :trace, 2),
164
+ Mnogootex::Log::Matcher.new(//, :trace, 1)]
165
+
166
+ it 'can be initilized and run' do
167
+ my_processor = described_class.new matchers: matchers,
168
+ levels: levels,
169
+ min_level: :warning,
170
+ colorize: true,
171
+ indent_width: 4
172
+
173
+ expect(my_processor.run(log.lines)).to eq(
174
+ [" \e[0;33;49mHey, I'm warning you, dude. Stuff is gonna get bad.\e[0m\n",
175
+ " \e[0;31;49mI warned you, dude. Here's an ERROR. :(\e[0m\n"],
176
+ )
177
+ end
178
+
179
+ it 'can disable colorization' do
180
+ my_processor = described_class.new matchers: matchers,
181
+ levels: levels,
182
+ min_level: :warning,
183
+ colorize: false,
184
+ indent_width: 4
185
+
186
+ expect(my_processor.run(log.lines)).to eq(
187
+ [" Hey, I'm warning you, dude. Stuff is gonna get bad.\n",
188
+ " I warned you, dude. Here's an ERROR. :(\n"],
189
+ )
190
+ end
191
+
192
+ it 'does not mutate given lines' do
193
+ my_processor = described_class.new matchers: matchers,
194
+ levels: levels,
195
+ min_level: :warning,
196
+ colorize: true,
197
+ indent_width: 4
198
+
199
+ log_lines = log.lines
200
+ expect { my_processor.run(log_lines) }.to_not(change { log_lines })
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'tmpdir'
6
+
7
+ require 'mnogootex/utils'
8
+
9
+ describe Mnogootex::Utils do
10
+ describe '.short_md5' do
11
+ it 'gives expected hash for empty string' do
12
+ expect(described_class.short_md5('')).to eq('1B2M2Y8AsgTpgAmY7PhCfg')
13
+ end
14
+
15
+ it 'gives an url/path-safe hash' do
16
+ expect(described_class.short_md5('Knuth')).to eq('KyIs0ZIec5GkG7_G-clv6Q')
17
+ end
18
+ end
19
+
20
+ describe '.humanize_bytes' do
21
+ it 'rounds to smaller unit' do
22
+ expect(described_class.humanize_bytes(1023 * 1024)).to eq('1023Kb')
23
+ expect(described_class.humanize_bytes(1024 * 1024)).to eq('1Mb')
24
+ expect(described_class.humanize_bytes(1025 * 1024)).to eq('1Mb')
25
+ end
26
+
27
+ it 'covers a reasonable scale' do
28
+ %w[b Kb Mb Gb Tb Pb Eb Zb Yb].each_with_index do |unit, index|
29
+ expect(described_class.humanize_bytes((2**10)**index)).to eq("1#{unit}")
30
+ end
31
+ end
32
+ end
33
+
34
+ describe '.dir_size' do
35
+ let(:tmpdir) { Pathname.new(Dir.mktmpdir) }
36
+ before { tmpdir.mkpath }
37
+ after { tmpdir.rmtree }
38
+
39
+ it 'measures an empty dir' do
40
+ expect(described_class.dir_size(tmpdir)).to eq(0)
41
+ end
42
+
43
+ it 'measures a subtree' do
44
+ tmpdir.join('foo').write('foo' * 100)
45
+ tmpdir.join('bar').write('bar' * 200)
46
+ tmpdir.join('baz').mkpath
47
+ tmpdir.join('baz', 'qux').write('qux' * 300)
48
+ # NOTE: dir size is fs dependent, so let's not care about that
49
+ expect(described_class.dir_size(tmpdir.to_s)).to eq(300 + 600 + tmpdir.join('baz').size + 900)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'timeout'
4
+
5
+ if ENV['COVERAGE'] == 'true'
6
+ require 'simplecov'
7
+
8
+ SimpleCov.configure do
9
+ track_files 'lib/**/*.rb'
10
+ add_filter '/spec/'
11
+ end
12
+
13
+ # SimpleCov.at_exit do
14
+ # SimpleCov.result.format!
15
+ # puts "#{SimpleCov.result.covered_percent.floor}%"
16
+ # end
17
+
18
+ SimpleCov.start
19
+ end
20
+
21
+ # This file was generated by the `rspec --init` command. Conventionally, all
22
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
23
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
24
+ # this file to always be loaded, without a need to explicitly require it in any
25
+ # files.
26
+ #
27
+ # Given that it is always loaded, you are encouraged to keep this file as
28
+ # light-weight as possible. Requiring heavyweight dependencies from this file
29
+ # will add to the boot time of your test suite on EVERY test run, even for an
30
+ # individual file that may not need all of that loaded. Instead, consider making
31
+ # a separate helper file that requires the additional dependencies and performs
32
+ # the additional setup, and require it from the spec files that actually need
33
+ # it.
34
+ #
35
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
36
+ RSpec.configure do |config|
37
+ config.fail_fast = true
38
+ # rspec-expectations config goes here. You can use an alternate
39
+ # assertion/expectation library such as wrong or the stdlib/minitest
40
+ # assertions if you prefer.
41
+ config.expect_with :rspec do |expectations|
42
+ # This option will default to `true` in RSpec 4. It makes the `description`
43
+ # and `failure_message` of custom matchers include text for helper methods
44
+ # defined using `chain`, e.g.:
45
+ # be_bigger_than(2).and_smaller_than(4).description
46
+ # # => "be bigger than 2 and smaller than 4"
47
+ # ...rather than:
48
+ # # => "be bigger than 2"
49
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
50
+ end
51
+
52
+ # rspec-mocks config goes here. You can use an alternate test double
53
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
54
+ config.mock_with :rspec do |mocks|
55
+ # Prevents you from mocking or stubbing a method that does not exist on
56
+ # a real object. This is generally recommended, and will default to
57
+ # `true` in RSpec 4.
58
+ mocks.verify_partial_doubles = true
59
+ end
60
+
61
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
62
+ # have no way to turn it off -- the option exists only for backwards
63
+ # compatibility in RSpec 3). It causes shared context metadata to be
64
+ # inherited by the metadata hash of host groups and examples, rather than
65
+ # triggering implicit auto-inclusion in groups with matching metadata.
66
+ config.shared_context_metadata_behavior = :apply_to_host_groups
67
+
68
+ # The settings below are suggested to provide a good initial experience
69
+ # with RSpec, but feel free to customize to your heart's content.
70
+ # # This allows you to limit a spec run to individual examples or groups
71
+ # # you care about by tagging them with `:focus` metadata. When nothing
72
+ # # is tagged with `:focus`, all examples get run. RSpec also provides
73
+ # # aliases for `it`, `describe`, and `context` that include `:focus`
74
+ # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
75
+ config.filter_run_when_matching :focus
76
+ #
77
+ # # Allows RSpec to persist some state between runs in order to support
78
+ # # the `--only-failures` and `--next-failure` CLI options. We recommend
79
+ # # you configure your source control system to ignore this file.
80
+ # config.example_status_persistence_file_path = "spec/examples.txt"
81
+ #
82
+ # # Limits the available syntax to the non-monkey patched syntax that is
83
+ # # recommended. For more details, see:
84
+ # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
85
+ # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
86
+ # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
87
+ # config.disable_monkey_patching!
88
+ #
89
+ # # This setting enables warnings. It's recommended, but in some cases may
90
+ # # be too noisy due to issues in dependencies.
91
+ # config.warnings = true
92
+ #
93
+ # # Many RSpec users commonly either run the entire suite or an individual
94
+ # # file, and it's useful to allow more verbose output when running an
95
+ # # individual spec file.
96
+ if config.files_to_run.one?
97
+ # Use the documentation formatter for detailed output,
98
+ # unless a formatter has already been configured
99
+ # (e.g. via a command-line flag).
100
+ config.default_formatter = 'doc'
101
+ end
102
+ #
103
+ # # Print the 10 slowest examples and example groups at the
104
+ # # end of the spec run, to help surface which specs are running
105
+ # # particularly slow.
106
+ # config.profile_examples = 10
107
+ #
108
+ # # Run specs in random order to surface order dependencies. If you find an
109
+ # # order dependency and want to debug it, you can fix the order by providing
110
+ # # the seed, which is printed after each run.
111
+ # # --seed 1234
112
+ config.order = :random
113
+ #
114
+ # # Seed global randomization in this process using the `--seed` CLI option.
115
+ # # Setting this allows you to use `--seed` to deterministically reproduce
116
+ # # test failures related to randomization by passing the same `--seed` value
117
+ # # as the one that triggered the failure.
118
+ # Kernel.srand config.seed
119
+
120
+ # # Timeout to help mutant
121
+ # config.around(:each) do |example|
122
+ # Timeout.timeout(0.1, &example)
123
+ # end
124
+ end