Giter Club home page Giter Club logo

querly's Introduction

Querly logo

Querly - Pattern Based Checking Tool for Ruby

Ruby

Querly is a query language and tool to find out method calls from Ruby programs. Define rules to check your program with patterns to find out bad pieces. Querly finds out matching pieces from your program.

Overview

Your project may have many local rules:

  • Should not use Customer#update_mail and use 30x faster Customer.update_all_email instead (Slower #update_mail is left just for existing code, but new code should not use it)
  • Should not use root_url without locale: parameter
  • Should not use Net::HTTP for Web API calls, but use HTTPClient

These local rule violations will be found during code review. Reviewers will ask commiter to revise; commiter will fix; fine. Really? It is boring and time-consuming. We need some automation!

However, that rules cannot be the standard. They make sense only in your project. Okay, start writing a plug-in for RuboCop? (or other checking tools)

Instead of writing RuboCop plug-in, just define a Querly rule in a few lines of YAML.

rules:
  - id: my_project.use_faster_email_update
    pattern: update_mail
    message: When updating Customer#email, newly written code should use 30x faster Customer.update_all_email
    justification:
      - When you are editing old code (it should be refactored...)
      - You are sure updating only small number of customers, and performance does not matter

  - id: my_project.root_url_without_locale
    pattern: "root_url(!locale: _)"
    message: Links to top page should be with locale parameter

  - id: my_project.net_http
    pattern: Net::HTTP
    message: Use HTTPClient to make HTTP request

Write down your local rules, and let Querly check conformance with them. Focus on spec, design, UX, and other important things during code review!

Installation

Install via RubyGems.

$ gem install querly

Or you can put it in your Gemfile.

gem 'querly'

Quick Start

Copy the following YAML and paste as querly.yml in your project's repo.

rules:
  - id: sample.debug_print
    pattern:
      - self.p
      - self.pp
    message: Delete debug print

Run querly in the repo.

$ querly check .

If your code contains p or pp calls, querly will print warning messages.

./app/models/account.rb:44:10                  p(account.id)      Delete debug print
./app/controllers/accounts_controller.rb:17:2  pp params: params  Delete debug print

Configuration

See the following manual for configuration and query language reference.

Use querly console command to test patterns interactively.

Requiring Rules

import section in config file now allows accepts require command.

import:
  - require: querly/rules/sample
  - require: your_library/querly/rules

Querly ships with querly/rules/sample rule set. Check lib/querly/rules/sample.rb and rules/sample.yml for detail.

Publishing Gems with Querly Rules

Querly provides Querly.load_rule API to allow publishing your rules as part of Ruby library. Put rules YAML file in your gem, and add Ruby script in some directory like lib/your_library/querly/rules.rb.

Querly.load_rules File.join(__dir__, relative_path_to_yaml_file)

Notes

Querly's analysis is syntactic

The analysis is currently purely syntactic:

record.save(validate: false)

and

x = false
record.save(validate: x)

will yield different results. This can be improved by doing very primitive data flow analysis, and I'm planning to do that.

Too many false positives!

The analysis itself does not have very good precision. There will be many false positives, and querly warning free code does not make much sense.

  • TODO: support to ignore warnings through magic comments in code

Querly is not to ensure there is nothing wrong in the code, but just tells you code fragments you should review with special care. I believe it still improves your software development productivity.

Incoming updates?

The following is the list of updates which would make sense.

  • Support for importing rule sets, and provide some good default rules
  • Support for ignoring warnings
  • Improve analysis precision by intra procedural data flow analysis

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/soutaro/querly.

querly's People

Contributors

gfx avatar hanachin avatar ivanha09 avatar kohtaro24 avatar koic avatar mallowlabs avatar pocke avatar shinnn avatar soutaro avatar vzvu3k6k avatar wata727 avatar y-yagi avatar ybiquitous avatar yoshoku avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

querly's Issues

`f(..., :foo, ...)` not working

I'd like to find FactoryBot.create(..., :some_traint, ...) but querly v0.13.0 raises errors:

> find create(..., :foo, ...)
Error:
parse error on value :foo (SYMBOL)

find order(created_at: ...) is not possible?

In most of Rails projects, order(id: ...) is better than order(created_at: ...) so I'd like to add rules about it; however find order(created_at: ...) raises errors as follows.

In console:

> find order(created_at: ...)
Error:
parse error on value "..." (DOTDOTDOT)

Detect csend node as method call

Querly does not detect a csend node as a method call.

foo.bar
foo&.bar

With the above Ruby file, I expect querly find bar detects the both lines. But actually it detects only the first line.

So, I'd like to change querly to detect csend node as a method call.
If you accept this proposal, I'll work on it.

[Feature Request] Different exit code for fatal error

Hello,

I'm in trouble because I cannot distinguish a fatal error from a rule violation by the exit code. ๐Ÿ˜ฐ

rescue => exn
stderr.puts Rainbow("Fatal error:").red
stderr.puts exn.inspect
stderr.puts exn.backtrace.map {|x| " " + x }.join("\n")
1

querly/lib/querly/cli.rb

Lines 59 to 61 in 6bfde87

rescue => exn
formatter.fatal_error exn
exit 1

Without parsing the output (STDOUT and STDERR), is there a way to distinguish them?
If no way, perhaps this may be a breaking change, would it be a good idea to add a new exit code (e.g. 1) for a fatal error?

I would be happy if you could consider this idea.
Thank you.

crashes in `find order(params[...])`

In querly console:

> find order(params[...])
Error:
parse error on value "$" ($end)
Backtrace:
  /Users/gfx/.rbenv/versions/2.3.1/lib/ruby/2.3.0/racc/parser.rb:528:in `on_error'

[Feature Request] Support `--format=json` option for `querly test`

Hello,

I want to parse the output of the querly test command more easily and safely.
So, what do you think about the suggestion to add a new option --format=json to the querly test command?

The option is almost similar to the querly check command. Here is the current querly check usage:

$ querly help check
Usage:
  querly check [paths]

Options:
  [--config=CONFIG]  
                     # Default: querly.yml
  [--root=ROOT]      
  [--format=FORMAT]  
                     # Default: text
                     # Possible values: text, json
  [--rule=RULE]      
  [--threads=N]      
                     # Default: 8

Check paths based on configuration

On the other hand, the new options of querly test will be similar:

  • querly test (without --format, defaults to --format=text. The output is the current one)
  • querly test --format=text
  • querly test --format=json

I would be happy if you could consider this suggestion.
Thank you.

[Feature request] `querly init` command

$ querly init
`querly.yaml` is generated!

$ cat querly.yaml
rules:
  # - id: com.example.some_rule
  #   pattern: 'some_method_call()'
...

Some lint tool has init command to generate configuration file. For example: ESLint
And, querly requires a configuration file. So, I guess initialise command is useful for first-time user.

WDYT?

Redesign rule filtering language

config:
  - rule: sample.test
    on: /test
  - rule: rails.app.controller
    on: /app/controllers
  - rule: capybara
    on: /features
  - rule: minitest
    on:
      - /test
      - /features

namespace of ::Concerns

about lib/querly/concerns/backtrace_formatter.rb

Concerns is defined in the top level namespace, it may conflict to another Concerns module defined on the application layer.

I propose the following.

before

module Concerns
  module BacktraceFormatter
    def format_backtrace(backtrace, indent: 2)
      backtrace.map {|x| " "*indent + x }.join("\n")
    end
  end
end

after

module Querly
  module Concerns
    module BacktraceFormatter
      def format_backtrace(backtrace, indent: 2)
        backtrace.map {|x| " "*indent + x }.join("\n")
      end
    end
  end
end

[Feature Request] Add schema check for config file

To save Querly users from typos on querly.yml, I strongly suggest checking the schema of querly.yml.

For example, because I couldn't notice a typo like except and expect, my configuration (rule2) didn't work well. ๐Ÿ˜“

check:
  - path: /
    rules:
      - except: rule1
      - expect: rule2

When there are mistakes in the configuration like above, I hope querly check or querly test command fails immediately and outputs an easy message to understand.

For example:

$ querly test
Error: Querly configuration in /path/to/my/project/querly.yml is invalid:
       - Unexpected property "expect".

What do you think about this suggestion?

Error: undefined method `line' for nil:NilClass

Patten

!field(_, _, null: _, ...)

This is a useless pattern because of just my mistake, but it causes NoMethoderror and I think it is a bug in querly.

Environment

Ruby 2.5.1
Querly 0.11.0
macOS

Backtrace

Error: undefined method `line' for nil:NilClass
Backtrace:
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/parser-2.5.1.2/lib/parser/source/map.rb:100:in `line'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/cli/console.rb:71:in `block in loop'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/analyzer.rb:35:in `block (2 levels) in find'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:25:in `each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:28:in `block in each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:28:in `block in each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:28:in `block in each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:28:in `block in each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:28:in `block in each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/node_pair.rb:27:in `each_subpair'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/analyzer.rb:33:in `block in find'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/analyzer.rb:32:in `each'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/analyzer.rb:32:in `find'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/cli/console.rb:69:in `loop'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/cli/console.rb:27:in `start'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/lib/querly/cli.rb:68:in `console'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor/command.rb:27:in `run'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor/invocation.rb:126:in `invoke_command'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor.rb:387:in `dispatch'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor/base.rb:466:in `start'
  /Users/gfx/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/querly-0.11.0/exe/querly:8:in `<top (required)>'
  /Users/gfx/.rbenv/versions/2.5.1/bin/querly:23:in `load'
  /Users/gfx/.rbenv/versions/2.5.1/bin/querly:23:in `<main>'

`querly-pp haml` does not work with HAML 5

$ querly-pp haml < test.haml
/home/pocke/.gem/ruby/2.4.0/gems/haml-5.0.1/lib/haml/parser.rb:92:in `initialize': wrong number of arguments (given 2, expected 1) (ArgumentError)
	from /home/pocke/.gem/ruby/2.4.0/gems/querly-0.5.0/lib/querly/pp/cli.rb:64:in `new'
	from /home/pocke/.gem/ruby/2.4.0/gems/querly-0.5.0/lib/querly/pp/cli.rb:64:in `run_haml'
	from /home/pocke/.gem/ruby/2.4.0/gems/querly-0.5.0/lib/querly/pp/cli.rb:48:in `run'
	from /home/pocke/.gem/ruby/2.4.0/gems/querly-0.5.0/exe/querly-pp:7:in `<top (required)>'
	from /home/pocke/.gem/ruby/2.4.0/bin/querly-pp:22:in `load'
	from /home/pocke/.gem/ruby/2.4.0/bin/querly-pp:22:in `<main>'

$ haml --version
Haml 5.0.1

$ querly version
Querly 0.5.0

New ruby syntax support

Hi there,

I'm trying to use querly with a project on ruby 2.7 and it causes a couple of errors like

#<Parser::SyntaxError: unexpected token tDOT3>
#<Parser::SyntaxError: unexpected token tRBRACK>

It seems to be a problem of using Parser::Ruby25 class instead of Parser::CurrentRuby.

Not defined rules on `check` section

Even if the following incorrect querly.yml is given, Querly succeeds.
I think good that the querly test command could tell such incorrectness.

# querly.yml
rules:
  - id: sample.foo
    pattern:
      - self.p
      - self.pp
    message: Delete debug print

check:
  - path: /
    rules:
      - except: sample.test #<= Not defined!
  - path: /test
    rules:
      - append: sample.test #<= Not defined!
$ querly test
Checking rule id uniqueness...
Checking rule patterns...
Tested 1 rules with 0 tests.
  All tests green!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.