roda-phlex 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.devcontainer/Gemfile +7 -0
- data/.devcontainer/devcontainer.json +46 -0
- data/.rspec +3 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +22 -0
- data/README.md +171 -0
- data/Rakefile +10 -0
- data/lib/roda/phlex.rb +9 -0
- data/lib/roda/plugins/phlex.rb +170 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 697b0c167a1b8e7c0a878d07a7b45c69e8ce1ea4ec7d04a8a2a1743df8856d63
|
4
|
+
data.tar.gz: 0ef55428df093f8e8d61106b7819bf822fea490228e58c7c921ecf8e4d54aed6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6789258cef5d8ed114bc9cf5322b3440eb5b01122a8d046f09f30fe0382ee3b2eb7a2f055089c25cbce2d351d4b7da1041691e5c03a272c439b4fd41ad8440c7
|
7
|
+
data.tar.gz: c98632f1b504f435755b410dfcf0a5c7cc61b2f8fd9e59048bcde01966b01749b04a8aef1c4557a3f50e38911580e014a3869fe2a41408b2516e76ac55007ccf
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# -*- mode: ruby; indent-tabs-mode: nil; tab-width: 2 -*-
|
2
|
+
# This custom gemfile is automatically generated by the Ruby LSP.
|
3
|
+
|
4
|
+
eval_gemfile(File.expand_path("../Gemfile", __dir__))
|
5
|
+
|
6
|
+
gem "ruby-lsp", require: false, group: :development
|
7
|
+
gem "ruby-lsp-rspec", require: false, group: :development
|
@@ -0,0 +1,46 @@
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
2
|
+
// README at: https://github.com/devcontainers/templates/tree/main/src/ruby
|
3
|
+
{
|
4
|
+
"name": "Ruby",
|
5
|
+
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
6
|
+
"image": "mcr.microsoft.com/devcontainers/ruby:1-3.3-bullseye",
|
7
|
+
"features": {
|
8
|
+
"ghcr.io/devcontainers/features/git:1": {}
|
9
|
+
},
|
10
|
+
|
11
|
+
// Features to add to the dev container. More info: https://containers.dev/features.
|
12
|
+
// "features": {},
|
13
|
+
|
14
|
+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
15
|
+
// "forwardPorts": [],
|
16
|
+
|
17
|
+
// Use 'postCreateCommand' to run commands after the container is created.
|
18
|
+
// "postCreateCommand": "ruby --version",
|
19
|
+
|
20
|
+
// Configure tool-specific properties.
|
21
|
+
"customizations": {
|
22
|
+
"vscode": {
|
23
|
+
"extensions": [
|
24
|
+
"shopify.ruby-extensions-pack"
|
25
|
+
],
|
26
|
+
"settings": {
|
27
|
+
"[ruby]": {
|
28
|
+
"editor.defaultFormatter": "Shopify.ruby-lsp", // Use the Ruby LSP as the default formatter
|
29
|
+
"editor.formatOnSave": true, // Format files automatically when saving
|
30
|
+
"editor.tabSize": 2, // Use 2 spaces for indentation
|
31
|
+
"editor.insertSpaces": true, // Use spaces and not tabs for indentation
|
32
|
+
"editor.semanticHighlighting.enabled": true, // Enable semantic highlighting
|
33
|
+
"editor.formatOnType": true // Enable formatting while typing
|
34
|
+
},
|
35
|
+
"rubyLsp.bundleGemfile": ".devcontainer/Gemfile",
|
36
|
+
"rubyLsp.formatter": "standard",
|
37
|
+
"rubyLsp.linters": [
|
38
|
+
"standard"
|
39
|
+
]
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
45
|
+
// "remoteUser": "root"
|
46
|
+
}
|
data/.rspec
ADDED
data/.standard.yml
ADDED
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
9
|
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
10
|
+
identity and orientation.
|
11
|
+
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
13
|
+
diverse, inclusive, and healthy community.
|
14
|
+
|
15
|
+
## Our Standards
|
16
|
+
|
17
|
+
Examples of behavior that contributes to a positive environment for our
|
18
|
+
community include:
|
19
|
+
|
20
|
+
* Demonstrating empathy and kindness toward other people
|
21
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
22
|
+
* Giving and gracefully accepting constructive feedback
|
23
|
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
24
|
+
and learning from the experience
|
25
|
+
* Focusing on what is best not just for us as individuals, but for the overall
|
26
|
+
community
|
27
|
+
|
28
|
+
Examples of unacceptable behavior include:
|
29
|
+
|
30
|
+
* The use of sexualized language or imagery, and sexual attention or advances of
|
31
|
+
any kind
|
32
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
33
|
+
* Public or private harassment
|
34
|
+
* Publishing others' private information, such as a physical or email address,
|
35
|
+
without their explicit permission
|
36
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
37
|
+
professional setting
|
38
|
+
|
39
|
+
## Enforcement Responsibilities
|
40
|
+
|
41
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
42
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
43
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
44
|
+
or harmful.
|
45
|
+
|
46
|
+
Community leaders have the right and responsibility to remove, edit, or reject
|
47
|
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
48
|
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
49
|
+
decisions when appropriate.
|
50
|
+
|
51
|
+
## Scope
|
52
|
+
|
53
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
54
|
+
an individual is officially representing the community in public spaces.
|
55
|
+
Examples of representing our community include using an official email address,
|
56
|
+
posting via an official social media account, or acting as an appointed
|
57
|
+
representative at an online or offline event.
|
58
|
+
|
59
|
+
## Enforcement
|
60
|
+
|
61
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
62
|
+
reported to the community leaders responsible for enforcement at
|
63
|
+
[INSERT CONTACT METHOD].
|
64
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
65
|
+
|
66
|
+
All community leaders are obligated to respect the privacy and security of the
|
67
|
+
reporter of any incident.
|
68
|
+
|
69
|
+
## Enforcement Guidelines
|
70
|
+
|
71
|
+
Community leaders will follow these Community Impact Guidelines in determining
|
72
|
+
the consequences for any action they deem in violation of this Code of Conduct:
|
73
|
+
|
74
|
+
### 1. Correction
|
75
|
+
|
76
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
77
|
+
unprofessional or unwelcome in the community.
|
78
|
+
|
79
|
+
**Consequence**: A private, written warning from community leaders, providing
|
80
|
+
clarity around the nature of the violation and an explanation of why the
|
81
|
+
behavior was inappropriate. A public apology may be requested.
|
82
|
+
|
83
|
+
### 2. Warning
|
84
|
+
|
85
|
+
**Community Impact**: A violation through a single incident or series of
|
86
|
+
actions.
|
87
|
+
|
88
|
+
**Consequence**: A warning with consequences for continued behavior. No
|
89
|
+
interaction with the people involved, including unsolicited interaction with
|
90
|
+
those enforcing the Code of Conduct, for a specified period of time. This
|
91
|
+
includes avoiding interactions in community spaces as well as external channels
|
92
|
+
like social media. Violating these terms may lead to a temporary or permanent
|
93
|
+
ban.
|
94
|
+
|
95
|
+
### 3. Temporary Ban
|
96
|
+
|
97
|
+
**Community Impact**: A serious violation of community standards, including
|
98
|
+
sustained inappropriate behavior.
|
99
|
+
|
100
|
+
**Consequence**: A temporary ban from any sort of interaction or public
|
101
|
+
communication with the community for a specified period of time. No public or
|
102
|
+
private interaction with the people involved, including unsolicited interaction
|
103
|
+
with those enforcing the Code of Conduct, is allowed during this period.
|
104
|
+
Violating these terms may lead to a permanent ban.
|
105
|
+
|
106
|
+
### 4. Permanent Ban
|
107
|
+
|
108
|
+
**Community Impact**: Demonstrating a pattern of violation of community
|
109
|
+
standards, including sustained inappropriate behavior, harassment of an
|
110
|
+
individual, or aggression toward or disparagement of classes of individuals.
|
111
|
+
|
112
|
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
113
|
+
community.
|
114
|
+
|
115
|
+
## Attribution
|
116
|
+
|
117
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
118
|
+
version 2.1, available at
|
119
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
120
|
+
|
121
|
+
Community Impact Guidelines were inspired by
|
122
|
+
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
123
|
+
|
124
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
125
|
+
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
126
|
+
[https://www.contributor-covenant.org/translations][translations].
|
127
|
+
|
128
|
+
[homepage]: https://www.contributor-covenant.org
|
129
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
130
|
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
131
|
+
[FAQ]: https://www.contributor-covenant.org/faq
|
132
|
+
[translations]: https://www.contributor-covenant.org/translations
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Robert Schulze
|
4
|
+
Copyright (c) 2023 Ben Pickles
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
# roda-phlex
|
2
|
+
|
3
|
+
A [Roda](https://github.com/jeremyevans/roda) plugin that adds some convenience rendering [Phlex](https://github.com/phlex-ruby/phlex) views.
|
4
|
+
Especially accessing application methods from the view.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Install the gem and add to the application's Gemfile by executing:
|
9
|
+
|
10
|
+
```bash
|
11
|
+
bundle add roda-phlex
|
12
|
+
```
|
13
|
+
|
14
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
15
|
+
|
16
|
+
```bash
|
17
|
+
gem install roda-phlex
|
18
|
+
```
|
19
|
+
|
20
|
+
## Configuration
|
21
|
+
|
22
|
+
`plugin :phlex` takes the following options:
|
23
|
+
|
24
|
+
- `:layout` (`Phlex::SGML`): Specifies the layout class to be used for rendering
|
25
|
+
views. This class should be a Phlex layout class that defines how the
|
26
|
+
views are structured and rendered.
|
27
|
+
- `:layout_opts` (`Object`): Options that are passed to the layout
|
28
|
+
class when it is instantiated. These options can be used to customize
|
29
|
+
the behavior of the layout. Usually, this is a `Hash`.
|
30
|
+
- `:layout_handler` (`#call`): A custom handler for creating layout
|
31
|
+
instances. This proc receives three arguments: the layout class, the
|
32
|
+
layout options, and the object to be rendered. By default, it uses the
|
33
|
+
`layout.new(obj, **layout_opts)`, which instantiates the layout class with the
|
34
|
+
provided view object and options as keyword arguments.
|
35
|
+
- `:delegate`: Define if or which methods should be delegated to the Roda app:
|
36
|
+
- `true` (default): Create a single `app` method that delegates to the Roda app.
|
37
|
+
- `false`: Do not create any delegate methods.
|
38
|
+
- `:all`: Delegate all methods the Roda app responds to, to it. Be careful with this option.
|
39
|
+
It can lead to unexpected behavior if the Roda app has methods that conflict with Phlex methods.
|
40
|
+
- `Symbol`, `String`, `Array`: Delegate only the specified methods to the Roda app.
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
|
44
|
+
Add the plugin to the Roda application:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
plugin :phlex
|
48
|
+
```
|
49
|
+
|
50
|
+
Use the `phlex` method in the view to render a Phlex view:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
route do |r|
|
54
|
+
r.root do
|
55
|
+
phlex MyView.new
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
You can use all application methods in the view:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
plugin :sinatra_helpers
|
64
|
+
plugin :phlex, delegate: [:url]
|
65
|
+
|
66
|
+
class MyView < Phlex::View
|
67
|
+
def view_template
|
68
|
+
h1 { 'Phlex / Roda request params integration' }
|
69
|
+
p {
|
70
|
+
a(href: url("/path", true)) { "link" }
|
71
|
+
}
|
72
|
+
pre { app.request.params.inspect }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
You can also pass an alternative content type (automatically sets `image/svg+xml` for a `Phlex::SVG` instance):
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
route do |r|
|
81
|
+
r.get '/foo' do
|
82
|
+
phlex MyView.new, content_type: "application/xml"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
## Streaming
|
88
|
+
|
89
|
+
Streaming a Phlex view can be enabled by passing `stream: true` which will cause Phlex to automatically write to the response after the closing `</head>` and buffer the remaining content.
|
90
|
+
The Roda `:stream` plugin must be enabled for this to work.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
plugin :streaming
|
94
|
+
|
95
|
+
get '/foo' do
|
96
|
+
phlex MyView.new, stream: true
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
You can also manually flush the contents of the buffer at any point using Phlex's `#flush` method:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
class Layout < Phlex::HTML
|
104
|
+
def template(&block)
|
105
|
+
doctype
|
106
|
+
html {
|
107
|
+
head {
|
108
|
+
# All the usual stuff: links to external stylesheets and JavaScript etc.
|
109
|
+
}
|
110
|
+
# Phlex will automatically flush to the response at this point which will
|
111
|
+
# benefit all pages that opt in to streaming.
|
112
|
+
body {
|
113
|
+
# Standard site header and navigation.
|
114
|
+
render Header.new
|
115
|
+
|
116
|
+
yield_content(&block)
|
117
|
+
}
|
118
|
+
}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class MyView < Phlex::HTML
|
123
|
+
def template
|
124
|
+
render Layout.new {
|
125
|
+
# Knowing that this page can take a while to generate we can choose to
|
126
|
+
# flush here so the browser can render the site header while downloading
|
127
|
+
# the rest of the page - which should help minimise the First Contentful
|
128
|
+
# Paint metric.
|
129
|
+
flush
|
130
|
+
|
131
|
+
# The rest of the big long page...
|
132
|
+
}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
## Reconfiguring in a route
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
# Define a default layout and layout options for the whole application
|
141
|
+
plugin :phlex, layout: MyLayout, layout_opts: { title: +"My App" }
|
142
|
+
route do |r|
|
143
|
+
r.on "posts" do
|
144
|
+
# redefine the layout and layout options for this route tree
|
145
|
+
phlex_layout MyPostLayout
|
146
|
+
phlex_layout_opts[:title] << " - Posts"
|
147
|
+
|
148
|
+
r.get 'new' do
|
149
|
+
# Redefine the layout and layout options for this route
|
150
|
+
phlex_layout_opts[:title] = "Create new post"
|
151
|
+
phlex MyView.new
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
## Contributing
|
158
|
+
|
159
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/fnordfish/roda-phlex>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/fnordfish/roda-phlex/blob/main/CODE_OF_CONDUCT.md).
|
160
|
+
|
161
|
+
## License
|
162
|
+
|
163
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
164
|
+
|
165
|
+
## Code of Conduct
|
166
|
+
|
167
|
+
Everyone interacting in the Roda::Phlex project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/fnordfish/roda-phlex/blob/main/CODE_OF_CONDUCT.md).
|
168
|
+
|
169
|
+
## Acknowledgements
|
170
|
+
|
171
|
+
This gem is based on [phlex-sinatra](https://github.com/benpickles/phlex-sinatra), and extended by the layout handling features in [RomanTurner's gist](https://gist.github.com/RomanTurner/0ce0b8792e4149d152d2af2224cb6407)
|
data/Rakefile
ADDED
data/lib/roda/phlex.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Roda
|
4
|
+
module RodaPlugins
|
5
|
+
# The Phlex Plugin provides functionality for integrating Phlex with Roda applications.
|
6
|
+
#
|
7
|
+
# ### Phlex Plugin Options
|
8
|
+
#
|
9
|
+
# - `:layout` (+::Phlex::SGML+): Specifies the layout class to be used for rendering
|
10
|
+
# views. This class should be a Phlex layout class that defines how the
|
11
|
+
# views are structured and rendered.
|
12
|
+
# - `:layout_opts` (+Object+): Options that are passed to the layout
|
13
|
+
# class when it is instantiated. These options can be used to customize
|
14
|
+
# the behavior of the layout. Usually, this is a +Hash+.
|
15
|
+
# - `:layout_handler` (+#call+): A custom handler for creating layout
|
16
|
+
# instances. This proc receives three arguments: the layout class, the
|
17
|
+
# layout options, and the object to be rendered. By default, it uses the
|
18
|
+
# `DEFAULT_LAYOUT_HANDLER`, which instantiates the layout class with the
|
19
|
+
# provided object and options as keyword arguments.
|
20
|
+
# - `:delegate`: Define if or which methods should be delegated to the Roda app:
|
21
|
+
# - `true` (default): Create a single `app` method that delegates to the Roda app.
|
22
|
+
# - `false`: Do not create any delegate methods.
|
23
|
+
# - `:all`: Delegate all methods the Roda app responds to, to it. Be careful with this option.
|
24
|
+
# It can lead to unexpected behavior if the Roda app has methods that conflict with Phlex methods.
|
25
|
+
# - `Symbol`, `String`, `Array`: Delegate only the specified methods to the Roda app.
|
26
|
+
module Phlex
|
27
|
+
Undefined = Object.new
|
28
|
+
private_constant :Undefined
|
29
|
+
|
30
|
+
Error = Class.new(StandardError)
|
31
|
+
|
32
|
+
# Custom TypeError class for Phlex errors.
|
33
|
+
class TypeError < Error
|
34
|
+
MAX_SIZE = 32
|
35
|
+
|
36
|
+
# Initializes a TypeError instance.
|
37
|
+
# @param obj [Object] The object that caused the error.
|
38
|
+
def initialize(obj)
|
39
|
+
content = obj.inspect
|
40
|
+
content = content[0, MAX_SIZE] + "…" if content.size > MAX_SIZE
|
41
|
+
super("Expected a Phlex instance, received #{content}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# The default layout handler for creating layout instances.
|
46
|
+
# Expects layout options to be a +Hash+ when provided.
|
47
|
+
DEFAULT_LAYOUT_HANDLER = proc do |layout, layout_opts, obj|
|
48
|
+
layout_opts ? layout.new(obj, **layout_opts) : layout.new(obj)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Configures the Phlex plugin for the Roda application.
|
52
|
+
# @param app [Roda] The Roda application.
|
53
|
+
# @param opts [Hash] The options for configuring the Phlex plugin.
|
54
|
+
def self.configure(app, opts = OPTS)
|
55
|
+
delegate = opts.key?(:delegate) ? opts.delete(:delegate) : true
|
56
|
+
app.opts[:phlex] = opts
|
57
|
+
app.opts[:phlex][:layout_handler] ||= DEFAULT_LAYOUT_HANDLER
|
58
|
+
|
59
|
+
if delegate
|
60
|
+
overrides = Module.new do
|
61
|
+
def app
|
62
|
+
@_view_context
|
63
|
+
end
|
64
|
+
|
65
|
+
case delegate
|
66
|
+
when :all
|
67
|
+
def method_missing(name, ...)
|
68
|
+
if app.respond_to?(name)
|
69
|
+
app.send(name, ...)
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def respond_to_missing?(name, include_private = false)
|
76
|
+
app.respond_to?(name) || super
|
77
|
+
end
|
78
|
+
|
79
|
+
when Symbol, String, Array
|
80
|
+
Array(delegate).each do |delegate|
|
81
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
82
|
+
def #{delegate}(...)
|
83
|
+
app.#{delegate}(...)
|
84
|
+
end
|
85
|
+
RUBY
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
::Phlex::SGML.include(overrides)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
module InstanceMethods
|
95
|
+
# Retrieves or sets the layout.
|
96
|
+
# @param layout [Phlex::SGML, Undefined, nil] The layout to be set.
|
97
|
+
# @return [Phlex::SGML, nil] The current layout or nil if not set.
|
98
|
+
def phlex_layout(layout = Undefined)
|
99
|
+
case layout
|
100
|
+
when Undefined
|
101
|
+
opts.dig(:phlex, :layout)
|
102
|
+
when nil
|
103
|
+
opts[:phlex].delete(:layout)
|
104
|
+
opts[:phlex].delete(:layout_opts)
|
105
|
+
when ::Phlex::SGML
|
106
|
+
opts[:phlex][:layout] = layout
|
107
|
+
else
|
108
|
+
raise TypeError.new(layout)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Retrieves or sets the layout options.
|
113
|
+
# @param layout_opts [Undefined, nil] The layout options to be set.
|
114
|
+
# @return [Object, nil] The current layout options or nil if not set.
|
115
|
+
def phlex_layout_opts(layout_opts = Undefined)
|
116
|
+
case layout_opts
|
117
|
+
when Undefined
|
118
|
+
opts.dig(:phlex, :layout_opts)
|
119
|
+
when nil
|
120
|
+
opts[:phlex].delete(:layout_opts)
|
121
|
+
else
|
122
|
+
opts[:phlex][:layout_opts] = layout_opts
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Retrieves or sets the layout handler.
|
127
|
+
# @param handler [#call, Undefined, nil] The layout handler to be set.
|
128
|
+
# @return [#call, nil] The current layout handler or nil if not set.
|
129
|
+
def phlex_layout_handler(handler = Undefined)
|
130
|
+
case handler
|
131
|
+
when Undefined
|
132
|
+
opts.dig(:phlex, :layout_handler)
|
133
|
+
when nil
|
134
|
+
opts[:phlex].delete(:layout_handler)
|
135
|
+
else
|
136
|
+
opts[:phlex][:layout_handler] = handler
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Renders a Phlex object.
|
141
|
+
# @param obj [Phlex::SGML] The Phlex object to be rendered.
|
142
|
+
# @param content_type [String, nil] The content type of the response.
|
143
|
+
# @param stream [Boolean] Whether to stream the response or not.
|
144
|
+
def phlex(obj, content_type: nil, stream: false)
|
145
|
+
raise TypeError.new(obj) unless obj.is_a?(::Phlex::SGML)
|
146
|
+
|
147
|
+
content_type ||= "image/svg+xml" if obj.is_a?(::Phlex::SVG)
|
148
|
+
response["Content-Type"] = content_type if content_type
|
149
|
+
|
150
|
+
phlex_opts = opts[:phlex]
|
151
|
+
renderer = if (layout = phlex_opts[:layout])
|
152
|
+
phlex_layout_handler.call(layout, phlex_opts[:layout_opts], obj)
|
153
|
+
else
|
154
|
+
obj
|
155
|
+
end
|
156
|
+
|
157
|
+
if stream
|
158
|
+
self.stream do |out|
|
159
|
+
renderer.call(out, view_context: self)
|
160
|
+
end
|
161
|
+
else
|
162
|
+
renderer.call(view_context: self)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
register_plugin :phlex, Phlex
|
169
|
+
end
|
170
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: roda-phlex
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert Schulze
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-08-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: phlex
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.7.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.7.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: roda
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.0.0
|
41
|
+
description: A Phlex adapter for Roda
|
42
|
+
email:
|
43
|
+
- robert@dotless.de
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".devcontainer/Gemfile"
|
49
|
+
- ".devcontainer/devcontainer.json"
|
50
|
+
- ".rspec"
|
51
|
+
- ".standard.yml"
|
52
|
+
- CHANGELOG.md
|
53
|
+
- CODE_OF_CONDUCT.md
|
54
|
+
- LICENSE.txt
|
55
|
+
- README.md
|
56
|
+
- Rakefile
|
57
|
+
- lib/roda/phlex.rb
|
58
|
+
- lib/roda/plugins/phlex.rb
|
59
|
+
homepage: https://github.com/fnordfish/roda-phlex
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
metadata:
|
63
|
+
homepage_uri: https://github.com/fnordfish/roda-phlex
|
64
|
+
source_code_uri: https://github.com/fnordfish/roda-phlex
|
65
|
+
changelog_uri: https://github.com/fnordfish/roda-phlex/blob/main/CHANGELOG.md
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '2.7'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubygems_version: 3.5.17
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: A Phlex adapter for Roda
|
85
|
+
test_files: []
|