├── .github
├── ISSUE_TEMPLATE
│ ├── new-issue.md
│ └── update-dependencies.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── main.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE.txt
├── Makefile
├── README.md
├── RELEASING.md
├── Rakefile
├── bin
├── console
└── setup
├── config
├── base.yml
├── graphql.yml
├── rails-locales.yml
├── rails.yml
├── rspec.yml
└── ruby.yml
├── datarockets-style.gemspec
├── doc
├── STYLE_GUIDE.md
├── STYLE_GUIDE_GRAPHQL.md
├── STYLE_GUIDE_RAILS.md
└── STYLE_GUIDE_RSPEC.md
├── lib
├── datarockets_style.rb
└── datarockets_style
│ ├── cop
│ ├── layout
│ │ └── array_alignment_extended.rb
│ ├── rspec
│ │ └── prefer_before_over_setup.rb
│ └── style
│ │ └── nested_interpolation.rb
│ ├── formatter
│ ├── todo_list_formatter.rb
│ └── todo_list_formatter
│ │ └── report_summary.rb
│ └── version.rb
├── manual
└── cops_layout.md
└── spec
├── datarockets_style
├── cop
│ ├── layout
│ │ └── array_alignment_extended_spec.rb
│ ├── rspec
│ │ └── prefer_before_over_setup_spec.rb
│ └── style
│ │ └── nested_interpolation_spec.rb
├── formatter
│ ├── todo_list_formatter
│ │ └── report_summary_spec.rb
│ └── todo_list_formatter_spec.rb
└── version_spec.rb
├── rubocop_examples
├── cop
│ └── layout
│ │ └── array_alignment_extended_spec.rb
└── hash_styles.rb
└── spec_helper.rb
/.github/ISSUE_TEMPLATE/new-issue.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: New issue or feature request
3 | about: Suggest a new feature or enhancement, ask a question, report bug, etc.
4 | title: "Title goes here"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is.
12 |
13 | **Additional context.**
14 | Add any other context or screenshots about the feature request here.
15 |
16 | **Add label.**
17 | Add label for easier navigation by issues and understanding your expectations.
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/update-dependencies.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Update Dependencies
3 | about: Updating dependencies issue
4 | title: "Update *dependency* to *version*"
5 | labels: dependencies
6 | assignees: ''
7 |
8 | ---
9 |
10 | Link to the new release: *link*
11 |
12 | To-Do list:
13 |
14 | - [ ] update dependencies to the latest version
15 | - [ ] investigate how it changes and affect our current styles and cops
16 | - [ ] check the required ruby version
17 | - [ ] enable pending cops
18 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Before you submit a pull request, please make sure you have to follow:
2 |
3 | - [ ] read and know items from the [Contributing Guide](https://github.com/datarockets/datarockets-style/blob/master/CONTRIBUTING.md#pull-requests)
4 | - [ ] add a description of the problem you're trying to solve (short summary from related issue)
5 | - [ ] verified that cops are ordered by alphabet
6 | - [ ] add a note to the style guide docs (if it needs)
7 | - [ ] add a note to the changelog file
8 | - [ ] the commit message contains the number of the related issue (if it presents)
9 | and word `Fix` if this PR closes related issue
10 | - [ ] squash all commits before submitting to review
11 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Run tests
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - 'master'
7 | push:
8 | branches:
9 | - 'master'
10 |
11 | jobs:
12 | test:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v3
17 |
18 | - name: Set up Ruby 3.0
19 | uses: ruby/setup-ruby@v1
20 | with:
21 | ruby-version: '3.0'
22 | bundler-cache: true
23 |
24 | - name: Run linter
25 | run: make lint
26 |
27 | - name: Run tests
28 | run: make test
29 |
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.bundle/
2 | /bundler/
3 | /.yardoc
4 | /_yardoc/
5 | /pkg/
6 | /tmp/
7 |
8 | .byebug_history
9 | .idea
10 | Gemfile.lock
11 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | inherit_from:
2 | - config/ruby.yml
3 | - config/rspec.yml
4 |
5 | inherit_mode:
6 | merge:
7 | - Exclude
8 |
9 | AllCops:
10 | TargetRubyVersion: 3.0
11 |
12 | # for checking cops with interpolation
13 | Lint/InterpolationCheck:
14 | Exclude:
15 | - 'spec/**/*.rb'
16 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | The format is described in [Contributing notes](CONTRIBUTING.md#changelog-entry-format).
4 |
5 | ## master
6 |
7 | ## 1.6.0 (2024-08-27)
8 |
9 | ### Changed
10 |
11 | * **(Breaking)** Support Ruby >= 3.0.0
12 |
13 | * Update rubocop to `1.65.1`. ([@Set27])
14 | * Update rubocop-graphql to `1.5.4`. ([@Set27])
15 | * Update rubocop-rails to `2.26`. ([@Set27])
16 | * Update rubocop-spec to `3.0.4`. ([@Set27])
17 |
18 | ## 1.5.0 (2023-09-11)
19 |
20 | ### Added
21 |
22 | * Added GraphQL cops. ([@Anastastasia-B][])
23 |
24 | ### Changed
25 |
26 | * **(Breaking)** Support Ruby >= 2.7.0
27 |
28 | * Update rubocop to `1.56.3`. ([@Set27])
29 | * Update rubocop-rails to `2.21.0`. ([@Set27])
30 | * Update rubocop-spec to `2.24.0`. ([@Set27])
31 |
32 | ## 1.4.0 (2023-02-11)
33 |
34 | ### Changed
35 |
36 | * Update rubocop to `1.45.1`. ([@r.dubrovsky][])
37 | * Update rubocop-rails to `2.17.4`. ([@r.dubrovsky][])
38 | * Update rubocop-rspec to `2.18.1`. ([@r.dubrovsky][])
39 |
40 | ## 1.3.0 (2022-12-02)
41 |
42 | ### Added
43 |
44 | * [#261](https://github.com/datarockets/ruby-style/issues/261) Add new config `rails-locales`. ([@r.dubrovsky][])
45 |
46 | ### Changed
47 |
48 | * **(Breaking)** Drop support for Ruby 2.4 and Ruby 2.5. ([@r.dubrovsky][])
49 |
50 | * [#260](https://github.com/datarockets/ruby-style/issues/260) Update rubocop to `1.39`. ([@r.dubrovsky][])
51 | * Setup `Layout/CaseIndentation` rule. ([@r.dubrovsky][])
52 | * [#261](https://github.com/datarockets/ruby-style/issues/261) Update rubocop-rails to `2.17.3`. ([@r.dubrovsky][])
53 | * [#262](https://github.com/datarockets/ruby-style/issues/262) Update rubocop-rspec to `2.15`. ([@r.dubrovsky][])
54 | * [#32](https://github.com/datarockets/ruby-style/issues/32) Enable back `Style/FrozenStringLiteralComment` cop. ([@r.dubrovsky][])
55 | * [#176](https://github.com/datarockets/ruby-style/issues/176) Fix hash alignment via changing `Layout/HashAlignment` cop. ([@r.dubrovsky][])
56 | * [#263](https://github.com/datarockets/ruby-style/issues/263) Setup `EnforcedStyle` for `Layout/LineEndStringConcatenationIndentation` cop. ([@r.dubrovsky][])
57 | * [#258](https://github.com/datarockets/ruby-style/issues/258) Setup `EnforcedStyle` for `Layout/FirstArrayElementIndentation` cop. ([@r.dubrovsky][])
58 | * [#179](https://github.com/datarockets/ruby-style/issues/179) Setup `EnforcedStyleAlignWith` rule for `Layout/BlockAlignment` cop. ([@r.dubrovsky][])
59 |
60 | ### Fixed
61 |
62 | * [#196](https://github.com/datarockets/ruby-style/issues/196) Fix `Layout/ArrayAlignmentExtended` cop. ([@r.dubrovsky][])
63 | * [#258](https://github.com/datarockets/ruby-style/issues/258) Fix conflict between `Layout/ArrayAlignmentExtended` and `Layout/FirstArrayElementIndentation` cops. ([@r.dubrovsky][])
64 |
65 | ## 1.2.0 (2021-02-24)
66 |
67 | ### Added
68 |
69 | * [#219](https://github.com/datarockets/datarockets-style/issues/219) Add `RSpec/PreferBeforeOverSetup` cop. ([@paydaylight][])
70 |
71 | ### Changed
72 |
73 | * [#233](https://github.com/datarockets/datarockets-style/issues/233) Setup `EnforcedStyleForMultiline` for `Style/TrailingCommaInArguments` and `Style/TrailingCommaInArrayLiteral` rules. ([@paydaylight][])
74 | * [#124](https://github.com/datarockets/datarockets-style/issues/124) Move gem dependencies to `./datarockets-style.gemspec` and drop `Gemfile.lock` tracking. ([@paydaylight][])
75 | * [#253](https://github.com/datarockets/datarockets-style/issues/253) Update rubocop to `1.10`. ([@paydaylight][])
76 | * [#124](https://github.com/datarockets/datarockets-style/issues/124) Update rubocop-rails to `2.9`. ([@paydaylight][])
77 |
78 | ### Fixed
79 |
80 | * [#251](https://github.com/datarockets/datarockets-style/issues/251) Update documentation to match `1.1.0` release changes. ([@paydaylight][])
81 |
82 | ## 1.1.0 (2021-02-09)
83 |
84 | ### Changed
85 |
86 | * Setup `EnforcedStyleForMultiline` for `Style/TrailingCommaInHashLiteral` rule. ([@r.dubrovsky][])
87 | * Update rubocop to `1.9.1`. ([@paydaylight][])
88 | * Update rubocop-rails requirement to `>= 2.8.0, < 2.10.0`. ([@paydaylight][])
89 | * Update rubocop-rspec to `2.2.0`. ([@paydaylight][])
90 | * Change `Datarockets::Style` module to `DatarocketsStyle`. ([@paydaylight][])
91 |
92 | ### Fixed
93 |
94 | * [#177](https://github.com/datarockets/datarockets-style/issues/177) set `Layout/MultilineOperationIndentation` to indented ([@paydaylight][])
95 |
96 | ## 1.0.0 (2020-11-10)
97 |
98 | ### Changed
99 |
100 | * Update rubocop to `1.2.0`.
101 | * Update rubocop-rails to `2.8.1`.
102 | * Update rubocop-rspec tp `2.0.0`.
103 |
104 | ## 0.11.0 (2020-11-07)
105 |
106 | ### Changed
107 |
108 | * Update rubocop to '0.93.1'. ([@r.dubrovsky][])
109 | * Enable new cops `Lint/BinaryOperatorWithIdenticalOperands`, `Lint/DuplicateRescueException`, `Lint/EmptyConditionalBody`, `Lint/FloatComparison`, `Lint/MissingSuper
110 | `, `Lint/OutOfRangeRegexpRef`, `Lint/SelfAssignment`, `Lint/TopLevelReturnWithArgument`, `Lint/UnreachableLoop`, `Style/ExplicitBlockArgument`, `Style/GlobalStdStream`, `Style/OptionalBooleanParameter`, `Style/SingleArgumentDig`, `Style/SoleNestedConditional` and `Style/StringConcatenation` in version `0.89`.
111 | * Allow to add all new lints automatically.
112 | * Add auto-correctable count notification.
113 | * Fix tests
114 | * Update rubocop-rails to `2.7.1`.
115 | * Update rubocop-rspec tp `1.43.2`.
116 | * Disable `RSpec/MultipleMemoizedHelpers` cop.
117 |
118 | ## 0.10.0 (2020-07-17)
119 |
120 | ### Changed
121 |
122 | * Update rubocop to `0.88.0`. ([@r.dubrovsky][])
123 | * Enable new cops `Lint/MixedRegexpCaptureTypes`, `Style/RedundantRegexpCharacterClass` and `Style/RedundantRegexpEscape`. Cops were added in version `0.85`.
124 | * Enable new cop `Style/RedundantFetchBlock`. Cop was added in version `0.86`.
125 | * Enable new cops `Style/AccessorGrouping`, `Style/BisectedAttrAccessor` and `Style/RedundantAssignment`. Cops were added in version `0.87`.
126 | * Enable new cops `Lint/DuplicateElsifCondition`, `Style/ArrayCoercion`, `Style/CaseLikeIf`, `Style/HashAsLastArrayItem`, `Style/HashLikeCase` and `Style/RedundantFileExtensionInRequire`. Cops were added in version `0.88`.
127 | * Update rubocop-rails to `2.6.0`.
128 | * Update rubocop-rspec to `1.42.0`.
129 |
130 | * Setup `no_braces` rule for `Style/HashAsLastArrayItem` cop which added in the rubocop version `0.88`.
131 |
132 | ## 0.9.0 (2020-05-27)
133 |
134 | ### Changed
135 |
136 | * **(Breaking)** Drop support for Ruby 2.3. ([@r.dubrovsky][])
137 |
138 | * Update rubocop to `0.84.0`. ([@r.dubrovsky][])
139 | * Enable new cops `Lint/RaiseException` and `Lint/StructNewOverride`. Cops were added in version `0.81`.
140 | * Enable new cops `Layout/SpaceAroundMethodCallOperator` and `Style/ExponentialNotation`. Cops were added in version `0.82`.
141 | * Enable new cops `Layout/EmptyLinesAroundAttributeAccessor` and `Style/SlicingWithRange`. Cops were added in version `0.83`.
142 | * Enable new cop `Lint/DeprecatedOpenSSLConstant`. Cop was added in version `0.84`.
143 |
144 | * Update rubocop-rails to `2.5.2`.
145 | * Update rubocop-rspec to `1.39`.
146 | * Update `activesupport` for fixing security issues.
147 |
148 | ## 0.8.1 (2020-03-02)
149 |
150 | ### Changed
151 |
152 | * Update rubocop to `0.80.1`.
153 |
154 | ## 0.8.0 (2020-02-20)
155 |
156 | ### Added
157 |
158 | * Add `Style/NestedInterpolation` cop. ([@r.dubrovsky][])
159 |
160 | ### Changed
161 |
162 | * Update rubocop to `0.80.0`. ([@r.dubrovsky][])
163 | * Add `Style/HashEachMethods`, `Style/HashTransformKey`, `Style/HashTransformValues` cops.
164 | * [#7641](https://github.com/rubocop-hq/rubocop/issues/7641): Remove `Style/BracesAroundHashParameters` cop.
165 |
166 | * Update rubocop-rspec to `1.38.1`.
167 | * Add RSpec/RepeatedExampleGroupBody cop. ([@ula][])
168 | * Add RSpec/RepeatedExampleGroupDescription cop. ([@ula][])
169 |
170 | * Enable `rubocop-rails` cops for rails config. ([@ula][])
171 | * Setup `Style/Documentation` for rails config. ([@r.dubrovsky][])
172 | * Setup `Style/ClassAndModuleChildren` cop. ([@r.dubrovsky][])
173 | * Enable `RSpec/LetSetup` cop. ([@r.dubrovsky][])
174 |
175 | ## 0.7.0 (2020-01-27)
176 |
177 | ### Added
178 |
179 | * [#130](https://github.com/datarockets/datarockets-style/issues/130): Add Layout/ArrayAlignmentExtended cop ([@nikitasakov][])
180 |
181 | ### Changed
182 |
183 | * Update rubocop to `0.79.0`.
184 | * Update rubocop-rspec to `1.37.1`.
185 | * Add notes for setting up Rspec configuration for fixing Rspec internal style issues. ([@r.dubrovsky][])
186 | * [#58](https://github.com/datarockets/datarockets-style/issues/58): Disable `RSpec/LetSetup` cop by default. ([@ula][])
187 |
188 | ### Fixed
189 |
190 | * [#80](https://github.com/datarockets/datarockets-style/issues/80): Allows adding additional files and directories to excluding block for rubocop. ([@nikitasakov][])
191 | * Fix documentation issues. ([@ula][])
192 |
193 |
194 | ## 0.6.2 (2019-12-05)
195 |
196 | ### Changed
197 |
198 | * Update rubocop to `0.77.0`.
199 |
200 | ## Fixed
201 |
202 | * [#137](https://github.com/datarockets/datarockets-style/issues/137): Usage of rubocop 0.77.0 version causes errors. ([@d.kachur][])
203 |
204 | ## 0.6.1 (2019-11-06)
205 |
206 | ### Fixed
207 |
208 | * [#126](https://github.com/datarockets/datarockets-style/issues/126): Result for ToDo list formatter. ([@r.dubrovsky][])
209 |
210 | ## 0.6.0 (2019-11-06)
211 |
212 | ### Added
213 |
214 | * [#107](https://github.com/datarockets/datarockets-style/issues/107): Add ToDo list formatter. ([@r.dubrovsky][])
215 |
216 | ### Changed
217 |
218 | * Update rubocop to `0.76`. ([@r.dubrovsky][])
219 | * Change default value for `RSpec/ExampleLength` cop. ([@a.branzeanu][])
220 | * Disable `RSpec/NestedGroups` cop by default. ([@r.dubrovsky][])
221 |
222 | ## 0.5.0 (2019-10-26)
223 |
224 | ### Changed
225 |
226 | * Split single rubocop config to smaller (for ruby, rails and rspec). ([@r.dubrovsky][])
227 | * Update rubocop to `0.75.1`.
228 | * Update rubocop-rspec to `1.36.0`.
229 | * Use block style for `RSpec/ExpectChange` cop. ([@r.dubrovsky][])
230 | * Add `RSpec/MessageSpies` cop to style guide. ([@r.dubrovsky][])
231 |
232 | ### Fixed
233 |
234 | * Fix `RSpec/DescribedClass`'s error when `described_class` is used as part of a constant. This is part of rubocop-rspec changes.
235 |
236 | ## 0.4.0 (2019-08-13)
237 |
238 | ### Changed
239 |
240 | * Update rubocop-rspec to `1.35.0`. ([@r.dubrovsky][])
241 | * Use context-dependent style for curly braces around hash params. ([@v.kuzmik][])
242 | * Use leading underscores in cached instance variable name (cop: `Naming/MemoizedInstanceVariableName`). ([@ula][])
243 | * Allow use `for` with `RSpec/ContextWording` cop. ([@r.dubrovsky][])
244 | * Change `Layout/AlignArguments` and `Layout/IndentFirstHashElement` cops for aligning arguments with fixed indentation. ([@r.dubrovsky][])
245 | * Enable `Layout/MultilineMethodCallIndentation` cop for aligning arguments with fixed indentation. ([@r.dubrovsky][], [@ula][])
246 |
247 | ## 0.3.0 (2019-08-02)
248 |
249 | ### Changed
250 |
251 | * Update rubocop to `0.74.0`. ([@r.dubrovsky][])
252 | * Update rubocop-rspec to `1.34.1`. ([@r.dubrovsky][])
253 | * Move shared rubocop config into `config` directory. ([@r.dubrovsky][])
254 | * Allow writing empty methods in two lines. ([@v.kuzmik][])
255 | * Disable `Style/FrozenStringLiteralComment` cop by default. ([@r.dubrovsky][])
256 |
257 | ### Fixed
258 |
259 | * [#4222](https://github.com/rubocop-hq/rubocop/issues/4222): Disable `Lint/AmbiguousBlockAssociation` for Rspec directory. ([@r.dubrovsky][])
260 | * [#65](https://github.com/datarockets/datarockets-style/issues/65): Exclude `node_modules` from rubocop scope. ([@r.dubrovsky][])
261 |
262 | ## 0.2.0 (2019-07-17)
263 |
264 | ### Changed
265 |
266 | * Update rubocop to `0.73.0`. ([@r.dubrovsky][])
267 | * Use preferred variable name in rescued exceptions (cop: `Naming/RescuedExceptionsVariableName`). ([@ula][])
268 | * Disable `RSpec/ImplicitSubject` cop for rspec files. ([@r.dubrovsky][])
269 |
270 | ## 0.1.0 (2019-06-27)
271 |
272 | ### Added
273 |
274 | * Base config with community rules and some basic override rules. ([@r.dubrovsky][], [@aleks][])
275 | * Config is based on rubocop version 0.72.0. ([@r.dubrovsky][])
276 | * Enable `rubocop-spec` cops by default. ([@r.dubrovsky][])
277 | * Enable `Bundler/DuplicatedGem` cop by default. ([@r.dubrovsky][])
278 | * Enable `Bundler/OrderedGems` cop with allowing ordering by groups. ([@r.dubrovsky][])
279 |
280 |
281 | ### Changed
282 |
283 | * Change the limit for size of line to 120 symbols. ([@r.dubrovsky][])
284 | * Disable `Metrics/BlockLength` cop for rspec files. ([@r.dubrovsky][])
285 | * Exclude rubocop checking for some config directories. ([@r.dubrovsky][])
286 | * Enable preferring double quotes for string literals. ([@r.dubrovsky][])
287 | * Do not add spaces between hash literal braces (cop `Layout/SpaceInsideHashLiteralBraces`). ([@r.dubrovsky][])
288 | * Prefer normal style for `Layout/IndentationConsistency` cop for Rails apps too. ([@r.dubrovsky][])
289 | * Change style to `variable` for `Layout/EndAlignment` cop. ([@r.dubrovsky][])
290 | * Change style to `with_fixed_indentation` with indentation width 2 for `Layout/AlignParameter` cop. ([@r.dubrovsky][])
291 | * Always ignore hash aligning for key word arguments. (cop: `Layout/AlignHash`) ([@r.dubrovsky][])
292 |
293 | [@r.dubrovsky]: https://github.com/roman-dubrovsky
294 | [@aleks]: https://github.com/AleksSenkou
295 | [@ula]: https://github.com/lazycoder9
296 | [@v.kuzmik]: https://github.com/TheBlackArroVV/
297 | [@a.branzeanu]: https://github.com/texpert
298 | [@nikitasakov]: https://github.com/nikitasakov
299 | [@paydaylight]: https://github.com/paydaylight
300 | [@Anastastasia-B]: https://github.com/Anastastasia-B
301 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at hello@datarockets.com All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | If you discover issues, want to add or change some code-style rules,
4 | have ideas for improvements or new features,
5 | please report them to the [issue tracker][1] of the repository or
6 | submit a pull request. Please, try to follow these guidelines when you
7 | do so.
8 |
9 | ## Issue reporting
10 |
11 | * Check that the issue has not already been reported.
12 | * Check that the issue has not already been fixed in the latest code
13 | (a.k.a. `master`).
14 | * Be clear, concise and precise in your description of the problem.
15 | * Open an issue with a descriptive title and a summary in grammatically correct,
16 | complete sentences.
17 | * Include any relevant code to the issue summary
18 |
19 | ## Pull requests
20 |
21 | * Read [how to properly contribute to open source projects on GitHub][2].
22 | * Fork the project (if it's necessary and you don't have writing access).
23 | * Use a topic/feature branch to easily amend a pull request later, if necessary.
24 | * Write [good commit messages][3].
25 | * Use the same coding conventions as the rest of the project.
26 | * Commit and push until you are happy with your contribution.
27 | * If your change has a corresponding open GitHub issue, prefix the commit message with `[Fix #github-issue-number]`.
28 | * Make sure to add tests for it. This is important so we don't break it
29 | in a future version unintentionally.
30 | * If you add new code-style rule or cop, add some words about it in the [Code Style Notes](doc/STYLE_GUIDE.md) or related files.
31 | * Add an entry to the [Changelog](CHANGELOG.md) accordingly. See [changelog entry format](#changelog-entry-format).
32 | * If you deliver new cop, try to suggest and deliver it to the community [rubocop][7] gem.
33 | * [Squash related commits together][5].
34 | * Open a [pull request][4] that relates to *only* one subject with a clear title
35 | and description in grammatically correct, complete sentences.
36 |
37 | ### Changelog entry format
38 |
39 | Here are a few examples:
40 |
41 | ```
42 | * [#716](https://github.com/rubocop-hq/rubocop/issues/716): Fixed a regression in the auto-correction logic of `MethodDefParentheses`. ([@bbatsov][])
43 | * New cop `ElseLayout` checks for odd arrangement of code in the `else` branch of a conditional expression. ([@bbatsov][])
44 | ```
45 |
46 | * There are four categories for each release: added, changed, bug fixed and removed
47 | * Mark it up in [Markdown syntax][6].
48 | * The entry line should start with `* ` (an asterisk and a space).
49 | * If the change has a related GitHub issue (e.g. a bug fix for a reported issue), put a link to the issue as `[#123](https://github.com/rubocop-hq/rubocop/issues/123): `.
50 | * Describe the brief of the change. The sentence should end with a punctuation.
51 | * At the end of the entry, add an implicit link to your GitHub user page as `([@username][])`.
52 | * If this is your first contribution to RuboCop project, add a link definition for the implicit link to the bottom of the changelog as `[@username]: https://github.com/username`.
53 |
54 | [1]: https://github.com/datarockets/datarockets-style/issues
55 | [2]: https://www.gun.io/blog/how-to-github-fork-branch-and-pull-request
56 | [3]: https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
57 | [4]: https://help.github.com/articles/about-pull-requests
58 | [5]: http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html
59 | [6]: https://daringfireball.net/projects/markdown/syntax
60 | [7]: https://github.com/rubocop-hq/rubocop
61 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6 |
7 | gemspec
8 |
9 | gem "pry-byebug"
10 | gem "rake", "~> 13.0"
11 | gem "rspec", "~> 3.12.0"
12 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 datarockets
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | install:
2 | bundle install
3 |
4 | test:
5 | bundle exec rspec spec
6 |
7 | lint:
8 | bundle exec rubocop
9 |
10 | .PHONY: test
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Datarockets::Style [](https://badge.fury.io/rb/datarockets-style)
2 |
3 | Datarockets shared style configs and notes of code-style conventions. Based on the [Rubocop](https://github.com/rubocop-hq/rubocop) util.
4 |
5 | This config enforces many of the guidelines outlined in the datarockets [Ruby Style Guide](doc/STYLE_GUIDE.md).
6 |
7 | ## Installation
8 |
9 | Add this line to your application's Gemfile:
10 |
11 | ```ruby
12 | group :test, :development do
13 | gem 'datarockets-style', '~> 1.6.0'
14 | end
15 | ```
16 |
17 | Or, for a Ruby library, add this to your gemspec:
18 |
19 | ```ruby
20 | spec.add_development_dependency 'datarockets-style', '~> 1.6.0'
21 | ```
22 |
23 | And then execute:
24 |
25 | ```bash
26 | $ bundle install
27 | ```
28 |
29 | ## Usage
30 |
31 | Create a `.rubocop.yml` with the following directives:
32 |
33 |
34 | ### Ruby application
35 |
36 | This config includes specific rules for Ruby application. It works for Ruby gems and no-Rails applications.
37 |
38 | ```yaml
39 | inherit_gem:
40 | datarockets-style:
41 | - config/ruby.yml
42 | ```
43 |
44 | ### Rails application
45 |
46 | For Rails applications, you can use a specific Rails instead of Ruby config
47 |
48 | ```yaml
49 | inherit_gem:
50 | datarockets-style:
51 | - config/rails.yml
52 | ```
53 |
54 | By default, it doesn't include rules for I18n. For enabling them, add the next styles
55 |
56 | ```yaml
57 | inherit_gem:
58 | datarockets-style:
59 | - config/rails.yml
60 | - config/rails-locales.yml
61 | ```
62 |
63 | ### GraphQL config
64 |
65 | To include specific rules for GraphQL, you can add the following config
66 |
67 | ```yaml
68 | inherit_gem:
69 | datarockets-style:
70 | - config/graphql.yml
71 | ```
72 |
73 | ### Rspec config
74 |
75 | For Rspec tests, you can add a special rubocop config
76 |
77 | ```yaml
78 | inherit_gem:
79 | datarockets-style:
80 | - config/ruby.yml
81 | - config/rspec.yml
82 | ```
83 |
84 | Now, run:
85 |
86 | ```bash
87 | $ bundle exec rubocop
88 | ```
89 |
90 | You do not need to include rubocop directly in your application's dependencies. Datarockets-style will include a specific version of `rubocop` and `rubocop-rspec` that is shared across all projects.
91 |
92 | ### Configurable cops
93 |
94 | There are some areas in which there is no clear consensus in datarockets team regarding a particular style (like string literal quoting).
95 | In such scenarios, all popular styles are acknowledged and it’s up to you to pick one and apply it consistently.
96 | For that just set up these cops before starting of usage.
97 |
98 | #### RSpec/LetSetup
99 |
100 | [This cop](https://rubocop-rspec.readthedocs.io/en/latest/cops_rspec/#rspecletsetup) is enabled by default and we suggest not to use unreferenced `let` variables in your test cases.
101 | However, if it feels like the cop should be enabled and tests can't be written w/o them, please create an issue with your cases so that we can re-thinking our solution about enabling this cop.
102 |
103 | #### Style/StringLiterals
104 |
105 | There are two popular styles in the Ruby community, both of which are considered good - single quotes by default and double quotes by default.
106 | There is no clear consensus about this style in the Ruby community and in the datarockets team.
107 | So we suggest just to set up a [preferable style](https://rubocop.readthedocs.io/en/latest/cops_style/#stylestringliterals) before running this gem.
108 |
109 | P.S. The string literals in this gem are using double quotes by default.
110 |
111 | ##### Tips
112 |
113 | For an existing project, we suggest running rubocop with both styles and choose which has fewer offenses (which is more popular in the current project).
114 |
115 | ### Custom cops
116 |
117 | We have custom cops. You can find specification for them [here](manual).
118 |
119 | ## Formatters
120 |
121 | ### ToDo list formatter
122 |
123 | This formatter allows us to get list of files for some offense and with number of offenses in each file. This file can be useful if you need to fix a large some cop step by step.
124 |
125 | Result of the formatter is compatible with rubocop config or rubocop todo file.
126 |
127 | For running that cop, just print in your command like
128 |
129 | ```bash
130 | $ bundle exec rubocop -f TodoListFormatter -r datarockets_style
131 | Inspecting 10 files
132 | ...CC.CC..
133 | 10 files inspected, 7 offenses detected
134 |
135 | Layout/IndentationConsistency:
136 | Exclude:
137 | - 'spec/datarockets_style/formatter/todo_list_formatter_spec.rb' # 1
138 |
139 | Naming/MemoizedInstanceVariableName:
140 | Exclude:
141 | - 'lib/datarockets_style/formatter/todo_list_formatter/report_summary.rb' # 1
142 |
143 | RSpec/ExampleLength:
144 | Exclude:
145 | - 'spec/datarockets_style/formatter/todo_list_formatter/report_summary_spec.rb' # 1
146 | - 'spec/datarockets_style/formatter/todo_list_formatter_spec.rb' # 2
147 |
148 | Style/Documentation:
149 | Exclude:
150 | - 'lib/datarockets_style/formatter/todo_list_formatter/report_summary.rb' # 1
151 | - 'lib/datarockets_style/formatter/todo_list_formatter.rb' # 1
152 | ```
153 |
154 | #### Autocorrection
155 |
156 | If you run the formatter with autocorrection options, the formatter skip corrected cop and does not include it to the result.
157 |
158 | ```bash
159 | $ bundle exec rubocop -f TodoListFormatter -r datarockets_style -a
160 | Inspecting 10 files
161 | ...CC.CC..
162 | 10 files inspected, 7 offenses detected, 1 offenses corrected
163 |
164 | Naming/MemoizedInstanceVariableName:
165 | Exclude:
166 | - 'lib/datarockets_style/formatter/todo_list_formatter/report_summary.rb' # 1
167 |
168 | RSpec/ExampleLength:
169 | Exclude:
170 | - 'spec/datarockets_style/formatter/todo_list_formatter/report_summary_spec.rb' # 1
171 | - 'spec/datarockets_style/formatter/todo_list_formatter_spec.rb' # 2
172 |
173 | Style/Documentation:
174 | Exclude:
175 | - 'lib/datarockets_style/formatter/todo_list_formatter/report_summary.rb' # 1
176 | - 'lib/datarockets_style/formatter/todo_list_formatter.rb' # 1
177 | ```
178 |
179 | ## Non-goals of RuboCop
180 |
181 | ### Rspec configuration
182 |
183 | RSpec-core library provides some configuration rules which provides some linting rules itself. Read more about it in [RuboCop Rspec non-goals topic](https://github.com/rubocop-hq/rubocop-rspec#non-goals-of-rubocop-rspec).
184 |
185 | ## Changelog
186 |
187 | Datarockets Style's changelog is available [here](CHANGELOG.md).
188 |
189 | ## Contributing
190 |
191 | Bug reports and pull requests are welcome on GitHub at https://github.com/datarockets/datarockets-style. If you'd like to contribute to our RuboCop config and code-style rules, please take the time to go through our short [contribution guidelines](CONTRIBUTING.md).
192 |
193 |
194 | ## License
195 |
196 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
197 |
198 | ## Code of Conduct
199 |
200 | Everyone interacting in the DatarocketsStyle project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
201 |
--------------------------------------------------------------------------------
/RELEASING.md:
--------------------------------------------------------------------------------
1 | # Releasing
2 |
3 | * Update `version.rb` file accordingly.
4 | * Update `README.mb` file.
5 | * Update `CHANGELOG.md` file.
6 | * Build and publish (and verify that everything ok):
7 |
8 | ```bash
9 | bundle exec rake build
10 | gem push *built_file*
11 | ```
12 | * Tag the release: `git tag vVERSION`.
13 | * Push changes: `git push --tags`.
14 | * Update the release notes on GitHub.com.
15 | * Announce the new release,
16 | making sure to say "thank you" to the contributors
17 | who helped shape this version!
18 |
19 | ## Versioning stragety
20 |
21 | As versioning strategy, we're using SemVer: `MAJOR.MINOR.PATCH`
22 |
23 | A `MAJOR` version must be incremented if there are any backward-incompatible breaking changes included in a release. This has the benefit of making it easy for anyone to quickly identify if a new version will work differently than a previous one.
24 |
25 | Usually, we'll increment it on updating major versions of rubocop dependencies. Ideally, it should be synchronized with the major verion of `rubocop`.
26 |
27 | The `MINOR` version must be incremented if backward-compatible functionality is introduced. In the strictest sense, this means you should be able to upgrade to a new minor version without experiencing any breaking changes.
28 |
29 | Usually, we'll increment it on changing the list of cops, updating minor versions of dependencies.
30 |
31 | The `PATCH` version is meant for backward-compatible bug fixes. You should expect no new functionality with a new patch version, only improvements.
32 |
33 | Usually, we'll use it for updating patch versions of dependencies or fixing bugs of the last version. Changed rules of cops in most cases should be added to minor version.
34 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/gem_tasks"
2 | # require "rspec/core/rake_task"
3 |
4 | # RSpec::Core::RakeTask.new(:spec)
5 |
6 | task :default => :spec
7 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "bundler/setup"
4 | require "datarockets_style"
5 |
6 | # You can add fixtures and/or initialization code here to make experimenting
7 | # with your gem easier. You can also use a different console, if you like.
8 |
9 | # (If you use this, don't forget to add pry to your Gemfile!)
10 | # require "pry"
11 | # Pry.start
12 |
13 | require "irb"
14 | IRB.start(__FILE__)
15 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 | IFS=$'\n\t'
4 | set -vx
5 |
6 | bundle install --path=bundler
7 |
8 | # Do any other automated setup that you need to do here
9 |
--------------------------------------------------------------------------------
/config/base.yml:
--------------------------------------------------------------------------------
1 | require: datarockets_style
2 |
3 | AllCops:
4 | NewCops: enable
5 |
6 | Bundler/DuplicatedGem:
7 | Enabled: true
8 |
9 | Bundler/OrderedGems:
10 | TreatCommentsAsGroupSeparators: true
11 |
12 | Layout/ArgumentAlignment:
13 | EnforcedStyle: with_fixed_indentation
14 |
15 | Layout/ArrayAlignment:
16 | Enabled: false
17 |
18 | Layout/ArrayAlignmentExtended:
19 | Description: >-
20 | Align the elements of an array literal if they span more than
21 | one line.
22 | EnforcedStyle: with_fixed_indentation
23 | SupportedStyles:
24 | - with_first_parameter
25 | - with_fixed_indentation
26 | IndentationWidth: ~
27 |
28 | Layout/BlockAlignment:
29 | EnforcedStyleAlignWith: start_of_block
30 |
31 | Layout/CaseIndentation:
32 | EnforcedStyle: end
33 |
34 | Layout/FirstArrayElementIndentation:
35 | EnforcedStyle: consistent
36 |
37 | Layout/HashAlignment:
38 | EnforcedColonStyle: key
39 | EnforcedHashRocketStyle: key
40 |
41 | Layout/ParameterAlignment:
42 | EnforcedStyle: with_fixed_indentation
43 | IndentationWidth: 2
44 |
45 | Layout/EmptyLinesAroundAttributeAccessor:
46 | Enabled: true
47 |
48 | Layout/EndAlignment:
49 | EnforcedStyleAlignWith: variable
50 |
51 | Layout/IndentationConsistency:
52 | EnforcedStyle: normal
53 |
54 | Layout/LineEndStringConcatenationIndentation:
55 | EnforcedStyle: indented
56 |
57 | Layout/LineLength:
58 | Max: 120
59 |
60 | Layout/FirstHashElementIndentation:
61 | EnforcedStyle: consistent
62 |
63 | Layout/MultilineMethodCallIndentation:
64 | EnforcedStyle: indented
65 |
66 | Layout/MultilineOperationIndentation:
67 | EnforcedStyle: indented
68 |
69 | Layout/SpaceAroundMethodCallOperator:
70 | Enabled: true
71 |
72 | Layout/SpaceInsideHashLiteralBraces:
73 | EnforcedStyle: no_space
74 | EnforcedStyleForEmptyBraces: no_space
75 |
76 | Lint/BinaryOperatorWithIdenticalOperands:
77 | Enabled: true
78 |
79 | Lint/DeprecatedOpenSSLConstant:
80 | Enabled: true
81 |
82 | Lint/DuplicateElsifCondition:
83 | Enabled: true
84 |
85 | Lint/DuplicateRescueException:
86 | Enabled: true
87 |
88 | Lint/EmptyConditionalBody:
89 | Enabled: true
90 |
91 | Lint/FloatComparison:
92 | Enabled: true
93 |
94 | Lint/MissingSuper:
95 | Enabled: true
96 |
97 | Lint/MixedRegexpCaptureTypes:
98 | Enabled: true
99 |
100 | Lint/OutOfRangeRegexpRef:
101 | Enabled: true
102 |
103 | Lint/RaiseException:
104 | Enabled: true
105 |
106 | Lint/SelfAssignment:
107 | Enabled: true
108 |
109 | Lint/StructNewOverride:
110 | Enabled: true
111 |
112 | Lint/TopLevelReturnWithArgument:
113 | Enabled: true
114 |
115 | Lint/UnreachableLoop:
116 | Enabled: true
117 |
118 | Naming/MemoizedInstanceVariableName:
119 | EnforcedStyleForLeadingUnderscores: required
120 |
121 | Naming/RescuedExceptionsVariableName:
122 | PreferredName: error
123 |
124 | Style/AccessorGrouping:
125 | Enabled: true
126 |
127 | Style/ArrayCoercion:
128 | Enabled: true
129 |
130 | Style/BisectedAttrAccessor:
131 | Enabled: true
132 |
133 | Style/CaseLikeIf:
134 | Enabled: true
135 |
136 | Style/ClassAndModuleChildren:
137 | EnforcedStyle: nested
138 |
139 | Style/EmptyMethod:
140 | EnforcedStyle: expanded
141 |
142 | Style/ExplicitBlockArgument:
143 | Enabled: true
144 |
145 | Style/ExponentialNotation:
146 | Enabled: true
147 |
148 | Style/GlobalStdStream:
149 | Enabled: true
150 |
151 | Style/HashAsLastArrayItem:
152 | Enabled: true
153 | EnforcedStyle: no_braces
154 |
155 | Style/HashEachMethods:
156 | Enabled: true
157 |
158 | Style/HashLikeCase:
159 | Enabled: true
160 |
161 | Style/HashTransformKeys:
162 | Enabled: true
163 |
164 | Style/HashTransformValues:
165 | Enabled: true
166 |
167 | Style/FrozenStringLiteralComment:
168 | Enabled: true
169 |
170 | Style/NestedInterpolation:
171 | Enabled: true
172 |
173 | Style/OptionalBooleanParameter:
174 | Enabled: true
175 |
176 | Style/RedundantAssignment:
177 | Enabled: true
178 |
179 | Style/RedundantFetchBlock:
180 | Enabled: true
181 |
182 | Style/RedundantFileExtensionInRequire:
183 | Enabled: true
184 |
185 | Style/RedundantRegexpCharacterClass:
186 | Enabled: true
187 |
188 | Style/RedundantRegexpEscape:
189 | Enabled: true
190 |
191 | Style/SingleArgumentDig:
192 | Enabled: true
193 |
194 | Style/SlicingWithRange:
195 | Enabled: true
196 |
197 | Style/SoleNestedConditional:
198 | Enabled: true
199 |
200 | Style/StringConcatenation:
201 | Enabled: true
202 |
203 | Style/StringLiterals:
204 | EnforcedStyle: double_quotes
205 |
206 | Style/TrailingCommaInArguments:
207 | EnforcedStyleForMultiline: comma
208 |
209 | Style/TrailingCommaInArrayLiteral:
210 | EnforcedStyleForMultiline: comma
211 |
212 | Style/TrailingCommaInHashLiteral:
213 | EnforcedStyleForMultiline: comma
214 |
--------------------------------------------------------------------------------
/config/graphql.yml:
--------------------------------------------------------------------------------
1 | require: rubocop-graphql
2 |
3 | GraphQL/ExtractInputType:
4 | Enabled: false
5 |
6 | GraphQL/ExtractType:
7 | Enabled: false
8 |
9 | GraphQL/ResolverMethodLength:
10 | Max: 10
11 |
--------------------------------------------------------------------------------
/config/rails-locales.yml:
--------------------------------------------------------------------------------
1 | Rails/I18nLocaleTexts:
2 | Enabled: true
3 |
--------------------------------------------------------------------------------
/config/rails.yml:
--------------------------------------------------------------------------------
1 | require: rubocop-rails
2 |
3 | inherit_from: base.yml
4 |
5 | AllCops:
6 | Exclude:
7 | - "db/**/*"
8 | - "bin/*"
9 | - "lib/tasks/**/*"
10 | - "config/**/*"
11 | - "node_modules/**/*"
12 | - "vendor/**/*"
13 | - "app/views/**/*"
14 | - "config.ru"
15 | - "Rakefile"
16 |
17 | Rails/I18nLocaleTexts:
18 | Enabled: false
19 |
20 | Style/Documentation:
21 | Enabled: true
22 | Exclude:
23 | - "app/**/*"
24 |
--------------------------------------------------------------------------------
/config/rspec.yml:
--------------------------------------------------------------------------------
1 | require: rubocop-rspec
2 |
3 | Lint/AmbiguousBlockAssociation:
4 | Exclude:
5 | - "spec/**/*"
6 |
7 | Metrics/BlockLength:
8 | Exclude:
9 | - "spec/**/*"
10 |
11 | RSpec/ContextWording:
12 | Prefixes:
13 | - when
14 | - with
15 | - without
16 | - for
17 |
18 | RSpec/ExampleLength:
19 | Enabled: true
20 | Max: 10
21 |
22 | RSpec/ExpectChange:
23 | EnforcedStyle: block
24 |
25 | RSpec/ImplicitSubject:
26 | Enabled: false
27 |
28 | RSpec/LetSetup:
29 | Enabled: true
30 |
31 | RSpec/MessageSpies:
32 | EnforcedStyle: have_received
33 |
34 | RSpec/MultipleMemoizedHelpers:
35 | Enabled: false
36 |
37 | RSpec/NestedGroups:
38 | Enabled: false
39 |
40 | RSpec/PreferBeforeOverSetup:
41 | Enabled: true
42 |
--------------------------------------------------------------------------------
/config/ruby.yml:
--------------------------------------------------------------------------------
1 | AllCops:
2 | Exclude:
3 | - "bundler/**/*"
4 | - "bin/*"
5 | - "lib/tasks/**/*"
6 | - "vendor/**/*"
7 | - "config.ru"
8 | - "Rakefile"
9 |
10 | inherit_from: base.yml
11 |
--------------------------------------------------------------------------------
/datarockets-style.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | lib = File.expand_path("lib", __dir__)
4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5 | require "datarockets_style/version"
6 |
7 | Gem::Specification.new do |spec|
8 | spec.name = "datarockets-style"
9 | spec.version = DatarocketsStyle::VERSION
10 | spec.authors = ["Roman Dubrovsky"]
11 | spec.email = ["r.dubrovsky@datarockets.com"]
12 |
13 | spec.summary = "Datarockets style guides and shared style configs"
14 | spec.homepage = "https://github.com/datarockets/datarockets-style"
15 | spec.license = "MIT"
16 |
17 | spec.required_ruby_version = ">= 3.0.0"
18 |
19 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
20 | # to allow pushing to a single host or delete this section to allow pushing to any host.
21 | if spec.respond_to?(:metadata)
22 | spec.metadata["allowed_push_host"] = "https://rubygems.org"
23 | else
24 | raise "RubyGems 2.0 or newer is required to protect against " \
25 | "public gem pushes."
26 | end
27 |
28 | spec.files = `git ls-files -z`.split("\x0").reject do |f|
29 | f.match(%r{^(test|spec|features)/})
30 | end
31 | spec.bindir = "exe"
32 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33 | spec.require_paths = ["lib"]
34 |
35 | spec.add_dependency "rubocop", "~> 1.65.1"
36 | spec.add_dependency "rubocop-graphql", "~> 1.5.4"
37 | spec.add_dependency "rubocop-rails", "~> 2.26"
38 | spec.add_dependency "rubocop-rspec", "~> 3.0.4"
39 |
40 | spec.metadata["rubygems_mfa_required"] = "true"
41 | end
42 |
--------------------------------------------------------------------------------
/doc/STYLE_GUIDE.md:
--------------------------------------------------------------------------------
1 | # Style Guide
2 |
3 | In datarockets we enforce a community [Ruby Style Guide](https://github.com/rubocop-hq/ruby-style-guide).
4 |
5 | Also, we have some new rules for writing Rails applications and Rspec test. You can find it by next links:
6 |
7 | - [Rails Style Guide](doc/STYLE_GUIDE_RAILS.md)
8 | - [Rspec Style Guide](doc/STYLE_GUIDE_RSPEC.md)
9 |
10 | This is a small list of differences which we have when compared with community style guide:
11 |
12 | ## Table of contents
13 |
14 | * [Bundler](#Bundler)
15 | * [Style](#Style)
16 | * [Rspec](#Rspec)
17 |
18 | ## Bundler
19 |
20 | *
21 | A Gem's requirements should be listed only once in a Gemfile.
22 | [[link](#bundler-add-once)]
23 |
24 | *
25 | Gems should be alphabetically sorted within groups. Also, you can use a line comment as a group separator.
26 | [[link](#bundler-ordering)]
27 |
28 | ## Style
29 |
30 | *
31 | Limit lines to 120 characters.
32 | [[link](#style-line-length)]
33 |
34 | *
35 | Adopt a consistent string literal quoting style.
36 | [[link](#style-string-quotes)]
37 |
38 | *
39 | Avoid using nested interpolation.
40 | [[link](#style-nested-interpolation)]
41 |
42 | ```ruby
43 | # bad
44 | "Hello, #{user.blank? ? 'guest' : "dear #{user.name}"}"
45 |
46 | # good
47 | user_name = user.blank? ? 'guest' : "dear #{user.name}"
48 | "Hello, #{user_name}"
49 | ```
50 |
51 | *
52 | If elements of a hash literal span more than one line, we're aligning them by keys.
53 | Also, the first hash key is aligned by an indentation level.
54 | [[link](#style-hash-aligning)]
55 |
56 |
57 | ```ruby
58 | # bad
59 | {
60 | foo: bar,
61 | ba: baz
62 | }
63 |
64 | {
65 | foo: bar,
66 | ba: baz
67 | }
68 |
69 | {
70 | foo: bar,
71 | ba: baz
72 | }
73 |
74 | {
75 | foo: {
76 | bar: bar,
77 | ba: baz
78 | }
79 | }
80 |
81 | method_call({
82 | its_like: :this
83 | })
84 |
85 | # good
86 | {
87 | foo: bar,
88 | ba: baz
89 | }
90 |
91 | {
92 | foo: {
93 | bar: bar,
94 | ba: baz
95 | }
96 | }
97 |
98 | method_call({
99 | no: :difference
100 | })
101 | ```
102 |
103 | *
104 | All arguments on a multi-line method definition are aligning by an indentation level.
105 | This rule works as for keyword arguments, as for usual arguments.
106 | [[link](#style-arguments-aligning)]
107 |
108 | ```ruby
109 | # bad
110 | do_something(foo: 1,
111 | bar: 2)
112 |
113 | # good
114 | do_something(foo: 1,
115 | bar: 2)
116 |
117 | # good
118 | foo :bar,
119 | :baz
120 |
121 | # bad
122 | foo :bar,
123 | :baz
124 | ```
125 |
126 | *
127 | The parameters on a multi-line method call or definition are aligning by an indentation level.
128 | [[link](#style-parameters-aligning)]
129 |
130 | **Recommended:** write each parameter on the separate line.
131 |
132 | ```ruby
133 | # bad
134 |
135 | def foo(bar, baz,
136 | kek, lol)
137 | 123
138 | end
139 |
140 | # bad
141 |
142 | def foo(
143 | bar,
144 | baz)
145 | 123
146 | end
147 |
148 | # good
149 |
150 | def foo(bar, baz,
151 | kek, lol)
152 | 123
153 | end
154 |
155 | # better
156 |
157 | def foo(
158 | bar,
159 | baz,
160 | kek,
161 | lol
162 | )
163 | 123
164 | end
165 | ```
166 |
167 | *
168 | The elements of a multi-line array are aligning by an indentation level.
169 | [[link](#style-array-aligning)]
170 |
171 | ```ruby
172 | # bad
173 |
174 | array = [1, 2, 3,
175 | 4, 5, 6]
176 |
177 | # bad
178 |
179 | array = [1, 2, 3,
180 | 4, 5, 6]
181 |
182 | # good
183 |
184 | array = [1, 2, 3,
185 | 4, 5, 6]
186 | ```
187 |
188 | *
189 | The indentation of the method name part in method calls that span more than one line are aligning by an indentation level.
190 | [[link](#style-multiline-method-call-indentation)]
191 |
192 | ```ruby
193 | # bad
194 | while myvariable
195 | .b
196 | # do something
197 | end
198 |
199 | # bad
200 | Thing.a
201 | .b
202 | .c
203 |
204 | # good
205 | while myvariable
206 | .b
207 |
208 | # do something
209 | end
210 |
211 | # good
212 | Thing.a
213 | .b
214 | .c
215 | ```
216 |
217 | *
218 | The `end` shall be aligned with the left-hand-side of the variable assignment. But we prefer not to use code blocks with `end` for variable assignment and prefer move it into the separate methods.
219 | [[link](#style-end-aligning)]
220 |
221 | ```ruby
222 | # bad
223 |
224 | variable = if true
225 | end
226 |
227 | variable = array.map do |value|
228 | value
229 | end
230 |
231 | # good
232 |
233 | variable = if true
234 | end
235 |
236 | variable =
237 | if true
238 | end
239 |
240 | variable = array.map do |value|
241 | value
242 | end
243 |
244 | # better
245 |
246 | variable = condition_value
247 |
248 | def condition_value(*args)
249 | if true
250 | end
251 | end
252 |
253 | variable = values_from_array(array)
254 |
255 | def values_from_array(array)
256 | array.map do |value|
257 | value
258 | end
259 | end
260 |
261 | ```
262 |
263 | *
264 | We're preferring a ruby style for methods indentations, not rails. You can check it [here](https://github.com/rubocop-hq/ruby-style-guide#indent-public-private-protected).
265 | [[link](#style-method-indentations)]
266 |
267 | ```ruby
268 | # bad
269 | class A
270 | def test
271 | puts "hello"
272 | puts "world"
273 | end
274 | end
275 |
276 | # bad
277 | class A
278 | def test
279 | puts "hello"
280 | puts "world"
281 | end
282 |
283 | protected
284 |
285 | def foo
286 | end
287 |
288 | private
289 |
290 | def bar
291 | end
292 | end
293 |
294 | # good
295 | class A
296 | def test
297 | puts "hello"
298 | puts "world"
299 | end
300 | end
301 |
302 | # good
303 | class A
304 | def test
305 | puts "hello"
306 | puts "world"
307 | end
308 |
309 | protected
310 |
311 | def foo
312 | end
313 |
314 | private
315 |
316 | def bar
317 | end
318 | end
319 | ```
320 |
321 | *
322 | For hash literals not to add spaces after `{` or before `}`. We want to have the advantage of adding visual difference between block and hash literals.
323 | [[link](#style-hash-spaces)]
324 |
325 | ```ruby
326 | # bad
327 | h = { a: 1, b: 2 }
328 | Array.new(3) {|i| i + 1}
329 |
330 | # good
331 | h = {a: 1, b: 2}
332 | Array.new(3) { |i| i + 1 }
333 | ```
334 |
335 | *
336 | Use `error` as a variable name on processing exceptions.
337 | [[link](#style-rescued-variable-name)]
338 |
339 | ```ruby
340 | # bad
341 | begin
342 | # do something
343 | rescue MyException => e
344 | # do something
345 | end
346 |
347 | # good
348 | begin
349 | # do something
350 | rescue MyException => error
351 | # do something
352 | end
353 | ```
354 |
355 |
356 | *
357 | Write empty methods in an expanded way.
358 | [[link](#style-empty-method)]
359 |
360 | ```ruby
361 | # bad
362 | def foo(bar); end
363 |
364 | def self.foo(bar); end
365 |
366 | # good
367 | def foo(bar)
368 | end
369 |
370 | def self.foo(bar)
371 | end
372 | ```
373 |
374 | *
375 | Use leading underscores in cached instance variable name.
376 | [[link](#style-cached-instance-variable-name)]
377 |
378 | ```ruby
379 | # bad
380 | def foo
381 | @something ||= calculate_expensive_thing
382 | end
383 |
384 | # bad
385 | def foo
386 | @foo ||= calculate_expensive_thing
387 | end
388 |
389 | # good
390 | def foo
391 | @_foo ||= calculate_expensive_thing
392 | end
393 | ```
394 |
395 | *
396 | Requires a comma after the last argument, but only for parenthesized method calls where each argument is on its own line.
397 | [[link](#style-trailing-comma-in-arguments)]
398 |
399 | ```ruby
400 | # bad
401 | method(1, 2,)
402 |
403 | # good
404 | method(1, 2)
405 |
406 | # bad
407 | method(
408 | 1, 2,
409 | 3,
410 | )
411 |
412 | # good
413 | method(
414 | 1, 2,
415 | 3
416 | )
417 |
418 | # bad
419 | method(
420 | 1, 2, 3,
421 | )
422 |
423 | # good
424 | method(
425 | 1, 2, 3
426 | )
427 |
428 | # good
429 | method(
430 | 1,
431 | 2,
432 | )
433 | ```
434 |
435 | *
436 | Requires a comma after last item in an array, but only when each item is on its own line.
437 | [[link](#style-trailing-comma-in-array-literals)]
438 |
439 | ```ruby
440 | # bad
441 | a = [1, 2,]
442 |
443 | # good
444 | a = [1, 2]
445 |
446 | # bad
447 | a = [
448 | 1, 2,
449 | 3,
450 | ]
451 |
452 | # good
453 | a = [
454 | 1, 2,
455 | 3
456 | ]
457 |
458 | # bad
459 | a = [
460 | 1, 2, 3,
461 | ]
462 |
463 | # good
464 | a = [
465 | 1, 2, 3
466 | ]
467 |
468 | # good
469 | a = [
470 | 1,
471 | 2,
472 | ]
473 | ```
474 |
475 | *
476 | Requires a comma after the last item in a hash.
477 | [[link](#style-trailing-comma-in-hash-literal)]
478 |
479 | ```ruby
480 | # bad
481 | a = { foo: 1, bar: 2, }
482 |
483 | # good
484 | a = { foo: 1, bar: 2 }
485 |
486 | # bad
487 | a = {
488 | foo: 1, bar: 2,
489 | qux: 3,
490 | }
491 |
492 | # good
493 | a = {
494 | foo: 1, bar: 2,
495 | qux: 3
496 | }
497 |
498 | # bad
499 | a = {
500 | foo: 1, bar: 2, qux: 3,
501 | }
502 |
503 | # good
504 | a = {
505 | foo: 1, bar: 2, qux: 3
506 | }
507 |
508 | # good
509 | a = {
510 | foo: 1,
511 | bar: 2,
512 | }
513 | ```
514 |
515 | *
516 | There are not any required rules for `frozen_string_literal` magic url.
517 | Set up [this cop](https://rubocop.readthedocs.io/en/latest/cops_style/#stylefrozenstringliteralcomment) depends on the project.
518 | So set up it on the local rubocop config manually.
519 | [[link](#style-magic-link)]
520 |
--------------------------------------------------------------------------------
/doc/STYLE_GUIDE_GRAPHQL.md:
--------------------------------------------------------------------------------
1 | # GraphQL Style Guide
2 |
3 | This style is based on the rules from [RuboCop::GraphQL](https://github.com/DmitryTsepelev/rubocop-graphql) gem with a few differences.
4 |
5 | ## Table of contents
6 |
7 | * [Style](#Style)
8 |
9 | ## Style
10 |
11 | *
12 | Each argument should have a description.
13 | [[link](#graphql-argument-description)]
14 |
15 | ```ruby
16 | # bad
17 | class BanUser < BaseMutation
18 | argument :uuid, ID, required: true
19 | end
20 |
21 | # good
22 | class BanUser < BaseMutation
23 | argument :uuid, ID, required: true, description: "UUID of the user to ban"
24 | end
25 | ```
26 |
27 | *
28 | All argument names should be snake_case.
29 | [[link](#graphql-argument-name)]
30 |
31 | ```ruby
32 | # bad
33 | class BanUser < BaseMutation
34 | argument :userId, ID, required: true
35 | end
36 |
37 | # good
38 | class BanUser < BaseMutation
39 | argument :user_id, ID, required: true
40 | end
41 | ```
42 |
43 | *
44 | Avoid duplicate argument definitions.
45 | [[link](#graphql-argument-uniqueness)]
46 |
47 | ```ruby
48 | # bad
49 | class BanUser < BaseMutation
50 | argument :user_id, ID, required: true
51 | argument :user_id, ID, required: true
52 | end
53 |
54 | # good
55 | class BanUser < BaseMutation
56 | argument :user_id, ID, required: true
57 | end
58 | ```
59 |
60 | *
61 | All field definitions should be grouped together.
62 | [[link](#graphql-field-definitions)]
63 |
64 | ```ruby
65 | # bad
66 | class UserType < BaseType
67 | field :first_name, String, null: true
68 |
69 | def first_name
70 | object.contact_data.first_name
71 | end
72 |
73 | field :last_name, String, null: true
74 |
75 | def last_name
76 | object.contact_data.last_name
77 | end
78 | end
79 |
80 | # good
81 | class UserType < BaseType
82 | field :first_name, String, null: true
83 | field :last_name, String, null: true
84 |
85 | def first_name
86 | object.contact_data.first_name
87 | end
88 |
89 | def last_name
90 | object.contact_data.last_name
91 | end
92 | end
93 | ```
94 |
95 | *
96 | Each field should have a description.
97 | [[link](#graphql-field-description)]
98 |
99 | ```ruby
100 | # bad
101 | class UserType < BaseType
102 | field :name, String, null: true
103 | end
104 |
105 | # good
106 | class UserType < BaseType
107 | field :name, String, "Name of the user", null: true
108 | end
109 | ```
110 |
111 | *
112 | Avoid unnecessary resolver methods in cases when :hash_key option can be used.
113 | [[link](#graphql-field-hash-key)]
114 |
115 | ```ruby
116 | # bad
117 | class Types::UserType < Types::BaseObject
118 | field :phone, String, null: true
119 |
120 | def phone
121 | object[:home_phone]
122 | end
123 | end
124 |
125 | # good
126 | class Types::UserType < Types::BaseObject
127 | field :phone, String, null: true, hash_key: :home_phone
128 | end
129 | ```
130 |
131 | *
132 | Avoid unnecessary resolver methods in cases when :method option can be used.
133 | [[link](#graphql-field-mathod)]
134 |
135 | ```ruby
136 | # bad
137 | class Types::UserType < Types::BaseObject
138 | field :phone, String, null: true
139 |
140 | def phone
141 | object.home_phone
142 | end
143 | end
144 |
145 | # good
146 | class Types::UserType < Types::BaseObject
147 | field :phone, String, null: true, method: :home_phone
148 | end
149 | ```
150 |
151 | *
152 | All field names should be snake_case.
153 | [[link](#graphql-field-name)]
154 |
155 | ```ruby
156 | # bad
157 | class UserType < BaseType
158 | field :firstName, String, null: true
159 | end
160 |
161 | # good
162 | class UserType < BaseType
163 | field :first_name, String, null: true
164 | end
165 | ```
166 |
167 | *
168 | Avoid duplicate field definitions.
169 | [[link](#graphql-field-uniqueness)]
170 |
171 | ```ruby
172 | # bad
173 | class UserType < BaseType
174 | field :name, String, null: true
175 | field :phone, String, null: true
176 | field :phone, String, null: true do
177 | argument :something, String, required: false
178 | end
179 | end
180 |
181 | # good
182 | class UserType < BaseType
183 | field :name, String, null: true
184 | field :phone, String, null: true do
185 | argument :something, String, required: false
186 | end
187 | end
188 | ```
189 |
190 | *
191 | Types and mutations should have graphql_name configured only if it's different from the default name.
192 | [[link](#graphql-graphql-name)]
193 |
194 | ```ruby
195 | # bad
196 | class UserType < BaseType
197 | graphql_name 'User'
198 | end
199 |
200 | # good
201 | class UserType < BaseType
202 | graphql_name 'Viewer'
203 | end
204 | ```
205 |
206 | *
207 | Use max_complexity configuration in schema files.
208 | [[link](#graphql-max-complexity-schema)]
209 |
210 | ```ruby
211 | # good
212 | class AppSchema < BaseSchema
213 | max_complexity 42
214 | end
215 | ```
216 |
217 | *
218 | Use max_depth configuration in schema files.
219 | [[link](#graphql-max-depth-schema)]
220 |
221 | ```ruby
222 | # good
223 | class AppSchema < BaseSchema
224 | max_depth 42
225 | end
226 | ```
227 |
228 | *
229 | Fields with multiple definitions should be grouped together.
230 | [[link](#graphql-multiple-field-definitions)]
231 |
232 | ```ruby
233 | # bad
234 | class UserType < BaseType
235 | field :first_name, String, null: true
236 |
237 | def first_name
238 | object.contact_data.first_name
239 | end
240 | field :first_name, Name, null: true
241 | end
242 |
243 | # good
244 | class UserType < BaseType
245 | field :first_name, String, null: true
246 | field :first_name, Name, null: true
247 |
248 | def first_name
249 | object.contact_data.first_name
250 | end
251 | end
252 | ```
253 |
254 | *
255 | Types that implement Node interface should have `.authorized?` check. Such types can be fetched by ID and therefore should have type level check to avoid accidental information exposure.
256 | If `.authorized?` is defined in a parent class, you can add parent to the "SafeBaseClasses" to avoid offenses in children.
257 | This cop also checks the `can_can_action` or `pundit_role` methods that can be used as part of the Ruby GraphQL Pro.
258 | [[link](#graphql-not-authorized-node-type)]
259 |
260 | ```ruby
261 | # bad
262 | class UserType < BaseType
263 | implements GraphQL::Types::Relay::Node
264 |
265 | field :uuid, ID, null: false
266 | end
267 |
268 | # good
269 | class UserType < BaseType
270 | implements GraphQL::Types::Relay::Node
271 |
272 | field :uuid, ID, null: false
273 |
274 | def self.authorized?(object, context)
275 | super && object.owner == context[:viewer]
276 | end
277 | end
278 |
279 | # good
280 | class UserType < BaseType
281 | implements GraphQL::Types::Relay::Node
282 |
283 | pundit_role :staff
284 |
285 | field :uuid, ID, null: false
286 | end
287 |
288 | # good
289 | class UserType < BaseType
290 | implements GraphQL::Types::Relay::Node
291 |
292 | can_can_action :staff
293 |
294 | field :uuid, ID, null: false
295 | end
296 | ```
297 |
298 | *
299 | All types (objects, inputs, interfaces, scalars, unions, mutations, subscriptions, and resolvers) should have a description.
300 | [[link](#graphql-object-description)]
301 |
302 | ```ruby
303 | # bad
304 | class Types::UserType < Types::BaseObject
305 | ...
306 | end
307 |
308 | # good
309 | class Types::UserType < Types::BaseObject
310 | description "Represents application user"
311 | ...
312 | end
313 | ```
314 |
315 | *
316 | Arguments should be alphabetically sorted within groups.
317 | [[link](#graphql-ordered-arguments)]
318 |
319 | ```ruby
320 | # bad
321 | class UpdateProfile < BaseMutation
322 | argument :uuid, ID, required: true
323 | argument :email, String, required: false
324 | argument :name, String, required: false
325 | end
326 |
327 | # good
328 | class UpdateProfile < BaseMutation
329 | argument :email, String, required: false
330 | argument :name, String, required: false
331 | end
332 |
333 | # good
334 | class UpdateProfile < BaseMutation
335 | argument :uuid, ID, required: true
336 |
337 | argument :email, String, required: false
338 | argument :name, String, required: false
339 | end
340 | ```
341 |
342 | *
343 | Fields should be alphabetically sorted within groups.
344 | [[link](#graphql-ordered-fields)]
345 |
346 | ```ruby
347 | # bad
348 | class UpdateProfile < BaseMutation
349 | field :phone, String, null: true
350 | field :name, String, null: true
351 | end
352 |
353 | # good
354 | class UpdateProfile < BaseMutation
355 | field :name, String, null: true
356 | field :phone, String, null: true
357 | end
358 |
359 | # good
360 | class UpdateProfile < BaseMutation
361 | field :phone, String, null: true
362 |
363 | field :name, String, null: true
364 | end
365 | ```
366 |
367 | *
368 | The length of a resolver method should not exceed 10 lines.
369 | [[link](#graphql-resolver-method-length)]
370 |
371 | *
372 | Avoid using :camelize option for arguments where it is unnecessary.
373 | [[link](#graphql-unnecessary-argument-camelize)]
374 |
375 | ```ruby
376 | # bad
377 | class UserType < BaseType
378 | argument :filter, String, required: false, camelize: false
379 | end
380 |
381 | # good
382 | class UserType < BaseType
383 | argument :filter, String, required: false
384 | end
385 |
386 | # good
387 | class UserType < BaseType
388 | argument :email_filter, String, required: false, camelize: true
389 | end
390 | ```
391 |
392 | *
393 | Avoid defining an unnecessary alias, method, or resolver_method.
394 | [[link](#graphql-unnecessary-field-alias)]
395 |
396 | ```ruby
397 | # bad
398 | field :name, String, "Name of the user", null: true, alias: :name
399 | field :name, String, "Name of the user", null: true, method: :name
400 | field :name, String, "Name of the user", null: true, resolver_method: :name
401 | field :name, String, "Name of the user", null: true, hash_key: :name
402 |
403 | # good
404 | field :name, String, "Name of the user", null: true, alias: :real_name
405 | field :name, String, "Name of the user", null: true, method: :real_name
406 | field :name, String, "Name of the user", null: true, resolver_method: :real_name
407 | field :name, String, "Name of the user", null: true, hash_key: :real_name
408 | ```
409 |
410 | *
411 | Avoid using :camelize option for fields where it is unnecessary.
412 | [[link](#graphql-unnecessary-field-camelize)]
413 |
414 | ```ruby
415 | # bad
416 | class UserType < BaseType
417 | field :name, "Name of the user", String, null: true, camelize: true
418 | end
419 |
420 | # good
421 | class UserType < BaseType
422 | field :name, String, "Name of the user", null: true
423 | end
424 |
425 | # good
426 | class UserType < BaseType
427 | field :first_name, "Name of the user", String, null: true, camelize: true
428 | end
429 | ```
430 |
431 | *
432 | Arguments should either be listed explicitly or **rest should be in the resolve signature (and similar methods, such as #authorized?).
433 | [[link](#graphql-unused-argument)]
434 |
435 | ```ruby
436 | # bad
437 | class SomeResolver < Resolvers::Base
438 | type SomeType, null: false
439 |
440 | argument :arg1, String, required: true
441 | argument :arg2, String, required: true
442 |
443 | def authorized?; end
444 | def resolve(arg1:); end
445 | end
446 |
447 | # bad
448 | class SomeResolver < Resolvers::Base
449 | type SomeType, null: false
450 |
451 | argument :arg1, String, required: true
452 | argument :arg2, String, required: true
453 |
454 | def resolve; end
455 | end
456 |
457 | # good
458 | class SomeResolver < Resolvers::Base
459 | argument :arg1, String, required: true
460 | argument :user_id, String, required: true, loads: Types::UserType
461 | argument :post_id, String, loads: Types::PostType, as: :article
462 | argument :comment_ids, String, loads: Types::CommentType
463 |
464 | def authorized?(arg1:, user:, article:, comments:); end
465 | def resolve(arg1:, user:, article:, comments:); end
466 | end
467 |
468 | # good
469 | class SomeResolver < Resolvers::Base
470 | argument :arg1, String, required: true
471 | argument :user_id, String, required: true, loads: Types::UserType
472 | argument :comment_ids, String, loads: Types::CommentType
473 |
474 | def resolve(arg1:, **rest); end
475 | end
476 |
477 | # good
478 | class SomeResolver < Resolvers::Base
479 | type SomeType, null: false
480 |
481 | argument :arg1, String, required: true
482 | argument :arg2, String, required: true
483 |
484 | def resolve(args); end
485 | end
486 | ```
487 |
--------------------------------------------------------------------------------
/doc/STYLE_GUIDE_RAILS.md:
--------------------------------------------------------------------------------
1 | # Rails Style Guide
2 |
3 | This style is based on rules from [Ruby Style Guide](docs/STYLE_GUIDE.md). Also, we enforce rules from [community Rails Style Guide][1].
4 |
5 | This is a small list of differences which we have when compared with community and our Ruby style guides:
6 |
7 | ## Table of contents
8 |
9 | * [Style](#Style)
10 |
11 | ## Style
12 |
13 | *
14 | Documentation is requeried for all files except `app` directory.
15 | [[link](#documentation)]
16 |
17 | *
18 | Prefer to use nested style of children definitions at classes and modules.
19 | [[link](#nested-style-and-modules)]
20 |
21 | ```ruby
22 | # bad
23 | class Api::V1::UsersController
24 | end
25 |
26 | # good
27 | module Api
28 | module V1
29 | class UsersController
30 | end
31 | end
32 | end
33 | ```
34 |
35 | [1]: https://github.com/rubocop-hq/rails-style-guide
36 |
--------------------------------------------------------------------------------
/doc/STYLE_GUIDE_RSPEC.md:
--------------------------------------------------------------------------------
1 | # Rspec Style Guide
2 |
3 | This style guide recommends best practices for writing a clear Rspec tests and enjoy this process.
4 |
5 | *
6 | We're happy to use [better spec rules](http://www.betterspecs.org/) for improving our tests.
7 | [[link](#rspec-betterrspec)]
8 |
9 | *
10 | We're not limiting a length of rspec files.
11 | [[link](#rspec-file-length)]
12 |
13 | *
14 | Nested context is a nice approach for organizing your code and tests structure.
15 | So there are not any limits for deep or nested groups.
16 | [[link](#rspec-nested-groups)]
17 |
18 | *
19 | We're not limiting a number of `let` blocks in describe and context blocks.
20 | [[link](#rspec-let-count)]
21 |
22 | *
23 | Each subject should be named, and we should not use `subject` in our test cases.
24 | Prefer to use `is_expected` that `expect(subject_name)` for small tests.
25 | [[link](#rspec-subject)]
26 |
27 | ```ruby
28 | # bad
29 | subject { service.call }
30 |
31 | it "test" do
32 | expect(subject).to eq value
33 | end
34 |
35 | # ok
36 | subject(:service_call) { service.call }
37 |
38 | it "test" do
39 | expect(service_call).to eq value
40 | end
41 |
42 | # better
43 | subject { service.call }
44 |
45 | it "test" do
46 | is_expected.to eq value
47 | end
48 | ```
49 |
50 | *
51 | When describing a context, start its description with "when", "for", with" or "without".
52 | [[link](#rspec-context-wording)]
53 |
54 | ```ruby
55 | # bad
56 | context "the display name not present" do
57 | # ...
58 | end
59 |
60 | # good
61 | context "when the display name is not present" do
62 | # ...
63 | end
64 | ```
65 |
66 | *
67 | A long example is usually more difficult to understand. Consider extracting out some behavior, e.g. with a `let` block, or a helper method.
68 |
69 | [[link](#rspec-example-length)]
70 |
71 | ```ruby
72 | # bad
73 | it 'creates correct deal config object' do
74 | expect(ZohoUtil::DealConfig).to receive(:new)
75 | .with(
76 | deal_name: translated_deal_name,
77 | stage_uid: zoho_post.stage_uid,
78 | change_existing_stage: zoho_post.change_existing_stage,
79 | note_title: translated_note_title,
80 | note: translated_note
81 | )
82 |
83 | execute_action
84 | end
85 |
86 | # good
87 | let(:service_arguments) do
88 | {
89 | deal_name: translated_deal_name,
90 | stage_uid: zoho_post.stage_uid,
91 | change_existing_stage: zoho_post.change_existing_stage,
92 | note_title: translated_note_title,
93 | note: translated_note
94 | }
95 | end
96 |
97 | it 'creates correct deal config object' do
98 | expect(ZohoUtil::DealConfig).to receive(:new).with(**service_arguments)
99 | execute_action
100 | end
101 | ```
102 |
103 | *
104 | Prefer using blocks for change matcher than method calls.
105 | [[link](#rspec-expect-change)]
106 |
107 | ```ruby
108 | # bad
109 | expect { run }.to change(Foo, :bar)
110 |
111 | # good
112 | expect { run }.to change { Foo.bar }
113 | ```
114 |
115 | *
116 | Check spies messages post-factum (after calling some methods).
117 | [[link](#rspec-message-spies)]
118 |
119 | ```ruby
120 | # bad
121 | expect(foo).to receive(:bar)
122 | foo.bar
123 |
124 | # good
125 | foo.bar
126 | expect(foo).to have_received(:bar)
127 | ```
128 |
129 | *
130 | Prefer using `expect` instead of `should` matchers.
131 | [[link](#rspec-prefer-expect)]
132 |
133 | ```ruby
134 | # bad
135 | calculator.compute(line_item).should == 5
136 |
137 | # good
138 | expect(calculator.compute(line_item)).to eq(5)
139 | ```
140 |
141 | **Note:** this is a Part of Rspec configuration. Read more [by link](https://github.com/rubocop-hq/rubocop-rspec#enforcing-should-vs-expect-syntax).
142 |
143 | *
144 | Not to use `Rspec.describe` in your test and just write `describe` instead.
145 | [[link](#rspec-top-rspec)]
146 |
147 | ```ruby
148 | # bad
149 | RSpec.describe MyClass do
150 | # ...
151 | end
152 |
153 | # good
154 | describe MyClass do
155 | # ...
156 | end
157 | ```
158 |
159 | **Note:** this is a Part of Rspec configuration. Read more [by link](https://github.com/rubocop-hq/rubocop-rspec#enforcing-an-explicit-rspec-receiver-for-top-level-methods-disabling-monkey-patching).
160 |
161 | *
162 | We allow using let! in your test, but suggest not to use it for setting up testing data.
163 | [[link](#rspec-let-setup)]
164 |
165 | ```ruby
166 | # ok
167 | let!(:my_widget) { create(:widget) }
168 |
169 | it "counts widgets" do
170 | expect(Widget.count).to eq(1)
171 | end
172 |
173 | # better
174 | before do
175 | create(:widget)
176 | end
177 |
178 | it "counts widgets" do
179 | expect(Widget.count).to eq(1)
180 | end
181 |
182 | # good
183 | let!(:my_widget) { create(:widget) }
184 |
185 | it "returns the last widget" do
186 | expect(Widget.last).to eq my_widget
187 | end
188 | ```
189 |
190 | *
191 | Prefer using `before` instead of `setup`.
192 | [[link](#rspec-prefer-before)]
193 |
194 | ```ruby
195 | # bad
196 | setup do
197 | allow(post).to receive(:publish!)
198 | end
199 |
200 | # good
201 | before do
202 | allow(post).to receive(:publish!)
203 | end
204 | ```
205 |
--------------------------------------------------------------------------------
/lib/datarockets_style.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rubocop"
4 | require "datarockets_style/formatter/todo_list_formatter"
5 |
6 | require "datarockets_style/version"
7 |
8 | require "datarockets_style/cop/layout/array_alignment_extended"
9 | require "datarockets_style/cop/style/nested_interpolation"
10 | require "datarockets_style/cop/rspec/prefer_before_over_setup"
11 |
12 | # Top level module for datarockets-style
13 | module DatarocketsStyle
14 | # Datarickors sharable config
15 | end
16 |
--------------------------------------------------------------------------------
/lib/datarockets_style/cop/layout/array_alignment_extended.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DatarocketsStyle
4 | module Cop
5 | module Layout
6 | # Here we check if the elements of a multi-line array literal are
7 | # aligned.
8 | #
9 | # @example EnforcedStyle: with_first_argument (default)
10 | # # good
11 | #
12 | # array = [1, 2, 3,
13 | # 4, 5, 6]
14 | # array = ['run',
15 | # 'forrest',
16 | # 'run']
17 | #
18 | # # bad
19 | #
20 | # array = [1, 2, 3,
21 | # 4, 5, 6]
22 | # array = ['run',
23 | # 'forrest',
24 | # 'run']
25 | #
26 | # @example EnforcedStyle: with_fixed_indentation
27 | # # good
28 | #
29 | # array = [1, 2, 3,
30 | # 4, 5, 6]
31 | #
32 | # # bad
33 | #
34 | # array = [1, 2, 3,
35 | # 4, 5, 6]
36 | class ArrayAlignmentExtended < RuboCop::Cop::Base
37 | include RuboCop::Cop::Alignment
38 | extend RuboCop::Cop::AutoCorrector
39 |
40 | ALIGN_PARAMS_MSG = "Align the elements of an array literal if they span more than one line."
41 |
42 | FIXED_INDENT_MSG = "Use one level of indentation for elements " \
43 | "following the first line of a multi-line array."
44 |
45 | def on_array(node)
46 | return if node.children.size < 2
47 |
48 | check_alignment(node.children, base_column(node, node.children))
49 | end
50 |
51 | def autocorrect(corrector, node)
52 | RuboCop::Cop::AlignmentCorrector.correct(corrector, processed_source, node, column_delta)
53 | end
54 |
55 | private
56 |
57 | def message(_node)
58 | fixed_indentation? ? FIXED_INDENT_MSG : ALIGN_PARAMS_MSG
59 | end
60 |
61 | def fixed_indentation?
62 | cop_config["EnforcedStyle"] == "with_fixed_indentation"
63 | end
64 |
65 | def base_column(node, args)
66 | fixed_indentation? ? line_indentation(node) : display_column(args.first.source_range)
67 | end
68 |
69 | def line_indentation(node)
70 | lineno = target_method_lineno(node)
71 | line = node.source_range.source_buffer.source_line(lineno)
72 | line_indentation = /\S.*/.match(line).begin(0)
73 | line_indentation + configured_indentation_width
74 | end
75 |
76 | def target_method_lineno(node)
77 | node.loc.line
78 | end
79 | end
80 | end
81 | end
82 | end
83 |
--------------------------------------------------------------------------------
/lib/datarockets_style/cop/rspec/prefer_before_over_setup.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DatarocketsStyle
4 | module Cop
5 | module RSpec
6 | # Checks that tests use `before` instead of RoR unit-test `setup` method (part of `rspec-rails` gem)
7 | #
8 | # bad
9 | #
10 | # setup do
11 | # allow(post).to receive(:publish!)
12 | # end
13 | #
14 | # good
15 | #
16 | # before do
17 | # allow(post).to receive(:publish!)
18 | # end
19 | class PreferBeforeOverSetup < RuboCop::Cop::Cop
20 | MSG = "Use `before` instead of `setup`."
21 |
22 | def_node_matcher :setup_call?, <<-PATTERN
23 | (block
24 | (send _ :setup)
25 | (args) _)
26 | PATTERN
27 |
28 | def on_block(node)
29 | return unless setup_call?(node)
30 |
31 | add_offense(node)
32 | end
33 |
34 | def autocorrect(node)
35 | lambda do |corrector|
36 | block_internals = node.source.split(/ /)
37 | corrector.replace node.loc.expression, ["before", *block_internals[1..]].join(" ")
38 | end
39 | end
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/datarockets_style/cop/style/nested_interpolation.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DatarocketsStyle
4 | module Cop
5 | module Style
6 | # This cop checks nested interpolations
7 | #
8 | # @example
9 | #
10 | # # bad
11 | # "Hello, #{user.blank? ? 'guest' : "dear #{user.name}"}"
12 | #
13 | # # good
14 | # user_name = user.blank? ? 'guest' : "dear #{user.name}"
15 | # "Hello, #{user_name}"
16 | class NestedInterpolation < RuboCop::Cop::Cop
17 | include RuboCop::Cop::Interpolation
18 |
19 | MSG = "Redundant nested interpolation."
20 |
21 | def on_interpolation(node)
22 | node.each_descendant(:dstr) do |descendant_node|
23 | detect_double_interpolation(descendant_node)
24 | end
25 | end
26 |
27 | private
28 |
29 | def detect_double_interpolation(node)
30 | node.each_child_node(:begin) do |begin_node|
31 | add_offense(begin_node)
32 | end
33 | end
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/lib/datarockets_style/formatter/todo_list_formatter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "pathname"
4 | require_relative "todo_list_formatter/report_summary"
5 |
6 | # This formatter works like default formattter (display dots for files with no offenses and
7 | # letters for files with problems in the them).
8 | #
9 | # In the end, it shows report with sorted cops and files which can be added to rubocop config.
10 | #
11 | # Here's the format:
12 | #
13 | # Inspecting 3 files
14 | # .CC
15 | # 3 files inspected, 1005001 offenses detected
16 | #
17 | # LineLength
18 | # Exclude:
19 | # - "really/bad/file.rb" # 100500
20 | # - "almost/ok.rb" # 1
21 | class TodoListFormatter < RuboCop::Formatter::ProgressFormatter
22 | attr_reader :offense_list
23 |
24 | FileOffence = Struct.new(:file_path, :cop_name)
25 |
26 | def started(target_files)
27 | super
28 | @offense_list = []
29 | end
30 |
31 | def file_finished(file, offenses)
32 | count_stats(offenses)
33 | report_file_as_mark(offenses)
34 |
35 | return if offenses.empty?
36 |
37 | path = Pathname.new(file).relative_path_from(Pathname.new(Dir.pwd))
38 |
39 | offenses.reject(&:corrected?).each do |offense|
40 | offense_list << FileOffence.new(path, offense.cop_name)
41 | end
42 | end
43 |
44 | def finished(inspected_files)
45 | report_summary(inspected_files.length,
46 | @total_offense_count,
47 | @total_correction_count,
48 | @total_correctable_count)
49 | output.puts
50 |
51 | DatarocketsStyle::Formatter::TodoListFormatter::ReportSummary.new(offense_list).call(output)
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/datarockets_style/formatter/todo_list_formatter/report_summary.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DatarocketsStyle
4 | module Formatter
5 | module TodoListFormatter
6 | # Get file of pairs: file path and cop name - and prepare report for ToDo list formatter.
7 | #
8 | # Example of result:
9 | #
10 | # LineLength
11 | # Exclude:
12 | # - "really/bad/file.rb" # 100500
13 | # - "almost/ok.rb" # 1
14 | class ReportSummary
15 | attr_reader :offense_list
16 |
17 | FileGroup = Struct.new(:file, :offenses_count) do
18 | def print(output)
19 | output.puts " - '#{file}' # #{offenses_count}"
20 | end
21 | end
22 |
23 | OffenseGroup = Struct.new(:cop_name, :offenses) do
24 | def file_groups
25 | @_file_groups ||= offenses.group_by(&:file_path).map do |file, offenses|
26 | FileGroup.new(file, offenses.length)
27 | end
28 | end
29 |
30 | def print(output)
31 | output.puts("#{cop_name}:")
32 | output.puts(" Exclude:")
33 | file_groups.sort_by(&:file).each do |file_group|
34 | file_group.print(output)
35 | end
36 | output.puts
37 | end
38 | end
39 |
40 | def initialize(offense_list)
41 | @offense_list = offense_list
42 | end
43 |
44 | def call(output)
45 | offense_groups.sort_by(&:cop_name).each { |group| group.print(output) }
46 | end
47 |
48 | private
49 |
50 | def offense_groups
51 | @_offense_groups ||= offense_list.group_by(&:cop_name)
52 | .map { |cop_name, offenses| OffenseGroup.new(cop_name, offenses) }
53 | end
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/lib/datarockets_style/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DatarocketsStyle
4 | VERSION = "1.6.0"
5 | end
6 |
--------------------------------------------------------------------------------
/manual/cops_layout.md:
--------------------------------------------------------------------------------
1 | # Layout
2 |
3 | ## Layout/ArrayAlignmentExtended
4 |
5 | Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
6 | --- | --- | --- | --- | ---
7 | Enabled | Yes | Yes | 0.7.0 | -
8 |
9 | Here we check if the elements of a multi-line array literal are
10 | aligned.
11 |
12 | ### Examples
13 |
14 | #### EnforcedStyle: with_fixed_indentation (default)
15 |
16 | ```ruby
17 | # good
18 |
19 | array = [1, 2, 3,
20 | 4, 5, 6]
21 |
22 | # bad
23 |
24 | array = [1, 2, 3,
25 | 4, 5, 6]
26 | ```
27 |
28 | #### EnforcedStyle: with_first_argument
29 |
30 | ```ruby
31 | # good
32 |
33 | array = [1, 2, 3,
34 | 4, 5, 6]
35 | array = ['run',
36 | 'forrest',
37 | 'run']
38 |
39 | # bad
40 |
41 | array = [1, 2, 3,
42 | 4, 5, 6]
43 | array = ['run',
44 | 'forrest',
45 | 'run']
46 | ```
47 |
48 | ### Configurable attributes
49 |
50 | Name | Default value | Configurable values
51 | --- | --- | ---
52 | EnforcedStyle | `with_first_parameter` | `with_first_parameter`, `with_fixed_indentation`
53 | IndentationWidth | `` | Integer
54 |
55 | # RSpec
56 |
57 | ## RSpec/PreferBeforeOverSetup
58 |
59 | Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
60 | --- | --- | --- | --- | ---
61 | Enabled | Yes | Yes | 1.2.0 | -
62 |
63 | Checks that tests use `before` instead of RoR unit-test `setup` method (part of `rspec-rails` gem)
64 |
65 | ### Example
66 |
67 | ```ruby
68 | # bad
69 | setup do
70 | allow(post).to receive(:publish!)
71 | end
72 |
73 | # good
74 | before do
75 | allow(post).to receive(:publish!)
76 | end
77 | ```
78 |
79 | # Style
80 |
81 | ## Style/NestedInterpolation
82 |
83 | Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
84 | --- | --- | --- | --- | ---
85 | Enabled | Yes | No | 0.8.0 | -
86 |
87 | This cop checks nested interpolations
88 |
89 | ### Example
90 |
91 | ```ruby
92 | # bad
93 | "Hello, #{user.blank? ? 'guest' : "dear #{user.name}"}"
94 |
95 | # good
96 | user_name = user.blank? ? 'guest' : "dear #{user.name}"
97 | "Hello, #{user_name}"
98 | ```
99 |
--------------------------------------------------------------------------------
/spec/datarockets_style/cop/layout/array_alignment_extended_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | RSpec.describe DatarocketsStyle::Cop::Layout::ArrayAlignmentExtended do
4 | subject(:cop) { described_class.new(config) }
5 |
6 | let(:config) do
7 | RuboCop::Config.new(
8 | "Layout/ArrayAlignmentExtended" => {
9 | "EnforcedStyle" => cop_enforced_style,
10 | },
11 | "Layout/IndentationWidth" => {
12 | "Width" => 2,
13 | },
14 | )
15 | end
16 |
17 | context "when aligned with first parameter" do
18 | let(:cop_enforced_style) { "with_first_parameter" }
19 |
20 | it "accepts single line array" do
21 | expect_no_offenses("array = [ a, b ]")
22 | end
23 |
24 | it "accepts several elements per line" do
25 | expect_no_offenses(<<~RUBY)
26 | array = [ a, b,
27 | c, d ]
28 | RUBY
29 | end
30 |
31 | it "accepts aligned array with fullwidth characters" do
32 | expect_no_offenses(<<~RUBY)
33 | puts 'Ruby', [ a,
34 | b ]
35 | RUBY
36 | end
37 |
38 | context "when basic usage" do
39 | let(:not_aligned_array) do
40 | <<~RUBY
41 | array = [a,
42 | b,
43 | ^ Align the elements of an array literal if they span more than one line.
44 | c,
45 | ^ Align the elements of an array literal if they span more than one line.
46 | d]
47 | ^ Align the elements of an array literal if they span more than one line.
48 | RUBY
49 | end
50 |
51 | let(:aligned_array) do
52 | <<~RUBY
53 | array = [a,
54 | b,
55 | c,
56 | d]
57 | RUBY
58 | end
59 |
60 | it "registers an offense and corrects misaligned array elements" do
61 | expect_offense(not_aligned_array)
62 |
63 | expect_correction(aligned_array)
64 | end
65 |
66 | it "accepts aligned array keys" do
67 | expect_no_offenses(aligned_array)
68 | end
69 | end
70 |
71 | context "when using nested arrays" do
72 | let(:not_aligned_arrays) do
73 | <<~RUBY
74 | [:l1,
75 | [:l2,
76 | [:l3,
77 | [:l4]]]]
78 | RUBY
79 | end
80 |
81 | it "does not auto-correct array within array with too much indentation" do
82 | expect_offense(<<~RUBY)
83 | [:l1,
84 | [:l2,
85 | ^^^^^ Align the elements of an array literal if they span more than one line.
86 | [:l3,
87 | ^^^^^ Align the elements of an array literal if they span more than one line.
88 | [:l4]]]]
89 | RUBY
90 |
91 | expect_correction(not_aligned_arrays)
92 | end
93 |
94 | it "does not auto-correct array within array with too little indentation" do
95 | expect_offense(<<~RUBY)
96 | [:l1,
97 | [:l2,
98 | ^^^^^ Align the elements of an array literal if they span more than one line.
99 | [:l3,
100 | ^^^^^ Align the elements of an array literal if they span more than one line.
101 | [:l4]]]]
102 | RUBY
103 |
104 | expect_correction(not_aligned_arrays)
105 | end
106 | end
107 |
108 | context "when arrays with heredoc strings" do
109 | let(:not_aligned_array) do
110 | <<~RUBY
111 | var = [
112 | { :type => 'something',
113 | :sql => < 'something',
119 | ^^^^^^^^^^^^^^^^^^^^^^^ Align the elements of an array literal if they span more than one line.
120 | :sql => < 'something',
133 | :sql => < 'something',
139 | :sql => < 'something',
287 | :sql => < 'something',
293 | ^^^^^^^^^^^^^^^^^^^^^^^ Use one level of indentation for elements following the first line of a multi-line array.
294 | :sql => < 'something',
307 | :sql => < 'something',
313 | :sql => <