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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d4cbcb774d4dca95d1cb9740c0a002fd394c6887dec1e1cabe543c87f94308b
4
- data.tar.gz: 1df41572816aefd255defc3ceace6e4c5eaeb5f462d26e2605fc751a4ea3d3d0
3
+ metadata.gz: e074c926f013d613e2523b41c8dd604758d087c64d377b50a343c651b0164c0d
4
+ data.tar.gz: 56019e811dff06ef053adfeb20160fe29c247ee2e2f37848eba1580d240c41fd
5
5
  SHA512:
6
- metadata.gz: 589006a44bc566ce1e1dfc90f1e05e9b3f6c7871c9686ba3670fd36b68b1318449b05cc2268c865b89779126092065a7d69cde793d753ea8d7dcaf268d8e1e9e
7
- data.tar.gz: c7a960b66cd78bb9605cb37408bc6a044167ec912a249b40e46e58dd07e398e5a122737a28246e3eac2945a65156b72e57fb35096069719be3c4faa72b007ef7
6
+ metadata.gz: 24489ae7f67415aa23ce258d6a121fe37418ce32e543888410b730821feeafd5fda6f164dd6f390f9dd4a0ec7a8a92ae5c50deb53376f95f987203ad4da2acf2
7
+ data.tar.gz: 1ddfa0b6dff09c597cec5f77f521faf89344981e4f3ddd3237722d94cb4d4faeec0d385a7ef4a0a18acec770d7f22811ac489ae94dfdfc3fc92fbf1cbb676f20
data/.rubocop.yml CHANGED
@@ -24,3 +24,7 @@ Style/MethodCallWithoutArgsParentheses:
24
24
 
25
25
  Style/MixinUsage:
26
26
  Enabled: false
27
+
28
+ Style/AccessModifierDeclarations:
29
+ Enabled: true
30
+ EnforcedStyle: inline
data/Gemfile CHANGED
@@ -10,6 +10,7 @@ gem "sus"
10
10
  gem "syntax_suggest"
11
11
  gem "zeitwerk"
12
12
  gem "benchmark-ips"
13
+ gem "erb"
13
14
 
14
15
  group :test do
15
16
  gem "i18n"
data/SECURITY.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Security Policy
2
2
 
3
- ## Reporting a Vulnerability
3
+ ## Reporting a vulnerability
4
4
 
5
- If you found a possible security vulnerability in Phlex, please email security@phlex.fun.
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.
@@ -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
@@ -2,6 +2,12 @@
2
2
 
3
3
  module Phlex
4
4
  class Configuration
5
- # Config coming soon.
5
+ attr_writer :experimental_warnings
6
+
7
+ def experimental_warnings
8
+ return @experimental_warnings if defined? @experimental_warnings
9
+
10
+ true
11
+ end
6
12
  end
7
13
  end
@@ -3,7 +3,10 @@
3
3
  module Phlex
4
4
  module Experimental
5
5
  def before_template
6
- puts "Warning: #{self.class.name} is experimental and subject to change."
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
- when Symbol then next unless send(condition)
14
- when Proc then next unless condition.call
15
- else raise ArgumentError,
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
- case token
20
- when Symbol then tokens << token.name
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 { template { yield_content(&block) } }
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
- if renderable.is_a?(Phlex::HTML)
163
+ case renderable
164
+ when Phlex::HTML
155
165
  renderable.call(@_target, view_context: @_view_context, parent: self, &block)
156
- elsif renderable.is_a?(Class) && renderable < Phlex::HTML
157
- raise ArgumentError, "You tried to render the Phlex view class: #{renderable.name} but you probably meant to render an instance of that class instead."
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
- case content
187
- when String
188
- @_target << CGI.escape_html(content)
189
- when Symbol
190
- @_target << CGI.escape_html(content.name)
191
- when Integer, Float
192
- @_target << CGI.escape_html(content.to_s)
193
- end
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
- private
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 << CGI.escape_html(content)
278
+ @_target << ERB::Util.html_escape(content)
268
279
  when Symbol
269
- @_target << CGI.escape_html(content.name)
280
+ @_target << ERB::Util.html_escape(content.name)
270
281
  when Integer, Float
271
- @_target << CGI.escape_html(content.to_s)
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 << '="' << CGI.escape_html(v) << '"'
352
+ buffer << " " << name << '="' << ERB::Util.html_escape(v) << '"'
313
353
  when Symbol
314
- buffer << " " << name << '="' << CGI.escape_html(v.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 << '="' << CGI.escape_html(v.to_s) << '"'
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Phlex
4
- VERSION = "1.0.0.rc1"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/phlex.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cgi"
3
+ require "erb"
4
4
  require "zeitwerk"
5
5
 
6
6
  module Phlex
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.rc1
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-25 00:00:00.000000000 Z
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: 1.3.1
86
+ version: '0'
87
87
  requirements: []
88
88
  rubygems_version: 3.3.25
89
89
  signing_key: