phlex 1.2.1 β 1.3.1
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/README.md +3 -3
- data/lib/phlex/deferred_render.rb +1 -1
- data/lib/phlex/html.rb +36 -11
- data/lib/phlex/unbuffered.rb +14 -23
- data/lib/phlex/version.rb +1 -1
- data/lib/phlex.rb +2 -11
- metadata +16 -6
- 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: 9cd9fd26d33fcf92978a26d9d94b81485871fa3f54c98639eb4ba5932960df84
|
4
|
+
data.tar.gz: c8f0ded1ee9cd43c12e8358af687b7fe4f21e732031ca4fb009020dfaaeb72b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 890ccb499d210d332f5b2213bfdce51bd1e2212c550b20b0d9de3d1698205ca45b82e86e7850dc037e07a43e3da70a011e27d2310618f203882a00b32750704d
|
7
|
+
data.tar.gz: fd9794d862a27ddaafa53c1f0d5fcecd3a967391083e2073922a2e83cbc19db7f95f4d19dd5db64b3c186e5c1c6292a6cef71dc05842c7216bd1e9b07046edc8
|
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
@@ -126,12 +126,12 @@ module Phlex
|
|
126
126
|
|
127
127
|
EVENT_ATTRIBUTES = %w[onabort onafterprint onbeforeprint onbeforeunload onblur oncanplay oncanplaythrough onchange onclick oncontextmenu oncopy oncuechange oncut ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop ondurationchange onemptied onended onerror onerror onfocus onhashchange oninput oninvalid onkeydown onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart onmessage onmousedown onmousemove onmouseout onmouseover onmouseup onmousewheel onoffline ononline onpagehide onpageshow onpaste onpause onplay onplaying onpopstate onprogress onratechange onreset onresize onscroll onsearch onseeked onseeking onselect onstalled onstorage onsubmit onsuspend ontimeupdate ontoggle onunload onvolumechange onwaiting onwheel].to_h { [_1, true] }.freeze
|
128
128
|
|
129
|
+
UNBUFFERED_MUTEX = Mutex.new
|
130
|
+
|
129
131
|
extend Elements
|
130
132
|
include Helpers
|
131
133
|
|
132
134
|
class << self
|
133
|
-
attr_accessor :rendered_at_least_once
|
134
|
-
|
135
135
|
def call(...)
|
136
136
|
new(...).call
|
137
137
|
end
|
@@ -146,9 +146,30 @@ module Phlex
|
|
146
146
|
super
|
147
147
|
end
|
148
148
|
end
|
149
|
+
|
150
|
+
def rendered_at_least_once!
|
151
|
+
alias_method :__attributes__, :__final_attributes__
|
152
|
+
alias_method :call, :__final_call__
|
153
|
+
end
|
154
|
+
|
155
|
+
def __unbuffered_class__
|
156
|
+
UNBUFFERED_MUTEX.synchronize do
|
157
|
+
if defined? @unbuffered_class
|
158
|
+
@unbuffered_class
|
159
|
+
else
|
160
|
+
@unbuffered_class = Class.new(Unbuffered)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def call(...)
|
167
|
+
__final_call__(...).tap do
|
168
|
+
self.class.rendered_at_least_once!
|
169
|
+
end
|
149
170
|
end
|
150
171
|
|
151
|
-
def
|
172
|
+
def __final_call__(buffer = +"", view_context: nil, parent: nil, &block)
|
152
173
|
@_target = buffer
|
153
174
|
@_view_context = view_context
|
154
175
|
@_parent = parent
|
@@ -176,8 +197,6 @@ module Phlex
|
|
176
197
|
end
|
177
198
|
end
|
178
199
|
|
179
|
-
self.class.rendered_at_least_once = true
|
180
|
-
|
181
200
|
buffer
|
182
201
|
end
|
183
202
|
|
@@ -265,6 +284,10 @@ module Phlex
|
|
265
284
|
@_target = original_buffer
|
266
285
|
end
|
267
286
|
|
287
|
+
def unbuffered
|
288
|
+
self.class.__unbuffered_class__.new(self)
|
289
|
+
end
|
290
|
+
|
268
291
|
# Like `capture` but the output is vanished into a BlackHole buffer.
|
269
292
|
# Becuase the BlackHole does nothing with the output, this should be faster.
|
270
293
|
private def __vanish__(*args)
|
@@ -356,21 +379,23 @@ module Phlex
|
|
356
379
|
end
|
357
380
|
|
358
381
|
private def __attributes__(**attributes)
|
359
|
-
|
382
|
+
__final_attributes__(**attributes).tap do |buffer|
|
383
|
+
Phlex::ATTRIBUTE_CACHE[attributes.hash] = buffer.freeze
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
private def __final_attributes__(**attributes)
|
388
|
+
if attributes[:href]&.start_with?(/\s*javascript:/)
|
360
389
|
attributes.delete(:href)
|
361
390
|
end
|
362
391
|
|
363
|
-
if attributes["href"]&.start_with?(/\s*javascript
|
392
|
+
if attributes["href"]&.start_with?(/\s*javascript:/)
|
364
393
|
attributes.delete("href")
|
365
394
|
end
|
366
395
|
|
367
396
|
buffer = +""
|
368
397
|
__build_attributes__(attributes, buffer: buffer)
|
369
398
|
|
370
|
-
unless self.class.rendered_at_least_once
|
371
|
-
Phlex::ATTRIBUTE_CACHE[attributes.hash] = buffer.freeze
|
372
|
-
end
|
373
|
-
|
374
399
|
buffer
|
375
400
|
end
|
376
401
|
|
data/lib/phlex/unbuffered.rb
CHANGED
@@ -2,13 +2,6 @@
|
|
2
2
|
|
3
3
|
module Phlex
|
4
4
|
class Unbuffered < BasicObject
|
5
|
-
CACHE = {}
|
6
|
-
|
7
|
-
def self.call(object)
|
8
|
-
decorator = CACHE[object.class.name] ||= ::Class.new(self)
|
9
|
-
decorator.new(object)
|
10
|
-
end
|
11
|
-
|
12
5
|
def initialize(object)
|
13
6
|
@object = object
|
14
7
|
end
|
@@ -24,37 +17,35 @@ module Phlex
|
|
24
17
|
define_method :__public_send__,
|
25
18
|
::Object.instance_method(:public_send)
|
26
19
|
|
27
|
-
define_method :__callee__,
|
28
|
-
::Object.instance_method(:__callee__)
|
29
|
-
|
30
20
|
def respond_to_missing?(...)
|
31
21
|
@object.respond_to?(...)
|
32
22
|
end
|
33
23
|
|
34
|
-
def method_missing(name, *args, &block)
|
24
|
+
def method_missing(name, *args, **kwargs, &block)
|
35
25
|
if @object.respond_to?(name)
|
36
|
-
|
37
|
-
__class__.
|
26
|
+
|
27
|
+
__class__.define_method(name) do |*a, **k, &b|
|
28
|
+
@object.capture { @object.public_send(name, *a, **k, &b) }
|
29
|
+
end
|
38
30
|
|
39
31
|
# Now we've defined this missing method, we can call it.
|
40
|
-
__public_send__(name, *args, &block)
|
32
|
+
__public_send__(name, *args, **kwargs, &block)
|
41
33
|
else
|
42
34
|
super
|
43
35
|
end
|
44
36
|
end
|
45
37
|
|
46
|
-
#
|
47
|
-
def
|
48
|
-
@object.
|
38
|
+
# Forward some methods to the original underlying method
|
39
|
+
def call(...)
|
40
|
+
@object.call(...)
|
49
41
|
end
|
50
42
|
|
51
|
-
def
|
52
|
-
@object.
|
43
|
+
def send(...)
|
44
|
+
@object.send(...)
|
53
45
|
end
|
54
46
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
alias_method :public_send, :__forward_method__
|
47
|
+
def public_send(...)
|
48
|
+
@object.public_send(...)
|
49
|
+
end
|
59
50
|
end
|
60
51
|
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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Drapper
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-01-
|
11
|
+
date: 2023-01-30 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
|
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
|