phlex 1.9.3 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of phlex might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.editorconfig +13 -0
- data/.rubocop.yml +27 -0
- data/.ruby-version +1 -0
- data/.solargraph.yml +11 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +62 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/CONTRIBUTING.md +33 -0
- data/Gemfile +21 -0
- data/README.md +3 -1
- data/SECURITY.md +14 -0
- data/bench.rb +21 -0
- data/config/sus.rb +8 -0
- data/fixtures/components/say_hi.rb +15 -0
- data/fixtures/components.rb +7 -0
- data/fixtures/layout.rb +31 -0
- data/fixtures/page.rb +37 -0
- data/fixtures/view_helper.rb +22 -0
- data/gd/phlex/callable.rb +18 -0
- data/gd/phlex/sgml/attributes.rb +107 -0
- data/gd/support/helper.rb +23 -0
- data/lib/phlex/black_hole.rb +1 -1
- data/lib/phlex/context.rb +45 -8
- data/lib/phlex/csv.rb +133 -0
- data/lib/phlex/deferred_render.rb +1 -1
- data/lib/phlex/elements.rb +72 -19
- data/lib/phlex/helpers.rb +17 -5
- data/lib/phlex/html/standard_elements.rb +138 -96
- data/lib/phlex/html/void_elements.rb +17 -17
- data/lib/phlex/html.rb +16 -2
- data/lib/phlex/kit.rb +62 -0
- data/lib/phlex/sgml.rb +110 -62
- data/lib/phlex/svg/standard_elements.rb +64 -64
- data/lib/phlex/svg.rb +10 -0
- data/lib/phlex/version.rb +1 -1
- data/lib/phlex.rb +34 -12
- data/phlex_logo.png +0 -0
- data/sig/phlex.rbs +4 -0
- metadata +29 -48
- data/lib/phlex/overrides/symbol/name.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6cb979c6d7c51d88b32f291de0ca3133594a03e70615b17c7fe7bff3b4b3e8c6
|
4
|
+
data.tar.gz: 4649c3a4526638bbbde4c627c70d57e969e9924cf4d2fac9706ab01d1283faa0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aaf25254c000f2bc39fb949427bfcced283df5c0dd4b44284ae30ba830d8141d6789adde5548911cb4b381ff096a7a31cc5d877d55cc7d48dfaf650670f08232
|
7
|
+
data.tar.gz: f8714c5084425f13c1ebcc7fcdf1e436a6a4ce501568dcf6522e7fd10279dd2902242e3b38ef4d1d1499d316237483eadf65f143718161676677d54c1c8ff65f
|
data/.editorconfig
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
inherit_from:
|
2
|
+
- "https://www.goodcop.style/rubocop.yml"
|
3
|
+
- "https://www.goodcop.style/tabs.yml"
|
4
|
+
|
5
|
+
AllCops:
|
6
|
+
TargetRubyVersion: 2.7
|
7
|
+
|
8
|
+
Style/ExplicitBlockArgument:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Style/MixinUsage:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Style/RedundantDoubleSplatHashBraces:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Style/OptionalArguments:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Naming/AsciiIdentifiers:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Naming/MethodName:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/ReturnNilInPredicateMethodDefinition:
|
27
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.3.0
|
data/.solargraph.yml
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--private --hide-api private --markup markdown
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
4
|
+
|
5
|
+
## [1.10.0] 2024-04-05
|
6
|
+
|
7
|
+
- [Added] new `Phlex::CSV` class for streaming CSV views
|
8
|
+
- [Added] new (experimental) `Phlex::Kit` for collections of components
|
9
|
+
- [Added] support for selective rendering
|
10
|
+
- [Changed] `mix` does a better job when mixing different types of attributes
|
11
|
+
- [Changed] Phlex will now try to call `to_s` on attribute values
|
12
|
+
- [Changed] No runtime dependencies
|
13
|
+
- [Deprecated] `Phlex::HTML#param`, (`<param>`) tags have been deprecated
|
14
|
+
- [Deprecated] Defining the `template` method is now deprecated. You should define `view_template` instead. In Phlex 2.0, the `template` method will render a `<template>` tag.
|
15
|
+
|
16
|
+
# [1.9.1] 2024-03-11
|
17
|
+
|
18
|
+
- Security update
|
19
|
+
|
20
|
+
## [1.9.0] 2024-11-24
|
21
|
+
|
22
|
+
- Improved documentation
|
23
|
+
- Fixed an issue with flushing to the buffer while capturing
|
24
|
+
- Added `<canvas>` element
|
25
|
+
- Very minor performance improvements by using `block` instead of `block_given?` where a block has already been captured
|
26
|
+
- `Integer` objects are now handled by the `format_object` method, which you can override to customise how various objects are rendered
|
27
|
+
- You can now use `render` with `String` and `Method` objects
|
28
|
+
|
29
|
+
## [1.8.1] 2023-04-19
|
30
|
+
|
31
|
+
### Fixed
|
32
|
+
|
33
|
+
- Rendering a component with a false `render?` predicate should return an empty String rather than `nil`.
|
34
|
+
|
35
|
+
## [1.8.0] 2023-04-19
|
36
|
+
|
37
|
+
### Changed
|
38
|
+
|
39
|
+
- Support `Integer` and `Float` attribute values, and fall back to calling `to_str` on other objects.
|
40
|
+
|
41
|
+
## [1.7.0] 2023-04-18
|
42
|
+
|
43
|
+
### Added
|
44
|
+
|
45
|
+
- Experimental Smart chunking.
|
46
|
+
|
47
|
+
### Changed
|
48
|
+
|
49
|
+
- Improved YARD documentation, which is now available here https://rubydoc.info/gems/phlex
|
50
|
+
- `SGML#render` can now render lambdas with zero or one arguments. Previously, it could only render lambdas with exactly one argument, although it could always render Procs with any number of arguments. When an argument is accepted, the `self` of the component rendering it is yielded to the Proc.
|
51
|
+
- Raise an error when outputting an unknown object using `SGML#plain`.
|
52
|
+
- Raise an error when using attribute keys that aren't Strings or Symbols.
|
53
|
+
- Support Array and Set values for HTML/SVG attributes.
|
54
|
+
|
55
|
+
### Removed
|
56
|
+
|
57
|
+
- Removed the `menuitem` element as it's a deprecated HTML element.
|
58
|
+
- Removed the `SGML#text` method. This has been replaced with `SGML#plain`.
|
59
|
+
|
60
|
+
---
|
61
|
+
|
62
|
+
Before this changelog was introduced, changes were logged in the [release notes](https://github.com/phlex-ruby/phlex/releases).
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
6
|
+
|
7
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
8
|
+
|
9
|
+
## Our Standards
|
10
|
+
|
11
|
+
Examples of behavior that contributes to a positive environment for our community include:
|
12
|
+
|
13
|
+
* Demonstrating empathy and kindness toward other people
|
14
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
15
|
+
* Giving and gracefully accepting constructive feedback
|
16
|
+
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
17
|
+
* Focusing on what is best not just for us as individuals, but for the overall community
|
18
|
+
|
19
|
+
Examples of unacceptable behavior include:
|
20
|
+
|
21
|
+
* The use of sexualized language or imagery, and sexual attention or
|
22
|
+
advances of any kind
|
23
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
24
|
+
* Public or private harassment
|
25
|
+
* Publishing others' private information, such as a physical or email
|
26
|
+
address, without their explicit permission
|
27
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
28
|
+
professional setting
|
29
|
+
|
30
|
+
## Enforcement Responsibilities
|
31
|
+
|
32
|
+
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
33
|
+
|
34
|
+
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
35
|
+
|
36
|
+
## Scope
|
37
|
+
|
38
|
+
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
39
|
+
|
40
|
+
## Enforcement
|
41
|
+
|
42
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at joel@drapper.me. All complaints will be reviewed and investigated promptly and fairly.
|
43
|
+
|
44
|
+
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
45
|
+
|
46
|
+
## Enforcement Guidelines
|
47
|
+
|
48
|
+
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
49
|
+
|
50
|
+
### 1. Correction
|
51
|
+
|
52
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
53
|
+
|
54
|
+
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
55
|
+
|
56
|
+
### 2. Warning
|
57
|
+
|
58
|
+
**Community Impact**: A violation through a single incident or series of actions.
|
59
|
+
|
60
|
+
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
61
|
+
|
62
|
+
### 3. Temporary Ban
|
63
|
+
|
64
|
+
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
|
65
|
+
|
66
|
+
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
67
|
+
|
68
|
+
### 4. Permanent Ban
|
69
|
+
|
70
|
+
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
71
|
+
|
72
|
+
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
73
|
+
|
74
|
+
## Attribution
|
75
|
+
|
76
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
|
77
|
+
available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
78
|
+
|
79
|
+
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
80
|
+
|
81
|
+
[homepage]: https://www.contributor-covenant.org
|
82
|
+
|
83
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
84
|
+
https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Contributing to Phlex
|
2
|
+
|
3
|
+
## Priorities
|
4
|
+
|
5
|
+
We’re trying to provide the best possible developer experience for the people using Phlex in their apps and the best possible performance for the users of those apps.
|
6
|
+
|
7
|
+
Phlex is incredibly complex and requires a lot of meta-programming but when you use it, it feels simple. Phlex views feel like plain old Ruby objects. You just subclass and define a couple of methods. That’s it. That’s how it should be.
|
8
|
+
|
9
|
+
## Setup
|
10
|
+
|
11
|
+
- Install dependencies `bundle install`
|
12
|
+
- Run the tests `bundle exec sus`
|
13
|
+
- Run Rubocop and auto-correct `bundle exec rubocop -A`
|
14
|
+
|
15
|
+
## Tests
|
16
|
+
|
17
|
+
New tests should be written using [GreenDots](https://github.com/joeldrapper/green_dots) and placed in the `gd` folder. You can run these tests with:
|
18
|
+
|
19
|
+
```
|
20
|
+
bundle exec gd gd
|
21
|
+
```
|
22
|
+
|
23
|
+
Joel maintains GreenDots itself, so if you run into any issues, please reach out to him by creating an issue in the GreenDots repo so he can improve the framework.
|
24
|
+
|
25
|
+
Previously, we used **[Sus](https://github.com/ioquatix/sus)**. Sus tests are in the `test` folder and can be run with:
|
26
|
+
|
27
|
+
```
|
28
|
+
bundle exec sus
|
29
|
+
```
|
30
|
+
|
31
|
+
## Documentation
|
32
|
+
|
33
|
+
Documentation is deployed when it’s merged into the `latest` branch with a release. But you can build and preview the docs locally by running `bin/docs`.
|
data/Gemfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
5
|
+
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
group :test do
|
9
|
+
gem "sus"
|
10
|
+
if RUBY_ENGINE == "ruby" && RUBY_VERSION[0] > "3"
|
11
|
+
gem "async"
|
12
|
+
end
|
13
|
+
gem "concurrent-ruby"
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development do
|
17
|
+
gem "rubocop"
|
18
|
+
gem "solargraph"
|
19
|
+
gem "yard"
|
20
|
+
gem "benchmark-ips"
|
21
|
+
end
|
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
<a href="https://www.phlex.fun"><img alt="Phlex logo" src="https://www.phlex.fun/assets/logo.png" width="180" /></a>
|
1
|
+
<a href="https://www.phlex.fun/"><img alt="Phlex logo" src="https://www.phlex.fun/assets/logo.png" width="180" /></a>
|
2
2
|
|
3
3
|
Phlex lets you compose web views in pure Ruby — kind of like JSX, but not really anything like JSX. It’s super-fast, thread-safe and supports TruffleRuby v22.2+, JRuby v9.2+ and MRI v2.7+. Phlex currently supports [HTML](https://rubydoc.info/gems/phlex/Phlex/HTML) and [SVG](https://rubydoc.info/gems/phlex/Phlex/SVG) views, and we’re exploring JSON and XML.
|
4
4
|
|
5
|
+
Docs and more at [Phlex.fun](https://www.phlex.fun/)
|
6
|
+
|
5
7
|
### Prior Art 🎨
|
6
8
|
|
7
9
|
- [markaby](https://github.com/markaby/markaby)
|
data/SECURITY.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Security
|
2
|
+
|
3
|
+
If you find a possible security vulnerability, please [send us a private advisory](https://github.com/phlex-ruby/phlex/security/advisories/new).
|
4
|
+
|
5
|
+
> [!WARNING]
|
6
|
+
> Please do not open a public Issue or Pull Request.
|
7
|
+
|
8
|
+
## Bug bounty
|
9
|
+
|
10
|
+
There is currently a bounty of $100 USD, kindly sponsored by [Seth Horsley](https://twitter.com/SethHorsley), for the next serious vulnerability responsibly disclosed to us.
|
11
|
+
|
12
|
+
## Bug bounty pot
|
13
|
+
|
14
|
+
If you wish to sponsor a bug bounty for Phlex, please get in touch with Joel at [joel@drapper.me](mailto:joel@drapper.me).
|
data/bench.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "phlex"
|
5
|
+
require "benchmark/ips"
|
6
|
+
|
7
|
+
require_relative "fixtures/page"
|
8
|
+
require_relative "fixtures/layout"
|
9
|
+
|
10
|
+
puts RUBY_DESCRIPTION
|
11
|
+
|
12
|
+
a = Example::Page.new.call
|
13
|
+
# Example::Page.compile
|
14
|
+
# Example::LayoutComponent.compile
|
15
|
+
b = Example::Page.new.call
|
16
|
+
|
17
|
+
raise unless a == b
|
18
|
+
|
19
|
+
Benchmark.ips do |x|
|
20
|
+
x.report("Page") { Example::Page.new.call }
|
21
|
+
end
|
data/config/sus.rb
ADDED
data/fixtures/layout.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Example
|
4
|
+
class LayoutComponent < Phlex::HTML
|
5
|
+
def initialize(title: "Example")
|
6
|
+
@title = title
|
7
|
+
end
|
8
|
+
|
9
|
+
def view_template(&block)
|
10
|
+
html do
|
11
|
+
head do
|
12
|
+
title { @title }
|
13
|
+
meta name: "viewport", content: "width=device-width,initial-scale=1"
|
14
|
+
link href: "/assets/tailwind.css", rel: "stylesheet"
|
15
|
+
end
|
16
|
+
|
17
|
+
body class: "bg-zinc-100" do
|
18
|
+
nav class: "p-5", id: "main_nav" do
|
19
|
+
ul do
|
20
|
+
li(class: "p-5") { a(href: "/") { "Home" } }
|
21
|
+
li(class: "p-5") { a(href: "/about") { "About" } }
|
22
|
+
li(class: "p-5") { a(href: "/contact") { "Contact" } }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
div class: "container mx-auto p-5", &block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/fixtures/page.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Example
|
4
|
+
class Page < Phlex::HTML
|
5
|
+
def view_template
|
6
|
+
render LayoutComponent.new do
|
7
|
+
h1 { "Hi" }
|
8
|
+
|
9
|
+
100.times do
|
10
|
+
table id: "test", class: "a b c d e f g" do
|
11
|
+
tr do
|
12
|
+
td id: "test", class: "a b c d e f g" do
|
13
|
+
span { "Hi" }
|
14
|
+
end
|
15
|
+
|
16
|
+
td id: "test", class: "a b c d e f g" do
|
17
|
+
span { "Hi" }
|
18
|
+
end
|
19
|
+
|
20
|
+
td id: "test", class: "a b c d e f g" do
|
21
|
+
span { "Hi" }
|
22
|
+
end
|
23
|
+
|
24
|
+
td id: "test", class: "a b c d e f g" do
|
25
|
+
span { "Hi" }
|
26
|
+
end
|
27
|
+
|
28
|
+
td id: "test", class: "a b c d e f g" do
|
29
|
+
span { "Hi" }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewHelper
|
4
|
+
def self.extended(parent)
|
5
|
+
parent.class_exec do
|
6
|
+
let(:output) { example.call }
|
7
|
+
let(:example) { view.new }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def view(&block)
|
12
|
+
let :view do
|
13
|
+
Class.new(Phlex::HTML, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def svg_view(&block)
|
18
|
+
let :view do
|
19
|
+
Class.new(Phlex::SVG, &block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Example
|
4
|
+
include Phlex::Callable
|
5
|
+
|
6
|
+
def call
|
7
|
+
"Hello, world!"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def example
|
12
|
+
Example.new
|
13
|
+
end
|
14
|
+
|
15
|
+
test "to_proc" do
|
16
|
+
expect(example.to_proc).to_be_a Proc
|
17
|
+
expect(example.to_proc.call) == "Hello, world!"
|
18
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
include TestHelper
|
4
|
+
|
5
|
+
class ToPhlexAttributeValueable
|
6
|
+
def to_phlex_attribute_value
|
7
|
+
"to_phlex_attribute_value"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ToSable
|
12
|
+
def to_s
|
13
|
+
"to_s"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ToStrable
|
18
|
+
def to_str
|
19
|
+
"to_str"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
test "with symbol-keyed hash attributes" do
|
24
|
+
component = build_component_with_template do
|
25
|
+
div data: { name: { first_name: "Joel" } }
|
26
|
+
end
|
27
|
+
|
28
|
+
expect(component.new).to_render %(<div data-name-first-name="Joel"></div>)
|
29
|
+
end
|
30
|
+
|
31
|
+
test "with string-keyed hash attributes" do
|
32
|
+
component = build_component_with_template do
|
33
|
+
div data: { "name" => { "first_name" => "Joel" } }
|
34
|
+
end
|
35
|
+
|
36
|
+
expect(component.new).to_render %(<div data-name-first_name="Joel"></div>)
|
37
|
+
end
|
38
|
+
|
39
|
+
test "with an array of symbols and strings" do
|
40
|
+
component = build_component_with_template do
|
41
|
+
div class: ["bg-red-500", :rounded]
|
42
|
+
end
|
43
|
+
|
44
|
+
expect(component.new).to_render %(<div class="bg-red-500 rounded"></div>)
|
45
|
+
end
|
46
|
+
|
47
|
+
test "with a set of symbols and strings" do
|
48
|
+
component = build_component_with_template do
|
49
|
+
div class: Set.new(["bg-red-500", :rounded])
|
50
|
+
end
|
51
|
+
|
52
|
+
expect(component.new).to_render %(<div class="bg-red-500 rounded"></div>)
|
53
|
+
end
|
54
|
+
|
55
|
+
test "with a to_phlex_attribute_value-able object" do
|
56
|
+
component = build_component_with_template do
|
57
|
+
div class: ToPhlexAttributeValueable.new
|
58
|
+
end
|
59
|
+
|
60
|
+
expect(component.new).to_render %(<div class="to_phlex_attribute_value"></div>)
|
61
|
+
end
|
62
|
+
|
63
|
+
test "with a to_s-able object" do
|
64
|
+
component = build_component_with_template do
|
65
|
+
div class: ToSable.new
|
66
|
+
end
|
67
|
+
|
68
|
+
expect(component.new).to_render %(<div class="to_s"></div>)
|
69
|
+
end
|
70
|
+
|
71
|
+
test "with a to_str-able object" do
|
72
|
+
component = build_component_with_template do
|
73
|
+
div class: ToStrable.new
|
74
|
+
end
|
75
|
+
|
76
|
+
expect(component.new).to_render %(<div class="to_str"></div>)
|
77
|
+
end
|
78
|
+
|
79
|
+
test "with numeric integer/float" do
|
80
|
+
component = build_component_with_template do
|
81
|
+
input type: "range", min: 0, max: 10, step: 0.5
|
82
|
+
end
|
83
|
+
|
84
|
+
expect(component.new).to_render %(<input type="range" min="0" max="10" step="0.5">)
|
85
|
+
end
|
86
|
+
|
87
|
+
if RUBY_ENGINE == "ruby"
|
88
|
+
context "with unique tag attributes" do
|
89
|
+
let def component
|
90
|
+
build_component_with_template do
|
91
|
+
div class: SecureRandom.hex
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
let def report
|
96
|
+
component.call
|
97
|
+
|
98
|
+
MemoryProfiler.report do
|
99
|
+
2.times { component.call }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
test "doesn't leak memory" do
|
104
|
+
expect(report.total_retained) == 0
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "phlex"
|
4
|
+
require "bundler"
|
5
|
+
|
6
|
+
Bundler.require :test
|
7
|
+
|
8
|
+
module TestHelper
|
9
|
+
def build_component_with_template(&block)
|
10
|
+
Class.new(Phlex::HTML) { define_method(:template, &block) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ToRender
|
15
|
+
def to_render(expected_output)
|
16
|
+
output = subject.call
|
17
|
+
assert(output == expected_output) { "Expected `#{output.inspect}` to equal `#{expected_output.inspect}`." }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
GreenDots.configure do |config|
|
22
|
+
config.register_matcher ToRender, Phlex::SGML
|
23
|
+
end
|