cql_ruby 0.0.3 → 0.0.8
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 +4 -4
- data/bin/cql_ruby +40 -6
- data/lib/cql_ruby.rb +12 -9
- data/lib/cql_ruby/console_printer.rb +24 -5
- data/lib/cql_ruby/executor.rb +82 -27
- data/lib/cql_ruby/filter_evaluator.rb +75 -1
- data/lib/cql_ruby/filter_reader.rb +23 -7
- data/lib/cql_ruby/pattern_matcher.rb +9 -3
- metadata +23 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17840020ae4f57f60763716ac438b33a68abb4b1add767d5f8e88cfb946439c8
|
4
|
+
data.tar.gz: 789aa975ced7c62036da026f7e4bd377c09b1502692ff217fb697641d5478d64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee8c4e5ea2cfde9a8837cc1e19734e0051424af9c15fe02fc5db49b11984052b70a4acb6d196b94c38820ea34bccbb8d78ff431e5bef45ac0627a55548fae324
|
7
|
+
data.tar.gz: 9e550d59e360717069c3198269bbe815d73aae7cc1d43b9532ed2fc4dee60b8f9decee399051ceedb9b0ae21867e785cce0423170f1f417550b3611c018d4270
|
data/bin/cql_ruby
CHANGED
@@ -1,26 +1,37 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require 'parser'
|
3
4
|
require 'cql_ruby'
|
4
5
|
|
5
6
|
def show_help
|
6
7
|
puts <<~HELP
|
7
8
|
|
8
9
|
\tSYNOPSIS
|
9
|
-
\tcql_ruby options pattern path filters ...
|
10
|
+
\t\tcql_ruby options pattern path filters ...
|
10
11
|
|
11
12
|
\tDESCRIPTION
|
12
|
-
\tCQL (Code Query Language) is a semantic search tool for your Ruby source code.
|
13
|
+
\t\tCQL (Code Query Language) is a semantic search tool for your Ruby source code.
|
13
14
|
|
14
15
|
\tFILTERS
|
15
|
-
\t\tParent node type: type:T(,T)*
|
16
|
+
\t\tParent node type: type:T(,T)* Example: type:def,send,arg
|
17
|
+
\t\tNesting under: nest:T(=NAME) Example: nest:def=save_user nest:class=UserManager
|
18
|
+
\t\tHas child: has:T(=NAME) Example: has:const has:def=valid?
|
16
19
|
|
17
20
|
\tOPTIONS
|
21
|
+
\t\t-lN (N is integer) Add N surrounding line before and after.
|
18
22
|
\t\t-nc (--no-color) No color on output.
|
19
23
|
\t\t-nf (--no-file) No file names.
|
20
24
|
\t\t-ns (--no-source) No source code.
|
25
|
+
\t\t-nr (--no-recursion) Non-recursive search.
|
26
|
+
\t\t-v -vv -vvv Debug output levels.
|
27
|
+
|
28
|
+
\tALLOWED NODE TYPES
|
29
|
+
\t\tWhen defining filters only valid AST types can be defined. They are:
|
30
|
+
#{Parser::Meta::NODE_TYPES.to_a.join(' ')}
|
21
31
|
|
22
32
|
\tEXAMPLES
|
23
|
-
\tcql_ruby
|
33
|
+
\t\tcql_ruby user ./
|
34
|
+
\t\tcql_ruby -ns -nr %user_info ./ type:send,arg nest:block nest:class=r/User/i has:str=WARNING
|
24
35
|
HELP
|
25
36
|
|
26
37
|
exit
|
@@ -32,6 +43,8 @@ def extract_options
|
|
32
43
|
show_color: true,
|
33
44
|
show_file: true,
|
34
45
|
show_source: true,
|
46
|
+
recursive_search: true,
|
47
|
+
surrounding_lines: 0,
|
35
48
|
}
|
36
49
|
|
37
50
|
ARGV.delete_if do |arg|
|
@@ -42,8 +55,15 @@ def extract_options
|
|
42
55
|
options[:show_file] = false
|
43
56
|
elsif %w[-ns --no-source].include?(arg)
|
44
57
|
options[:show_source] = false
|
45
|
-
elsif %w[-h --help]
|
58
|
+
elsif %w[-h --help].include?(arg)
|
46
59
|
show_help
|
60
|
+
elsif %w[-v -vv -vvv].include?(arg)
|
61
|
+
lvl = arg.chars.find_all { |c| c == 'v' }.size
|
62
|
+
CqlRuby::Config.debug_level = lvl
|
63
|
+
elsif %w[-nr --no-recursive].include?(arg)
|
64
|
+
options[:recursive_search] = false
|
65
|
+
elsif arg[0..1] == '-l' && arg[2..].to_i > 0
|
66
|
+
options[:surrounding_lines] = arg[2..].to_i
|
47
67
|
else
|
48
68
|
raise "Unknown arg #{arg}"
|
49
69
|
end
|
@@ -64,24 +84,38 @@ end
|
|
64
84
|
|
65
85
|
begin
|
66
86
|
options = extract_options
|
87
|
+
CqlRuby.log "Call options: #{options}" if CqlRuby::Config.debug_level_2?
|
67
88
|
|
68
89
|
raise unless ARGV.size >= 2
|
69
90
|
|
70
91
|
pattern = ARGV.shift
|
92
|
+
CqlRuby.log "Call pattern: <#{pattern}>" if CqlRuby::Config.debug_level_2?
|
93
|
+
|
71
94
|
# TODO Make path patterns universal.
|
72
95
|
path = ARGV.shift
|
96
|
+
CqlRuby.log "Call path: <#{path}>" if CqlRuby::Config.debug_level_2?
|
73
97
|
|
74
98
|
# Rest must be filters - can sink ARGV now.
|
75
99
|
filters = extract_filters
|
100
|
+
CqlRuby.log "Call filters: #{filters}" if CqlRuby::Config.debug_level_2?
|
101
|
+
|
76
102
|
filter_reader = CqlRuby::FilterReader.new(filters)
|
77
103
|
|
78
104
|
printer = CqlRuby::ConsolePrinter.new
|
79
105
|
printer.color_on = options[:show_color]
|
80
106
|
printer.file_on = options[:show_file]
|
81
107
|
printer.source_on = options[:show_source]
|
108
|
+
printer.surrounding_lines = options[:surrounding_lines]
|
82
109
|
|
83
110
|
collector = CqlRuby::CrumbCollector.new(printer)
|
84
|
-
CqlRuby::Executor.new(
|
111
|
+
CqlRuby::Executor.new(
|
112
|
+
collector: collector,
|
113
|
+
filter_reader: filter_reader,
|
114
|
+
pattern: pattern,
|
115
|
+
path: path,
|
116
|
+
filters: filters,
|
117
|
+
recursive: options[:recursive_search],
|
118
|
+
).search_all
|
85
119
|
rescue => e
|
86
120
|
puts "Error: #{e}"
|
87
121
|
show_help
|
data/lib/cql_ruby.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module CqlRuby
|
4
|
-
|
3
|
+
module CqlRuby;
|
4
|
+
def self.log(txt)
|
5
|
+
p txt
|
6
|
+
end
|
7
|
+
end
|
5
8
|
|
6
|
-
require '
|
7
|
-
require '
|
8
|
-
require '
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require '
|
12
|
-
require '
|
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
|
-
|
25
|
-
|
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(
|
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(
|
92
|
+
color(97) +
|
74
93
|
suffix +
|
75
94
|
decor_reset
|
76
95
|
end
|
data/lib/cql_ruby/executor.rb
CHANGED
@@ -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
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
if
|
37
|
-
|
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
|
-
|
42
|
-
|
79
|
+
def match?(target)
|
80
|
+
CqlRuby::PatternMatcher.match?(pattern, target)
|
81
|
+
end
|
43
82
|
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
49
|
-
|
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
|
|
@@ -7,6 +7,7 @@ module CqlRuby
|
|
7
7
|
[
|
8
8
|
pass_type?(filter_reader, ancestors),
|
9
9
|
pass_nesting?(filter_reader, ancestors),
|
10
|
+
pass_has?(filter_reader, node, ancestors),
|
10
11
|
].all?
|
11
12
|
end
|
12
13
|
|
@@ -25,7 +26,7 @@ module CqlRuby
|
|
25
26
|
end
|
26
27
|
|
27
28
|
#
|
28
|
-
# @param [
|
29
|
+
# @param [CqlRuby::FilterReader] filter_reader
|
29
30
|
# @param [Array<Parser::AST::Node>] ancestors
|
30
31
|
#
|
31
32
|
# @return [Boolean]
|
@@ -49,6 +50,79 @@ module CqlRuby
|
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# @param [CqlRuby::FilterReader] filter_reader
|
56
|
+
# @param [Parser::AST::Node] node
|
57
|
+
# @param [Array<Parser::AST::Node>] ancestors
|
58
|
+
#
|
59
|
+
def pass_has?(filter_reader, node, ancestors)
|
60
|
+
return true unless filter_reader.restrict_children?
|
61
|
+
|
62
|
+
filter_reader.has_leaves.all? do |has_rule|
|
63
|
+
anchor_node = try_get_class(ancestors) || try_get_module(ancestors) || try_get_def(ancestors)
|
64
|
+
next false unless anchor_node
|
65
|
+
|
66
|
+
has_node_with_name?(anchor_node, has_rule)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# @param [Array<Parser::AST::Node>] ancestors
|
72
|
+
#
|
73
|
+
def try_get_class(ancestors)
|
74
|
+
return nil unless ancestors.size >= 2
|
75
|
+
return nil unless ancestors[-1].type == :const
|
76
|
+
return nil unless ancestors[-2].type == :class
|
77
|
+
|
78
|
+
ancestors[-2].children[2]
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# @param [Array<Parser::AST::Node>] ancestors
|
83
|
+
#
|
84
|
+
def try_get_module(ancestors)
|
85
|
+
return nil unless ancestors.size >= 2
|
86
|
+
return nil unless ancestors[-1].type == :const
|
87
|
+
return nil unless ancestors[-2].type == :module
|
88
|
+
|
89
|
+
ancestors[-2].children[1]
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# @param [Array<Parser::AST::Node>] ancestors
|
94
|
+
#
|
95
|
+
def try_get_def(ancestors)
|
96
|
+
return nil unless ancestors.size >= 1
|
97
|
+
return nil unless ancestors[-1].type == :def
|
98
|
+
|
99
|
+
ancestors[-1].children[2]
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# @param [Parser::AST::Node] anchor_node
|
104
|
+
# @param [CqlRuby::NodeSpec]
|
105
|
+
#
|
106
|
+
def has_node_with_name?(anchor_node, has_rule)
|
107
|
+
return false unless anchor_node.is_a?(Parser::AST::Node)
|
108
|
+
|
109
|
+
fn_children_with_type = ->(node) { node.children.map { |child| [child, node.type] } }
|
110
|
+
to_visit = fn_children_with_type.call(anchor_node)
|
111
|
+
|
112
|
+
until to_visit.empty?
|
113
|
+
current_node, current_type = to_visit.shift
|
114
|
+
|
115
|
+
if current_node.is_a?(Parser::AST::Node)
|
116
|
+
to_visit += fn_children_with_type.call(current_node)
|
117
|
+
else
|
118
|
+
if current_type == has_rule.type.to_sym && CqlRuby::PatternMatcher.match?(has_rule.name, current_node)
|
119
|
+
return true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
false
|
125
|
+
end
|
52
126
|
end
|
53
127
|
end
|
54
128
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# TODO: Have convenience filters for type:_ such as: isclass, ismodule, isdef ...
|
4
|
+
|
3
5
|
module CqlRuby
|
4
|
-
class
|
6
|
+
class NodeSpec < Struct.new(:type, :name)
|
7
|
+
# Make this non duplicated.
|
5
8
|
NAME_ANY = '*'
|
6
|
-
ALLOWED_TYPE = %w[class module def block].freeze
|
7
9
|
|
8
10
|
class << self
|
9
11
|
#
|
@@ -15,8 +17,7 @@ module CqlRuby
|
|
15
17
|
type, name = raw_value.split('=')
|
16
18
|
name ||= NAME_ANY
|
17
19
|
|
18
|
-
raise "
|
19
|
-
raise "Type #{type} cannot have a name." if %w[block].include?(type) && name != NAME_ANY
|
20
|
+
raise "Type '#{type}' is not recognized. See 'cql_ruby --help' for allowed types." unless Parser::Meta::NODE_TYPES.member?(type.to_sym)
|
20
21
|
|
21
22
|
new(type, name)
|
22
23
|
end
|
@@ -38,16 +39,21 @@ module CqlRuby
|
|
38
39
|
# example: type:def,send
|
39
40
|
#
|
40
41
|
class FilterReader
|
41
|
-
|
42
|
+
NESTING_ALLOWED_TYPES = %w[class module def block].freeze
|
43
|
+
|
44
|
+
# @attribute [Array<Symbol>] allowed_types
|
42
45
|
attr_reader :allowed_types
|
43
|
-
# @attribute [Array<
|
46
|
+
# @attribute [Array<CqlRuby::NodeSpec>] nest_under
|
44
47
|
attr_reader :nest_under
|
48
|
+
# @attribute [Array<CqlRuby::NodeSpec>] has_leaves
|
49
|
+
attr_reader :has_leaves
|
45
50
|
|
46
51
|
def initialize(raw_filters)
|
47
52
|
super()
|
48
53
|
|
49
54
|
@allowed_types = []
|
50
55
|
@nest_under = []
|
56
|
+
@has_leaves = []
|
51
57
|
|
52
58
|
parse_raw_filters(raw_filters)
|
53
59
|
end
|
@@ -60,6 +66,10 @@ module CqlRuby
|
|
60
66
|
!@nest_under.empty?
|
61
67
|
end
|
62
68
|
|
69
|
+
def restrict_children?
|
70
|
+
!@has_leaves.empty?
|
71
|
+
end
|
72
|
+
|
63
73
|
private
|
64
74
|
|
65
75
|
# @param [Array<String>] raw_filters
|
@@ -71,7 +81,13 @@ module CqlRuby
|
|
71
81
|
if %w[type t].include?(name)
|
72
82
|
@allowed_types += value.split(',').map(&:to_sym)
|
73
83
|
elsif %w[nest n].include?(name)
|
74
|
-
|
84
|
+
spec = NodeSpec.from(value)
|
85
|
+
raise "Unknown type for nesting: '#{spec.type}' from '#{raw_filter}'. Allowed: #{NESTING_ALLOWED_TYPES}" unless NESTING_ALLOWED_TYPES.include?(spec.type)
|
86
|
+
raise "Type #{spec.type} cannot have a name." if %w[block].include?(spec.type) && spec.restrict_name?
|
87
|
+
|
88
|
+
@nest_under << spec
|
89
|
+
elsif %w[has h].include?(name)
|
90
|
+
@has_leaves << NodeSpec.from(value)
|
75
91
|
end
|
76
92
|
end
|
77
93
|
|
@@ -1,9 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module CqlRuby
|
3
3
|
module PatternMatcher
|
4
|
+
MATCH_ANY = '*'
|
5
|
+
|
4
6
|
def self.match?(pattern, subject)
|
5
|
-
subject = subject.to_s
|
6
7
|
pattern = pattern.to_s
|
8
|
+
return true if pattern == MATCH_ANY
|
9
|
+
|
10
|
+
subject = subject.to_s
|
7
11
|
|
8
12
|
if regex?(pattern)
|
9
13
|
regex_match?(pattern, subject)
|
@@ -15,7 +19,7 @@ module CqlRuby
|
|
15
19
|
end
|
16
20
|
|
17
21
|
def self.regex?(pattern)
|
18
|
-
pattern[0..1] == 'r
|
22
|
+
pattern[0..1] == 'r/'
|
19
23
|
end
|
20
24
|
private_class_method :regex?
|
21
25
|
|
@@ -26,7 +30,9 @@ module CqlRuby
|
|
26
30
|
|
27
31
|
def self.regex_match?(pattern, subject)
|
28
32
|
pattern = pattern[2..]
|
29
|
-
|
33
|
+
delim_idx = pattern.rindex('/')
|
34
|
+
mods = pattern[delim_idx + 1..].chars
|
35
|
+
pattern = pattern[0..delim_idx - 1]
|
30
36
|
|
31
37
|
fops = 0
|
32
38
|
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.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- itarato
|
@@ -9,7 +9,27 @@ 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
35
|
executables:
|
@@ -38,7 +58,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
38
58
|
requirements:
|
39
59
|
- - ">="
|
40
60
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
61
|
+
version: 2.5.0
|
42
62
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
63
|
requirements:
|
44
64
|
- - ">="
|