cql_ruby 0.0.2 → 0.0.7

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: 6255a37c5d7ad3bb69be36d10bf4056eb8b40729a5989db72ecdc81e30a2784a
4
- data.tar.gz: e60a47023bf3062f83157f1d414dfc8122c58df9a4c6898f6048ac91727accea
3
+ metadata.gz: 7bd516a07069a73fad1c48a2ca7ae536d7c52a891c882211d2de0b5d9c670fb1
4
+ data.tar.gz: 9ec5696402ffd46da3427c338e18b33cc7d7fecf39df135cee451a29ccee39ae
5
5
  SHA512:
6
- metadata.gz: 773f82e313c1ce9ad9a3c7f24d243d7045d7ad731d508ec082a5b8f3dce7a0d13078a9f21a0930bd535b2d3b530d801ee534eabcfa70ab44eada8af01b6adc65
7
- data.tar.gz: 9dbca8f1684162d99e81a8729cd1544fae6fc32bb7a327e184fa47b44939892a97940dc11e8880bfe99eac7e9d6793a235bfd0e0cae78b3053bc2ad5bf2c286e
6
+ metadata.gz: 9b6dbc5df16b5042e431d6682435e0f993b013c66ab70541a259b66ed487405c71c088b63f554085fb2018bd59bd0e3499931c87dcfc0d2f4bc9c8bfbabeb421
7
+ data.tar.gz: ff722aee7187a9b0a44cbe9ff45182fa13fe97add03a46545f7de26238993abefdb16cb85e4e4302a90cf1f7c39d8071e1d1bcb1213db382df8a6d4f505ac819
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'cql_ruby'
4
+
5
+ def show_help
6
+ puts <<~HELP
7
+
8
+ \tSYNOPSIS
9
+ \t\tcql_ruby options pattern path filters ...
10
+
11
+ \tDESCRIPTION
12
+ \t\tCQL (Code Query Language) is a semantic search tool for your Ruby source code.
13
+
14
+ \tFILTERS
15
+ \t\tParent node type: type:T(,T)* Example: type:def,send,arg
16
+ \t\tNesting under: nest:T(=NAME) Example: nest:def=save_user nest:class=UserManager
17
+
18
+ \tOPTIONS
19
+ \t\t-lN (N is integer) Add N surrounding line before and after.
20
+ \t\t-nc (--no-color) No color on output.
21
+ \t\t-nf (--no-file) No file names.
22
+ \t\t-ns (--no-source) No source code.
23
+ \t\t-nr (--no-recursion) Non-recursive search.
24
+ \t\t-v -vv -vvv Debug output levels.
25
+
26
+ \tEXAMPLES
27
+ \t\tcql_ruby user ./
28
+ \t\tcql_ruby -ns -nr %user_info ./ type:send,arg nest:block nest:class=r/User/i
29
+ HELP
30
+
31
+ exit
32
+ end
33
+
34
+ # @return [Hash{Symbol->Boolean}]
35
+ def extract_options
36
+ options = {
37
+ show_color: true,
38
+ show_file: true,
39
+ show_source: true,
40
+ recursive_search: true,
41
+ surrounding_lines: 0,
42
+ }
43
+
44
+ ARGV.delete_if do |arg|
45
+ if arg[0] == '-'
46
+ if %w[-nc --no-color].include?(arg)
47
+ options[:show_color] = false
48
+ elsif %w[-nf --no-file].include?(arg)
49
+ options[:show_file] = false
50
+ elsif %w[-ns --no-source].include?(arg)
51
+ options[:show_source] = false
52
+ elsif %w[-h --help].include?(arg)
53
+ show_help
54
+ elsif %w[-v -vv -vvv].include?(arg)
55
+ lvl = arg.chars.find_all { |c| c == 'v' }.size
56
+ CqlRuby::Config.debug_level = lvl
57
+ elsif %w[-nr --no-recursive].include?(arg)
58
+ options[:recursive_search] = false
59
+ elsif arg[0..1] == '-l' && arg[2..].to_i > 0
60
+ options[:surrounding_lines] = arg[2..].to_i
61
+ else
62
+ raise "Unknown arg #{arg}"
63
+ end
64
+
65
+ true
66
+ else
67
+ false
68
+ end
69
+ end
70
+
71
+ options
72
+ end
73
+
74
+ # @return [Array]
75
+ def extract_filters
76
+ ARGV.take(ARGV.size)
77
+ end
78
+
79
+ begin
80
+ options = extract_options
81
+ CqlRuby.log "Call options: #{options}" if CqlRuby::Config.debug_level_2?
82
+
83
+ raise unless ARGV.size >= 2
84
+
85
+ pattern = ARGV.shift
86
+ CqlRuby.log "Call pattern: <#{pattern}>" if CqlRuby::Config.debug_level_2?
87
+
88
+ # TODO Make path patterns universal.
89
+ path = ARGV.shift
90
+ CqlRuby.log "Call path: <#{path}>" if CqlRuby::Config.debug_level_2?
91
+
92
+ # Rest must be filters - can sink ARGV now.
93
+ filters = extract_filters
94
+ CqlRuby.log "Call filters: #{filters}" if CqlRuby::Config.debug_level_2?
95
+
96
+ filter_reader = CqlRuby::FilterReader.new(filters)
97
+
98
+ printer = CqlRuby::ConsolePrinter.new
99
+ printer.color_on = options[:show_color]
100
+ printer.file_on = options[:show_file]
101
+ printer.source_on = options[:show_source]
102
+ printer.surrounding_lines = options[:surrounding_lines]
103
+
104
+ collector = CqlRuby::CrumbCollector.new(printer)
105
+ CqlRuby::Executor.new(
106
+ collector: collector,
107
+ filter_reader: filter_reader,
108
+ pattern: pattern,
109
+ path: path,
110
+ filters: filters,
111
+ recursive: options[:recursive_search],
112
+ ).search_all
113
+ rescue => e
114
+ puts "Error: #{e}"
115
+ show_help
116
+ end
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module CqlRuby
4
- ; end
3
+ module CqlRuby;
4
+ def self.log(txt)
5
+ p txt
6
+ end
7
+ end
5
8
 
6
- require 'cql/executor'
7
- require 'cql/crumb_collector'
8
- require 'cql/abstract_printer'
9
- require 'cql/console_printer'
10
- require 'cql/filter_reader'
11
- require 'cql/filter_evaluator'
12
- require 'cql/pattern_matcher'
9
+ require 'cql_ruby/executor'
10
+ require 'cql_ruby/crumb_collector'
11
+ require 'cql_ruby/abstract_printer'
12
+ require 'cql_ruby/console_printer'
13
+ require 'cql_ruby/filter_reader'
14
+ require 'cql_ruby/filter_evaluator'
15
+ require 'cql_ruby/pattern_matcher'
@@ -8,6 +8,7 @@ module CqlRuby
8
8
  attr_writer :color_on
9
9
  attr_writer :file_on
10
10
  attr_writer :source_on
11
+ attr_writer :surrounding_lines
11
12
 
12
13
  def initialize
13
14
  super
@@ -15,14 +16,33 @@ module CqlRuby
15
16
  @color_on = true
16
17
  @file_on = true
17
18
  @source_on = true
19
+ @surrounding_lines = 0
20
+ @counter = 0
18
21
  end
19
22
 
20
23
  #
21
24
  # @param crumb [Cqlruby::Crumb]
22
25
  #
23
26
  def print(crumb)
24
- puts "#{color(94)}#{crumb.file_name}#{decor_reset}:#{color(33)}#{crumb.line_no}#{decor_reset} #{color(93)}#{crumb.type}#{decor_reset}" if @file_on
25
- puts decorate_source_line(crumb) if @source_on
27
+ parts = "##{color(97)}#{@counter}#{decor_reset}"
28
+ parts += " #{color(94)}#{crumb.file_name}#{decor_reset}:#{color(33)}#{crumb.line_no}#{decor_reset} #{color(93)}#{crumb.type}#{decor_reset}" if @file_on
29
+
30
+ if @source_on && @surrounding_lines.positive?
31
+ parts_visible_len = parts.gsub(/\e\[\d+m/, '').size + 1
32
+ indent = ' ' * parts_visible_len
33
+ (-@surrounding_lines).upto(-1).each { |offs| puts "#{indent}#{crumb.surrounding_line(offs)}" }
34
+ end
35
+
36
+ parts += ' ' + decorate_source_line(crumb) if @source_on
37
+
38
+ puts parts
39
+
40
+ if @source_on && @surrounding_lines.positive?
41
+ 1.upto(@surrounding_lines).each { |offs| puts "#{indent}#{crumb.surrounding_line(offs)}" }
42
+ puts '--'
43
+ end
44
+
45
+ @counter += 1
26
46
  end
27
47
 
28
48
  private
@@ -54,7 +74,6 @@ module CqlRuby
54
74
  # @param [Cqlruby::Crumb] crumb
55
75
  # @return [String]
56
76
  def decorate_source_line(crumb)
57
- # TODO add +- line surrounding options
58
77
  source = crumb.source
59
78
  from = crumb.line_col_no
60
79
  to = from + crumb.expression_size
@@ -63,14 +82,14 @@ module CqlRuby
63
82
  subject = source[from..to - 1] || ''
64
83
  suffix = source[to..] || ''
65
84
 
66
- color(90) +
85
+ color(97) +
67
86
  prefix +
68
87
  decor_reset +
69
88
  color(31) +
70
89
  bold +
71
90
  subject +
72
91
  decor_reset +
73
- color(90) +
92
+ color(97) +
74
93
  suffix +
75
94
  decor_reset
76
95
  end
@@ -1,6 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'parser/current'
4
+ require 'pathname'
5
+
6
+ module CqlRuby
7
+ class Config
8
+ @@debug_level = 0
9
+
10
+ class << self
11
+ def debug_level=(lvl); @@debug_level = lvl; end
12
+ def debug_level; @@debug_level; end
13
+ def debug_level_1?; @@debug_level >= 1; end
14
+ def debug_level_2?; @@debug_level >= 2; end
15
+ def debug_level_3?; @@debug_level >= 3; end
16
+ end
17
+ end
18
+ end
4
19
 
5
20
  #
6
21
  # Executes search and dumps results into the collector.
@@ -10,43 +25,77 @@ require 'parser/current'
10
25
  # @param path [String]
11
26
  # @param filters [Array<String>]
12
27
  #
13
- CqlRuby::Executor = Struct.new(:collector, :filter_reader, :pattern, :path, :filters) do
14
- def search_all
15
- files.flat_map do |file|
16
- search(file)
28
+ module CqlRuby
29
+ class Executor
30
+ def initialize(
31
+ collector:,
32
+ filter_reader:,
33
+ pattern:,
34
+ path:,
35
+ filters: [],
36
+ recursive: true
37
+ )
38
+ @collector = collector
39
+ @filter_reader = filter_reader
40
+ @pattern = pattern
41
+ @path = path
42
+ @filters = filters
43
+ @recursive = recursive
17
44
  end
18
- end
19
45
 
20
- private
46
+ def search_all
47
+ files.flat_map do |file|
48
+ CqlRuby.log "File check: #{file}" if CqlRuby::Config.debug_level_3?
49
+ search(file)
50
+ end
51
+ end
21
52
 
22
- def search(file)
23
- ast = Parser::CurrentRuby.parse(File.read(file))
24
- source_reader = CqlRuby::SourceReader.new(file)
25
- walk(ast, [], source_reader)
53
+ private
26
54
 
27
- nil
28
- end
55
+ def search(file)
56
+ ast = Parser::CurrentRuby.parse(File.read(file))
57
+ source_reader = CqlRuby::SourceReader.new(file)
58
+ walk(ast, [], source_reader)
29
59
 
30
- def walk(node, ancestors, source_reader)
31
- if node.is_a?(Parser::AST::Node)
32
- node.children.flat_map do |child|
33
- walk(child, ancestors.dup + [node], source_reader)
34
- end
35
- else
36
- if match?(node) && CqlRuby::FilterEvaluator.pass?(filter_reader, node, ancestors)
37
- collector.add(CqlRuby::Crumb.new(node, ancestors, source_reader))
60
+ nil
61
+ rescue => e
62
+ CqlRuby.log "File #{file} cannot be parsed: #{e}"
63
+ end
64
+
65
+ def walk(node, ancestors, source_reader)
66
+ if node.is_a?(Parser::AST::Node)
67
+ node.children.flat_map do |child|
68
+ walk(child, ancestors.dup + [node], source_reader)
69
+ end
70
+ else
71
+ if match?(node) && CqlRuby::FilterEvaluator.pass?(filter_reader, node, ancestors)
72
+ collector.add(CqlRuby::Crumb.new(node, ancestors, source_reader))
73
+ end
38
74
  end
75
+
76
+ nil
39
77
  end
40
78
 
41
- nil
42
- end
79
+ def match?(target)
80
+ CqlRuby::PatternMatcher.match?(pattern, target)
81
+ end
43
82
 
44
- def match?(target)
45
- CqlRuby::PatternMatcher.match?(pattern, target)
46
- end
83
+ def files
84
+ return [path] if File.file?(path)
85
+
86
+ clean_path = Pathname(path).cleanpath.to_s
87
+ clean_path += '/**' if recursive
88
+ clean_path += '/*.rb'
47
89
 
48
- def files
49
- Dir.glob(path)
90
+ Dir.glob(clean_path)
91
+ end
92
+
93
+ attr_reader :collector
94
+ attr_reader :filter_reader
95
+ attr_reader :pattern
96
+ attr_reader :path
97
+ attr_reader :filters
98
+ attr_reader :recursive
50
99
  end
51
100
  end
52
101
 
@@ -63,6 +112,10 @@ CqlRuby::Crumb = Struct.new(:full_name, :ancestors, :source_reader) do
63
112
  source_reader.source_line(line_no)
64
113
  end
65
114
 
115
+ def surrounding_line(offset)
116
+ source_reader.source_line(line_no + offset)
117
+ end
118
+
66
119
  def file_name
67
120
  source_reader.file
68
121
  end
@@ -82,6 +135,8 @@ CqlRuby::SourceReader = Struct.new(:file) do
82
135
  end
83
136
 
84
137
  def source_line(n)
138
+ return nil unless lines.size >= n
139
+
85
140
  lines[n - 1].chop
86
141
  end
87
142
 
@@ -15,7 +15,7 @@ module CqlRuby
15
15
  end
16
16
 
17
17
  def self.regex?(pattern)
18
- pattern[0..1] == 'r:'
18
+ pattern[0..1] == 'r/'
19
19
  end
20
20
  private_class_method :regex?
21
21
 
@@ -26,7 +26,9 @@ module CqlRuby
26
26
 
27
27
  def self.regex_match?(pattern, subject)
28
28
  pattern = pattern[2..]
29
- pattern, *mods = pattern.split('+')
29
+ delim_idx = pattern.rindex('/')
30
+ mods = pattern[delim_idx + 1..].chars
31
+ pattern = pattern[0..delim_idx - 1]
30
32
 
31
33
  fops = 0
32
34
  fops |= Regexp::IGNORECASE if mods.include?('i')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cql_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - itarato
@@ -9,13 +9,35 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2020-07-05 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: parser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.7.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.7'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.7.1
13
33
  description:
14
34
  email: it.arato@gmail.com
15
- executables: []
35
+ executables:
36
+ - cql_ruby
16
37
  extensions: []
17
38
  extra_rdoc_files: []
18
39
  files:
40
+ - bin/cql_ruby
19
41
  - lib/cql_ruby.rb
20
42
  - lib/cql_ruby/abstract_printer.rb
21
43
  - lib/cql_ruby/console_printer.rb
@@ -36,7 +58,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
36
58
  requirements:
37
59
  - - ">="
38
60
  - !ruby/object:Gem::Version
39
- version: '0'
61
+ version: 2.5.0
40
62
  required_rubygems_version: !ruby/object:Gem::Requirement
41
63
  requirements:
42
64
  - - ">="