slimcop 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d598a52269b8958e493b5b29b175e58d96d122381679e21b5c90c86b2c50d8a
4
- data.tar.gz: 8f45fae7e940bdc8ece0c4ae5575554ba715f6d79e986a9c18fd9893e7c9ff61
3
+ metadata.gz: bace4128c4ef162ff7f9a4f1eca5af7275631b850df5a6ad48a92d8693114771
4
+ data.tar.gz: d7a04c3c5ed2930490174e41e838cd6c7e26a8eae8e6476fa188ee89ae3f103f
5
5
  SHA512:
6
- metadata.gz: bbcc157e1514269668fe126bce9f29315cf848ef49208c784877a36fdd00b5d71de538af0474ca76dfdee44c4aa3920167b065bc0f41b65a5948facf04f133b8
7
- data.tar.gz: '009cdacfe8068fcda5c90a172ca49ef0b77db8e965d4700723f6010bbe0fd0b35b5dcbe8f8d7472b79121785961e0997d1a41146b1aeb0eb4c21add9240bb126'
6
+ metadata.gz: d4cacec671cd5855ceedd2183099450f2e4abf759d71f11e77e4af5f5c25b7e52a71d6da4f4e7fbaac812bf7509311c4edc5233501b021dfbb9da6259e1b305d
7
+ data.tar.gz: 0db1c7751629572c7e8738e52fe8d44f41e20047b48f091aa00defa0dad62f2674bf5ae0fafe2b2a53ce5b3eab006fde3f0a9ae840a8cc6c779cadb9632c4845
data/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.2.0 - 2021-12-21
6
+
7
+ ### Added
8
+
9
+ - Add --color and --no-color option.
10
+
11
+ ### Changed
12
+
13
+ - Improve offenses CLI output format.
14
+ - Return exit status 1 if any offense found.
15
+
5
16
  ## 0.1.0 - 2021-12-21
6
17
 
7
18
  - Initial release.
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- slimcop (0.1.0)
4
+ slimcop (0.2.0)
5
+ rainbow
5
6
  rubocop (>= 0.87)
6
7
  slimi (>= 0.1.1)
7
8
 
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # Slimcop
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/slimcop.svg)](https://rubygems.org/gems/slimcop)
3
4
  [![test](https://github.com/r7kamura/slimcop/actions/workflows/test.yml/badge.svg)](https://github.com/r7kamura/slimcop/actions/workflows/test.yml)
4
5
 
5
6
  [RuboCop](https://github.com/rubocop/rubocop) runner for [Slim template](https://github.com/slim-template/slim).
@@ -32,4 +33,5 @@ Use `slimcop` executable to check offenses and auto-correct them.
32
33
  $ slimcop --help
33
34
  Usage: slimcop [options] [file1, file2, ...]
34
35
  -a, --auto-correct Auto-correct offenses.
36
+ --[no-]color Force color output on or off.
35
37
  ```
data/lib/slimcop/cli.rb CHANGED
@@ -1,36 +1,71 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'optparse'
4
- require 'rubocop'
3
+ require 'rainbow'
5
4
 
6
5
  module Slimcop
7
6
  class Cli
8
7
  def initialize(argv)
9
8
  @argv = argv.dup
9
+ @configuration = Configuration.new
10
+ @formatter = Formatter.new
10
11
  end
11
12
 
12
13
  def call
13
14
  options = parse!
14
- @argv.each do |slim_file_path|
15
- runner = Runner.new(
16
- file_path: slim_file_path
17
- )
18
- if options[:auto_correct]
19
- ::File.write(
20
- slim_file_path,
21
- runner.auto_correct
22
- )
23
- else
24
- messages = runner.offenses.map do |offense|
25
- offense[:rubocop_offense].message
26
- end
27
- puts messages
28
- end
29
- end
15
+ slim_file_paths = @argv
16
+
17
+ Rainbow.enabled = options[:color] if options.key?(:color)
18
+
19
+ offenses_set = investigate(auto_correct: options[:auto_correct], slim_file_paths: slim_file_paths)
20
+ correct(offenses_set) if options[:auto_correct]
21
+ offenses = offenses_set.flat_map { |(_, _, array)| array }
22
+ report(offenses)
23
+ exit(offenses.empty? ? 0 : 1)
30
24
  end
31
25
 
32
26
  private
33
27
 
28
+ # @param [Array] offenses_set
29
+ def correct(offenses_set)
30
+ offenses_set.each do |(file_path, source, offenses)|
31
+ rewritten_source = SlimCorrector.new(
32
+ file_path: file_path,
33
+ offenses: offenses,
34
+ source: source
35
+ ).call
36
+ ::File.write(file_path, rewritten_source)
37
+ end
38
+ end
39
+
40
+ # @param [Boolean] auto_correct
41
+ # @param [Array] slim_file_paths
42
+ # @return [Array]
43
+ def investigate(auto_correct:, slim_file_paths:)
44
+ slim_file_paths.map do |file_path|
45
+ source = ::File.read(file_path)
46
+ offenses = SlimOffenseCollector.new(
47
+ auto_correct: auto_correct,
48
+ file_path: file_path,
49
+ rubocop_config: @configuration.rubocop_config,
50
+ source: source
51
+ ).call
52
+ [file_path, source, offenses]
53
+ end
54
+ end
55
+
56
+ # @param [Array<Slimcop::Offense>] offenses
57
+ def report(offenses)
58
+ result = +''
59
+ unless offenses.empty?
60
+ result << "\nOffenses:\n\n"
61
+ lines = offenses.map do |offense|
62
+ @formatter.format_offense(offense)
63
+ end
64
+ result << lines.join("\n")
65
+ end
66
+ puts(result)
67
+ end
68
+
34
69
  # @return [Hash]
35
70
  def parse!
36
71
  options = {}
@@ -39,6 +74,9 @@ module Slimcop
39
74
  parser.on('-a', '--auto-correct', 'Auto-correct offenses.') do
40
75
  options[:auto_correct] = true
41
76
  end
77
+ parser.on('--[no-]color', 'Force color output on or off.') do |value|
78
+ options[:color] = value
79
+ end
42
80
  parser.parse!(@argv)
43
81
  options
44
82
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module Slimcop
6
+ class Configuration
7
+ # @return [RuboCop::Config]
8
+ def rubocop_config
9
+ @rubocop_config ||= begin
10
+ config_path = ::File.expand_path('../../default.yml', __dir__)
11
+ config = ::RuboCop::ConfigLoader.load_file(config_path)
12
+ ::RuboCop::ConfigLoader.merge_with_default(config, config_path)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require 'rainbow'
5
+
6
+ module Slimcop
7
+ # Format String for CLI output.
8
+ class Formatter
9
+ COLOR_FOR_SEVERITY_CODE = {
10
+ convention: :yellow,
11
+ error: :red,
12
+ fatal: :red,
13
+ info: :gray,
14
+ refactor: :yellow,
15
+ warning: :magenta
16
+ }.freeze
17
+
18
+ # @param [Slimcop::Offense] offense
19
+ # @return [String]
20
+ def format_offense(offense)
21
+ format(
22
+ '%<path>s:%<line>d:%<column>d %<severity>s: %<message>s',
23
+ column: offense.real_column,
24
+ line: offense.line,
25
+ message: message(offense),
26
+ path: file_path(offense),
27
+ severity: severity(offense)
28
+ )
29
+ end
30
+
31
+ private
32
+
33
+ # @param [String] path e.g. "./spec/fixtures/dummy.slim"
34
+ # @return [String]
35
+ # @example "spec/fixtures/dummy.slim"
36
+ def canonicalize_path(path)
37
+ ::File.expand_path(path).delete_prefix("#{::Dir.pwd}/")
38
+ end
39
+
40
+ # @param [Slimcop::Offense] offense
41
+ # @return [String]
42
+ def file_path(offense)
43
+ Rainbow(canonicalize_path(offense.file_path)).cyan
44
+ end
45
+
46
+ # @param [Slimcop::Offense] offense
47
+ # @return [String]
48
+ def message(offense)
49
+ "#{status(offense)}#{offense.message}"
50
+ end
51
+
52
+ # @param [Slimcop::Offense] offense
53
+ # @return [String]
54
+ def severity(offense)
55
+ Rainbow(offense.severity.code).color(COLOR_FOR_SEVERITY_CODE[offense.severity.name])
56
+ end
57
+
58
+ # @param [Slimcop::Offense] offense
59
+ # @return [String]
60
+ def status(offense)
61
+ if offense.rubocop_offense.corrected_with_todo?
62
+ Rainbow('[Todo] ').green
63
+ elsif offense.rubocop_offense.corrected?
64
+ Rainbow('[Corrected] ').green
65
+ elsif offense.rubocop_offense.correctable?
66
+ Rainbow('[Correctable] ').yellow
67
+ else
68
+ ''
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parser'
4
+
5
+ module Slimcop
6
+ class Offense
7
+ # @return [Integer]
8
+ attr_reader :offset
9
+
10
+ # @return [RuboCop::Cop::Offense]
11
+ attr_reader :rubocop_offense
12
+
13
+ # @param [Integer] offset
14
+ # @param [RuboCop::Cop::Offense] rubocop_offense
15
+ # @param [String] source Slim code.
16
+ def initialize(offset:, rubocop_offense:, source:)
17
+ @offset = offset
18
+ @rubocop_offense = rubocop_offense
19
+ @source = source
20
+ end
21
+
22
+ # @return [RuboCop::Cop::Corrector]
23
+ def corrector
24
+ @rubocop_offense.corrector
25
+ end
26
+
27
+ # @return [String]
28
+ def file_path
29
+ @rubocop_offense.location.source_buffer.name
30
+ end
31
+
32
+ # @return [Integer]
33
+ def line
34
+ range.line
35
+ end
36
+
37
+ # @return [String]
38
+ def message
39
+ @rubocop_offense.message
40
+ end
41
+
42
+ # @return [Integer]
43
+ def real_column
44
+ range.column + 1
45
+ end
46
+
47
+ # @return [RuboCop::Cop::Severity]
48
+ def severity
49
+ @rubocop_offense.severity
50
+ end
51
+
52
+ private
53
+
54
+ # @return [Parser::Source::Buffer]
55
+ def buffer
56
+ ::Parser::Source::Buffer.new(
57
+ file_path,
58
+ source: @source
59
+ )
60
+ end
61
+
62
+ # @return [Parser::Source::Range]
63
+ def range
64
+ @range ||= ::Parser::Source::Range.new(
65
+ buffer,
66
+ @rubocop_offense.location.begin_pos + @offset,
67
+ @rubocop_offense.location.end_pos + @offset
68
+ )
69
+ end
70
+ end
71
+ end
@@ -5,10 +5,12 @@ require 'rubocop'
5
5
  module Slimcop
6
6
  # Collect RuboCop offenses from Ruby code.
7
7
  class RubyOffenseCollector
8
+ # @param [Boolean] auto_correct
8
9
  # @param [String] file_path
9
10
  # @param [RuboCop::Config] rubocop_config
10
11
  # @param [String] source
11
- def initialize(file_path:, rubocop_config:, source:)
12
+ def initialize(auto_correct:, file_path:, rubocop_config:, source:)
13
+ @auto_correct = auto_correct
12
14
  @file_path = file_path
13
15
  @rubocop_config = rubocop_config
14
16
  @source = source
@@ -37,7 +39,7 @@ module Slimcop
37
39
  ::RuboCop::Cop::Team.new(
38
40
  ::RuboCop::Cop::Registry.new(::RuboCop::Cop::Cop.all),
39
41
  @rubocop_config,
40
- auto_correct: true,
42
+ auto_correct: @auto_correct,
41
43
  display_cop_names: true,
42
44
  extra_details: true,
43
45
  stdin: ''
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'parser'
3
4
  require 'rubocop/cop/legacy/corrector'
4
5
 
5
6
  module Slimcop
6
7
  # Apply auto-corrections to Slim file.
7
8
  class SlimCorrector
8
9
  # @param [String] file_path
9
- # @param [Array<Hash>] offenses
10
+ # @param [Array<Slimcop::Offense>] offenses
10
11
  # @param [String] source
11
12
  def initialize(file_path:, offenses:, source:)
12
13
  @file_path = file_path
@@ -25,7 +26,7 @@ module Slimcop
25
26
  def corrections
26
27
  @offenses.map do |offense|
27
28
  lambda do |corrector|
28
- corrector.import!(offense[:rubocop_offense].corrector, offset: offense[:offset])
29
+ corrector.import!(offense.corrector, offset: offense.offset)
29
30
  end
30
31
  end
31
32
  end
@@ -3,27 +3,31 @@
3
3
  module Slimcop
4
4
  # Collect RuboCop offenses from Slim code.
5
5
  class SlimOffenseCollector
6
+ # @param [Boolean] auto_correct
6
7
  # @param [String] file_path Slim file path
7
8
  # @param [RuboCop::Config] rubocop_config
8
9
  # @param [String] source Slim code
9
- def initialize(file_path:, rubocop_config:, source:)
10
+ def initialize(auto_correct:, file_path:, rubocop_config:, source:)
11
+ @auto_correct = auto_correct
10
12
  @file_path = file_path
11
13
  @rubocop_config = rubocop_config
12
14
  @source = source
13
15
  end
14
16
 
15
- # @return [Array<Hash>]
17
+ # @return [Array<Slimcop::Offense>]
16
18
  def call
17
19
  snippets.flat_map do |snippet|
18
20
  RubyOffenseCollector.new(
21
+ auto_correct: @auto_correct,
19
22
  file_path: @file_path,
20
23
  rubocop_config: @rubocop_config,
21
24
  source: snippet[:code]
22
25
  ).call.map do |rubocop_offense|
23
- {
26
+ Offense.new(
24
27
  offset: snippet[:begin_],
25
- rubocop_offense: rubocop_offense
26
- }
28
+ rubocop_offense: rubocop_offense,
29
+ source: @source
30
+ )
27
31
  end
28
32
  end
29
33
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Slimcop
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/slimcop.rb CHANGED
@@ -4,9 +4,11 @@ require_relative 'slimcop/version'
4
4
 
5
5
  module Slimcop
6
6
  autoload :Cli, 'slimcop/cli'
7
+ autoload :Configuration, 'slimcop/configuration'
8
+ autoload :Formatter, 'slimcop/formatter'
9
+ autoload :Offense, 'slimcop/offense'
7
10
  autoload :RubyExtractor, 'slimcop/ruby_extractor'
8
11
  autoload :RubyOffenseCollector, 'slimcop/ruby_offense_collector'
9
- autoload :Runner, 'slimcop/runner'
10
12
  autoload :SlimCorrector, 'slimcop/slim_corrector'
11
13
  autoload :SlimOffenseCollector, 'slimcop/slim_offense_collector'
12
14
  end
data/slimcop.gemspec CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
31
31
  'rubygems_mfa_required' => 'true'
32
32
  }
33
33
 
34
+ spec.add_dependency 'rainbow'
34
35
  spec.add_dependency 'rubocop', '>= 0.87'
35
36
  spec.add_dependency 'slimi', '>= 0.1.1'
36
37
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slimcop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-20 00:00:00.000000000 Z
11
+ date: 2021-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rainbow
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rubocop
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -61,9 +75,11 @@ files:
61
75
  - exe/slimcop
62
76
  - lib/slimcop.rb
63
77
  - lib/slimcop/cli.rb
78
+ - lib/slimcop/configuration.rb
79
+ - lib/slimcop/formatter.rb
80
+ - lib/slimcop/offense.rb
64
81
  - lib/slimcop/ruby_extractor.rb
65
82
  - lib/slimcop/ruby_offense_collector.rb
66
- - lib/slimcop/runner.rb
67
83
  - lib/slimcop/slim_corrector.rb
68
84
  - lib/slimcop/slim_offense_collector.rb
69
85
  - lib/slimcop/version.rb
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rubocop'
4
-
5
- module Slimcop
6
- # Report offenses in Slim file, and apply auto-corrections if required.
7
- class Runner
8
- # @param [String] file_path
9
- def initialize(file_path:)
10
- @file_path = file_path
11
- end
12
-
13
- # @return [Array<Hash>]
14
- def offenses
15
- @offenses ||= SlimOffenseCollector.new(
16
- file_path: @file_path,
17
- rubocop_config: rubocop_config,
18
- source: source
19
- ).call
20
- end
21
-
22
- def auto_correct
23
- SlimCorrector.new(
24
- file_path: @file_path,
25
- offenses: offenses,
26
- source: source
27
- ).call
28
- end
29
-
30
- private
31
-
32
- # @return [RuboCop::Config]
33
- def rubocop_config
34
- config_path = ::File.expand_path('../../default.yml', __dir__)
35
- config = ::RuboCop::ConfigLoader.load_file(config_path)
36
- ::RuboCop::ConfigLoader.merge_with_default(config, config_path)
37
- end
38
-
39
- # @return [Array<Hash>]
40
- def snippets
41
- RubyExtractor.new(source: source).call
42
- end
43
-
44
- # @return [String]
45
- def source
46
- ::File.read(@file_path)
47
- end
48
- end
49
- end