auxiliary_rails 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +26 -0
  3. data/.rubocop.yml +11 -2
  4. data/.rubocop_todo.yml +13 -9
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +19 -2
  7. data/CONTRIBUTING.md +0 -6
  8. data/Gemfile.lock +20 -16
  9. data/README.md +204 -3
  10. data/auxiliary_rails.gemspec +7 -5
  11. data/bin/rubocop +3 -0
  12. data/lib/auxiliary_rails.rb +5 -3
  13. data/lib/auxiliary_rails/application/command.rb +56 -0
  14. data/lib/auxiliary_rails/application/error.rb +10 -0
  15. data/lib/auxiliary_rails/application/form.rb +30 -0
  16. data/lib/auxiliary_rails/application/query.rb +78 -0
  17. data/lib/auxiliary_rails/cli.rb +19 -5
  18. data/lib/auxiliary_rails/concerns/performable.rb +141 -0
  19. data/lib/auxiliary_rails/version.rb +1 -1
  20. data/lib/generators/auxiliary_rails/install_commands_generator.rb +5 -0
  21. data/lib/generators/auxiliary_rails/install_generator.rb +0 -1
  22. data/lib/generators/auxiliary_rails/templates/application_error_template.rb +1 -1
  23. data/lib/generators/auxiliary_rails/templates/commands/application_command_template.rb +1 -1
  24. data/lib/generators/auxiliary_rails/templates/commands/command_template.rb +2 -2
  25. data/lib/generators/auxiliary_rails/templates/commands/commands.en_template.yml +5 -0
  26. data/templates/rails/elementary.rb +45 -9
  27. metadata +43 -11
  28. data/lib/auxiliary_rails/abstract_command.rb +0 -95
  29. data/lib/auxiliary_rails/abstract_error.rb +0 -7
  30. data/lib/generators/auxiliary_rails/install_rubocop_generator.rb +0 -29
  31. data/lib/generators/auxiliary_rails/templates/rubocop/rubocop_auxiliary_rails_template.yml +0 -65
  32. data/lib/generators/auxiliary_rails/templates/rubocop/rubocop_template.yml +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6270fee8c57097f95277b91cb770228af36551459ebd01fbbe1900ff43a5b4b3
4
- data.tar.gz: 6b6e074c5751b729106fe2dcdc1f606474a95f6575eb8df0b1cbd68d54ebbe7b
3
+ metadata.gz: d2dca627a51fe1045de4e00f82cd2ac9dcc96df20816d7de67a8bf818180a06c
4
+ data.tar.gz: e5ae6c889d8ed752d382d86822410a409daaf9f14b04cbf833938af32adab6e9
5
5
  SHA512:
6
- metadata.gz: 77302dee8e26ab571731ee47779f70ade277fc5c476f197259a18d321336c0952f45bb69bba62bcde6d52cba677c979ac00646cc8e8165e7288da023cabb5642
7
- data.tar.gz: 450261a1b391e70b1cd7b926bb0cb4985f2f82021713041be5f6f04a403ea0b48eb9b8623ea2178c40a10533d05013067997dd15868def2a686947187af9fccc
6
+ metadata.gz: cabb77bb72b361996f1bd9623768d7c1af219c0f1bed3a516781493b0b77b7892bb42a3e4ffbefaabd879862fd7b3f25872a87e814e6b7aa7ec2bfc51e1e93d1
7
+ data.tar.gz: 07d26c7e442836147af787b33b5d6300f8e3d01c4b60a53fd31cbf0381158a7af5f16f8cb67af8d395ac8df25333cc75de8edaf8d1b0eb01e5cb1f708a1ebc43
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,26 @@
1
+ image: ruby:2.6
2
+
3
+ cache:
4
+ paths:
5
+ - vendor/bundle
6
+ - vendor/ruby
7
+
8
+ before_script:
9
+ - ruby -v
10
+ - gem install bundler --no-document
11
+ - bundle config set path 'vendor'
12
+ - bundle install --jobs $(nproc)
13
+
14
+ rspec:
15
+ stage: test
16
+ script:
17
+ - bundle exec rspec
18
+
19
+ rubocop:
20
+ stage: test
21
+ allow_failure: true
22
+ script:
23
+ - bundle exec rubocop
24
+
25
+ stages:
26
+ - test
data/.rubocop.yml CHANGED
@@ -7,13 +7,17 @@ require:
7
7
 
8
8
  AllCops:
9
9
  Exclude:
10
- - vendor/bundle/**/* # fix for running on Travis CI
10
+ - lib/generators/auxiliary_rails/templates/**/*
11
+ - vendor/**/* # fix for CI
11
12
 
12
13
  #################### Layout ##############################
13
14
 
14
- Layout/AlignArguments:
15
+ Layout/ArgumentAlignment:
15
16
  EnforcedStyle: with_fixed_indentation
16
17
 
18
+ Layout/MultilineMethodCallIndentation:
19
+ EnforcedStyle: indented
20
+
17
21
  #################### Metrics ##############################
18
22
 
19
23
  Metrics/BlockLength:
@@ -22,6 +26,8 @@ Metrics/BlockLength:
22
26
 
23
27
  #################### RSpec ################################
24
28
 
29
+ RSpec/ExampleLength:
30
+ Max: 10
25
31
 
26
32
  RSpec/MultipleExpectations:
27
33
  Max: 3
@@ -33,3 +39,6 @@ Style/Documentation:
33
39
 
34
40
  Style/FrozenStringLiteralComment:
35
41
  Enabled: false
42
+
43
+ Style/NegatedIf:
44
+ EnforcedStyle: postfix
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2019-05-12 09:23:17 +0300 using RuboCop version 0.68.1.
3
+ # on 2020-01-25 02:14:48 +0200 using RuboCop version 0.78.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -8,20 +8,24 @@
8
8
 
9
9
  # Offense count: 1
10
10
  # Cop supports --auto-correct.
11
- # Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
12
- Layout/ExtraSpacing:
11
+ Lint/SendWithMixinArgument:
13
12
  Exclude:
14
- - 'auxiliary_rails.gemspec'
13
+ - 'lib/auxiliary_rails/railtie.rb'
15
14
 
16
15
  # Offense count: 1
17
- # Cop supports --auto-correct.
18
- # Configuration parameters: AllowForAlignment.
19
- Layout/SpaceAroundOperators:
20
- Exclude:
21
- - 'auxiliary_rails.gemspec'
16
+ RSpec/NestedGroups:
17
+ Max: 4
22
18
 
23
19
  # Offense count: 1
24
20
  # Configuration parameters: MinBodyLength.
25
21
  Style/GuardClause:
26
22
  Exclude:
27
23
  - 'auxiliary_rails.gemspec'
24
+
25
+ # Offense count: 1
26
+ # Cop supports --auto-correct.
27
+ # Configuration parameters: EnforcedStyle, AllowInnerSlashes.
28
+ # SupportedStyles: slashes, percent_r, mixed
29
+ Style/RegexpLiteral:
30
+ Exclude:
31
+ - 'lib/generators/auxiliary_rails/command_generator.rb'
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --title "AuxiliaryRails"
2
+ --private --protected
3
+ --exclude lib/generators/*
4
+ --exclude lib/auxiliary_rails.rb
5
+ --exclude lib/auxiliary_rails/railtie.rb
data/CHANGELOG.md CHANGED
@@ -1,9 +1,26 @@
1
1
  # AuxiliaryRails Changelog
2
2
 
3
+ ## v0.3.0
4
+
5
+ ### Added
6
+ - Form Objects
7
+ - Query Objects
8
+ - Performable concern
9
+ - YARD docs and link to API documentation
10
+ - Commands usage examples
11
+ - Commands: `arguments` helper to get hash of all `param`s
12
+
13
+ ### Changed
14
+ - Namespace `Application` instead of `Abstract` prefixes for classes
15
+ - Commands migrate from `#call` to `#perform` method
16
+ - Commands: force validations
17
+
18
+ ### Removed
19
+ - RuboCop generator replaced with `rubocop-ergoserv` gem
20
+
3
21
  ## v0.2.0
4
22
 
5
23
  * Commands migration to `dry-initializer`
6
- * Commands usage examples
7
24
 
8
25
  ## v0.1.7
9
26
 
@@ -26,7 +43,7 @@
26
43
 
27
44
  ## v0.1.3
28
45
 
29
- * Upgrate `rubocop` gem and its configs
46
+ * Upgrade `rubocop` gem and its configs
30
47
  * `rubocop-rspec` and `rubocop-performance` gem iteration
31
48
  * Added basic Rails application template
32
49
  * CLI with `create_rails_app` command
data/CONTRIBUTING.md CHANGED
@@ -1,7 +1 @@
1
1
  # Contributing to AuxiliaryRails
2
-
3
- ## Rubocop Templates
4
-
5
- ### Versioning
6
-
7
- File `rubocop_auxiliary_rails_template.yml` contains a basic template of Rubocop config. After making any changes to this file the line `Version: N` should be updated and `N` (version number) should be incremented by one.
data/Gemfile.lock CHANGED
@@ -1,7 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- auxiliary_rails (0.2.0)
4
+ auxiliary_rails (0.3.0)
5
+ dry-core
6
+ dry-initializer
5
7
  dry-initializer-rails
6
8
  thor
7
9
 
@@ -66,17 +68,19 @@ GEM
66
68
  ast (2.4.0)
67
69
  builder (3.2.4)
68
70
  coderay (1.1.2)
69
- concurrent-ruby (1.1.5)
70
- crass (1.0.5)
71
+ concurrent-ruby (1.1.6)
72
+ crass (1.0.6)
71
73
  diff-lcs (1.3)
72
- dry-initializer (3.0.2)
74
+ dry-core (0.4.9)
75
+ concurrent-ruby (~> 1.0)
76
+ dry-initializer (3.0.3)
73
77
  dry-initializer-rails (3.1.1)
74
78
  dry-initializer (>= 2.4, < 4)
75
79
  rails (> 3.0)
76
80
  erubi (1.9.0)
77
81
  globalid (0.4.2)
78
82
  activesupport (>= 4.2.0)
79
- i18n (1.7.0)
83
+ i18n (1.8.2)
80
84
  concurrent-ruby (~> 1.0)
81
85
  jaro_winkler (1.5.4)
82
86
  loofah (2.4.0)
@@ -87,20 +91,20 @@ GEM
87
91
  marcel (0.3.3)
88
92
  mimemagic (~> 0.3.2)
89
93
  method_source (0.9.2)
90
- mimemagic (0.3.3)
94
+ mimemagic (0.3.4)
91
95
  mini_mime (1.0.2)
92
96
  mini_portile2 (2.4.0)
93
- minitest (5.13.0)
97
+ minitest (5.14.0)
94
98
  nio4r (2.5.2)
95
- nokogiri (1.10.7)
99
+ nokogiri (1.10.9)
96
100
  mini_portile2 (~> 2.4.0)
97
101
  parallel (1.19.1)
98
- parser (2.7.0.1)
102
+ parser (2.7.0.4)
99
103
  ast (~> 2.4.0)
100
104
  pry (0.12.2)
101
105
  coderay (~> 1.1.0)
102
106
  method_source (~> 0.9.0)
103
- rack (2.0.8)
107
+ rack (2.2.2)
104
108
  rack-test (1.1.0)
105
109
  rack (>= 1.0, < 3)
106
110
  rails (6.0.2.1)
@@ -144,16 +148,16 @@ GEM
144
148
  diff-lcs (>= 1.2.0, < 2.0)
145
149
  rspec-support (~> 3.9.0)
146
150
  rspec-support (3.9.2)
147
- rubocop (0.78.0)
151
+ rubocop (0.79.0)
148
152
  jaro_winkler (~> 1.5.1)
149
153
  parallel (~> 1.10)
150
- parser (>= 2.6)
154
+ parser (>= 2.7.0.1)
151
155
  rainbow (>= 2.2.2, < 4.0)
152
156
  ruby-progressbar (~> 1.7)
153
157
  unicode-display_width (>= 1.4.0, < 1.7)
154
158
  rubocop-performance (1.5.2)
155
159
  rubocop (>= 0.71.0)
156
- rubocop-rspec (1.37.1)
160
+ rubocop-rspec (1.38.1)
157
161
  rubocop (>= 0.68.1)
158
162
  ruby-progressbar (1.10.1)
159
163
  sprockets (4.0.0)
@@ -167,11 +171,11 @@ GEM
167
171
  thread_safe (0.3.6)
168
172
  tzinfo (1.2.6)
169
173
  thread_safe (~> 0.1)
170
- unicode-display_width (1.6.0)
174
+ unicode-display_width (1.6.1)
171
175
  websocket-driver (0.7.1)
172
176
  websocket-extensions (>= 0.1.0)
173
177
  websocket-extensions (0.1.4)
174
- zeitwerk (2.2.2)
178
+ zeitwerk (2.3.0)
175
179
 
176
180
  PLATFORMS
177
181
  ruby
@@ -183,7 +187,7 @@ DEPENDENCIES
183
187
  rails (>= 5.2, < 7)
184
188
  rake
185
189
  rspec (~> 3.8)
186
- rubocop
190
+ rubocop (= 0.79)
187
191
  rubocop-performance
188
192
  rubocop-rspec
189
193
 
data/README.md CHANGED
@@ -29,18 +29,22 @@ Or install it yourself as:
29
29
 
30
30
  ## Usage
31
31
 
32
+ - [API documentation](https://www.rubydoc.info/gems/auxiliary_rails)
33
+
32
34
  ### Rails Application Templates
33
35
 
34
36
  Install gem into the system (e.g. using `gem install auxiliary_rails`) then:
35
37
 
36
38
  ```sh
37
39
  auxiliary_rails new APP_PATH
40
+ # or add `--develop` option to pull the most recent template from repository
41
+ auxiliary_rails new APP_PATH --develop
38
42
  ```
39
43
 
40
44
  Or use `rails new` command specifying `--template` argument:
41
45
 
42
46
  ```sh
43
- rails new APP_PATH --skip-action-cable --skip-coffee --skip-test --database=postgresql --template=https://raw.githubusercontent.com/ergoserv/auxiliary_rails/develop/templates/rails/elementary.rb
47
+ rails new APP_PATH --database=postgresql --template=https://raw.githubusercontent.com/ergoserv/auxiliary_rails/develop/templates/rails/elementary.rb --skip-action-cable --skip-coffee --skip-test --skip-webpack-install
44
48
  ```
45
49
 
46
50
  ### Generators
@@ -52,8 +56,6 @@ rails generate auxiliary_rails:install
52
56
  # Install one by one
53
57
  rails generate auxiliary_rails:install_commands
54
58
  rails generate auxiliary_rails:install_errors
55
- rails generate auxiliary_rails:install_rubocop
56
- rails generate auxiliary_rails:install_rubocop --no-specify-gems
57
59
 
58
60
  # API resource generator
59
61
  rails generate auxiliary_rails:api_resource
@@ -62,6 +64,205 @@ rails generate auxiliary_rails:api_resource
62
64
  rails generate auxiliary_rails:command
63
65
  ```
64
66
 
67
+ ### Command Objects
68
+
69
+ Variation of implementation of [Command pattern](https://en.wikipedia.org/wiki/Command_pattern).
70
+
71
+ ```ruby
72
+ # app/commands/application_command.rb
73
+ class ApplicationCommand < AuxiliaryRails::Application::Command
74
+ end
75
+
76
+ # app/commands/register_user_command.rb
77
+ class RegisterUserCommand < ApplicationCommand
78
+ # Define command arguments
79
+ # using `param` or `option` methods provided by dry-initializer
80
+ # https://dry-rb.org/gems/dry-initializer/3.0/
81
+ param :email
82
+ param :password
83
+
84
+ # Define the results of the command
85
+ # using `attr_reader` and set it as a regular instance var inside the command
86
+ attr_reader :user
87
+
88
+ # Regular Active Model Validations can be used to validate params
89
+ # https://api.rubyonrails.org/classes/ActiveModel/Validations.html
90
+ # Use #valid?, #invalid?, #validate! methods to engage validations
91
+ validates :password, length: { in: 8..32 }
92
+
93
+ # Define the only public method `#perform`
94
+ # where command's flow is defined
95
+ def perform
96
+ # Use `return failure!` to exit from the command with failure
97
+ return failure! if registration_disabled?
98
+
99
+ # Method `#transaction` is a shortcut for `ActiveRecord::Base.transaction`
100
+ transaction do
101
+ # Keep the `#perform` method short and clean, put all the steps, actions
102
+ # and business logic into meaningful and self-explanatory methods
103
+ create_user
104
+
105
+ # Use `error!` method to interrupt the flow raising an error
106
+ error! unless @user.persistent?
107
+
108
+ send_notification
109
+ # ...
110
+ end
111
+
112
+ # Always end the `#perform` method with `success!`
113
+ # this will set the proper status and allow to chain command methods.
114
+ success!
115
+ end
116
+
117
+ private
118
+
119
+ def create_user
120
+ @user = User.create(email: email, password: password)
121
+ end
122
+
123
+ def send_notification
124
+ # ...
125
+ end
126
+ end
127
+
128
+ ### usage ###
129
+
130
+ class RegistrationsController
131
+ def register
132
+ cmd = RegisterUserCommand.call(params[:email], params[:password])
133
+
134
+ if cmd.success?
135
+ redirect_to user_path(cmd.user) and return
136
+ else
137
+ @errors = cmd.errors
138
+ end
139
+
140
+ ### OR ###
141
+
142
+ RegisterUserCommand.call(params[:email], params[:password])
143
+ .on(:success) do
144
+ redirect_to dashboard_path and return
145
+ end
146
+ .on(:failure) do |cmd|
147
+ @errors = cmd.errors
148
+ end
149
+ end
150
+ end
151
+ ```
152
+
153
+ ### Form Objects
154
+
155
+ ```ruby
156
+ # app/forms/application_form.rb
157
+ class ApplicationForm < AuxiliaryRails::Application::Form
158
+ end
159
+
160
+ # app/forms/company_registration_form.rb
161
+ class CompanyRegistrationForm < ApplicationForm
162
+ # Define form attributes
163
+ attribute :company_name, :string
164
+ attribute :email, :string
165
+
166
+ # Define form submission results
167
+ attr_reader :company
168
+
169
+ # Regular Active Model Validations can be used to validate attributes
170
+ # https://api.rubyonrails.org/classes/ActiveModel/Validations.html
171
+ validates :company_name, presence: true
172
+ validates :email, email: true
173
+
174
+ def perform
175
+ # Perform business logic here
176
+
177
+ # Use `attr_reader` to expose the submission results.
178
+ @company = create_company
179
+ # Return `failure!` to indicate failure and stop execution
180
+ return failure! if @company.invalid?
181
+
182
+ send_notification if email.present?
183
+
184
+ # Always end with `success!` method call to indicate success
185
+ success!
186
+ end
187
+
188
+ private
189
+
190
+ def create_comany
191
+ Company.create(name: company_name)
192
+ end
193
+
194
+ def send_notification
195
+ # mail to: email
196
+ end
197
+ end
198
+
199
+ ### Usage ###
200
+
201
+ form = CompanyRegistrationForm.call(params[:company])
202
+ if form.success?
203
+ redirect_to company_path(form.company) and return
204
+ else
205
+ @errors = form.errors
206
+ end
207
+ ```
208
+
209
+ ### Query Objects
210
+
211
+ ```ruby
212
+ # app/queries/application_query.rb
213
+ class ApplicationQuery < AuxiliaryRails::Application::Query
214
+ end
215
+
216
+ # app/queries/authors_query.rb
217
+ class AuthorsQuery < ApplicationQuery
218
+ default_relation Author.all
219
+
220
+ option :name_like, optional: true
221
+ option :with_books, optional: true
222
+
223
+ def perform
224
+ if recent == true
225
+ # equivalent to `@query = @query.order(:created_at)`:
226
+ query order(:created_at)
227
+ end
228
+
229
+ if name_like.present?
230
+ query with_name_like(name_like)
231
+ end
232
+ end
233
+
234
+ private
235
+
236
+ def with_name_like(value)
237
+ where('authors.name LIKE ?', "%#{value}%")
238
+ end
239
+ end
240
+
241
+ # app/queries/authors_with_books_query.rb
242
+ class AuthorsWithBooksQuery < AuthorsQuery
243
+ option :min_book_count, default: { 3 }
244
+
245
+ def perform
246
+ query joins(:books)
247
+ .group(:author_id)
248
+ .having('COUNT(books.id) > ?', min_book_count)
249
+ end
250
+ end
251
+
252
+ ### Usage ###
253
+
254
+ # it is possible to wrap query object in a scope and use as a regular scope
255
+ # app/models/inmate.rb
256
+ class Author < ApplicationRecord
257
+ scope :name_like, ->(value) { AuthorsQuery.call(name_like: value) }
258
+ end
259
+
260
+ authors = Author.name_like('Arthur')
261
+
262
+ # or call query directly
263
+ authors = AuthorsWithBooksQuery.call(min_book_count: 10)
264
+ ```
265
+
65
266
  ### View Helpers
66
267
 
67
268
  ```ruby