phlexible 3.1.1 → 3.2.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/.claude/agents/rubocop-reviewer.md +31 -0
- data/.claude/hooks/protect-files.sh +11 -0
- data/.claude/hooks/rubocop-check.sh +18 -0
- data/.claude/settings.json +27 -0
- data/.claude/skills/test/SKILL.md +21 -0
- data/.rubocop.yml +1 -0
- data/CLAUDE.md +80 -0
- data/README.md +116 -19
- data/gemfiles/phlex1_rails7.gemfile.lock +2 -2
- data/gemfiles/phlex1_rails8.gemfile.lock +2 -2
- data/gemfiles/phlex2_rails7.gemfile.lock +2 -2
- data/gemfiles/phlex2_rails8.gemfile.lock +2 -2
- data/lib/phlexible/callbacks.rb +12 -0
- data/lib/phlexible/rails/auto_layout.rb +91 -0
- data/lib/phlexible/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ba0c7764b691fdb2ea92f5d8ef9389e1eb31bd97483f210e1b5e8f7c9fcd0c09
|
|
4
|
+
data.tar.gz: 80b397992cf20e11e9e971d744f6a7cea5bfa56a1b1186c4a629ec04bb836624
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 375b7283fa50d41cf9e94bdc131f5faa469d73f67c8f2f8fdf34badb6c722edf193c9d9d64ffb7fee6f565d7d2a7a853a91f2d3f4ffed901e8d8b4421b967e9b
|
|
7
|
+
data.tar.gz: b5fba4880d3a63faca0e67fe09a422a34b12b322ae6dd73ebca5b3a4b0137db0b80f177df306f18b27942a9d57fcd1501da6a2b8d9bafc5c3f6899fa729f4b90
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
You are a RuboCop style reviewer for the Phlexible Ruby gem.
|
|
2
|
+
|
|
3
|
+
## Project Style Rules
|
|
4
|
+
|
|
5
|
+
This project enforces strict RuboCop rules. Review changed Ruby files and flag violations.
|
|
6
|
+
|
|
7
|
+
### Disabled Syntax (hard errors)
|
|
8
|
+
- **No `unless`** — use `if !` or negated conditions instead
|
|
9
|
+
- **No `and` / `or` / `not`** — use `&&` / `||` / `!` instead
|
|
10
|
+
- **No numbered parameters** (`_1`, `_2`) — use named block parameters
|
|
11
|
+
|
|
12
|
+
### Formatting
|
|
13
|
+
- **Max line length**: 100 characters
|
|
14
|
+
- **Private method indentation**: `indented_internal_methods` — private/protected methods are indented one extra level beneath the access modifier
|
|
15
|
+
- **String literals**: prefer double quotes
|
|
16
|
+
|
|
17
|
+
### Enabled Plugins
|
|
18
|
+
Review against these RuboCop plugins:
|
|
19
|
+
- `rubocop-rails`
|
|
20
|
+
- `rubocop-minitest`
|
|
21
|
+
- `rubocop-performance`
|
|
22
|
+
- `rubocop-packaging`
|
|
23
|
+
- `rubocop-rake`
|
|
24
|
+
|
|
25
|
+
## Instructions
|
|
26
|
+
|
|
27
|
+
1. Read the files that were changed (use `jj diff --name-only` or check recent edits).
|
|
28
|
+
2. For each `.rb` file, check for violations of the rules above.
|
|
29
|
+
3. Run `bundle exec rubocop -P --fail-level C --force-exclusion <file>` to confirm.
|
|
30
|
+
4. Report any issues found, grouped by file, with the specific rule violated and a suggested fix.
|
|
31
|
+
5. If no issues are found, confirm the code passes review.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
INPUT=$(cat)
|
|
3
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')
|
|
4
|
+
|
|
5
|
+
# Block edits to lock files and generated gemfiles
|
|
6
|
+
if [[ "$FILE_PATH" == *.lock ]] || [[ "$FILE_PATH" == */gemfiles/*.gemfile ]]; then
|
|
7
|
+
echo "Do not edit lock files or generated Appraisal gemfiles directly." >&2
|
|
8
|
+
exit 2
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
exit 0
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
INPUT=$(cat)
|
|
3
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')
|
|
4
|
+
|
|
5
|
+
# Only lint Ruby files
|
|
6
|
+
if [[ "$FILE_PATH" != *.rb ]]; then
|
|
7
|
+
exit 0
|
|
8
|
+
fi
|
|
9
|
+
|
|
10
|
+
RESULT=$(bundle exec rubocop -P --fail-level C --force-exclusion "$FILE_PATH" 2>&1)
|
|
11
|
+
EXIT_CODE=$?
|
|
12
|
+
|
|
13
|
+
if [ $EXIT_CODE -ne 0 ]; then
|
|
14
|
+
echo "$RESULT" >&2
|
|
15
|
+
exit 2
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
exit 0
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Edit|Write",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"PostToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "Edit|Write",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/rubocop-check.sh",
|
|
21
|
+
"timeout": 30
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test
|
|
3
|
+
description: Run tests for the Phlexible gem across the Appraisal matrix
|
|
4
|
+
arguments:
|
|
5
|
+
- name: appraisal
|
|
6
|
+
description: "Appraisal to test: phlex1-rails7, phlex1-rails8, phlex2-rails7, phlex2-rails8, or 'all' (default: phlex2-rails8)"
|
|
7
|
+
default: "phlex2-rails8"
|
|
8
|
+
- name: file
|
|
9
|
+
description: "Optional test file path, or path:line for a single test"
|
|
10
|
+
disable-model-invocation: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Run Phlexible tests using the Appraisal gem for multi-version testing.
|
|
14
|
+
|
|
15
|
+
## Instructions
|
|
16
|
+
|
|
17
|
+
1. If `appraisal` is "all", run: `bundle exec appraisal rails test {file}`
|
|
18
|
+
2. Otherwise, run: `bundle exec appraisal {appraisal} rails test {file}`
|
|
19
|
+
3. If no `file` is given, omit it to run the full suite for that appraisal.
|
|
20
|
+
4. Report pass/fail/skip counts from the test output.
|
|
21
|
+
5. If tests fail, summarise which tests failed and why.
|
data/.rubocop.yml
CHANGED
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Phlexible is a Ruby gem providing helpers and extensions for [Phlex](https://phlex.fun) views in Rails applications. It supports Phlex 1.x and 2.x across Rails 7.2+ and Ruby >= 3.3.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
### Tests
|
|
12
|
+
|
|
13
|
+
Tests use Minitest (with maxitest, minitest-focus, minitest-spec-rails). The project uses [Appraisal](https://github.com/thoughtbot/appraisal) to test across multiple Phlex/Rails version combinations defined in `Appraisals`.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Run all tests across all appraisals (phlex1/rails7, phlex1/rails8, phlex2/rails7, phlex2/rails8)
|
|
17
|
+
bundle exec appraisal rails test
|
|
18
|
+
|
|
19
|
+
# Run tests for a specific appraisal
|
|
20
|
+
bundle exec appraisal phlex2/rails8 rails test
|
|
21
|
+
|
|
22
|
+
# Run a single test file
|
|
23
|
+
bundle exec appraisal phlex2/rails8 rails test test/phlexible/alias_view_test.rb
|
|
24
|
+
|
|
25
|
+
# Run a single test by line number
|
|
26
|
+
bundle exec appraisal phlex2/rails8 rails test test/phlexible/alias_view_test.rb:10
|
|
27
|
+
|
|
28
|
+
# Focus a single test (add `focus` before the test method, provided by minitest-focus)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Lint
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bundle exec rubocop -P --fail-level C
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Setup
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bin/setup
|
|
41
|
+
bundle exec appraisal install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Architecture
|
|
45
|
+
|
|
46
|
+
All source code lives under `lib/phlexible/`. Autoloading is handled by Zeitwerk (`Zeitwerk::Loader.for_gem` in `lib/phlexible.rb`).
|
|
47
|
+
|
|
48
|
+
### Module Organization
|
|
49
|
+
|
|
50
|
+
Modules are split into two categories:
|
|
51
|
+
|
|
52
|
+
**Standalone modules** (no Rails dependency):
|
|
53
|
+
- `Phlexible::AliasView` — `extend` in a view to create shortcut methods for rendering other components
|
|
54
|
+
- `Phlexible::Callbacks` — `include` for ActiveSupport::Callbacks-based `before_template`/`after_template`/`around_template` hooks. Also provides `before_layout`/`after_layout`/`around_layout` when used with `AutoLayout`.
|
|
55
|
+
- `Phlexible::PageTitle` — `include` for hierarchical page title management across nested views
|
|
56
|
+
- `Phlexible::ProcessAttributes` — `extend` to intercept and modify HTML element attributes before rendering (Phlex 2.x only; Phlex 1.x has this built-in). Prepends wrappers onto all StandardElements, VoidElements, and custom `register_element` methods.
|
|
57
|
+
|
|
58
|
+
**Rails-specific modules** (`lib/phlexible/rails/`):
|
|
59
|
+
- `ActionController::ImplicitRender` — convention-based automatic Phlex view rendering (resolves `UsersController#index` to `Users::IndexView`)
|
|
60
|
+
- `ControllerVariables` — explicit interface to expose controller instance variables to Phlex views via `controller_variable` class method
|
|
61
|
+
- `AElement` — overrides `a` tag to pass `href` through Rails `url_for`
|
|
62
|
+
- `ButtonTo` — Phlex component replacing Rails `button_to` helper
|
|
63
|
+
- `Responder` — integration with the [Responders](https://github.com/heartcombo/responders) gem
|
|
64
|
+
- `AutoLayout` — automatic layout wrapping based on view namespace conventions (e.g., `Views::Admin::Index` resolves to `Views::Layouts::Admin`). Includes `ViewAssigns` and `Callbacks`. Layout resolution is cached per class in production.
|
|
65
|
+
- `MetaTags` / `MetaTagsComponent` — define meta tags in controllers, render in views
|
|
66
|
+
|
|
67
|
+
### Key Patterns
|
|
68
|
+
|
|
69
|
+
- Modules use `extend` (AliasView, ProcessAttributes) or `include` (Callbacks, PageTitle, ControllerVariables) depending on whether they add class-level or instance-level behavior.
|
|
70
|
+
- `ProcessAttributes` uses `class_eval` with string interpolation to dynamically wrap every HTML element method — be careful when modifying this.
|
|
71
|
+
- `ControllerVariables` depends on both `ViewAssigns` and `Callbacks` internally.
|
|
72
|
+
- `AutoLayout` depends on both `ViewAssigns` and `Callbacks`. Layout resolution is cached in production via `resolved_layout` class method; use `reset_resolved_layout!` to clear.
|
|
73
|
+
- Tests use a Rails dummy app at `test/dummy/` for integration testing with real controllers/routes.
|
|
74
|
+
|
|
75
|
+
## Style
|
|
76
|
+
|
|
77
|
+
- RuboCop enforced with `rubocop-rails`, `rubocop-minitest`, `rubocop-performance`, `rubocop-packaging`, `rubocop-rake`.
|
|
78
|
+
- `unless`, `and`/`or`/`not`, and numbered parameters are **disabled** via `rubocop-disable_syntax`.
|
|
79
|
+
- `indented_internal_methods` indentation style (private methods indented one extra level).
|
|
80
|
+
- Max line length: 100 characters.
|
data/README.md
CHANGED
|
@@ -14,9 +14,7 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
|
14
14
|
|
|
15
15
|
## Usage
|
|
16
16
|
|
|
17
|
-
### Rails
|
|
18
|
-
|
|
19
|
-
#### `ActionController::ImplicitRender`
|
|
17
|
+
### `Rails::ActionController::ImplicitRender`
|
|
20
18
|
|
|
21
19
|
Adds support for default and `action_missing` rendering of Phlex views. So instead of this:
|
|
22
20
|
|
|
@@ -25,6 +23,10 @@ class UsersController
|
|
|
25
23
|
def index
|
|
26
24
|
render Views::Users::Index.new
|
|
27
25
|
end
|
|
26
|
+
|
|
27
|
+
def show
|
|
28
|
+
render Views::Users::Show.new
|
|
29
|
+
end
|
|
28
30
|
end
|
|
29
31
|
```
|
|
30
32
|
|
|
@@ -36,9 +38,9 @@ class UsersController
|
|
|
36
38
|
end
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
#### View Resolution
|
|
40
42
|
|
|
41
|
-
By default, views are resolved using the `phlex_view_path` method, which constructs a path based on the controller and action name. For example, `UsersController#index` will look for `Users::IndexView`.
|
|
43
|
+
By default, views are resolved using the `phlex_view_path` method, which constructs a path based on the controller and action name. For example, `UsersController#index` will look for `Views::Users::IndexView`.
|
|
42
44
|
|
|
43
45
|
You can customize this behavior by overriding `phlex_view_path` in your controller:
|
|
44
46
|
|
|
@@ -56,7 +58,7 @@ end
|
|
|
56
58
|
|
|
57
59
|
This would resolve `UsersController#index` to `Views::Users::Index` instead.
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
### `Callbacks`
|
|
60
62
|
|
|
61
63
|
While Phlex does have `before_template`, `after_template`, and `around_template` hooks, they must be defined as regular Ruby methods, meaning you have to always remember to call `super` when redefining any hook method.
|
|
62
64
|
|
|
@@ -82,9 +84,105 @@ end
|
|
|
82
84
|
|
|
83
85
|
You can still use the regular `before_template`, `after_template`, and `around_template` hooks as well, but I recommend that if you include this module, that you use callbacks instead.
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
When used with `Rails::AutoLayout`, layout callbacks (`before_layout`, `after_layout`, `around_layout`) are also available. See the `Rails::AutoLayout` section below.
|
|
88
|
+
|
|
89
|
+
### `Rails::AutoLayout`
|
|
90
|
+
|
|
91
|
+
Automatically wraps Phlex views in a layout component based on namespace conventions. Include this module in your view classes to enable automatic layout resolution.
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
class Views::Admin::Index < Phlex::HTML
|
|
95
|
+
include Phlexible::Rails::AutoLayout
|
|
96
|
+
|
|
97
|
+
def view_template
|
|
98
|
+
span { 'admin index' }
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Layout Resolution
|
|
104
|
+
|
|
105
|
+
Layouts are resolved by mapping the view's namespace to a layout class under `Views::Layouts::`. For example:
|
|
106
|
+
|
|
107
|
+
| View class | Layout resolved |
|
|
108
|
+
|---|---|
|
|
109
|
+
| `Views::Admin::Index` | `Views::Layouts::Admin` |
|
|
110
|
+
| `Views::Admin::Users::Show` | `Views::Layouts::Admin::Users` (falls back to `Views::Layouts::Admin` if not found) |
|
|
111
|
+
| `Views::Dashboard::Index` | `Views::Layouts::Application` (default fallback) |
|
|
112
|
+
|
|
113
|
+
Layout classes receive the view instance as a constructor argument and yield the view content:
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
class Views::Layouts::Admin < Phlex::HTML
|
|
117
|
+
def initialize(view)
|
|
118
|
+
@view = view
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def view_template(&block)
|
|
122
|
+
div(id: 'admin-layout', &block)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Controller-Assigned Layouts
|
|
128
|
+
|
|
129
|
+
You can override automatic resolution by setting a `@layout` instance variable in your controller. The view must also include `ViewAssigns` (which `AutoLayout` includes automatically):
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
class AdminController < ApplicationController
|
|
133
|
+
def index
|
|
134
|
+
@layout = Views::Layouts::Custom
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### Configuration
|
|
140
|
+
|
|
141
|
+
Three class attributes control layout resolution:
|
|
142
|
+
|
|
143
|
+
| Attribute | Default | Description |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `auto_layout_view_prefix` | `'Views::'` | Only views matching this prefix get auto-layout. Set to `nil` to match all view classes. |
|
|
146
|
+
| `auto_layout_namespace` | `'Views::Layouts::'` | Namespace where layout classes are looked up. |
|
|
147
|
+
| `auto_layout_default` | `'Views::Layouts::Application'` | Fallback layout when no namespace match is found. Set to `nil` to render without a layout. |
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
class Views::Base < Phlex::HTML
|
|
151
|
+
include Phlexible::Rails::AutoLayout
|
|
152
|
+
|
|
153
|
+
self.auto_layout_view_prefix = 'Views::'
|
|
154
|
+
self.auto_layout_namespace = 'Views::Layouts::'
|
|
155
|
+
self.auto_layout_default = 'Views::Layouts::Application'
|
|
156
|
+
end
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### Layout Callbacks
|
|
160
|
+
|
|
161
|
+
When `Rails::AutoLayout` is included, `before_layout`, `after_layout`, and `around_layout` callbacks become available (provided by the `Callbacks` module):
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
class Views::Admin::Index < Phlex::HTML
|
|
165
|
+
include Phlexible::Rails::AutoLayout
|
|
166
|
+
|
|
167
|
+
before_layout :log_render
|
|
168
|
+
|
|
169
|
+
def view_template
|
|
170
|
+
span { 'admin index' }
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
private
|
|
86
174
|
|
|
87
|
-
|
|
175
|
+
def log_render
|
|
176
|
+
Rails.logger.info "Rendering with layout"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### Caching
|
|
182
|
+
|
|
183
|
+
Layout resolution is cached per class in production. In development (when `Rails.configuration.enable_reloading` is enabled), layouts are resolved fresh on each render. You can manually clear the cache with `reset_resolved_layout!`.
|
|
184
|
+
|
|
185
|
+
### `Rails::ControllerVariables`
|
|
88
186
|
|
|
89
187
|
> **NOTE:** Prior to **1.0.0**, this module was called `ControllerAttributes` with a very different API. This is no longer available since **1.0.0**.
|
|
90
188
|
|
|
@@ -102,7 +200,7 @@ class Views::Users::Index < Views::Base
|
|
|
102
200
|
end
|
|
103
201
|
```
|
|
104
202
|
|
|
105
|
-
|
|
203
|
+
#### Options
|
|
106
204
|
|
|
107
205
|
`controller_variable` accepts one or many symbols, or a hash of symbols to options.
|
|
108
206
|
|
|
@@ -127,9 +225,9 @@ end
|
|
|
127
225
|
|
|
128
226
|
Please note that defining a variable with the same name as an existing variable in the view will be overwritten.
|
|
129
227
|
|
|
130
|
-
|
|
228
|
+
### `Rails::Responder`
|
|
131
229
|
|
|
132
|
-
If you use [Responders](https://github.com/heartcombo/responders), Phlexible provides a responder to support implicit rendering similar to `ActionController::ImplicitRender` above. It will render the Phlex view using `respond_with` if one exists, and fall back to default rendering.
|
|
230
|
+
If you use [Responders](https://github.com/heartcombo/responders), Phlexible provides a responder to support implicit rendering similar to `Rails::ActionController::ImplicitRender` above. It will render the Phlex view using `respond_with` if one exists, and fall back to default rendering.
|
|
133
231
|
|
|
134
232
|
Just include it in your ApplicationResponder:
|
|
135
233
|
|
|
@@ -156,9 +254,9 @@ end
|
|
|
156
254
|
|
|
157
255
|
This responder requires the use of `ActionController::ImplicitRender`, so don't forget to include that in your `ApplicationController`.
|
|
158
256
|
|
|
159
|
-
If you use `ControllerVariables` in your view, and define a `resource` attribute, the responder will pass that to your view.
|
|
257
|
+
If you use `Rails::ControllerVariables` in your view, and define a `resource` attribute, the responder will pass that to your view.
|
|
160
258
|
|
|
161
|
-
|
|
259
|
+
### `Rails::AElement`
|
|
162
260
|
|
|
163
261
|
No need to call Rails `link_to` helper, when you can simply render an anchor tag directly with Phlex. But unfortunately that means you lose some of the magic that `link_to` provides. Especially the automatic resolution of URL's and Rails routes.
|
|
164
262
|
|
|
@@ -180,7 +278,7 @@ class MyView < Phlex::HTML
|
|
|
180
278
|
end
|
|
181
279
|
```
|
|
182
280
|
|
|
183
|
-
|
|
281
|
+
### `Rails::ButtonTo`
|
|
184
282
|
|
|
185
283
|
Generates a form containing a single button that submits to the URL created by the set of options.
|
|
186
284
|
|
|
@@ -198,7 +296,7 @@ The form submits a POST request by default. You can specify a different HTTP ver
|
|
|
198
296
|
Phlexible::Rails::ButtonTo.new(:root, method: :patch) { 'My Button' }
|
|
199
297
|
```
|
|
200
298
|
|
|
201
|
-
|
|
299
|
+
#### Options
|
|
202
300
|
|
|
203
301
|
- `:class` - Specify the HTML class name of the button (not the form).
|
|
204
302
|
- `:form_attributes` - Hash of HTML attributes for the form tag.
|
|
@@ -207,9 +305,7 @@ Phlexible::Rails::ButtonTo.new(:root, method: :patch) { 'My Button' }
|
|
|
207
305
|
- `:method` - Symbol of the HTTP verb. Supported verbs are :post (default), :get, :delete, :patch,
|
|
208
306
|
and :put.
|
|
209
307
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
> Available in **>= 1.0.0**
|
|
308
|
+
### `Rails::MetaTags`
|
|
213
309
|
|
|
214
310
|
A super simple way to define and render meta tags in your Phlex views. Just render the
|
|
215
311
|
`Phlexible::Rails::MetaTagsComponent` component in the head element of your page, and define the
|
|
@@ -269,12 +365,13 @@ class MyView < Phlex::HTML
|
|
|
269
365
|
end
|
|
270
366
|
```
|
|
271
367
|
|
|
272
|
-
### PageTitle
|
|
368
|
+
### `PageTitle`
|
|
273
369
|
|
|
274
370
|
Helper to assist in defining page titles within Phlex views. Also includes support for nested views, where each desendent view class will have its title prepended to the page title. Simply include *Phlexible::PageTitle* module and assign the title to the `page_title` class variable:
|
|
275
371
|
|
|
276
372
|
```ruby
|
|
277
373
|
class MyView
|
|
374
|
+
include Phlexible::PageTitle
|
|
278
375
|
self.page_title = 'My Title'
|
|
279
376
|
end
|
|
280
377
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
phlexible (3.
|
|
4
|
+
phlexible (3.1.1)
|
|
5
5
|
phlex (>= 1.10.0, < 3.0.0)
|
|
6
6
|
phlex-rails (>= 1.2.0, < 3.0.0)
|
|
7
7
|
rails (>= 7.2.0, < 9.0.0)
|
|
@@ -416,7 +416,7 @@ CHECKSUMS
|
|
|
416
416
|
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
417
417
|
phlex (1.11.0) sha256=979548e79a205c981612f1ab613addc8fa128c8092694d02f41aad4cea905e73
|
|
418
418
|
phlex-rails (1.2.2) sha256=a20218449e71bc9fa5a71b672fbede8a654c6b32a58f1c4ea83ddc1682307a4c
|
|
419
|
-
phlexible (3.
|
|
419
|
+
phlexible (3.1.1)
|
|
420
420
|
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
421
421
|
pretty_please (0.2.0) sha256=1f00296f946ae8ffd53db25803ed3998d615b9cc07526517dc75fcca6af3a0d3
|
|
422
422
|
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
phlexible (3.
|
|
4
|
+
phlexible (3.1.1)
|
|
5
5
|
phlex (>= 1.10.0, < 3.0.0)
|
|
6
6
|
phlex-rails (>= 1.2.0, < 3.0.0)
|
|
7
7
|
rails (>= 7.2.0, < 9.0.0)
|
|
@@ -414,7 +414,7 @@ CHECKSUMS
|
|
|
414
414
|
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
415
415
|
phlex (1.11.0) sha256=979548e79a205c981612f1ab613addc8fa128c8092694d02f41aad4cea905e73
|
|
416
416
|
phlex-rails (1.2.2) sha256=a20218449e71bc9fa5a71b672fbede8a654c6b32a58f1c4ea83ddc1682307a4c
|
|
417
|
-
phlexible (3.
|
|
417
|
+
phlexible (3.1.1)
|
|
418
418
|
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
419
419
|
pretty_please (0.2.0) sha256=1f00296f946ae8ffd53db25803ed3998d615b9cc07526517dc75fcca6af3a0d3
|
|
420
420
|
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
phlexible (3.
|
|
4
|
+
phlexible (3.1.1)
|
|
5
5
|
phlex (>= 1.10.0, < 3.0.0)
|
|
6
6
|
phlex-rails (>= 1.2.0, < 3.0.0)
|
|
7
7
|
rails (>= 7.2.0, < 9.0.0)
|
|
@@ -422,7 +422,7 @@ CHECKSUMS
|
|
|
422
422
|
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
423
423
|
phlex (2.4.0) sha256=8aad2f0cd792d7b1bd287f15a1f89474c9cacac28120dc33d2a81467ae934067
|
|
424
424
|
phlex-rails (2.4.0) sha256=2bcddbd488681acb25753bab1887d3ac150e644244ff8ba307f2171a4d0195f5
|
|
425
|
-
phlexible (3.
|
|
425
|
+
phlexible (3.1.1)
|
|
426
426
|
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
427
427
|
pretty_please (0.2.0) sha256=1f00296f946ae8ffd53db25803ed3998d615b9cc07526517dc75fcca6af3a0d3
|
|
428
428
|
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
phlexible (3.
|
|
4
|
+
phlexible (3.1.1)
|
|
5
5
|
phlex (>= 1.10.0, < 3.0.0)
|
|
6
6
|
phlex-rails (>= 1.2.0, < 3.0.0)
|
|
7
7
|
rails (>= 7.2.0, < 9.0.0)
|
|
@@ -420,7 +420,7 @@ CHECKSUMS
|
|
|
420
420
|
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
421
421
|
phlex (2.4.0) sha256=8aad2f0cd792d7b1bd287f15a1f89474c9cacac28120dc33d2a81467ae934067
|
|
422
422
|
phlex-rails (2.4.0) sha256=2bcddbd488681acb25753bab1887d3ac150e644244ff8ba307f2171a4d0195f5
|
|
423
|
-
phlexible (3.
|
|
423
|
+
phlexible (3.1.1)
|
|
424
424
|
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
425
425
|
pretty_please (0.2.0) sha256=1f00296f946ae8ffd53db25803ed3998d615b9cc07526517dc75fcca6af3a0d3
|
|
426
426
|
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
data/lib/phlexible/callbacks.rb
CHANGED
|
@@ -33,6 +33,18 @@ module Phlexible
|
|
|
33
33
|
def after_template(*names, &block)
|
|
34
34
|
set_callback(:template, :after, *names, &block)
|
|
35
35
|
end
|
|
36
|
+
|
|
37
|
+
def before_layout(*names, &block)
|
|
38
|
+
set_callback(:layout, :before, *names, &block)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def after_layout(*names, &block)
|
|
42
|
+
set_callback(:layout, :after, *names, &block)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def around_layout(*names, &block)
|
|
46
|
+
set_callback(:layout, :around, *names, &block)
|
|
47
|
+
end
|
|
36
48
|
end
|
|
37
49
|
|
|
38
50
|
def around_template
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phlexible
|
|
4
|
+
module Rails
|
|
5
|
+
module AutoLayout
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
include Phlexible::Rails::ViewAssigns
|
|
8
|
+
include Phlexible::Callbacks
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
define_callbacks :layout
|
|
12
|
+
|
|
13
|
+
class_attribute :auto_layout_view_prefix, instance_writer: false, default: 'Views::'
|
|
14
|
+
class_attribute :auto_layout_namespace, instance_writer: false, default: 'Views::Layouts::'
|
|
15
|
+
class_attribute :auto_layout_default, instance_writer: false, default: 'Views::Layouts::Application'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def around_template
|
|
19
|
+
layout_class = controller_assigned_layout || self.class.resolved_layout
|
|
20
|
+
if layout_class
|
|
21
|
+
run_callbacks :layout do
|
|
22
|
+
render(@layout = layout_class.new(self)) { super }
|
|
23
|
+
end
|
|
24
|
+
else
|
|
25
|
+
super
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class_methods do
|
|
30
|
+
def resolved_layout
|
|
31
|
+
if ::Rails.configuration.enable_reloading
|
|
32
|
+
resolve_layout
|
|
33
|
+
else
|
|
34
|
+
return @resolved_layout if defined?(@resolved_layout)
|
|
35
|
+
|
|
36
|
+
@resolved_layout = resolve_layout
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reset_resolved_layout!
|
|
41
|
+
remove_instance_variable(:@resolved_layout) if defined?(@resolved_layout)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def resolve_layout
|
|
47
|
+
view_name = resolve_view_name
|
|
48
|
+
return nil if view_name.blank?
|
|
49
|
+
|
|
50
|
+
prefix = auto_layout_view_prefix
|
|
51
|
+
return nil if prefix && !view_name.start_with?(prefix)
|
|
52
|
+
|
|
53
|
+
resolve_layout_from_namespace(view_name, prefix) ||
|
|
54
|
+
auto_layout_default&.safe_constantize
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def resolve_layout_from_namespace(view_name, prefix)
|
|
58
|
+
strip_prefix = prefix || infer_prefix_from_namespace || ''
|
|
59
|
+
segments = view_name.delete_prefix(strip_prefix).split('::')[..-2]
|
|
60
|
+
|
|
61
|
+
segments.length.downto(1) do |i|
|
|
62
|
+
klass = "#{auto_layout_namespace}#{segments.first(i).join('::')}".safe_constantize
|
|
63
|
+
return klass if klass.is_a?(Class)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def infer_prefix_from_namespace
|
|
70
|
+
root = auto_layout_namespace&.split('::')&.first
|
|
71
|
+
"#{root}::" if root
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def resolve_view_name
|
|
75
|
+
ancestors.each do |ancestor|
|
|
76
|
+
return ancestor.name if ancestor.is_a?(Class) && ancestor.name.present?
|
|
77
|
+
end
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def controller_assigned_layout
|
|
85
|
+
return nil if !respond_to?(:view_assigns, true)
|
|
86
|
+
|
|
87
|
+
view_assigns['layout']
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/phlexible/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: phlexible
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joel Moss
|
|
@@ -91,9 +91,15 @@ executables: []
|
|
|
91
91
|
extensions: []
|
|
92
92
|
extra_rdoc_files: []
|
|
93
93
|
files:
|
|
94
|
+
- ".claude/agents/rubocop-reviewer.md"
|
|
95
|
+
- ".claude/hooks/protect-files.sh"
|
|
96
|
+
- ".claude/hooks/rubocop-check.sh"
|
|
97
|
+
- ".claude/settings.json"
|
|
98
|
+
- ".claude/skills/test/SKILL.md"
|
|
94
99
|
- ".rubocop.yml"
|
|
95
100
|
- ".ruby-version"
|
|
96
101
|
- Appraisals
|
|
102
|
+
- CLAUDE.md
|
|
97
103
|
- CODE_OF_CONDUCT.md
|
|
98
104
|
- LICENSE.txt
|
|
99
105
|
- README.md
|
|
@@ -115,6 +121,7 @@ files:
|
|
|
115
121
|
- lib/phlexible/rails/a_element.rb
|
|
116
122
|
- lib/phlexible/rails/action_controller/implicit_render.rb
|
|
117
123
|
- lib/phlexible/rails/action_controller/meta_tags.rb
|
|
124
|
+
- lib/phlexible/rails/auto_layout.rb
|
|
118
125
|
- lib/phlexible/rails/button_to.rb
|
|
119
126
|
- lib/phlexible/rails/button_to_concerns.rb
|
|
120
127
|
- lib/phlexible/rails/controller_variables.rb
|
|
@@ -144,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
144
151
|
- !ruby/object:Gem::Version
|
|
145
152
|
version: '0'
|
|
146
153
|
requirements: []
|
|
147
|
-
rubygems_version: 4.0.
|
|
154
|
+
rubygems_version: 4.0.6
|
|
148
155
|
specification_version: 4
|
|
149
156
|
summary: A bunch of helpers and goodies intended to make life with Phlex even easier!
|
|
150
157
|
test_files: []
|