Welcome to mirror list, hosted at ThFree Co, Russian Federation.

rubocop-parse « scripts - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c99d66e99ad6546175a7f98611f4705c085110a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/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'

module Helper
  extend self

  class << self
    attr_writer :ruby_version
  end

  def ast(source, file: '', version: nil)
    version ||= ruby_version

    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
  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
end

def start_irb
  require 'irb'

  include Helper # rubocop:disable Style/MixinUsage

  puts <<~BANNER
    Ruby version: #{ruby_version}

    Type `help!` for instructions and examples.

  BANNER

  IRB.start
end

options = Struct.new(:eval, :interactive, :print_help, keyword_init: true).new

parser = OptionParser.new do |opts|
  opts.banner = "Usage: #{$PROGRAM_NAME} [-e code] [FILE...]"

  opts.on('-e FRAGMENT', '--eval FRAGMENT', 'Process a fragment of Ruby code') do |code|
    options.eval = code
  end

  opts.on('-i', '--interactive', '') do
    options.interactive = true
  end

  opts.on('-v RUBY_VERSION', '--ruby-version RUBY_VERSION',
          'Parse as Ruby would. Defaults to RuboCop TargetRubyVersion setting.') do |ruby_version|
    Helper.ruby_version = Float(ruby_version)
  end

  opts.on('-h', '--help') do
    options.print_help = true
  end
end

files = parser.parse!

if options.print_help
  puts parser
elsif options.interactive
  if options.eval || files.any?
    puts "Cannot combine `--interactive` with `--eval` or passing files. Aborting..."
    puts

    puts parser
    exit 1
  else
    start_irb
  end
elsif options.eval
  puts Helper.ast(options.eval)
elsif files.any?
  files.each do |file|
    if File.file?(file)
      source = File.read(file)
      puts Helper.ast(source, file: file)
    else
      warn "Skipping non-file #{file.inspect}"
    end
  end
else
  puts parser
end