|
| 1 | +# Style gate for the SDK, added long after the code — so this file calibrates the cops to |
| 2 | +# the style the code already uses consistently, and leaves enabled only the ones that say |
| 3 | +# something. A linter that fights the codebase teaches people to ignore it. |
| 4 | +# |
| 5 | +# Every relaxation below is a decision with a reason. The cops NOT listed are on. |
| 6 | +require: |
| 7 | + - rubocop-rspec |
| 8 | + |
| 9 | +AllCops: |
| 10 | + # The plugin nudge is noise in CI output; the extensions we want are in the Gemfile. |
| 11 | + SuggestExtensions: false |
| 12 | + # Matches the gemspec, which is the contract — not the newest thing that happens to work. |
| 13 | + TargetRubyVersion: 3.0 |
| 14 | + NewCops: enable |
| 15 | + Exclude: |
| 16 | + - "vendor/**/*" |
| 17 | + - "tmp/**/*" |
| 18 | + # A build script that writes SDK files: not shipped, and shaped by what it emits. |
| 19 | + - "gen/**/*" |
| 20 | + |
| 21 | +# The project writes double quotes everywhere, deliberately and without exception. Rubocop |
| 22 | +# defaults to single; following the default would have rewritten 1139 strings to settle a |
| 23 | +# preference the project had already settled. |
| 24 | +Style/StringLiterals: |
| 25 | + EnforcedStyle: double_quotes |
| 26 | + |
| 27 | +# Hashes are aligned in columns where that makes a literal readable (a table of chain → |
| 28 | +# address) and key-aligned elsewhere. Both are intentional, so both are allowed. |
| 29 | +Layout/HashAlignment: |
| 30 | + EnforcedColonStyle: |
| 31 | + - key |
| 32 | + - table |
| 33 | + EnforcedHashRocketStyle: |
| 34 | + - key |
| 35 | + - table |
| 36 | + |
| 37 | +# An rspec `describe` is a block, and a long one is a well-covered subject rather than a |
| 38 | +# smell. Same for the gemspec. |
| 39 | +Metrics/BlockLength: |
| 40 | + # 30, for the HTTP retry loop: one `loop do` that owns attempt counting, backoff, the |
| 41 | + # Retry-After honouring and cancellation. Splitting it would hide the sequence. |
| 42 | + Max: 30 |
| 43 | + Exclude: |
| 44 | + - "spec/**/*" |
| 45 | + - "*.gemspec" |
| 46 | + |
| 47 | +# The SDK's shape sets these, not a preference: a resource method mirrors an endpoint, so a |
| 48 | +# request builder with eight optional filters has eight parameters, and splitting it into |
| 49 | +# objects would make the SDK less like the API it wraps. |
| 50 | +Metrics/ParameterLists: |
| 51 | + Max: 10 |
| 52 | + CountKeywordArgs: false |
| 53 | + |
| 54 | +# Signing and error decoding are long by nature: a single EIP-712 payload or a revert |
| 55 | +# decoder is one idea that happens to take thirty lines, and cutting it into named halves |
| 56 | +# that are each called once would spread it rather than simplify it. |
| 57 | +Metrics/MethodLength: |
| 58 | + Max: 30 |
| 59 | +Metrics/AbcSize: |
| 60 | + Max: 25 |
| 61 | +Metrics/CyclomaticComplexity: |
| 62 | + Max: 12 |
| 63 | +Metrics/PerceivedComplexity: |
| 64 | + Max: 12 |
| 65 | +Metrics/ClassLength: |
| 66 | + Max: 250 |
| 67 | +Metrics/ModuleLength: |
| 68 | + Max: 250 |
| 69 | + Exclude: |
| 70 | + - "spec/**/*" |
| 71 | + |
| 72 | +# Chain ids and amounts are written the way they appear on chain and in the gateway's |
| 73 | +# seeds — 84532, not 84_532 — so a value can be grepped across repos. |
| 74 | +Style/NumericLiterals: |
| 75 | + Enabled: false |
| 76 | + |
| 77 | +# A spec's `let` blocks legitimately define constants for the example group. |
| 78 | +Lint/ConstantDefinitionInBlock: |
| 79 | + Exclude: |
| 80 | + - "spec/**/*" |
| 81 | + |
| 82 | +# Documentation is in prose above the interesting methods, not as a mandatory class banner. |
| 83 | +Style/Documentation: |
| 84 | + Enabled: false |
| 85 | + |
| 86 | +# RSpec's own opinions about example length and count say nothing about whether the tests |
| 87 | +# are good; the ones about structure are kept. |
| 88 | +RSpec/ExampleLength: |
| 89 | + Enabled: false |
| 90 | +RSpec/MultipleExpectations: |
| 91 | + Enabled: false |
| 92 | +RSpec/NestedGroups: |
| 93 | + Max: 4 |
| 94 | + |
| 95 | +# ── RSpec structure: the project's, not the plugin's ───────────────────────── |
| 96 | +# The specs name the class under test explicitly. `described_class` saves a line and costs |
| 97 | +# a reader the answer to "what is this testing?" — worth it in a long file, not in these. |
| 98 | +RSpec/DescribedClass: |
| 99 | + Enabled: false |
| 100 | + |
| 101 | +# The spec directory is FLAT (client_spec.rb, signing_spec.rb, analytics_spec.rb) and mirrors |
| 102 | +# the SDK's surface rather than its file tree, so a reader looking for "how do I use |
| 103 | +# analytics" finds one file. Requiring spec/rail0/resources/analytics_spec.rb would nest |
| 104 | +# every file one deep to satisfy a naming rule. |
| 105 | +RSpec/SpecFilePathFormat: |
| 106 | + Enabled: false |
| 107 | + |
| 108 | +# Some specs describe a behaviour rather than a class — the load path, the default logger's |
| 109 | +# output — and naming a string subject is the honest way to say so. |
| 110 | +RSpec/DescribeClass: |
| 111 | + Enabled: false |
| 112 | + |
| 113 | +# A constant inside an example group is scoped to that group by intent: a fixture address or |
| 114 | +# a payload shape belongs to the examples that use it, not to the file. |
| 115 | +RSpec/LeakyConstantDeclaration: |
| 116 | + Exclude: |
| 117 | + - "spec/**/*" |
| 118 | + |
| 119 | +# One file per subject, and a subject can have two aspects worth their own describe. |
| 120 | +RSpec/MultipleDescribes: |
| 121 | + Enabled: false |
| 122 | + |
| 123 | +# `x.zero?` RAISES on nil where `x == 0` does not, and both places this cop rewrote compare |
| 124 | +# an OPTIONAL value: `chain_id` is nil when the caller wants every chain. The autocorrection |
| 125 | +# turned two nil-safe guards into NoMethodError, which six specs caught — the cop is right |
| 126 | +# about style and wrong about this code. |
| 127 | +Style/NumericPredicate: |
| 128 | + Enabled: false |
| 129 | + |
| 130 | +# Off, because neither style is right for this code: the numbers in these names are PROTOCOL |
| 131 | +# identifiers, and each protocol has its own conventional spelling — `retry_on_429` for the |
| 132 | +# HTTP status, `eip712` and `secp256k1` for the standards, which is how they are written |
| 133 | +# everywhere including their own specifications. Enforcing either style renames the other |
| 134 | +# half, and the name is carrying the protocol, not a counter. |
| 135 | +Naming/VariableNumber: |
| 136 | + Enabled: false |
| 137 | + |
| 138 | +# 120, with three kinds of exception — and ONE block, because a second `Layout/LineLength:` |
| 139 | +# key silently replaces the first in YAML rather than merging with it. |
| 140 | +# |
| 141 | +# - comments: a usage example a reader can copy is worth more than a wrap, and wrapping a |
| 142 | +# one-line `client.payments.create(...)` makes it uncopyable; |
| 143 | +# - data tables: stablecoins, error hints and type aliases are one row per line by design, |
| 144 | +# and a table is easier to scan than the same rows folded; |
| 145 | +# - specs: a stub URL or an expected payload wrapped across lines is harder to read than |
| 146 | +# the long line it came from. |
| 147 | +Layout/LineLength: |
| 148 | + Max: 120 |
| 149 | + AllowedPatterns: |
| 150 | + - "^\\s*#" |
| 151 | + Exclude: |
| 152 | + - "lib/rail0/stablecoins.rb" |
| 153 | + - "lib/rail0/error_hints.rb" |
| 154 | + - "lib/rail0/types.rb" |
| 155 | + - "spec/**/*" |
| 156 | + |
| 157 | +# The HTTP layer's send-and-retry path: the branching IS the feature (status classes, retry |
| 158 | +# budgets, Retry-After, cancellation), and splitting it into halves each called once would |
| 159 | +# spread the logic rather than reduce it. |
| 160 | +Metrics/AbcSize: |
| 161 | + Max: 40 |
0 commit comments