phlex 1.1.1 → 1.2.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/.rubocop.yml +2 -1
- data/.ruby-version +1 -1
- data/Gemfile +0 -1
- data/README.md +1 -0
- data/lib/phlex/black_hole.rb +15 -0
- data/lib/phlex/buffered.rb +2 -2
- data/lib/phlex/deferred_render.rb +7 -0
- data/lib/phlex/elements.rb +7 -3
- data/lib/phlex/experimental.rb +1 -1
- data/lib/phlex/helpers.rb +4 -4
- data/lib/phlex/html.rb +73 -24
- data/lib/phlex/unbuffered.rb +60 -0
- data/lib/phlex/version.rb +1 -1
- metadata +6 -5
- data/lib/phlex/turbo/frame.rb +0 -23
- data/lib/phlex/turbo/stream.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1a287ded1bcdc949fef4ca4ae24eb7870a83f9eb90c02d1cdd04152e1606ea1
|
4
|
+
data.tar.gz: 0aa47c95c2a46aacf2845f8bd58af88683b5283554c8f0e90d0199386505ef14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9cc696d354b00376956a4574c27f00851c3ad0b0598132dcb301cccf65a9b5d95cf35adc2032afb47b53ff9f52899090b3657113d4d8483e3d410efdf19478e0
|
7
|
+
data.tar.gz: 9cd0b3c7a746f58faaf77bcd0502fb96721889622e6cc1bf0e7b9e2f97f859bb8562fd800609ee5d964f9b1cee39e31c2c66c72ff0fba93653c6d4fc6ac85bc4
|
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.2.0
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -42,3 +42,4 @@ Thanks [Logology](https://www.logology.co) for sponsoring our logo.
|
|
42
42
|
- [tubby](https://github.com/judofyr/tubby)
|
43
43
|
- [hoshi](https://github.com/pete/hoshi)
|
44
44
|
- [hyperstack](https://github.com/hyperstack-org/hyperstack)
|
45
|
+
- [clearwater](https://github.com/clearwater-rb/clearwater)
|
data/lib/phlex/buffered.rb
CHANGED
@@ -10,8 +10,8 @@ module Phlex
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# Alias output methods to this
|
13
|
-
def __output_method__(
|
14
|
-
output = __getobj__.public_send(__callee__,
|
13
|
+
def __output_method__(...)
|
14
|
+
output = __getobj__.public_send(__callee__, ...)
|
15
15
|
@buffer << output if output.is_a? String
|
16
16
|
nil
|
17
17
|
end
|
data/lib/phlex/elements.rb
CHANGED
@@ -13,11 +13,11 @@ module Phlex
|
|
13
13
|
def #{element}(**attributes, &block)
|
14
14
|
if attributes.length > 0
|
15
15
|
if block_given?
|
16
|
-
@_target << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes.hash] ||
|
16
|
+
@_target << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes.hash] || __attributes__(**attributes)) << ">"
|
17
17
|
yield_content(&block)
|
18
18
|
@_target << "</#{tag}>"
|
19
19
|
else
|
20
|
-
@_target << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes.hash] ||
|
20
|
+
@_target << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes.hash] || __attributes__(**attributes)) << "></#{tag}>"
|
21
21
|
end
|
22
22
|
else
|
23
23
|
if block_given?
|
@@ -31,6 +31,8 @@ module Phlex
|
|
31
31
|
|
32
32
|
nil
|
33
33
|
end
|
34
|
+
|
35
|
+
alias_method :_#{element}, :#{element}
|
34
36
|
RUBY
|
35
37
|
end
|
36
38
|
|
@@ -40,13 +42,15 @@ module Phlex
|
|
40
42
|
|
41
43
|
def #{element}(**attributes)
|
42
44
|
if attributes.length > 0
|
43
|
-
@_target << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes.hash] ||
|
45
|
+
@_target << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes.hash] || __attributes__(**attributes)) << ">"
|
44
46
|
else
|
45
47
|
@_target << "<#{tag}>"
|
46
48
|
end
|
47
49
|
|
48
50
|
nil
|
49
51
|
end
|
52
|
+
|
53
|
+
alias_method :_#{element}, :#{element}
|
50
54
|
RUBY
|
51
55
|
end
|
52
56
|
end
|
data/lib/phlex/experimental.rb
CHANGED
@@ -4,7 +4,7 @@ module Phlex
|
|
4
4
|
module Experimental
|
5
5
|
def before_template
|
6
6
|
if Phlex.configuration.experimental_warnings
|
7
|
-
puts "Warning: #{self.class.name} is experimental
|
7
|
+
puts "Warning: #{self.class.name} is using experimental Phlex features that are subject to change."
|
8
8
|
end
|
9
9
|
|
10
10
|
super
|
data/lib/phlex/helpers.rb
CHANGED
@@ -15,12 +15,12 @@ module Phlex::Helpers
|
|
15
15
|
|
16
16
|
if truthy
|
17
17
|
case token
|
18
|
-
when Hash then
|
19
|
-
else
|
18
|
+
when Hash then __append_token__(tokens, token[:then])
|
19
|
+
else __append_token__(tokens, token)
|
20
20
|
end
|
21
21
|
else
|
22
22
|
case token
|
23
|
-
when Hash then
|
23
|
+
when Hash then __append_token__(tokens, token[:else])
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -28,7 +28,7 @@ module Phlex::Helpers
|
|
28
28
|
tokens.join(" ")
|
29
29
|
end
|
30
30
|
|
31
|
-
private def
|
31
|
+
private def __append_token__(tokens, token)
|
32
32
|
case token
|
33
33
|
when nil then nil
|
34
34
|
when String then tokens << token
|
data/lib/phlex/html.rb
CHANGED
@@ -131,6 +131,21 @@ module Phlex
|
|
131
131
|
|
132
132
|
class << self
|
133
133
|
attr_accessor :rendered_at_least_once
|
134
|
+
|
135
|
+
def call(...)
|
136
|
+
new(...).call
|
137
|
+
end
|
138
|
+
alias_method :render, :call
|
139
|
+
|
140
|
+
def new(*args, **kwargs, &block)
|
141
|
+
if block
|
142
|
+
object = super(*args, **kwargs, &nil)
|
143
|
+
object.instance_variable_set(:@_content_block, block)
|
144
|
+
object
|
145
|
+
else
|
146
|
+
super
|
147
|
+
end
|
148
|
+
end
|
134
149
|
end
|
135
150
|
|
136
151
|
def call(buffer = +"", view_context: nil, parent: nil, &block)
|
@@ -138,15 +153,22 @@ module Phlex
|
|
138
153
|
@_view_context = view_context
|
139
154
|
@_parent = parent
|
140
155
|
|
156
|
+
block ||= @_content_block
|
157
|
+
|
141
158
|
return buffer unless render?
|
142
159
|
|
143
160
|
around_template do
|
144
|
-
if
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
161
|
+
if block
|
162
|
+
if DeferredRender === self
|
163
|
+
__vanish__(self, &block)
|
164
|
+
template
|
165
|
+
else
|
166
|
+
template do |*args|
|
167
|
+
if args.length > 0
|
168
|
+
yield_content_with_args(*args, &block)
|
169
|
+
else
|
170
|
+
yield_content(&block)
|
171
|
+
end
|
150
172
|
end
|
151
173
|
end
|
152
174
|
else
|
@@ -159,7 +181,7 @@ module Phlex
|
|
159
181
|
buffer
|
160
182
|
end
|
161
183
|
|
162
|
-
def render(renderable,
|
184
|
+
def render(renderable, &block)
|
163
185
|
case renderable
|
164
186
|
when Phlex::HTML
|
165
187
|
renderable.call(@_target, view_context: @_view_context, parent: self, &block)
|
@@ -191,7 +213,7 @@ module Phlex
|
|
191
213
|
case content
|
192
214
|
when String then content
|
193
215
|
when Symbol then content.name
|
194
|
-
when Integer
|
216
|
+
when Integer then content.to_s
|
195
217
|
else format_object(content) || content.to_s
|
196
218
|
end
|
197
219
|
)
|
@@ -223,13 +245,13 @@ module Phlex
|
|
223
245
|
nil
|
224
246
|
end
|
225
247
|
|
226
|
-
def unsafe_raw(content = nil
|
248
|
+
def unsafe_raw(content = nil)
|
227
249
|
return nil unless content
|
228
250
|
|
229
251
|
@_target << content
|
230
252
|
end
|
231
253
|
|
232
|
-
def capture
|
254
|
+
def capture
|
233
255
|
return unless block_given?
|
234
256
|
|
235
257
|
original_buffer = @_target
|
@@ -238,9 +260,23 @@ module Phlex
|
|
238
260
|
|
239
261
|
yield
|
240
262
|
|
263
|
+
new_buffer
|
264
|
+
ensure
|
241
265
|
@_target = original_buffer
|
266
|
+
end
|
242
267
|
|
243
|
-
|
268
|
+
# Like `capture` but the output is vanished into a BlackHole buffer.
|
269
|
+
# Becuase the BlackHole does nothing with the output, this should be faster.
|
270
|
+
def __vanish__(*args)
|
271
|
+
return unless block_given?
|
272
|
+
|
273
|
+
original_buffer = @_target
|
274
|
+
@_target = BlackHole
|
275
|
+
|
276
|
+
yield(*args)
|
277
|
+
nil
|
278
|
+
ensure
|
279
|
+
@_target = original_buffer
|
244
280
|
end
|
245
281
|
|
246
282
|
# Default render predicate can be overridden to prevent rendering
|
@@ -248,8 +284,11 @@ module Phlex
|
|
248
284
|
true
|
249
285
|
end
|
250
286
|
|
251
|
-
private def format_object(
|
252
|
-
|
287
|
+
private def format_object(object)
|
288
|
+
case object
|
289
|
+
when Float
|
290
|
+
object.to_s
|
291
|
+
end
|
253
292
|
end
|
254
293
|
|
255
294
|
private def around_template
|
@@ -266,7 +305,7 @@ module Phlex
|
|
266
305
|
nil
|
267
306
|
end
|
268
307
|
|
269
|
-
private def yield_content
|
308
|
+
private def yield_content
|
270
309
|
return unless block_given?
|
271
310
|
|
272
311
|
original_length = @_target.length
|
@@ -279,7 +318,7 @@ module Phlex
|
|
279
318
|
@_target << ERB::Util.html_escape(content)
|
280
319
|
when Symbol
|
281
320
|
@_target << ERB::Util.html_escape(content.name)
|
282
|
-
when Integer
|
321
|
+
when Integer
|
283
322
|
@_target << ERB::Util.html_escape(content.to_s)
|
284
323
|
else
|
285
324
|
if (formatted_object = format_object(content))
|
@@ -291,7 +330,7 @@ module Phlex
|
|
291
330
|
nil
|
292
331
|
end
|
293
332
|
|
294
|
-
private def yield_content_with_args(*args
|
333
|
+
private def yield_content_with_args(*args)
|
295
334
|
return unless block_given?
|
296
335
|
|
297
336
|
original_length = @_target.length
|
@@ -316,9 +355,13 @@ module Phlex
|
|
316
355
|
nil
|
317
356
|
end
|
318
357
|
|
319
|
-
private def
|
358
|
+
private def __attributes__(**attributes)
|
359
|
+
if attributes[:href]&.start_with?(/\s*javascript/)
|
360
|
+
attributes[:href] = attributes[:href].sub(/^\s*(javascript:)+/, "")
|
361
|
+
end
|
362
|
+
|
320
363
|
buffer = +""
|
321
|
-
|
364
|
+
__build_attributes__(attributes, buffer: buffer)
|
322
365
|
|
323
366
|
unless self.class.rendered_at_least_once
|
324
367
|
Phlex::ATTRIBUTE_CACHE[attributes.hash] = buffer.freeze
|
@@ -327,7 +370,7 @@ module Phlex
|
|
327
370
|
buffer
|
328
371
|
end
|
329
372
|
|
330
|
-
private def
|
373
|
+
private def __build_attributes__(attributes, buffer:)
|
331
374
|
attributes.each do |k, v|
|
332
375
|
next unless v
|
333
376
|
|
@@ -337,11 +380,8 @@ module Phlex
|
|
337
380
|
else k.to_s
|
338
381
|
end
|
339
382
|
|
340
|
-
lower_name = name.downcase
|
341
|
-
next if lower_name == "href" && v.start_with?(/\s*javascript:/i)
|
342
|
-
|
343
383
|
# Detect unsafe attribute names. Attribute names are considered unsafe if they match an event attribute or include unsafe characters.
|
344
|
-
if HTML::EVENT_ATTRIBUTES[
|
384
|
+
if HTML::EVENT_ATTRIBUTES[name] || name.match?(/[<>&"']/)
|
345
385
|
raise ArgumentError, "Unsafe attribute name detected: #{k}."
|
346
386
|
end
|
347
387
|
|
@@ -353,7 +393,7 @@ module Phlex
|
|
353
393
|
when Symbol
|
354
394
|
buffer << " " << name << '="' << ERB::Util.html_escape(v.name) << '"'
|
355
395
|
when Hash
|
356
|
-
|
396
|
+
__build_attributes__(
|
357
397
|
v.transform_keys { |subkey|
|
358
398
|
case subkey
|
359
399
|
when Symbol then"#{k}-#{subkey.name.tr('_', '-')}"
|
@@ -368,5 +408,14 @@ module Phlex
|
|
368
408
|
|
369
409
|
buffer
|
370
410
|
end
|
411
|
+
|
412
|
+
# This should be the last method defined
|
413
|
+
def self.method_added(method_name)
|
414
|
+
if method_name[0] == "_" && Phlex::HTML.instance_methods.include?(method_name) && instance_method(method_name).owner != Phlex::HTML
|
415
|
+
raise NameError, "👋 Redefining the method `#{name}##{method_name}` is not a good idea."
|
416
|
+
end
|
417
|
+
|
418
|
+
super
|
419
|
+
end
|
371
420
|
end
|
372
421
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex
|
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
|
+
def initialize(object)
|
13
|
+
@object = object
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
"Unbuffered(#{@object.class.name})[object: #{@object.inspect}]"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Borrow some important methods from Object
|
21
|
+
define_method :__class__,
|
22
|
+
::Object.instance_method(:class)
|
23
|
+
|
24
|
+
define_method :__public_send__,
|
25
|
+
::Object.instance_method(:public_send)
|
26
|
+
|
27
|
+
define_method :__callee__,
|
28
|
+
::Object.instance_method(:__callee__)
|
29
|
+
|
30
|
+
def respond_to_missing?(...)
|
31
|
+
@object.respond_to?(...)
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(name, *args, &block)
|
35
|
+
if @object.respond_to?(name)
|
36
|
+
# If the object responds to this method, we want to define it by aliasing the __output_method__.
|
37
|
+
__class__.alias_method(name, :__output_method__)
|
38
|
+
|
39
|
+
# Now we've defined this missing method, we can call it.
|
40
|
+
__public_send__(name, *args, &block)
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# This method is designed to be aliased and references the callee which is whatever alias you called.
|
47
|
+
def __output_method__(*args, &block)
|
48
|
+
@object.capture { @object.public_send(__callee__, *args, &block) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def __forward_method__(*args, &block)
|
52
|
+
@object.public_send(__callee__, *args, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Forward some methods to the original underlying method
|
56
|
+
alias_method :call, :__forward_method__
|
57
|
+
alias_method :send, :__forward_method__
|
58
|
+
alias_method :public_send, :__forward_method__
|
59
|
+
end
|
60
|
+
end
|
data/lib/phlex/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phlex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.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-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -47,18 +47,19 @@ files:
|
|
47
47
|
- fixtures/view_helper.rb
|
48
48
|
- lib/overrides/symbol/name.rb
|
49
49
|
- lib/phlex.rb
|
50
|
+
- lib/phlex/black_hole.rb
|
50
51
|
- lib/phlex/buffered.rb
|
51
52
|
- lib/phlex/callable.rb
|
52
53
|
- lib/phlex/collection.rb
|
53
54
|
- lib/phlex/configuration.rb
|
55
|
+
- lib/phlex/deferred_render.rb
|
54
56
|
- lib/phlex/elements.rb
|
55
57
|
- lib/phlex/experimental.rb
|
56
58
|
- lib/phlex/helpers.rb
|
57
59
|
- lib/phlex/html.rb
|
58
60
|
- lib/phlex/table.rb
|
59
61
|
- lib/phlex/testing/view_helper.rb
|
60
|
-
- lib/phlex/
|
61
|
-
- lib/phlex/turbo/stream.rb
|
62
|
+
- lib/phlex/unbuffered.rb
|
62
63
|
- lib/phlex/version.rb
|
63
64
|
- phlex_logo.png
|
64
65
|
- sig/phlex.rbs
|
@@ -86,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
87
|
- !ruby/object:Gem::Version
|
87
88
|
version: '0'
|
88
89
|
requirements: []
|
89
|
-
rubygems_version: 3.
|
90
|
+
rubygems_version: 3.4.4
|
90
91
|
signing_key:
|
91
92
|
specification_version: 4
|
92
93
|
summary: A framework for building views in Ruby.
|
data/lib/phlex/turbo/frame.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Phlex
|
4
|
-
module Turbo
|
5
|
-
class Frame < Phlex::HTML
|
6
|
-
include Experimental
|
7
|
-
|
8
|
-
register_element :turbo_frame
|
9
|
-
|
10
|
-
def initialize(src:, loading:, disabled:, target:, autoscroll:)
|
11
|
-
@src = src
|
12
|
-
@loading = loading
|
13
|
-
@disabled = disabled
|
14
|
-
@target = target
|
15
|
-
@autoscroll = autoscroll
|
16
|
-
end
|
17
|
-
|
18
|
-
def template(&content)
|
19
|
-
turbo_frame(src: @src, loading: @loading, disabled: @disabled, target: @target, autoscroll: @autoscroll, &content)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/lib/phlex/turbo/stream.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Phlex
|
4
|
-
module Turbo
|
5
|
-
class Stream < Phlex::HTML
|
6
|
-
include Experimental
|
7
|
-
|
8
|
-
register_element :turbo_stream
|
9
|
-
|
10
|
-
def initialize(action:, **attributes)
|
11
|
-
@action = action
|
12
|
-
@attributes = attributes
|
13
|
-
end
|
14
|
-
|
15
|
-
def template(&content)
|
16
|
-
turbo_stream(action: @action, **@attributes, &content)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|