tarquinn 0.2.0 → 0.4.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 +4 -4
- data/.circleci/config.yml +16 -10
- data/.github/copilot-instructions.md +188 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +29 -0
- data/.rubocop_todo.yml +13 -0
- data/Dockerfile +2 -2
- data/Gemfile +15 -0
- data/Makefile +21 -0
- data/README.md +110 -3
- data/Rakefile +5 -0
- data/config/check_specs.yml +4 -0
- data/config/rubycritc.rb +12 -0
- data/config/yardstick.rb +13 -0
- data/config/yardstick.yml +55 -0
- data/docker-compose.yml +1 -1
- data/lib/tarquinn/class_methods.rb +132 -12
- data/lib/tarquinn/condition/action_checker.rb +45 -7
- data/lib/tarquinn/condition/method_caller.rb +46 -8
- data/lib/tarquinn/condition/proc_runner.rb +36 -7
- data/lib/tarquinn/condition.rb +65 -4
- data/lib/tarquinn/controller.rb +59 -13
- data/lib/tarquinn/exception.rb +20 -0
- data/lib/tarquinn/redirection_config/options.rb +58 -0
- data/lib/tarquinn/redirection_config.rb +175 -0
- data/lib/tarquinn/redirection_config_builder.rb +88 -0
- data/lib/tarquinn/redirection_handler.rb +194 -0
- data/lib/tarquinn/request_handler.rb +89 -0
- data/lib/tarquinn/request_handler_builder.rb +90 -0
- data/lib/tarquinn/version.rb +6 -1
- data/lib/tarquinn.rb +97 -8
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/stylesheets/application.css +1 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +6 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +6 -0
- data/spec/dummy/app/controllers/application_controller.rb +4 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/controllers/tarquinn/dummy_controller.rb +43 -0
- data/spec/dummy/app/controllers/tarquinn/dummy_route_controller.rb +37 -0
- data/spec/dummy/app/helpers/application_helper.rb +4 -0
- data/spec/dummy/app/jobs/application_job.rb +9 -0
- data/spec/dummy/app/mailers/application_mailer.rb +6 -0
- data/spec/dummy/app/models/application_record.rb +5 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +15 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/app/views/tarquinn/dummy_route/index.html +0 -0
- data/spec/dummy/app/views/tarquinn/dummy_route/new.html +0 -0
- data/spec/dummy/bin/rails +6 -0
- data/spec/dummy/bin/rake +6 -0
- data/spec/dummy/bin/setup +35 -0
- data/spec/dummy/config/application.rb +24 -0
- data/spec/dummy/config/boot.rb +7 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +7 -0
- data/spec/dummy/config/environments/development.rb +69 -0
- data/spec/dummy/config/environments/production.rb +89 -0
- data/spec/dummy/config/environments/test.rb +62 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +26 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +10 -0
- data/spec/dummy/config/initializers/inflections.rb +17 -0
- data/spec/dummy/config/initializers/permissions_policy.rb +12 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/puma.rb +45 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/config/storage.yml +34 -0
- data/spec/dummy/config.ru +8 -0
- data/spec/dummy/db/schema.rb +16 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/storage/.keep +0 -0
- data/spec/dummy/tmp/.keep +0 -0
- data/spec/dummy/tmp/pids/.keep +0 -0
- data/spec/dummy/tmp/storage/.keep +0 -0
- data/spec/lib/tarquinn/condition/action_checker_spec.rb +4 -2
- data/spec/lib/tarquinn/condition/method_caller_spec.rb +5 -3
- data/spec/lib/tarquinn/condition/proc_runner_spec.rb +56 -4
- data/spec/lib/tarquinn/condition_spec.rb +53 -0
- data/spec/lib/tarquinn/controller_spec.rb +83 -10
- data/spec/lib/tarquinn/exception/redirection_already_defined_spec.rb +13 -0
- data/spec/lib/tarquinn/redirection_config/options_spec.rb +45 -0
- data/spec/lib/tarquinn/redirection_config_builder_spec.rb +57 -0
- data/spec/lib/tarquinn/{config_spec.rb → redirection_config_spec.rb} +4 -2
- data/spec/lib/tarquinn/{handler_spec.rb → redirection_handler_spec.rb} +42 -5
- data/spec/lib/tarquinn/request_handler_builder_spec.rb +45 -0
- data/spec/lib/tarquinn/{engine_spec.rb → request_handler_spec.rb} +5 -3
- data/spec/lib/tarquinn_spec.rb +202 -13
- data/spec/spec_helper.rb +16 -6
- data/spec/support/shared_examples/config.rb +4 -2
- data/tarquinn.gemspec +10 -13
- metadata +87 -92
- data/lib/tarquinn/builder.rb +0 -28
- data/lib/tarquinn/concern.rb +0 -17
- data/lib/tarquinn/config.rb +0 -39
- data/lib/tarquinn/engine.rb +0 -31
- data/lib/tarquinn/handler.rb +0 -49
- data/spec/lib/tarquinn/builder_spec.rb +0 -13
- data/spec/support/models/tarquinn/dummy_controller.rb +0 -43
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 472e75e26a2d619f0284c9eb797c5e47f717a9f9a6e52757fc1c5ad7272a174f
|
|
4
|
+
data.tar.gz: efb31ef0021491a3b99c48cb8c3a34026493a10500636449195c1070d281dc91
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9391c038495ea739fee48b43a9c104bcb0dfb887aa87ecb75be3d1378ee2c11649cc68725fd8beea215036065b5deb1aeca08babea956d77b42628b887ead261
|
|
7
|
+
data.tar.gz: 59ccde1cade0e2b76b82f89073409cf9ced274d7346214ae08f2d4e6f06e11269feb9b768c219064bcec0e748205c1ce6a5eb45515e21dbe404a53459cb6643b
|
data/.circleci/config.yml
CHANGED
|
@@ -18,30 +18,24 @@ workflows:
|
|
|
18
18
|
only: /\d+\.\d+\.\d+/
|
|
19
19
|
branches:
|
|
20
20
|
only:
|
|
21
|
-
-
|
|
21
|
+
- main
|
|
22
22
|
jobs:
|
|
23
23
|
test:
|
|
24
24
|
docker:
|
|
25
|
-
- image: darthjee/
|
|
25
|
+
- image: darthjee/circleci_ruby_331:1.0.1
|
|
26
26
|
environment:
|
|
27
27
|
PROJECT: tarquinn
|
|
28
28
|
steps:
|
|
29
29
|
- checkout
|
|
30
|
-
- run:
|
|
31
|
-
name: Prepare Coverage Test Report
|
|
32
|
-
command: cc-test-reporter before-build
|
|
33
30
|
- run:
|
|
34
31
|
name: Bundle Install
|
|
35
32
|
command: bundle install
|
|
36
33
|
- run:
|
|
37
34
|
name: RSpec
|
|
38
35
|
command: bundle exec rspec
|
|
39
|
-
- run:
|
|
40
|
-
name: Coverage Test Report
|
|
41
|
-
command: cc-test-reporter after-build --exit-code $?
|
|
42
36
|
checks:
|
|
43
37
|
docker:
|
|
44
|
-
- image: darthjee/
|
|
38
|
+
- image: darthjee/circleci_ruby_331:1.0.1
|
|
45
39
|
environment:
|
|
46
40
|
PROJECT: tarquinn
|
|
47
41
|
steps:
|
|
@@ -49,12 +43,24 @@ jobs:
|
|
|
49
43
|
- run:
|
|
50
44
|
name: Bundle Install
|
|
51
45
|
command: bundle install
|
|
46
|
+
- run:
|
|
47
|
+
name: Rubocop
|
|
48
|
+
command: rubocop
|
|
49
|
+
- run:
|
|
50
|
+
name: Yardstick coverage check
|
|
51
|
+
command: bundle exec rake verify_measurements
|
|
52
52
|
- run:
|
|
53
53
|
name: Check version documentation
|
|
54
54
|
command: check_readme.sh
|
|
55
|
+
- run:
|
|
56
|
+
name: Rubycritcs check
|
|
57
|
+
command: rubycritic.sh
|
|
58
|
+
- run:
|
|
59
|
+
name: Check unit tests
|
|
60
|
+
command: check_specs
|
|
55
61
|
build-and-release:
|
|
56
62
|
docker:
|
|
57
|
-
- image: darthjee/
|
|
63
|
+
- image: darthjee/circleci_ruby_331:1.0.1
|
|
58
64
|
environment:
|
|
59
65
|
PROJECT: tarquinn
|
|
60
66
|
steps:
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# GitHub Copilot Instructions for Tarquinn
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
Tarquinn is a Ruby gem that provides generic redirection control for Rails controllers.
|
|
6
|
+
It is implemented as an `ActiveSupport::Concern` that adds `before_action` hooks and
|
|
7
|
+
class-level DSL methods (`redirection_rule`, `skip_redirection`, `skip_redirection_rule`)
|
|
8
|
+
to any Rails controller.
|
|
9
|
+
|
|
10
|
+
Key components:
|
|
11
|
+
|
|
12
|
+
- **`Tarquinn`** – The main concern included in controllers; sets up `before_action :perform_redirection`.
|
|
13
|
+
- **`Tarquinn::ClassMethods`** – DSL methods added to controller classes.
|
|
14
|
+
- **`Tarquinn::RequestHandlerBuilder`** – Accumulates redirection configurations for a controller class.
|
|
15
|
+
- **`Tarquinn::RequestHandler`** – Processes a single request, iterating over configs to find the first matching redirect.
|
|
16
|
+
- **`Tarquinn::RedirectionHandler`** – Evaluates one redirection config (conditions + skip rules) for a request.
|
|
17
|
+
- **`Tarquinn::RedirectionConfig`** – Holds the data for a single redirection rule (blocks, skip blocks, redirect target).
|
|
18
|
+
- **`Tarquinn::Condition`** – Wraps a single condition (method name or block) used in redirection/skip evaluation.
|
|
19
|
+
- **`Tarquinn::Controller`** – Thin wrapper around the Rails controller instance, used by handlers.
|
|
20
|
+
|
|
21
|
+
## Redirection Rules Data Flow
|
|
22
|
+
|
|
23
|
+
### How It Works
|
|
24
|
+
|
|
25
|
+
1. A controller includes `Tarquinn` (an `ActiveSupport::Concern`), which:
|
|
26
|
+
- Extends the controller with `Tarquinn::ClassMethods`, making the DSL methods available.
|
|
27
|
+
- Registers a `before_action :perform_redirection` that runs on every request.
|
|
28
|
+
|
|
29
|
+
2. During a request, `perform_redirection` delegates to `Tarquinn::RequestHandler`, which
|
|
30
|
+
iterates over all registered `Tarquinn::RedirectionConfig` objects (in definition order)
|
|
31
|
+
and applies the **first** rule whose conditions are satisfied.
|
|
32
|
+
|
|
33
|
+
3. Each rule is evaluated by `Tarquinn::RedirectionHandler`:
|
|
34
|
+
- All condition methods and/or the optional block are evaluated against the current
|
|
35
|
+
controller instance.
|
|
36
|
+
- If **any** condition returns a truthy value the rule fires and the controller redirects
|
|
37
|
+
to the path returned by the rule's target method.
|
|
38
|
+
- Skip conditions (registered via `skip_redirection` or `skip_redirection_rule`) are
|
|
39
|
+
checked first; if any skip condition is truthy the rule is bypassed entirely.
|
|
40
|
+
|
|
41
|
+
### Defining a Redirection Rule — `redirection_rule`
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
redirection_rule <rule_name>, *<condition_methods>, &<block>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
| Argument | Description |
|
|
48
|
+
|---------------------|----------------------------------------------------------------------------------------------|
|
|
49
|
+
| `rule_name` | Symbol. Also the name of the controller method that returns the redirect path. |
|
|
50
|
+
| `condition_methods` | Zero or more symbol method names. Each is called on the controller; truthy → rule fires. |
|
|
51
|
+
| `block` | Optional. Evaluated in the context of the controller; truthy → rule fires. |
|
|
52
|
+
|
|
53
|
+
**Evaluation**: the rule fires when **any** condition method **or** the block returns truthy.
|
|
54
|
+
|
|
55
|
+
#### Example 1 — block-based rule
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
redirection_rule :redirect_home { params[:secret_key] != '12345' }
|
|
59
|
+
|
|
60
|
+
def redirect_home
|
|
61
|
+
home_path
|
|
62
|
+
end
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Redirects to `home_path` if `secret_key` is absent or different from `'12345'`.
|
|
66
|
+
|
|
67
|
+
#### Example 2 — method-based rule
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
redirection_rule :redirect_home, :misses_secret_key
|
|
71
|
+
|
|
72
|
+
def redirect_home
|
|
73
|
+
home_path
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def misses_secret_key
|
|
77
|
+
params[:secret_key] != '12345'
|
|
78
|
+
end
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Same behaviour as Example 1, but the condition is extracted into a dedicated method.
|
|
82
|
+
|
|
83
|
+
### Skipping a Rule for Specific Actions — `skip_redirection`
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
skip_redirection <rule_name>, *<actions>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Prevents the named rule from running for the listed controller actions.
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
skip_redirection :redirect_home, :index
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The `index` action is not affected by the `redirect_home` rule; all other actions still are.
|
|
96
|
+
|
|
97
|
+
### Skipping a Rule Under a Condition — `skip_redirection_rule`
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
skip_redirection_rule <rule_name>, *<condition_methods>, &<block>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Registers a skip condition for a rule. When the condition is truthy the rule is bypassed,
|
|
104
|
+
regardless of the action.
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
skip_redirection_rule :redirect_home { params[:admin_key] == '9999' }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The `redirect_home` rule does not fire when the correct admin key is provided.
|
|
111
|
+
|
|
112
|
+
### Passing Options to Redirection Rules
|
|
113
|
+
|
|
114
|
+
You can pass options to `redirection_rule` to control advanced behavior. Currently, the main supported option is `domain`, which enables cross-domain redirection.
|
|
115
|
+
|
|
116
|
+
| Option | Description |
|
|
117
|
+
|----------|---------------------------------------------------------------------------------------------|
|
|
118
|
+
| `domain` | String. If set, allows redirection to the specified domain (cross-domain). If not set, only same-host redirection is allowed. |
|
|
119
|
+
|
|
120
|
+
#### Example — domain-based rule
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
redirection_rule :redirect_external, domain: 'example.com' do
|
|
124
|
+
params[:should_redirect]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def redirect_external
|
|
128
|
+
'/external_path'
|
|
129
|
+
end
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This will only allow redirection to `https://example.com/external_path` because the domain option is set to `'example.com'`.
|
|
133
|
+
|
|
134
|
+
## Language
|
|
135
|
+
|
|
136
|
+
All code, comments, documentation, commit messages, and PR descriptions must be written in **English**.
|
|
137
|
+
|
|
138
|
+
## Coding Standards
|
|
139
|
+
|
|
140
|
+
### General Style
|
|
141
|
+
|
|
142
|
+
- Follow the existing RuboCop configuration (`.rubocop.yml` / `.rubocop_todo.yml`).
|
|
143
|
+
- Use `# frozen_string_literal: true` at the top of every Ruby file.
|
|
144
|
+
- Keep methods small and focused (Sandi Metz style): aim for methods under 5 lines.
|
|
145
|
+
- Keep classes small with clear, single responsibilities and explicit object boundaries.
|
|
146
|
+
- Avoid deeply nested conditionals; extract guard clauses or helper methods.
|
|
147
|
+
- Use `private` / `attr_reader` to hide implementation details.
|
|
148
|
+
- Use `delegate` (ActiveSupport) instead of manual forwarding where it improves readability.
|
|
149
|
+
|
|
150
|
+
### Documentation
|
|
151
|
+
|
|
152
|
+
- Add **YARD** documentation to all public classes, modules, and methods.
|
|
153
|
+
- Non-obvious private methods should also have short YARD comments.
|
|
154
|
+
- Always include `@param`, `@return`, and `@api public` / `@api private` tags where applicable.
|
|
155
|
+
- Ensure documentation coverage stays at or above the threshold in `config/yardstick.yml`.
|
|
156
|
+
|
|
157
|
+
### Tests
|
|
158
|
+
|
|
159
|
+
- Write **RSpec** tests using the patterns established in `spec/`.
|
|
160
|
+
- Keep tests small and focused — one behaviour per example.
|
|
161
|
+
- Use `let` definitions that are **reusable** and **avoid duplication** across contexts.
|
|
162
|
+
- Prefer `context` blocks to describe different input/state scenarios.
|
|
163
|
+
- Avoid `before` blocks that do more than one thing; split them if needed.
|
|
164
|
+
- Use `shared_examples` or `shared_context` when the same setup appears in multiple groups.
|
|
165
|
+
|
|
166
|
+
## CI Checks
|
|
167
|
+
|
|
168
|
+
The CI pipeline (`.circleci/config.yml`) runs the following checks on every push.
|
|
169
|
+
Reproduce them locally before opening a PR:
|
|
170
|
+
|
|
171
|
+
| CI Step | Local Command |
|
|
172
|
+
|-------------------------------|--------------------------------------------------|
|
|
173
|
+
| Run tests | `bundle exec rspec` |
|
|
174
|
+
| RuboCop lint | `bundle exec rubocop` |
|
|
175
|
+
| YARD documentation coverage | `bundle exec rake verify_measurements` |
|
|
176
|
+
| RubyCritic quality check | `rubycritic.sh` (or `bundle exec rubycritic`) |
|
|
177
|
+
|
|
178
|
+
All checks must pass before a PR can be merged.
|
|
179
|
+
|
|
180
|
+
## Docker / Local Development
|
|
181
|
+
|
|
182
|
+
To run the project locally, use the Makefile targets:
|
|
183
|
+
|
|
184
|
+
- Build Docker image: `make build`
|
|
185
|
+
- Start development environment: `make dev`
|
|
186
|
+
- Run tests: `make tests`
|
|
187
|
+
|
|
188
|
+
See the [Developer Guide](../README.md#developer-guide) in the README for further instructions.
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
AllCops:
|
|
4
|
+
TargetRubyVersion: 3.3
|
|
5
|
+
NewCops: enable
|
|
6
|
+
|
|
7
|
+
Lint/BooleanSymbol:
|
|
8
|
+
Enabled: false
|
|
9
|
+
|
|
10
|
+
Lint/EmptyBlock:
|
|
11
|
+
Exclude:
|
|
12
|
+
- spec/dummy/db/schema.rb
|
|
13
|
+
|
|
14
|
+
Metrics/BlockLength:
|
|
15
|
+
Exclude:
|
|
16
|
+
- spec/**/*_spec.rb
|
|
17
|
+
|
|
18
|
+
Lint/MissingSuper:
|
|
19
|
+
Enabled: false
|
|
20
|
+
|
|
21
|
+
Lint/ScriptPermission:
|
|
22
|
+
Exclude:
|
|
23
|
+
- spec/dummy/bin/*
|
|
24
|
+
|
|
25
|
+
Naming/BlockForwarding:
|
|
26
|
+
Enabled: false
|
|
27
|
+
|
|
28
|
+
Style/ArgumentsForwarding:
|
|
29
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2024-07-10 16:10:57 UTC using RuboCop version 1.59.0.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 9
|
|
10
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
11
|
+
# AllowedMethods: refine
|
|
12
|
+
Metrics/BlockLength:
|
|
13
|
+
Max: 87
|
data/Dockerfile
CHANGED
data/Gemfile
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
source 'https://rubygems.org'
|
|
2
4
|
|
|
5
|
+
gem 'bundler', '~> 2.5.13'
|
|
6
|
+
gem 'pry', '~> 0.14.2'
|
|
7
|
+
gem 'pry-nav', '~> 1.0.0'
|
|
8
|
+
gem 'rails', '7.2.3'
|
|
9
|
+
gem 'rake', '~> 13.1.0'
|
|
10
|
+
gem 'rspec', '~> 3.12.0'
|
|
11
|
+
gem 'rspec-rails', '6.1.1'
|
|
12
|
+
gem 'rubycritic', '4.9.1'
|
|
13
|
+
gem 'simplecov', '~> 0.22.0'
|
|
14
|
+
gem 'sqlite3', '1.4.2'
|
|
15
|
+
gem 'yard', '0.9.38'
|
|
16
|
+
gem 'yardstick', '0.9.9'
|
|
17
|
+
|
|
3
18
|
gemspec
|
data/Makefile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.PHONY: build dev tests
|
|
2
|
+
|
|
3
|
+
PROJECT?=tarquinn
|
|
4
|
+
IMAGE?=$(PROJECT)
|
|
5
|
+
BASE_IMAGE?=$(DOCKER_ID_USER)/$(PROJECT)-base
|
|
6
|
+
DOCKER_FILE_BASE=Dockerfile.$(PROJECT)-base
|
|
7
|
+
|
|
8
|
+
all:
|
|
9
|
+
@echo "Usage:"
|
|
10
|
+
@echo " make build\n Build docker image for $(PROJECT)"
|
|
11
|
+
@echo " make dev\n Run development environment for $(PROJECT)"
|
|
12
|
+
@echo " make tests\n Run tests for $(PROJECT)"
|
|
13
|
+
|
|
14
|
+
build:
|
|
15
|
+
docker build -f Dockerfile.$(PROJECT) . -t $(IMAGE) -t $(PUSH_IMAGE):latest
|
|
16
|
+
|
|
17
|
+
tests:
|
|
18
|
+
docker-compose run $(PROJECT)_tests /bin/bash
|
|
19
|
+
|
|
20
|
+
dev:
|
|
21
|
+
docker-compose run $(PROJECT) /bin/bash
|
data/README.md
CHANGED
|
@@ -2,8 +2,6 @@ Tarquinn
|
|
|
2
2
|
========
|
|
3
3
|
[](https://circleci.com/gh/darthjee/tarquinn)
|
|
4
4
|
[](https://codeclimate.com/github/darthjee/tarquinn)
|
|
5
|
-
[](https://codeclimate.com/github/darthjee/tarquinn/coverage)
|
|
6
|
-
[](https://codeclimate.com/github/darthjee/tarquinn)
|
|
7
5
|
[](https://badge.fury.io/rb/tarquinn)
|
|
8
6
|
[](http://inch-ci.org/github/darthjee/tarquinn)
|
|
9
7
|
|
|
@@ -11,10 +9,14 @@ Tarquinn
|
|
|
11
9
|
|
|
12
10
|
Yard Documentation
|
|
13
11
|
-------------------
|
|
14
|
-
[https://www.rubydoc.info/gems/tarquinn/0.
|
|
12
|
+
[https://www.rubydoc.info/gems/tarquinn/0.4.0](https://www.rubydoc.info/gems/tarquinn/0.4.0)
|
|
15
13
|
|
|
16
14
|
This gem makes easier to controll generic redirection
|
|
17
15
|
|
|
16
|
+
Current Release: [0.4.0](https://github.com/darthjee/tarquinn/tree/0.4.0)
|
|
17
|
+
|
|
18
|
+
Next Version [0.4.1](https://github.com/darthjee/tarquinn/compare/0.4.0...main)
|
|
19
|
+
|
|
18
20
|
Getting started
|
|
19
21
|
---------------
|
|
20
22
|
1. Add Tarquinn to your `Gemfile` and `bundle install`:
|
|
@@ -56,3 +58,108 @@ Getting started
|
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
60
|
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Developer Guide
|
|
65
|
+
|
|
66
|
+
### How It Works
|
|
67
|
+
|
|
68
|
+
Tarquinn is a Rails concern that adds a `before_action` to any controller it is included in.
|
|
69
|
+
On each request the action chain works as follows:
|
|
70
|
+
|
|
71
|
+
1. `before_action :perform_redirection` is triggered automatically.
|
|
72
|
+
2. A `RequestHandlerBuilder` (stored per controller class) holds all registered redirection
|
|
73
|
+
configs (`redirection_rule` / `skip_redirection` / `skip_redirection_rule` calls).
|
|
74
|
+
3. At request time, `RequestHandlerBuilder` creates a `RequestHandler` for the current request.
|
|
75
|
+
4. `RequestHandler` iterates over every `RedirectionConfig` and checks whether a redirect
|
|
76
|
+
should fire via `RedirectionHandler`.
|
|
77
|
+
5. `RedirectionHandler` evaluates skip conditions first; if none match, it evaluates redirect
|
|
78
|
+
conditions. The first config that requires a redirect triggers `redirect_to`.
|
|
79
|
+
|
|
80
|
+
### Running Locally with Docker Compose
|
|
81
|
+
|
|
82
|
+
> Prerequisites: Docker and Docker Compose installed.
|
|
83
|
+
|
|
84
|
+
**Build the image**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
docker compose build base_build
|
|
88
|
+
# or
|
|
89
|
+
### Running Locally with Docker Compose and Makefile
|
|
90
|
+
|
|
91
|
+
| `make build` | Build the Docker image |
|
|
92
|
+
|
|
93
|
+
| `make dev` | Open an interactive bash shell inside the container |
|
|
94
|
+
|
|
95
|
+
| `make test` | Run RSpec tests inside the container |
|
|
96
|
+
make build
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Run the test suite**
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
make tests
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Open an interactive shell inside the container**
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
make dev
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Makefile Targets
|
|
112
|
+
|
|
113
|
+
| Target | Description |
|
|
114
|
+
|--------------|---------------------------------------------|
|
|
115
|
+
| `make build` | Build Docker image for the project |
|
|
116
|
+
| `make dev` | Run development environment (bash shell) |
|
|
117
|
+
| `make tests` | Run tests (RSpec) in the container |
|
|
118
|
+
|
|
119
|
+
### CI Checks
|
|
120
|
+
|
|
121
|
+
The CircleCI pipeline (`.circleci/config.yml`) runs three jobs:
|
|
122
|
+
|
|
123
|
+
| Job | What it does |
|
|
124
|
+
|-----------------------|------------------------------------------------------------------------------------------|
|
|
125
|
+
| `test` | `bundle exec rspec` + uploads coverage report |
|
|
126
|
+
| `checks` | RuboCop, Yardstick coverage, README version check, RubyCritic, unit-test structure check |
|
|
127
|
+
| `build-and-release` | Builds and pushes the gem (tags only, on `master`) |
|
|
128
|
+
|
|
129
|
+
Run the same checks locally before opening a PR:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Tests
|
|
133
|
+
bundle exec rspec
|
|
134
|
+
|
|
135
|
+
# RuboCop
|
|
136
|
+
bundle exec rubocop
|
|
137
|
+
|
|
138
|
+
# YARD documentation coverage
|
|
139
|
+
bundle exec rake verify_measurements
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Domain Option for Cross-Domain Redirection
|
|
143
|
+
|
|
144
|
+
You can specify a `domain` option in your `redirection_rule` to allow cross-domain redirection. When set, the redirection will be allowed to external hosts and the specified domain will be used for validation.
|
|
145
|
+
|
|
146
|
+
**Example:**
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
class ExternalRedirectController < ApplicationController
|
|
150
|
+
include Tarquinn
|
|
151
|
+
|
|
152
|
+
redirection_rule :redirect_external, domain: 'example.com' do
|
|
153
|
+
params[:should_redirect]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def redirect_external
|
|
159
|
+
'/external_path'
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- If `domain` is not set, redirection is only allowed for the same host.
|
|
165
|
+
- If `domain` is set, redirection to the specified domain is allowed.
|
data/Rakefile
CHANGED
data/config/rubycritc.rb
ADDED
data/config/yardstick.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yardstick/rake/measurement'
|
|
4
|
+
require 'yardstick/rake/verify'
|
|
5
|
+
require 'yaml'
|
|
6
|
+
|
|
7
|
+
options = YAML.load_file('config/yardstick.yml')
|
|
8
|
+
|
|
9
|
+
Yardstick::Rake::Measurement.new(:yardstick_measure, options) do |measurement|
|
|
10
|
+
measurement.output = 'measurement/report.txt'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
Yardstick::Rake::Verify.new(:verify_measurements, options)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
threshold: 100.0
|
|
2
|
+
require_exact_threshold: false
|
|
3
|
+
rules:
|
|
4
|
+
ApiTag::Presence:
|
|
5
|
+
enabled: true
|
|
6
|
+
exclude: []
|
|
7
|
+
ApiTag::Inclusion:
|
|
8
|
+
enabled: true
|
|
9
|
+
exclude: []
|
|
10
|
+
ApiTag::ProtectedMethod:
|
|
11
|
+
enabled: true
|
|
12
|
+
exclude: []
|
|
13
|
+
ApiTag::PrivateMethod:
|
|
14
|
+
enabled: true
|
|
15
|
+
exclude: []
|
|
16
|
+
ExampleTag:
|
|
17
|
+
enabled: true
|
|
18
|
+
exclude:
|
|
19
|
+
- Tarquinn.redirection_rule
|
|
20
|
+
- Tarquinn.skip_redirection
|
|
21
|
+
- Tarquinn.skip_redirection_rule
|
|
22
|
+
ReturnTag:
|
|
23
|
+
enabled: true
|
|
24
|
+
exclude:
|
|
25
|
+
- Tarquinn.redirection_rule
|
|
26
|
+
- Tarquinn.skip_redirection
|
|
27
|
+
- Tarquinn.skip_redirection_rule
|
|
28
|
+
- Tarquinn.redirector_builder
|
|
29
|
+
- Tarquinn#perform_redirection
|
|
30
|
+
- Tarquinn::RedirectionHandler#initialize
|
|
31
|
+
- Tarquinn::RequestHandler#initialize
|
|
32
|
+
- Tarquinn::RedirectionConfigBuilder#initialize
|
|
33
|
+
- Tarquinn::Condition::ProcRunner#initialize
|
|
34
|
+
- Tarquinn::Condition::MethodCaller#initialize
|
|
35
|
+
- Tarquinn::Condition::ActionChecker#initialize
|
|
36
|
+
- Tarquinn::Exception::RedirectionAlreadyDefined#initialize
|
|
37
|
+
Summary::Presence:
|
|
38
|
+
enabled: true
|
|
39
|
+
exclude:
|
|
40
|
+
- Tarquinn::RedirectionHandler#initialize
|
|
41
|
+
- Tarquinn::RequestHandler#initialize
|
|
42
|
+
- Tarquinn::RedirectionConfigBuilder#initialize
|
|
43
|
+
- Tarquinn::Condition::ProcRunner#initialize
|
|
44
|
+
- Tarquinn::Condition::MethodCaller#initialize
|
|
45
|
+
- Tarquinn::Condition::ActionChecker#initialize
|
|
46
|
+
- Tarquinn::Exception::RedirectionAlreadyDefined#initialize
|
|
47
|
+
Summary::Length:
|
|
48
|
+
enabled: true
|
|
49
|
+
exclude: []
|
|
50
|
+
Summary::Delimiter:
|
|
51
|
+
enabled: true
|
|
52
|
+
exclude: []
|
|
53
|
+
Summary::SingleLine:
|
|
54
|
+
enabled: true
|
|
55
|
+
exclude: []
|
data/docker-compose.yml
CHANGED