rubocop-rspec 1.38.0 → 1.42.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 +44 -0
- data/CODE_OF_CONDUCT.md +17 -0
- data/README.md +1 -61
- data/config/default.yml +147 -17
- data/lib/rubocop-rspec.rb +3 -1
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +11 -18
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +11 -18
- data/lib/rubocop/cop/rspec/be.rb +1 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +5 -5
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +18 -16
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +8 -9
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +69 -0
- data/lib/rubocop/cop/rspec/context_method.rb +5 -7
- data/lib/rubocop/cop/rspec/cop.rb +9 -29
- data/lib/rubocop/cop/rspec/describe_class.rb +20 -5
- data/lib/rubocop/cop/rspec/describe_method.rb +0 -1
- data/lib/rubocop/cop/rspec/described_class.rb +10 -7
- data/lib/rubocop/cop/rspec/dialect.rb +4 -11
- data/lib/rubocop/cop/rspec/empty_hook.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +5 -3
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +5 -5
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +4 -1
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +5 -5
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +4 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +6 -7
- data/lib/rubocop/cop/rspec/expect_actual.rb +7 -10
- data/lib/rubocop/cop/rspec/expect_change.rb +9 -34
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +2 -2
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +23 -20
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +10 -16
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +6 -7
- data/lib/rubocop/cop/rspec/file_path.rb +32 -4
- data/lib/rubocop/cop/rspec/hook_argument.rb +11 -17
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +9 -28
- data/lib/rubocop/cop/rspec/implicit_expect.rb +6 -14
- data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -5
- data/lib/rubocop/cop/rspec/instance_spy.rb +17 -11
- data/lib/rubocop/cop/rspec/instance_variable.rb +3 -7
- data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +2 -5
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +4 -5
- data/lib/rubocop/cop/rspec/leading_subject.rb +12 -19
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -4
- data/lib/rubocop/cop/rspec/let_before_examples.rb +9 -25
- data/lib/rubocop/cop/rspec/let_setup.rb +15 -3
- data/lib/rubocop/cop/rspec/message_chain.rb +6 -5
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/message_spies.rb +1 -2
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +17 -18
- data/lib/rubocop/cop/rspec/named_subject.rb +7 -7
- data/lib/rubocop/cop/rspec/nested_groups.rb +9 -10
- data/lib/rubocop/cop/rspec/not_to_not.rb +4 -5
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +25 -55
- data/lib/rubocop/cop/rspec/rails/http_status.rb +6 -8
- data/lib/rubocop/cop/rspec/receive_counts.rb +14 -16
- data/lib/rubocop/cop/rspec/receive_never.rb +10 -10
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +11 -1
- data/lib/rubocop/cop/rspec/return_from_stub.rb +11 -21
- data/lib/rubocop/cop/rspec/scattered_let.rb +11 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +7 -20
- data/lib/rubocop/cop/rspec/shared_examples.rb +6 -8
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +14 -17
- data/lib/rubocop/cop/rspec/subject_stub.rb +23 -51
- data/lib/rubocop/cop/rspec/variable_definition.rb +56 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +47 -0
- data/lib/rubocop/cop/rspec/yield.rb +13 -10
- data/lib/rubocop/cop/rspec_cops.rb +5 -1
- data/lib/rubocop/rspec/blank_line_separation.rb +0 -8
- data/lib/rubocop/rspec/corrector/move_node.rb +52 -0
- data/lib/rubocop/rspec/description_extractor.rb +2 -6
- data/lib/rubocop/rspec/example.rb +1 -1
- data/lib/rubocop/rspec/example_group.rb +21 -49
- data/lib/rubocop/rspec/factory_bot.rb +7 -1
- data/lib/rubocop/rspec/language.rb +8 -0
- data/lib/rubocop/rspec/language/node_pattern.rb +5 -1
- data/lib/rubocop/rspec/top_level_group.rb +44 -0
- data/lib/rubocop/rspec/variable.rb +16 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +17 -10
- data/lib/rubocop/rspec/util.rb +0 -19
@@ -55,6 +55,7 @@ module RuboCop
|
|
55
55
|
# end
|
56
56
|
#
|
57
57
|
class DescribedClass < Cop
|
58
|
+
extend AutoCorrector
|
58
59
|
include ConfigurableEnforcedStyle
|
59
60
|
|
60
61
|
DESCRIBED_CLASS = 'described_class'
|
@@ -85,22 +86,24 @@ module RuboCop
|
|
85
86
|
return unless body
|
86
87
|
|
87
88
|
find_usage(body) do |match|
|
88
|
-
|
89
|
+
msg = message(match.const_name)
|
90
|
+
add_offense(match, message: msg) do |corrector|
|
91
|
+
autocorrect(corrector, match)
|
92
|
+
end
|
89
93
|
end
|
90
94
|
end
|
91
95
|
|
92
|
-
|
96
|
+
private
|
97
|
+
|
98
|
+
def autocorrect(corrector, match)
|
93
99
|
replacement = if style == :described_class
|
94
100
|
DESCRIBED_CLASS
|
95
101
|
else
|
96
102
|
@described_class.const_name
|
97
103
|
end
|
98
|
-
lambda do |corrector|
|
99
|
-
corrector.replace(node.loc.expression, replacement)
|
100
|
-
end
|
101
|
-
end
|
102
104
|
|
103
|
-
|
105
|
+
corrector.replace(match, replacement)
|
106
|
+
end
|
104
107
|
|
105
108
|
def find_usage(node, &block)
|
106
109
|
yield(node) if offensive?(node)
|
@@ -42,6 +42,7 @@ module RuboCop
|
|
42
42
|
# # ...
|
43
43
|
# end
|
44
44
|
class Dialect < Cop
|
45
|
+
extend AutoCorrector
|
45
46
|
include MethodPreference
|
46
47
|
|
47
48
|
MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
|
@@ -52,24 +53,16 @@ module RuboCop
|
|
52
53
|
return unless rspec_method?(node)
|
53
54
|
return unless preferred_methods[node.method_name]
|
54
55
|
|
55
|
-
|
56
|
-
|
56
|
+
msg = format(MSG, prefer: preferred_method(node.method_name),
|
57
|
+
current: node.method_name)
|
57
58
|
|
58
|
-
|
59
|
-
lambda do |corrector|
|
59
|
+
add_offense(node, message: msg) do |corrector|
|
60
60
|
current = node.loc.selector
|
61
61
|
preferred = preferred_method(current.source)
|
62
62
|
|
63
63
|
corrector.replace(current, preferred)
|
64
64
|
end
|
65
65
|
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def message(node)
|
70
|
-
format(MSG, prefer: preferred_method(node.method_name),
|
71
|
-
current: node.method_name)
|
72
|
-
end
|
73
66
|
end
|
74
67
|
end
|
75
68
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for empty before and after hooks.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# before {}
|
11
|
+
# after do; end
|
12
|
+
# before(:all) do
|
13
|
+
# end
|
14
|
+
# after(:all) { }
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# before { create_users }
|
18
|
+
# after do
|
19
|
+
# cleanup_users
|
20
|
+
# end
|
21
|
+
# before(:all) do
|
22
|
+
# create_feed
|
23
|
+
# end
|
24
|
+
# after(:all) { cleanup_feed }
|
25
|
+
class EmptyHook < Cop
|
26
|
+
extend AutoCorrector
|
27
|
+
include RuboCop::Cop::RangeHelp
|
28
|
+
|
29
|
+
MSG = 'Empty hook detected.'
|
30
|
+
|
31
|
+
def_node_matcher :empty_hook?, <<~PATTERN
|
32
|
+
(block $#{Hooks::ALL.send_pattern} _ nil?)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_block(node)
|
36
|
+
empty_hook?(node) do |hook|
|
37
|
+
add_offense(hook) do |corrector|
|
38
|
+
range = range_with_surrounding_space(range: node.loc.expression)
|
39
|
+
corrector.remove(range)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -42,6 +42,7 @@ module RuboCop
|
|
42
42
|
# end
|
43
43
|
#
|
44
44
|
class EmptyLineAfterExample < Cop
|
45
|
+
extend AutoCorrector
|
45
46
|
include RuboCop::RSpec::BlankLineSeparation
|
46
47
|
|
47
48
|
MSG = 'Add an empty line after `%<example>s`.'
|
@@ -52,9 +53,10 @@ module RuboCop
|
|
52
53
|
return if allowed_one_liner?(node)
|
53
54
|
|
54
55
|
missing_separating_line(node) do |location|
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
msg = format(MSG, example: node.method_name)
|
57
|
+
add_offense(location, message: msg) do |corrector|
|
58
|
+
corrector.insert_after(location.end, "\n")
|
59
|
+
end
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
@@ -24,6 +24,7 @@ module RuboCop
|
|
24
24
|
# end
|
25
25
|
#
|
26
26
|
class EmptyLineAfterExampleGroup < Cop
|
27
|
+
extend AutoCorrector
|
27
28
|
include RuboCop::RSpec::BlankLineSeparation
|
28
29
|
|
29
30
|
MSG = 'Add an empty line after `%<example_group>s`.'
|
@@ -33,11 +34,10 @@ module RuboCop
|
|
33
34
|
return if last_child?(node)
|
34
35
|
|
35
36
|
missing_separating_line(node) do |location|
|
36
|
-
|
37
|
-
|
38
|
-
location
|
39
|
-
|
40
|
-
)
|
37
|
+
msg = format(MSG, example_group: node.method_name)
|
38
|
+
add_offense(location, message: msg) do |corrector|
|
39
|
+
corrector.insert_after(location.end, "\n")
|
40
|
+
end
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -17,6 +17,7 @@ module RuboCop
|
|
17
17
|
#
|
18
18
|
# it { does_something }
|
19
19
|
class EmptyLineAfterFinalLet < Cop
|
20
|
+
extend AutoCorrector
|
20
21
|
include RuboCop::RSpec::BlankLineSeparation
|
21
22
|
|
22
23
|
MSG = 'Add an empty line after the last `let` block.'
|
@@ -30,7 +31,9 @@ module RuboCop
|
|
30
31
|
return if last_child?(latest_let)
|
31
32
|
|
32
33
|
missing_separating_line(latest_let) do |location|
|
33
|
-
add_offense(
|
34
|
+
add_offense(location) do |corrector|
|
35
|
+
corrector.insert_after(location.end, "\n")
|
36
|
+
end
|
34
37
|
end
|
35
38
|
end
|
36
39
|
end
|
@@ -34,6 +34,7 @@ module RuboCop
|
|
34
34
|
# it { does_something }
|
35
35
|
#
|
36
36
|
class EmptyLineAfterHook < Cop
|
37
|
+
extend AutoCorrector
|
37
38
|
include RuboCop::RSpec::BlankLineSeparation
|
38
39
|
|
39
40
|
MSG = 'Add an empty line after `%<hook>s`.'
|
@@ -43,11 +44,10 @@ module RuboCop
|
|
43
44
|
return if last_child?(node)
|
44
45
|
|
45
46
|
missing_separating_line(node) do |location|
|
46
|
-
|
47
|
-
|
48
|
-
location
|
49
|
-
|
50
|
-
)
|
47
|
+
msg = format(MSG, hook: node.method_name)
|
48
|
+
add_offense(location, message: msg) do |corrector|
|
49
|
+
corrector.insert_after(location.end, "\n")
|
50
|
+
end
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -15,6 +15,7 @@ module RuboCop
|
|
15
15
|
#
|
16
16
|
# let(:foo) { bar }
|
17
17
|
class EmptyLineAfterSubject < Cop
|
18
|
+
extend AutoCorrector
|
18
19
|
include RuboCop::RSpec::BlankLineSeparation
|
19
20
|
|
20
21
|
MSG = 'Add empty line after `subject`.'
|
@@ -24,7 +25,9 @@ module RuboCop
|
|
24
25
|
return if last_child?(node)
|
25
26
|
|
26
27
|
missing_separating_line(node) do |location|
|
27
|
-
add_offense(
|
28
|
+
add_offense(location) do |corrector|
|
29
|
+
corrector.insert_after(location.end, "\n")
|
30
|
+
end
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
@@ -30,6 +30,8 @@ module RuboCop
|
|
30
30
|
# it 'does things' do
|
31
31
|
# end
|
32
32
|
class ExampleWording < Cop
|
33
|
+
extend AutoCorrector
|
34
|
+
|
33
35
|
MSG_SHOULD = 'Do not use should when describing your tests.'
|
34
36
|
MSG_IT = "Do not repeat 'it' when describing your tests."
|
35
37
|
|
@@ -53,16 +55,13 @@ module RuboCop
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
def autocorrect(node)
|
57
|
-
lambda do |corrector|
|
58
|
-
corrector.replace(docstring(node), replacement_text(node))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
58
|
private
|
63
59
|
|
64
60
|
def add_wording_offense(node, message)
|
65
|
-
|
61
|
+
docstring = docstring(node)
|
62
|
+
add_offense(docstring, message: message) do |corrector|
|
63
|
+
corrector.replace(docstring, replacement_text(node))
|
64
|
+
end
|
66
65
|
end
|
67
66
|
|
68
67
|
def docstring(node)
|
@@ -17,6 +17,8 @@ module RuboCop
|
|
17
17
|
# expect(name).to eq("John")
|
18
18
|
#
|
19
19
|
class ExpectActual < Cop
|
20
|
+
extend AutoCorrector
|
21
|
+
|
20
22
|
MSG = 'Provide the actual you are testing to `expect(...)`.'
|
21
23
|
|
22
24
|
SIMPLE_LITERALS = %i[
|
@@ -55,17 +57,12 @@ module RuboCop
|
|
55
57
|
PATTERN
|
56
58
|
|
57
59
|
def on_send(node)
|
58
|
-
expect_literal(node) do |
|
59
|
-
add_offense(
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
def autocorrect(node)
|
64
|
-
actual, matcher, expected = expect_literal(node)
|
65
|
-
lambda do |corrector|
|
66
|
-
return unless SUPPORTED_MATCHERS.include?(matcher)
|
60
|
+
expect_literal(node) do |actual, matcher, expected|
|
61
|
+
add_offense(actual.source_range) do |corrector|
|
62
|
+
next unless SUPPORTED_MATCHERS.include?(matcher)
|
67
63
|
|
68
|
-
|
64
|
+
swap(corrector, actual, expected)
|
65
|
+
end
|
69
66
|
end
|
70
67
|
end
|
71
68
|
|
@@ -30,6 +30,7 @@ module RuboCop
|
|
30
30
|
# expect { run }.to change { user.reload.name }
|
31
31
|
#
|
32
32
|
class ExpectChange < Cop
|
33
|
+
extend AutoCorrector
|
33
34
|
include ConfigurableEnforcedStyle
|
34
35
|
|
35
36
|
MSG_BLOCK = 'Prefer `change(%<obj>s, :%<attr>s)`.'
|
@@ -51,10 +52,11 @@ module RuboCop
|
|
51
52
|
return unless style == :block
|
52
53
|
|
53
54
|
expect_change_with_arguments(node) do |receiver, message|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
msg = format(MSG_CALL, obj: receiver, attr: message)
|
56
|
+
add_offense(node, message: msg) do |corrector|
|
57
|
+
replacement = "change { #{receiver}.#{message} }"
|
58
|
+
corrector.replace(node, replacement)
|
59
|
+
end
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
@@ -62,37 +64,10 @@ module RuboCop
|
|
62
64
|
return unless style == :method_call
|
63
65
|
|
64
66
|
expect_change_with_block(node) do |receiver, message|
|
65
|
-
|
66
|
-
|
67
|
-
message: format(MSG_BLOCK, obj: receiver, attr: message)
|
68
|
-
)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def autocorrect(node)
|
73
|
-
if style == :block
|
74
|
-
autocorrect_method_call_to_block(node)
|
75
|
-
else
|
76
|
-
autocorrect_block_to_method_call(node)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
private
|
81
|
-
|
82
|
-
def autocorrect_method_call_to_block(node)
|
83
|
-
lambda do |corrector|
|
84
|
-
expect_change_with_arguments(node) do |receiver, message|
|
85
|
-
replacement = "change { #{receiver}.#{message} }"
|
86
|
-
corrector.replace(node.loc.expression, replacement)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def autocorrect_block_to_method_call(node)
|
92
|
-
lambda do |corrector|
|
93
|
-
expect_change_with_block(node) do |receiver, message|
|
67
|
+
msg = format(MSG_BLOCK, obj: receiver, attr: message)
|
68
|
+
add_offense(node, message: msg) do |corrector|
|
94
69
|
replacement = "change(#{receiver}, :#{message})"
|
95
|
-
corrector.replace(node
|
70
|
+
corrector.replace(node, replacement)
|
96
71
|
end
|
97
72
|
end
|
98
73
|
end
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
name = variable_name[1..-1]
|
28
28
|
return unless name.eql?('stdout') || name.eql?('stderr')
|
29
29
|
|
30
|
-
add_offense(node
|
30
|
+
add_offense(node.loc.name, message: format(MSG, name: name))
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
@@ -25,35 +25,42 @@ module RuboCop
|
|
25
25
|
# # good
|
26
26
|
# count { 1 }
|
27
27
|
class AttributeDefinedStatically < Cop
|
28
|
+
extend AutoCorrector
|
29
|
+
|
28
30
|
MSG = 'Use a block to declare attribute values.'
|
29
31
|
|
30
32
|
def_node_matcher :value_matcher, <<-PATTERN
|
31
33
|
(send _ !#reserved_method? $...)
|
32
34
|
PATTERN
|
33
35
|
|
34
|
-
|
36
|
+
def_node_matcher :factory_attributes, <<-PATTERN
|
35
37
|
(block (send _ #attribute_defining_method? ...) _ { (begin $...) $(send ...) } )
|
36
38
|
PATTERN
|
37
39
|
|
38
40
|
def on_block(node)
|
39
|
-
factory_attributes(node)
|
41
|
+
attributes = factory_attributes(node) || []
|
42
|
+
attributes = [attributes] unless attributes.is_a?(Array)
|
43
|
+
|
44
|
+
attributes.each do |attribute|
|
40
45
|
next unless offensive_receiver?(attribute.receiver, node)
|
41
46
|
next if proc?(attribute) || association?(attribute.first_argument)
|
42
47
|
|
43
|
-
add_offense(attribute)
|
48
|
+
add_offense(attribute) do |corrector|
|
49
|
+
autocorrect(corrector, attribute)
|
50
|
+
end
|
44
51
|
end
|
45
52
|
end
|
46
53
|
|
47
|
-
|
54
|
+
private
|
55
|
+
|
56
|
+
def autocorrect(corrector, node)
|
48
57
|
if node.parenthesized?
|
49
|
-
autocorrect_replacing_parens(node)
|
58
|
+
autocorrect_replacing_parens(corrector, node)
|
50
59
|
else
|
51
|
-
autocorrect_without_parens(node)
|
60
|
+
autocorrect_without_parens(corrector, node)
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
|
-
private
|
56
|
-
|
57
64
|
def offensive_receiver?(receiver, node)
|
58
65
|
receiver.nil? ||
|
59
66
|
receiver.self_type? ||
|
@@ -74,24 +81,20 @@ module RuboCop
|
|
74
81
|
|
75
82
|
def_node_matcher :association?, '(hash <(pair (sym :factory) _) ...>)'
|
76
83
|
|
77
|
-
def autocorrect_replacing_parens(node)
|
84
|
+
def autocorrect_replacing_parens(corrector, node)
|
78
85
|
left_braces, right_braces = braces(node)
|
79
86
|
|
80
|
-
|
81
|
-
|
82
|
-
corrector.replace(node.location.end, right_braces)
|
83
|
-
end
|
87
|
+
corrector.replace(node.location.begin, ' ' + left_braces)
|
88
|
+
corrector.replace(node.location.end, right_braces)
|
84
89
|
end
|
85
90
|
|
86
|
-
def autocorrect_without_parens(node)
|
91
|
+
def autocorrect_without_parens(corrector, node)
|
87
92
|
left_braces, right_braces = braces(node)
|
88
93
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
corrector.insert_after(expression, right_braces)
|
94
|
-
end
|
94
|
+
argument = node.first_argument
|
95
|
+
expression = argument.location.expression
|
96
|
+
corrector.insert_before(expression, left_braces)
|
97
|
+
corrector.insert_after(expression, right_braces)
|
95
98
|
end
|
96
99
|
|
97
100
|
def braces(node)
|