{"id":33916671,"url":"https://github.com/unurgunite/rubocop-sorted_methods_by_call","last_synced_at":"2026-01-16T06:54:53.776Z","repository":{"id":115935342,"uuid":"567789714","full_name":"unurgunite/rubocop-sorted_methods_by_call","owner":"unurgunite","description":"RuboCop extension for method sorting in AST by stack trace.","archived":false,"fork":false,"pushed_at":"2025-11-12T15:14:48.000Z","size":55,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-04T19:40:37.819Z","etag":null,"topics":["ast","rubocop","ruby"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/rubocop-sorted_methods_by_call","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unurgunite.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-11-18T15:28:04.000Z","updated_at":"2025-11-14T06:24:21.000Z","dependencies_parsed_at":"2023-03-10T21:01:30.877Z","dependency_job_id":null,"html_url":"https://github.com/unurgunite/rubocop-sorted_methods_by_call","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/unurgunite/rubocop-sorted_methods_by_call","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Frubocop-sorted_methods_by_call","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Frubocop-sorted_methods_by_call/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Frubocop-sorted_methods_by_call/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Frubocop-sorted_methods_by_call/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unurgunite","download_url":"https://codeload.github.com/unurgunite/rubocop-sorted_methods_by_call/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unurgunite%2Frubocop-sorted_methods_by_call/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27678877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-12T02:00:06.775Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ast","rubocop","ruby"],"created_at":"2025-12-12T07:26:57.554Z","updated_at":"2026-01-16T06:54:53.765Z","avatar_url":"https://github.com/unurgunite.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RuboCop::SortedMethodsByCall\n\n![Repobeats](https://repobeats.axiom.co/api/embed/7926fec94bffd7fcaa69700fb9464ed96cf69083.svg \"Repobeats analytics image\")\n[![CI](https://github.com/unurgunite/rubocop-sorted_methods_by_call/actions/workflows/ci.yml/badge.svg)](https://github.com/unurgunite/rubocop-sorted_methods_by_call/actions)\n[![Gem Version](https://badge.fury.io/rb/rubocop-sorted_methods_by_call.svg)](https://rubygems.org/gems/rubocop-sorted_methods_by_call)\n\n**Enforces \"waterfall\" method ordering**: define methods *after* any method that calls them within the same scope.\n\n* [RuboCop::SortedMethodsByCall](#rubocopsortedmethodsbycall)\n    * [Features](#features)\n    * [Installation](#installation)\n    * [Configuration](#configuration)\n        * [Basic Setup](#basic-setup)\n        * [Configuration Options](#configuration-options)\n    * [Usage Examples](#usage-examples)\n        * [Good Code (waterfall order)](#good-code-waterfall-order)\n        * [Bad Code (violates waterfall order)](#bad-code-violates-waterfall-order)\n        * [Sibling ordering and cycles (why autocorrect can be skipped)](#sibling-ordering-and-cycles-why-autocorrect-can-be-skipped)\n        * [Autocorrection](#autocorrection)\n    * [Testing](#testing)\n    * [Development](#development)\n        * [Available Commands](#available-commands)\n        * [Release Process](#release-process)\n    * [Requirements](#requirements)\n    * [Contributing](#contributing)\n    * [Documentation](#documentation)\n    * [License](#license)\n    * [Code of Conduct](#code-of-conduct)\n\n## Features\n\n- **Waterfall ordering enforcement**: Caller methods must be defined before their callees;\n- **Smart visibility handling**: Respects `private`/`protected`/`public` sections;\n- **Safe mutual recursion**: Handles recursive method calls gracefully;\n- **Autocorrection support**: Automatically reorders methods (opt-in with `-A`);\n- **Full RuboCop integration**: Works seamlessly with modern RuboCop plugin system;\n- **Comprehensive scope support**: Classes, modules, singleton classes, and top-level;\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'rubocop-sorted_methods_by_call'\n```\n\nAnd then execute:\n\n```bash\nbundle install\n```\n\nOr install it yourself:\n\n```bash\ngem install rubocop-sorted_methods_by_call\n```\n\n## Configuration\n\n### Basic Setup\n\nAdd to your `.rubocop.yml`:\n\n```yaml\nplugins:\n  - rubocop-sorted_methods_by_call\n\nSortedMethodsByCall/Waterfall:\n  Enabled: true\n```\n\n### Configuration Options\n\n```yaml\nSortedMethodsByCall/Waterfall:\n  Enabled: true\n  SafeAutoCorrect: false          # Autocorrection requires -A flag\n  AllowedRecursion: true          # Allow mutual recursion (default: true)\n  # If true, the cop will NOT add \"called together\" sibling-order edges\n  # that would introduce a cycle with existing constraints. This reduces\n  # impossible-to-fix sibling offenses and makes autocorrect more reliable.\n  #\n  # Default: false\n  SkipCyclicSiblingEdges: false\n```\n\n## Usage Examples\n\n### Good Code (waterfall order)\n\nIn waterfall ordering, **callers come before callees**. This creates a top-down reading flow where main logic appears\nbefore implementation details.\n\n```ruby\n\nclass Service\n  def call\n    foo\n    bar\n  end\n\n  private\n\n  def bar\n    method123\n  end\n\n  def method123\n    foo\n  end\n\n  def foo\n    123\n  end\nend\n```\n\n### Bad Code (violates waterfall order)\n\n```ruby\n\nclass Service\n  def call\n    foo\n    bar\n  end\n\n  private\n\n  def foo # ❌ Offense: Define #foo after its caller #method123\n    123\n  end\n\n  def bar\n    method123\n  end\n\n  def method123\n    foo\n  end\nend\n```\n\n### Sibling ordering and cycles (why autocorrect can be skipped)\n\n`SortedMethodsByCall/Waterfall` enforces two kinds of ordering constraints:\n\n1. **Direct call edges**: if `caller` calls `callee`, then `caller` must be defined **before** `callee`.\n2. **Sibling (\"called together\") edges**: in orchestration methods (methods not called by others in the same scope),\n   consecutive calls imply an intended order (e.g., `a` then `b`), so `a` should be defined before `b`.\n\nSometimes these constraints can conflict and create a **cycle**, which means there is no valid ordering that satisfies\nall constraints. In this situation, autocorrect may be skipped.\n\nExample:\n\n```ruby\nclass SiblingCycleExample\n  def call\n    a\n    b\n  end\n\n  private\n\n  def b\n    c\n  end\n\n  def c\n    a\n  end\n\n  def a; end\nend\n```\n\nHere, the direct dependencies imply `b -\u003e c -\u003e a`, but the orchestration method implies `a -\u003e b`,\nwhich forms the cycle `a -\u003e b -\u003e c -\u003e a`.\n\nIf you prefer to keep the warning (to encourage refactoring), leave `SkipCyclicSiblingEdges: false`.\nIf you prefer the cop to avoid enforcing sibling edges that create cycles, set `SkipCyclicSiblingEdges: true`.\n\n### Autocorrection\n\nRun with unsafe autocorrection to automatically fix violations:\n\n```bash\nbundle exec rubocop -A\n```\n\nThis will reorder the methods while preserving comments and visibility modifiers.\n\n## Testing\n\nRun the test suite:\n\n```bash\nbundle exec rspec\n```\n\nRun RuboCop on the gem itself:\n\n```bash\nbundle exec rubocop\nbundle exec rubocop --config test_project/.rubocop.test.yml lib/ -A\n```\n\n## Development\n\nAfter checking out the repo, run:\n\n```bash\nbin/setup\n```\n\nThis will install dependencies and start an interactive console.\n\n### Available Commands\n\n- `bin/console` - Interactive development console\n- `bin/setup` - Install dependencies and build gem\n- `bundle exec rake` - Run tests and linting\n\n### Release Process\n\n1. Update version in `lib/rubocop/sorted_methods_by_call/version.rb`\n2. Create and push a git tag: `git tag v0.1.0 \u0026\u0026 git push origin v0.1.0`\n3. GitHub Actions will automatically:\n    - Build the gem\n    - Publish to RubyGems.org\n    - Create a GitHub release\n\n## Requirements\n\n- **Ruby**: \u003e= 2.7\n- **RuboCop**: \u003e= 1.72.0 (required for plugin system)\n\n## Contributing\n\nBug reports and pull requests are welcome! Please follow these guidelines:\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -am 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a pull request\n\nPlease ensure your code passes all tests and follows the existing style.\n\n## Documentation\n\nCode is covered with YARD docs, you can access online docs\nat https://unurgunite.github.io/rubocop-sorted_methods_by_call_docs/\n\n## License\n\nThe gem is available as open source under the terms of MIT License.\n\n## Code of Conduct\n\nEveryone interacting with this project is expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md).\n\n---\n\n\u003e **Note**: This gem implements **true waterfall ordering** that considers the complete call graph across all methods in\n\u003e a scope. Methods are ordered so that every callee appears after all of its callers, creating a natural top-down\n\u003e reading flow.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funurgunite%2Frubocop-sorted_methods_by_call","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funurgunite%2Frubocop-sorted_methods_by_call","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funurgunite%2Frubocop-sorted_methods_by_call/lists"}