code complexity metrics visualization and exploration tool for ruby and javascript
Ruby
409
400 commits
updated Sep 22, 2026

If you are looking for a managed solution to observe your code's quality, check out UseAttractor
Many authors (Michael Feathers, Sandi Metz) have shown that an evaluation of churn vs complexity of files in software projects provide a valuable metric towards code quality. This is another take on the matter, for ruby code, using the churn and flog projects.
Here's an article on medium explaining the approach in greater detail.
Attractor's installation is standard for a Ruby gem:
gem install attractor
You'll also want to install some plugins to go along with the main gem:
gem install attractor-ruby # https://github.com/julianrubisch/attractor-ruby
gem install attractor-javascript # https://github.com/julianrubisch/attractor-javascript
gem install attractor-swift # https://github.com/julianrubisch/attractor-swift (needs uv or lizard)
You will most likely want to install Attractor using Bundler:
gem 'attractor'
gem 'attractor-ruby'
gem 'attractor-javascript'
gem 'attractor-swift'
And then execute:
bundle
To create a HTML report in attractor_output/index.html:
attractor report
If you'd like to specify a directory, use the file prefix option:
attractor report --file_prefix app/models
Or shorter:
attractor report -p app/models
Check JavaScript:
attractor report -p app/javascript -t js
Watch for file changes:
attractor report -p app/models --watch
Serve at http://localhost:7890:
attractor serve -p app/models
Enable rack-livereload:
attractor serve -p app/models --watch
Make sure you prefix these commands with bundle exec if you are using Bundler.
If you have guard-livereload (or a similar service) running on your project, you can leverage the hot reloading functionality by specifying --watch|-w. Attractor will then live-reload the browser window when a file watched by guard-livereload changes.
To use this CLI in a CI environment, use the --ci option, which will suppress automatic opening of a browser window.
There is a dedicated Github Action that will compile Attractor's output.
You can quickly integrate it into your action's workflow by grabbing it on the Marketplace.
The simplest use case is to store the attractor_output directory as an artifact.
attractor:
stage: your-stage-label
image: ruby:latest
script:
- gem install attractor
- attractor report --ci
artifacts:
when: on_success
paths:
- attractor_output
Attractor can read defaults from an .attractor.yml file in the repository root. This keeps project-specific settings in version control and avoids repeating flags on every command.
report:
app_root: app # maps to --file_prefix
minimum_churn: 3
ignore: "vendor,node_modules"
start_ago: 2y
skip:
includes: ["wip"] # CI-only for now
branches:
only: [main] # CI-only for now
except: [gh-pages] # CI-only for now
Values under report are picked up by all CLI commands. Explicit CLI flags always override the config file. The skip and branches keys are reserved for CI/SaaS usage and are currently ignored by the CLI.
You can also point to a custom config path:
attractor report --config path/to/attractor.yml
Initialize the local cache:
attractor init
--file_prefix|-p app/models
--type|-t rb|js
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--config path/to/.attractor.yml
Print a simple output to console:
attractor calc
--file_prefix|-p app/models
--type|-t rb|js
--watch|-w
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--files 'app/models/user.rb,app/models/post.rb' # restrict to an explicit list of paths
--files - # read newline-separated paths from stdin
--config path/to/.attractor.yml
Calculate the complexity delta between two git refs:
attractor diff
--base main
--head HEAD
--file_prefix|-p app/models
--type|-t rb|js
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--files 'app/models/user.rb,app/models/post.rb'
--files -
--format|-f table|markdown|json
--config path/to/.attractor.yml
The markdown format produces a PR/MR-ready summary with Stats, Trends, and To-dos sections, followed by the full per-file table wrapped in a collapsible <details> block. Pipe it into a GitHub or GitLab comment:
attractor diff --base main --head HEAD --format markdown | gh pr comment 123 --body-file -
attractor diff --base main --head HEAD --format markdown | glab mr note 45 --message "$(cat)"
Generate a full report
attractor report
--file_prefix|-p app/models
--type|-t rb|js
--watch|-w
--no-open-browser|--ci
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--files 'app/models/user.rb,app/models/post.rb'
--files -
--config path/to/.attractor.yml
Serve the output on http://localhost:7890
attractor serve
--file_prefix|-p app/models
--watch|-w
--no-open-browser|--ci
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--config path/to/.attractor.yml
Clear the local cache:
attractor clean
After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.
To run all tests, run bin/test. You can run the specs by themselves with bundle exec rspec, and the cucumber features with bundle exec cucumber.
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.
Bug reports and pull requests are welcome on GitHub.
Black Hole by Eynav Raphael from the Noun Project
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
359 commits
12 commits
12 commits
6 commits
Ruby
68.5%
JavaScript
23.5%
SCSS
4.5%
Gherkin
2.5%
code complexity metrics visualization and exploration tool for ruby and javascript
Ruby
409
400 commits
updated Sep 22, 2026

If you are looking for a managed solution to observe your code's quality, check out UseAttractor
Many authors (Michael Feathers, Sandi Metz) have shown that an evaluation of churn vs complexity of files in software projects provide a valuable metric towards code quality. This is another take on the matter, for ruby code, using the churn and flog projects.
Here's an article on medium explaining the approach in greater detail.
Attractor's installation is standard for a Ruby gem:
gem install attractor
You'll also want to install some plugins to go along with the main gem:
gem install attractor-ruby # https://github.com/julianrubisch/attractor-ruby
gem install attractor-javascript # https://github.com/julianrubisch/attractor-javascript
gem install attractor-swift # https://github.com/julianrubisch/attractor-swift (needs uv or lizard)
You will most likely want to install Attractor using Bundler:
gem 'attractor'
gem 'attractor-ruby'
gem 'attractor-javascript'
gem 'attractor-swift'
And then execute:
bundle
To create a HTML report in attractor_output/index.html:
attractor report
If you'd like to specify a directory, use the file prefix option:
attractor report --file_prefix app/models
Or shorter:
attractor report -p app/models
Check JavaScript:
attractor report -p app/javascript -t js
Watch for file changes:
attractor report -p app/models --watch
Serve at http://localhost:7890:
attractor serve -p app/models
Enable rack-livereload:
attractor serve -p app/models --watch
Make sure you prefix these commands with bundle exec if you are using Bundler.
If you have guard-livereload (or a similar service) running on your project, you can leverage the hot reloading functionality by specifying --watch|-w. Attractor will then live-reload the browser window when a file watched by guard-livereload changes.
To use this CLI in a CI environment, use the --ci option, which will suppress automatic opening of a browser window.
There is a dedicated Github Action that will compile Attractor's output.
You can quickly integrate it into your action's workflow by grabbing it on the Marketplace.
The simplest use case is to store the attractor_output directory as an artifact.
attractor:
stage: your-stage-label
image: ruby:latest
script:
- gem install attractor
- attractor report --ci
artifacts:
when: on_success
paths:
- attractor_output
Attractor can read defaults from an .attractor.yml file in the repository root. This keeps project-specific settings in version control and avoids repeating flags on every command.
report:
app_root: app # maps to --file_prefix
minimum_churn: 3
ignore: "vendor,node_modules"
start_ago: 2y
skip:
includes: ["wip"] # CI-only for now
branches:
only: [main] # CI-only for now
except: [gh-pages] # CI-only for now
Values under report are picked up by all CLI commands. Explicit CLI flags always override the config file. The skip and branches keys are reserved for CI/SaaS usage and are currently ignored by the CLI.
You can also point to a custom config path:
attractor report --config path/to/attractor.yml
Initialize the local cache:
attractor init
--file_prefix|-p app/models
--type|-t rb|js
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--config path/to/.attractor.yml
Print a simple output to console:
attractor calc
--file_prefix|-p app/models
--type|-t rb|js
--watch|-w
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--files 'app/models/user.rb,app/models/post.rb' # restrict to an explicit list of paths
--files - # read newline-separated paths from stdin
--config path/to/.attractor.yml
Calculate the complexity delta between two git refs:
attractor diff
--base main
--head HEAD
--file_prefix|-p app/models
--type|-t rb|js
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--files 'app/models/user.rb,app/models/post.rb'
--files -
--format|-f table|markdown|json
--config path/to/.attractor.yml
The markdown format produces a PR/MR-ready summary with Stats, Trends, and To-dos sections, followed by the full per-file table wrapped in a collapsible <details> block. Pipe it into a GitHub or GitLab comment:
attractor diff --base main --head HEAD --format markdown | gh pr comment 123 --body-file -
attractor diff --base main --head HEAD --format markdown | glab mr note 45 --message "$(cat)"
Generate a full report
attractor report
--file_prefix|-p app/models
--type|-t rb|js
--watch|-w
--no-open-browser|--ci
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--files 'app/models/user.rb,app/models/post.rb'
--files -
--config path/to/.attractor.yml
Serve the output on http://localhost:7890
attractor serve
--file_prefix|-p app/models
--watch|-w
--no-open-browser|--ci
--start_ago|-s (e.g. 5y, 3m, 7w)
--minimum_churn|-c (minimum times a file must have changed to be processed)
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
--config path/to/.attractor.yml
Clear the local cache:
attractor clean
After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.
To run all tests, run bin/test. You can run the specs by themselves with bundle exec rspec, and the cucumber features with bundle exec cucumber.
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.
Bug reports and pull requests are welcome on GitHub.
Black Hole by Eynav Raphael from the Noun Project
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
359 commits
12 commits
12 commits
6 commits
Ruby
68.5%
JavaScript
23.5%
SCSS
4.5%
Gherkin
2.5%