smart_types 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/Gemfile.lock +33 -32
  4. data/README.md +161 -16
  5. data/lib/smart_core/types.rb +2 -0
  6. data/lib/smart_core/types/errors.rb +12 -0
  7. data/lib/smart_core/types/primitive.rb +49 -4
  8. data/lib/smart_core/types/primitive/caster.rb +5 -2
  9. data/lib/smart_core/types/primitive/checker.rb +5 -2
  10. data/lib/smart_core/types/primitive/factory.rb +64 -6
  11. data/lib/smart_core/types/primitive/factory/definition_context.rb +37 -11
  12. data/lib/smart_core/types/primitive/factory/runtime_type_builder.rb +53 -0
  13. data/lib/smart_core/types/primitive/invariant_control.rb +6 -3
  14. data/lib/smart_core/types/primitive/invariant_control/chain.rb +5 -2
  15. data/lib/smart_core/types/primitive/invariant_control/single.rb +5 -2
  16. data/lib/smart_core/types/primitive/mult_factory.rb +40 -6
  17. data/lib/smart_core/types/primitive/mult_factory/definition_context.rb +23 -1
  18. data/lib/smart_core/types/primitive/mult_validator.rb +8 -0
  19. data/lib/smart_core/types/primitive/nilable_factory.rb +10 -3
  20. data/lib/smart_core/types/primitive/runtime_attributes_checker.rb +77 -0
  21. data/lib/smart_core/types/primitive/sum_factory.rb +40 -6
  22. data/lib/smart_core/types/primitive/sum_factory/definition_context.rb +23 -1
  23. data/lib/smart_core/types/primitive/sum_validator.rb +18 -2
  24. data/lib/smart_core/types/primitive/undefined_caster.rb +4 -1
  25. data/lib/smart_core/types/primitive/validator.rb +16 -7
  26. data/lib/smart_core/types/protocol.rb +7 -0
  27. data/lib/smart_core/types/protocol/instance_of.rb +19 -0
  28. data/lib/smart_core/types/value/array.rb +3 -0
  29. data/lib/smart_core/types/value/big_decimal.rb +4 -1
  30. data/lib/smart_core/types/value/boolean.rb +3 -0
  31. data/lib/smart_core/types/value/class.rb +3 -0
  32. data/lib/smart_core/types/value/date.rb +3 -0
  33. data/lib/smart_core/types/value/date_time.rb +3 -0
  34. data/lib/smart_core/types/value/enumerable.rb +1 -1
  35. data/lib/smart_core/types/value/float.rb +3 -0
  36. data/lib/smart_core/types/value/hash.rb +3 -0
  37. data/lib/smart_core/types/value/integer.rb +3 -0
  38. data/lib/smart_core/types/value/module.rb +3 -0
  39. data/lib/smart_core/types/value/numeric.rb +3 -0
  40. data/lib/smart_core/types/value/proc.rb +3 -0
  41. data/lib/smart_core/types/value/set.rb +11 -3
  42. data/lib/smart_core/types/value/string.rb +3 -0
  43. data/lib/smart_core/types/value/string_io.rb +2 -0
  44. data/lib/smart_core/types/value/symbol.rb +3 -0
  45. data/lib/smart_core/types/value/text.rb +6 -4
  46. data/lib/smart_core/types/value/time.rb +3 -0
  47. data/lib/smart_core/types/value/time_based.rb +8 -5
  48. data/lib/smart_core/types/variadic.rb +7 -0
  49. data/lib/smart_core/types/variadic/tuple.rb +23 -0
  50. data/lib/smart_core/types/version.rb +2 -2
  51. data/smart_types.gemspec +3 -3
  52. metadata +15 -10
  53. data/.travis.yml +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5f0c7f2b54ceaa7fe20e85d7d280b64b8310eb5f4fa802d11052074e6b10f96
4
- data.tar.gz: 021c3c6194fb4f54246f4a44a7c548ce9da0790a66b95e0a060547e73efeaf3f
3
+ metadata.gz: fdcbf29c692c77b4968df1ad7cbc629164de818da1859fc871c776b8e94152b1
4
+ data.tar.gz: 3fe9ffe11f8d84b11a3b274a59c1d826a2d8a64eb9c289c1bf5166690d379f31
5
5
  SHA512:
6
- metadata.gz: 6e2fc86bcea2292570d2c51e9b95ead6ecc30f8251db75a61fda088c1a84bdb15cea65fdc478728869fb5e5e56b7cddb774938cae38c60e4dee70197e6c1c7f3
7
- data.tar.gz: c7b27e2f70f3f8eac851f63365b3287a2c7aeb8f7f999679daa715d5ff7de93b32bd6204ea67f6af2c2ea1e5ccd569027051674c9266c62ff7d425c55692619a
6
+ metadata.gz: d8dd2d8a3e397c02caf8a6b32347105b2f2b860c3847a8f08d5713d5e1791845aa8a598a21b3dc8be63c526e63d323349e144366836518a74409c39904140eef
7
+ data.tar.gz: 5ead029c27b2b4aae1a6b509e0e268f92cf85fc34c207f5af76b4b79cdb72a494bb61d16a5e50d979c61a4d6b161983b45bd013207ca047f4b5852601c7bd088
@@ -1,6 +1,31 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.3.0] - 2020-12-22
5
+ ### Added
6
+ - Extended **Type Definition API**: support for **runtime attributes**:
7
+ - Type checkers, type casters and type invariants now receives runtime attributes (you can omit these);
8
+ - Type definitioning extended with `runtime_attribute_checker`-checker definition (runtime attributes validator);
9
+ - Types with incorrect runtime attributes will raise `SmartCore::Types::IncorrectRuntimeAttributesError` exception;
10
+ - Types which has no support for runtime attributes will raise `SmartCore::Types::RuntimeAttributesUnsupportedError` excpetion;
11
+ - All types by default has a method alias (`()`) which does not allow runtime attributes (for example: `SmartCore::Types::Value::String` has
12
+ a runtime-based alias `SmartCore::Types::Value::String()` which does not accept any attribute
13
+ (`SmartCore::Types::Value::String('test')` will raise `SmartCore::Types::RuntimeAttributesUnsupportedError` respectively));
14
+ - Extended Internal **Type Development API**:
15
+ - all types has a reference to it's type category;
16
+ - Brand new `SmartCore::Types::Protocol` type category and new types:
17
+ - `SmartCore::Types::Protocol::InstanceOf` (runtime-based type);
18
+ - Brand new `SmartCore::Types::Variadic` type category and new types:
19
+ - `SmartCore::Types::Variadic::Tuple` (runtime-based type);
20
+ - New types of `SmartCore::Types::Value` category:
21
+ - `SmartCore::Types::Value::Set` (based on `Set` type with a support for type casting);
22
+ - Support for BasicObject values inside type checkers that can not be checked correctly via `#is_a?/#kind_of?` before;
23
+
24
+ ### Changed
25
+ - Updated development dependencies;
26
+ - Drop `Travis CI` (TODO: migrate to `Github Actions`);
27
+ - **Ruby@2.4** is no longer supported;
28
+
4
29
  ## [0.2.0] - 2020-11-21
5
30
  ### Added
6
31
  - Brand new **Type invariant API**:
@@ -1,34 +1,34 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_types (0.2.0)
5
- smart_engine (~> 0.7)
4
+ smart_types (0.3.0)
5
+ smart_engine (~> 0.10)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (6.0.3.4)
10
+ activesupport (6.1.0)
11
11
  concurrent-ruby (~> 1.0, >= 1.0.2)
12
- i18n (>= 0.7, < 2)
13
- minitest (~> 5.1)
14
- tzinfo (~> 1.1)
15
- zeitwerk (~> 2.2, >= 2.2.2)
16
- armitage-rubocop (1.3.1.1)
17
- rubocop (= 1.3.1)
18
- rubocop-performance (= 1.9.0)
19
- rubocop-rails (= 2.8.1)
12
+ i18n (>= 1.6, < 2)
13
+ minitest (>= 5.1)
14
+ tzinfo (~> 2.0)
15
+ zeitwerk (~> 2.3)
16
+ armitage-rubocop (1.6.1)
17
+ rubocop (= 1.6.1)
18
+ rubocop-performance (= 1.9.1)
19
+ rubocop-rails (= 2.9.0)
20
20
  rubocop-rake (= 0.5.1)
21
- rubocop-rspec (= 2.0.0)
21
+ rubocop-rspec (= 2.0.1)
22
22
  ast (2.4.1)
23
23
  coderay (1.1.3)
24
24
  concurrent-ruby (1.1.7)
25
25
  diff-lcs (1.4.4)
26
- docile (1.3.2)
26
+ docile (1.3.3)
27
27
  i18n (1.8.5)
28
28
  concurrent-ruby (~> 1.0)
29
29
  method_source (1.0.0)
30
30
  minitest (5.14.2)
31
- parallel (1.20.0)
31
+ parallel (1.20.1)
32
32
  parser (2.7.2.0)
33
33
  ast (~> 2.4.1)
34
34
  pry (0.13.1)
@@ -36,8 +36,8 @@ GEM
36
36
  method_source (~> 1.0)
37
37
  rack (2.2.3)
38
38
  rainbow (3.0.0)
39
- rake (13.0.1)
40
- regexp_parser (1.8.2)
39
+ rake (13.0.3)
40
+ regexp_parser (2.0.1)
41
41
  rexml (3.2.4)
42
42
  rspec (3.10.0)
43
43
  rspec-core (~> 3.10.0)
@@ -52,51 +52,52 @@ GEM
52
52
  diff-lcs (>= 1.2.0, < 2.0)
53
53
  rspec-support (~> 3.10.0)
54
54
  rspec-support (3.10.0)
55
- rubocop (1.3.1)
55
+ rubocop (1.6.1)
56
56
  parallel (~> 1.10)
57
57
  parser (>= 2.7.1.5)
58
58
  rainbow (>= 2.2.2, < 4.0)
59
- regexp_parser (>= 1.8)
59
+ regexp_parser (>= 1.8, < 3.0)
60
60
  rexml
61
- rubocop-ast (>= 1.1.1)
61
+ rubocop-ast (>= 1.2.0, < 2.0)
62
62
  ruby-progressbar (~> 1.7)
63
63
  unicode-display_width (>= 1.4.0, < 2.0)
64
- rubocop-ast (1.1.1)
64
+ rubocop-ast (1.3.0)
65
65
  parser (>= 2.7.1.5)
66
- rubocop-performance (1.9.0)
66
+ rubocop-performance (1.9.1)
67
67
  rubocop (>= 0.90.0, < 2.0)
68
68
  rubocop-ast (>= 0.4.0)
69
- rubocop-rails (2.8.1)
69
+ rubocop-rails (2.9.0)
70
70
  activesupport (>= 4.2.0)
71
71
  rack (>= 1.1)
72
- rubocop (>= 0.87.0)
72
+ rubocop (>= 0.90.0, < 2.0)
73
73
  rubocop-rake (0.5.1)
74
74
  rubocop
75
- rubocop-rspec (2.0.0)
75
+ rubocop-rspec (2.0.1)
76
76
  rubocop (~> 1.0)
77
77
  rubocop-ast (>= 1.1.0)
78
78
  ruby-progressbar (1.10.1)
79
- simplecov (0.19.1)
79
+ simplecov (0.20.0)
80
80
  docile (~> 1.1)
81
81
  simplecov-html (~> 0.11)
82
+ simplecov_json_formatter (~> 0.1)
82
83
  simplecov-html (0.12.3)
83
- smart_engine (0.8.0)
84
- thread_safe (0.3.6)
85
- tzinfo (1.2.8)
86
- thread_safe (~> 0.1)
84
+ simplecov_json_formatter (0.1.2)
85
+ smart_engine (0.10.0)
86
+ tzinfo (2.0.4)
87
+ concurrent-ruby (~> 1.0)
87
88
  unicode-display_width (1.7.0)
88
- zeitwerk (2.4.1)
89
+ zeitwerk (2.4.2)
89
90
 
90
91
  PLATFORMS
91
92
  ruby
92
93
 
93
94
  DEPENDENCIES
94
- armitage-rubocop (~> 1.3)
95
+ armitage-rubocop (~> 1.6)
95
96
  bundler (~> 2.1)
96
97
  pry (~> 0.13)
97
98
  rake (~> 13.0)
98
99
  rspec (~> 3.10)
99
- simplecov (~> 0.19)
100
+ simplecov (~> 0.20)
100
101
  smart_types!
101
102
 
102
103
  BUNDLED WITH
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # SmartCore::Types &middot; [![Gem Version](https://badge.fury.io/rb/smart_types.svg)](https://badge.fury.io/rb/smart_types) [![Build Status](https://travis-ci.org/smart-rb/smart_types.svg?branch=master)](https://travis-ci.org/smart-rb/smart_types)
1
+ # SmartCore::Types &middot; [![Gem Version](https://badge.fury.io/rb/smart_types.svg)](https://badge.fury.io/rb/smart_types)
2
2
 
3
3
  > A set of objects that acts like types (type checking and type casting) with a support for basic type algebra.
4
4
 
@@ -24,6 +24,25 @@ require 'smart_core/types'
24
24
 
25
25
  ---
26
26
 
27
+ ## Usage
28
+
29
+ - [Type interface](#type-interface)
30
+ - [Basic type algebra](#basic-type-algebra)
31
+ - [Supported types](#supported-types)
32
+ - [Nilable types](#nilable-types)
33
+ - [Custom type definition](#custom-type-definition)
34
+ - [Primitive type definition](#primitive-type-definition)
35
+ - [With type invariants](#with-type-invariants)
36
+ - [Type validation](#type-validation)
37
+ - [Type casting](#type-casting)
38
+ - [Roadmap](#roadmap)
39
+ - [Contributing](#contributing)
40
+ - [Build](#build)
41
+ - [License](#license)
42
+ - [Authors](#authors)
43
+
44
+ ---
45
+
27
46
  ## Type Interface
28
47
 
29
48
  ```ruby
@@ -37,6 +56,21 @@ type3 = type1 | type2
37
56
  type4 = type1 & type2
38
57
  ```
39
58
 
59
+ Types with runtime:
60
+
61
+ ```ruby
62
+ # get a type object with a custom runtime (instances of String or Symbol):
63
+ type = SmartCore::Types::Protocol::InstanceOf(::String, ::Symbol)
64
+ type.valid?(:test) # => true
65
+ type.valid?('test') # => true
66
+ type.valid?(123.456) # => false
67
+
68
+ # another type object with a custom runtime (tuple (String, Integer, Time)):
69
+ type = SmartCore::Types::Variadic::Tuple(::String, ::Integer, ::DateTime)
70
+ type.valid?(['test', 1, DateTime.new]) # => true
71
+ type.valid?([:test, 2]) # => false
72
+ ```
73
+
40
74
  ## Supported types
41
75
 
42
76
  - Primitives
@@ -53,6 +87,7 @@ SmartCore::Types::Value::Numeric
53
87
  SmartCore::Types::Value::BigDecimal
54
88
  SmartCore::Types::Value::Boolean
55
89
  SmartCore::Types::Value::Array
90
+ SmartCore::Types::Value::Set
56
91
  SmartCore::Types::Value::Hash
57
92
  SmartCore::Types::Value::Proc
58
93
  SmartCore::Types::Value::Class
@@ -63,6 +98,31 @@ SmartCore::Types::Value::Date
63
98
  SmartCore::Types::Value::TimeBased
64
99
  ```
65
100
 
101
+ - Protocols:
102
+
103
+ ```ruby
104
+ SmartCore::Types::Protocol::InstanceOf
105
+ ```
106
+
107
+ ```ruby
108
+ # examples (SmartCore::Types::Protocol::InstanceOf):
109
+ SmartCore::Types::Protocol::InstanceOf(::Integer) # only integer
110
+ SmartCore::Types::Protocol::InstanceOf(::String, ::Symbol) # string or symbol
111
+ SmartCore::Types::Protocol::InstanceOf(::Time, ::DateTime, ::Date) # time or datetime or date
112
+ ```
113
+
114
+ - Variadic:
115
+
116
+ ```ruby
117
+ SmartCore::Types::Variadic::Tuple
118
+ ```
119
+
120
+ ```ruby
121
+ # examples (SmartCore::Types::Variadic::Tuple):
122
+ SmartCore::Types::Variadic::Tuple(::String, ::Integer, ::Time) # array with signature [<string>, <integer>, <time>]
123
+ SmartCore::Types::Variadic::Tuple(::Symbol, ::Float) # array with signature [<symbol>, <float>]
124
+ ```
125
+
66
126
  ---
67
127
 
68
128
  ## Nilable types
@@ -107,41 +167,56 @@ Invariant checking is a special validation layer (see [#type validation](#type-v
107
167
 
108
168
  # example:
109
169
  SmartCore::Types::Value.define_type(:String) do |type|
110
- type.define_checker do |value|
170
+ type.define_checker do |value, runtime_attrs| # runtime attributes are optional
111
171
  value.is_a?(::String)
112
172
  end
113
173
 
114
- type.define_caster do |value|
174
+ type.define_caster do |value, runtime_attrs| # runtime attributes are optional
115
175
  value.to_s
116
176
  end
117
177
  end
178
+
179
+ # get a type object:
180
+ SmartCore::Types::Value::String
181
+ # --- or ---
182
+ SmartCore::Types::Value::String() # without runtime attributes
183
+ # --- or ---
184
+ SmartCore::Types::Value::String('some_attr', :another_attr) # with runtime attributes
185
+
186
+ # work with type object: see documentation below
118
187
  ```
119
188
 
120
189
  #### With type invariants
121
190
 
122
191
  ```ruby
123
192
  SmartCore::Types::Value.define_type(:String) do |type|
124
- type.define_checker do |value|
193
+ type.define_checker do |value, runtime_attrs|
125
194
  value.is_a?(::String)
126
195
  end
127
196
 
128
- type.define_caster do |value|
197
+ type.define_caster do |value, runtime_attrs|
129
198
  value.to_s
130
199
  end
131
200
 
132
201
  # NOTE:
133
202
  # invariant defined out from chain does not depends on other invariants
134
- type.invariant(:uncensored_content) do |value|
203
+ type.invariant(:uncensored_content) do |value, runtime_attrs|
135
204
  !value.include?('uncensored_word')
136
205
  end
137
206
 
138
- type.invariant(:filled) do |value|
207
+ type.invariant(:filled) do |value, runtime_attrs|
139
208
  value != ''
140
209
  end
141
210
 
142
211
  type.invariant_chain(:password) do
143
- invariant(:should_present) { |value| value != '' }
144
- invariant(:should_have_numbers) { |value| v.match?(/[0-9]+/) }
212
+ invariant(:should_present) do |value, runtime_attrs|
213
+ value != ''
214
+ end
215
+
216
+ invariant(:should_have_numbers) do |value, runtime_attrs|
217
+ v.match?(/[0-9]+/)
218
+ end
219
+
145
220
  # NOTE:
146
221
  # inside a chain each next invariant invokation
147
222
  # depends on previous successful invariant check
@@ -190,6 +265,36 @@ Validation result object interface:
190
265
  - for single invariant: `TypeName.invariant_name`;
191
266
  - `#checked_value` (the same as `#value`) - checked value :)
192
267
 
268
+ ---
269
+
270
+ Imagine that we have `String` type like this:
271
+
272
+ ```ruby
273
+ SmartCore::Types::Value.define_type(:String) do |type|
274
+ type.define_checker do |value|
275
+ value.is_a?(::String)
276
+ end
277
+
278
+ type.define_caster do |value|
279
+ value.to_s
280
+ end
281
+
282
+ type.invariant(:uncensored_content) do |value|
283
+ !value.include?('uncensored_word')
284
+ end
285
+
286
+ type.invariant(:filled) do |value|
287
+ value != ''
288
+ end
289
+
290
+ type.invariant_chain(:password) do
291
+ invariant(:should_present) { |value| value != '' }
292
+ invariant(:should_have_numbers) { |value| v.match?(/[0-9]+/) }
293
+ end
294
+ end
295
+ ```
296
+
297
+ Validation interface and usage:
193
298
 
194
299
  ```ruby
195
300
  SmartCore::Types::Value::String.valid?('test123') # => true
@@ -231,7 +336,7 @@ SmartCore::Types::Value::String.validate!('test') # => SmartCore::Types::TypeErr
231
336
 
232
337
  ## Type casting
233
338
 
234
- ```
339
+ ```ruby
235
340
  SmartCore::Types::Value::String.cast(123) # => "123"
236
341
  SmartCore::Types::Value::Float.cast('55') # => 55.0
237
342
  ```
@@ -257,6 +362,10 @@ SmartCore::Types::Value::CryptoString = SmartCore::Types::Value::NumberdString &
257
362
 
258
363
  ## Roadmap
259
364
 
365
+ - migrate to `Github Actions`;
366
+
367
+ - support for `block`-attribute in runtime attributes;
368
+
260
369
  - type configuration:
261
370
 
262
371
  ```ruby
@@ -319,8 +428,17 @@ SmartCore::Types::Value::Time.refine_caster do |value, original_caster|
319
428
  # new type caster
320
429
  end
321
430
 
322
- # .refine_invariant
323
- # .refine_invariant_chain
431
+ SmartCore::Types::Value::Time.refine_runtime_attributes_checker do |value, original_checker|
432
+ # new runtime attribute checker
433
+ end
434
+
435
+ SmartCore::Types::Value::Time.refine_invariant(:name) do |value|
436
+ # new invariant
437
+ end
438
+
439
+ SmartCore::Types::Value::Time.refine_invariant_chain(:chain_name) do
440
+ # new invariant chain
441
+ end
324
442
  ```
325
443
 
326
444
  - options for type casters:
@@ -348,18 +466,16 @@ SmartCore::Types::Value::Enumerator
348
466
  SmartCore::Types::Value::EnumeratorChain
349
467
  SmartCore::Types::Value::Range
350
468
  SmartCore::Types::Value::Rational
351
- SmartCore::Types::Value::Set
352
469
  SmartCore::Types::Value::SortedSet
353
470
  SmartCore::Types::Value::IO
354
471
  SmartCore::Types::Value::StringIO
472
+ SmartCore::Types::Value::BasicObject
355
473
  SmartCore::Types::Struct::Schema
356
474
  SmartCore::Types::Struct::JSONSchema
357
475
  SmartCore::Types::Struct::StrictArray
358
476
  SmartCore::Types::Struct::StrictHash
359
477
  SmartCore::Types::Struct::Map
360
- SmartCore::Types::Variative::Enum
361
- SmartCore::Types::Variative::Variant
362
- SmartCore::Types::Protocol::InstanceOf
478
+ SmartCore::Types::Variadic::Enum
363
479
  SmartCore::Types::Protocol::Interface
364
480
  SmartCore::Types::Protocol::Ancestors
365
481
  SmartCore::Types::Protocol::Enumerable
@@ -368,6 +484,17 @@ SmartCore::Types::Protocol::Forwardable
368
484
  SmartCore::Types::Protocol::Callable
369
485
  ```
370
486
 
487
+ - `#sum` alias for `|` and `#mult` alias for `&` (with a support for type name definition and other API);
488
+
489
+ - type category in invariant error codes:
490
+ ```ruby
491
+ # before:
492
+ 'String.password.should_contain_numbers' # `String` type from `Value` category
493
+
494
+ # after:
495
+ 'Value.String.password.should_contain_numbers' # `Value::String`
496
+ ```
497
+
371
498
  - support for type of empty non-defined type (`SmartCore::Types::Primitive::Undefined`);
372
499
  - constrained types;
373
500
  - moudle-based type system integration;
@@ -391,6 +518,24 @@ SmartCore::Types::Protocol::Callable
391
518
  - Push to the branch (`git push origin feature/my-new-feature`)
392
519
  - Create new Pull Request
393
520
 
521
+ ## Build
522
+
523
+ - run tests:
524
+
525
+ ```shell
526
+ bundle exec rake rspec
527
+ # --- or ---
528
+ bundle exec rspec
529
+ ```
530
+
531
+ - run code stye linting:
532
+
533
+ ```shell
534
+ bundle exec rake rubocop
535
+ # --- or ---
536
+ bundle exec rubocop
537
+ ```
538
+
394
539
  ## License
395
540
 
396
541
  Released under MIT License.