Skip to content

Commit 425f53f

Browse files
committed
refactor indentation with a dedicated class
1 parent 47c4ab7 commit 425f53f

File tree

4 files changed

+102
-10
lines changed

4 files changed

+102
-10
lines changed

.rubocop.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ Metrics/PerceivedComplexity: { Exclude: [lib/bashly/config_validator.rb] }
1919
Metrics/MethodLength: { Exclude: [lib/bashly/config_validator.rb] }
2020
Style/GuardClause: { Exclude: [lib/bashly/config_validator.rb] }
2121

22+
# False positive report of invalid use of a method that starts with `set_`
23+
Naming/AccessorMethodName:
24+
Exclude:
25+
- 'lib/bashly/indenter.rb'
26+
2227
# FIXME: The `Command` class is too long
2328
Metrics/ClassLength: { Exclude: [lib/bashly/script/command.rb] }
2429

lib/bashly/extensions/array.rb

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
1+
require 'bashly/indenter'
2+
13
class Array
24
def indent(offset)
35
return self unless offset.positive?
46

57
indentation = ' ' * offset
6-
heredoc_marker = nil
8+
indenter = Indenter.new indentation
79

8-
map do |line|
9-
if heredoc_marker
10-
heredoc_marker = nil if /^#{heredoc_marker}\n?$/.match?(line)
11-
line
12-
else
13-
heredoc_marker = $1 if line =~ /<<-?\s*(\w+)/
14-
"#{indentation}#{line}"
15-
end
16-
end
10+
map { |line| indenter.indent line }
1711
end
1812

1913
def nonuniq

lib/bashly/indenter.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# A helper class, used by the `Array#indent` extension.
2+
# It will return the array of strings with all strings prefixed by `indentation`
3+
# unless the line is within a heredoc block.
4+
class Indenter
5+
attr_reader :marker, :indentation
6+
7+
def initialize(indentation)
8+
@indentation = indentation
9+
@marker = nil
10+
end
11+
12+
def indent(line)
13+
if inside_heredoc?
14+
reset_marker if heredoc_closed?(line)
15+
line
16+
else
17+
set_heredoc_state(line)
18+
"#{indentation}#{line}"
19+
end
20+
end
21+
22+
private
23+
24+
def reset_marker
25+
@marker = nil
26+
end
27+
28+
def inside_heredoc?
29+
!!marker
30+
end
31+
32+
def set_heredoc_state(line)
33+
@marker = extract_heredoc_marker(line)
34+
end
35+
36+
def extract_heredoc_marker(line)
37+
line =~ /<<-?\s*(\w+)/ ? $1 : nil
38+
end
39+
40+
def heredoc_closed?(line)
41+
inside_heredoc? && /^#{marker}\n?$/.match?(line)
42+
end
43+
end

spec/bashly/indenter_spec.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
describe Indenter do
2+
# this is tested through the array extension for convenience
3+
subject { ['flat', ' indented', ' very indented'] }
4+
5+
describe '#indent' do
6+
it 'prepends each element with the indentation string' do
7+
expect(subject.indent(2)).to eq [' flat', ' indented', ' very indented']
8+
end
9+
10+
context 'when offset is 0' do
11+
it 'returns the array as is' do
12+
expect(subject.indent(0)).to eq subject
13+
end
14+
end
15+
16+
# context 'when the string contains heredoc block' do
17+
# subject do
18+
# result = <<~SUBJECT
19+
# function() {
20+
# cat <<-SOME_EOF_MARKER
21+
# not-indented
22+
# indented-once
23+
# indented-twice
24+
# SOME_EOF_MARKER
25+
# } # indented with function() start
26+
# SUBJECT
27+
28+
# result.lines
29+
# end
30+
31+
# let(:expected) do
32+
# result = <<~SUBJECT
33+
# function() {
34+
# cat <<-SOME_EOF_MARKER
35+
# not-indented
36+
# indented-once
37+
# indented-twice
38+
# SOME_EOF_MARKER
39+
# } # indented with function() start
40+
# SUBJECT
41+
42+
# result.lines
43+
# end
44+
45+
# it 'does not indent it but indents everything else' do
46+
# expect(subject.indent 2).to eq expected
47+
# end
48+
# end
49+
end
50+
end

0 commit comments

Comments
 (0)