Skip to content

Commit e79d8e1

Browse files
committed
Approve with comment when using method chaining with a longform block syntax
1 parent c3bf34b commit e79d8e1

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed

lib/analyzers/acronym/analyze.rb

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,27 @@ module Acronym
22
class Analyze < ExerciseAnalyzer
33
include Mandate
44

5+
MESSAGES = {
6+
use_shorthand_block_syntax: "ruby.acronym.block_syntax.shorthand", # "Use ruby's short hand block syntax to be more concise"
7+
}
8+
59
def analyze!
6-
if solution.uses_method_chain? || solution.uses_scan? || solution.uses_split?
7-
self.status = :approve
10+
approve! if approve_without_comment?
11+
12+
approve!(:use_shorthand_block_syntax) if solution.uses_method_chain_with_block?
13+
end
14+
15+
private
16+
17+
def approve_without_comment?
18+
solution.uses_method_chain? || solution.uses_scan? || solution.uses_split?
19+
end
20+
21+
def approve!(msg = nil)
22+
self.comments << MESSAGES[msg] if msg
23+
self.status = :approve
824

9-
raise FinishedFlowControlException
10-
end
25+
raise FinishedFlowControlException
1126
end
1227
end
1328
end

lib/analyzers/acronym/representation.rb

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,40 @@ def uses_method_chain?
2929
matches?(target_method.body, matchers)
3030
end
3131

32+
def uses_method_chain_with_block?
33+
matchers = [
34+
{
35+
method_name: :upcase,
36+
},
37+
{
38+
method_name: :join,
39+
chained?: true
40+
},
41+
{
42+
type: :block,
43+
method_name: :map,
44+
chained?: true,
45+
arguments: s(:args, s(:arg, :word)),
46+
body: s(:send, s(:lvar, :word), :chr)
47+
},
48+
{
49+
method_name: :map,
50+
},
51+
{
52+
method_name: :split,
53+
chained?: true
54+
},
55+
{
56+
method_name: :tr,
57+
receiver: s(:lvar, :words),
58+
chained?: true,
59+
arguments: [{ to_ast: s(:str, "-") }, { to_ast: s(:str, " ") }]
60+
}
61+
]
62+
63+
matches?(target_method.body, matchers, [:send, :block])
64+
end
65+
3266
def uses_scan?
3367
matchers = [
3468
{
@@ -84,9 +118,9 @@ def target_module
84118
SA::Helpers.extract_module_or_class(root_node, "Acronym")
85119
end
86120

87-
def matches?(body, matchers)
121+
def matches?(body, matchers, types = [:send])
88122
body.
89-
each_node(:send).
123+
each_node(*types).
90124
with_index.
91125
all? { |node, i| node_matches?(node, matchers[i]) }
92126
end

test/exercises/acronym_test.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ def self.abbreviate(words)
1515
assert_equal [], results[:comments]
1616
end
1717

18+
def test_method_chaining_with_block_syntax_passes_with_comment
19+
source = %q{
20+
class Acronym
21+
def self.abbreviate(words)
22+
words.tr('-', ' ').split.map { |word| word.chr }.join.upcase
23+
end
24+
end
25+
}
26+
results = Acronym::Analyze.(source)
27+
assert_equal :approve, results[:status]
28+
assert_equal ["ruby.acronym.block_syntax.shorthand"], results[:comments]
29+
end
30+
1831
def test_module_method_passes
1932
source = %q{
2033
module Acronym

0 commit comments

Comments
 (0)