├── .gitignore ├── .rubocop.yml ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── examples └── getting_started.rb ├── exponent-server-sdk.gemspec ├── lib ├── exponent-server-sdk.rb └── exponent-server-sdk │ ├── too_many_messages_error.rb │ └── version.rb └── test └── exponent-server-sdk-test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | *.log 19 | .ruby-version 20 | /.idea 21 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | RubyInterpreters: 3 | - ruby 4 | - macruby 5 | - rake 6 | - jruby 7 | - rbx 8 | # Include common Ruby source files. 9 | Include: 10 | - "**/*.rb" 11 | - "**/*.arb" 12 | - "**/*.axlsx" 13 | - "**/*.builder" 14 | - "**/*.fcgi" 15 | - "**/*.gemfile" 16 | - "**/*.gemspec" 17 | - "**/*.god" 18 | - "**/*.jb" 19 | - "**/*.jbuilder" 20 | - "**/*.mspec" 21 | - "**/*.opal" 22 | - "**/*.pluginspec" 23 | - "**/*.podspec" 24 | - "**/*.rabl" 25 | - "**/*.rake" 26 | - "**/*.rbuild" 27 | - "**/*.rbw" 28 | - "**/*.rbx" 29 | - "**/*.ru" 30 | - "**/*.ruby" 31 | - "**/*.spec" 32 | - "**/*.thor" 33 | - "**/*.watchr" 34 | - "**/.irbrc" 35 | - "**/.pryrc" 36 | - "**/buildfile" 37 | - "**/Appraisals" 38 | - "**/Berksfile" 39 | - "**/Brewfile" 40 | - "**/Buildfile" 41 | - "**/Capfile" 42 | - "**/Cheffile" 43 | - "**/Dangerfile" 44 | - "**/Deliverfile" 45 | - "**/Fastfile" 46 | - "**/*Fastfile" 47 | - "**/Gemfile" 48 | - "**/Guardfile" 49 | - "**/Jarfile" 50 | - "**/Mavenfile" 51 | - "**/Podfile" 52 | - "**/Puppetfile" 53 | - "**/Rakefile" 54 | - "**/Snapfile" 55 | - "**/Thorfile" 56 | - "**/Vagabondfile" 57 | - "**/Vagrantfile" 58 | Exclude: 59 | - "node_modules/**/*" 60 | - "vendor/**/*" 61 | - ".git/**/*" 62 | # Default formatter will be used if no `-f/--format` option is given. 63 | DefaultFormatter: progress 64 | # Cop names are displayed in offense messages by default. Change behavior 65 | # by overriding DisplayCopNames, or by giving the `--no-display-cop-names` 66 | # option. 67 | DisplayCopNames: true 68 | # Style guide URLs are not displayed in offense messages by default. Change 69 | # behavior by overriding `DisplayStyleGuide`, or by giving the 70 | # `-S/--display-style-guide` option. 71 | DisplayStyleGuide: false 72 | # When specifying style guide URLs, any paths and/or fragments will be 73 | # evaluated relative to the base URL. 74 | StyleGuideBaseURL: https://rubystyle.guide 75 | # Extra details are not displayed in offense messages by default. Change 76 | # behavior by overriding ExtraDetails, or by giving the 77 | # `-E/--extra-details` option. 78 | ExtraDetails: false 79 | # Additional cops that do not reference a style guide rule may be enabled by 80 | # default. Change behavior by overriding `StyleGuideCopsOnly`, or by giving 81 | # the `--only-guide-cops` option. 82 | StyleGuideCopsOnly: false 83 | # All cops except the ones configured `Enabled: false` in this file are enabled by default. 84 | # Change this behavior by overriding either `DisabledByDefault` or `EnabledByDefault`. 85 | # When `DisabledByDefault` is `true`, all cops in the default configuration 86 | # are disabled, and only cops in user configuration are enabled. This makes 87 | # cops opt-in instead of opt-out. Note that when `DisabledByDefault` is `true`, 88 | # cops in user configuration will be enabled even if they don't set the 89 | # Enabled parameter. 90 | # When `EnabledByDefault` is `true`, all cops, even those configured `Enabled: false` 91 | # in this file are enabled by default. Cops can still be disabled in user configuration. 92 | # Note that it is invalid to set both EnabledByDefault and DisabledByDefault 93 | # to true in the same configuration. 94 | EnabledByDefault: false 95 | DisabledByDefault: false 96 | # Enables the result cache if `true`. Can be overridden by the `--cache` command 97 | # line option. 98 | UseCache: true 99 | # Threshold for how many files can be stored in the result cache before some 100 | # of the files are automatically removed. 101 | MaxFilesInCache: 20000 102 | # The cache will be stored in "rubocop_cache" under this directory. If 103 | # CacheRootDirectory is ~ (nil), which it is by default, the root will be 104 | # taken from the environment variable `$XDG_CACHE_HOME` if it is set, or if 105 | # `$XDG_CACHE_HOME` is not set, it will be `$HOME/.cache/`. 106 | CacheRootDirectory: ~ 107 | # It is possible for a malicious user to know the location of RuboCop's cache 108 | # directory by looking at CacheRootDirectory, and create a symlink in its 109 | # place that could cause RuboCop to overwrite unintended files, or read 110 | # malicious input. If you are certain that your cache location is secure from 111 | # this kind of attack, and wish to use a symlinked cache location, set this 112 | # value to "true". 113 | AllowSymlinksInCacheRootDirectory: false 114 | # What MRI version of the Ruby interpreter is the inspected code intended to 115 | # run on? (If there is more than one, set this to the lowest version.) 116 | # If a value is specified for TargetRubyVersion then it is used. Acceptable 117 | # values are specificed as a float (i.e. 2.5); the teeny version of Ruby 118 | # should not be included. If the project specifies a Ruby version in the 119 | # .ruby-version file, Gemfile or gems.rb file, RuboCop will try to determine 120 | # the desired version of Ruby by inspecting the .ruby-version file first, 121 | # followed by the Gemfile.lock or gems.locked file. (Although the Ruby version 122 | # is specified in the Gemfile or gems.rb file, RuboCop reads the final value 123 | # from the lock file.) If the Ruby version is still unresolved, RuboCop will 124 | # use the oldest officially supported Ruby version (currently Ruby 2.3). 125 | TargetRubyVersion: ~ 126 | 127 | #################### Bundler ############################### 128 | 129 | Bundler/DuplicatedGem: 130 | Description: "Checks for duplicate gem entries in Gemfile." 131 | Enabled: true 132 | VersionAdded: "0.46" 133 | Include: 134 | - "**/*.gemfile" 135 | - "**/Gemfile" 136 | - "**/gems.rb" 137 | 138 | Bundler/GemComment: 139 | Description: "Add a comment describing each gem." 140 | Enabled: false 141 | VersionAdded: "0.59" 142 | Include: 143 | - "**/*.gemfile" 144 | - "**/Gemfile" 145 | - "**/gems.rb" 146 | IgnoredGems: [] 147 | 148 | Bundler/InsecureProtocolSource: 149 | Description: >- 150 | The source `:gemcutter`, `:rubygems` and `:rubyforge` are deprecated 151 | because HTTP requests are insecure. Please change your source to 152 | 'https://rubygems.org' if possible, or 'http://rubygems.org' if not. 153 | Enabled: true 154 | VersionAdded: "0.50" 155 | Include: 156 | - "**/*.gemfile" 157 | - "**/Gemfile" 158 | - "**/gems.rb" 159 | 160 | Bundler/OrderedGems: 161 | Description: >- 162 | Gems within groups in the Gemfile should be alphabetically sorted. 163 | Enabled: true 164 | VersionAdded: "0.46" 165 | VersionChanged: "0.47" 166 | TreatCommentsAsGroupSeparators: true 167 | Include: 168 | - "**/*.gemfile" 169 | - "**/Gemfile" 170 | - "**/gems.rb" 171 | 172 | #################### Gemspec ############################### 173 | 174 | Gemspec/DuplicatedAssignment: 175 | Description: "An attribute assignment method calls should be listed only once in a gemspec." 176 | Enabled: true 177 | VersionAdded: "0.52" 178 | Include: 179 | - "**/*.gemspec" 180 | 181 | Gemspec/OrderedDependencies: 182 | Description: >- 183 | Dependencies in the gemspec should be alphabetically sorted. 184 | Enabled: true 185 | VersionAdded: "0.51" 186 | TreatCommentsAsGroupSeparators: true 187 | Include: 188 | - "**/*.gemspec" 189 | 190 | Gemspec/RequiredRubyVersion: 191 | Description: "Checks that `required_ruby_version` of gemspec and `TargetRubyVersion` of .rubocop.yml are equal." 192 | Enabled: true 193 | VersionAdded: "0.52" 194 | Include: 195 | - "**/*.gemspec" 196 | - 197 | Gemspec/RubyVersionGlobalsUsage: 198 | Description: Checks usage of RUBY_VERSION in gemspec. 199 | Enabled: true 200 | VersionAdded: "0.72" 201 | Include: 202 | - "**/*.gemspec" 203 | 204 | #################### Layout ########################### 205 | 206 | Layout/AccessModifierIndentation: 207 | Description: Check indentation of private/protected visibility modifiers. 208 | StyleGuide: "#indent-public-private-protected" 209 | Enabled: true 210 | VersionAdded: "0.49" 211 | EnforcedStyle: indent 212 | SupportedStyles: 213 | - outdent 214 | - indent 215 | # By default, the indentation width from Layout/IndentationWidth is used 216 | # But it can be overridden by setting this parameter 217 | IndentationWidth: ~ 218 | 219 | Layout/ArgumentAlignment: 220 | Description: >- 221 | Align the arguments of a method call if they span more 222 | than one line. 223 | StyleGuide: "#no-double-indent" 224 | Enabled: false 225 | VersionAdded: "0.68" 226 | # Alignment of arguments in multi-line method calls. 227 | # 228 | # The `with_first_argument` style aligns the following lines along the same 229 | # column as the first parameter. 230 | # 231 | # method_call(a, 232 | # b) 233 | # 234 | # The `with_fixed_indentation` style aligns the following lines with one 235 | # level of indentation relative to the start of the line with the method call. 236 | # 237 | # method_call(a, 238 | # b) 239 | EnforcedStyle: with_first_argument 240 | SupportedStyles: 241 | - with_first_argument 242 | - with_fixed_indentation 243 | # By default, the indentation width from Layout/IndentationWidth is used 244 | # But it can be overridden by setting this parameter 245 | IndentationWidth: ~ 246 | 247 | Layout/ArrayAlignment: 248 | Description: >- 249 | Align the elements of an array literal if they span more than 250 | one line. 251 | StyleGuide: "#align-multiline-arrays" 252 | Enabled: false 253 | VersionAdded: "0.49" 254 | 255 | Layout/HashAlignment: 256 | Description: >- 257 | Align the elements of a hash literal if they span more than 258 | one line. 259 | Enabled: false 260 | AllowMultipleStyles: true 261 | VersionAdded: "0.49" 262 | # Alignment of entries using hash rocket as separator. Valid values are: 263 | # 264 | # key - left alignment of keys 265 | # 'a' => 2 266 | # 'bb' => 3 267 | # separator - alignment of hash rockets, keys are right aligned 268 | # 'a' => 2 269 | # 'bb' => 3 270 | # table - left alignment of keys, hash rockets, and values 271 | # 'a' => 2 272 | # 'bb' => 3 273 | EnforcedHashRocketStyle: key 274 | SupportedHashRocketStyles: 275 | - key 276 | - separator 277 | - table 278 | # Alignment of entries using colon as separator. Valid values are: 279 | # 280 | # key - left alignment of keys 281 | # a: 0 282 | # bb: 1 283 | # separator - alignment of colons, keys are right aligned 284 | # a: 0 285 | # bb: 1 286 | # table - left alignment of keys and values 287 | # a: 0 288 | # bb: 1 289 | EnforcedColonStyle: key 290 | SupportedColonStyles: 291 | - key 292 | - separator 293 | - table 294 | # Select whether hashes that are the last argument in a method call should be 295 | # inspected? Valid values are: 296 | # 297 | # always_inspect - Inspect both implicit and explicit hashes. 298 | # Registers an offense for: 299 | # function(a: 1, 300 | # b: 2) 301 | # Registers an offense for: 302 | # function({a: 1, 303 | # b: 2}) 304 | # always_ignore - Ignore both implicit and explicit hashes. 305 | # Accepts: 306 | # function(a: 1, 307 | # b: 2) 308 | # Accepts: 309 | # function({a: 1, 310 | # b: 2}) 311 | # ignore_implicit - Ignore only implicit hashes. 312 | # Accepts: 313 | # function(a: 1, 314 | # b: 2) 315 | # Registers an offense for: 316 | # function({a: 1, 317 | # b: 2}) 318 | # ignore_explicit - Ignore only explicit hashes. 319 | # Accepts: 320 | # function({a: 1, 321 | # b: 2}) 322 | # Registers an offense for: 323 | # function(a: 1, 324 | # b: 2) 325 | EnforcedLastArgumentHashStyle: always_inspect 326 | SupportedLastArgumentHashStyles: 327 | - always_inspect 328 | - always_ignore 329 | - ignore_implicit 330 | - ignore_explicit 331 | 332 | Layout/ParameterAlignment: 333 | Description: >- 334 | Align the parameters of a method definition if they span more 335 | than one line. 336 | StyleGuide: "#no-double-indent" 337 | Enabled: false 338 | VersionAdded: "0.49" 339 | VersionChanged: "0.68" 340 | # Alignment of parameters in multi-line method calls. 341 | # 342 | # The `with_first_parameter` style aligns the following lines along the same 343 | # column as the first parameter. 344 | # 345 | # def method_foo(a, 346 | # b) 347 | # 348 | # The `with_fixed_indentation` style aligns the following lines with one 349 | # level of indentation relative to the start of the line with the method call. 350 | # 351 | # def method_foo(a, 352 | # b) 353 | EnforcedStyle: with_first_parameter 354 | SupportedStyles: 355 | - with_first_parameter 356 | - with_fixed_indentation 357 | # By default, the indentation width from Layout/IndentationWidth is used 358 | # But it can be overridden by setting this parameter 359 | IndentationWidth: ~ 360 | 361 | Layout/BlockAlignment: 362 | Description: "Align block ends correctly." 363 | Enabled: true 364 | VersionAdded: "0.53" 365 | # The value `start_of_block` means that the `end` should be aligned with line 366 | # where the `do` keyword appears. 367 | # The value `start_of_line` means it should be aligned with the whole 368 | # expression's starting line. 369 | # The value `either` means both are allowed. 370 | EnforcedStyleAlignWith: either 371 | SupportedStylesAlignWith: 372 | - either 373 | - start_of_block 374 | - start_of_line 375 | 376 | Layout/BlockEndNewline: 377 | Description: "Put end statement of multiline block on its own line." 378 | Enabled: true 379 | VersionAdded: "0.49" 380 | 381 | Layout/CaseIndentation: 382 | Description: "Indentation of when in a case/when/[else/]end." 383 | StyleGuide: "#indent-when-to-case" 384 | Enabled: true 385 | VersionAdded: "0.49" 386 | EnforcedStyle: case 387 | SupportedStyles: 388 | - case 389 | - end 390 | IndentOneStep: false 391 | # By default, the indentation width from `Layout/IndentationWidth` is used. 392 | # But it can be overridden by setting this parameter. 393 | # This only matters if `IndentOneStep` is `true` 394 | IndentationWidth: ~ 395 | 396 | Layout/ClassStructure: 397 | Description: "Enforces a configured order of definitions within a class body." 398 | StyleGuide: "#consistent-classes" 399 | Enabled: false 400 | VersionAdded: "0.52" 401 | Categories: 402 | module_inclusion: 403 | - include 404 | - prepend 405 | - extend 406 | ExpectedOrder: 407 | - module_inclusion 408 | - constants 409 | - public_class_methods 410 | - initializer 411 | - public_methods 412 | - protected_methods 413 | - private_methods 414 | 415 | Layout/ClosingHeredocIndentation: 416 | Description: "Checks the indentation of here document closings." 417 | Enabled: true 418 | VersionAdded: "0.57" 419 | 420 | Layout/ClosingParenthesisIndentation: 421 | Description: "Checks the indentation of hanging closing parentheses." 422 | Enabled: true 423 | VersionAdded: "0.49" 424 | 425 | Layout/CommentIndentation: 426 | Description: "Indentation of comments." 427 | Enabled: true 428 | VersionAdded: "0.49" 429 | 430 | Layout/ConditionPosition: 431 | Description: >- 432 | Checks for condition placed in a confusing position relative to 433 | the keyword. 434 | StyleGuide: "#same-line-condition" 435 | Enabled: true 436 | VersionAdded: "0.53" 437 | 438 | Layout/DefEndAlignment: 439 | Description: "Align ends corresponding to defs correctly." 440 | Enabled: true 441 | VersionAdded: "0.53" 442 | # The value `def` means that `end` should be aligned with the def keyword. 443 | # The value `start_of_line` means that `end` should be aligned with method 444 | # calls like `private`, `public`, etc, if present in front of the `def` 445 | # keyword on the same line. 446 | EnforcedStyleAlignWith: start_of_line 447 | SupportedStylesAlignWith: 448 | - start_of_line 449 | - def 450 | AutoCorrect: false 451 | Severity: warning 452 | 453 | Layout/DotPosition: 454 | Description: "Checks the position of the dot in multi-line method calls." 455 | StyleGuide: "#consistent-multi-line-chains" 456 | Enabled: true 457 | VersionAdded: "0.49" 458 | EnforcedStyle: leading 459 | SupportedStyles: 460 | - leading 461 | - trailing 462 | 463 | Layout/ElseAlignment: 464 | Description: "Align elses and elsifs correctly." 465 | Enabled: true 466 | VersionAdded: "0.49" 467 | 468 | Layout/EmptyComment: 469 | Description: "Checks empty comment." 470 | Enabled: true 471 | VersionAdded: "0.53" 472 | AllowBorderComment: true 473 | AllowMarginComment: true 474 | 475 | Layout/EmptyLineAfterGuardClause: 476 | Description: "Add empty line after guard clause." 477 | Enabled: true 478 | VersionAdded: "0.56" 479 | VersionChanged: "0.59" 480 | 481 | Layout/EmptyLineAfterMagicComment: 482 | Description: "Add an empty line after magic comments to separate them from code." 483 | StyleGuide: "#separate-magic-comments-from-code" 484 | Enabled: true 485 | VersionAdded: "0.49" 486 | 487 | Layout/EmptyLineBetweenDefs: 488 | Description: "Use empty lines between defs." 489 | StyleGuide: "#empty-lines-between-methods" 490 | Enabled: true 491 | VersionAdded: "0.49" 492 | # If `true`, this parameter means that single line method definitions don't 493 | # need an empty line between them. 494 | AllowAdjacentOneLineDefs: false 495 | # Can be array to specify minimum and maximum number of empty lines, e.g. [1, 2] 496 | NumberOfEmptyLines: 1 497 | 498 | Layout/EmptyLines: 499 | Description: "Don't use several empty lines in a row." 500 | StyleGuide: "#two-or-more-empty-lines" 501 | Enabled: true 502 | VersionAdded: "0.49" 503 | 504 | Layout/EmptyLinesAroundAccessModifier: 505 | Description: "Keep blank lines around access modifiers." 506 | StyleGuide: "#empty-lines-around-access-modifier" 507 | Enabled: true 508 | VersionAdded: "0.49" 509 | EnforcedStyle: around 510 | SupportedStyles: 511 | - around 512 | - only_before 513 | Reference: 514 | # A reference to `EnforcedStyle: only_before`. 515 | - https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions 516 | 517 | Layout/EmptyLinesAroundArguments: 518 | Description: "Keeps track of empty lines around method arguments." 519 | Enabled: true 520 | VersionAdded: "0.52" 521 | 522 | Layout/EmptyLinesAroundBeginBody: 523 | Description: "Keeps track of empty lines around begin-end bodies." 524 | StyleGuide: "#empty-lines-around-bodies" 525 | Enabled: true 526 | VersionAdded: "0.49" 527 | 528 | Layout/EmptyLinesAroundBlockBody: 529 | Description: "Keeps track of empty lines around block bodies." 530 | StyleGuide: "#empty-lines-around-bodies" 531 | Enabled: true 532 | VersionAdded: "0.49" 533 | EnforcedStyle: no_empty_lines 534 | SupportedStyles: 535 | - empty_lines 536 | - no_empty_lines 537 | 538 | Layout/EmptyLinesAroundClassBody: 539 | Description: "Keeps track of empty lines around class bodies." 540 | StyleGuide: "#empty-lines-around-bodies" 541 | Enabled: true 542 | VersionAdded: "0.49" 543 | VersionChanged: "0.53" 544 | EnforcedStyle: no_empty_lines 545 | SupportedStyles: 546 | - empty_lines 547 | - empty_lines_except_namespace 548 | - empty_lines_special 549 | - no_empty_lines 550 | - beginning_only 551 | - ending_only 552 | 553 | Layout/EmptyLinesAroundExceptionHandlingKeywords: 554 | Description: "Keeps track of empty lines around exception handling keywords." 555 | StyleGuide: "#empty-lines-around-bodies" 556 | Enabled: true 557 | VersionAdded: "0.49" 558 | 559 | Layout/EmptyLinesAroundMethodBody: 560 | Description: "Keeps track of empty lines around method bodies." 561 | StyleGuide: "#empty-lines-around-bodies" 562 | Enabled: true 563 | VersionAdded: "0.49" 564 | 565 | Layout/EmptyLinesAroundModuleBody: 566 | Description: "Keeps track of empty lines around module bodies." 567 | StyleGuide: "#empty-lines-around-bodies" 568 | Enabled: true 569 | VersionAdded: "0.49" 570 | EnforcedStyle: no_empty_lines 571 | SupportedStyles: 572 | - empty_lines 573 | - empty_lines_except_namespace 574 | - empty_lines_special 575 | - no_empty_lines 576 | 577 | Layout/EndAlignment: 578 | Description: "Align ends correctly." 579 | Enabled: true 580 | VersionAdded: "0.53" 581 | # The value `keyword` means that `end` should be aligned with the matching 582 | # keyword (`if`, `while`, etc.). 583 | # The value `variable` means that in assignments, `end` should be aligned 584 | # with the start of the variable on the left hand side of `=`. In all other 585 | # situations, `end` should still be aligned with the keyword. 586 | # The value `start_of_line` means that `end` should be aligned with the start 587 | # of the line which the matching keyword appears on. 588 | EnforcedStyleAlignWith: keyword 589 | SupportedStylesAlignWith: 590 | - keyword 591 | - variable 592 | - start_of_line 593 | AutoCorrect: false 594 | Severity: warning 595 | 596 | Layout/EndOfLine: 597 | Description: "Use Unix-style line endings." 598 | StyleGuide: "#crlf" 599 | Enabled: true 600 | VersionAdded: "0.49" 601 | # The `native` style means that CR+LF (Carriage Return + Line Feed) is 602 | # enforced on Windows, and LF is enforced on other platforms. The other styles 603 | # mean LF and CR+LF, respectively. 604 | EnforcedStyle: native 605 | SupportedStyles: 606 | - native 607 | - lf 608 | - crlf 609 | 610 | Layout/ExtraSpacing: 611 | Description: "Do not use unnecessary spacing." 612 | Enabled: true 613 | VersionAdded: "0.49" 614 | # When true, allows most uses of extra spacing if the intent is to align 615 | # things with the previous or next line, not counting empty lines or comment 616 | # lines. 617 | AllowForAlignment: true 618 | # When true, allows things like 'obj.meth(arg) # comment', 619 | # rather than insisting on 'obj.meth(arg) # comment'. 620 | # If done for alignment, either this OR AllowForAlignment will allow it. 621 | AllowBeforeTrailingComments: false 622 | # When true, forces the alignment of `=` in assignments on consecutive lines. 623 | ForceEqualSignAlignment: false 624 | 625 | Layout/FirstArrayElementLineBreak: 626 | Description: >- 627 | Checks for a line break before the first element in a 628 | multi-line array. 629 | Enabled: false 630 | VersionAdded: "0.49" 631 | 632 | Layout/FirstHashElementLineBreak: 633 | Description: >- 634 | Checks for a line break before the first element in a 635 | multi-line hash. 636 | Enabled: false 637 | VersionAdded: "0.49" 638 | 639 | Layout/FirstMethodArgumentLineBreak: 640 | Description: >- 641 | Checks for a line break before the first argument in a 642 | multi-line method call. 643 | Enabled: false 644 | VersionAdded: "0.49" 645 | 646 | Layout/FirstMethodParameterLineBreak: 647 | Description: >- 648 | Checks for a line break before the first parameter in a 649 | multi-line method parameter definition. 650 | Enabled: false 651 | VersionAdded: "0.49" 652 | 653 | Layout/HeredocArgumentClosingParenthesis: 654 | Description: >- 655 | Checks for the placement of the closing parenthesis in a 656 | method call that passes a HEREDOC string as an argument. 657 | Enabled: false 658 | StyleGuide: "#heredoc-argument-closing-parentheses" 659 | VersionAdded: "0.68" 660 | 661 | Layout/AssignmentIndentation: 662 | Description: >- 663 | Checks the indentation of the first line of the 664 | right-hand-side of a multi-line assignment. 665 | Enabled: true 666 | VersionAdded: "0.49" 667 | # By default, the indentation width from `Layout/IndentationWidth` is used 668 | # But it can be overridden by setting this parameter 669 | IndentationWidth: ~ 670 | 671 | Layout/FirstArgumentIndentation: 672 | Description: "Checks the indentation of the first argument in a method call." 673 | Enabled: true 674 | VersionAdded: "0.68" 675 | EnforcedStyle: special_for_inner_method_call_in_parentheses 676 | SupportedStyles: 677 | # The first parameter should always be indented one step more than the 678 | # preceding line. 679 | - consistent 680 | # The first parameter should always be indented one level relative to the 681 | # parent that is receiving the parameter 682 | - consistent_relative_to_receiver 683 | # The first parameter should normally be indented one step more than the 684 | # preceding line, but if it's a parameter for a method call that is itself 685 | # a parameter in a method call, then the inner parameter should be indented 686 | # relative to the inner method. 687 | - special_for_inner_method_call 688 | # Same as `special_for_inner_method_call` except that the special rule only 689 | # applies if the outer method call encloses its arguments in parentheses. 690 | - special_for_inner_method_call_in_parentheses 691 | # By default, the indentation width from `Layout/IndentationWidth` is used 692 | # But it can be overridden by setting this parameter 693 | IndentationWidth: ~ 694 | 695 | Layout/FirstArrayElementIndentation: 696 | Description: >- 697 | Checks the indentation of the first element in an array 698 | literal. 699 | Enabled: true 700 | VersionAdded: "0.68" 701 | # The value `special_inside_parentheses` means that array literals with 702 | # brackets that have their opening bracket on the same line as a surrounding 703 | # opening round parenthesis, shall have their first element indented relative 704 | # to the first position inside the parenthesis. 705 | # 706 | # The value `consistent` means that the indentation of the first element shall 707 | # always be relative to the first position of the line where the opening 708 | # bracket is. 709 | # 710 | # The value `align_brackets` means that the indentation of the first element 711 | # shall always be relative to the position of the opening bracket. 712 | EnforcedStyle: special_inside_parentheses 713 | SupportedStyles: 714 | - special_inside_parentheses 715 | - consistent 716 | - align_brackets 717 | # By default, the indentation width from `Layout/IndentationWidth` is used 718 | # But it can be overridden by setting this parameter 719 | IndentationWidth: ~ 720 | 721 | Layout/FirstHashElementIndentation: 722 | Description: "Checks the indentation of the first key in a hash literal." 723 | Enabled: false 724 | VersionAdded: "0.68" 725 | # The value `special_inside_parentheses` means that hash literals with braces 726 | # that have their opening brace on the same line as a surrounding opening 727 | # round parenthesis, shall have their first key indented relative to the 728 | # first position inside the parenthesis. 729 | # 730 | # The value `consistent` means that the indentation of the first key shall 731 | # always be relative to the first position of the line where the opening 732 | # brace is. 733 | # 734 | # The value `align_braces` means that the indentation of the first key shall 735 | # always be relative to the position of the opening brace. 736 | EnforcedStyle: special_inside_parentheses 737 | SupportedStyles: 738 | - special_inside_parentheses 739 | - consistent 740 | - align_braces 741 | # By default, the indentation width from `Layout/IndentationWidth` is used 742 | # But it can be overridden by setting this parameter 743 | IndentationWidth: ~ 744 | 745 | Layout/FirstParameterIndentation: 746 | Description: >- 747 | Checks the indentation of the first parameter in a 748 | method definition. 749 | Enabled: true 750 | VersionAdded: "0.49" 751 | VersionChanged: "0.68" 752 | EnforcedStyle: consistent 753 | SupportedStyles: 754 | - consistent 755 | - align_parentheses 756 | # By default, the indentation width from `Layout/IndentationWidth` is used 757 | # But it can be overridden by setting this parameter 758 | IndentationWidth: ~ 759 | 760 | Layout/HeredocIndentation: 761 | Description: "This cop checks the indentation of the here document bodies." 762 | StyleGuide: "#squiggly-heredocs" 763 | Enabled: true 764 | VersionAdded: "0.49" 765 | VersionChanged: "0.69" 766 | EnforcedStyle: squiggly 767 | SupportedStyles: 768 | - squiggly 769 | - active_support 770 | - powerpack 771 | - unindent 772 | 773 | Layout/IndentationConsistency: 774 | Description: "Keep indentation straight." 775 | StyleGuide: "#spaces-indentation" 776 | Enabled: true 777 | VersionAdded: "0.49" 778 | # The difference between `indented` and `normal` is that the `indented_internal_methods` 779 | # style prescribes that in classes and modules the `protected` and `private` 780 | # modifier keywords shall be indented the same as public methods and that 781 | # protected and private members shall be indented one step more than the 782 | # modifiers. Other than that, both styles mean that entities on the same 783 | # logical depth shall have the same indentation. 784 | EnforcedStyle: normal 785 | SupportedStyles: 786 | - normal 787 | - indented_internal_methods 788 | Reference: 789 | # A reference to `EnforcedStyle: indented_internal_methods`. 790 | - https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions 791 | 792 | Layout/IndentationWidth: 793 | Description: "Use 2 spaces for indentation." 794 | StyleGuide: "#spaces-indentation" 795 | Enabled: true 796 | VersionAdded: "0.49" 797 | # Number of spaces for each indentation level. 798 | Width: 2 799 | IgnoredPatterns: [] 800 | 801 | Layout/InitialIndentation: 802 | Description: >- 803 | Checks the indentation of the first non-blank non-comment line in a file. 804 | Enabled: true 805 | VersionAdded: "0.49" 806 | 807 | Layout/LeadingEmptyLines: 808 | Description: Check for unnecessary blank lines at the beginning of a file. 809 | Enabled: true 810 | VersionAdded: "0.57" 811 | 812 | Layout/LeadingCommentSpace: 813 | Description: "Comments should start with a space." 814 | StyleGuide: "#hash-space" 815 | Enabled: true 816 | VersionAdded: "0.49" 817 | VersionChanged: "0.73" 818 | AllowDoxygenCommentStyle: false 819 | 820 | Layout/MultilineArrayBraceLayout: 821 | Description: >- 822 | Checks that the closing brace in an array literal is 823 | either on the same line as the last array element, or 824 | a new line. 825 | Enabled: true 826 | VersionAdded: "0.49" 827 | EnforcedStyle: symmetrical 828 | SupportedStyles: 829 | # symmetrical: closing brace is positioned in same way as opening brace 830 | # new_line: closing brace is always on a new line 831 | # same_line: closing brace is always on the same line as last element 832 | - symmetrical 833 | - new_line 834 | - same_line 835 | 836 | Layout/MultilineArrayLineBreaks: 837 | Description: >- 838 | Checks that each item in a multi-line array literal 839 | starts on a separate line. 840 | Enabled: false 841 | VersionAdded: "0.67" 842 | 843 | Layout/MultilineAssignmentLayout: 844 | Description: "Check for a newline after the assignment operator in multi-line assignments." 845 | StyleGuide: "#indent-conditional-assignment" 846 | Enabled: false 847 | VersionAdded: "0.49" 848 | # The types of assignments which are subject to this rule. 849 | SupportedTypes: 850 | - block 851 | - case 852 | - class 853 | - if 854 | - kwbegin 855 | - module 856 | EnforcedStyle: new_line 857 | SupportedStyles: 858 | # Ensures that the assignment operator and the rhs are on the same line for 859 | # the set of supported types. 860 | - same_line 861 | # Ensures that the assignment operator and the rhs are on separate lines 862 | # for the set of supported types. 863 | - new_line 864 | 865 | Layout/MultilineBlockLayout: 866 | Description: "Ensures newlines after multiline block do statements." 867 | Enabled: true 868 | VersionAdded: "0.49" 869 | 870 | Layout/MultilineHashBraceLayout: 871 | Description: >- 872 | Checks that the closing brace in a hash literal is 873 | either on the same line as the last hash element, or 874 | a new line. 875 | Enabled: true 876 | VersionAdded: "0.49" 877 | EnforcedStyle: symmetrical 878 | SupportedStyles: 879 | # symmetrical: closing brace is positioned in same way as opening brace 880 | # new_line: closing brace is always on a new line 881 | # same_line: closing brace is always on same line as last element 882 | - symmetrical 883 | - new_line 884 | - same_line 885 | 886 | Layout/MultilineHashKeyLineBreaks: 887 | Description: >- 888 | Checks that each item in a multi-line hash literal 889 | starts on a separate line. 890 | Enabled: false 891 | VersionAdded: "0.67" 892 | 893 | Layout/MultilineMethodArgumentLineBreaks: 894 | Description: >- 895 | Checks that each argument in a multi-line method call 896 | starts on a separate line. 897 | Enabled: false 898 | VersionAdded: "0.67" 899 | 900 | Layout/MultilineMethodCallBraceLayout: 901 | Description: >- 902 | Checks that the closing brace in a method call is 903 | either on the same line as the last method argument, or 904 | a new line. 905 | Enabled: true 906 | VersionAdded: "0.49" 907 | EnforcedStyle: symmetrical 908 | SupportedStyles: 909 | # symmetrical: closing brace is positioned in same way as opening brace 910 | # new_line: closing brace is always on a new line 911 | # same_line: closing brace is always on the same line as last argument 912 | - symmetrical 913 | - new_line 914 | - same_line 915 | 916 | Layout/MultilineMethodCallIndentation: 917 | Description: >- 918 | Checks indentation of method calls with the dot operator 919 | that span more than one line. 920 | Enabled: true 921 | VersionAdded: "0.49" 922 | EnforcedStyle: aligned 923 | SupportedStyles: 924 | - aligned 925 | - indented 926 | - indented_relative_to_receiver 927 | # By default, the indentation width from Layout/IndentationWidth is used 928 | # But it can be overridden by setting this parameter 929 | IndentationWidth: ~ 930 | 931 | Layout/MultilineMethodDefinitionBraceLayout: 932 | Description: >- 933 | Checks that the closing brace in a method definition is 934 | either on the same line as the last method parameter, or 935 | a new line. 936 | Enabled: true 937 | VersionAdded: "0.49" 938 | EnforcedStyle: symmetrical 939 | SupportedStyles: 940 | # symmetrical: closing brace is positioned in same way as opening brace 941 | # new_line: closing brace is always on a new line 942 | # same_line: closing brace is always on the same line as last parameter 943 | - symmetrical 944 | - new_line 945 | - same_line 946 | 947 | Layout/MultilineOperationIndentation: 948 | Description: >- 949 | Checks indentation of binary operations that span more than 950 | one line. 951 | Enabled: true 952 | VersionAdded: "0.49" 953 | EnforcedStyle: aligned 954 | SupportedStyles: 955 | - aligned 956 | - indented 957 | # By default, the indentation width from `Layout/IndentationWidth` is used 958 | # But it can be overridden by setting this parameter 959 | IndentationWidth: ~ 960 | 961 | Layout/RescueEnsureAlignment: 962 | Description: "Align rescues and ensures correctly." 963 | Enabled: true 964 | VersionAdded: "0.49" 965 | 966 | Layout/SpaceAfterColon: 967 | Description: "Use spaces after colons." 968 | StyleGuide: "#spaces-operators" 969 | Enabled: true 970 | VersionAdded: "0.49" 971 | 972 | Layout/SpaceAfterComma: 973 | Description: "Use spaces after commas." 974 | StyleGuide: "#spaces-operators" 975 | Enabled: true 976 | VersionAdded: "0.49" 977 | 978 | Layout/SpaceAfterMethodName: 979 | Description: >- 980 | Do not put a space between a method name and the opening 981 | parenthesis in a method definition. 982 | StyleGuide: "#parens-no-spaces" 983 | Enabled: true 984 | VersionAdded: "0.49" 985 | 986 | Layout/SpaceAfterNot: 987 | Description: Tracks redundant space after the ! operator. 988 | StyleGuide: "#no-space-bang" 989 | Enabled: true 990 | VersionAdded: "0.49" 991 | 992 | Layout/SpaceAfterSemicolon: 993 | Description: "Use spaces after semicolons." 994 | StyleGuide: "#spaces-operators" 995 | Enabled: true 996 | VersionAdded: "0.49" 997 | 998 | Layout/SpaceAroundBlockParameters: 999 | Description: "Checks the spacing inside and after block parameters pipes." 1000 | Enabled: true 1001 | VersionAdded: "0.49" 1002 | EnforcedStyleInsidePipes: no_space 1003 | SupportedStylesInsidePipes: 1004 | - space 1005 | - no_space 1006 | 1007 | Layout/SpaceAroundEqualsInParameterDefault: 1008 | Description: >- 1009 | Checks that the equals signs in parameter default assignments 1010 | have or don't have surrounding space depending on 1011 | configuration. 1012 | StyleGuide: "#spaces-around-equals" 1013 | Enabled: true 1014 | VersionAdded: "0.49" 1015 | EnforcedStyle: space 1016 | SupportedStyles: 1017 | - space 1018 | - no_space 1019 | 1020 | Layout/SpaceAroundKeyword: 1021 | Description: "Use a space around keywords if appropriate." 1022 | Enabled: true 1023 | VersionAdded: "0.49" 1024 | 1025 | Layout/SpaceAroundOperators: 1026 | Description: "Use a single space around operators." 1027 | StyleGuide: "#spaces-operators" 1028 | Enabled: false 1029 | VersionAdded: "0.49" 1030 | # When `true`, allows most uses of extra spacing if the intent is to align 1031 | # with an operator on the previous or next line, not counting empty lines 1032 | # or comment lines. 1033 | AllowForAlignment: true 1034 | 1035 | Layout/SpaceBeforeBlockBraces: 1036 | Description: >- 1037 | Checks that the left block brace has or doesn't have space 1038 | before it. 1039 | Enabled: true 1040 | VersionAdded: "0.49" 1041 | EnforcedStyle: space 1042 | SupportedStyles: 1043 | - space 1044 | - no_space 1045 | EnforcedStyleForEmptyBraces: space 1046 | SupportedStylesForEmptyBraces: 1047 | - space 1048 | - no_space 1049 | VersionChanged: "0.52.1" 1050 | 1051 | Layout/SpaceBeforeComma: 1052 | Description: "No spaces before commas." 1053 | Enabled: true 1054 | VersionAdded: "0.49" 1055 | 1056 | Layout/SpaceBeforeComment: 1057 | Description: >- 1058 | Checks for missing space between code and a comment on the 1059 | same line. 1060 | Enabled: true 1061 | VersionAdded: "0.49" 1062 | 1063 | Layout/SpaceBeforeFirstArg: 1064 | Description: >- 1065 | Checks that exactly one space is used between a method name 1066 | and the first argument for method calls without parentheses. 1067 | Enabled: true 1068 | VersionAdded: "0.49" 1069 | # When `true`, allows most uses of extra spacing if the intent is to align 1070 | # things with the previous or next line, not counting empty lines or comment 1071 | # lines. 1072 | AllowForAlignment: true 1073 | 1074 | Layout/SpaceBeforeSemicolon: 1075 | Description: "No spaces before semicolons." 1076 | Enabled: true 1077 | VersionAdded: "0.49" 1078 | 1079 | Layout/SpaceInLambdaLiteral: 1080 | Description: "Checks for spaces in lambda literals." 1081 | Enabled: true 1082 | VersionAdded: "0.49" 1083 | EnforcedStyle: require_no_space 1084 | SupportedStyles: 1085 | - require_no_space 1086 | - require_space 1087 | 1088 | Layout/SpaceInsideArrayLiteralBrackets: 1089 | Description: "Checks the spacing inside array literal brackets." 1090 | Enabled: true 1091 | VersionAdded: "0.52" 1092 | EnforcedStyle: no_space 1093 | SupportedStyles: 1094 | - space 1095 | - no_space 1096 | # 'compact' normally requires a space inside the brackets, with the exception 1097 | # that successive left brackets or right brackets are collapsed together 1098 | - compact 1099 | EnforcedStyleForEmptyBrackets: no_space 1100 | SupportedStylesForEmptyBrackets: 1101 | - space 1102 | - no_space 1103 | 1104 | Layout/SpaceInsideArrayPercentLiteral: 1105 | Description: "No unnecessary additional spaces between elements in %i/%w literals." 1106 | Enabled: true 1107 | VersionAdded: "0.49" 1108 | 1109 | Layout/SpaceInsideBlockBraces: 1110 | Description: >- 1111 | Checks that block braces have or don't have surrounding space. 1112 | For blocks taking parameters, checks that the left brace has 1113 | or doesn't have trailing space. 1114 | Enabled: true 1115 | VersionAdded: "0.49" 1116 | EnforcedStyle: space 1117 | SupportedStyles: 1118 | - space 1119 | - no_space 1120 | EnforcedStyleForEmptyBraces: no_space 1121 | SupportedStylesForEmptyBraces: 1122 | - space 1123 | - no_space 1124 | # Space between `{` and `|`. Overrides `EnforcedStyle` if there is a conflict. 1125 | SpaceBeforeBlockParameters: true 1126 | 1127 | Layout/SpaceInsideHashLiteralBraces: 1128 | Description: "Use spaces inside hash literal braces - or don't." 1129 | StyleGuide: "#spaces-operators" 1130 | Enabled: true 1131 | VersionAdded: "0.49" 1132 | EnforcedStyle: space 1133 | SupportedStyles: 1134 | - space 1135 | - no_space 1136 | # 'compact' normally requires a space inside hash braces, with the exception 1137 | # that successive left braces or right braces are collapsed together 1138 | - compact 1139 | EnforcedStyleForEmptyBraces: no_space 1140 | SupportedStylesForEmptyBraces: 1141 | - space 1142 | - no_space 1143 | 1144 | Layout/SpaceInsideParens: 1145 | Description: "No spaces after ( or before )." 1146 | StyleGuide: "#spaces-braces" 1147 | Enabled: true 1148 | VersionAdded: "0.49" 1149 | VersionChanged: "0.55" 1150 | EnforcedStyle: no_space 1151 | SupportedStyles: 1152 | - space 1153 | - no_space 1154 | 1155 | Layout/SpaceInsidePercentLiteralDelimiters: 1156 | Description: "No unnecessary spaces inside delimiters of %i/%w/%x literals." 1157 | Enabled: true 1158 | VersionAdded: "0.49" 1159 | 1160 | Layout/SpaceInsideRangeLiteral: 1161 | Description: "No spaces inside range literals." 1162 | StyleGuide: "#no-space-inside-range-literals" 1163 | Enabled: true 1164 | VersionAdded: "0.49" 1165 | 1166 | Layout/SpaceInsideReferenceBrackets: 1167 | Description: "Checks the spacing inside referential brackets." 1168 | Enabled: true 1169 | VersionAdded: "0.52" 1170 | VersionChanged: "0.53" 1171 | EnforcedStyle: no_space 1172 | SupportedStyles: 1173 | - space 1174 | - no_space 1175 | EnforcedStyleForEmptyBrackets: no_space 1176 | SupportedStylesForEmptyBrackets: 1177 | - space 1178 | - no_space 1179 | 1180 | Layout/SpaceInsideStringInterpolation: 1181 | Description: "Checks for padding/surrounding spaces inside string interpolation." 1182 | StyleGuide: "#string-interpolation" 1183 | Enabled: true 1184 | VersionAdded: "0.49" 1185 | EnforcedStyle: no_space 1186 | SupportedStyles: 1187 | - space 1188 | - no_space 1189 | 1190 | Layout/Tab: 1191 | Description: "No hard tabs." 1192 | StyleGuide: "#spaces-indentation" 1193 | Enabled: false 1194 | VersionAdded: "0.49" 1195 | VersionChanged: "0.51" 1196 | # By default, the indentation width from Layout/IndentationWidth is used 1197 | # But it can be overridden by setting this parameter 1198 | # It is used during auto-correction to determine how many spaces should 1199 | # replace each tab. 1200 | IndentationWidth: ~ 1201 | AutoCorrect: true 1202 | 1203 | Layout/TrailingEmptyLines: 1204 | Description: "Checks trailing blank lines and final newline." 1205 | StyleGuide: "#newline-eof" 1206 | Enabled: true 1207 | VersionAdded: "0.49" 1208 | EnforcedStyle: final_newline 1209 | SupportedStyles: 1210 | - final_newline 1211 | - final_blank_line 1212 | 1213 | Layout/TrailingWhitespace: 1214 | Description: "Avoid trailing whitespace." 1215 | StyleGuide: "#no-trailing-whitespace" 1216 | Enabled: true 1217 | VersionAdded: "0.49" 1218 | VersionChanged: "0.55" 1219 | AllowInHeredoc: false 1220 | AutoCorrect: true 1221 | 1222 | #################### Lint ################################## 1223 | ### Warnings 1224 | 1225 | Lint/RaiseException: 1226 | Enabled: false 1227 | 1228 | Lint/StructNewOverride: 1229 | Enabled: false 1230 | 1231 | Lint/AmbiguousBlockAssociation: 1232 | Description: >- 1233 | Checks for ambiguous block association with method when param passed without 1234 | parentheses. 1235 | StyleGuide: "#syntax" 1236 | Enabled: true 1237 | VersionAdded: "0.48" 1238 | 1239 | Lint/AmbiguousOperator: 1240 | Description: >- 1241 | Checks for ambiguous operators in the first argument of a 1242 | method invocation without parentheses. 1243 | StyleGuide: "#method-invocation-parens" 1244 | Enabled: true 1245 | VersionAdded: "0.17" 1246 | 1247 | Lint/AmbiguousRegexpLiteral: 1248 | Description: >- 1249 | Checks for ambiguous regexp literals in the first argument of 1250 | a method invocation without parentheses. 1251 | Enabled: true 1252 | VersionAdded: "0.17" 1253 | 1254 | Lint/AssignmentInCondition: 1255 | Description: "Don't use assignment in conditions." 1256 | StyleGuide: "#safe-assignment-in-condition" 1257 | Enabled: true 1258 | VersionAdded: "0.9" 1259 | AllowSafeAssignment: true 1260 | 1261 | Lint/BigDecimalNew: 1262 | Description: "`BigDecimal.new()` is deprecated. Use `BigDecimal()` instead." 1263 | Enabled: true 1264 | VersionAdded: "0.53" 1265 | 1266 | Lint/BooleanSymbol: 1267 | Description: "Check for `:true` and `:false` symbols." 1268 | Enabled: true 1269 | VersionAdded: "0.50" 1270 | 1271 | Lint/CircularArgumentReference: 1272 | Description: "Default values in optional keyword arguments and optional ordinal arguments should not refer back to the name of the argument." 1273 | Enabled: true 1274 | VersionAdded: "0.33" 1275 | 1276 | Lint/Debugger: 1277 | Description: "Check for debugger calls." 1278 | Enabled: true 1279 | VersionAdded: "0.14" 1280 | VersionChanged: "0.49" 1281 | 1282 | Lint/DeprecatedClassMethods: 1283 | Description: "Check for deprecated class method calls." 1284 | Enabled: true 1285 | VersionAdded: "0.19" 1286 | 1287 | Lint/DisjunctiveAssignmentInConstructor: 1288 | Description: "In constructor, plain assignment is preferred over disjunctive." 1289 | Enabled: true 1290 | Safe: false 1291 | VersionAdded: "0.62" 1292 | 1293 | Lint/DuplicateCaseCondition: 1294 | Description: "Do not repeat values in case conditionals." 1295 | Enabled: true 1296 | VersionAdded: "0.45" 1297 | 1298 | Lint/DuplicateMethods: 1299 | Description: "Check for duplicate method definitions." 1300 | Enabled: true 1301 | VersionAdded: "0.29" 1302 | 1303 | Lint/DuplicateHashKey: 1304 | Description: "Check for duplicate keys in hash literals." 1305 | Enabled: true 1306 | VersionAdded: "0.34" 1307 | 1308 | Lint/EachWithObjectArgument: 1309 | Description: "Check for immutable argument given to each_with_object." 1310 | Enabled: true 1311 | VersionAdded: "0.31" 1312 | 1313 | Lint/ElseLayout: 1314 | Description: "Check for odd code arrangement in an else block." 1315 | Enabled: true 1316 | VersionAdded: "0.17" 1317 | 1318 | Lint/EmptyEnsure: 1319 | Description: "Checks for empty ensure block." 1320 | Enabled: true 1321 | VersionAdded: "0.10" 1322 | VersionChanged: "0.48" 1323 | AutoCorrect: false 1324 | 1325 | Lint/EmptyExpression: 1326 | Description: "Checks for empty expressions." 1327 | Enabled: true 1328 | VersionAdded: "0.45" 1329 | 1330 | Lint/EmptyInterpolation: 1331 | Description: "Checks for empty string interpolation." 1332 | Enabled: true 1333 | VersionAdded: "0.20" 1334 | VersionChanged: "0.45" 1335 | 1336 | Lint/EmptyWhen: 1337 | Description: "Checks for `when` branches with empty bodies." 1338 | Enabled: true 1339 | VersionAdded: "0.45" 1340 | 1341 | Lint/EnsureReturn: 1342 | Description: "Do not use return in an ensure block." 1343 | StyleGuide: "#no-return-ensure" 1344 | Enabled: true 1345 | VersionAdded: "0.9" 1346 | 1347 | Lint/ErbNewArguments: 1348 | Description: "Use `:trim_mode` and `:eoutvar` keyword arguments to `ERB.new`." 1349 | Enabled: true 1350 | VersionAdded: "0.56" 1351 | 1352 | Lint/FlipFlop: 1353 | Description: "Checks for flip-flops." 1354 | StyleGuide: "#no-flip-flops" 1355 | Enabled: true 1356 | VersionAdded: "0.16" 1357 | 1358 | Lint/FloatOutOfRange: 1359 | Description: >- 1360 | Catches floating-point literals too large or small for Ruby to 1361 | represent. 1362 | Enabled: true 1363 | VersionAdded: "0.36" 1364 | 1365 | Lint/FormatParameterMismatch: 1366 | Description: "The number of parameters to format/sprint must match the fields." 1367 | Enabled: true 1368 | VersionAdded: "0.33" 1369 | 1370 | Lint/SuppressedException: 1371 | Description: "Don't suppress exception." 1372 | StyleGuide: "#dont-hide-exceptions" 1373 | Enabled: true 1374 | AllowComments: false 1375 | VersionAdded: "0.9" 1376 | VersionChanged: "0.70" 1377 | 1378 | Lint/HeredocMethodCallPosition: 1379 | Description: >- 1380 | Checks for the ordering of a method call where 1381 | the receiver of the call is a HEREDOC. 1382 | Enabled: false 1383 | StyleGuide: "#heredoc-method-calls" 1384 | VersionAdded: "0.68" 1385 | 1386 | Lint/ImplicitStringConcatenation: 1387 | Description: >- 1388 | Checks for adjacent string literals on the same line, which 1389 | could better be represented as a single string literal. 1390 | Enabled: true 1391 | VersionAdded: "0.36" 1392 | 1393 | Lint/IneffectiveAccessModifier: 1394 | Description: >- 1395 | Checks for attempts to use `private` or `protected` to set 1396 | the visibility of a class method, which does not work. 1397 | Enabled: true 1398 | VersionAdded: "0.36" 1399 | 1400 | Lint/InheritException: 1401 | Description: "Avoid inheriting from the `Exception` class." 1402 | Enabled: true 1403 | VersionAdded: "0.41" 1404 | # The default base class in favour of `Exception`. 1405 | EnforcedStyle: runtime_error 1406 | SupportedStyles: 1407 | - runtime_error 1408 | - standard_error 1409 | 1410 | Lint/InterpolationCheck: 1411 | Description: "Raise warning for interpolation in single q strs." 1412 | Enabled: true 1413 | VersionAdded: "0.50" 1414 | 1415 | Lint/LiteralAsCondition: 1416 | Description: "Checks of literals used in conditions." 1417 | Enabled: true 1418 | VersionAdded: "0.51" 1419 | 1420 | Lint/LiteralInInterpolation: 1421 | Description: "Checks for literals used in interpolation." 1422 | Enabled: true 1423 | VersionAdded: "0.19" 1424 | VersionChanged: "0.32" 1425 | 1426 | Lint/Loop: 1427 | Description: >- 1428 | Use Kernel#loop with break rather than begin/end/until or 1429 | begin/end/while for post-loop tests. 1430 | StyleGuide: "#loop-with-break" 1431 | Enabled: true 1432 | VersionAdded: "0.9" 1433 | 1434 | Lint/MissingCopEnableDirective: 1435 | Description: "Checks for a `# rubocop:enable` after `# rubocop:disable`." 1436 | Enabled: true 1437 | VersionAdded: "0.52" 1438 | # Maximum number of consecutive lines the cop can be disabled for. 1439 | # 0 allows only single-line disables 1440 | # 1 would mean the maximum allowed is the following: 1441 | # # rubocop:disable SomeCop 1442 | # a = 1 1443 | # # rubocop:enable SomeCop 1444 | # .inf for any size 1445 | MaximumRangeSize: .inf 1446 | 1447 | Lint/MultipleComparison: 1448 | Description: "Use `&&` operator to compare multiple value." 1449 | Enabled: true 1450 | VersionAdded: "0.47" 1451 | 1452 | Lint/NestedMethodDefinition: 1453 | Description: "Do not use nested method definitions." 1454 | StyleGuide: "#no-nested-methods" 1455 | Enabled: true 1456 | VersionAdded: "0.32" 1457 | 1458 | Lint/NestedPercentLiteral: 1459 | Description: "Checks for nested percent literals." 1460 | Enabled: true 1461 | VersionAdded: "0.52" 1462 | 1463 | Lint/NextWithoutAccumulator: 1464 | Description: >- 1465 | Do not omit the accumulator when calling `next` 1466 | in a `reduce`/`inject` block. 1467 | Enabled: true 1468 | VersionAdded: "0.36" 1469 | 1470 | Lint/NonLocalExitFromIterator: 1471 | Description: "Do not use return in iterator to cause non-local exit." 1472 | Enabled: true 1473 | VersionAdded: "0.30" 1474 | 1475 | Lint/NumberConversion: 1476 | Description: "Checks unsafe usage of number conversion methods." 1477 | Enabled: false 1478 | VersionAdded: "0.53" 1479 | VersionChanged: "0.70" 1480 | SafeAutoCorrect: false 1481 | 1482 | Lint/OrderedMagicComments: 1483 | Description: "Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang." 1484 | Enabled: true 1485 | VersionAdded: "0.53" 1486 | 1487 | Lint/ParenthesesAsGroupedExpression: 1488 | Description: >- 1489 | Checks for method calls with a space before the opening 1490 | parenthesis. 1491 | StyleGuide: "#parens-no-spaces" 1492 | Enabled: true 1493 | VersionAdded: "0.12" 1494 | 1495 | Lint/PercentStringArray: 1496 | Description: >- 1497 | Checks for unwanted commas and quotes in %w/%W literals. 1498 | Enabled: true 1499 | Safe: false 1500 | VersionAdded: "0.41" 1501 | 1502 | Lint/PercentSymbolArray: 1503 | Description: >- 1504 | Checks for unwanted commas and colons in %i/%I literals. 1505 | Enabled: true 1506 | VersionAdded: "0.41" 1507 | 1508 | Lint/RandOne: 1509 | Description: >- 1510 | Checks for `rand(1)` calls. Such calls always return `0` 1511 | and most likely a mistake. 1512 | Enabled: true 1513 | VersionAdded: "0.36" 1514 | 1515 | Lint/RedundantWithIndex: 1516 | Description: "Checks for redundant `with_index`." 1517 | Enabled: true 1518 | VersionAdded: "0.50" 1519 | 1520 | Lint/RedundantWithObject: 1521 | Description: "Checks for redundant `with_object`." 1522 | Enabled: true 1523 | VersionAdded: "0.51" 1524 | 1525 | Lint/RegexpAsCondition: 1526 | Description: >- 1527 | Do not use regexp literal as a condition. 1528 | The regexp literal matches `$_` implicitly. 1529 | Enabled: true 1530 | VersionAdded: "0.51" 1531 | 1532 | Lint/RequireParentheses: 1533 | Description: >- 1534 | Use parentheses in the method call to avoid confusion 1535 | about precedence. 1536 | Enabled: true 1537 | VersionAdded: "0.18" 1538 | 1539 | Lint/RescueException: 1540 | Description: "Avoid rescuing the Exception class." 1541 | StyleGuide: "#no-blind-rescues" 1542 | Enabled: true 1543 | VersionAdded: "0.9" 1544 | VersionChanged: "0.27.1" 1545 | 1546 | Lint/RescueType: 1547 | Description: "Avoid rescuing from non constants that could result in a `TypeError`." 1548 | Enabled: true 1549 | VersionAdded: "0.49" 1550 | 1551 | Lint/ReturnInVoidContext: 1552 | Description: "Checks for return in void context." 1553 | Enabled: true 1554 | VersionAdded: "0.50" 1555 | 1556 | Lint/SafeNavigationChain: 1557 | Description: "Do not chain ordinary method call after safe navigation operator." 1558 | Enabled: true 1559 | VersionAdded: "0.47" 1560 | VersionChanged: "0.56" 1561 | AllowedMethods: 1562 | - present? 1563 | - blank? 1564 | - presence 1565 | - try 1566 | - try! 1567 | 1568 | Lint/SafeNavigationConsistency: 1569 | Description: >- 1570 | Check to make sure that if safe navigation is used for a method 1571 | call in an `&&` or `||` condition that safe navigation is used 1572 | for all method calls on that same object. 1573 | Enabled: true 1574 | VersionAdded: "0.55" 1575 | AllowedMethods: 1576 | - present? 1577 | - blank? 1578 | - presence 1579 | - try 1580 | - try! 1581 | 1582 | Lint/SafeNavigationWithEmpty: 1583 | Description: "Avoid `foo&.empty?` in conditionals." 1584 | Enabled: true 1585 | VersionAdded: "0.62" 1586 | 1587 | Lint/ScriptPermission: 1588 | Description: "Grant script file execute permission." 1589 | Enabled: true 1590 | VersionAdded: "0.49" 1591 | VersionChanged: "0.50" 1592 | 1593 | Lint/SendWithMixinArgument: 1594 | Description: "Checks for `send` method when using mixin." 1595 | Enabled: true 1596 | VersionAdded: "0.75" 1597 | 1598 | Lint/ShadowedArgument: 1599 | Description: "Avoid reassigning arguments before they were used." 1600 | Enabled: true 1601 | VersionAdded: "0.52" 1602 | IgnoreImplicitReferences: false 1603 | 1604 | Lint/ShadowedException: 1605 | Description: >- 1606 | Avoid rescuing a higher level exception 1607 | before a lower level exception. 1608 | Enabled: true 1609 | VersionAdded: "0.41" 1610 | 1611 | Lint/ShadowingOuterLocalVariable: 1612 | Description: >- 1613 | Do not use the same name as outer local variable 1614 | for block arguments or block local variables. 1615 | Enabled: true 1616 | VersionAdded: "0.9" 1617 | 1618 | Lint/RedundantStringCoercion: 1619 | Description: "Checks for Object#to_s usage in string interpolation." 1620 | StyleGuide: "#no-to-s" 1621 | Enabled: true 1622 | VersionAdded: "0.19" 1623 | VersionChanged: "0.20" 1624 | 1625 | Lint/Syntax: 1626 | Description: "Checks syntax error." 1627 | Enabled: true 1628 | VersionAdded: "0.9" 1629 | 1630 | Lint/ToJSON: 1631 | Description: "Ensure #to_json includes an optional argument." 1632 | Enabled: true 1633 | 1634 | Lint/UnderscorePrefixedVariableName: 1635 | Description: "Do not use prefix `_` for a variable that is used." 1636 | Enabled: true 1637 | VersionAdded: "0.21" 1638 | AllowKeywordBlockArguments: false 1639 | 1640 | Lint/UnifiedInteger: 1641 | Description: "Use Integer instead of Fixnum or Bignum." 1642 | Enabled: true 1643 | VersionAdded: "0.43" 1644 | 1645 | Lint/RedundantCopDisableDirective: 1646 | Description: >- 1647 | Checks for rubocop:disable comments that can be removed. 1648 | Note: this cop is not disabled when disabling all cops. 1649 | It must be explicitly disabled. 1650 | Enabled: true 1651 | VersionAdded: "0.53" 1652 | 1653 | Lint/RedundantCopEnableDirective: 1654 | Description: Checks for rubocop:enable comments that can be removed. 1655 | Enabled: true 1656 | VersionAdded: "0.53" 1657 | 1658 | Lint/RedundantRequireStatement: 1659 | Description: "Checks for unnecessary `require` statement." 1660 | Enabled: true 1661 | VersionAdded: "0.51" 1662 | 1663 | Lint/RedundantSplatExpansion: 1664 | Description: "Checks for splat unnecessarily being called on literals." 1665 | Enabled: true 1666 | VersionAdded: "0.43" 1667 | 1668 | Lint/UnreachableCode: 1669 | Description: "Unreachable code." 1670 | Enabled: true 1671 | VersionAdded: "0.9" 1672 | 1673 | Lint/UnusedBlockArgument: 1674 | Description: "Checks for unused block arguments." 1675 | StyleGuide: "#underscore-unused-vars" 1676 | Enabled: true 1677 | VersionAdded: "0.21" 1678 | VersionChanged: "0.22" 1679 | IgnoreEmptyBlocks: true 1680 | AllowUnusedKeywordArguments: false 1681 | 1682 | Lint/UnusedMethodArgument: 1683 | Description: "Checks for unused method arguments." 1684 | StyleGuide: "#underscore-unused-vars" 1685 | Enabled: true 1686 | VersionAdded: "0.21" 1687 | VersionChanged: "0.35" 1688 | AllowUnusedKeywordArguments: false 1689 | IgnoreEmptyMethods: true 1690 | 1691 | Lint/UriEscapeUnescape: 1692 | Description: >- 1693 | `URI.escape` method is obsolete and should not be used. Instead, use 1694 | `CGI.escape`, `URI.encode_www_form` or `URI.encode_www_form_component` 1695 | depending on your specific use case. 1696 | Also `URI.unescape` method is obsolete and should not be used. Instead, use 1697 | `CGI.unescape`, `URI.decode_www_form` or `URI.decode_www_form_component` 1698 | depending on your specific use case. 1699 | Enabled: true 1700 | VersionAdded: "0.50" 1701 | 1702 | Lint/UriRegexp: 1703 | Description: "Use `URI::DEFAULT_PARSER.make_regexp` instead of `URI.regexp`." 1704 | Enabled: true 1705 | VersionAdded: "0.50" 1706 | 1707 | Lint/UselessAccessModifier: 1708 | Description: "Checks for useless access modifiers." 1709 | Enabled: true 1710 | VersionAdded: "0.20" 1711 | VersionChanged: "0.47" 1712 | ContextCreatingMethods: [] 1713 | MethodCreatingMethods: [] 1714 | 1715 | Lint/UselessAssignment: 1716 | Description: "Checks for useless assignment to a local variable." 1717 | StyleGuide: "#underscore-unused-vars" 1718 | Enabled: true 1719 | VersionAdded: "0.11" 1720 | 1721 | Lint/UselessComparison: 1722 | Description: "Checks for comparison of something with itself." 1723 | Enabled: true 1724 | VersionAdded: "0.11" 1725 | 1726 | Lint/UselessElseWithoutRescue: 1727 | Description: "Checks for useless `else` in `begin..end` without `rescue`." 1728 | Enabled: true 1729 | VersionAdded: "0.17" 1730 | 1731 | Lint/UselessSetterCall: 1732 | Description: "Checks for useless setter call to a local variable." 1733 | Enabled: true 1734 | VersionAdded: "0.13" 1735 | 1736 | Lint/Void: 1737 | Description: "Possible use of operator/literal/variable in void context." 1738 | Enabled: true 1739 | VersionAdded: "0.9" 1740 | CheckForMethodsWithNoSideEffects: false 1741 | 1742 | #################### Metrics ############################### 1743 | 1744 | Metrics/AbcSize: 1745 | Description: >- 1746 | A calculated magnitude based on number of assignments, 1747 | branches, and conditions. 1748 | Reference: 1749 | - http://c2.com/cgi/wiki?AbcMetric 1750 | - https://en.wikipedia.org/wiki/ABC_Software_Metric 1751 | Enabled: false 1752 | VersionAdded: "0.27" 1753 | VersionChanged: "0.66" 1754 | # The ABC size is a calculated magnitude, so this number can be an Integer or 1755 | # a Float. 1756 | Max: 15 1757 | 1758 | Metrics/BlockLength: 1759 | Description: "Avoid long blocks with many lines." 1760 | Enabled: true 1761 | VersionAdded: "0.44" 1762 | VersionChanged: "0.66" 1763 | CountComments: false # count full line comments? 1764 | Max: 25 1765 | ExcludedMethods: 1766 | # By default, exclude the `#refine` method, as it tends to have larger 1767 | # associated blocks. 1768 | - refine 1769 | Exclude: 1770 | - "**/*.gemspec" 1771 | 1772 | Metrics/BlockNesting: 1773 | Description: "Avoid excessive block nesting." 1774 | StyleGuide: "#three-is-the-number-thou-shalt-count" 1775 | Enabled: true 1776 | VersionAdded: "0.25" 1777 | VersionChanged: "0.47" 1778 | CountBlocks: false 1779 | Max: 3 1780 | 1781 | Metrics/ClassLength: 1782 | Description: "Avoid classes longer than 100 lines of code." 1783 | Enabled: false 1784 | VersionAdded: "0.25" 1785 | CountComments: false # count full line comments? 1786 | Max: 100 1787 | 1788 | # Avoid complex methods. 1789 | Metrics/CyclomaticComplexity: 1790 | Description: >- 1791 | A complexity metric that is strongly correlated to the number 1792 | of test cases needed to validate a method. 1793 | Enabled: true 1794 | VersionAdded: "0.25" 1795 | Max: 6 1796 | 1797 | Metrics/MethodLength: 1798 | Description: "Avoid methods longer than 10 lines of code." 1799 | StyleGuide: "#short-methods" 1800 | Enabled: false 1801 | VersionAdded: "0.25" 1802 | VersionChanged: "0.59.2" 1803 | CountComments: false # count full line comments? 1804 | Max: 10 1805 | ExcludedMethods: [] 1806 | 1807 | Layout/LineLength: 1808 | Description: "Limit lines to 80 characters." 1809 | StyleGuide: "#80-character-limits" 1810 | Enabled: false 1811 | VersionAdded: "0.25" 1812 | VersionChanged: "0.68" 1813 | AutoCorrect: false 1814 | Max: 80 1815 | # To make it possible to copy or click on URIs in the code, we allow lines 1816 | # containing a URI to be longer than Max. 1817 | AllowHeredoc: true 1818 | AllowURI: true 1819 | URISchemes: 1820 | - http 1821 | - https 1822 | # The IgnoreCopDirectives option causes the LineLength rule to ignore cop 1823 | # directives like '# rubocop: enable ...' when calculating a line's length. 1824 | IgnoreCopDirectives: false 1825 | # The IgnoredPatterns option is a list of !ruby/regexp and/or string 1826 | # elements. Strings will be converted to Regexp objects. A line that matches 1827 | # any regular expression listed in this option will be ignored by LineLength. 1828 | IgnoredPatterns: [] 1829 | 1830 | Metrics/ModuleLength: 1831 | Description: "Avoid modules longer than 100 lines of code." 1832 | Enabled: true 1833 | VersionAdded: "0.31" 1834 | CountComments: false # count full line comments? 1835 | Max: 100 1836 | 1837 | Metrics/ParameterLists: 1838 | Description: "Avoid parameter lists longer than three or four parameters." 1839 | StyleGuide: "#too-many-params" 1840 | Enabled: true 1841 | VersionAdded: "0.25" 1842 | Max: 5 1843 | CountKeywordArgs: true 1844 | 1845 | Metrics/PerceivedComplexity: 1846 | Description: >- 1847 | A complexity metric geared towards measuring complexity for a 1848 | human reader. 1849 | Enabled: false 1850 | VersionAdded: "0.25" 1851 | Max: 7 1852 | 1853 | ################## Migration ############################# 1854 | 1855 | Migration/DepartmentName: 1856 | Description: >- 1857 | Check that cop names in rubocop:disable (etc) comments are 1858 | given with department name. 1859 | Enabled: false 1860 | 1861 | #################### Naming ############################## 1862 | 1863 | Naming/PredicateName: 1864 | Description: "Check the names of predicate methods." 1865 | StyleGuide: "#bool-methods-qmark" 1866 | Enabled: false 1867 | VersionAdded: "0.50" 1868 | VersionChanged: "0.51" 1869 | # Predicate name prefixes. 1870 | NamePrefix: 1871 | - is_ 1872 | - has_ 1873 | - have_ 1874 | # Predicate name prefixes that should be removed. 1875 | ForbiddenPrefixes: 1876 | - is_ 1877 | - has_ 1878 | - have_ 1879 | # Predicate names which, despite having a blacklisted prefix, or no `?`, 1880 | # should still be accepted 1881 | AllowedMethods: 1882 | - is_a? 1883 | # Method definition macros for dynamically generated methods. 1884 | MethodDefinitionMacros: 1885 | - define_method 1886 | - define_singleton_method 1887 | # Exclude Rspec specs because there is a strong convention to write spec 1888 | # helpers in the form of `have_something` or `be_something`. 1889 | Exclude: 1890 | - "spec/**/*" 1891 | 1892 | Naming/AccessorMethodName: 1893 | Description: Check the naming of accessor methods for get_/set_. 1894 | StyleGuide: "#accessor_mutator_method_names" 1895 | Enabled: true 1896 | VersionAdded: "0.50" 1897 | 1898 | Naming/AsciiIdentifiers: 1899 | Description: "Use only ascii symbols in identifiers." 1900 | StyleGuide: "#english-identifiers" 1901 | Enabled: true 1902 | VersionAdded: "0.50" 1903 | 1904 | Naming/BinaryOperatorParameterName: 1905 | Description: "When defining binary operators, name the argument other." 1906 | StyleGuide: "#other-arg" 1907 | Enabled: true 1908 | VersionAdded: "0.50" 1909 | 1910 | Naming/ClassAndModuleCamelCase: 1911 | Description: "Use CamelCase for classes and modules." 1912 | StyleGuide: "#camelcase-classes" 1913 | Enabled: true 1914 | VersionAdded: "0.50" 1915 | 1916 | Naming/ConstantName: 1917 | Description: "Constants should use SCREAMING_SNAKE_CASE." 1918 | StyleGuide: "#screaming-snake-case" 1919 | Enabled: true 1920 | VersionAdded: "0.50" 1921 | 1922 | Naming/FileName: 1923 | Description: "Use snake_case for source file names." 1924 | StyleGuide: "#snake-case-files" 1925 | Enabled: false 1926 | VersionAdded: "0.50" 1927 | # Camel case file names listed in `AllCops:Include` and all file names listed 1928 | # in `AllCops:Exclude` are excluded by default. Add extra excludes here. 1929 | Exclude: [] 1930 | # When `true`, requires that each source file should define a class or module 1931 | # with a name which matches the file name (converted to ... case). 1932 | # It further expects it to be nested inside modules which match the names 1933 | # of subdirectories in its path. 1934 | ExpectMatchingDefinition: false 1935 | # If non-`nil`, expect all source file names to match the following regex. 1936 | # Only the file name itself is matched, not the entire file path. 1937 | # Use anchors as necessary if you want to match the entire name rather than 1938 | # just a part of it. 1939 | Regex: ~ 1940 | # With `IgnoreExecutableScripts` set to `true`, this cop does not 1941 | # report offending filenames for executable scripts (i.e. source 1942 | # files with a shebang in the first line). 1943 | IgnoreExecutableScripts: true 1944 | AllowedAcronyms: 1945 | - CLI 1946 | - DSL 1947 | - ACL 1948 | - API 1949 | - ASCII 1950 | - CPU 1951 | - CSS 1952 | - DNS 1953 | - EOF 1954 | - GUID 1955 | - HTML 1956 | - HTTP 1957 | - HTTPS 1958 | - ID 1959 | - IP 1960 | - JSON 1961 | - LHS 1962 | - QPS 1963 | - RAM 1964 | - RHS 1965 | - RPC 1966 | - SLA 1967 | - SMTP 1968 | - SQL 1969 | - SSH 1970 | - TCP 1971 | - TLS 1972 | - TTL 1973 | - UDP 1974 | - UI 1975 | - UID 1976 | - UUID 1977 | - URI 1978 | - URL 1979 | - UTF8 1980 | - VM 1981 | - XML 1982 | - XMPP 1983 | - XSRF 1984 | - XSS 1985 | 1986 | Naming/HeredocDelimiterCase: 1987 | Description: "Use configured case for heredoc delimiters." 1988 | StyleGuide: "#heredoc-delimiters" 1989 | Enabled: true 1990 | VersionAdded: "0.50" 1991 | EnforcedStyle: uppercase 1992 | SupportedStyles: 1993 | - lowercase 1994 | - uppercase 1995 | 1996 | Naming/HeredocDelimiterNaming: 1997 | Description: "Use descriptive heredoc delimiters." 1998 | StyleGuide: "#heredoc-delimiters" 1999 | Enabled: true 2000 | VersionAdded: "0.50" 2001 | ForbiddenDelimiters: 2002 | - !ruby/regexp '/(^|\s)(EO[A-Z]{1}|END)(\s|$)/' 2003 | 2004 | Naming/MemoizedInstanceVariableName: 2005 | Description: >- 2006 | Memoized method name should match memo instance variable name. 2007 | Enabled: true 2008 | VersionAdded: "0.53" 2009 | VersionChanged: "0.58" 2010 | EnforcedStyleForLeadingUnderscores: disallowed 2011 | SupportedStylesForLeadingUnderscores: 2012 | - disallowed 2013 | - required 2014 | - optional 2015 | 2016 | Naming/MethodName: 2017 | Description: "Use the configured style when naming methods." 2018 | StyleGuide: "#snake-case-symbols-methods-vars" 2019 | Enabled: true 2020 | VersionAdded: "0.50" 2021 | EnforcedStyle: snake_case 2022 | SupportedStyles: 2023 | - snake_case 2024 | - camelCase 2025 | # Method names matching patterns are always allowed. 2026 | # 2027 | # IgnoredPatterns: 2028 | # - '\A\s*onSelectionBulkChange\s*' 2029 | # - '\A\s*onSelectionCleared\s*' 2030 | # 2031 | IgnoredPatterns: [] 2032 | 2033 | Naming/RescuedExceptionsVariableName: 2034 | Description: "Use consistent rescued exceptions variables naming." 2035 | Enabled: true 2036 | VersionAdded: "0.67" 2037 | VersionChanged: "0.68" 2038 | PreferredName: e 2039 | 2040 | Naming/BlockParameterName: 2041 | Description: >- 2042 | Checks for block parameter names that contain capital letters, 2043 | end in numbers, or do not meet a minimal length. 2044 | Enabled: true 2045 | VersionAdded: "0.53" 2046 | # Parameter names may be equal to or greater than this value 2047 | MinNameLength: 1 2048 | AllowNamesEndingInNumbers: true 2049 | # Whitelisted names that will not register an offense 2050 | AllowedNames: [] 2051 | # Blacklisted names that will register an offense 2052 | ForbiddenNames: [] 2053 | 2054 | Naming/MethodParameterName: 2055 | Description: >- 2056 | Checks for method parameter names that contain capital letters, 2057 | end in numbers, or do not meet a minimal length. 2058 | Enabled: true 2059 | VersionAdded: "0.53" 2060 | VersionChanged: "0.59" 2061 | # Parameter names may be equal to or greater than this value 2062 | MinNameLength: 3 2063 | AllowNamesEndingInNumbers: true 2064 | # Whitelisted names that will not register an offense 2065 | AllowedNames: 2066 | - io 2067 | - id 2068 | - to 2069 | - by 2070 | - "on" 2071 | - in 2072 | - at 2073 | - ip 2074 | - db 2075 | # Blacklisted names that will register an offense 2076 | ForbiddenNames: [] 2077 | 2078 | Naming/VariableName: 2079 | Description: "Use the configured style when naming variables." 2080 | StyleGuide: "#snake-case-symbols-methods-vars" 2081 | Enabled: true 2082 | VersionAdded: "0.50" 2083 | EnforcedStyle: snake_case 2084 | SupportedStyles: 2085 | - snake_case 2086 | - camelCase 2087 | 2088 | Naming/VariableNumber: 2089 | Description: "Use the configured style when numbering variables." 2090 | Enabled: true 2091 | VersionAdded: "0.50" 2092 | EnforcedStyle: normalcase 2093 | SupportedStyles: 2094 | - snake_case 2095 | - normalcase 2096 | - non_integer 2097 | 2098 | #################### Security ############################## 2099 | 2100 | Security/Eval: 2101 | Description: "The use of eval represents a serious security risk." 2102 | Enabled: true 2103 | VersionAdded: "0.47" 2104 | 2105 | Security/JSONLoad: 2106 | Description: >- 2107 | Prefer usage of `JSON.parse` over `JSON.load` due to potential 2108 | security issues. See reference for more information. 2109 | Reference: "https://ruby-doc.org/stdlib-2.3.0/libdoc/json/rdoc/JSON.html#method-i-load" 2110 | Enabled: true 2111 | VersionAdded: "0.43" 2112 | VersionChanged: "0.44" 2113 | # Autocorrect here will change to a method that may cause crashes depending 2114 | # on the value of the argument. 2115 | AutoCorrect: false 2116 | SafeAutoCorrect: false 2117 | 2118 | Security/MarshalLoad: 2119 | Description: >- 2120 | Avoid using of `Marshal.load` or `Marshal.restore` due to potential 2121 | security issues. See reference for more information. 2122 | Reference: "https://ruby-doc.org/core-2.3.3/Marshal.html#module-Marshal-label-Security+considerations" 2123 | Enabled: true 2124 | VersionAdded: "0.47" 2125 | 2126 | Security/Open: 2127 | Description: "The use of Kernel#open represents a serious security risk." 2128 | Enabled: true 2129 | VersionAdded: "0.53" 2130 | Safe: false 2131 | 2132 | Security/YAMLLoad: 2133 | Description: >- 2134 | Prefer usage of `YAML.safe_load` over `YAML.load` due to potential 2135 | security issues. See reference for more information. 2136 | Reference: "https://ruby-doc.org/stdlib-2.3.3/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security" 2137 | Enabled: true 2138 | VersionAdded: "0.47" 2139 | SafeAutoCorrect: false 2140 | 2141 | #################### Style ############################### 2142 | 2143 | Style/AccessModifierDeclarations: 2144 | Description: "Checks style of how access modifiers are used." 2145 | Enabled: true 2146 | VersionAdded: "0.57" 2147 | EnforcedStyle: group 2148 | SupportedStyles: 2149 | - inline 2150 | - group 2151 | 2152 | Style/Alias: 2153 | Description: "Use alias instead of alias_method." 2154 | StyleGuide: "#alias-method-lexically" 2155 | Enabled: true 2156 | VersionAdded: "0.9" 2157 | VersionChanged: "0.36" 2158 | EnforcedStyle: prefer_alias 2159 | SupportedStyles: 2160 | - prefer_alias 2161 | - prefer_alias_method 2162 | 2163 | Style/AndOr: 2164 | Description: "Use &&/|| instead of and/or." 2165 | StyleGuide: "#no-and-or-or" 2166 | Enabled: true 2167 | VersionAdded: "0.9" 2168 | VersionChanged: "0.25" 2169 | # Whether `and` and `or` are banned only in conditionals (conditionals) 2170 | # or completely (always). 2171 | EnforcedStyle: always 2172 | SupportedStyles: 2173 | - always 2174 | - conditionals 2175 | 2176 | Style/ArrayJoin: 2177 | Description: "Use Array#join instead of Array#*." 2178 | StyleGuide: "#array-join" 2179 | Enabled: true 2180 | VersionAdded: "0.20" 2181 | VersionChanged: "0.31" 2182 | 2183 | Style/AsciiComments: 2184 | Description: "Use only ascii symbols in comments." 2185 | StyleGuide: "#english-comments" 2186 | Enabled: true 2187 | VersionAdded: "0.9" 2188 | VersionChanged: "0.52" 2189 | AllowedChars: [] 2190 | 2191 | Style/Attr: 2192 | Description: "Checks for uses of Module#attr." 2193 | StyleGuide: "#attr" 2194 | Enabled: true 2195 | VersionAdded: "0.9" 2196 | VersionChanged: "0.12" 2197 | 2198 | Style/AutoResourceCleanup: 2199 | Description: "Suggests the usage of an auto resource cleanup version of a method (if available)." 2200 | Enabled: false 2201 | VersionAdded: "0.30" 2202 | 2203 | Style/BarePercentLiterals: 2204 | Description: "Checks if usage of %() or %Q() matches configuration." 2205 | StyleGuide: "#percent-q-shorthand" 2206 | Enabled: true 2207 | VersionAdded: "0.25" 2208 | EnforcedStyle: bare_percent 2209 | SupportedStyles: 2210 | - percent_q 2211 | - bare_percent 2212 | 2213 | Style/BeginBlock: 2214 | Description: "Avoid the use of BEGIN blocks." 2215 | StyleGuide: "#no-BEGIN-blocks" 2216 | Enabled: true 2217 | VersionAdded: "0.9" 2218 | 2219 | Style/BlockComments: 2220 | Description: "Do not use block comments." 2221 | StyleGuide: "#no-block-comments" 2222 | Enabled: true 2223 | VersionAdded: "0.9" 2224 | VersionChanged: "0.23" 2225 | 2226 | Style/BlockDelimiters: 2227 | Description: >- 2228 | Avoid using {...} for multi-line blocks (multiline chaining is 2229 | always ugly). 2230 | Prefer {...} over do...end for single-line blocks. 2231 | StyleGuide: "#single-line-blocks" 2232 | Enabled: true 2233 | VersionAdded: "0.30" 2234 | VersionChanged: "0.35" 2235 | EnforcedStyle: line_count_based 2236 | SupportedStyles: 2237 | # The `line_count_based` style enforces braces around single line blocks and 2238 | # do..end around multi-line blocks. 2239 | - line_count_based 2240 | # The `semantic` style enforces braces around functional blocks, where the 2241 | # primary purpose of the block is to return a value and do..end for 2242 | # multi-line procedural blocks, where the primary purpose of the block is 2243 | # its side-effects. Single-line procedural blocks may only use do-end, 2244 | # unless AllowBracesOnProceduralOneLiners has a truthy value (see below). 2245 | # 2246 | # This looks at the usage of a block's method to determine its type (e.g. is 2247 | # the result of a `map` assigned to a variable or passed to another 2248 | # method) but exceptions are permitted in the `ProceduralMethods`, 2249 | # `FunctionalMethods` and `IgnoredMethods` sections below. 2250 | - semantic 2251 | # The `braces_for_chaining` style enforces braces around single line blocks 2252 | # and do..end around multi-line blocks, except for multi-line blocks whose 2253 | # return value is being chained with another method (in which case braces 2254 | # are enforced). 2255 | - braces_for_chaining 2256 | # The `always_braces` style always enforces braces. 2257 | - always_braces 2258 | ProceduralMethods: 2259 | # Methods that are known to be procedural in nature but look functional from 2260 | # their usage, e.g. 2261 | # 2262 | # time = Benchmark.realtime do 2263 | # foo.bar 2264 | # end 2265 | # 2266 | # Here, the return value of the block is discarded but the return value of 2267 | # `Benchmark.realtime` is used. 2268 | - benchmark 2269 | - bm 2270 | - bmbm 2271 | - create 2272 | - each_with_object 2273 | - measure 2274 | - new 2275 | - realtime 2276 | - tap 2277 | - with_object 2278 | FunctionalMethods: 2279 | # Methods that are known to be functional in nature but look procedural from 2280 | # their usage, e.g. 2281 | # 2282 | # let(:foo) { Foo.new } 2283 | # 2284 | # Here, the return value of `Foo.new` is used to define a `foo` helper but 2285 | # doesn't appear to be used from the return value of `let`. 2286 | - let 2287 | - let! 2288 | - subject 2289 | - watch 2290 | IgnoredMethods: 2291 | # Methods that can be either procedural or functional and cannot be 2292 | # categorised from their usage alone, e.g. 2293 | # 2294 | # foo = lambda do |x| 2295 | # puts "Hello, #{x}" 2296 | # end 2297 | # 2298 | # foo = lambda do |x| 2299 | # x * 100 2300 | # end 2301 | # 2302 | # Here, it is impossible to tell from the return value of `lambda` whether 2303 | # the inner block's return value is significant. 2304 | - lambda 2305 | - proc 2306 | - it 2307 | # The AllowBracesOnProceduralOneLiners option is ignored unless the 2308 | # EnforcedStyle is set to `semantic`. If so: 2309 | # 2310 | # If AllowBracesOnProceduralOneLiners is unspecified, or set to any 2311 | # falsey value, then semantic purity is maintained, so one-line 2312 | # procedural blocks must use do-end, not braces. 2313 | # 2314 | # # bad 2315 | # collection.each { |element| puts element } 2316 | # 2317 | # # good 2318 | # collection.each do |element| puts element end 2319 | # 2320 | # If AllowBracesOnProceduralOneLiners is set to any truthy value, 2321 | # then one-line procedural blocks may use either style. 2322 | # 2323 | # # good 2324 | # collection.each { |element| puts element } 2325 | # 2326 | # # also good 2327 | # collection.each do |element| puts element end 2328 | AllowBracesOnProceduralOneLiners: false 2329 | 2330 | Style/CaseEquality: 2331 | Description: "Avoid explicit use of the case equality operator(===)." 2332 | StyleGuide: "#no-case-equality" 2333 | Enabled: true 2334 | VersionAdded: "0.9" 2335 | 2336 | Style/CharacterLiteral: 2337 | Description: "Checks for uses of character literals." 2338 | StyleGuide: "#no-character-literals" 2339 | Enabled: true 2340 | VersionAdded: "0.9" 2341 | 2342 | Style/ClassAndModuleChildren: 2343 | Description: "Checks style of children classes and modules." 2344 | StyleGuide: "#namespace-definition" 2345 | # Moving from compact to nested children requires knowledge of whether the 2346 | # outer parent is a module or a class. Moving from nested to compact requires 2347 | # verification that the outer parent is defined elsewhere. Rubocop does not 2348 | # have the knowledge to perform either operation safely and thus requires 2349 | # manual oversight. 2350 | SafeAutoCorrect: false 2351 | AutoCorrect: false 2352 | Enabled: false 2353 | VersionAdded: "0.19" 2354 | # 2355 | # Basically there are two different styles: 2356 | # 2357 | # `nested` - have each child on a separate line 2358 | # class Foo 2359 | # class Bar 2360 | # end 2361 | # end 2362 | # 2363 | # `compact` - combine definitions as much as possible 2364 | # class Foo::Bar 2365 | # end 2366 | # 2367 | # The compact style is only forced, for classes or modules with one child. 2368 | EnforcedStyle: nested 2369 | SupportedStyles: 2370 | - nested 2371 | - compact 2372 | 2373 | Style/ClassCheck: 2374 | Description: "Enforces consistent use of `Object#is_a?` or `Object#kind_of?`." 2375 | Enabled: true 2376 | VersionAdded: "0.24" 2377 | EnforcedStyle: is_a? 2378 | SupportedStyles: 2379 | - is_a? 2380 | - kind_of? 2381 | 2382 | Style/ClassMethods: 2383 | Description: "Use self when defining module/class methods." 2384 | StyleGuide: "#def-self-class-methods" 2385 | Enabled: true 2386 | VersionAdded: "0.9" 2387 | VersionChanged: "0.20" 2388 | 2389 | Style/ClassVars: 2390 | Description: "Avoid the use of class variables." 2391 | StyleGuide: "#no-class-vars" 2392 | Enabled: true 2393 | VersionAdded: "0.13" 2394 | 2395 | # Align with the style guide. 2396 | Style/CollectionMethods: 2397 | Description: "Preferred collection methods." 2398 | StyleGuide: "#map-find-select-reduce-size" 2399 | Enabled: false 2400 | VersionAdded: "0.9" 2401 | VersionChanged: "0.27" 2402 | Safe: false 2403 | # Mapping from undesired method to desired method 2404 | # e.g. to use `detect` over `find`: 2405 | # 2406 | # Style/CollectionMethods: 2407 | # PreferredMethods: 2408 | # find: detect 2409 | PreferredMethods: 2410 | collect: "map" 2411 | collect!: "map!" 2412 | inject: "reduce" 2413 | detect: "find" 2414 | find_all: "select" 2415 | 2416 | Style/ColonMethodCall: 2417 | Description: "Do not use :: for method call." 2418 | StyleGuide: "#double-colons" 2419 | Enabled: true 2420 | VersionAdded: "0.9" 2421 | 2422 | Style/ColonMethodDefinition: 2423 | Description: "Do not use :: for defining class methods." 2424 | StyleGuide: "#colon-method-definition" 2425 | Enabled: true 2426 | VersionAdded: "0.52" 2427 | 2428 | Style/CommandLiteral: 2429 | Description: "Use `` or %x around command literals." 2430 | StyleGuide: "#percent-x" 2431 | Enabled: true 2432 | VersionAdded: "0.30" 2433 | EnforcedStyle: backticks 2434 | # backticks: Always use backticks. 2435 | # percent_x: Always use `%x`. 2436 | # mixed: Use backticks on single-line commands, and `%x` on multi-line commands. 2437 | SupportedStyles: 2438 | - backticks 2439 | - percent_x 2440 | - mixed 2441 | # If `false`, the cop will always recommend using `%x` if one or more backticks 2442 | # are found in the command string. 2443 | AllowInnerBackticks: false 2444 | 2445 | # Checks formatting of special comments 2446 | Style/CommentAnnotation: 2447 | Description: >- 2448 | Checks formatting of special comments 2449 | (TODO, FIXME, OPTIMIZE, HACK, REVIEW). 2450 | StyleGuide: "#annotate-keywords" 2451 | Enabled: true 2452 | VersionAdded: "0.10" 2453 | VersionChanged: "0.31" 2454 | Keywords: 2455 | - TODO 2456 | - FIXME 2457 | - OPTIMIZE 2458 | - HACK 2459 | - REVIEW 2460 | 2461 | Style/CommentedKeyword: 2462 | Description: "Do not place comments on the same line as certain keywords." 2463 | Enabled: true 2464 | VersionAdded: "0.51" 2465 | 2466 | Style/ConditionalAssignment: 2467 | Description: >- 2468 | Use the return value of `if` and `case` statements for 2469 | assignment to a variable and variable comparison instead 2470 | of assigning that variable inside of each branch. 2471 | Enabled: true 2472 | VersionAdded: "0.36" 2473 | VersionChanged: "0.47" 2474 | EnforcedStyle: assign_to_condition 2475 | SupportedStyles: 2476 | - assign_to_condition 2477 | - assign_inside_condition 2478 | # When configured to `assign_to_condition`, `SingleLineConditionsOnly` 2479 | # will only register an offense when all branches of a condition are 2480 | # a single line. 2481 | # When configured to `assign_inside_condition`, `SingleLineConditionsOnly` 2482 | # will only register an offense for assignment to a condition that has 2483 | # at least one multiline branch. 2484 | SingleLineConditionsOnly: true 2485 | IncludeTernaryExpressions: true 2486 | 2487 | Style/ConstantVisibility: 2488 | Description: >- 2489 | Check that class- and module constants have 2490 | visibility declarations. 2491 | Enabled: false 2492 | VersionAdded: "0.66" 2493 | 2494 | # Checks that you have put a copyright in a comment before any code. 2495 | # 2496 | # You can override the default Notice in your .rubocop.yml file. 2497 | # 2498 | # In order to use autocorrect, you must supply a value for the 2499 | # `AutocorrectNotice` key that matches the regexp Notice. A blank 2500 | # `AutocorrectNotice` will cause an error during autocorrect. 2501 | # 2502 | # Autocorrect will add a copyright notice in a comment at the top 2503 | # of the file immediately after any shebang or encoding comments. 2504 | # 2505 | # Example rubocop.yml: 2506 | # 2507 | # Style/Copyright: 2508 | # Enabled: true 2509 | # Notice: 'Copyright (\(c\) )?2015 Yahoo! Inc' 2510 | # AutocorrectNotice: '# Copyright (c) 2015 Yahoo! Inc.' 2511 | # 2512 | Style/Copyright: 2513 | Description: "Include a copyright notice in each file before any code." 2514 | Enabled: false 2515 | VersionAdded: "0.30" 2516 | Notice: '^Copyright (\(c\) )?2[0-9]{3} .+' 2517 | AutocorrectNotice: "" 2518 | 2519 | Style/DateTime: 2520 | Description: "Use Time over DateTime." 2521 | StyleGuide: "#date--time" 2522 | Enabled: false 2523 | VersionAdded: "0.51" 2524 | VersionChanged: "0.59" 2525 | AllowCoercion: false 2526 | 2527 | Style/DefWithParentheses: 2528 | Description: "Use def with parentheses when there are arguments." 2529 | StyleGuide: "#method-parens" 2530 | Enabled: true 2531 | VersionAdded: "0.9" 2532 | VersionChanged: "0.12" 2533 | 2534 | Style/Dir: 2535 | Description: >- 2536 | Use the `__dir__` method to retrieve the canonicalized 2537 | absolute path to the current file. 2538 | Enabled: true 2539 | VersionAdded: "0.50" 2540 | 2541 | Style/Documentation: 2542 | Description: "Document classes and non-namespace modules." 2543 | Enabled: false 2544 | VersionAdded: "0.9" 2545 | Exclude: 2546 | - "spec/**/*" 2547 | - "test/**/*" 2548 | 2549 | Style/DocumentationMethod: 2550 | Description: "Checks for missing documentation comment for public methods." 2551 | Enabled: false 2552 | VersionAdded: "0.43" 2553 | Exclude: 2554 | - "spec/**/*" 2555 | - "test/**/*" 2556 | RequireForNonPublicMethods: false 2557 | 2558 | Style/DoubleCopDisableDirective: 2559 | Description: "Checks for double rubocop:disable comments on a single line." 2560 | Enabled: true 2561 | VersionAdded: "0.73" 2562 | 2563 | Style/DoubleNegation: 2564 | Description: "Checks for uses of double negation (!!)." 2565 | StyleGuide: "#no-bang-bang" 2566 | Enabled: true 2567 | VersionAdded: "0.19" 2568 | 2569 | Style/EachForSimpleLoop: 2570 | Description: >- 2571 | Use `Integer#times` for a simple loop which iterates a fixed 2572 | number of times. 2573 | Enabled: true 2574 | VersionAdded: "0.41" 2575 | 2576 | Style/EachWithObject: 2577 | Description: "Prefer `each_with_object` over `inject` or `reduce`." 2578 | Enabled: true 2579 | VersionAdded: "0.22" 2580 | VersionChanged: "0.42" 2581 | 2582 | Style/EmptyBlockParameter: 2583 | Description: "Omit pipes for empty block parameters." 2584 | Enabled: true 2585 | VersionAdded: "0.52" 2586 | 2587 | Style/EmptyCaseCondition: 2588 | Description: "Avoid empty condition in case statements." 2589 | Enabled: true 2590 | VersionAdded: "0.40" 2591 | 2592 | Style/EmptyElse: 2593 | Description: "Avoid empty else-clauses." 2594 | Enabled: true 2595 | VersionAdded: "0.28" 2596 | VersionChanged: "0.32" 2597 | EnforcedStyle: both 2598 | # empty - warn only on empty `else` 2599 | # nil - warn on `else` with nil in it 2600 | # both - warn on empty `else` and `else` with `nil` in it 2601 | SupportedStyles: 2602 | - empty 2603 | - nil 2604 | - both 2605 | 2606 | Style/EmptyLambdaParameter: 2607 | Description: "Omit parens for empty lambda parameters." 2608 | Enabled: true 2609 | VersionAdded: "0.52" 2610 | 2611 | Style/EmptyLiteral: 2612 | Description: "Prefer literals to Array.new/Hash.new/String.new." 2613 | StyleGuide: "#literal-array-hash" 2614 | Enabled: true 2615 | VersionAdded: "0.9" 2616 | VersionChanged: "0.12" 2617 | 2618 | Style/EmptyMethod: 2619 | Description: "Checks the formatting of empty method definitions." 2620 | StyleGuide: "#no-single-line-methods" 2621 | Enabled: true 2622 | VersionAdded: "0.46" 2623 | EnforcedStyle: compact 2624 | SupportedStyles: 2625 | - compact 2626 | - expanded 2627 | 2628 | Style/Encoding: 2629 | Description: "Use UTF-8 as the source file encoding." 2630 | StyleGuide: "#utf-8" 2631 | Enabled: true 2632 | VersionAdded: "0.9" 2633 | VersionChanged: "0.50" 2634 | 2635 | Style/EndBlock: 2636 | Description: "Avoid the use of END blocks." 2637 | StyleGuide: "#no-END-blocks" 2638 | Enabled: true 2639 | VersionAdded: "0.9" 2640 | 2641 | Style/EvalWithLocation: 2642 | Description: "Pass `__FILE__` and `__LINE__` to `eval` method, as they are used by backtraces." 2643 | Enabled: true 2644 | VersionAdded: "0.52" 2645 | 2646 | Style/EvenOdd: 2647 | Description: "Favor the use of `Integer#even?` && `Integer#odd?`." 2648 | StyleGuide: "#predicate-methods" 2649 | Enabled: true 2650 | VersionAdded: "0.12" 2651 | VersionChanged: "0.29" 2652 | 2653 | Style/ExpandPathArguments: 2654 | Description: "Use `expand_path(__dir__)` instead of `expand_path('..', __FILE__)`." 2655 | Enabled: true 2656 | VersionAdded: "0.53" 2657 | 2658 | Style/FloatDivision: 2659 | Description: "For performing float division, coerce one side only." 2660 | StyleGuide: "#float-division" 2661 | Reference: "https://github.com/rubocop-hq/ruby-style-guide/issues/628" 2662 | Enabled: true 2663 | VersionAdded: "0.72" 2664 | EnforcedStyle: single_coerce 2665 | SupportedStyles: 2666 | - left_coerce 2667 | - right_coerce 2668 | - single_coerce 2669 | - fdiv 2670 | 2671 | Style/For: 2672 | Description: "Checks use of for or each in multiline loops." 2673 | StyleGuide: "#no-for-loops" 2674 | Enabled: true 2675 | VersionAdded: "0.13" 2676 | VersionChanged: "0.59" 2677 | EnforcedStyle: each 2678 | SupportedStyles: 2679 | - each 2680 | - for 2681 | 2682 | Style/FormatString: 2683 | Description: "Enforce the use of Kernel#sprintf, Kernel#format or String#%." 2684 | StyleGuide: "#sprintf" 2685 | Enabled: true 2686 | VersionAdded: "0.19" 2687 | VersionChanged: "0.49" 2688 | EnforcedStyle: format 2689 | SupportedStyles: 2690 | - format 2691 | - sprintf 2692 | - percent 2693 | 2694 | Style/FormatStringToken: 2695 | Description: "Use a consistent style for format string tokens." 2696 | Enabled: true 2697 | EnforcedStyle: annotated 2698 | SupportedStyles: 2699 | # Prefer tokens which contain a sprintf like type annotation like 2700 | # `%s`, `%d`, `%f` 2701 | - annotated 2702 | # Prefer simple looking "template" style tokens like `%{name}`, `%{age}` 2703 | - template 2704 | - unannotated 2705 | VersionAdded: "0.49" 2706 | VersionChanged: "0.75" 2707 | 2708 | Style/FrozenStringLiteralComment: 2709 | Description: >- 2710 | Add the frozen_string_literal comment to the top of files 2711 | to help transition to frozen string literals by default. 2712 | Enabled: false 2713 | VersionAdded: "0.36" 2714 | VersionChanged: "0.69" 2715 | EnforcedStyle: always 2716 | SupportedStyles: 2717 | # `always` will always add the frozen string literal comment to a file 2718 | # regardless of the Ruby version or if `freeze` or `<<` are called on a 2719 | # string literal. If you run code against multiple versions of Ruby, it is 2720 | # possible that this will create errors in Ruby 2.3.0+. 2721 | - always 2722 | # `never` will enforce that the frozen string literal comment does not 2723 | # exist in a file. 2724 | - never 2725 | 2726 | Style/GlobalVars: 2727 | Description: "Do not introduce global variables." 2728 | StyleGuide: "#instance-vars" 2729 | Reference: "https://www.zenspider.com/ruby/quickref.html" 2730 | Enabled: true 2731 | VersionAdded: "0.13" 2732 | # Built-in global variables are allowed by default. 2733 | AllowedVariables: [] 2734 | 2735 | Style/GuardClause: 2736 | Description: "Check for conditionals that can be replaced with guard clauses." 2737 | StyleGuide: "#no-nested-conditionals" 2738 | Enabled: true 2739 | VersionAdded: "0.20" 2740 | VersionChanged: "0.22" 2741 | # `MinBodyLength` defines the number of lines of the a body of an `if` or `unless` 2742 | # needs to have to trigger this cop 2743 | MinBodyLength: 1 2744 | 2745 | Style/HashSyntax: 2746 | Description: >- 2747 | Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax 2748 | { :a => 1, :b => 2 }. 2749 | StyleGuide: "#hash-literals" 2750 | Enabled: true 2751 | VersionAdded: "0.9" 2752 | VersionChanged: "0.43" 2753 | EnforcedStyle: ruby19 2754 | SupportedStyles: 2755 | # checks for 1.9 syntax (e.g. {a: 1}) for all symbol keys 2756 | - ruby19 2757 | # checks for hash rocket syntax for all hashes 2758 | - hash_rockets 2759 | # forbids mixed key syntaxes (e.g. {a: 1, :b => 2}) 2760 | - no_mixed_keys 2761 | # enforces both ruby19 and no_mixed_keys styles 2762 | - ruby19_no_mixed_keys 2763 | # Force hashes that have a symbol value to use hash rockets 2764 | UseHashRocketsWithSymbolValues: false 2765 | # Do not suggest { a?: 1 } over { :a? => 1 } in ruby19 style 2766 | PreferHashRocketsForNonAlnumEndingSymbols: false 2767 | 2768 | Style/IdenticalConditionalBranches: 2769 | Description: >- 2770 | Checks that conditional statements do not have an identical 2771 | line at the end of each branch, which can validly be moved 2772 | out of the conditional. 2773 | Enabled: true 2774 | VersionAdded: "0.36" 2775 | 2776 | Style/IfInsideElse: 2777 | Description: "Finds if nodes inside else, which can be converted to elsif." 2778 | Enabled: true 2779 | AllowIfModifier: false 2780 | VersionAdded: "0.36" 2781 | 2782 | Style/IfUnlessModifier: 2783 | Description: >- 2784 | Favor modifier if/unless usage when you have a 2785 | single-line body. 2786 | StyleGuide: "#if-as-a-modifier" 2787 | Enabled: true 2788 | VersionAdded: "0.9" 2789 | VersionChanged: "0.30" 2790 | 2791 | Style/IfUnlessModifierOfIfUnless: 2792 | Description: >- 2793 | Avoid modifier if/unless usage on conditionals. 2794 | Enabled: true 2795 | VersionAdded: "0.39" 2796 | 2797 | Style/IfWithSemicolon: 2798 | Description: "Do not use if x; .... Use the ternary operator instead." 2799 | StyleGuide: "#no-semicolon-ifs" 2800 | Enabled: true 2801 | VersionAdded: "0.9" 2802 | 2803 | Style/ImplicitRuntimeError: 2804 | Description: >- 2805 | Use `raise` or `fail` with an explicit exception class and 2806 | message, rather than just a message. 2807 | Enabled: false 2808 | VersionAdded: "0.41" 2809 | 2810 | Style/InfiniteLoop: 2811 | Description: "Use Kernel#loop for infinite loops." 2812 | StyleGuide: "#infinite-loop" 2813 | Enabled: true 2814 | VersionAdded: "0.26" 2815 | VersionChanged: "0.61" 2816 | SafeAutoCorrect: true 2817 | 2818 | Style/InlineComment: 2819 | Description: "Avoid trailing inline comments." 2820 | Enabled: false 2821 | VersionAdded: "0.23" 2822 | 2823 | Style/InverseMethods: 2824 | Description: >- 2825 | Use the inverse method instead of `!.method` 2826 | if an inverse method is defined. 2827 | Enabled: true 2828 | Safe: false 2829 | VersionAdded: "0.48" 2830 | # `InverseMethods` are methods that can be inverted by a not (`not` or `!`) 2831 | # The relationship of inverse methods only needs to be defined in one direction. 2832 | # Keys and values both need to be defined as symbols. 2833 | InverseMethods: 2834 | :any?: :none? 2835 | :even?: :odd? 2836 | :==: :!= 2837 | :=~: :!~ 2838 | :<: :>= 2839 | :>: :<= 2840 | # `ActiveSupport` defines some common inverse methods. They are listed below, 2841 | # and not enabled by default. 2842 | #:present?: :blank?, 2843 | #:include?: :exclude? 2844 | # `InverseBlocks` are methods that are inverted by inverting the return 2845 | # of the block that is passed to the method 2846 | InverseBlocks: 2847 | :select: :reject 2848 | :select!: :reject! 2849 | 2850 | Style/IpAddresses: 2851 | Description: "Don't include literal IP addresses in code." 2852 | Enabled: false 2853 | VersionAdded: "0.58" 2854 | # Allow strings to be whitelisted 2855 | AllowedAddresses: 2856 | - "::" 2857 | # :: is a valid IPv6 address, but could potentially be legitimately in code 2858 | 2859 | Style/Lambda: 2860 | Description: "Use the new lambda literal syntax for single-line blocks." 2861 | StyleGuide: "#lambda-multi-line" 2862 | Enabled: true 2863 | VersionAdded: "0.9" 2864 | VersionChanged: "0.40" 2865 | EnforcedStyle: line_count_dependent 2866 | SupportedStyles: 2867 | - line_count_dependent 2868 | - lambda 2869 | - literal 2870 | 2871 | Style/LambdaCall: 2872 | Description: "Use lambda.call(...) instead of lambda.(...)." 2873 | StyleGuide: "#proc-call" 2874 | Enabled: true 2875 | VersionAdded: "0.13.1" 2876 | VersionChanged: "0.14" 2877 | EnforcedStyle: call 2878 | SupportedStyles: 2879 | - call 2880 | - braces 2881 | 2882 | Style/LineEndConcatenation: 2883 | Description: >- 2884 | Use \ instead of + or << to concatenate two string literals at 2885 | line end. 2886 | Enabled: true 2887 | SafeAutoCorrect: false 2888 | VersionAdded: "0.18" 2889 | VersionChanged: "0.64" 2890 | 2891 | Style/MethodCallWithArgsParentheses: 2892 | Description: "Use parentheses for method calls with arguments." 2893 | StyleGuide: "#method-invocation-parens" 2894 | Enabled: false 2895 | VersionAdded: "0.47" 2896 | VersionChanged: "0.61" 2897 | IgnoreMacros: true 2898 | IgnoredMethods: [] 2899 | IgnoredPatterns: [] 2900 | IncludedMacros: [] 2901 | AllowParenthesesInMultilineCall: false 2902 | AllowParenthesesInChaining: false 2903 | AllowParenthesesInCamelCaseMethod: false 2904 | EnforcedStyle: require_parentheses 2905 | SupportedStyles: 2906 | - require_parentheses 2907 | - omit_parentheses 2908 | 2909 | Style/MethodCallWithoutArgsParentheses: 2910 | Description: "Do not use parentheses for method calls with no arguments." 2911 | StyleGuide: "#method-invocation-parens" 2912 | Enabled: true 2913 | IgnoredMethods: [] 2914 | VersionAdded: "0.47" 2915 | VersionChanged: "0.55" 2916 | 2917 | Style/MethodCalledOnDoEndBlock: 2918 | Description: "Avoid chaining a method call on a do...end block." 2919 | StyleGuide: "#single-line-blocks" 2920 | Enabled: false 2921 | VersionAdded: "0.14" 2922 | 2923 | Style/MethodDefParentheses: 2924 | Description: >- 2925 | Checks if the method definitions have or don't have 2926 | parentheses. 2927 | StyleGuide: "#method-parens" 2928 | Enabled: true 2929 | VersionAdded: "0.16" 2930 | VersionChanged: "0.35" 2931 | EnforcedStyle: require_parentheses 2932 | SupportedStyles: 2933 | - require_parentheses 2934 | - require_no_parentheses 2935 | - require_no_parentheses_except_multiline 2936 | 2937 | Style/MethodMissingSuper: 2938 | Description: Checks for `method_missing` to call `super`. 2939 | StyleGuide: "#no-method-missing" 2940 | Enabled: true 2941 | VersionAdded: "0.56" 2942 | 2943 | Style/MinMax: 2944 | Description: >- 2945 | Use `Enumerable#minmax` instead of `Enumerable#min` 2946 | and `Enumerable#max` in conjunction. 2947 | Enabled: true 2948 | VersionAdded: "0.50" 2949 | 2950 | Style/MissingElse: 2951 | Description: >- 2952 | Require if/case expressions to have an else branches. 2953 | If enabled, it is recommended that 2954 | Style/UnlessElse and Style/EmptyElse be enabled. 2955 | This will conflict with Style/EmptyElse if 2956 | Style/EmptyElse is configured to style "both". 2957 | Enabled: false 2958 | VersionAdded: "0.30" 2959 | VersionChanged: "0.38" 2960 | EnforcedStyle: both 2961 | SupportedStyles: 2962 | # if - warn when an if expression is missing an else branch 2963 | # case - warn when a case expression is missing an else branch 2964 | # both - warn when an if or case expression is missing an else branch 2965 | - if 2966 | - case 2967 | - both 2968 | 2969 | Style/MissingRespondToMissing: 2970 | Description: >- 2971 | Checks if `method_missing` is implemented 2972 | without implementing `respond_to_missing`. 2973 | StyleGuide: "#no-method-missing" 2974 | Enabled: true 2975 | VersionAdded: "0.56" 2976 | 2977 | Style/MixinGrouping: 2978 | Description: "Checks for grouping of mixins in `class` and `module` bodies." 2979 | StyleGuide: "#mixin-grouping" 2980 | Enabled: true 2981 | VersionAdded: "0.48" 2982 | VersionChanged: "0.49" 2983 | EnforcedStyle: separated 2984 | SupportedStyles: 2985 | # separated: each mixed in module goes in a separate statement. 2986 | # grouped: mixed in modules are grouped into a single statement. 2987 | - separated 2988 | - grouped 2989 | 2990 | Style/MixinUsage: 2991 | Description: "Checks that `include`, `extend` and `prepend` exists at the top level." 2992 | Enabled: true 2993 | VersionAdded: "0.51" 2994 | 2995 | Style/ModuleFunction: 2996 | Description: "Checks for usage of `extend self` in modules." 2997 | StyleGuide: "#module-function" 2998 | Enabled: true 2999 | VersionAdded: "0.11" 3000 | VersionChanged: "0.65" 3001 | EnforcedStyle: module_function 3002 | SupportedStyles: 3003 | - module_function 3004 | - extend_self 3005 | Autocorrect: false 3006 | SafeAutoCorrect: false 3007 | 3008 | Style/MultilineBlockChain: 3009 | Description: "Avoid multi-line chains of blocks." 3010 | StyleGuide: "#single-line-blocks" 3011 | Enabled: true 3012 | VersionAdded: "0.13" 3013 | 3014 | Style/MultilineIfModifier: 3015 | Description: "Only use if/unless modifiers on single line statements." 3016 | StyleGuide: "#no-multiline-if-modifiers" 3017 | Enabled: true 3018 | VersionAdded: "0.45" 3019 | 3020 | Style/MultilineIfThen: 3021 | Description: "Do not use then for multi-line if/unless." 3022 | StyleGuide: "#no-then" 3023 | Enabled: true 3024 | VersionAdded: "0.9" 3025 | VersionChanged: "0.26" 3026 | 3027 | Style/MultilineMemoization: 3028 | Description: "Wrap multiline memoizations in a `begin` and `end` block." 3029 | Enabled: true 3030 | VersionAdded: "0.44" 3031 | VersionChanged: "0.48" 3032 | EnforcedStyle: keyword 3033 | SupportedStyles: 3034 | - keyword 3035 | - braces 3036 | 3037 | Style/MultilineMethodSignature: 3038 | Description: "Avoid multi-line method signatures." 3039 | Enabled: false 3040 | VersionAdded: "0.59" 3041 | 3042 | Style/MultilineTernaryOperator: 3043 | Description: >- 3044 | Avoid multi-line ?: (the ternary operator); 3045 | use if/unless instead. 3046 | StyleGuide: "#no-multiline-ternary" 3047 | Enabled: true 3048 | VersionAdded: "0.9" 3049 | 3050 | Style/MultilineWhenThen: 3051 | Description: "Do not use then for multi-line when statement." 3052 | StyleGuide: "#no-then" 3053 | Enabled: true 3054 | VersionAdded: "0.73" 3055 | 3056 | Style/MultipleComparison: 3057 | Description: >- 3058 | Avoid comparing a variable with multiple items in a conditional, 3059 | use Array#include? instead. 3060 | Enabled: true 3061 | VersionAdded: "0.49" 3062 | 3063 | Style/MutableConstant: 3064 | Description: "Do not assign mutable objects to constants." 3065 | Enabled: true 3066 | VersionAdded: "0.34" 3067 | VersionChanged: "0.65" 3068 | EnforcedStyle: literals 3069 | SupportedStyles: 3070 | # literals: freeze literals assigned to constants 3071 | # strict: freeze all constants 3072 | # Strict mode is considered an experimental feature. It has not been updated 3073 | # with an exhaustive list of all methods that will produce frozen objects so 3074 | # there is a decent chance of getting some false positives. Luckily, there is 3075 | # no harm in freezing an already frozen object. 3076 | - literals 3077 | - strict 3078 | 3079 | Style/NegatedIf: 3080 | Description: >- 3081 | Favor unless over if for negative conditions 3082 | (or control flow or). 3083 | StyleGuide: "#unless-for-negatives" 3084 | Enabled: true 3085 | VersionAdded: "0.20" 3086 | VersionChanged: "0.48" 3087 | EnforcedStyle: both 3088 | SupportedStyles: 3089 | # both: prefix and postfix negated `if` should both use `unless` 3090 | # prefix: only use `unless` for negated `if` statements positioned before the body of the statement 3091 | # postfix: only use `unless` for negated `if` statements positioned after the body of the statement 3092 | - both 3093 | - prefix 3094 | - postfix 3095 | 3096 | Style/NegatedUnless: 3097 | Description: "Favor if over unless for negative conditions." 3098 | StyleGuide: "#if-for-negatives" 3099 | Enabled: true 3100 | VersionAdded: "0.69" 3101 | EnforcedStyle: both 3102 | SupportedStyles: 3103 | # both: prefix and postfix negated `unless` should both use `if` 3104 | # prefix: only use `if` for negated `unless` statements positioned before the body of the statement 3105 | # postfix: only use `if` for negated `unless` statements positioned after the body of the statement 3106 | - both 3107 | - prefix 3108 | - postfix 3109 | 3110 | Style/NegatedWhile: 3111 | Description: "Favor until over while for negative conditions." 3112 | StyleGuide: "#until-for-negatives" 3113 | Enabled: true 3114 | VersionAdded: "0.20" 3115 | 3116 | Style/NestedModifier: 3117 | Description: "Avoid using nested modifiers." 3118 | StyleGuide: "#no-nested-modifiers" 3119 | Enabled: true 3120 | VersionAdded: "0.35" 3121 | 3122 | Style/NestedParenthesizedCalls: 3123 | Description: >- 3124 | Parenthesize method calls which are nested inside the 3125 | argument list of another parenthesized method call. 3126 | Enabled: true 3127 | VersionAdded: "0.36" 3128 | VersionChanged: "0.50" 3129 | AllowedMethods: 3130 | - be 3131 | - be_a 3132 | - be_an 3133 | - be_between 3134 | - be_falsey 3135 | - be_kind_of 3136 | - be_instance_of 3137 | - be_truthy 3138 | - be_within 3139 | - eq 3140 | - eql 3141 | - end_with 3142 | - include 3143 | - match 3144 | - raise_error 3145 | - respond_to 3146 | - start_with 3147 | 3148 | Style/NestedTernaryOperator: 3149 | Description: "Use one expression per branch in a ternary operator." 3150 | StyleGuide: "#no-nested-ternary" 3151 | Enabled: true 3152 | VersionAdded: "0.9" 3153 | 3154 | Style/Next: 3155 | Description: "Use `next` to skip iteration instead of a condition at the end." 3156 | StyleGuide: "#no-nested-conditionals" 3157 | Enabled: true 3158 | VersionAdded: "0.22" 3159 | VersionChanged: "0.35" 3160 | # With `always` all conditions at the end of an iteration needs to be 3161 | # replaced by next - with `skip_modifier_ifs` the modifier if like this one 3162 | # are ignored: [1, 2].each { |a| return 'yes' if a == 1 } 3163 | EnforcedStyle: skip_modifier_ifs 3164 | # `MinBodyLength` defines the number of lines of the a body of an `if` or `unless` 3165 | # needs to have to trigger this cop 3166 | MinBodyLength: 3 3167 | SupportedStyles: 3168 | - skip_modifier_ifs 3169 | - always 3170 | 3171 | Style/NilComparison: 3172 | Description: "Prefer x.nil? to x == nil." 3173 | StyleGuide: "#predicate-methods" 3174 | Enabled: true 3175 | VersionAdded: "0.12" 3176 | VersionChanged: "0.59" 3177 | EnforcedStyle: predicate 3178 | SupportedStyles: 3179 | - predicate 3180 | - comparison 3181 | 3182 | Style/NonNilCheck: 3183 | Description: "Checks for redundant nil checks." 3184 | StyleGuide: "#no-non-nil-checks" 3185 | Enabled: true 3186 | VersionAdded: "0.20" 3187 | VersionChanged: "0.22" 3188 | # With `IncludeSemanticChanges` set to `true`, this cop reports offenses for 3189 | # `!x.nil?` and autocorrects that and `x != nil` to solely `x`, which is 3190 | # **usually** OK, but might change behavior. 3191 | # 3192 | # With `IncludeSemanticChanges` set to `false`, this cop does not report 3193 | # offenses for `!x.nil?` and does no changes that might change behavior. 3194 | IncludeSemanticChanges: false 3195 | 3196 | Style/Not: 3197 | Description: "Use ! instead of not." 3198 | StyleGuide: "#bang-not-not" 3199 | Enabled: true 3200 | VersionAdded: "0.9" 3201 | VersionChanged: "0.20" 3202 | 3203 | Style/NumericLiteralPrefix: 3204 | Description: "Use smallcase prefixes for numeric literals." 3205 | StyleGuide: "#numeric-literal-prefixes" 3206 | Enabled: true 3207 | VersionAdded: "0.41" 3208 | EnforcedOctalStyle: zero_with_o 3209 | SupportedOctalStyles: 3210 | - zero_with_o 3211 | - zero_only 3212 | 3213 | Style/NumericLiterals: 3214 | Description: >- 3215 | Add underscores to large numeric literals to improve their 3216 | readability. 3217 | StyleGuide: "#underscores-in-numerics" 3218 | Enabled: true 3219 | VersionAdded: "0.9" 3220 | VersionChanged: "0.48" 3221 | MinDigits: 5 3222 | Strict: false 3223 | 3224 | Style/NumericPredicate: 3225 | Description: >- 3226 | Checks for the use of predicate- or comparison methods for 3227 | numeric comparisons. 3228 | StyleGuide: "#predicate-methods" 3229 | Safe: false 3230 | # This will change to a new method call which isn't guaranteed to be on the 3231 | # object. Switching these methods has to be done with knowledge of the types 3232 | # of the variables which rubocop doesn't have. 3233 | SafeAutoCorrect: false 3234 | AutoCorrect: false 3235 | Enabled: true 3236 | VersionAdded: "0.42" 3237 | VersionChanged: "0.59" 3238 | EnforcedStyle: predicate 3239 | SupportedStyles: 3240 | - predicate 3241 | - comparison 3242 | IgnoredMethods: [] 3243 | # Exclude RSpec specs because assertions like `expect(1).to be > 0` cause 3244 | # false positives. 3245 | Exclude: 3246 | - "spec/**/*" 3247 | 3248 | Style/OneLineConditional: 3249 | Description: >- 3250 | Favor the ternary operator(?:) over 3251 | if/then/else/end constructs. 3252 | StyleGuide: "#ternary-operator" 3253 | Enabled: true 3254 | VersionAdded: "0.9" 3255 | VersionChanged: "0.38" 3256 | 3257 | Style/OptionHash: 3258 | Description: "Don't use option hashes when you can use keyword arguments." 3259 | Enabled: false 3260 | VersionAdded: "0.33" 3261 | VersionChanged: "0.34" 3262 | # A list of parameter names that will be flagged by this cop. 3263 | SuspiciousParamNames: 3264 | - options 3265 | - opts 3266 | - args 3267 | - params 3268 | - parameters 3269 | 3270 | Style/OptionalArguments: 3271 | Description: >- 3272 | Checks for optional arguments that do not appear at the end 3273 | of the argument list. 3274 | StyleGuide: "#optional-arguments" 3275 | Enabled: true 3276 | VersionAdded: "0.33" 3277 | 3278 | Style/OrAssignment: 3279 | Description: "Recommend usage of double pipe equals (||=) where applicable." 3280 | StyleGuide: "#double-pipe-for-uninit" 3281 | Enabled: true 3282 | VersionAdded: "0.50" 3283 | 3284 | Style/ParallelAssignment: 3285 | Description: >- 3286 | Check for simple usages of parallel assignment. 3287 | It will only warn when the number of variables 3288 | matches on both sides of the assignment. 3289 | StyleGuide: "#parallel-assignment" 3290 | Enabled: true 3291 | VersionAdded: "0.32" 3292 | 3293 | Style/ParenthesesAroundCondition: 3294 | Description: >- 3295 | Don't use parentheses around the condition of an 3296 | if/unless/while. 3297 | StyleGuide: "#no-parens-around-condition" 3298 | Enabled: true 3299 | VersionAdded: "0.9" 3300 | VersionChanged: "0.56" 3301 | AllowSafeAssignment: true 3302 | AllowInMultilineConditions: false 3303 | 3304 | Style/PercentLiteralDelimiters: 3305 | Description: "Use `%`-literal delimiters consistently." 3306 | StyleGuide: "#percent-literal-braces" 3307 | Enabled: false 3308 | VersionAdded: "0.19" 3309 | # Specify the default preferred delimiter for all types with the 'default' key 3310 | # Override individual delimiters (even with default specified) by specifying 3311 | # an individual key 3312 | PreferredDelimiters: 3313 | default: () 3314 | "%i": "[]" 3315 | "%I": "[]" 3316 | "%r": "{}" 3317 | "%w": "[]" 3318 | "%W": "[]" 3319 | VersionChanged: "0.48.1" 3320 | 3321 | Style/PercentQLiterals: 3322 | Description: "Checks if uses of %Q/%q match the configured preference." 3323 | Enabled: true 3324 | VersionAdded: "0.25" 3325 | EnforcedStyle: lower_case_q 3326 | SupportedStyles: 3327 | - lower_case_q # Use `%q` when possible, `%Q` when necessary 3328 | - upper_case_q # Always use `%Q` 3329 | 3330 | Style/PerlBackrefs: 3331 | Description: "Avoid Perl-style regex back references." 3332 | StyleGuide: "#no-perl-regexp-last-matchers" 3333 | Enabled: true 3334 | VersionAdded: "0.13" 3335 | 3336 | Style/PreferredHashMethods: 3337 | Description: "Checks use of `has_key?` and `has_value?` Hash methods." 3338 | StyleGuide: "#hash-key" 3339 | Enabled: true 3340 | Safe: false 3341 | VersionAdded: "0.41" 3342 | VersionChanged: "0.70" 3343 | EnforcedStyle: short 3344 | SupportedStyles: 3345 | - short 3346 | - verbose 3347 | 3348 | Style/Proc: 3349 | Description: "Use proc instead of Proc.new." 3350 | StyleGuide: "#proc" 3351 | Enabled: true 3352 | VersionAdded: "0.9" 3353 | VersionChanged: "0.18" 3354 | 3355 | Style/RaiseArgs: 3356 | Description: "Checks the arguments passed to raise/fail." 3357 | StyleGuide: "#exception-class-messages" 3358 | Enabled: true 3359 | VersionAdded: "0.14" 3360 | VersionChanged: "0.40" 3361 | EnforcedStyle: exploded 3362 | SupportedStyles: 3363 | - compact # raise Exception.new(msg) 3364 | - exploded # raise Exception, msg 3365 | 3366 | Style/RandomWithOffset: 3367 | Description: >- 3368 | Prefer to use ranges when generating random numbers instead of 3369 | integers with offsets. 3370 | StyleGuide: "#random-numbers" 3371 | Enabled: true 3372 | VersionAdded: "0.52" 3373 | 3374 | Style/RedundantBegin: 3375 | Description: "Don't use begin blocks when they are not needed." 3376 | StyleGuide: "#begin-implicit" 3377 | Enabled: true 3378 | VersionAdded: "0.10" 3379 | VersionChanged: "0.21" 3380 | 3381 | Style/RedundantConditional: 3382 | Description: "Don't return true/false from a conditional." 3383 | Enabled: true 3384 | VersionAdded: "0.50" 3385 | 3386 | Style/RedundantException: 3387 | Description: "Checks for an obsolete RuntimeException argument in raise/fail." 3388 | StyleGuide: "#no-explicit-runtimeerror" 3389 | Enabled: true 3390 | VersionAdded: "0.14" 3391 | VersionChanged: "0.29" 3392 | 3393 | Style/RedundantFreeze: 3394 | Description: "Checks usages of Object#freeze on immutable objects." 3395 | Enabled: true 3396 | VersionAdded: "0.34" 3397 | VersionChanged: "0.66" 3398 | 3399 | Style/RedundantParentheses: 3400 | Description: "Checks for parentheses that seem not to serve any purpose." 3401 | Enabled: true 3402 | VersionAdded: "0.36" 3403 | 3404 | Style/RedundantReturn: 3405 | Description: "Don't use return where it's not required." 3406 | StyleGuide: "#no-explicit-return" 3407 | Enabled: true 3408 | VersionAdded: "0.10" 3409 | VersionChanged: "0.14" 3410 | # When `true` allows code like `return x, y`. 3411 | AllowMultipleReturnValues: false 3412 | 3413 | Style/RedundantSelf: 3414 | Description: "Don't use self where it's not needed." 3415 | StyleGuide: "#no-self-unless-required" 3416 | Enabled: true 3417 | VersionAdded: "0.10" 3418 | VersionChanged: "0.13" 3419 | 3420 | Style/RedundantSortBy: 3421 | Description: "Use `sort` instead of `sort_by { |x| x }`." 3422 | Enabled: true 3423 | VersionAdded: "0.36" 3424 | 3425 | Style/RegexpLiteral: 3426 | Description: "Use / or %r around regular expressions." 3427 | StyleGuide: "#percent-r" 3428 | Enabled: true 3429 | VersionAdded: "0.9" 3430 | VersionChanged: "0.30" 3431 | EnforcedStyle: slashes 3432 | # slashes: Always use slashes. 3433 | # percent_r: Always use `%r`. 3434 | # mixed: Use slashes on single-line regexes, and `%r` on multi-line regexes. 3435 | SupportedStyles: 3436 | - slashes 3437 | - percent_r 3438 | - mixed 3439 | # If `false`, the cop will always recommend using `%r` if one or more slashes 3440 | # are found in the regexp string. 3441 | AllowInnerSlashes: false 3442 | 3443 | Style/RescueModifier: 3444 | Description: "Avoid using rescue in its modifier form." 3445 | StyleGuide: "#no-rescue-modifiers" 3446 | Enabled: true 3447 | VersionAdded: "0.9" 3448 | VersionChanged: "0.34" 3449 | 3450 | Style/RescueStandardError: 3451 | Description: "Avoid rescuing without specifying an error class." 3452 | Enabled: true 3453 | VersionAdded: "0.52" 3454 | EnforcedStyle: explicit 3455 | # implicit: Do not include the error class, `rescue` 3456 | # explicit: Require an error class `rescue StandardError` 3457 | SupportedStyles: 3458 | - implicit 3459 | - explicit 3460 | 3461 | Style/ReturnNil: 3462 | Description: "Use return instead of return nil." 3463 | Enabled: false 3464 | EnforcedStyle: return 3465 | SupportedStyles: 3466 | - return 3467 | - return_nil 3468 | VersionAdded: "0.50" 3469 | 3470 | Style/SafeNavigation: 3471 | Description: >- 3472 | This cop transforms usages of a method call safeguarded by 3473 | a check for the existence of the object to 3474 | safe navigation (`&.`). 3475 | Enabled: true 3476 | VersionAdded: "0.43" 3477 | VersionChanged: "0.56" 3478 | # Safe navigation may cause a statement to start returning `nil` in addition 3479 | # to whatever it used to return. 3480 | ConvertCodeThatCanStartToReturnNil: false 3481 | AllowedMethods: 3482 | - present? 3483 | - blank? 3484 | - presence 3485 | - try 3486 | - try! 3487 | 3488 | Style/Sample: 3489 | Description: >- 3490 | Use `sample` instead of `shuffle.first`, 3491 | `shuffle.last`, and `shuffle[Integer]`. 3492 | Reference: "https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code" 3493 | Enabled: true 3494 | VersionAdded: "0.30" 3495 | 3496 | Style/SelfAssignment: 3497 | Description: >- 3498 | Checks for places where self-assignment shorthand should have 3499 | been used. 3500 | StyleGuide: "#self-assignment" 3501 | Enabled: true 3502 | VersionAdded: "0.19" 3503 | VersionChanged: "0.29" 3504 | 3505 | Style/Semicolon: 3506 | Description: "Don't use semicolons to terminate expressions." 3507 | StyleGuide: "#no-semicolon" 3508 | Enabled: true 3509 | VersionAdded: "0.9" 3510 | VersionChanged: "0.19" 3511 | # Allow `;` to separate several expressions on the same line. 3512 | AllowAsExpressionSeparator: false 3513 | 3514 | Style/Send: 3515 | Description: "Prefer `Object#__send__` or `Object#public_send` to `send`, as `send` may overlap with existing methods." 3516 | StyleGuide: "#prefer-public-send" 3517 | Enabled: false 3518 | VersionAdded: "0.33" 3519 | 3520 | Style/SignalException: 3521 | Description: "Checks for proper usage of fail and raise." 3522 | StyleGuide: "#prefer-raise-over-fail" 3523 | Enabled: true 3524 | VersionAdded: "0.11" 3525 | VersionChanged: "0.37" 3526 | EnforcedStyle: only_raise 3527 | SupportedStyles: 3528 | - only_raise 3529 | - only_fail 3530 | - semantic 3531 | 3532 | Style/SingleLineBlockParams: 3533 | Description: "Enforces the names of some block params." 3534 | Enabled: false 3535 | VersionAdded: "0.16" 3536 | VersionChanged: "0.47" 3537 | Methods: 3538 | - reduce: 3539 | - acc 3540 | - elem 3541 | - inject: 3542 | - acc 3543 | - elem 3544 | 3545 | Style/SingleLineMethods: 3546 | Description: "Avoid single-line methods." 3547 | StyleGuide: "#no-single-line-methods" 3548 | Enabled: true 3549 | VersionAdded: "0.9" 3550 | VersionChanged: "0.19" 3551 | AllowIfMethodIsEmpty: true 3552 | 3553 | Style/SpecialGlobalVars: 3554 | Description: "Avoid Perl-style global variables." 3555 | StyleGuide: "#no-cryptic-perlisms" 3556 | Enabled: true 3557 | VersionAdded: "0.13" 3558 | VersionChanged: "0.36" 3559 | SafeAutoCorrect: false 3560 | EnforcedStyle: use_english_names 3561 | SupportedStyles: 3562 | - use_perl_names 3563 | - use_english_names 3564 | 3565 | Style/StabbyLambdaParentheses: 3566 | Description: "Check for the usage of parentheses around stabby lambda arguments." 3567 | StyleGuide: "#stabby-lambda-with-args" 3568 | Enabled: true 3569 | VersionAdded: "0.35" 3570 | EnforcedStyle: require_parentheses 3571 | SupportedStyles: 3572 | - require_parentheses 3573 | - require_no_parentheses 3574 | 3575 | Style/StderrPuts: 3576 | Description: "Use `warn` instead of `$stderr.puts`." 3577 | StyleGuide: "#warn" 3578 | Enabled: true 3579 | VersionAdded: "0.51" 3580 | 3581 | Style/StringHashKeys: 3582 | Description: "Prefer symbols instead of strings as hash keys." 3583 | StyleGuide: "#symbols-as-keys" 3584 | Enabled: false 3585 | VersionAdded: "0.52" 3586 | VersionChanged: "0.75" 3587 | Safe: false 3588 | 3589 | Style/StringLiterals: 3590 | Description: "Checks if uses of quotes match the configured preference." 3591 | StyleGuide: "#consistent-string-literals" 3592 | Enabled: true 3593 | VersionAdded: "0.9" 3594 | VersionChanged: "0.36" 3595 | EnforcedStyle: single_quotes 3596 | SupportedStyles: 3597 | - single_quotes 3598 | - double_quotes 3599 | # If `true`, strings which span multiple lines using `\` for continuation must 3600 | # use the same type of quotes on each line. 3601 | ConsistentQuotesInMultiline: false 3602 | 3603 | Style/StringLiteralsInInterpolation: 3604 | Description: >- 3605 | Checks if uses of quotes inside expressions in interpolated 3606 | strings match the configured preference. 3607 | Enabled: true 3608 | VersionAdded: "0.27" 3609 | EnforcedStyle: single_quotes 3610 | SupportedStyles: 3611 | - single_quotes 3612 | - double_quotes 3613 | 3614 | Style/StringMethods: 3615 | Description: "Checks if configured preferred methods are used over non-preferred." 3616 | Enabled: false 3617 | VersionAdded: "0.34" 3618 | VersionChanged: "0.34.2" 3619 | # Mapping from undesired method to desired_method 3620 | # e.g. to use `to_sym` over `intern`: 3621 | # 3622 | # StringMethods: 3623 | # PreferredMethods: 3624 | # intern: to_sym 3625 | PreferredMethods: 3626 | intern: to_sym 3627 | 3628 | Style/Strip: 3629 | Description: "Use `strip` instead of `lstrip.rstrip`." 3630 | Enabled: true 3631 | VersionAdded: "0.36" 3632 | 3633 | Style/StructInheritance: 3634 | Description: "Checks for inheritance from Struct.new." 3635 | StyleGuide: "#no-extend-struct-new" 3636 | Enabled: true 3637 | VersionAdded: "0.29" 3638 | 3639 | Style/SymbolArray: 3640 | Description: "Use %i or %I for arrays of symbols." 3641 | StyleGuide: "#percent-i" 3642 | Enabled: true 3643 | VersionAdded: "0.9" 3644 | VersionChanged: "0.49" 3645 | EnforcedStyle: percent 3646 | MinSize: 2 3647 | SupportedStyles: 3648 | - percent 3649 | - brackets 3650 | 3651 | Style/SymbolLiteral: 3652 | Description: "Use plain symbols instead of string symbols when possible." 3653 | Enabled: true 3654 | VersionAdded: "0.30" 3655 | 3656 | Style/SymbolProc: 3657 | Description: "Use symbols as procs instead of blocks when possible." 3658 | Enabled: true 3659 | SafeAutoCorrect: false 3660 | VersionAdded: "0.26" 3661 | VersionChanged: "0.64" 3662 | # A list of method names to be ignored by the check. 3663 | # The names should be fairly unique, otherwise you'll end up ignoring lots of code. 3664 | IgnoredMethods: 3665 | - respond_to 3666 | - define_method 3667 | 3668 | Style/TernaryParentheses: 3669 | Description: "Checks for use of parentheses around ternary conditions." 3670 | Enabled: true 3671 | VersionAdded: "0.42" 3672 | VersionChanged: "0.46" 3673 | EnforcedStyle: require_no_parentheses 3674 | SupportedStyles: 3675 | - require_parentheses 3676 | - require_no_parentheses 3677 | - require_parentheses_when_complex 3678 | AllowSafeAssignment: true 3679 | 3680 | Style/TrailingBodyOnClass: 3681 | Description: "Class body goes below class statement." 3682 | Enabled: true 3683 | VersionAdded: "0.53" 3684 | 3685 | Style/TrailingBodyOnMethodDefinition: 3686 | Description: "Method body goes below definition." 3687 | Enabled: true 3688 | VersionAdded: "0.52" 3689 | 3690 | Style/TrailingBodyOnModule: 3691 | Description: "Module body goes below module statement." 3692 | Enabled: true 3693 | VersionAdded: "0.53" 3694 | 3695 | Style/TrailingCommaInArguments: 3696 | Description: "Checks for trailing comma in argument lists." 3697 | StyleGuide: "#no-trailing-params-comma" 3698 | Enabled: true 3699 | VersionAdded: "0.36" 3700 | # If `comma`, the cop requires a comma after the last argument, but only for 3701 | # parenthesized method calls where each argument is on its own line. 3702 | # If `consistent_comma`, the cop requires a comma after the last argument, 3703 | # for all parenthesized method calls with arguments. 3704 | EnforcedStyleForMultiline: no_comma 3705 | SupportedStylesForMultiline: 3706 | - comma 3707 | - consistent_comma 3708 | - no_comma 3709 | 3710 | Style/TrailingCommaInArrayLiteral: 3711 | Description: "Checks for trailing comma in array literals." 3712 | StyleGuide: "#no-trailing-array-commas" 3713 | Enabled: true 3714 | VersionAdded: "0.53" 3715 | # but only when each item is on its own line. 3716 | # If `consistent_comma`, the cop requires a comma after the last item of all 3717 | # non-empty array literals. 3718 | EnforcedStyleForMultiline: no_comma 3719 | SupportedStylesForMultiline: 3720 | - comma 3721 | - consistent_comma 3722 | - no_comma 3723 | 3724 | Style/TrailingCommaInHashLiteral: 3725 | Description: "Checks for trailing comma in hash literals." 3726 | Enabled: true 3727 | # If `comma`, the cop requires a comma after the last item in a hash, 3728 | # but only when each item is on its own line. 3729 | # If `consistent_comma`, the cop requires a comma after the last item of all 3730 | # non-empty hash literals. 3731 | EnforcedStyleForMultiline: no_comma 3732 | SupportedStylesForMultiline: 3733 | - comma 3734 | - consistent_comma 3735 | - no_comma 3736 | VersionAdded: "0.53" 3737 | 3738 | Style/TrailingMethodEndStatement: 3739 | Description: "Checks for trailing end statement on line of method body." 3740 | Enabled: true 3741 | VersionAdded: "0.52" 3742 | 3743 | Style/TrailingUnderscoreVariable: 3744 | Description: >- 3745 | Checks for the usage of unneeded trailing underscores at the 3746 | end of parallel variable assignment. 3747 | AllowNamedUnderscoreVariables: true 3748 | Enabled: true 3749 | VersionAdded: "0.31" 3750 | VersionChanged: "0.35" 3751 | 3752 | # `TrivialAccessors` requires exact name matches and doesn't allow 3753 | # predicated methods by default. 3754 | Style/TrivialAccessors: 3755 | Description: "Prefer attr_* methods to trivial readers/writers." 3756 | StyleGuide: "#attr_family" 3757 | Enabled: true 3758 | VersionAdded: "0.9" 3759 | VersionChanged: "0.38" 3760 | # When set to `false` the cop will suggest the use of accessor methods 3761 | # in situations like: 3762 | # 3763 | # def name 3764 | # @other_name 3765 | # end 3766 | # 3767 | # This way you can uncover "hidden" attributes in your code. 3768 | ExactNameMatch: true 3769 | AllowPredicates: true 3770 | # Allows trivial writers that don't end in an equal sign. e.g. 3771 | # 3772 | # def on_exception(action) 3773 | # @on_exception=action 3774 | # end 3775 | # on_exception :restart 3776 | # 3777 | # Commonly used in DSLs 3778 | AllowDSLWriters: false 3779 | IgnoreClassMethods: false 3780 | AllowedMethods: 3781 | - to_ary 3782 | - to_a 3783 | - to_c 3784 | - to_enum 3785 | - to_h 3786 | - to_hash 3787 | - to_i 3788 | - to_int 3789 | - to_io 3790 | - to_open 3791 | - to_path 3792 | - to_proc 3793 | - to_r 3794 | - to_regexp 3795 | - to_str 3796 | - to_s 3797 | - to_sym 3798 | 3799 | Style/UnlessElse: 3800 | Description: >- 3801 | Do not use unless with else. Rewrite these with the positive 3802 | case first. 3803 | StyleGuide: "#no-else-with-unless" 3804 | Enabled: true 3805 | VersionAdded: "0.9" 3806 | 3807 | Style/RedundantCapitalW: 3808 | Description: "Checks for %W when interpolation is not needed." 3809 | Enabled: true 3810 | VersionAdded: "0.21" 3811 | 3812 | Style/RedundantCondition: 3813 | Description: "Checks for unnecessary conditional expressions." 3814 | Enabled: true 3815 | VersionAdded: "0.57" 3816 | 3817 | Style/RedundantInterpolation: 3818 | Description: "Checks for strings that are just an interpolated expression." 3819 | Enabled: true 3820 | VersionAdded: "0.36" 3821 | 3822 | Style/RedundantPercentQ: 3823 | Description: "Checks for %q/%Q when single quotes or double quotes would do." 3824 | StyleGuide: "#percent-q" 3825 | Enabled: false 3826 | VersionAdded: "0.24" 3827 | 3828 | Style/RedundantSort: 3829 | Description: >- 3830 | Use `min` instead of `sort.first`, 3831 | `max_by` instead of `sort_by...last`, etc. 3832 | Enabled: true 3833 | VersionAdded: "0.55" 3834 | 3835 | Style/UnpackFirst: 3836 | Description: >- 3837 | Checks for accessing the first element of `String#unpack` 3838 | instead of using `unpack1`. 3839 | Enabled: true 3840 | VersionAdded: "0.54" 3841 | 3842 | Style/VariableInterpolation: 3843 | Description: >- 3844 | Don't interpolate global, instance and class variables 3845 | directly in strings. 3846 | StyleGuide: "#curlies-interpolate" 3847 | Enabled: true 3848 | VersionAdded: "0.9" 3849 | VersionChanged: "0.20" 3850 | 3851 | Style/WhenThen: 3852 | Description: "Use when x then ... for one-line cases." 3853 | StyleGuide: "#one-line-cases" 3854 | Enabled: true 3855 | VersionAdded: "0.9" 3856 | 3857 | Style/WhileUntilDo: 3858 | Description: "Checks for redundant do after while or until." 3859 | StyleGuide: "#no-multiline-while-do" 3860 | Enabled: true 3861 | VersionAdded: "0.9" 3862 | 3863 | Style/WhileUntilModifier: 3864 | Description: >- 3865 | Favor modifier while/until usage when you have a 3866 | single-line body. 3867 | StyleGuide: "#while-as-a-modifier" 3868 | Enabled: true 3869 | VersionAdded: "0.9" 3870 | VersionChanged: "0.30" 3871 | 3872 | Style/WordArray: 3873 | Description: "Use %w or %W for arrays of words." 3874 | StyleGuide: "#percent-w" 3875 | Enabled: true 3876 | VersionAdded: "0.9" 3877 | VersionChanged: "0.36" 3878 | EnforcedStyle: percent 3879 | SupportedStyles: 3880 | # percent style: %w(word1 word2) 3881 | - percent 3882 | # bracket style: ['word1', 'word2'] 3883 | - brackets 3884 | # The `MinSize` option causes the `WordArray` rule to be ignored for arrays 3885 | # smaller than a certain size. The rule is only applied to arrays 3886 | # whose element count is greater than or equal to `MinSize`. 3887 | MinSize: 2 3888 | # The regular expression `WordRegex` decides what is considered a word. 3889 | WordRegex: !ruby/regexp '/\A(?:\p{Word}|\p{Word}-\p{Word}|\n|\t)+\z/' 3890 | 3891 | Style/YodaCondition: 3892 | Description: "Forbid or enforce yoda conditions." 3893 | Reference: "https://en.wikipedia.org/wiki/Yoda_conditions" 3894 | Enabled: true 3895 | EnforcedStyle: forbid_for_all_comparison_operators 3896 | SupportedStyles: 3897 | # check all comparison operators 3898 | - forbid_for_all_comparison_operators 3899 | # check only equality operators: `!=` and `==` 3900 | - forbid_for_equality_operators_only 3901 | # enforce yoda for all comparison operators 3902 | - require_for_all_comparison_operators 3903 | # enforce yoda only for equality operators: `!=` and `==` 3904 | - require_for_equality_operators_only 3905 | Safe: false 3906 | VersionAdded: "0.49" 3907 | VersionChanged: "0.75" 3908 | 3909 | Style/ZeroLengthPredicate: 3910 | Description: "Use #empty? when testing for objects of length 0." 3911 | Enabled: true 3912 | Safe: false 3913 | VersionAdded: "0.37" 3914 | VersionChanged: "0.39" 3915 | 3916 | Style/HashTransformValues: 3917 | Enabled: false 3918 | 3919 | Style/HashEachMethods: 3920 | Enabled: false 3921 | 3922 | Style/HashTransformKeys: 3923 | Enabled: false 3924 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | cache: bundler 3 | rvm: 4 | - 2.6.0 5 | - 2.5.0 6 | - 2.4.0 7 | - 2.3.0 8 | before_install: 9 | - gem update --system 10 | - gem install bundler 11 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in exponent-server-sdk.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Jesse Ruder 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Exponent Server SDK Ruby 2 | 3 | [![Build Status](https://travis-ci.org/expo/expo-server-sdk-ruby.svg?branch=master)](https://travis-ci.org/expo/expo-server-sdk-ruby) 4 | [![Gem Version](https://badge.fury.io/rb/exponent-server-sdk.svg)](https://badge.fury.io/rb/exponent-server-sdk) 5 | 6 | Use to send push notifications to Exponent Experiences from a Ruby server. 7 | 8 | ## Installation 9 | 10 | Add this line to your application's Gemfile: 11 | 12 | ```ruby 13 | gem 'exponent-server-sdk' 14 | ``` 15 | 16 | And then execute: 17 | 18 | ```shell 19 | $ bundle 20 | ``` 21 | 22 | Or install it yourself as: 23 | 24 | ```shell 25 | $ gem install exponent-server-sdk 26 | ``` 27 | 28 | ## Usage 29 | 30 | ### Client 31 | 32 | The push client is the preferred way. This hits the latest version of the api. 33 | 34 | Optional arguments: `gzip: true` 35 | 36 | ```ruby 37 | client = Exponent::Push::Client.new 38 | # client = Exponent::Push::Client.new(gzip: true) # for compressed, faster requests 39 | 40 | messages = [{ 41 | to: "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]", 42 | sound: "default", 43 | body: "Hello world!" 44 | }, { 45 | to: "ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]", 46 | badge: 1, 47 | body: "You've got mail" 48 | }] 49 | 50 | # @Deprecated 51 | # client.publish(messages) 52 | 53 | # MAX 100 messages at a time 54 | handler = client.send_messages(messages) 55 | 56 | # Array of all errors returned from the API 57 | # puts handler.errors 58 | 59 | # you probably want to delay calling this because the service might take a few moments to send 60 | # I would recommend reading the expo documentation regarding delivery delays 61 | client.verify_deliveries(handler.receipt_ids) 62 | 63 | ``` 64 | 65 | See the getting started example. If you clone this repo, you can also use it to test locally by entering your ExponentPushToken. Otherwise it serves as a good copy pasta example to get you going. 66 | 67 | The complete format of the messages can be found [here.](https://docs.expo.io/push-notifications/sending-notifications/#message-request-format) 68 | 69 | ## Contributing 70 | 71 | If you have problems with the code in this repository, please file issues & bug reports. We encourage you 72 | to submit a pull request with a solution or a failing test to reproduce your issue. Thanks! 73 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/testtask' 3 | 4 | def load_libs(rake_task) 5 | rake_task.libs << 'test' 6 | rake_task.libs << 'lib' 7 | end 8 | 9 | Rake::TestTask.new(:test) do |rake_task| 10 | load_libs rake_task 11 | rake_task.test_files = FileList['test/**/*-test.rb'] 12 | end 13 | 14 | Rake::TestTask.new(:getting_started) do |rake_task| 15 | load_libs rake_task 16 | rake_task.test_files = FileList['examples/getting_started.rb'] 17 | end 18 | 19 | task default: :test 20 | -------------------------------------------------------------------------------- /examples/getting_started.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'exponent-server-sdk' 4 | 5 | class Test 6 | def initialize 7 | # @client = Exponent::Push::Client.new 8 | 9 | # OR use GZIP to be AWESOME 10 | @client = Exponent::Push::Client.new(gzip: true) 11 | end 12 | 13 | def too_many_messages 14 | (0..101).map { create_message } 15 | end 16 | 17 | def create_message 18 | { 19 | # REPLACE WITH YOUR EXPONENT PUSH TOKEN LIKE: 20 | # to: 'ExponentPushToken[g5sIEbOm2yFdzn5VdSSy9n]', 21 | to: "ExponentPushToken[#{(0...22).map { ('a'..'z').to_a[rand(26)] }.join}]", 22 | sound: 'default', 23 | title: 'Hello World', 24 | subtitle: 'This is a Push Notification', 25 | body: 'Here\'s a little message for you...', 26 | data: { 27 | user_id: 1, 28 | points: 23_434 29 | }, 30 | ttl: 10, 31 | expiration: 1_886_207_332, 32 | priority: 'default', 33 | badge: 0, 34 | channelId: 'game' 35 | } 36 | end 37 | 38 | def test 39 | # messages = too_many_messages 40 | messages = [create_message] 41 | 42 | response_handler = @client.send_messages(messages) 43 | puts response_handler.response.response_body 44 | end 45 | end 46 | 47 | Test.new.test 48 | -------------------------------------------------------------------------------- /exponent-server-sdk.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path('lib', __dir__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require 'exponent-server-sdk/version' 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = 'exponent-server-sdk' 7 | spec.version = Exponent::VERSION 8 | spec.authors = ['Jesse Ruder', 'Pablo Gomez'] 9 | spec.email = ['jesse@sixfivezero.net', 'pablonahuelgomez@gmail.com'] 10 | spec.summary = %q{Exponent Server SDK} 11 | spec.description = %q{Exponent Server SDK} 12 | spec.homepage = '' 13 | spec.license = 'MIT' 14 | 15 | spec.files = `git ls-files -z`.split("\x0") 16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 17 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 18 | spec.require_paths = ['lib'] 19 | 20 | spec.add_dependency 'typhoeus' 21 | 22 | spec.add_development_dependency 'bundler' 23 | spec.add_development_dependency 'minitest' 24 | spec.add_development_dependency 'rake' 25 | spec.add_development_dependency 'rubocop' 26 | end 27 | -------------------------------------------------------------------------------- /lib/exponent-server-sdk.rb: -------------------------------------------------------------------------------- 1 | require 'exponent-server-sdk/version' 2 | require 'exponent-server-sdk/too_many_messages_error' 3 | require 'typhoeus' 4 | require 'json' 5 | 6 | # Basic Usage: 7 | # 8 | # Create new client 9 | # client = Exponent::Push::Client.new(**args) 10 | # 11 | # Send UPTO ~~100~~ messages per call, 12 | # https://docs.expo.io/versions/latest/guides/push-notifications/#message-format 13 | # response_handler = client.send_messages([list of formatted messages]) 14 | # 15 | # Check the response to see if any errors were re 16 | # response_handler.errors? 17 | # 18 | # To process each error, iterate over the errors array 19 | # which contains each Error class instance 20 | # response_handler.errors 21 | # 22 | # There is an array of invalid ExponentPushTokens that were found in the initial /send call 23 | # response_handler.invalid_push_tokens['ExponentPushToken[1212121212121212]'] 24 | # 25 | # You can use the handler to get receipt_ids 26 | # response_handler.receipt_ids 27 | # 28 | # You can pass an array of receipt_ids to verify_deliveries method and 29 | # it will populate a new ResponseHandler with any errors 30 | # receipt_response = client.verify_deliveries(receipt_ids) 31 | 32 | module Exponent 33 | def self.is_exponent_push_token?(token) 34 | token.start_with?('ExponentPushToken') 35 | end 36 | 37 | module Push 38 | class Client 39 | def initialize(**args) 40 | @http_client = args[:http_client] || Typhoeus 41 | @error_builder = ErrorBuilder.new 42 | # future versions will deprecate this 43 | @response_handler = args[:response_handler] || ResponseHandler.new 44 | @gzip = args[:gzip] == true 45 | end 46 | 47 | # returns a string response with parsed success json or error 48 | # @deprecated 49 | def publish(messages) 50 | warn '[DEPRECATION] `publish` is deprecated. Please use `send_messages` instead.' 51 | @response_handler.handle(push_notifications(messages)) 52 | end 53 | 54 | # returns response handler that provides access to errors? and other response inspection methods 55 | def send_messages(messages, **args) 56 | # https://docs.expo.io/versions/latest/guides/push-notifications/#message-format 57 | raise TooManyMessagesError, 'Only 100 message objects at a time allowed.' if messages.length > 100 58 | 59 | response = push_notifications(messages) 60 | 61 | # each call to send_messages will return a new instance of ResponseHandler 62 | handler = args[:response_handler] || ResponseHandler.new 63 | handler.process_response(response) 64 | handler 65 | end 66 | 67 | def verify_deliveries(receipt_ids, **args) 68 | response = get_receipts(receipt_ids) 69 | handler = args[:response_handler] || ResponseHandler.new 70 | handler.process_response(response) 71 | handler 72 | end 73 | 74 | private 75 | 76 | def push_notifications(messages) 77 | @http_client.post( 78 | push_url, 79 | body: messages.to_json, 80 | headers: headers, 81 | accept_encoding: @gzip 82 | ) 83 | end 84 | 85 | def push_url 86 | 'https://exp.host/--/api/v2/push/send' 87 | end 88 | 89 | def get_receipts(receipt_ids) 90 | @http_client.post( 91 | receipts_url, 92 | body: { ids: receipt_ids }.to_json, 93 | headers: headers, 94 | accept_encoding: @gzip 95 | ) 96 | end 97 | 98 | def receipts_url 99 | 'https://exp.host/--/api/v2/push/getReceipts' 100 | end 101 | 102 | def headers 103 | headers = { 104 | 'Content-Type' => 'application/json', 105 | 'Accept' => 'application/json' 106 | } 107 | headers 108 | end 109 | end 110 | 111 | class ResponseHandler 112 | attr_reader :response, :invalid_push_tokens, :receipt_ids, :errors 113 | 114 | def initialize(error_builder = ErrorBuilder.new) 115 | @error_builder = error_builder 116 | @response = nil 117 | @receipt_ids = [] 118 | @invalid_push_tokens = [] 119 | @errors = [] 120 | end 121 | 122 | def process_response(response) 123 | @response = response 124 | 125 | case response.code.to_s 126 | when /(^4|^5)/ 127 | raise @error_builder.parse_response(response) 128 | else 129 | sort_results 130 | end 131 | end 132 | 133 | def errors? 134 | @errors.any? 135 | end 136 | 137 | # @deprecated 138 | def handle(response) 139 | warn '[DEPRECATION] `handle` is deprecated. Please use `process_response` instead.' 140 | @response = response 141 | case response.code.to_s 142 | when /(^4|^5)/ 143 | raise build_error_from_failure 144 | else 145 | extract_data 146 | end 147 | end 148 | 149 | private 150 | 151 | def sort_results 152 | data = body&.fetch('data', nil) || nil 153 | 154 | # something is definitely wrong 155 | return if data.nil? 156 | 157 | # Array indicates a response from the /send endpoint 158 | # Hash indicates a response from the /getReceipts endpoint 159 | if data.is_a? Array 160 | data.each do |push_ticket| 161 | receipt_id = push_ticket.fetch('id', nil) 162 | if push_ticket.fetch('status', nil) == 'ok' 163 | @receipt_ids.push(receipt_id) unless receipt_id.nil? 164 | else 165 | process_error(push_ticket) 166 | end 167 | end 168 | else 169 | process_receipts(data) 170 | end 171 | end 172 | 173 | def process_receipts(receipts) 174 | receipts.each do |receipt_id, receipt| 175 | @receipt_ids.push(receipt_id) unless receipt_id.nil? 176 | process_error(receipt) unless receipt.fetch('status') == 'ok' 177 | end 178 | end 179 | 180 | def process_error(push_ticket) 181 | message = push_ticket.fetch('message') 182 | invalid = message.match(/ExponentPushToken\[(...*)\]/) 183 | unregistered = message.match(/\"(...*)\"/) 184 | error_class = @error_builder.parse_push_ticket(push_ticket) 185 | 186 | @invalid_push_tokens.push(invalid[0]) unless invalid.nil? 187 | @invalid_push_tokens.push(unregistered[1]) unless unregistered.nil? 188 | 189 | @errors.push(error_class) unless @errors.include?(error_class) 190 | end 191 | 192 | def body 193 | # memoization FTW! 194 | @body ||= JSON.parse(@response.body) 195 | rescue SyntaxError 196 | # Sometimes the server returns an empty string. 197 | # It must be escaped before we can process it. 198 | @body = JSON.parse(@response.body.to_json) 199 | rescue StandardError 200 | # Prevent nil errors in old version of ruby when using fetch 201 | @body = {} 202 | end 203 | 204 | ##### DEPRECATED METHODS ##### 205 | 206 | # @deprecated 207 | def build_error_from_failure 208 | @error_builder.build_from_erroneous(body) 209 | end 210 | 211 | # @deprecated 212 | def extract_data 213 | data = body.fetch('data') 214 | if data.is_a? Hash 215 | validate_status(data.fetch('status'), body) 216 | data 217 | elsif data.is_a? Array 218 | data.map do |receipt| 219 | validate_status(receipt.fetch('status'), body) 220 | receipt 221 | end 222 | else 223 | {} 224 | end 225 | end 226 | 227 | # @deprecated 228 | def validate_status(status, response) 229 | raise build_error_from_success(response) unless status == 'ok' 230 | end 231 | 232 | # @deprecated 233 | def build_error_from_success(response) 234 | @error_builder.build_from_successful(response) 235 | end 236 | end 237 | 238 | class ErrorBuilder 239 | def parse_response(response) 240 | with_error_handling(response) do 241 | error = response.fetch('errors') 242 | error_name = error.fetch('code') 243 | message = error.fetch('message') 244 | 245 | get_error_class(error_name).new(message) 246 | end 247 | end 248 | 249 | def parse_push_ticket(push_ticket) 250 | with_error_handling(push_ticket) do 251 | message = push_ticket.fetch('message') 252 | get_error_class(push_ticket.fetch('details').fetch('error')).new(message) 253 | end 254 | end 255 | 256 | %i[erroneous successful].each do |selector| 257 | define_method(:"build_from_#{selector}") do |response| 258 | with_error_handling(response) do 259 | send "from_#{selector}_response", response 260 | end 261 | end 262 | end 263 | 264 | private 265 | 266 | def with_error_handling(response) 267 | yield(response) 268 | rescue KeyError, NoMethodError 269 | unknown_error_format(response) 270 | end 271 | 272 | def validate_error_name(condition) 273 | condition ? yield : Exponent::Push::UnknownError 274 | end 275 | 276 | def get_error_class(error_name) 277 | validate_error_name(Exponent::Push.error_names.include?(error_name)) do 278 | Exponent::Push.const_get("#{error_name}Error") 279 | end 280 | end 281 | 282 | def unknown_error_format(response) 283 | Exponent::Push::UnknownError.new("Unknown error format: #{response.respond_to?(:body) ? response.body : response}") 284 | end 285 | 286 | ##### DEPRECATED METHODS ##### 287 | 288 | # @deprecated 289 | def from_erroneous_response(response) 290 | error = response.fetch('errors').first 291 | error_name = error.fetch('code') 292 | message = error.fetch('message') 293 | 294 | get_error_class(error_name).new(message) 295 | end 296 | 297 | # @deprecated 298 | def from_successful_response(response) 299 | delivery_result = response.fetch('data').first 300 | message = delivery_result.fetch('message') 301 | get_error_class(delivery_result.fetch('details').fetch('error')).new(message) 302 | end 303 | end 304 | 305 | Error = Class.new(StandardError) 306 | 307 | def self.error_names 308 | %w[DeviceNotRegistered MessageTooBig 309 | MessageRateExceeded InvalidCredentials 310 | Unknown] 311 | end 312 | 313 | error_names.each do |error_name| 314 | const_set "#{error_name}Error", Class.new(Error) 315 | end 316 | end 317 | end 318 | -------------------------------------------------------------------------------- /lib/exponent-server-sdk/too_many_messages_error.rb: -------------------------------------------------------------------------------- 1 | class TooManyMessagesError < StandardError 2 | end 3 | -------------------------------------------------------------------------------- /lib/exponent-server-sdk/version.rb: -------------------------------------------------------------------------------- 1 | module Exponent 2 | VERSION = '0.1.0'.freeze 3 | end 4 | -------------------------------------------------------------------------------- /test/exponent-server-sdk-test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'minitest/autorun' 4 | require 'exponent-server-sdk' 5 | require 'exponent-server-sdk/too_many_messages_error' 6 | 7 | class ExponentServerSdkTest < Minitest::Test 8 | def setup 9 | @mock = MiniTest::Mock.new 10 | @response_mock = MiniTest::Mock.new 11 | @client = Exponent::Push::Client.new(http_client: @mock) 12 | @client_gzip = Exponent::Push::Client.new(http_client: @mock, gzip: true) 13 | end 14 | 15 | def test_send_messages_with_success 16 | @response_mock.expect(:code, 200) 17 | @response_mock.expect(:body, success_body.to_json) 18 | 19 | @mock.expect(:post, @response_mock, client_args) 20 | 21 | response = @client.send_messages(messages) 22 | assert_equal(response.errors?, false) 23 | 24 | @mock.verify 25 | end 26 | 27 | def test_send_messages_alternate_message_format_with_success 28 | @response_mock.expect(:code, 200) 29 | @response_mock.expect(:body, success_body.to_json) 30 | 31 | alternate_messages = alternate_format_messages 32 | @mock.expect(:post, @response_mock, alternative_client_args(alternate_messages)) 33 | 34 | response = @client.send_messages(alternate_messages) 35 | assert_equal(response.errors?, false) 36 | 37 | @mock.verify 38 | end 39 | 40 | def test_send_messages_with_gzip_success 41 | @response_mock.expect(:code, 200) 42 | @response_mock.expect(:body, success_body.to_json) 43 | 44 | @mock.expect(:post, @response_mock, gzip_client_args) 45 | 46 | response = @client_gzip.send_messages(messages) 47 | assert_equal(response.errors?, false) 48 | 49 | @mock.verify 50 | end 51 | 52 | def test_send_messages_with_empty_string_response_body 53 | @response_mock.expect(:code, 400) 54 | @response_mock.expect(:body, '') 55 | 56 | @mock.expect(:post, @response_mock, client_args) 57 | 58 | exception = assert_raises Exponent::Push::UnknownError do 59 | handler = @client.send_messages(messages) 60 | # this first assertion is just stating that errors will be false when 61 | # an exception is thrown on the request, not the content of the request 62 | # 400/500 level errors are not delivery errors, they are functionality errors 63 | assert_equal(handler.response.errors?, false) 64 | assert_equal(handler.response.body, {}) 65 | assert_equal(handler.response.code, 400) 66 | end 67 | 68 | assert_match(/Unknown error format/, exception.message) 69 | 70 | @mock.verify 71 | end 72 | 73 | def test_send_messages_with_nil_response_body 74 | @response_mock.expect(:code, 400) 75 | @response_mock.expect(:body, nil) 76 | 77 | @mock.expect(:post, @response_mock, client_args) 78 | 79 | exception = assert_raises Exponent::Push::UnknownError do 80 | handler = @client.send_messages(messages) 81 | # this first assertion is just stating that errors will be false when 82 | # an exception is thrown on the request, not the content of the request 83 | # 400/500 level errors are not delivery errors, they are functionality errors 84 | assert_equal(handler.response.errors?, false) 85 | assert_equal(handler.response.body, {}) 86 | assert_equal(handler.response.code, 400) 87 | end 88 | 89 | assert_match(/Unknown error format/, exception.message) 90 | 91 | @mock.verify 92 | end 93 | 94 | def test_send_messages_with_gzip_empty_string_response 95 | @response_mock.expect(:code, 400) 96 | @response_mock.expect(:body, '') 97 | 98 | @mock.expect(:post, @response_mock, gzip_client_args) 99 | 100 | exception = assert_raises Exponent::Push::UnknownError do 101 | handler = @client_gzip.send_messages(messages) 102 | # this first assertion is just stating that errors will be false when 103 | # an exception is thrown on the request, not the content of the request 104 | # 400/500 level errors are not delivery errors, they are functionality errors 105 | assert_equal(handler.response.errors?, false) 106 | assert_equal(handler.response.body, {}) 107 | assert_equal(handler.response.code, 400) 108 | end 109 | 110 | assert_match(/Unknown error format/, exception.message) 111 | 112 | @mock.verify 113 | end 114 | 115 | def test_send_messages_with_gzip_nil_response_body 116 | @response_mock.expect(:code, 400) 117 | @response_mock.expect(:body, nil) 118 | 119 | @mock.expect(:post, @response_mock, gzip_client_args) 120 | 121 | exception = assert_raises Exponent::Push::UnknownError do 122 | handler = @client_gzip.send_messages(messages) 123 | # this first assertion is just stating that errors will be false when 124 | # an exception is thrown on the request, not the content of the request 125 | # 400/500 level errors are not delivery errors, they are functionality errors 126 | assert_equal(handler.response.errors?, false) 127 | assert_equal(handler.response.body, {}) 128 | assert_equal(handler.response.code, 400) 129 | end 130 | 131 | assert_match(/Unknown error format/, exception.message) 132 | 133 | @mock.verify 134 | end 135 | 136 | def test_send_messages_with_unknown_error 137 | @response_mock.expect(:code, 400) 138 | @response_mock.expect(:body, error_body.to_json) 139 | 140 | @mock.expect(:post, @response_mock, client_args) 141 | 142 | exception = assert_raises Exponent::Push::UnknownError do 143 | @client.send_messages(messages) 144 | end 145 | 146 | assert_equal("Unknown error format: #{error_body.to_json}", exception.message) 147 | 148 | @mock.verify 149 | end 150 | 151 | def test_send_messages_with_gzip_unknown_error 152 | @response_mock.expect(:code, 400) 153 | @response_mock.expect(:body, error_body.to_json) 154 | 155 | @mock.expect(:post, @response_mock, gzip_client_args) 156 | 157 | exception = assert_raises Exponent::Push::UnknownError do 158 | @client_gzip.send_messages(messages) 159 | end 160 | 161 | assert_match(/Unknown error format/, exception.message) 162 | 163 | @mock.verify 164 | end 165 | 166 | def test_send_messages_with_device_not_registered_error 167 | @response_mock.expect(:code, 200) 168 | @response_mock.expect(:body, not_registered_device_error_body.to_json) 169 | token = 'ExponentPushToken[42]' 170 | message = "\"#{token}\" is not a registered push notification recipient" 171 | 172 | @mock.expect(:post, @response_mock, client_args) 173 | 174 | response_handler = @client.send_messages(messages) 175 | assert_equal(message, response_handler.errors.first.message) 176 | assert(response_handler.errors.first.instance_of?(Exponent::Push::DeviceNotRegisteredError)) 177 | assert(response_handler.invalid_push_tokens.include?(token)) 178 | assert(response_handler.errors?) 179 | 180 | @mock.verify 181 | end 182 | 183 | def test_send_messages_too_many_messages 184 | message = 'Only 100 message objects at a time allowed.' 185 | 186 | e = assert_raises TooManyMessagesError do 187 | @client.send_messages(too_many_messages) 188 | end 189 | 190 | assert_equal(e.message, message) 191 | end 192 | 193 | def test_send_messages_with_message_too_big_error 194 | @response_mock.expect(:code, 200) 195 | @response_mock.expect(:body, message_too_big_error_body.to_json) 196 | message = 'Message too big' 197 | 198 | @mock.expect(:post, @response_mock, client_args) 199 | 200 | response_handler = @client.send_messages(messages) 201 | assert(response_handler.errors.first.instance_of?(Exponent::Push::MessageTooBigError)) 202 | assert_equal(message, response_handler.errors.first.message) 203 | assert(response_handler.errors?) 204 | 205 | @mock.verify 206 | end 207 | 208 | def test_send_messages_with_message_rate_exceeded_error 209 | @response_mock.expect(:code, 200) 210 | @response_mock.expect(:body, message_rate_exceeded_error_body.to_json) 211 | message = 'Message rate exceeded' 212 | 213 | @mock.expect(:post, @response_mock, client_args) 214 | 215 | response_handler = @client.send_messages(messages) 216 | assert(response_handler.errors.first.instance_of?(Exponent::Push::MessageRateExceededError)) 217 | assert_equal(message, response_handler.errors.first.message) 218 | 219 | @mock.verify 220 | end 221 | 222 | def test_send_messages_with_invalid_credentials_error 223 | @response_mock.expect(:code, 200) 224 | @response_mock.expect(:body, invalid_credentials_error_body.to_json) 225 | message = 'Invalid credentials' 226 | 227 | @mock.expect(:post, @response_mock, client_args) 228 | 229 | response_handler = @client.send_messages(messages) 230 | assert(response_handler.errors.first.instance_of?(Exponent::Push::InvalidCredentialsError)) 231 | assert_equal(message, response_handler.errors.first.message) 232 | 233 | @mock.verify 234 | end 235 | 236 | def test_send_messages_with_apn_error 237 | @response_mock.expect(:code, 200) 238 | @response_mock.expect(:body, apn_error_body.to_json) 239 | 240 | @mock.expect(:post, @response_mock, client_args) 241 | 242 | response_handler = @client.send_messages(messages) 243 | assert(response_handler.errors.first.instance_of?(Exponent::Push::UnknownError)) 244 | assert_match(/Unknown error format/, response_handler.errors.first.message) 245 | 246 | @mock.verify 247 | end 248 | 249 | def test_get_receipts_with_success_receipt 250 | @response_mock.expect(:code, 200) 251 | @response_mock.expect(:body, receipt_success_body.to_json) 252 | receipt_ids = [success_receipt] 253 | 254 | @mock.expect(:post, @response_mock, receipt_client_args(receipt_ids)) 255 | 256 | response_handler = @client.verify_deliveries(receipt_ids) 257 | assert_match(success_receipt, response_handler.receipt_ids.first) 258 | 259 | @mock.verify 260 | end 261 | 262 | def test_get_receipts_with_error_receipt 263 | @response_mock.expect(:code, 200) 264 | @response_mock.expect(:body, receipt_error_body.to_json) 265 | receipt_ids = [error_receipt] 266 | 267 | @mock.expect(:post, @response_mock, receipt_client_args(receipt_ids)) 268 | 269 | response_handler = @client.verify_deliveries(receipt_ids) 270 | assert_match(error_receipt, response_handler.receipt_ids.first) 271 | assert_equal(true, response_handler.errors?) 272 | assert_equal(1, response_handler.errors.count) 273 | assert(response_handler.errors.first.instance_of?(Exponent::Push::DeviceNotRegisteredError)) 274 | 275 | @mock.verify 276 | end 277 | 278 | def test_get_receipts_with_variable_success_receipts 279 | @response_mock.expect(:code, 200) 280 | @response_mock.expect(:body, multiple_receipts.to_json) 281 | receipt_ids = [error_receipt, success_receipt] 282 | 283 | @mock.expect(:post, @response_mock, receipt_client_args(receipt_ids)) 284 | 285 | response_handler = @client.verify_deliveries(receipt_ids) 286 | assert_match(error_receipt, response_handler.receipt_ids.first) 287 | assert_match(success_receipt, response_handler.receipt_ids.last) 288 | assert_equal(true, response_handler.errors?) 289 | assert_equal(1, response_handler.errors.count) 290 | assert(response_handler.errors.first.instance_of?(Exponent::Push::DeviceNotRegisteredError)) 291 | 292 | @mock.verify 293 | end 294 | 295 | def test_get_receipts_with_gzip_success_receipt 296 | @response_mock.expect(:code, 200) 297 | @response_mock.expect(:body, receipt_success_body.to_json) 298 | receipt_ids = [success_receipt] 299 | 300 | @mock.expect(:post, @response_mock, gzip_receipt_client_args(receipt_ids)) 301 | 302 | response_handler = @client_gzip.verify_deliveries(receipt_ids) 303 | assert_match(success_receipt, response_handler.receipt_ids.first) 304 | 305 | @mock.verify 306 | end 307 | 308 | def test_get_receipts_with_gzip_error_receipt 309 | @response_mock.expect(:code, 200) 310 | @response_mock.expect(:body, receipt_error_body.to_json) 311 | receipt_ids = [error_receipt] 312 | 313 | @mock.expect(:post, @response_mock, gzip_receipt_client_args(receipt_ids)) 314 | 315 | response_handler = @client_gzip.verify_deliveries(receipt_ids) 316 | assert_match(error_receipt, response_handler.receipt_ids.first) 317 | assert_equal(true, response_handler.errors?) 318 | assert_equal(1, response_handler.errors.count) 319 | assert(response_handler.errors.first.instance_of?(Exponent::Push::DeviceNotRegisteredError)) 320 | 321 | @mock.verify 322 | end 323 | 324 | def test_get_receipts_with_gzip_variable_success_receipts 325 | @response_mock.expect(:code, 200) 326 | @response_mock.expect(:body, multiple_receipts.to_json) 327 | receipt_ids = [error_receipt, success_receipt] 328 | 329 | @mock.expect(:post, @response_mock, gzip_receipt_client_args(receipt_ids)) 330 | 331 | response_handler = @client_gzip.verify_deliveries(receipt_ids) 332 | assert_match(error_receipt, response_handler.receipt_ids.first) 333 | assert_match(success_receipt, response_handler.receipt_ids.last) 334 | assert_equal(true, response_handler.errors?) 335 | assert_equal(1, response_handler.errors.count) 336 | assert(response_handler.errors.first.instance_of?(Exponent::Push::DeviceNotRegisteredError)) 337 | 338 | @mock.verify 339 | end 340 | 341 | # DEPRECATED -- TESTS BELOW HERE RELATE TO CODE THAT WILL BE REMOVED 342 | 343 | def test_publish_with_success 344 | @response_mock.expect(:code, 200) 345 | @response_mock.expect(:body, success_body.to_json) 346 | 347 | @mock.expect(:post, @response_mock, client_args) 348 | 349 | @client.publish(messages) 350 | 351 | @mock.verify 352 | end 353 | 354 | def test_publish_with_gzip_success 355 | @response_mock.expect(:code, 200) 356 | @response_mock.expect(:body, success_body.to_json) 357 | 358 | @mock.expect(:post, @response_mock, gzip_client_args) 359 | 360 | @client_gzip.publish(messages) 361 | 362 | @mock.verify 363 | end 364 | 365 | def test_publish_with_gzip 366 | @response_mock.expect(:code, 200) 367 | @response_mock.expect(:body, success_body.to_json) 368 | 369 | @mock.expect(:post, @response_mock, gzip_client_args) 370 | 371 | @client_gzip.publish(messages) 372 | 373 | @mock.verify 374 | end 375 | 376 | def test_publish_with_unknown_error 377 | @response_mock.expect(:code, 400) 378 | @response_mock.expect(:body, error_body.to_json) 379 | message = 'An unknown error occurred.' 380 | 381 | @mock.expect(:post, @response_mock, client_args) 382 | 383 | exception = assert_raises Exponent::Push::UnknownError do 384 | @client.publish(messages) 385 | end 386 | 387 | assert_equal(message, exception.message) 388 | 389 | @mock.verify 390 | end 391 | 392 | def test_publish_with_device_not_registered_error 393 | @response_mock.expect(:code, 200) 394 | @response_mock.expect(:body, not_registered_device_error_body.to_json) 395 | message = '"ExponentPushToken[42]" is not a registered push notification recipient' 396 | 397 | @mock.expect(:post, @response_mock, client_args) 398 | 399 | exception = assert_raises Exponent::Push::DeviceNotRegisteredError do 400 | @client.publish(messages) 401 | end 402 | 403 | assert_equal(message, exception.message) 404 | 405 | @mock.verify 406 | end 407 | 408 | def test_publish_with_message_too_big_error 409 | @response_mock.expect(:code, 200) 410 | @response_mock.expect(:body, message_too_big_error_body.to_json) 411 | message = 'Message too big' 412 | 413 | @mock.expect(:post, @response_mock, client_args) 414 | 415 | exception = assert_raises Exponent::Push::MessageTooBigError do 416 | @client.publish(messages) 417 | end 418 | 419 | assert_equal(message, exception.message) 420 | 421 | @mock.verify 422 | end 423 | 424 | def test_publish_with_message_rate_exceeded_error 425 | @response_mock.expect(:code, 200) 426 | @response_mock.expect(:body, message_rate_exceeded_error_body.to_json) 427 | message = 'Message rate exceeded' 428 | 429 | @mock.expect(:post, @response_mock, client_args) 430 | 431 | exception = assert_raises Exponent::Push::MessageRateExceededError do 432 | @client.publish(messages) 433 | end 434 | 435 | assert_equal(message, exception.message) 436 | 437 | @mock.verify 438 | end 439 | 440 | def test_publish_with_invalid_credentials_error 441 | @response_mock.expect(:code, 200) 442 | @response_mock.expect(:body, invalid_credentials_error_body.to_json) 443 | message = 'Invalid credentials' 444 | 445 | @mock.expect(:post, @response_mock, client_args) 446 | 447 | exception = assert_raises Exponent::Push::InvalidCredentialsError do 448 | @client.publish(messages) 449 | end 450 | 451 | assert_equal(message, exception.message) 452 | 453 | @mock.verify 454 | end 455 | 456 | def test_publish_with_apn_error 457 | @response_mock.expect(:code, 200) 458 | @response_mock.expect(:body, apn_error_body.to_json) 459 | 460 | @mock.expect(:post, @response_mock, client_args) 461 | 462 | exception = assert_raises Exponent::Push::UnknownError do 463 | @client.publish(messages) 464 | end 465 | 466 | assert_match(/Unknown error format/, exception.message) 467 | 468 | @mock.verify 469 | end 470 | 471 | private 472 | 473 | def success_body 474 | { 'data' => [{ 'status' => 'ok' }] } 475 | end 476 | 477 | def success_receipt 478 | 'YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY' 479 | end 480 | 481 | def error_receipt 482 | 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' 483 | end 484 | 485 | def receipt_success_body 486 | { 487 | 'data' => { 488 | 'YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY' => { 489 | 'status' => 'ok' 490 | } 491 | } 492 | } 493 | end 494 | 495 | def receipt_error_body 496 | { 497 | 'data' => { 498 | 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' => { 499 | 'status' => 'error', 500 | 'message' => 'The Apple Push Notification service failed to send the notification', 501 | 'details' => { 502 | 'error' => 'DeviceNotRegistered' 503 | } 504 | } 505 | } 506 | } 507 | end 508 | 509 | def multiple_receipts 510 | { 511 | 'data' => { 512 | 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' => { 513 | 'status' => 'error', 514 | 'message' => 'The Apple Push Notification service failed to send the notification', 515 | 'details' => { 516 | 'error' => 'DeviceNotRegistered' 517 | } 518 | }, 519 | 'YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY' => { 520 | 'status' => 'ok' 521 | } 522 | } 523 | } 524 | end 525 | 526 | def error_body 527 | { 528 | 'errors' => [{ 529 | 'code' => 'INTERNAL_SERVER_ERROR', 530 | 'message' => 'An unknown error occurred.' 531 | }] 532 | } 533 | end 534 | 535 | def message_too_big_error_body 536 | build_error_body('MessageTooBig', 'Message too big') 537 | end 538 | 539 | def not_registered_device_error_body 540 | build_error_body( 541 | 'DeviceNotRegistered', 542 | '"ExponentPushToken[42]" is not a registered push notification recipient' 543 | ) 544 | end 545 | 546 | def message_rate_exceeded_error_body 547 | build_error_body('MessageRateExceeded', 'Message rate exceeded') 548 | end 549 | 550 | def invalid_credentials_error_body 551 | build_error_body('InvalidCredentials', 'Invalid credentials') 552 | end 553 | 554 | def apn_error_body 555 | { 556 | 'data' => [{ 557 | 'status' => 'error', 558 | 'message' => 559 | 'Could not find APNs credentials for you (your_app). Check whether you are trying to send a notification to a detached app.' 560 | }] 561 | } 562 | end 563 | 564 | def client_args 565 | [ 566 | 'https://exp.host/--/api/v2/push/send', 567 | { 568 | body: messages.to_json, 569 | headers: { 570 | 'Content-Type' => 'application/json', 571 | 'Accept' => 'application/json' 572 | }, 573 | accept_encoding: false 574 | } 575 | ] 576 | end 577 | 578 | def alternative_client_args(messages) 579 | [ 580 | 'https://exp.host/--/api/v2/push/send', 581 | { 582 | body: messages.to_json, 583 | headers: { 584 | 'Content-Type' => 'application/json', 585 | 'Accept' => 'application/json' 586 | }, 587 | accept_encoding: false 588 | } 589 | ] 590 | end 591 | 592 | def gzip_client_args 593 | [ 594 | 'https://exp.host/--/api/v2/push/send', 595 | { 596 | body: messages.to_json, 597 | headers: { 598 | 'Content-Type' => 'application/json', 599 | 'Accept' => 'application/json' 600 | }, 601 | accept_encoding: true 602 | } 603 | ] 604 | end 605 | 606 | def receipt_client_args(receipt_ids) 607 | [ 608 | 'https://exp.host/--/api/v2/push/getReceipts', 609 | { 610 | body: { ids: receipt_ids }.to_json, 611 | headers: { 612 | 'Content-Type' => 'application/json', 613 | 'Accept' => 'application/json' 614 | }, 615 | accept_encoding: false 616 | } 617 | ] 618 | end 619 | 620 | def gzip_receipt_client_args(receipt_ids) 621 | [ 622 | 'https://exp.host/--/api/v2/push/getReceipts', 623 | { 624 | body: { ids: receipt_ids }.to_json, 625 | headers: { 626 | 'Content-Type' => 'application/json', 627 | 'Accept' => 'application/json' 628 | }, 629 | accept_encoding: true 630 | } 631 | ] 632 | end 633 | 634 | def alternate_format_messages 635 | [{ 636 | to: [ 637 | 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]', 638 | 'ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]' 639 | ], 640 | badge: 1, 641 | sound: 'default', 642 | body: 'You got a completely unique message from us! /s' 643 | }] 644 | end 645 | 646 | def messages 647 | [{ 648 | to: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]', 649 | sound: 'default', 650 | body: 'Hello world!' 651 | }, { 652 | to: 'ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]', 653 | badge: 1, 654 | body: "You've got mail" 655 | }] 656 | end 657 | 658 | def too_many_messages 659 | (0..101).map { create_message } 660 | end 661 | 662 | def create_message 663 | id = (0...22).map { ('a'..'z').to_a[rand(26)] }.join 664 | { 665 | to: "ExponentPushToken[#{id}]", 666 | sound: 'default', 667 | body: 'Hello world!' 668 | } 669 | end 670 | 671 | def build_error_body(error_code, message) 672 | { 673 | 'data' => [{ 674 | 'status' => 'error', 675 | 'message' => message, 676 | 'details' => { 'error' => error_code } 677 | }] 678 | } 679 | end 680 | end 681 | --------------------------------------------------------------------------------