debian-mirror-gitlab/scripts/rubocop-parse

147 lines
3 KiB
Text
Raw Permalink Normal View History

2022-10-11 01:57:18 +05:30
#!/usr/bin/env ruby
# frozen_string_literal: true
# Emit AST from parsed Ruby code by RuboCop.
#
# This is an alternative to `ruby-parser` shipped with `parser` gem.
#
# Usage:
# rubocop-parse -e 'puts "hello"'
# (send nil :puts
# (str "hello"))
#
# rubocop-parse -e 'puts "hello"' -v 3.0
# (send nil :puts
# (str "hello"))
#
# rubocop-parse app/models/project.rb
# (begin
# (send nil :require
# (str "carrierwave/orm/activerecord"))
# (class
# (const nil :Project)
# (const nil :ApplicationRecord)
# (begin
# (send nil :include
# ...
require_relative '../config/bundler_setup'
require 'rubocop'
require 'optparse'
2022-11-25 23:54:43 +05:30
module Helper
extend self
class << self
attr_writer :ruby_version
end
def ast(source, file: '', version: nil)
version ||= ruby_version
2023-01-13 00:05:48 +05:30
ast = RuboCop::AST::ProcessedSource.new(source, version).ast
return ast if ast
warn "Syntax error in `#{source}`."
end
def pattern(string)
RuboCop::NodePattern.new(string)
end
def help!
puts <<~HELP
Use `ast(source_string, version: nil)` method to parse code and return its AST.
Use `pattern(string)` to compile RuboCop's node patterns.
See https://docs.rubocop.org/rubocop-ast/node_pattern.html.
Examples:
node = ast('puts :hello')
pat = pattern('`(sym :hello)')
pat.match(node) # => true
HELP
nil
2022-11-25 23:54:43 +05:30
end
def ruby_version
@ruby_version ||= rubocop_target_ruby_version
end
def rubocop_target_ruby_version
@rubocop_target_ruby_version ||= RuboCop::ConfigStore.new.for_file('.').target_ruby_version
end
2022-10-11 01:57:18 +05:30
end
2022-11-25 23:54:43 +05:30
def start_irb
require 'irb'
include Helper # rubocop:disable Style/MixinUsage
2023-01-13 00:05:48 +05:30
puts <<~BANNER
Ruby version: #{ruby_version}
Type `help!` for instructions and examples.
BANNER
2022-11-25 23:54:43 +05:30
IRB.start
end
options = Struct.new(:eval, :interactive, :print_help, keyword_init: true).new
2022-10-11 01:57:18 +05:30
parser = OptionParser.new do |opts|
2022-11-25 23:54:43 +05:30
opts.banner = "Usage: #{$PROGRAM_NAME} [-e code] [FILE...]"
2022-10-11 01:57:18 +05:30
opts.on('-e FRAGMENT', '--eval FRAGMENT', 'Process a fragment of Ruby code') do |code|
options.eval = code
end
2022-11-25 23:54:43 +05:30
opts.on('-i', '--interactive', '') do
options.interactive = true
end
2022-10-11 01:57:18 +05:30
opts.on('-v RUBY_VERSION', '--ruby-version RUBY_VERSION',
'Parse as Ruby would. Defaults to RuboCop TargetRubyVersion setting.') do |ruby_version|
2022-11-25 23:54:43 +05:30
Helper.ruby_version = Float(ruby_version)
2022-10-11 01:57:18 +05:30
end
opts.on('-h', '--help') do
options.print_help = true
end
end
2022-11-25 23:54:43 +05:30
files = parser.parse!
2022-10-11 01:57:18 +05:30
if options.print_help
puts parser
2022-11-25 23:54:43 +05:30
elsif options.interactive
if options.eval || files.any?
puts "Cannot combine `--interactive` with `--eval` or passing files. Aborting..."
puts
2022-10-11 01:57:18 +05:30
2022-11-25 23:54:43 +05:30
puts parser
exit 1
2022-10-11 01:57:18 +05:30
else
2022-11-25 23:54:43 +05:30
start_irb
2022-10-11 01:57:18 +05:30
end
2022-11-25 23:54:43 +05:30
elsif options.eval
2023-01-13 00:05:48 +05:30
puts Helper.ast(options.eval)
2022-11-25 23:54:43 +05:30
elsif files.any?
files.each do |file|
if File.file?(file)
source = File.read(file)
2023-01-13 00:05:48 +05:30
puts Helper.ast(source, file: file)
2022-11-25 23:54:43 +05:30
else
warn "Skipping non-file #{file.inspect}"
end
end
else
puts parser
2022-10-11 01:57:18 +05:30
end