phlex 1.2.2 β 1.3.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/.ruby-version +1 -1
- data/README.md +3 -3
- data/lib/phlex/deferred_render.rb +1 -1
- data/lib/phlex/html.rb +27 -13
- data/lib/phlex/unbuffered.rb +15 -14
- data/lib/phlex/version.rb +1 -1
- data/lib/phlex.rb +2 -11
- metadata +17 -7
- data/lib/phlex/collection.rb +0 -33
- data/lib/phlex/configuration.rb +0 -13
- data/lib/phlex/experimental.rb +0 -13
- data/lib/phlex/table.rb +0 -103
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8df07c966d273976d91feebba2528a5cdacb5bb28116af48a54f42a97128ad94
|
4
|
+
data.tar.gz: 638529d514e4d1938ec0c0bab224969cc16a252752da3e1ab67ae2f217f4ea3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3728d8501c975eef2caa6c8b7c78d98d0f4aa654a88787e13e58c608331112b06074a177f401f6691713e8bbc4eac863e2b318e6d58cc61a3bfa38319e69e82d
|
7
|
+
data.tar.gz: bfd075ce712b522da689ed643b9a52536a80a7e779b807e8994c00a623a9e45b8a051f2dc78166efeebed047f02cda97c10f70c8165b99325e9c0236937ab918
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.2.0
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<a href="https://www.phlex.fun"><img alt="Phlex logo" src="phlex_logo.png" width="180" /></a>
|
2
2
|
|
3
|
-
Phlex
|
3
|
+
Phlex lets you compose web views in pure Ruby. Itβs super-fast, thread-safe and supports TruffleRuby v22.2+, JRuby v9.2+ and MRI v2.7+.
|
4
4
|
|
5
5
|
### Documentation π
|
6
6
|
|
@@ -12,13 +12,13 @@ If you run into any trouble, please [start a discussion](https://github.com/joel
|
|
12
12
|
|
13
13
|
### Community π
|
14
14
|
|
15
|
-
Everyone interacting in Phlex codebases, issue trackers
|
15
|
+
Everyone interacting in Phlex codebases, issue trackers or chat rooms is expected to follow the [code of conduct](https://github.com/joeldrapper/phlex/blob/main/CODE_OF_CONDUCT.md).
|
16
16
|
|
17
17
|
### Who uses Phlex?
|
18
18
|
|
19
19
|
- [Clearscope](https://www.clearscope.io)
|
20
20
|
|
21
|
-
*If you
|
21
|
+
*If youβre using Phlex in production, please open a PR to list it here.*
|
22
22
|
|
23
23
|
### Sponsorship π
|
24
24
|
|
data/lib/phlex/html.rb
CHANGED
@@ -130,8 +130,6 @@ module Phlex
|
|
130
130
|
include Helpers
|
131
131
|
|
132
132
|
class << self
|
133
|
-
attr_accessor :rendered_at_least_once
|
134
|
-
|
135
133
|
def call(...)
|
136
134
|
new(...).call
|
137
135
|
end
|
@@ -146,9 +144,20 @@ module Phlex
|
|
146
144
|
super
|
147
145
|
end
|
148
146
|
end
|
147
|
+
|
148
|
+
def rendered_at_least_once!
|
149
|
+
alias_method :__attributes__, :__final_attributes__
|
150
|
+
alias_method :call, :__final_call__
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def call(...)
|
155
|
+
__final_call__(...).tap do
|
156
|
+
self.class.rendered_at_least_once!
|
157
|
+
end
|
149
158
|
end
|
150
159
|
|
151
|
-
def
|
160
|
+
def __final_call__(buffer = +"", view_context: nil, parent: nil, &block)
|
152
161
|
@_target = buffer
|
153
162
|
@_view_context = view_context
|
154
163
|
@_parent = parent
|
@@ -176,8 +185,6 @@ module Phlex
|
|
176
185
|
end
|
177
186
|
end
|
178
187
|
|
179
|
-
self.class.rendered_at_least_once = true
|
180
|
-
|
181
188
|
buffer
|
182
189
|
end
|
183
190
|
|
@@ -356,12 +363,22 @@ module Phlex
|
|
356
363
|
end
|
357
364
|
|
358
365
|
private def __attributes__(**attributes)
|
359
|
-
|
360
|
-
__build_attributes__(attributes, buffer: buffer)
|
361
|
-
|
362
|
-
unless self.class.rendered_at_least_once
|
366
|
+
__final_attributes__(**attributes).tap do |buffer|
|
363
367
|
Phlex::ATTRIBUTE_CACHE[attributes.hash] = buffer.freeze
|
364
368
|
end
|
369
|
+
end
|
370
|
+
|
371
|
+
private def __final_attributes__(**attributes)
|
372
|
+
if attributes[:href]&.start_with?(/\s*javascript:/)
|
373
|
+
attributes.delete(:href)
|
374
|
+
end
|
375
|
+
|
376
|
+
if attributes["href"]&.start_with?(/\s*javascript:/)
|
377
|
+
attributes.delete("href")
|
378
|
+
end
|
379
|
+
|
380
|
+
buffer = +""
|
381
|
+
__build_attributes__(attributes, buffer: buffer)
|
365
382
|
|
366
383
|
buffer
|
367
384
|
end
|
@@ -376,11 +393,8 @@ module Phlex
|
|
376
393
|
else k.to_s
|
377
394
|
end
|
378
395
|
|
379
|
-
lower_name = name.downcase
|
380
|
-
next if lower_name == "href" && v.start_with?(/\s*javascript:/i)
|
381
|
-
|
382
396
|
# Detect unsafe attribute names. Attribute names are considered unsafe if they match an event attribute or include unsafe characters.
|
383
|
-
if HTML::EVENT_ATTRIBUTES[
|
397
|
+
if HTML::EVENT_ATTRIBUTES[name] || name.match?(/[<>&"']/)
|
384
398
|
raise ArgumentError, "Unsafe attribute name detected: #{k}."
|
385
399
|
end
|
386
400
|
|
data/lib/phlex/unbuffered.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
module Phlex
|
4
4
|
class Unbuffered < BasicObject
|
5
|
-
CACHE =
|
5
|
+
CACHE = ::Concurrent::Map.new
|
6
6
|
|
7
7
|
def self.call(object)
|
8
|
-
decorator = CACHE
|
8
|
+
decorator = CACHE.compute_if_absent(object.class.name) { ::Class.new(self) }
|
9
9
|
decorator.new(object)
|
10
10
|
end
|
11
11
|
|
@@ -31,10 +31,12 @@ module Phlex
|
|
31
31
|
@object.respond_to?(...)
|
32
32
|
end
|
33
33
|
|
34
|
-
def method_missing(name, *args, &block)
|
34
|
+
def method_missing(name, *args, **kwargs, &block)
|
35
35
|
if @object.respond_to?(name)
|
36
|
-
|
37
|
-
__class__.
|
36
|
+
|
37
|
+
__class__.define_method(name) do |*a, **k, &b|
|
38
|
+
@object.capture { @object.public_send(name, *a, **k, &b) }
|
39
|
+
end
|
38
40
|
|
39
41
|
# Now we've defined this missing method, we can call it.
|
40
42
|
__public_send__(name, *args, &block)
|
@@ -43,18 +45,17 @@ module Phlex
|
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
46
|
-
#
|
47
|
-
def
|
48
|
-
@object.
|
48
|
+
# Forward some methods to the original underlying method
|
49
|
+
def call(...)
|
50
|
+
@object.call(...)
|
49
51
|
end
|
50
52
|
|
51
|
-
def
|
52
|
-
@object.
|
53
|
+
def send(...)
|
54
|
+
@object.send(...)
|
53
55
|
end
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
alias_method :public_send, :__forward_method__
|
57
|
+
def public_send(...)
|
58
|
+
@object.public_send(...)
|
59
|
+
end
|
59
60
|
end
|
60
61
|
end
|
data/lib/phlex/version.rb
CHANGED
data/lib/phlex.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "erb"
|
4
4
|
require "zeitwerk"
|
5
|
+
require "concurrent"
|
5
6
|
|
6
7
|
module Phlex
|
7
8
|
Loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false).tap do |loader|
|
@@ -14,15 +15,5 @@ module Phlex
|
|
14
15
|
ArgumentError = Class.new(ArgumentError) { include Error }
|
15
16
|
NameError = Class.new(NameError) { include Error }
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
ATTRIBUTE_CACHE = {}
|
20
|
-
|
21
|
-
def configuration
|
22
|
-
@configuration ||= Configuration.new
|
23
|
-
end
|
24
|
-
|
25
|
-
def configure
|
26
|
-
yield configuration
|
27
|
-
end
|
18
|
+
ATTRIBUTE_CACHE = Concurrent::Map.new
|
28
19
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phlex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Drapper
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: concurrent-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: zeitwerk
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,14 +64,10 @@ files:
|
|
50
64
|
- lib/phlex/black_hole.rb
|
51
65
|
- lib/phlex/buffered.rb
|
52
66
|
- lib/phlex/callable.rb
|
53
|
-
- lib/phlex/collection.rb
|
54
|
-
- lib/phlex/configuration.rb
|
55
67
|
- lib/phlex/deferred_render.rb
|
56
68
|
- lib/phlex/elements.rb
|
57
|
-
- lib/phlex/experimental.rb
|
58
69
|
- lib/phlex/helpers.rb
|
59
70
|
- lib/phlex/html.rb
|
60
|
-
- lib/phlex/table.rb
|
61
71
|
- lib/phlex/testing/view_helper.rb
|
62
72
|
- lib/phlex/unbuffered.rb
|
63
73
|
- lib/phlex/version.rb
|
@@ -87,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
97
|
- !ruby/object:Gem::Version
|
88
98
|
version: '0'
|
89
99
|
requirements: []
|
90
|
-
rubygems_version: 3.
|
100
|
+
rubygems_version: 3.4.4
|
91
101
|
signing_key:
|
92
102
|
specification_version: 4
|
93
103
|
summary: A framework for building views in Ruby.
|
data/lib/phlex/collection.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Phlex
|
4
|
-
module Collection
|
5
|
-
include Experimental
|
6
|
-
|
7
|
-
def initialize(collection: nil, item: nil)
|
8
|
-
unless collection || item
|
9
|
-
raise ArgumentError, "You must pass a collection or an item as a keyword argument."
|
10
|
-
end
|
11
|
-
|
12
|
-
@collection = collection
|
13
|
-
@item = item
|
14
|
-
end
|
15
|
-
|
16
|
-
def template
|
17
|
-
@item ? item_template : collection_template { yield_items }
|
18
|
-
end
|
19
|
-
|
20
|
-
private def yield_items
|
21
|
-
if @item
|
22
|
-
raise ArgumentError, "You can only yield_items when rendering a collection. You are currently rendering an item."
|
23
|
-
end
|
24
|
-
|
25
|
-
@collection.each do |item|
|
26
|
-
@item = item
|
27
|
-
item_template
|
28
|
-
end
|
29
|
-
|
30
|
-
@item = nil
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/phlex/configuration.rb
DELETED
data/lib/phlex/experimental.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Phlex
|
4
|
-
module Experimental
|
5
|
-
def before_template
|
6
|
-
if Phlex.configuration.experimental_warnings
|
7
|
-
puts "Warning: #{self.class.name} is using experimental Phlex features that are subject to change."
|
8
|
-
end
|
9
|
-
|
10
|
-
super
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/lib/phlex/table.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Phlex
|
4
|
-
module Table
|
5
|
-
include Experimental
|
6
|
-
include Collection
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
attr_accessor :header
|
10
|
-
|
11
|
-
def property(header = nil, **attributes, &body)
|
12
|
-
if header.is_a?(String)
|
13
|
-
header_text = header
|
14
|
-
header = -> { head_header(scope: "col") { header_text } }
|
15
|
-
end
|
16
|
-
|
17
|
-
properties << {
|
18
|
-
header: header,
|
19
|
-
body: body,
|
20
|
-
attributes: attributes,
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
def properties
|
25
|
-
@properties ||= []
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.included(child)
|
30
|
-
child.extend ClassMethods
|
31
|
-
|
32
|
-
child.alias_method :head, :thead
|
33
|
-
child.alias_method :body, :tbody
|
34
|
-
child.alias_method :foot, :tfoot
|
35
|
-
|
36
|
-
child.alias_method :row, :tr
|
37
|
-
|
38
|
-
child.alias_method :header, :th
|
39
|
-
child.alias_method :cell, :td
|
40
|
-
|
41
|
-
child.alias_method :head_row, :row
|
42
|
-
child.alias_method :body_row, :row
|
43
|
-
child.alias_method :foot_row, :row
|
44
|
-
|
45
|
-
child.alias_method :head_header, :header
|
46
|
-
child.alias_method :foot_header, :header
|
47
|
-
|
48
|
-
child.alias_method :head_cell, :cell
|
49
|
-
child.alias_method :body_cell, :cell
|
50
|
-
child.alias_method :foot_cell, :cell
|
51
|
-
end
|
52
|
-
|
53
|
-
private def properties
|
54
|
-
self.class.properties
|
55
|
-
end
|
56
|
-
|
57
|
-
private def collection_template(&block)
|
58
|
-
table do
|
59
|
-
head_template
|
60
|
-
body_template(&block)
|
61
|
-
foot_template
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
private def item_template
|
66
|
-
row_template
|
67
|
-
end
|
68
|
-
|
69
|
-
private def head_template
|
70
|
-
if self.class.properties.any? { |p| p[:header] }
|
71
|
-
head do
|
72
|
-
head_row do
|
73
|
-
self.class.properties.each do |property|
|
74
|
-
case property[:header]
|
75
|
-
when Proc
|
76
|
-
instance_exec(&property[:header])
|
77
|
-
when Symbol
|
78
|
-
send(property[:header])
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
private def body_template
|
87
|
-
body { yield_items }
|
88
|
-
end
|
89
|
-
|
90
|
-
private def foot_template
|
91
|
-
end
|
92
|
-
|
93
|
-
private def row_template
|
94
|
-
body_row do
|
95
|
-
self.class.properties.each do |property|
|
96
|
-
body_cell(**property[:attributes]) do
|
97
|
-
instance_exec(@item, &property[:body])
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|