undercarriage 0.5.7 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c80a0b92962c21262508fe3cfe89796a348e1b87c9e950d56e403ff114ba9c20
4
- data.tar.gz: ec30e3665b643a807e05ca1f4ced57c385bceb5ae1a7dae6db16d72f429d0232
3
+ metadata.gz: 59a96756fb12afc085cd7e915c6c55d4795d354ba3e1206d2f2e4c600366f8ce
4
+ data.tar.gz: 18b7f4c033a3c1e0ec2b15be8a648dd6dd8c44cb77ea3df455a63b7376aa1fc0
5
5
  SHA512:
6
- metadata.gz: a276544a8b9343c1224d02918846fde1b426aa193a46557f3d52b2b82280c7d6ab5941a1dfe59ecefc02959c1bf72078cd19588aa01ea916dfe047b7c1b5344b
7
- data.tar.gz: 134eec2dea285ff0a3de8521f9e0af1d2c20c4601ff1b2b07b7954a69ee00d1edb79b22939c635f7cdff9bdf4f610f248ce089142d7ccc81d04e075eaebc3407
6
+ metadata.gz: 0b22d67b2f8fddc1b9b5ab58205557e56c2e8ed1e4087092f265252ba573fc111f121c34b403e255556b03abde62dfe8046cb17711662f8c13cb7a9aba762003
7
+ data.tar.gz: b9c0d216a9c6e7455dad762f88dd13c953cc1dc251c4c3be6361b7d7e766882205878a52a923eaa81ace11762a09bd5cd3b670b85c8e3c0e07f4185513314097
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2021 David Freerksen
1
+ Copyright 2026 David Freerksen
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -2,28 +2,24 @@
2
2
 
3
3
  **\*Undercarriage is currently under development. It is not ready for production use.\***
4
4
 
5
- [![CircleCI](https://circleci.com/gh/dfreerksen/undercarriage.svg?style=shield)](https://circleci.com/gh/dfreerksen/undercarriage)
6
- [![Maintainability](https://api.codeclimate.com/v1/badges/d15980a534f8db936469/maintainability)](https://codeclimate.com/github/dfreerksen/undercarriage/maintainability)
7
- [![Test Coverage](https://api.codeclimate.com/v1/badges/d15980a534f8db936469/test_coverage)](https://codeclimate.com/github/dfreerksen/undercarriage/test_coverage)
8
-
9
5
  Undercarriage is a set of concerns to add to your application to trim some of the fat from controllers and models.
10
6
 
11
7
  ## Requirements
12
8
 
13
- * Ruby >= 2.6
9
+ * Ruby >= 3.3.0
14
10
  * Rails >= 6.0
15
11
 
16
12
  ## Installation
17
13
 
18
14
  Add to your application's Gemfile
19
15
 
20
- ```
21
- gem 'undercarriage', '~> 0.5'
16
+ ```bash
17
+ gem 'undercarriage', '~> 1.0'
22
18
  ```
23
19
 
24
20
  Run the bundle command
25
21
 
26
- ```
22
+ ```bash
27
23
  $ bundle install
28
24
  ```
29
25
 
@@ -31,41 +27,40 @@ $ bundle install
31
27
 
32
28
  TODO
33
29
 
34
- ## TODO
35
-
36
- * [ ] Allow a way to set locale instead of relying on browser preferred language in `Undercarriage::Controllers::LocaleConcern`
37
- * [ ] Add support for Rails 5.2
38
-
39
30
  ## Testing
40
31
 
41
32
  Run tests with one of the following
42
33
 
43
- ```
34
+ ```bash
44
35
  $ bundle exec rspec
45
36
  $ bundle exec rspec spec
46
37
  ```
47
38
 
48
39
  ### Appraisal
49
40
 
50
- Undercarriage uses [Appraisal](https://github.com/thoughtbot/appraisal) to ensure various dependency versions work as expected
41
+ Undercarriage uses [Appraisal2](https://github.com/appraisal-rb/appraisal2) (a maintained fork of [Appraisal](https://github.com/thoughtbot/appraisal), still exposing the `appraisal` executable) to ensure various dependency versions work as expected
51
42
 
52
43
  When dependencies change, run
53
44
 
54
- ```
45
+ ```bash
55
46
  $ bundle exec appraisal install
47
+ $ bundle exec appraisal generate-install
56
48
  ```
57
49
 
58
50
  To run tests with Appraisal, run
59
51
 
60
- ```
52
+ ```bash
61
53
  $ bundle exec appraisal rspec
62
54
  ```
63
55
 
64
- To run tests with a specific version of Appraisal, run
65
-
66
- ```
67
- $ bundle exec appraisal rails-60 rspec
68
- $ bundle exec appraisal rails-61 rspec
56
+ ```bash
57
+ $ bundle exec appraisal rails-6-0 rspec spec
58
+ $ bundle exec appraisal rails-6-1 rspec spec
59
+ $ bundle exec appraisal rails-7-0 rspec spec
60
+ $ bundle exec appraisal rails-7-1 rspec spec
61
+ $ bundle exec appraisal rails-7-2 rspec spec
62
+ $ bundle exec appraisal rails-8-0 rspec spec
63
+ $ bundle exec appraisal rails-8-1 rspec spec
69
64
  ```
70
65
 
71
66
  ## Code Analysis
@@ -76,24 +71,32 @@ Various tools are used to ensure code is linted and formatted correctly.
76
71
 
77
72
  [RuboCop](https://github.com/bbatsov/rubocop) is a Ruby static code analyzer.
78
73
 
79
- ```
74
+ ```bash
80
75
  $ rubocop
81
76
  ```
82
77
 
78
+ ### YARD-Lint
79
+
80
+ [YARD-Lint](https://github.com/mensfeld/yard-lint) is a linter for YARD documentation.
81
+
82
+ ```bash
83
+ $ bundle exec yard-lint
84
+ ```
85
+
83
86
  ## Documentation
84
87
 
85
88
  [Yard](https://github.com/lsegal/yard) is used to generate documentation. [Online documentation is available](http://www.rubydoc.info/github/dfreerksen/undercarriage/master)
86
89
 
87
90
  Build the documentation with one of the following
88
91
 
89
- ```
92
+ ```bash
90
93
  $ yard
91
94
  $ yard doc
92
95
  ```
93
96
 
94
97
  Build the documentation and list all undocumented objects
95
98
 
96
- ```
99
+ ```bash
97
100
  $ yard stats --list-undoc
98
101
  ```
99
102
 
data/Rakefile CHANGED
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
- require 'bundler/setup'
4
+ require "bundler/setup"
5
5
  rescue LoadError
6
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
7
  end
8
8
 
9
- require 'rdoc/task'
9
+ require "rdoc/task"
10
10
 
11
11
  RDoc::Task.new(:rdoc) do |rdoc|
12
- rdoc.rdoc_dir = 'rdoc'
13
- rdoc.title = 'Undercarriage'
14
- rdoc.options << '--line-numbers'
15
- rdoc.rdoc_files.include('README.md')
16
- rdoc.rdoc_files.include('lib/**/*.rb')
12
+ rdoc.rdoc_dir = "rdoc"
13
+ rdoc.title = "Undercarriage"
14
+ rdoc.options << "--line-numbers"
15
+ rdoc.rdoc_files.include("README.md")
16
+ rdoc.rdoc_files.include("lib/**/*.rb")
17
17
  end
18
18
 
19
- require 'bundler/gem_tasks'
19
+ require "bundler/gem_tasks"
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :nodoc:
3
4
  module Undercarriage
4
5
  # :nodoc:
5
6
  module Controllers
@@ -8,11 +9,10 @@ module Undercarriage
8
9
  #
9
10
  # Helpers for the controller or view to help identify the action
10
11
  #
11
- # Usage
12
+ # @example Controller
12
13
  # class ExamplesController < ApplicationController
13
14
  # include Undercarriage::Controllers::ActionConcern
14
15
  # end
15
- #
16
16
  module ActionConcern
17
17
  extend ActiveSupport::Concern
18
18
 
@@ -38,14 +38,13 @@ module Undercarriage
38
38
  #
39
39
  # Check if action is a certain action type
40
40
  #
41
- # Usage
42
- # action?(:show) # true
43
- # action?('show') # true
44
- # action?(:index) # false
45
- #
46
41
  # @param action_method [String, Symbol] the action to test
47
42
  # @return [Boolean] if action matches
48
43
  #
44
+ # @example View
45
+ # action?(:show) # true
46
+ # action?("show") # true
47
+ # action?(:index) # false
49
48
  def action?(action_method)
50
49
  action == action_method.to_sym
51
50
  end
@@ -55,14 +54,13 @@ module Undercarriage
55
54
  #
56
55
  # Check if action is the index action type. The check will pass if it is an `index` action
57
56
  #
58
- # Usage
59
- # index_action? # true
60
- # index_action? # false
61
- #
62
57
  # @return [Boolean] if action is action type
63
58
  #
59
+ # @example View
60
+ # index_action? # true
61
+ # index_action? # false
64
62
  def index_action?
65
- action?('index')
63
+ action?("index")
66
64
  end
67
65
 
68
66
  ##
@@ -70,14 +68,13 @@ module Undercarriage
70
68
  #
71
69
  # Check if action is the show action type. The check will pass if it is a `show` action
72
70
  #
73
- # Usage
74
- # show_action? # true
75
- # show_action? # false
76
- #
77
71
  # @return [Boolean] if action is action type
78
72
  #
73
+ # @example View
74
+ # show_action? # true
75
+ # show_action? # false
79
76
  def show_action?
80
- action?('show')
77
+ action?("show")
81
78
  end
82
79
 
83
80
  ##
@@ -85,14 +82,13 @@ module Undercarriage
85
82
  #
86
83
  # Check if action is the new action type. The check will pass if it is a `new` action
87
84
  #
88
- # Usage
89
- # new_action? # true
90
- # new_action? # false
91
- #
92
85
  # @return [Boolean] if action is action type
93
86
  #
87
+ # @example View
88
+ # new_action? # true
89
+ # new_action? # false
94
90
  def new_action?
95
- action?('new')
91
+ action?("new")
96
92
  end
97
93
 
98
94
  ##
@@ -100,14 +96,13 @@ module Undercarriage
100
96
  #
101
97
  # Check if action is the create action type. The check will pass if it is a `create` action
102
98
  #
103
- # Usage
104
- # create_action? # true
105
- # create_action? # false
106
- #
107
99
  # @return [Boolean] if action is action type
108
100
  #
101
+ # @example View
102
+ # create_action? # true
103
+ # create_action? # false
109
104
  def create_action?
110
- action?('create')
105
+ action?("create")
111
106
  end
112
107
 
113
108
  ##
@@ -115,14 +110,13 @@ module Undercarriage
115
110
  #
116
111
  # Check if action is the edit action type. The check will pass if it is an `edit` action
117
112
  #
118
- # Usage
119
- # edit_action? # true
120
- # edit_action? # false
121
- #
122
113
  # @return [Boolean] if action is action type
123
114
  #
115
+ # @example View
116
+ # edit_action? # true
117
+ # edit_action? # false
124
118
  def edit_action?
125
- action?('edit')
119
+ action?("edit")
126
120
  end
127
121
 
128
122
  ##
@@ -130,14 +124,13 @@ module Undercarriage
130
124
  #
131
125
  # Check if action is the update action type. The check will pass if it is an `update` action
132
126
  #
133
- # Usage
134
- # update_action? # true
135
- # update_action? # false
136
- #
137
127
  # @return [Boolean] if action is action type
138
128
  #
129
+ # @example View
130
+ # update_action? # true
131
+ # update_action? # false
139
132
  def update_action?
140
- action?('update')
133
+ action?("update")
141
134
  end
142
135
 
143
136
  ##
@@ -145,14 +138,13 @@ module Undercarriage
145
138
  #
146
139
  # Check if action is the destroy action type. The check will pass if it is a `destroy` action
147
140
  #
148
- # Usage
149
- # destroy_action? # true
150
- # destroy_action? # false
151
- #
152
141
  # @return [Boolean] if action is action type
153
142
  #
143
+ # @example View
144
+ # destroy_action? # true
145
+ # destroy_action? # false
154
146
  def destroy_action?
155
- action?('destroy')
147
+ action?("destroy")
156
148
  end
157
149
 
158
150
  ##
@@ -160,12 +152,11 @@ module Undercarriage
160
152
  #
161
153
  # Check if action is a collection action type. An action is a collection type if it is the `index` action
162
154
  #
163
- # Usage
164
- # collection_action? # true
165
- # collection_action? # false
166
- #
167
155
  # @return [Boolean] if action is collection type
168
156
  #
157
+ # @example View
158
+ # collection_action? # true
159
+ # collection_action? # false
169
160
  def collection_action?
170
161
  collection_actions.include?(action)
171
162
  end
@@ -175,15 +166,14 @@ module Undercarriage
175
166
  #
176
167
  # Check if action is a create or new action type. The check will pass if it is a `create` or `new` action
177
168
  #
178
- # Usage
169
+ # @return [Boolean] if action is actions type
170
+ #
171
+ # @example View create
179
172
  # create_actions? # true
180
173
  # create_actions? # false
181
- #
174
+ # @example View new
182
175
  # new_actions? # true
183
176
  # new_actions? # false
184
- #
185
- # @return [Boolean] if action is actions type
186
- #
187
177
  def create_actions?
188
178
  create_actions.include?(action)
189
179
  end
@@ -195,12 +185,11 @@ module Undercarriage
195
185
  # Check if action is a member action type. An action is a member type if it is the `edit`, `show`, or `update`
196
186
  # action
197
187
  #
198
- # Usage
199
- # member_action? # true
200
- # member_action? # false
201
- #
202
188
  # @return [Boolean] if action is member type
203
189
  #
190
+ # @example View
191
+ # member_action? # true
192
+ # member_action? # false
204
193
  def member_action?
205
194
  member_actions.include?(action)
206
195
  end
@@ -210,15 +199,14 @@ module Undercarriage
210
199
  #
211
200
  # Check if action is an edit or update action type. The check will pass if it is an `edit` or `update` action
212
201
  #
213
- # Usage
202
+ # @return [Boolean] if action is actions type
203
+ #
204
+ # @example View update
214
205
  # update_actions? # true
215
206
  # update_actions? # false
216
- #
207
+ # @example View edit
217
208
  # edit_actions? # true
218
209
  # edit_actions? # false
219
- #
220
- # @return [Boolean] if action is actions type
221
- #
222
210
  def update_actions?
223
211
  update_actions.include?(action)
224
212
  end
@@ -231,6 +219,7 @@ module Undercarriage
231
219
  #
232
220
  # Take `action_name` (string) and turn it into a symbol
233
221
  #
222
+ # @return [Symbol] action_name as a symbol
234
223
  def action
235
224
  action_name.to_sym
236
225
  end
@@ -238,6 +227,7 @@ module Undercarriage
238
227
  ##
239
228
  # Collection actions
240
229
  #
230
+ # @return [Array] collection actions
241
231
  def collection_actions
242
232
  %i[index]
243
233
  end
@@ -245,6 +235,7 @@ module Undercarriage
245
235
  ##
246
236
  # Member actions
247
237
  #
238
+ # @return [Array] member actions
248
239
  def member_actions
249
240
  %i[edit show update]
250
241
  end
@@ -252,6 +243,7 @@ module Undercarriage
252
243
  ##
253
244
  # Create actions
254
245
  #
246
+ # @return [Array] create actions
255
247
  def create_actions
256
248
  %i[create new]
257
249
  end
@@ -259,6 +251,7 @@ module Undercarriage
259
251
  ##
260
252
  # Update actions
261
253
  #
254
+ # @return [Array] update actions
262
255
  def update_actions
263
256
  %i[edit update]
264
257
  end
@@ -9,7 +9,7 @@ module Undercarriage
9
9
  # Helpers for Kaminari style pagination. Note that the Kaminari gem is not loaded with dependency. It must be added
10
10
  # to your own Gemfile
11
11
  #
12
- # Usage
12
+ # @example Controller
13
13
  # class ExamplesController < ApplicationController
14
14
  # include Undercarriage::Controllers::KaminariConcern
15
15
  #
@@ -17,7 +17,6 @@ module Undercarriage
17
17
  # @examples = Examples.page(page_num).per(per_page)
18
18
  # end
19
19
  # end
20
- #
21
20
  module KaminariConcern
22
21
  extend ActiveSupport::Concern
23
22
 
@@ -33,12 +32,11 @@ module Undercarriage
33
32
  #
34
33
  # This is asseccible from the View as `per_page`
35
34
  #
36
- # Usage
37
- # /examples?per=100 # Return 100 items per page
38
- # /examples?per=10&page=3 # Return page 3 of items with 10 items per page
39
- #
40
35
  # @return [Integer] the number of items per page
41
36
  #
37
+ # @example Request
38
+ # # GET /examples?per=100 # Return 100 items per page
39
+ # # GET /examples?per=10&page=3 # Return page 3 of items with 10 items per page
42
40
  def per_page
43
41
  params.fetch(per_page_key, per_page_default).to_i
44
42
  end
@@ -50,12 +48,11 @@ module Undercarriage
50
48
  #
51
49
  # This is asseccible from the View as `page_num`
52
50
  #
53
- # Usage
54
- # /examples?page=5 # Return page 5 of items
55
- # /examples?per=10&page=3 Return page 3 of items with 10 items per page
56
- #
57
51
  # @return [Integer] the page number
58
52
  #
53
+ # @example Request
54
+ # # GET /examples?page=5 # Return page 5 of items
55
+ # # GET /examples?per=10&page=3 # Return page 3 of items with 10 items per page
59
56
  def page_num
60
57
  params.fetch(page_num_key, page_num_default).to_i
61
58
  end
@@ -67,6 +64,7 @@ module Undercarriage
67
64
  #
68
65
  # Query param to be used to identify count to be returned
69
66
  #
67
+ # @return [Integer] per page count
70
68
  def per_page_key
71
69
  :per
72
70
  end
@@ -76,16 +74,29 @@ module Undercarriage
76
74
  #
77
75
  # Query param to be used to identify page offset
78
76
  #
77
+ # @return [String,Symbol] page number key
79
78
  def page_num_key
80
79
  Kaminari.config.param_name
81
80
  end
82
81
 
83
82
  private
84
83
 
84
+ ##
85
+ # Items per page default
86
+ #
87
+ # Fallback used when the `per` query param is absent.
88
+ #
89
+ # @return [Integer] default per page count
85
90
  def per_page_default
86
91
  Kaminari.config.default_per_page
87
92
  end
88
93
 
94
+ ##
95
+ # Page number default
96
+ #
97
+ # Fallback used when the page query param is absent.
98
+ #
99
+ # @return [Integer] default page number
89
100
  def page_num_default
90
101
  1
91
102
  end
@@ -13,11 +13,10 @@ module Undercarriage
13
13
  # When preferred language cannot be identified or no translation is available, fall back to `I18n.default_locale`
14
14
  # (typically `en`).
15
15
  #
16
- # Usage
16
+ # @example Controller
17
17
  # class ExamplesController < ApplicationController
18
18
  # include Undercarriage::Controllers::LocaleConcern
19
19
  # end
20
- #
21
20
  module LocaleConcern
22
21
  extend ActiveSupport::Concern
23
22
 
@@ -32,10 +31,11 @@ module Undercarriage
32
31
  #
33
32
  # Helper for Views to return the identified language.
34
33
  #
35
- # Usage
36
- # <html lang="<%= html_lang %>"> #=> '<html lang="de">'
37
- # <html lang="<%= html_lang %>"> #=> '<html lang="de-at">'
34
+ # @return [String] locale for html tag lang attribute
38
35
  #
36
+ # @example View
37
+ # # <html lang="<%= html_lang %>"> #=> '<html lang="de">'
38
+ # # <html lang="<%= html_lang %>"> #=> '<html lang="de-at">'
39
39
  def html_lang
40
40
  I18n.locale.to_s
41
41
  end
@@ -54,14 +54,15 @@ module Undercarriage
54
54
  # * Persian/Farsi
55
55
  # * Urdu
56
56
  #
57
- # Usage
58
- # <html dir="<%= html_dir %>"> #=> <html dir="ltr">
59
- # <html dir="<%= html_dir %>"> #=> <html dir="rtl">
57
+ # @return [String] direction for html tag dir attribute
60
58
  #
59
+ # @example View
60
+ # # <html dir="<%= html_dir %>"> #=> <html dir="ltr">
61
+ # # <html dir="<%= html_dir %>"> #=> <html dir="rtl">
61
62
  def html_dir
62
63
  rtl_languages = %w[am ar az dv fa he ur]
63
64
 
64
- html_lang.start_with?(*rtl_languages) ? 'rtl' : 'ltr'
65
+ html_lang.start_with?(*rtl_languages) ? "rtl" : "ltr"
65
66
  end
66
67
 
67
68
  protected
@@ -71,12 +72,20 @@ module Undercarriage
71
72
  #
72
73
  # Set I18n locale for the request
73
74
  #
75
+ # @return [String] locale
74
76
  def identify_locale(&action)
75
77
  I18n.with_locale(first_available_locale, &action)
76
78
  end
77
79
 
78
80
  private
79
81
 
82
+ ##
83
+ # First available locale
84
+ #
85
+ # Intersects the request's accepted languages (falling back to `I18n.default_locale`) against
86
+ # `I18n.available_locales`, preferring the request's order.
87
+ #
88
+ # @return [String] locale
80
89
  def first_available_locale
81
90
  preferred_locales = (accepted_languages_header << I18n.default_locale.to_s).uniq
82
91
  available_locales = I18n.available_locales.map(&:to_s)
@@ -84,11 +93,18 @@ module Undercarriage
84
93
  (preferred_locales & available_locales).first
85
94
  end
86
95
 
96
+ ##
97
+ # Accepted languages header
98
+ #
99
+ # Parses the `HTTP_ACCEPT_LANGUAGE` request header into an ordered list of language tags, stripping any
100
+ # `;q=` quality values.
101
+ #
102
+ # @return [Array<String>] accepted language tags
87
103
  def accepted_languages_header
88
- accepted_languages = request.env['HTTP_ACCEPT_LANGUAGE'] || ''
104
+ accepted_languages = request.env["HTTP_ACCEPT_LANGUAGE"] || ""
89
105
 
90
- accepted_languages.gsub(/\s+/, '').split(',').map do |lang|
91
- lang.split(';q=').first
106
+ accepted_languages.gsub(/\s+/, "").split(",").map do |lang|
107
+ lang.split(";q=").first
92
108
  end
93
109
  end
94
110
  end