querly 0.15.1 → 1.3.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: 667d28c47f1169482de3e65425249fd1e9ca2593876fe13c8661558b1a588151
4
- data.tar.gz: b0d6025b7fcb82b6933b020d080b28f8ef6e5637b9096fbd9d9e806cf5e1177f
3
+ metadata.gz: c9b153bfa5b7a49deb8a6bbff12517452d2b23498b371a4fcbc154fac2330dd9
4
+ data.tar.gz: 7d08df5b8053cbb9e45d6db6b132e6dcb9171797d5687caf96b3827aed53fae2
5
5
  SHA512:
6
- metadata.gz: cf4b1ce23c783b45e54369cfe5372d4be44bf516db2a9938f898d376706b832d3618d7940ed0f78135a565bd853a8707068390df71a1a8c41fdbc8581fec3e49
7
- data.tar.gz: 66cdc533c9a98c0a9cd9139a1f015225bc1d33ecb44c066c65b46c2ca608c80a37d6b31aec3dd7e1837a7684f7307e93e7acfe0be2c378fd9d994ac7cb213489
6
+ metadata.gz: c2a5371c77896ce523078b014875744f52a248b1e84f04772e0b1ae7eee3cdf876136915c87de876436dc180e9c0b1cbb6ef487a9aaf4dccaf7faad68223546d
7
+ data.tar.gz: 2671df7da016eeb25038a504ee5c7e203e6079ead0adcf2cdfeb25c02c3a3157ee5a05347f9cdd33e25289d12b28de5a38a15fb595bb258e49accf5c4d818b3d
@@ -0,0 +1,15 @@
1
+ name: RuboCop
2
+
3
+ on: pull_request
4
+
5
+ jobs:
6
+ rubocop:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - uses: ruby/setup-ruby@v1
11
+ with:
12
+ ruby-version: "3.0"
13
+ - run: gem install rubocop rubocop-rubycw
14
+ - name: Run RuboCop
15
+ run: rubocop --format github
@@ -0,0 +1,22 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request: {}
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby: ["2.7", "3.0", head]
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ bundler-cache: true
21
+ - run: bin/setup
22
+ - run: bundle exec rake build test
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ require:
2
+ - rubocop-rubycw
3
+
4
+ AllCops:
5
+ DisabledByDefault: true
6
+ Exclude:
7
+ - test/data/**/*.rb
8
+
9
+ Rubycw/Rubycw:
10
+ Enabled: true
data/CHANGELOG.md CHANGED
@@ -2,6 +2,34 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.3.0 (2021-07-05)
6
+
7
+ * Require Ruby 2.7 or 3.0 by @yubiquitous ([#88](https://github.com/soutaro/querly/pull/88))
8
+ * Use 3.0 compatible parser by @yubiquitous ([#88](https://github.com/soutaro/querly/pull/88))
9
+
10
+ ## 1.2.0 (2020-12-15)
11
+
12
+ * Relax Thor version requirements by @y-yagi ([#85](https://github.com/soutaro/querly/pull/85))
13
+ * Fix ERB comment preprocessing by @mallowlabs ([#84](https://github.com/soutaro/querly/pull/84))
14
+ * Better error message for Ruby code syntax error by @ybiquitous ([#83](https://github.com/soutaro/querly/pull/83))
15
+
16
+ ## 1.1.0 (2020-05-17)
17
+
18
+ * Fix invalid bytes sequence in UTF-8 error by @mallowlabs [#75](https://github.com/soutaro/querly/pull/75)
19
+ * Detect safe navigation operator as a method call by @pocke [#71](https://github.com/soutaro/querly/pull/71)
20
+
21
+ ## 1.0.0 (2019-7-19)
22
+
23
+ * Add `--config` option for `find` and `console` [#67](https://github.com/soutaro/querly/pull/67)
24
+ * Improve preprocessor performance by processing concurrently [#68](https://github.com/soutaro/querly/pull/68)
25
+
26
+ ## 0.16.0 (2019-04-23)
27
+
28
+ * Support string literal pattern (@pocke) [#64](https://github.com/soutaro/querly/pull/64)
29
+ * Allow underscore method name pattern (@pocke) [#63](https://github.com/soutaro/querly/pull/63)
30
+ * Add erb support (@hanachin) [#61](https://github.com/soutaro/querly/pull/61)
31
+ * Add `exit` command on console (@wata727) [#59](https://github.com/soutaro/querly/pull/59)
32
+
5
33
  ## 0.15.1 (2019-03-12)
6
34
 
7
35
  * Relax parser version requirement
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  ![Querly logo](https://github.com/soutaro/querly/blob/master/logo/Querly%20horizontal.png)
2
+
2
3
  # Querly - Pattern Based Checking Tool for Ruby
3
4
 
4
- [![Build Status](https://travis-ci.org/soutaro/querly.svg?branch=master)](https://travis-ci.org/soutaro/querly)
5
+ ![Ruby](https://github.com/soutaro/querly/workflows/Ruby/badge.svg)
5
6
 
6
7
  Querly is a query language and tool to find out method calls from Ruby programs.
7
8
  Define rules to check your program with patterns to find out *bad* pieces.
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ task :default => :test
11
11
  task :build => :racc
12
12
  task :test => :racc
13
13
 
14
- rule /\.rb/ => ".y" do |t|
14
+ rule %r/\.rb/ => ".y" do |t|
15
15
  sh "racc", "-v", "-o", "#{t.name}", "#{t.source}"
16
16
  end
17
17
 
data/bin/setup CHANGED
@@ -4,5 +4,4 @@ IFS=$'\n\t'
4
4
  set -vx
5
5
 
6
6
  bundle install
7
-
8
- # Do any other automated setup that you need to do here
7
+ bundle exec rake racc
data/lib/querly.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  require 'pathname'
2
2
  require "yaml"
3
3
  require "rainbow"
4
- require "parser/ruby25"
4
+ require "parser/ruby30"
5
5
  require "set"
6
6
  require "open3"
7
7
  require "active_support/inflector"
8
+ require "parallel"
8
9
 
9
10
  require "querly/version"
10
11
  require 'querly/analyzer'
data/lib/querly/cli.rb CHANGED
@@ -12,6 +12,7 @@ module Querly
12
12
  option :root
13
13
  option :format, default: "text", type: :string, enum: %w(text json)
14
14
  option :rule, type: :string
15
+ option :threads, default: Parallel.processor_count, type: :numeric
15
16
  def check(*paths)
16
17
  require 'querly/cli/formatter'
17
18
 
@@ -23,6 +24,8 @@ module Querly
23
24
  end
24
25
  formatter.start
25
26
 
27
+ threads = Integer(options[:threads])
28
+
26
29
  begin
27
30
  unless config_path.file?
28
31
  STDERR.puts <<-Message
@@ -32,20 +35,15 @@ Specify configuration file by --config option.
32
35
  exit 1
33
36
  end
34
37
 
35
- root_option = options[:root]
36
- root_path = root_option ? Pathname(root_option).realpath : config_path.parent.realpath
37
-
38
- config = begin
39
- yaml = YAML.load(config_path.read)
40
- Config.load(yaml, config_path: config_path, root_dir: root_path, stderr: STDERR)
38
+ begin
39
+ config = config(root_option: options[:root])
41
40
  rescue => exn
42
41
  formatter.config_error config_path, exn
43
- exit 1
44
42
  end
45
43
 
46
44
  analyzer = Analyzer.new(config: config, rule: options[:rule])
47
45
 
48
- ScriptEnumerator.new(paths: paths.empty? ? [Pathname.pwd] : paths.map {|path| Pathname(path) }, config: config).each do |path, script|
46
+ ScriptEnumerator.new(paths: paths.empty? ? [Pathname.pwd] : paths.map {|path| Pathname(path) }, config: config, threads: threads).each do |path, script|
49
47
  case script
50
48
  when Script
51
49
  analyzer.scripts << script
@@ -67,6 +65,8 @@ Specify configuration file by --config option.
67
65
  end
68
66
 
69
67
  desc "console [paths]", "Start console for given paths"
68
+ option :config, default: "querly.yml"
69
+ option :threads, default: Parallel.processor_count, type: :numeric
70
70
  def console(*paths)
71
71
  require 'querly/cli/console'
72
72
  home_path = if (path = ENV["QUERLY_HOME"])
@@ -75,21 +75,32 @@ Specify configuration file by --config option.
75
75
  Pathname(Dir.home) + ".querly"
76
76
  end
77
77
  home_path.mkdir unless home_path.exist?
78
+ config = config_path.file? ? config(root_option: nil) : nil
79
+ threads = Integer(options[:threads])
78
80
 
79
81
  Console.new(
80
82
  paths: paths.empty? ? [Pathname.pwd] : paths.map {|path| Pathname(path) },
81
83
  history_path: home_path + "history",
82
- history_size: ENV["QUERLY_HISTORY_SIZE"]&.to_i || 1_000_000
84
+ history_size: ENV["QUERLY_HISTORY_SIZE"]&.to_i || 1_000_000,
85
+ config: config,
86
+ threads: threads
83
87
  ).start
84
88
  end
85
89
 
86
90
  desc "find pattern [paths]", "Find for the pattern in given paths"
91
+ option :config, default: "querly.yml"
92
+ option :threads, default: Parallel.processor_count, type: :numeric
87
93
  def find(pattern, *paths)
88
94
  require 'querly/cli/find'
89
95
 
96
+ config = config_path.file? ? config(root_option: nil) : nil
97
+ threads = Integer(options[:threads])
98
+
90
99
  Find.new(
91
100
  pattern: pattern,
92
101
  paths: paths.empty? ? [Pathname.pwd] : paths.map {|path| Pathname(path) },
102
+ config: config,
103
+ threads: threads
93
104
  ).start
94
105
  end
95
106
 
@@ -125,6 +136,13 @@ Specify configuration file by --config option.
125
136
 
126
137
  private
127
138
 
139
+ def config(root_option:)
140
+ root_path = root_option ? Pathname(root_option).realpath : config_path.parent.realpath
141
+
142
+ yaml = YAML.load(config_path.read)
143
+ Config.load(yaml, config_path: config_path, root_dir: root_path, stderr: STDERR)
144
+ end
145
+
128
146
  def config_path
129
147
  [Pathname(options[:config]),
130
148
  Pathname("querly.yaml")].compact.find(&:file?) || Pathname(options[:config])
@@ -8,13 +8,17 @@ module Querly
8
8
  attr_reader :paths
9
9
  attr_reader :history_path
10
10
  attr_reader :history_size
11
+ attr_reader :config
11
12
  attr_reader :history
13
+ attr_reader :threads
12
14
 
13
- def initialize(paths:, history_path:, history_size:)
15
+ def initialize(paths:, history_path:, history_size:, config: nil, threads:)
14
16
  @paths = paths
15
17
  @history_path = history_path
16
18
  @history_size = history_size
19
+ @config = config
17
20
  @history = []
21
+ @threads = threads
18
22
  end
19
23
 
20
24
  def start
@@ -42,9 +46,9 @@ Querly #{VERSION}, interactive console
42
46
  def analyzer
43
47
  return @analyzer if @analyzer
44
48
 
45
- @analyzer = Analyzer.new(config: nil, rule: nil)
49
+ @analyzer = Analyzer.new(config: config, rule: nil)
46
50
 
47
- ScriptEnumerator.new(paths: paths, config: nil).each do |path, script|
51
+ ScriptEnumerator.new(paths: paths, config: config, threads: threads).each do |path, script|
48
52
  case script
49
53
  when Script
50
54
  @analyzer.scripts << script
@@ -60,7 +64,7 @@ Querly #{VERSION}, interactive console
60
64
  def start_loop
61
65
  while line = Readline.readline("> ", true)
62
66
  case line
63
- when "quit"
67
+ when "quit", "exit"
64
68
  exit
65
69
  when "reload!"
66
70
  STDOUT.print "reloading..."
@@ -7,10 +7,14 @@ module Querly
7
7
 
8
8
  attr_reader :pattern_str
9
9
  attr_reader :paths
10
+ attr_reader :config
11
+ attr_reader :threads
10
12
 
11
- def initialize(pattern:, paths:)
13
+ def initialize(pattern:, paths:, config: nil, threads:)
12
14
  @pattern_str = pattern
13
15
  @paths = paths
16
+ @config = config
17
+ @threads = threads
14
18
  end
15
19
 
16
20
  def start
@@ -36,7 +40,7 @@ module Querly
36
40
  puts "#{count} results"
37
41
  rescue => exn
38
42
  STDOUT.puts Rainbow("Error: #{exn}").red
39
- STDTOU.puts "pattern: #{pattern_str}"
43
+ STDOUT.puts "pattern: #{pattern_str}"
40
44
  STDOUT.puts "Backtrace:"
41
45
  STDOUT.puts format_backtrace(exn.backtrace)
42
46
  end
@@ -48,9 +52,9 @@ module Querly
48
52
  def analyzer
49
53
  return @analyzer if @analyzer
50
54
 
51
- @analyzer = Analyzer.new(config: nil, rule: nil)
55
+ @analyzer = Analyzer.new(config: config, rule: nil)
52
56
 
53
- ScriptEnumerator.new(paths: paths, config: nil).each do |path, script|
57
+ ScriptEnumerator.new(paths: paths, config: config, threads: threads).each do |path, script|
54
58
  case script
55
59
  when Script
56
60
  @analyzer.scripts << script
@@ -46,7 +46,12 @@ module Querly
46
46
 
47
47
  def script_error(path, error)
48
48
  STDERR.puts Rainbow("Failed to load script: #{path}").red
49
- STDERR.puts error.inspect
49
+
50
+ if error.is_a? Parser::SyntaxError
51
+ STDERR.puts error.diagnostic.render
52
+ else
53
+ STDERR.puts error.inspect
54
+ end
50
55
  end
51
56
 
52
57
  def issue_found(script, rule, pair)
@@ -140,7 +140,7 @@ module Querly
140
140
 
141
141
  found = false
142
142
 
143
- node = Parser::Ruby25.parse(example)
143
+ node = Parser::Ruby30.parse(example)
144
144
  NodePair.new(node: node).each_subpair do |pair|
145
145
  if analyzer.test_pair(pair, pattern)
146
146
  found = true
@@ -25,7 +25,7 @@ module Querly
25
25
  yield self
26
26
 
27
27
  children.each do |child|
28
- child.each_subpair &block
28
+ child.each_subpair(&block)
29
29
  end
30
30
  else
31
31
  enum_for :each_subpair
@@ -118,7 +118,7 @@ module Querly
118
118
 
119
119
  when :str
120
120
  return false unless type == :string
121
- test_value(node.children.first)
121
+ test_value(node.children.first.scrub)
122
122
 
123
123
  when :sym
124
124
  return false unless type == :symbol
@@ -147,7 +147,8 @@ module Querly
147
147
 
148
148
  def =~(pair)
149
149
  # Skip send node with block
150
- if pair.node.type == :send && pair.parent
150
+ type = pair.node.type
151
+ if (type == :send || type == :csend) && pair.parent
151
152
  if pair.parent.node.type == :block
152
153
  if pair.parent.node.children.first.equal? pair.node
153
154
  return false
@@ -176,7 +177,7 @@ module Querly
176
177
  node = node.children.first if node&.type == :block
177
178
 
178
179
  case node&.type
179
- when :send
180
+ when :send, :csend
180
181
  return false unless test_name(node)
181
182
  return false unless test_receiver(node.children[0])
182
183
  return false unless test_args(node.children.drop(2), args)
@@ -290,7 +291,8 @@ module Querly
290
291
  if receiver.test_node(node)
291
292
  true
292
293
  else
293
- node&.type == :send && test_node(node.children[0])
294
+ type = node&.type
295
+ (type == :send || type == :csend) && test_node(node.children[0])
294
296
  end
295
297
  end
296
298
  end
@@ -315,7 +317,7 @@ module Querly
315
317
  # We don't want lvar without method call
316
318
  # Skips when the node is not receiver of :send
317
319
  parent_node = pair.parent&.node
318
- if parent_node && parent_node.type == :send && parent_node.children.first.equal?(node)
320
+ if parent_node && (parent_node.type == :send || parent_node.type == :csend) && parent_node.children.first.equal?(node)
319
321
  test_node(node)
320
322
  end
321
323
  else
@@ -325,7 +327,7 @@ module Querly
325
327
 
326
328
  def test_node(node)
327
329
  case node&.type
328
- when :send
330
+ when :send, :csend
329
331
  node.children[1] == name
330
332
  when :lvar
331
333
  node.children.first == name
@@ -72,7 +72,7 @@ keyword: LIDENT | UIDENT
72
72
  constant: UIDENT { result = [val[0]] }
73
73
  | UIDENT COLONCOLON constant { result = [val[0]] + val[2] }
74
74
 
75
- send: LIDENT block { result = val[1] != nil ? Expr::Send.new(receiver: nil, name: val[0], args: Argument::AnySeq.new, block: val[1]) : Expr::Vcall.new(name: val[0]) }
75
+ send: LIDENT block { result = val[1] != nil ? Expr::Send.new(receiver: nil, name: val[0], block: val[1]) : Expr::Vcall.new(name: val[0]) }
76
76
  | UIDENT block { result = Expr::Send.new(receiver: nil, name: val[0], block: val[1]) }
77
77
  | method_name { result = Expr::Send.new(receiver: nil, name: val[0], block: nil) }
78
78
  | method_name_or_ident LPAREN args RPAREN block { result = Expr::Send.new(receiver: nil,
@@ -83,18 +83,15 @@ send: LIDENT block { result = val[1] != nil ? Expr::Send.new(receiver: nil, name
83
83
  name: val[1],
84
84
  args: Argument::AnySeq.new,
85
85
  block: val[2]) }
86
- | receiver method_name_or_ident block { result = Expr::Send.new(receiver: val[0],
87
- name: val[1],
88
- args: Argument::AnySeq.new,
89
- block: val[2]) }
90
- | receiver method_name_or_ident LPAREN args RPAREN block { result = Expr::Send.new(receiver: val[0],
91
- name: val[1],
92
- args: val[3],
93
- block: val[5]) }
94
86
  | receiver method_name_or_ident LPAREN args RPAREN block { result = Expr::Send.new(receiver: val[0],
95
87
  name: val[1],
96
88
  args: val[3],
97
89
  block: val[5]) }
90
+ | receiver UNDERBAR block { result = Expr::Send.new(receiver: val[0], name: /.+/, block: val[2]) }
91
+ | receiver UNDERBAR LPAREN args RPAREN block { result = Expr::Send.new(receiver: val[0],
92
+ name: /.+/,
93
+ args: val[3],
94
+ block: val[5]) }
98
95
 
99
96
  receiver: expr DOT { result = val[0] }
100
97
  | expr DOTDOTDOT { result = Expr::ReceiverContext.new(receiver: val[0]) }
@@ -136,6 +133,8 @@ def next_token
136
133
  [:NIL, false]
137
134
  when input.scan(/:string:/)
138
135
  [:STRING, nil]
136
+ when input.scan(/"([^"]+)"/)
137
+ [:STRING, input[1]]
139
138
  when input.scan(/:dstr:/)
140
139
  [:DSTR, nil]
141
140
  when input.scan(/:int:/)
data/lib/querly/pp/cli.rb CHANGED
@@ -42,7 +42,7 @@ module Querly
42
42
  end
43
43
 
44
44
  def run
45
- available_commands = [:haml]
45
+ available_commands = [:haml, :erb]
46
46
 
47
47
  if available_commands.include?(command)
48
48
  send :"run_#{command}"
@@ -70,6 +70,25 @@ module Querly
70
70
  stdout.print compiler.precompiled
71
71
  end
72
72
  end
73
+
74
+ def run_erb
75
+ require 'better_html'
76
+ require 'better_html/parser'
77
+ load_libs
78
+ source = stdin.read
79
+ source_buffer = Parser::Source::Buffer.new('(erb)')
80
+ source_buffer.source = source
81
+ parser = BetterHtml::Parser.new(source_buffer, template_language: :html)
82
+
83
+ new_source = source.gsub(/./, ' ')
84
+ parser.ast.descendants(:erb).each do |erb_node|
85
+ indicator_node, _, code_node, = *erb_node
86
+ next if indicator_node&.loc&.source == '#'
87
+ new_source[code_node.loc.range] = code_node.loc.source
88
+ new_source[code_node.loc.range.end] = ';'
89
+ end
90
+ stdout.puts new_source
91
+ end
73
92
  end
74
93
  end
75
94
  end
data/lib/querly/script.rb CHANGED
@@ -3,6 +3,16 @@ module Querly
3
3
  attr_reader :path
4
4
  attr_reader :node
5
5
 
6
+ def self.load(path:, source:)
7
+ parser = Parser::Ruby30.new(Builder.new).tap do |parser|
8
+ parser.diagnostics.all_errors_are_fatal = true
9
+ parser.diagnostics.ignore_warnings = true
10
+ end
11
+ buffer = Parser::Source::Buffer.new(path.to_s, 1)
12
+ buffer.source = source
13
+ self.new(path: path, node: parser.parse(buffer))
14
+ end
15
+
6
16
  def initialize(path:, node:)
7
17
  @path = path
8
18
  @node = node
@@ -11,5 +21,15 @@ module Querly
11
21
  def root_pair
12
22
  NodePair.new(node: node)
13
23
  end
24
+
25
+ class Builder < Parser::Builders::Default
26
+ def string_value(token)
27
+ value(token)
28
+ end
29
+
30
+ def emit_lambda
31
+ true
32
+ end
33
+ end
14
34
  end
15
35
  end
@@ -2,23 +2,36 @@ module Querly
2
2
  class ScriptEnumerator
3
3
  attr_reader :paths
4
4
  attr_reader :config
5
+ attr_reader :threads
5
6
 
6
- def initialize(paths:, config:)
7
+ def initialize(paths:, config:, threads:)
7
8
  @paths = paths
8
9
  @config = config
10
+ @threads = threads
9
11
  end
10
12
 
13
+ # Yields `Script` object concurrently, in different threads.
11
14
  def each(&block)
15
+ if block_given?
16
+ Parallel.each(each_path, in_threads: threads) do |path|
17
+ load_script_from_path path, &block
18
+ end
19
+ else
20
+ self.enum_for :each
21
+ end
22
+ end
23
+
24
+ def each_path(&block)
12
25
  if block_given?
13
26
  paths.each do |path|
14
27
  if path.directory?
15
28
  enumerate_files_in_dir(path, &block)
16
29
  else
17
- load_script_from_path path, &block
30
+ yield path
18
31
  end
19
32
  end
20
33
  else
21
- self.enum_for :each
34
+ enum_for :each_path
22
35
  end
23
36
  end
24
37
 
@@ -45,9 +58,7 @@ module Querly
45
58
  path.read
46
59
  end
47
60
 
48
- buffer = Parser::Source::Buffer.new(path.to_s, 1)
49
- buffer.source = source
50
- script = Script.new(path: path, node: parser.parse(buffer))
61
+ script = Script.load(path: path, source: source)
51
62
  rescue StandardError, LoadError, Preprocessor::Error => exn
52
63
  script = exn
53
64
  end
@@ -55,13 +66,6 @@ module Querly
55
66
  yield(path, script)
56
67
  end
57
68
 
58
- def parser
59
- Parser::Ruby25.new(Builder.new).tap do |parser|
60
- parser.diagnostics.all_errors_are_fatal = true
61
- parser.diagnostics.ignore_warnings = true
62
- end
63
- end
64
-
65
69
  def preprocessors
66
70
  config&.preprocessors || {}
67
71
  end
@@ -98,17 +102,7 @@ module Querly
98
102
  preprocessors.key?(path.extname)
99
103
  end
100
104
 
101
- load_script_from_path(path, &block) if should_load_file
102
- end
103
- end
104
-
105
- class Builder < Parser::Builders::Default
106
- def string_value(token)
107
- value(token)
108
- end
109
-
110
- def emit_lambda
111
- true
105
+ yield path if should_load_file
112
106
  end
113
107
  end
114
108
  end
@@ -1,3 +1,3 @@
1
1
  module Querly
2
- VERSION = "0.15.1"
2
+ VERSION = "1.3.0"
3
3
  end
data/manual/patterns.md CHANGED
@@ -71,6 +71,8 @@ bar.foo.baz # foo...bar...baz does not match
71
71
  * `1.23` (float)
72
72
  * `:foobar` (symbol)
73
73
  * `:symbol:` (any symbol literal)
74
+ * `"foobar"` (string)
75
+ * NOTE: It only supports double quotation.
74
76
  * `:string:` (any string literal)
75
77
  * `:dstr:` (any dstr `"hi #{name}"`)
76
78
  * `true`, `false` (true and false)
@@ -145,9 +147,9 @@ end
145
147
 
146
148
  # Interpolation Syntax
147
149
 
148
- If you want to describe a pattern that can not be described with adove syntax, you can use interpolation as follows:
150
+ If you want to describe a pattern that can not be described with above syntax, you can use interpolation as follows:
149
151
 
150
- ```rb
152
+ ```yaml
151
153
  id: find_by_abc_and_def
152
154
  pattern:
153
155
  subject: "'finder(...)"
@@ -164,6 +166,16 @@ It matches with `find_by_email_and_name(...)`.
164
166
  - If value of meta var is a string `foo`, it matches send nodes with exactly same method name
165
167
  - If value of meta var is a regexp `/foo/`, it matches send nodes with method name which `=~` the regexp
166
168
 
169
+ You can also use `as` syntax with `:symbol:` and so on.
170
+
171
+ ```yaml
172
+ id: migration_references
173
+ pattern:
174
+ subject: "t.integer(:symbol: as 'column, ...)"
175
+ where:
176
+ column: '/.+_id/'
177
+ ```
178
+
167
179
  # Difference from Ruby
168
180
 
169
181
  * Method call parenthesis cannot be omitted (if omitted, it means *any arguments*)
data/querly.gemspec CHANGED
@@ -22,14 +22,20 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
+ spec.required_ruby_version = ">= 2.7"
26
+
25
27
  spec.add_development_dependency "bundler", ">= 1.12"
26
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rake", "~> 13.0"
27
29
  spec.add_development_dependency "minitest", "~> 5.0"
28
- spec.add_development_dependency "racc", "= 1.4.14"
30
+ spec.add_development_dependency "racc", ">= 1.4.14"
29
31
  spec.add_development_dependency "unification_assertion", "0.0.1"
32
+ spec.add_development_dependency "better_html", "~> 1.0.13"
33
+ spec.add_development_dependency "slim", "~> 4.0.1"
34
+ spec.add_development_dependency "haml", "~> 5.0.4"
30
35
 
31
- spec.add_dependency 'thor', ">= 0.19.0", "< 0.21.0"
32
- spec.add_dependency "parser", ">= 2.5.0"
36
+ spec.add_dependency 'thor', ">= 0.19.0"
37
+ spec.add_dependency "parser", ">= 3.0"
33
38
  spec.add_dependency "rainbow", ">= 2.1"
34
39
  spec.add_dependency "activesupport", ">= 5.0"
40
+ spec.add_dependency "parallel", "~>1.17"
35
41
  end
data/sample.yaml CHANGED
@@ -146,6 +146,8 @@ rules:
146
146
 
147
147
  preprocessor:
148
148
  .slim: slimrb --compile
149
+ .haml: querly-pp haml
150
+ .erb: querly-pp erb
149
151
 
150
152
  import:
151
153
  - load: querly/rules/*.yml
data/template.yml CHANGED
@@ -58,7 +58,9 @@ rules:
58
58
  assert_empty some.count
59
59
 
60
60
  preprocessor:
61
- .slim: slimrb --compile
61
+ # .slim: slimrb --compile # Install `slim` gem for slim support
62
+ # .erb: querly-pp erb # Install `better_erb` gem for erb support
63
+ # .haml: querly-pp haml # Install `haml` gem for haml support
62
64
 
63
65
  check:
64
66
  - path: /
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: querly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-12 00:00:00.000000000 Z
11
+ date: 2021-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -56,14 +56,14 @@ dependencies:
56
56
  name: racc
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: 1.4.14
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: 1.4.14
69
69
  - !ruby/object:Gem::Dependency
@@ -80,6 +80,48 @@ dependencies:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.0.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: better_html
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.0.13
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.0.13
97
+ - !ruby/object:Gem::Dependency
98
+ name: slim
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 4.0.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 4.0.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: haml
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 5.0.4
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 5.0.4
83
125
  - !ruby/object:Gem::Dependency
84
126
  name: thor
85
127
  requirement: !ruby/object:Gem::Requirement
@@ -87,9 +129,6 @@ dependencies:
87
129
  - - ">="
88
130
  - !ruby/object:Gem::Version
89
131
  version: 0.19.0
90
- - - "<"
91
- - !ruby/object:Gem::Version
92
- version: 0.21.0
93
132
  type: :runtime
94
133
  prerelease: false
95
134
  version_requirements: !ruby/object:Gem::Requirement
@@ -97,23 +136,20 @@ dependencies:
97
136
  - - ">="
98
137
  - !ruby/object:Gem::Version
99
138
  version: 0.19.0
100
- - - "<"
101
- - !ruby/object:Gem::Version
102
- version: 0.21.0
103
139
  - !ruby/object:Gem::Dependency
104
140
  name: parser
105
141
  requirement: !ruby/object:Gem::Requirement
106
142
  requirements:
107
143
  - - ">="
108
144
  - !ruby/object:Gem::Version
109
- version: 2.5.0
145
+ version: '3.0'
110
146
  type: :runtime
111
147
  prerelease: false
112
148
  version_requirements: !ruby/object:Gem::Requirement
113
149
  requirements:
114
150
  - - ">="
115
151
  - !ruby/object:Gem::Version
116
- version: 2.5.0
152
+ version: '3.0'
117
153
  - !ruby/object:Gem::Dependency
118
154
  name: rainbow
119
155
  requirement: !ruby/object:Gem::Requirement
@@ -142,6 +178,20 @@ dependencies:
142
178
  - - ">="
143
179
  - !ruby/object:Gem::Version
144
180
  version: '5.0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: parallel
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '1.17'
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '1.17'
145
195
  description: Querly is a query language and tool to find out method calls from Ruby
146
196
  programs. Define rules to check your program with patterns to find out *bad* pieces.
147
197
  Querly finds out matching pieces from your program.
@@ -153,8 +203,10 @@ executables:
153
203
  extensions: []
154
204
  extra_rdoc_files: []
155
205
  files:
206
+ - ".github/workflows/rubocop.yml"
207
+ - ".github/workflows/ruby.yml"
156
208
  - ".gitignore"
157
- - ".travis.yml"
209
+ - ".rubocop.yml"
158
210
  - CHANGELOG.md
159
211
  - Gemfile
160
212
  - LICENSE
@@ -212,15 +264,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
212
264
  requirements:
213
265
  - - ">="
214
266
  - !ruby/object:Gem::Version
215
- version: '0'
267
+ version: '2.7'
216
268
  required_rubygems_version: !ruby/object:Gem::Requirement
217
269
  requirements:
218
270
  - - ">="
219
271
  - !ruby/object:Gem::Version
220
272
  version: '0'
221
273
  requirements: []
222
- rubyforge_project:
223
- rubygems_version: 2.7.6
274
+ rubygems_version: 3.1.2
224
275
  signing_key:
225
276
  specification_version: 4
226
277
  summary: Pattern Based Checking Tool for Ruby
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.4.5
5
- - 2.5.3
6
- - 2.6.0
7
- before_install: gem install bundler
8
- script:
9
- - bundle exec rake test
10
- - bundle exec querly test --config=sample.yaml