phlex 1.0.0.rc1 → 1.0.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 +4 -0
- data/Gemfile +1 -0
- data/SECURITY.md +10 -2
- data/lib/phlex/collection.rb +1 -3
- data/lib/phlex/configuration.rb +7 -1
- data/lib/phlex/experimental.rb +4 -1
- data/lib/phlex/helpers.rb +26 -15
- data/lib/phlex/html.rb +76 -36
- data/lib/phlex/table.rb +7 -9
- data/lib/phlex/version.rb +1 -1
- data/lib/phlex.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e074c926f013d613e2523b41c8dd604758d087c64d377b50a343c651b0164c0d
|
4
|
+
data.tar.gz: 56019e811dff06ef053adfeb20160fe29c247ee2e2f37848eba1580d240c41fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24489ae7f67415aa23ce258d6a121fe37418ce32e543888410b730821feeafd5fda6f164dd6f390f9dd4a0ec7a8a92ae5c50deb53376f95f987203ad4da2acf2
|
7
|
+
data.tar.gz: 1ddfa0b6dff09c597cec5f77f521faf89344981e4f3ddd3237722d94cb4d4faeec0d385a7ef4a0a18acec770d7f22811ac489ae94dfdfc3fc92fbf1cbb676f20
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/SECURITY.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Security Policy
|
2
2
|
|
3
|
-
## Reporting a
|
3
|
+
## Reporting a vulnerability
|
4
4
|
|
5
|
-
If you
|
5
|
+
If you find a possible security vulnerability, please email security@phlex.fun. Do not create an issue or pull request either demonstrating or fixing the vulnerability.
|
6
|
+
|
7
|
+
## Bug bounty
|
8
|
+
|
9
|
+
[The Gem Foundation](https://ryanbigg.com/2022/11/the-gem-foundation) has kindly sponsored a $1 bug bounty to discover security vulnerabilities in Phlex.
|
10
|
+
|
11
|
+
## Sponsoring a bug bounty
|
12
|
+
|
13
|
+
If you wish to sponsor a bug bounty for Phlex, please get in touch with Joel at joel@drapper.me.
|
data/lib/phlex/collection.rb
CHANGED
@@ -17,9 +17,7 @@ module Phlex
|
|
17
17
|
@item ? item_template : collection_template { yield_items }
|
18
18
|
end
|
19
19
|
|
20
|
-
private
|
21
|
-
|
22
|
-
def yield_items
|
20
|
+
private def yield_items
|
23
21
|
if @item
|
24
22
|
raise ArgumentError, "You can only yield_items when rendering a collection. You are currently rendering an item."
|
25
23
|
end
|
data/lib/phlex/configuration.rb
CHANGED
data/lib/phlex/experimental.rb
CHANGED
@@ -3,7 +3,10 @@
|
|
3
3
|
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 and subject to change."
|
8
|
+
end
|
9
|
+
|
7
10
|
super
|
8
11
|
end
|
9
12
|
end
|
data/lib/phlex/helpers.rb
CHANGED
@@ -5,30 +5,41 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.0")
|
|
5
5
|
end
|
6
6
|
|
7
7
|
module Phlex::Helpers
|
8
|
-
private
|
9
|
-
|
10
|
-
def tokens(*tokens, **conditional_tokens)
|
8
|
+
private def tokens(*tokens, **conditional_tokens)
|
11
9
|
conditional_tokens.each do |condition, token|
|
12
|
-
case condition
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
"The class condition must be a Symbol or a Proc."
|
10
|
+
truthy = case condition
|
11
|
+
when Symbol then send(condition)
|
12
|
+
when Proc then condition.call
|
13
|
+
else raise ArgumentError, "The class condition must be a Symbol or a Proc."
|
17
14
|
end
|
18
15
|
|
19
|
-
|
20
|
-
|
16
|
+
if truthy
|
17
|
+
case token
|
18
|
+
when Hash then _append_token(tokens, token[:then])
|
19
|
+
else _append_token(tokens, token)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
case token
|
23
|
+
when Hash then _append_token(tokens, token[:else])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
tokens.join(" ")
|
29
|
+
end
|
30
|
+
|
31
|
+
private def _append_token(tokens, token)
|
32
|
+
case token
|
33
|
+
when nil then nil
|
21
34
|
when String then tokens << token
|
35
|
+
when Symbol then tokens << token.name
|
22
36
|
when Array then tokens.concat(token)
|
23
37
|
else raise ArgumentError,
|
24
38
|
"Conditional classes must be Symbols, Strings, or Arrays of Symbols or Strings."
|
25
|
-
end
|
26
39
|
end
|
27
|
-
|
28
|
-
tokens.compact.join(" ")
|
29
40
|
end
|
30
41
|
|
31
|
-
def classes(*tokens, **conditional_tokens)
|
42
|
+
private def classes(*tokens, **conditional_tokens)
|
32
43
|
tokens = self.tokens(*tokens, **conditional_tokens)
|
33
44
|
|
34
45
|
if tokens.empty?
|
@@ -38,7 +49,7 @@ module Phlex::Helpers
|
|
38
49
|
end
|
39
50
|
end
|
40
51
|
|
41
|
-
def mix(*args)
|
52
|
+
private def mix(*args)
|
42
53
|
args.each_with_object({}) do |object, result|
|
43
54
|
result.merge!(object) do |_key, old, new|
|
44
55
|
case new
|
data/lib/phlex/html.rb
CHANGED
@@ -136,14 +136,23 @@ module Phlex
|
|
136
136
|
def call(buffer = +"", view_context: nil, parent: nil, &block)
|
137
137
|
return buffer unless render?
|
138
138
|
|
139
|
-
raise "The same view instance shouldn't be rendered twice" if rendered?
|
140
|
-
|
141
|
-
@_rendered = true
|
142
139
|
@_target = buffer
|
143
140
|
@_view_context = view_context
|
144
141
|
@_parent = parent
|
145
142
|
|
146
|
-
around_template
|
143
|
+
around_template do
|
144
|
+
if block_given?
|
145
|
+
template do |*args|
|
146
|
+
if args.length > 0
|
147
|
+
yield_content_with_args(*args, &block)
|
148
|
+
else
|
149
|
+
yield_content(&block)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
else
|
153
|
+
template
|
154
|
+
end
|
155
|
+
end
|
147
156
|
|
148
157
|
self.class.rendered_at_least_once ||= true
|
149
158
|
|
@@ -151,10 +160,13 @@ module Phlex
|
|
151
160
|
end
|
152
161
|
|
153
162
|
def render(renderable, *args, **kwargs, &block)
|
154
|
-
|
163
|
+
case renderable
|
164
|
+
when Phlex::HTML
|
155
165
|
renderable.call(@_target, view_context: @_view_context, parent: self, &block)
|
156
|
-
|
157
|
-
|
166
|
+
when Class
|
167
|
+
if renderable < Phlex::HTML
|
168
|
+
renderable.new.call(@_target, view_context: @_view_context, parent: self, &block)
|
169
|
+
end
|
158
170
|
else
|
159
171
|
raise ArgumentError, "You can't render a #{renderable}."
|
160
172
|
end
|
@@ -166,14 +178,6 @@ module Phlex
|
|
166
178
|
:html
|
167
179
|
end
|
168
180
|
|
169
|
-
def rendered?
|
170
|
-
@_rendered ||= false
|
171
|
-
end
|
172
|
-
|
173
|
-
def render?
|
174
|
-
true
|
175
|
-
end
|
176
|
-
|
177
181
|
STANDARD_ELEMENTS.each do |method_name, tag|
|
178
182
|
register_element(method_name, tag: tag)
|
179
183
|
end
|
@@ -183,14 +187,14 @@ module Phlex
|
|
183
187
|
end
|
184
188
|
|
185
189
|
def text(content)
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
190
|
+
@_target << ERB::Util.html_escape(
|
191
|
+
case content
|
192
|
+
when String then content
|
193
|
+
when Symbol then content.name
|
194
|
+
when Integer, Float then content.to_s
|
195
|
+
else format_object(content) || content.to_s
|
196
|
+
end
|
197
|
+
)
|
194
198
|
|
195
199
|
nil
|
196
200
|
end
|
@@ -238,23 +242,30 @@ module Phlex
|
|
238
242
|
new_buffer
|
239
243
|
end
|
240
244
|
|
241
|
-
|
245
|
+
# Default render predicate can be overridden to prevent rendering
|
246
|
+
private def render?
|
247
|
+
true
|
248
|
+
end
|
249
|
+
|
250
|
+
private def format_object(oject)
|
251
|
+
nil
|
252
|
+
end
|
242
253
|
|
243
|
-
def around_template
|
254
|
+
private def around_template
|
244
255
|
before_template
|
245
256
|
yield
|
246
257
|
after_template
|
247
258
|
end
|
248
259
|
|
249
|
-
def before_template
|
260
|
+
private def before_template
|
250
261
|
nil
|
251
262
|
end
|
252
263
|
|
253
|
-
def after_template
|
264
|
+
private def after_template
|
254
265
|
nil
|
255
266
|
end
|
256
267
|
|
257
|
-
def yield_content(&block)
|
268
|
+
private def yield_content(&block)
|
258
269
|
return unless block_given?
|
259
270
|
|
260
271
|
original_length = @_target.length
|
@@ -264,18 +275,47 @@ module Phlex
|
|
264
275
|
if unchanged
|
265
276
|
case content
|
266
277
|
when String
|
267
|
-
@_target <<
|
278
|
+
@_target << ERB::Util.html_escape(content)
|
268
279
|
when Symbol
|
269
|
-
@_target <<
|
280
|
+
@_target << ERB::Util.html_escape(content.name)
|
270
281
|
when Integer, Float
|
271
|
-
@_target <<
|
282
|
+
@_target << ERB::Util.html_escape(content.to_s)
|
283
|
+
else
|
284
|
+
if (formatted_object = format_object(content))
|
285
|
+
@_target << ERB::Util.html_escape(formatted_object)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
nil
|
291
|
+
end
|
292
|
+
|
293
|
+
private def yield_content_with_args(*args, &block)
|
294
|
+
return unless block_given?
|
295
|
+
|
296
|
+
original_length = @_target.length
|
297
|
+
content = yield(*args)
|
298
|
+
unchanged = (original_length == @_target.length)
|
299
|
+
|
300
|
+
if unchanged
|
301
|
+
case content
|
302
|
+
when String
|
303
|
+
@_target << ERB::Util.html_escape(content)
|
304
|
+
when Symbol
|
305
|
+
@_target << ERB::Util.html_escape(content.name)
|
306
|
+
when Integer, Float
|
307
|
+
@_target << ERB::Util.html_escape(content.to_s)
|
308
|
+
else
|
309
|
+
if (formatted_object = format_object(content))
|
310
|
+
@_target << ERB::Util.html_escape(formatted_object)
|
311
|
+
end
|
272
312
|
end
|
273
313
|
end
|
274
314
|
|
275
315
|
nil
|
276
316
|
end
|
277
317
|
|
278
|
-
def _attributes(**attributes)
|
318
|
+
private def _attributes(**attributes)
|
279
319
|
if attributes[:href]&.start_with?(/\s*javascript/)
|
280
320
|
attributes[:href] = attributes[:href].sub(/^\s*(javascript:)+/, "")
|
281
321
|
end
|
@@ -290,7 +330,7 @@ module Phlex
|
|
290
330
|
buffer
|
291
331
|
end
|
292
332
|
|
293
|
-
def _build_attributes(attributes, buffer:)
|
333
|
+
private def _build_attributes(attributes, buffer:)
|
294
334
|
attributes.each do |k, v|
|
295
335
|
next unless v
|
296
336
|
|
@@ -309,13 +349,13 @@ module Phlex
|
|
309
349
|
when true
|
310
350
|
buffer << " " << name
|
311
351
|
when String
|
312
|
-
buffer << " " << name << '="' <<
|
352
|
+
buffer << " " << name << '="' << ERB::Util.html_escape(v) << '"'
|
313
353
|
when Symbol
|
314
|
-
buffer << " " << name << '="' <<
|
354
|
+
buffer << " " << name << '="' << ERB::Util.html_escape(v.name) << '"'
|
315
355
|
when Hash
|
316
356
|
_build_attributes(v.transform_keys { "#{k}-#{_1.name.tr('_', '-')}" }, buffer: buffer)
|
317
357
|
else
|
318
|
-
buffer << " " << name << '="' <<
|
358
|
+
buffer << " " << name << '="' << ERB::Util.html_escape(v.to_s) << '"'
|
319
359
|
end
|
320
360
|
end
|
321
361
|
|
data/lib/phlex/table.rb
CHANGED
@@ -50,13 +50,11 @@ module Phlex
|
|
50
50
|
child.alias_method :foot_cell, :cell
|
51
51
|
end
|
52
52
|
|
53
|
-
private
|
54
|
-
|
55
|
-
def properties
|
53
|
+
private def properties
|
56
54
|
self.class.properties
|
57
55
|
end
|
58
56
|
|
59
|
-
def collection_template(&block)
|
57
|
+
private def collection_template(&block)
|
60
58
|
table do
|
61
59
|
head_template
|
62
60
|
body_template(&block)
|
@@ -64,11 +62,11 @@ module Phlex
|
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
67
|
-
def item_template
|
65
|
+
private def item_template
|
68
66
|
row_template
|
69
67
|
end
|
70
68
|
|
71
|
-
def head_template
|
69
|
+
private def head_template
|
72
70
|
if self.class.properties.any? { |p| p[:header] }
|
73
71
|
head do
|
74
72
|
head_row do
|
@@ -85,14 +83,14 @@ module Phlex
|
|
85
83
|
end
|
86
84
|
end
|
87
85
|
|
88
|
-
def body_template
|
86
|
+
private def body_template
|
89
87
|
body { yield_items }
|
90
88
|
end
|
91
89
|
|
92
|
-
def foot_template
|
90
|
+
private def foot_template
|
93
91
|
end
|
94
92
|
|
95
|
-
def row_template
|
93
|
+
private def row_template
|
96
94
|
body_row do
|
97
95
|
self.class.properties.each do |property|
|
98
96
|
body_cell(**property[:attributes]) do
|
data/lib/phlex/version.rb
CHANGED
data/lib/phlex.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.0.0
|
4
|
+
version: 1.0.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: 2022-
|
11
|
+
date: 2022-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -81,9 +81,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
81
|
version: '2.7'
|
82
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
83
|
requirements:
|
84
|
-
- - "
|
84
|
+
- - ">="
|
85
85
|
- !ruby/object:Gem::Version
|
86
|
-
version:
|
86
|
+
version: '0'
|
87
87
|
requirements: []
|
88
88
|
rubygems_version: 3.3.25
|
89
89
|
signing_key:
|