class HamlLint::Linter::RuboCop
Runs RuboCop
on Ruby code contained within HAML templates.
Constants
- SEVERITY_MAP
Maps the ::RuboCop::Cop::Severity levels to our own levels.
Private Class Methods
A single CLI
instance is shared between files to avoid RuboCop
having to repeatedly reload .rubocop.yml.
# File lib/haml_lint/linter/rubocop.rb, line 34 def self.rubocop_cli # The ivar is stored on the class singleton rather than the Linter instance # because it can't be Marshal.dump'd (as used by Parallel.map) @rubocop_cli ||= ::RuboCop::CLI.new end
Public Instance Methods
# File lib/haml_lint/linter/rubocop.rb, line 21 def visit_root(_node) extractor = HamlLint::RubyExtractor.new extracted_source = extractor.extract(document) return if extracted_source.source.empty? find_lints(extracted_source.source, extracted_source.source_map) end
Private Instance Methods
Aggregates RuboCop
offenses and converts them to {HamlLint::Lint}s suitable for reporting.
@param offenses [Array<RuboCop::Cop::Offense>] @param source_map [Hash]
# File lib/haml_lint/linter/rubocop.rb, line 79 def extract_lints_from_offenses(offenses, source_map) dummy_node = Struct.new(:line) offenses.reject { |offense| Array(config['ignored_cops']).include?(offense.cop_name) } .each do |offense| record_lint(dummy_node.new(source_map[offense.line]), offense.message, offense.severity.name) end end
Executes RuboCop
against the given Ruby code and records the offenses as lints.
@param ruby [String] Ruby code @param source_map [Hash] map of Ruby code line numbers to original line
numbers in the template
# File lib/haml_lint/linter/rubocop.rb, line 46 def find_lints(ruby, source_map) filename = if document.file "#{document.file}.rb" else 'ruby_script.rb' end with_ruby_from_stdin(ruby) do extract_lints_from_offenses(lint_file(self.class.rubocop_cli, filename), source_map) end end
Defined so we can stub the results in tests
@param rubocop [RuboCop::CLI] @param file [String] @return [Array<RuboCop::Cop::Offense>]
# File lib/haml_lint/linter/rubocop.rb, line 64 def lint_file(rubocop, file) status = rubocop.run(rubocop_flags << file) unless [::RuboCop::CLI::STATUS_SUCCESS, ::RuboCop::CLI::STATUS_OFFENSES].include?(status) raise HamlLint::Exceptions::ConfigurationError, "RuboCop exited unsuccessfully with status #{status}." \ ' Check the stack trace to see if there was a misconfiguration.' end OffenseCollector.offenses end
Record a lint for reporting back to the user.
@param node [#line] node to extract the line number from @param message [String] error/warning to display to the user @param severity [Symbol] RuboCop
severity level for the offense
# File lib/haml_lint/linter/rubocop.rb, line 94 def record_lint(node, message, severity) @lints << HamlLint::Lint.new(self, @document.file, node.line, message, SEVERITY_MAP.fetch(severity, :warning)) end
Returns flags that will be passed to RuboCop
CLI
.
@return [Array<String>]
# File lib/haml_lint/linter/rubocop.rb, line 102 def rubocop_flags flags = %w[--format HamlLint::OffenseCollector] flags += ['--config', ENV['HAML_LINT_RUBOCOP_CONF']] if ENV['HAML_LINT_RUBOCOP_CONF'] flags += ['--stdin'] flags end
Overrides the global stdin to allow RuboCop
to read Ruby code from it.
@param ruby [String] the Ruby code to write to the overridden stdin @param _block [Block] the block to perform with the overridden stdin @return [void]
# File lib/haml_lint/linter/rubocop.rb, line 114 def with_ruby_from_stdin(ruby, &_block) original_stdin = $stdin stdin = StringIO.new stdin.write(ruby) stdin.rewind $stdin = stdin yield ensure $stdin = original_stdin end