CQL
Code Query Language is a command line semantic code search tool for Ruby. This is not a replacement to Grep as it is only looking for AST leaf tokens in the source code (no comments and concatenation of tokens). Leaf tokens are variables, arguments, constants, operators, etc.
Why? Because sometimes you just want to know where something is used or called from. Maybe you're debugging a giant legacy codebase and wonder who is using a class or where a hash key might originate from.
This is so far a concept prototype, any feedback or feature request (and of course bug reports) are welcomed.
Examples:
Find all classes that subclasses ApplicationRecord and has an initializer defined:
cql_ruby ApplicationRecord ./app type:const has:def=initializerFind all occurrences of any variable ending with _user that is being assigned a new value inside a block, but not in test files:
cql_ruby r/_user$/ ./app type:lvasgn nest:block --exclude=%test.rbFind all arrays that has a constant definition inside:
cql_ruby --node array ./app has:constInstall:
gem install cql_rubyUsage:
To find tokens:
cql_ruby PATTERN PATH OPTIONS FILTERS
To find nodes:
cql_ruby --node TYPE PATH OPTIONS FILTERS
cql_ruby --help for more info.
Text matching both for the main pattern and any patterns in filters allows 3 different matching strategies:
- regex:
r/REGEX/(MODIFIER)*where modifier is:i,m,x,f,n, example:r/user_\d+/i - partial string match:
%PATTERN, example:%user - perfect string match:
PATTERN, example:user
Filters:
Type
Comma separated list of (parent node) types.
Example:
cql_ruby foo ./ type:send,arg
Available types: https://github.com/whitequark/parser/blob/master/lib/parser/meta.rb#L11-L34 (or use --help).
Nesting
Under what structure the subject is nested.
Examples:
cql_ruby foo ./ nest:class=Usercql_ruby bar ./ nest:block
Accepted nest structures: class, module, def, block.
Has child
Restrict to nodes that has a specific child.
Examples:
cql_ruby foo ./ has:defcql_ruby foo ./ has:def=r/user_(save|edit)/i
Pattern
Contextualize the matched node. For node searches it can handle ancestors and descendants, for token search only ancestors. X marks the primary match.
Examples:
cql_ruby --node def pattern:module-class-X-if-block
Assignment
Matches only for left side assignments in any form of:
x = _
_.x = _
_(x: _)
{ x: _ }
{ 'x' => _ }
_[:x] = _
_['x'] = _Examples:
cql_ruby user ./ assigned

