slimcop 0.1.0 → 0.2.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 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