cql_ruby 0.0.7 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bd516a07069a73fad1c48a2ca7ae536d7c52a891c882211d2de0b5d9c670fb1
4
- data.tar.gz: 9ec5696402ffd46da3427c338e18b33cc7d7fecf39df135cee451a29ccee39ae
3
+ metadata.gz: 17840020ae4f57f60763716ac438b33a68abb4b1add767d5f8e88cfb946439c8
4
+ data.tar.gz: 789aa975ced7c62036da026f7e4bd377c09b1502692ff217fb697641d5478d64
5
5
  SHA512:
6
- metadata.gz: 9b6dbc5df16b5042e431d6682435e0f993b013c66ab70541a259b66ed487405c71c088b63f554085fb2018bd59bd0e3499931c87dcfc0d2f4bc9c8bfbabeb421
7
- data.tar.gz: ff722aee7187a9b0a44cbe9ff45182fa13fe97add03a46545f7de26238993abefdb16cb85e4e4302a90cf1f7c39d8071e1d1bcb1213db382df8a6d4f505ac819
6
+ metadata.gz: ee8c4e5ea2cfde9a8837cc1e19734e0051424af9c15fe02fc5db49b11984052b70a4acb6d196b94c38820ea34bccbb8d78ff431e5bef45ac0627a55548fae324
7
+ data.tar.gz: 9e550d59e360717069c3198269bbe815d73aae7cc1d43b9532ed2fc4dee60b8f9decee399051ceedb9b0ae21867e785cce0423170f1f417550b3611c018d4270
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'parser'
3
4
  require 'cql_ruby'
4
5
 
5
6
  def show_help
@@ -14,6 +15,7 @@ def show_help
14
15
  \tFILTERS
15
16
  \t\tParent node type: type:T(,T)* Example: type:def,send,arg
16
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?
17
19
 
18
20
  \tOPTIONS
19
21
  \t\t-lN (N is integer) Add N surrounding line before and after.
@@ -23,9 +25,13 @@ def show_help
23
25
  \t\t-nr (--no-recursion) Non-recursive search.
24
26
  \t\t-v -vv -vvv Debug output levels.
25
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(' ')}
31
+
26
32
  \tEXAMPLES
27
33
  \t\tcql_ruby user ./
28
- \t\tcql_ruby -ns -nr %user_info ./ type:send,arg nest:block nest:class=r/User/i
34
+ \t\tcql_ruby -ns -nr %user_info ./ type:send,arg nest:block nest:class=r/User/i has:str=WARNING
29
35
  HELP
30
36
 
31
37
  exit
@@ -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 [Cqlruby::FilterReader] filter_reader
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 NestRule < Struct.new(:type, :name)
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 "Unknown type: #{type}. Allowed: #{ALLOWED_TYPE}" unless ALLOWED_TYPE.include?(type)
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
- # @attribute [Parser::AST::Node] allowed_types
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<Cqlruby::NestRule>] nest_under
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
- @nest_under << NestRule.from(value)
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)
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.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - itarato