rubocop-rspec 1.8.0 → 1.9.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -1
- data/Rakefile +3 -1
- data/config/default.yml +16 -0
- data/lib/rubocop-rspec.rb +6 -1
- data/lib/rubocop/cop/rspec/any_instance.rb +0 -2
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -2
- data/lib/rubocop/cop/rspec/cop.rb +66 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +6 -1
- data/lib/rubocop/cop/rspec/describe_method.rb +1 -2
- data/lib/rubocop/cop/rspec/described_class.rb +3 -6
- data/lib/rubocop/cop/rspec/empty_example_group.rb +1 -11
- data/lib/rubocop/cop/rspec/example_length.rb +1 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +0 -2
- data/lib/rubocop/cop/rspec/expect_actual.rb +0 -2
- data/lib/rubocop/cop/rspec/file_path.rb +1 -1
- data/lib/rubocop/cop/rspec/focus.rb +4 -9
- data/lib/rubocop/cop/rspec/hook_argument.rb +3 -5
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/instance_variable.rb +1 -5
- data/lib/rubocop/cop/rspec/leading_subject.rb +0 -2
- data/lib/rubocop/cop/rspec/let_setup.rb +1 -4
- data/lib/rubocop/cop/rspec/message_chain.rb +1 -8
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/message_spies.rb +79 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -2
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -6
- data/lib/rubocop/cop/rspec/named_subject.rb +0 -2
- data/lib/rubocop/cop/rspec/nested_groups.rb +2 -6
- data/lib/rubocop/cop/rspec/not_to_not.rb +1 -2
- data/lib/rubocop/cop/rspec/repeated_description.rb +59 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +48 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +1 -4
- data/lib/rubocop/cop/rspec/verified_doubles.rb +0 -2
- data/lib/rubocop/rspec.rb +1 -1
- data/lib/rubocop/rspec/description_extractor.rb +55 -18
- data/lib/rubocop/rspec/example.rb +56 -0
- data/lib/rubocop/rspec/example_group.rb +57 -0
- data/lib/rubocop/rspec/language.rb +28 -1
- data/lib/rubocop/rspec/language/node_pattern.rb +1 -3
- data/lib/rubocop/rspec/top_level_describe.rb +6 -10
- data/lib/rubocop/rspec/version.rb +1 -1
- data/spec/project/default_config_spec.rb +8 -5
- data/spec/project/project_requires_spec.rb +1 -1
- data/spec/rubocop/{rspec/spec_only_spec.rb → cop/rspec/cop_spec.rb} +2 -4
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +36 -0
- data/spec/rubocop/cop/rspec/described_class_spec.rb +2 -2
- data/spec/rubocop/cop/rspec/example_length_spec.rb +48 -60
- data/spec/rubocop/cop/rspec/implicit_expect_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/message_spies_spec.rb +93 -0
- data/spec/rubocop/cop/rspec/repeated_description_spec.rb +76 -0
- data/spec/rubocop/cop/rspec/single_argument_message_chain_spec.rb +75 -0
- data/spec/rubocop/rspec/description_extractor_spec.rb +46 -24
- data/spec/rubocop/rspec/example_group_spec.rb +44 -0
- data/spec/rubocop/rspec/example_spec.rb +62 -0
- data/spec/rubocop/rspec/language/selector_set_spec.rb +22 -2
- data/spec/spec_helper.rb +2 -9
- data/spec/support/expect_violation.rb +4 -2
- metadata +21 -8
- data/lib/rubocop/rspec/spec_only.rb +0 -61
- data/spec/shared/rspec_only_cop_behavior.rb +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d160e862b58dbfd9bcd2ae0966bd185d1ed13d25
|
4
|
+
data.tar.gz: 3b32f0c16a19b8f110e40d79f4a87d510e3c9226
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b429eb8553d36a1aec8613f57a4f3356518acb89ade8e41f96093dc6ba430b592b3a35899dcefe8df5833a1c0ceb7afa8d3bf1431ad554ffaeb057b2775df622
|
7
|
+
data.tar.gz: 4bc98868826de4ba820c107b5507beb1b57259d147199cec394054c5ac6887786ba1db1ce396bfcfe8ed345387b736b73b18c8b0e1bf0f3b3841f665e7f23064
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## Master (unreleased)
|
4
4
|
|
5
|
+
## 1.9.0 (2016-12-29)
|
6
|
+
|
7
|
+
* Add `MessageSpies` cop for enforcing consistent style of either `expect(...).to have_received` or `expect(...).to receive`, intended as a replacement for the `MessageExpectation` cop. ([@bquorning][])
|
8
|
+
* Fix `DescribeClass` to not flag `describe` at the top of a block of shared examples. ([@clupprich][])
|
9
|
+
* Add `SingleArgumentMessageChain` cop for recommending use of `receive` instead of `receive_message_chain` where possible. ([@bquorning][])
|
10
|
+
* Add `RepeatedDescription` cop for detecting repeated example descriptions within example groups. ([@backus][])
|
11
|
+
|
5
12
|
## 1.8.0 (2016-10-27)
|
6
13
|
|
7
14
|
* Optionally ignore method names in the `describe` argument when running the `FilePath` cop. ([@bquorning][])
|
@@ -148,3 +155,4 @@
|
|
148
155
|
[@jaredmoody]: https://github.com/jaredmoody
|
149
156
|
[@baberthal]: https://github.com/baberthal
|
150
157
|
[@jeffreyc]: https://github.com/jeffreyc
|
158
|
+
[@clupprich]: https://github.com/clupprich
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -20,6 +20,8 @@ desc 'Run RSpec with code coverage'
|
|
20
20
|
task :coverage do
|
21
21
|
ENV['COVERAGE'] = 'true'
|
22
22
|
Rake::Task['spec'].execute
|
23
|
+
|
24
|
+
sh('codeclimate-test-reporter') if ENV['CI']
|
23
25
|
end
|
24
26
|
|
25
27
|
desc 'Run RuboCop over this gem'
|
@@ -42,4 +44,4 @@ task confirm_config: :build_config do
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
|
-
task default:
|
47
|
+
task default: %i(build_config coverage internal_investigation confirm_config)
|
data/config/default.yml
CHANGED
@@ -103,6 +103,14 @@ RSpec/MessageExpectation:
|
|
103
103
|
- allow
|
104
104
|
- expect
|
105
105
|
|
106
|
+
RSpec/MessageSpies:
|
107
|
+
Description: Checks that message expectations are set using spies.
|
108
|
+
Enabled: true
|
109
|
+
EnforcedStyle: have_received
|
110
|
+
SupportedStyles:
|
111
|
+
- have_received
|
112
|
+
- receive
|
113
|
+
|
106
114
|
RSpec/MultipleDescribes:
|
107
115
|
Description: Checks for multiple top level describes.
|
108
116
|
Enabled: true
|
@@ -129,6 +137,14 @@ RSpec/NotToNot:
|
|
129
137
|
- to_not
|
130
138
|
Enabled: true
|
131
139
|
|
140
|
+
RSpec/RepeatedDescription:
|
141
|
+
Enabled: true
|
142
|
+
Description: Check for repeated description strings in example groups.
|
143
|
+
|
144
|
+
RSpec/SingleArgumentMessageChain:
|
145
|
+
Description: Checks that chains of messages contain more than one element.
|
146
|
+
Enabled: true
|
147
|
+
|
132
148
|
RSpec/SubjectStub:
|
133
149
|
Description: Checks for stubbed test subjects.
|
134
150
|
Enabled: true
|
data/lib/rubocop-rspec.rb
CHANGED
@@ -11,7 +11,9 @@ require 'rubocop/rspec/wording'
|
|
11
11
|
require 'rubocop/rspec/util'
|
12
12
|
require 'rubocop/rspec/language'
|
13
13
|
require 'rubocop/rspec/language/node_pattern'
|
14
|
-
require 'rubocop/rspec/
|
14
|
+
require 'rubocop/rspec/example_group'
|
15
|
+
require 'rubocop/rspec/example'
|
16
|
+
require 'rubocop/cop/rspec/cop'
|
15
17
|
|
16
18
|
RuboCop::RSpec::Inject.defaults!
|
17
19
|
|
@@ -34,10 +36,13 @@ require 'rubocop/cop/rspec/leading_subject'
|
|
34
36
|
require 'rubocop/cop/rspec/let_setup'
|
35
37
|
require 'rubocop/cop/rspec/message_chain'
|
36
38
|
require 'rubocop/cop/rspec/message_expectation'
|
39
|
+
require 'rubocop/cop/rspec/message_spies'
|
37
40
|
require 'rubocop/cop/rspec/multiple_describes'
|
38
41
|
require 'rubocop/cop/rspec/multiple_expectations'
|
39
42
|
require 'rubocop/cop/rspec/named_subject'
|
40
43
|
require 'rubocop/cop/rspec/nested_groups'
|
41
44
|
require 'rubocop/cop/rspec/not_to_not'
|
45
|
+
require 'rubocop/cop/rspec/repeated_description'
|
46
|
+
require 'rubocop/cop/rspec/single_argument_message_chain'
|
42
47
|
require 'rubocop/cop/rspec/subject_stub'
|
43
48
|
require 'rubocop/cop/rspec/verified_doubles'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop # rubocop:disable Style/Documentation
|
3
|
+
WorkaroundCop = Cop.dup
|
4
|
+
|
5
|
+
# Clone of the the normal RuboCop::Cop::Cop class so we can rewrite
|
6
|
+
# the inherited method without breaking functionality
|
7
|
+
class WorkaroundCop
|
8
|
+
# Overwrite the cop inherited method to be a noop. Our RSpec::Cop
|
9
|
+
# class will invoke the inherited hook instead
|
10
|
+
def self.inherited(*)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Special case `Module#<` so that the rspec support rubocop exports
|
14
|
+
# is compatible with our subclass
|
15
|
+
def self.<(other)
|
16
|
+
other.equal?(RuboCop::Cop::Cop) || super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
private_constant(:WorkaroundCop)
|
20
|
+
|
21
|
+
module RSpec
|
22
|
+
# @abstract parent class to rspec cops
|
23
|
+
#
|
24
|
+
# The criteria for whether rubocop-rspec analyzes a certain ruby file
|
25
|
+
# is configured via `AllCops/RSpec`. For example, if you want to
|
26
|
+
# customize your project to scan all files within a `test/` directory
|
27
|
+
# then you could add this to your configuration:
|
28
|
+
#
|
29
|
+
# @example configuring analyzed paths
|
30
|
+
#
|
31
|
+
# AllCops:
|
32
|
+
# RSpec:
|
33
|
+
# Patterns:
|
34
|
+
# - '_test.rb$'
|
35
|
+
# - '(?:^|/)test/'
|
36
|
+
class Cop < WorkaroundCop
|
37
|
+
DEFAULT_CONFIGURATION =
|
38
|
+
RuboCop::RSpec::CONFIG.fetch('AllCops').fetch('RSpec')
|
39
|
+
|
40
|
+
include RuboCop::RSpec::Language, RuboCop::RSpec::Language::NodePattern
|
41
|
+
|
42
|
+
# Invoke the original inherited hook so our cops are recognized
|
43
|
+
def self.inherited(subclass)
|
44
|
+
RuboCop::Cop::Cop.inherited(subclass)
|
45
|
+
end
|
46
|
+
|
47
|
+
def relevant_file?(file)
|
48
|
+
rspec_pattern =~ file && super
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def rspec_pattern
|
54
|
+
Regexp.union(rspec_pattern_config.map(&Regexp.public_method(:new)))
|
55
|
+
end
|
56
|
+
|
57
|
+
def rspec_pattern_config
|
58
|
+
config
|
59
|
+
.for_all_cops
|
60
|
+
.fetch('RSpec', DEFAULT_CONFIGURATION)
|
61
|
+
.fetch('Patterns')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
17
17
|
# describe "A feature example", type: :feature do
|
18
18
|
# end
|
19
19
|
class DescribeClass < Cop
|
20
|
-
include RuboCop::RSpec::
|
20
|
+
include RuboCop::RSpec::TopLevelDescribe
|
21
21
|
|
22
22
|
MSG = 'The first argument to describe should be '\
|
23
23
|
'the class or module being tested.'.freeze
|
@@ -39,7 +39,12 @@ module RuboCop
|
|
39
39
|
(sym {:request :feature :routing :view}))
|
40
40
|
PATTERN
|
41
41
|
|
42
|
+
def_node_matcher :shared_group?, <<-PATTERN
|
43
|
+
(block (send {(const nil :RSpec) nil} #{SharedGroups::ALL.node_pattern_union} ...) ...)
|
44
|
+
PATTERN
|
45
|
+
|
42
46
|
def on_top_level_describe(node, args)
|
47
|
+
return if shared_group?(root_node)
|
43
48
|
return if valid_describe?(node)
|
44
49
|
|
45
50
|
describe_with_metadata(node) do |pairs|
|
@@ -17,8 +17,7 @@ module RuboCop
|
|
17
17
|
# describe MyClass, '.my_class_method' do
|
18
18
|
# end
|
19
19
|
class DescribeMethod < Cop
|
20
|
-
include RuboCop::RSpec::
|
21
|
-
RuboCop::RSpec::TopLevelDescribe,
|
20
|
+
include RuboCop::RSpec::TopLevelDescribe,
|
22
21
|
RuboCop::RSpec::Util
|
23
22
|
|
24
23
|
MESSAGE = 'The second argument to describe should be the method ' \
|
@@ -20,20 +20,17 @@ module RuboCop
|
|
20
20
|
# subject { described_class.do_something }
|
21
21
|
# end
|
22
22
|
class DescribedClass < Cop
|
23
|
-
include RuboCop::RSpec::
|
23
|
+
include RuboCop::RSpec::TopLevelDescribe
|
24
24
|
|
25
25
|
DESCRIBED_CLASS = 'described_class'.freeze
|
26
26
|
MSG = "Use `#{DESCRIBED_CLASS}` instead of `%s`".freeze
|
27
27
|
|
28
|
-
RSPEC_BLOCK_METHODS = RuboCop::RSpec::Language::ALL.to_node_pattern
|
29
|
-
|
30
28
|
def_node_matcher :common_instance_exec_closure?, <<-PATTERN
|
31
29
|
(block (send (const nil {:Class :Module}) :new ...) ...)
|
32
30
|
PATTERN
|
33
31
|
|
34
|
-
def_node_matcher :rspec_block?,
|
35
|
-
|
36
|
-
PATTERN
|
32
|
+
def_node_matcher :rspec_block?,
|
33
|
+
RuboCop::RSpec::Language::ALL.block_pattern
|
37
34
|
|
38
35
|
def_node_matcher :scope_changing_syntax?, '{def class module}'
|
39
36
|
|
@@ -58,21 +58,11 @@ module RuboCop
|
|
58
58
|
# end
|
59
59
|
#
|
60
60
|
class EmptyExampleGroup < Cop
|
61
|
-
include RuboCop::RSpec::SpecOnly,
|
62
|
-
RuboCop::RSpec::Language,
|
63
|
-
RuboCop::RSpec::Language::NodePattern
|
64
|
-
|
65
61
|
MSG = 'Empty example group detected.'.freeze
|
66
62
|
|
67
63
|
def_node_search :contains_example?, <<-PATTERN
|
68
64
|
{
|
69
|
-
(
|
70
|
-
#{Examples::ALL.to_node_pattern}
|
71
|
-
:it_behaves_like
|
72
|
-
:it_should_behave_like
|
73
|
-
:include_context
|
74
|
-
:include_examples
|
75
|
-
} ...)
|
65
|
+
#{(Examples::ALL + Includes::ALL).send_pattern}
|
76
66
|
(send _ #custom_include? ...)
|
77
67
|
}
|
78
68
|
PATTERN
|
@@ -19,8 +19,6 @@ module RuboCop
|
|
19
19
|
# it 'finds nothing' do
|
20
20
|
# end
|
21
21
|
class ExampleWording < Cop
|
22
|
-
include RuboCop::RSpec::SpecOnly
|
23
|
-
|
24
22
|
MSG = 'Do not use should when describing your tests.'.freeze
|
25
23
|
|
26
24
|
def on_block(node) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/LineLength
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
# my_class_spec.rb # describe MyClass, '#method'
|
43
43
|
#
|
44
44
|
class FilePath < Cop
|
45
|
-
include RuboCop::RSpec::
|
45
|
+
include RuboCop::RSpec::TopLevelDescribe
|
46
46
|
|
47
47
|
MESSAGE = 'Spec path should end with `%s`'.freeze
|
48
48
|
ROUTING_PAIR = s(:pair, s(:sym, :type), s(:sym, :routing))
|
@@ -20,8 +20,6 @@ module RuboCop
|
|
20
20
|
# describe MyClass do
|
21
21
|
# end
|
22
22
|
class Focus < Cop
|
23
|
-
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language
|
24
|
-
|
25
23
|
MSG = 'Focused spec found.'.freeze
|
26
24
|
|
27
25
|
focusable =
|
@@ -32,20 +30,17 @@ module RuboCop
|
|
32
30
|
|
33
31
|
focused = ExampleGroups::FOCUSED + Examples::FOCUSED
|
34
32
|
|
35
|
-
FOCUSABLE_SELECTORS = focusable.
|
36
|
-
FOCUSING_SELECTORS = focused.to_node_pattern
|
33
|
+
FOCUSABLE_SELECTORS = focusable.node_pattern_union
|
37
34
|
|
38
35
|
FOCUS_SYMBOL = s(:sym, :focus)
|
39
36
|
FOCUS_TRUE = s(:pair, FOCUS_SYMBOL, s(:true))
|
40
37
|
|
41
38
|
def_node_matcher :metadata, <<-PATTERN
|
42
|
-
{(send nil
|
43
|
-
(send nil
|
39
|
+
{(send nil #{FOCUSABLE_SELECTORS} ... (hash $...))
|
40
|
+
(send nil #{FOCUSABLE_SELECTORS} $...)}
|
44
41
|
PATTERN
|
45
42
|
|
46
|
-
def_node_matcher :focused_block?,
|
47
|
-
(send nil {#{FOCUSING_SELECTORS}} ...)
|
48
|
-
PATTERN
|
43
|
+
def_node_matcher :focused_block?, focused.send_pattern
|
49
44
|
|
50
45
|
def on_send(node)
|
51
46
|
focus_metadata(node) do |focus|
|
@@ -57,15 +57,13 @@ module RuboCop
|
|
57
57
|
# before(:example) do
|
58
58
|
# ...
|
59
59
|
# end
|
60
|
-
class HookArgument <
|
61
|
-
include
|
62
|
-
RuboCop::RSpec::SpecOnly,
|
63
|
-
ConfigurableEnforcedStyle
|
60
|
+
class HookArgument < Cop
|
61
|
+
include ConfigurableEnforcedStyle
|
64
62
|
|
65
63
|
IMPLICIT_MSG = 'Omit the default `%p` argument for RSpec hooks.'.freeze
|
66
64
|
EXPLICIT_MSG = 'Use `%p` for RSpec hooks.'.freeze
|
67
65
|
|
68
|
-
HOOKS =
|
66
|
+
HOOKS = Hooks::ALL.node_pattern_union.freeze
|
69
67
|
|
70
68
|
def_node_matcher :scoped_hook, <<-PATTERN
|
71
69
|
(block $(send nil #{HOOKS} (sym ${:each :example})) ...)
|
@@ -47,15 +47,11 @@ module RuboCop
|
|
47
47
|
# end
|
48
48
|
#
|
49
49
|
class InstanceVariable < Cop
|
50
|
-
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language
|
51
|
-
|
52
50
|
MESSAGE = 'Use `let` instead of an instance variable'.freeze
|
53
51
|
|
54
52
|
EXAMPLE_GROUP_METHODS = ExampleGroups::ALL + SharedGroups::ALL
|
55
53
|
|
56
|
-
def_node_matcher :spec_group?,
|
57
|
-
(block (send _ {#{EXAMPLE_GROUP_METHODS.to_node_pattern}} ...) ...)
|
58
|
-
PATTERN
|
54
|
+
def_node_matcher :spec_group?, EXAMPLE_GROUP_METHODS.block_pattern
|
59
55
|
|
60
56
|
def_node_search :ivar_usage, '$(ivar $_)'
|
61
57
|
|
@@ -27,8 +27,6 @@ module RuboCop
|
|
27
27
|
# end
|
28
28
|
# end
|
29
29
|
class LeadingSubject < Cop
|
30
|
-
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language
|
31
|
-
|
32
30
|
MSG = 'Declare `subject` above any other `let` declarations'.freeze
|
33
31
|
|
34
32
|
def_node_matcher :subject?, '(block $(send nil :subject ...) args ...)'
|
@@ -26,10 +26,7 @@ module RuboCop
|
|
26
26
|
# expect(Widget.count).to eq(1)
|
27
27
|
# end
|
28
28
|
class LetSetup < Cop
|
29
|
-
include RuboCop::RSpec::
|
30
|
-
RuboCop::RSpec::TopLevelDescribe,
|
31
|
-
RuboCop::RSpec::Language,
|
32
|
-
RuboCop::RSpec::Language::NodePattern
|
29
|
+
include RuboCop::RSpec::TopLevelDescribe
|
33
30
|
|
34
31
|
MSG = 'Do not use `let!` for test setup.'.freeze
|
35
32
|
|
@@ -12,18 +12,11 @@ module RuboCop
|
|
12
12
|
# allow(foo).to receive(bar: thing)
|
13
13
|
#
|
14
14
|
class MessageChain < Cop
|
15
|
-
include RuboCop::RSpec::SpecOnly
|
16
|
-
|
17
15
|
MESSAGE = 'Avoid stubbing using `%<method>s`'.freeze
|
18
16
|
|
19
|
-
MESSAGE_CHAIN_METHODS = [
|
20
|
-
:receive_message_chain,
|
21
|
-
:stub_chain
|
22
|
-
].freeze
|
23
|
-
|
24
17
|
def on_send(node)
|
25
18
|
_receiver, method_name, *_args = *node
|
26
|
-
return unless
|
19
|
+
return unless Matchers::MESSAGE_CHAIN.include?(method_name)
|
27
20
|
|
28
21
|
add_offense(node, :selector, MESSAGE % { method: method_name })
|
29
22
|
end
|