2017-10-26 17:47:42 +00:00
< p align = "center" >
< img src = "https://media.githubusercontent.com/media/veelenga/bin/master/ameba/logo.png" width = "200" >
< h3 align = "center" > Ameba< / h3 >
< p align = "center" > Code style linter for Crystal< p >
< p align = "center" >
< sup >
2017-11-16 09:42:14 +00:00
< i > (a single-celled animal that catches food and moves about by extending fingerlike projections of protoplasm) < / i >
2017-10-26 17:47:42 +00:00
< / sup >
< / p >
2017-10-30 20:10:03 +00:00
< p align = "center" >
2017-11-03 10:12:45 +00:00
< a href = "https://travis-ci.org/veelenga/ameba" > < img src = "https://travis-ci.org/veelenga/ameba.svg?branch=master" > < / a >
2017-10-30 20:10:03 +00:00
< a href = "https://github.com/veelenga/ameba/releases" > < img src = "https://img.shields.io/github/release/veelenga/ameba.svg?maxAge=360" > < / a >
< a href = "https://shards.rocks/badge/github/veelenga/ameba" > < img src = "https://shards.rocks/badge/github/veelenga/ameba/status.svg" > < / a >
2017-11-02 08:39:29 +00:00
< a href = "https://github.com/veelenga/ameba/blob/master/LICENSE" > < img src = "https://img.shields.io/github/license/veelenga/ameba.svg" > < / a >
< a href = "https://gitter.im/veelenga/ameba?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge" > < img src = "https://badges.gitter.im/veelenga/ameba.svg" > < / a >
2017-10-30 20:10:03 +00:00
< / p >
2017-10-26 17:47:42 +00:00
< / p >
2017-11-01 17:14:38 +00:00
## About
2017-10-26 17:47:42 +00:00
2017-11-17 18:28:45 +00:00
Ameba is a static code analysis tool for the Crystal language.
It enforces a consistent [Crystal code style ](https://crystal-lang.org/docs/conventions/coding_style.html ),
also catches code smells and wrong code constructions.
## How it works
2017-11-17 18:58:52 +00:00
Ameba's *"fingerlike projections"* are [rules ](src/ameba/rule/ ). Each rule makes the inspection for that or
2017-11-17 18:28:45 +00:00
another problem in the source code. Currently rules are able to:
- [x] simply validate lines of source code
- [x] traverse AST using [`Crystal::Visitor` ](https://github.com/crystal-lang/crystal/blob/1f3e8b0e742b55c1feb5584dc932e87034365f48/src/compiler/crystal/syntax/visitor.cr )
- [x] tokenize sources using [`Crystal::Lexer` ](https://github.com/crystal-lang/crystal/blob/1f3e8b0e742b55c1feb5584dc932e87034365f48/src/compiler/crystal/syntax/lexer.cr ) and iterate through tokens
- [ ] do semantics analysis using [`Crystal::SemanticVisitor` ](https://github.com/crystal-lang/crystal/blob/master/src/compiler/crystal/semantic/semantic_visitor.cr )
2017-11-01 17:14:38 +00:00
2017-10-26 16:46:58 +00:00
## Installation
2017-11-14 18:52:15 +00:00
### As a project dependency:
2017-10-26 16:46:58 +00:00
Add this to your application's `shard.yml` :
```yaml
2017-10-26 17:47:42 +00:00
development_dependencies:
2017-10-26 16:46:58 +00:00
ameba:
2017-10-26 17:47:42 +00:00
github: veelenga/ameba
2017-10-26 16:46:58 +00:00
```
2017-11-16 08:18:11 +00:00
Build `bin/ameba` binary within your project directory while running `crystal deps` .
2017-11-17 18:28:45 +00:00
You may also want to use it on [Travis ](travis-ci.org ):
2017-11-16 08:18:11 +00:00
```yaml
2017-11-17 18:28:45 +00:00
# .travis.yml
2017-11-16 08:18:11 +00:00
language: crystal
install:
- crystal deps
script:
- crystal spec
- bin/ameba
```
2017-11-14 18:52:15 +00:00
2017-11-17 18:58:52 +00:00
Using this config Ameba will inspect files just after the specs run. Travis will also fail
2017-11-17 18:28:45 +00:00
the build if some problems detected.
2017-11-14 18:52:15 +00:00
### OS X
2017-11-14 23:02:07 +00:00
```sh
2017-11-14 18:52:15 +00:00
$ brew tap veelenga/tap
$ brew install ameba
```
### From sources
2017-10-26 16:46:58 +00:00
2017-11-14 23:02:07 +00:00
```sh
2017-11-14 18:52:15 +00:00
$ git clone https://github.com/veelenga/ameba & & cd ameba
$ make install
```
2017-10-26 16:46:58 +00:00
2017-11-01 17:14:38 +00:00
## Usage
2017-11-14 07:24:36 +00:00
Run `ameba` binary within your project directory to catch code issues:
2017-10-26 16:46:58 +00:00
2017-11-17 18:28:45 +00:00
```
2017-11-01 17:14:38 +00:00
$ ameba
2017-11-07 21:07:25 +00:00
Inspecting 52 files.
2017-10-26 21:01:23 +00:00
2017-11-07 21:07:25 +00:00
.........................F.......F........F.........
2017-10-26 21:01:23 +00:00
2017-11-07 21:07:25 +00:00
src/ameba/ast/traverse.cr:27:5
PredicateName: Favour method name 'node?' over 'is_node?'
2017-10-26 21:01:23 +00:00
2017-11-07 21:07:25 +00:00
src/ameba/rules/empty_expression.cr:42:7
LiteralInCondition: Literal value found in conditional
2017-10-26 21:01:23 +00:00
2017-11-07 21:07:25 +00:00
src/ameba/rules/empty_expression.cr:30:7
2017-10-31 20:11:49 +00:00
UnlessElse: Favour if over unless with else
2017-11-07 21:07:25 +00:00
Finished in 10.53 milliseconds
52 inspected, 3 failures.
2017-10-26 21:01:23 +00:00
```
2017-11-14 07:24:36 +00:00
## Configuration
2017-11-17 18:28:45 +00:00
Default configuration file is `.ameba.yml` .
It allows to configure or even disable specific rules.
Simply copy and adjust [existed sample ](config/ameba.yml ).
Each rule is enabled by default, even if you remove it from the config file.
2017-11-14 07:24:36 +00:00
2017-11-17 18:28:45 +00:00
## Writing a new Rule
2017-11-01 17:14:38 +00:00
2017-11-22 06:44:29 +00:00
Adding a new rule is as simple as inheriting from `Ameba::Rule::Base` struct and implementing
a logic to detect a problem in the source file:
2017-10-26 16:46:58 +00:00
2017-11-01 17:14:38 +00:00
```crystal
2017-11-22 06:44:29 +00:00
struct MySuperRule < Ameba::Rule::Base
2017-11-01 17:14:38 +00:00
# This is a required method to be implemented by the rule.
2017-11-22 06:44:29 +00:00
# Source will be passed here. If rule detects an issue in the source,
# it reports an error:
#
# source.error rule, location, message
2017-11-01 17:14:38 +00:00
#
def test(source)
2017-11-22 06:44:29 +00:00
# TODO: test source
2017-11-01 17:14:38 +00:00
end
2017-11-22 06:44:29 +00:00
end
2017-11-01 17:14:38 +00:00
2017-11-22 06:44:29 +00:00
```
2017-11-01 17:14:38 +00:00
2017-11-22 06:44:29 +00:00
As soon as a custom rule is defined, it becomes available in a full set of rules
executed by default and also can be configured via config file:
2017-11-01 17:14:38 +00:00
2017-11-22 06:44:29 +00:00
```yaml
MySuperRule:
Enabled: false
2017-11-01 17:14:38 +00:00
```
2017-10-26 16:46:58 +00:00
2017-11-17 18:28:45 +00:00
## Credits & inspirations
- [Crystal Language ](crystal-lang.org )
- [Rubocop ](http://rubocop.readthedocs.io/en/latest/ )
- [Credo ](http://credo-ci.org/ )
- [Dogma ](https://github.com/lpil/dogma )
2017-10-26 16:46:58 +00:00
## Contributors
2017-10-26 17:47:42 +00:00
- [veelenga ](https://github.com/veelenga ) Vitalii Elenhaupt - creator, maintainer