phlex 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/phlex/csv.rb +28 -12
- data/lib/phlex/helpers.rb +4 -0
- data/lib/phlex/html/standard_elements.rb +7 -0
- data/lib/phlex/html.rb +0 -3
- data/lib/phlex/sgml/state.rb +12 -15
- data/lib/phlex/sgml.rb +25 -23
- data/lib/phlex/svg.rb +0 -2
- data/lib/phlex/version.rb +1 -1
- data/lib/phlex.rb +14 -29
- metadata +18 -5
- data/lib/phlex/vanish.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3eae91fcc5ec985b668a5e016c518f6392cd91d6d155a1f60552282755ca0e7
|
4
|
+
data.tar.gz: 4bac6d025488edbc104135dc3417286cc4782d4f022caff2a8a414afa12d09c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a18175ffb32c8ae170f9fd2c7f4b990d39500cef81db66545c057f7ff6635a215ba257130c3715a82d1322666ec89badc9beb06fae3325d864a1630f685bea2
|
7
|
+
data.tar.gz: 4ee950b03d2d8f0b8efe085207ca42b139775dff4cc0a564661648995ef32f01fce22e84537194a7c37a6218031d9ab8a4ab7689b92bfeac53534aee4d2fc919
|
data/lib/phlex/csv.rb
CHANGED
@@ -13,6 +13,7 @@ class Phlex::CSV
|
|
13
13
|
@collection = collection
|
14
14
|
@_row_buffer = []
|
15
15
|
@_headers = []
|
16
|
+
@_row_appender = nil
|
16
17
|
end
|
17
18
|
|
18
19
|
attr_reader :collection
|
@@ -49,13 +50,7 @@ class Phlex::CSV
|
|
49
50
|
MESSAGE
|
50
51
|
end
|
51
52
|
|
52
|
-
|
53
|
-
if has_yielder
|
54
|
-
yielder(record) { |*a, **k| row = row_template(*a, **k) }
|
55
|
-
else
|
56
|
-
around_row(record)
|
57
|
-
end
|
58
|
-
|
53
|
+
row_appender = -> {
|
59
54
|
row = row_buffer
|
60
55
|
|
61
56
|
if first_row
|
@@ -108,13 +103,28 @@ class Phlex::CSV
|
|
108
103
|
buffer << "\n"
|
109
104
|
|
110
105
|
row_buffer.clear
|
106
|
+
}
|
107
|
+
|
108
|
+
if has_yielder
|
109
|
+
each_item do |record|
|
110
|
+
yielder(record) do |*a, **k|
|
111
|
+
row_template(*a, **k)
|
112
|
+
row_appender.call
|
113
|
+
end
|
114
|
+
end
|
115
|
+
else
|
116
|
+
@row_appender = row_appender
|
117
|
+
each_item do |record|
|
118
|
+
around_row(record)
|
119
|
+
end
|
111
120
|
end
|
112
121
|
|
113
122
|
buffer
|
114
123
|
end
|
115
124
|
|
116
|
-
def around_row(
|
117
|
-
row_template(
|
125
|
+
def around_row(...)
|
126
|
+
row_template(...)
|
127
|
+
@row_appender.call
|
118
128
|
end
|
119
129
|
|
120
130
|
def filename
|
@@ -168,7 +178,9 @@ class Phlex::CSV
|
|
168
178
|
value = value.strip
|
169
179
|
|
170
180
|
if escape_csv_injection
|
171
|
-
if
|
181
|
+
if value.empty?
|
182
|
+
buffer << value
|
183
|
+
elsif FORMULA_PREFIXES_MAP[value.getbyte(0)]
|
172
184
|
value.gsub!('"', '""')
|
173
185
|
buffer << '"\'' << value << '"'
|
174
186
|
elsif value.match?(escape_regex)
|
@@ -184,7 +196,9 @@ class Phlex::CSV
|
|
184
196
|
if escape_csv_injection
|
185
197
|
first_byte = value.getbyte(0)
|
186
198
|
|
187
|
-
if
|
199
|
+
if value.empty?
|
200
|
+
buffer << '""'
|
201
|
+
elsif FORMULA_PREFIXES_MAP[first_byte]
|
188
202
|
buffer << '"\'' << value.gsub('"', '""') << '"'
|
189
203
|
elsif value.match?(escape_regex)
|
190
204
|
buffer << '"' << value.gsub('"', '""') << '"'
|
@@ -192,7 +206,9 @@ class Phlex::CSV
|
|
192
206
|
buffer << value
|
193
207
|
end
|
194
208
|
else # not escaping CSV injection
|
195
|
-
if value.
|
209
|
+
if value.empty?
|
210
|
+
buffer << '""'
|
211
|
+
elsif value.match?(escape_regex)
|
196
212
|
buffer << '"' << value.gsub('"', '""') << '"'
|
197
213
|
else
|
198
214
|
buffer << value
|
data/lib/phlex/helpers.rb
CHANGED
@@ -472,6 +472,13 @@ module Phlex::HTML::StandardElements
|
|
472
472
|
# [Spec](https://html.spec.whatwg.org/#the-select-element)
|
473
473
|
register_element def select(**attributes, &content) = nil
|
474
474
|
|
475
|
+
# [EXPERIMENTAL] Outputs a `<selectedcontent>` tag.
|
476
|
+
#
|
477
|
+
# [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/selectedcontent)
|
478
|
+
# [Draft Spec](https://github.com/whatwg/html/pull/10633)
|
479
|
+
# [Can I Use?](https://caniuse.com/mdn-html_elements_selectedcontent)
|
480
|
+
register_element def selectedcontent(**attributes, &content) = nil
|
481
|
+
|
475
482
|
# Outputs a `<slot>` tag.
|
476
483
|
#
|
477
484
|
# [MDN Docs](https://developer.mozilla.org/docs/Web/HTML/Element/slot)
|
data/lib/phlex/html.rb
CHANGED
data/lib/phlex/sgml/state.rb
CHANGED
@@ -14,16 +14,7 @@ class Phlex::SGML::State
|
|
14
14
|
|
15
15
|
attr_accessor :capturing, :user_context
|
16
16
|
|
17
|
-
attr_reader :fragments, :fragment_depth, :output_buffer
|
18
|
-
|
19
|
-
def buffer
|
20
|
-
case @buffer
|
21
|
-
when Proc
|
22
|
-
@buffer.call
|
23
|
-
else
|
24
|
-
@buffer
|
25
|
-
end
|
26
|
-
end
|
17
|
+
attr_reader :fragments, :fragment_depth, :output_buffer, :buffer
|
27
18
|
|
28
19
|
def around_render(component)
|
29
20
|
stack = @stack
|
@@ -85,17 +76,23 @@ class Phlex::SGML::State
|
|
85
76
|
end
|
86
77
|
|
87
78
|
def caching(&)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
79
|
+
result = nil
|
80
|
+
|
81
|
+
capture do
|
82
|
+
@cache_stack.push([buffer, {}].freeze)
|
83
|
+
yield
|
84
|
+
result = @cache_stack.pop
|
85
|
+
end
|
86
|
+
|
87
|
+
result
|
92
88
|
end
|
93
89
|
|
94
90
|
def caching?
|
95
91
|
@cache_stack.length > 0
|
96
92
|
end
|
97
93
|
|
98
|
-
def
|
94
|
+
def capture
|
95
|
+
new_buffer = +""
|
99
96
|
original_buffer = @buffer
|
100
97
|
original_capturing = @capturing
|
101
98
|
original_fragments = @fragments
|
data/lib/phlex/sgml.rb
CHANGED
@@ -16,11 +16,6 @@ class Phlex::SGML
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
autoload :Elements, "phlex/sgml/elements"
|
20
|
-
autoload :SafeObject, "phlex/sgml/safe_object"
|
21
|
-
autoload :SafeValue, "phlex/sgml/safe_value"
|
22
|
-
autoload :State, "phlex/sgml/state"
|
23
|
-
|
24
19
|
include Phlex::Helpers
|
25
20
|
|
26
21
|
class << self
|
@@ -217,9 +212,9 @@ class Phlex::SGML
|
|
217
212
|
return "" unless block
|
218
213
|
|
219
214
|
if args.length > 0
|
220
|
-
@_state.
|
215
|
+
@_state.capture { __yield_content_with_args__(*args, &block) }
|
221
216
|
else
|
222
|
-
@_state.
|
217
|
+
@_state.capture { __yield_content__(&block) }
|
223
218
|
end
|
224
219
|
end
|
225
220
|
|
@@ -298,6 +293,8 @@ class Phlex::SGML
|
|
298
293
|
].freeze
|
299
294
|
|
300
295
|
low_level_cache(full_key, **, &content)
|
296
|
+
|
297
|
+
nil
|
301
298
|
end
|
302
299
|
|
303
300
|
# Cache a block of content where you control the entire cache key.
|
@@ -331,6 +328,8 @@ class Phlex::SGML
|
|
331
328
|
end
|
332
329
|
end
|
333
330
|
end
|
331
|
+
|
332
|
+
nil
|
334
333
|
end
|
335
334
|
|
336
335
|
def json_escape(string)
|
@@ -353,15 +352,8 @@ class Phlex::SGML
|
|
353
352
|
false
|
354
353
|
end
|
355
354
|
|
356
|
-
def vanish(
|
357
|
-
|
358
|
-
|
359
|
-
if args.length > 0
|
360
|
-
@_state.capturing_into(Phlex::Vanish) { yield(*args) }
|
361
|
-
else
|
362
|
-
@_state.capturing_into(Phlex::Vanish) { yield(self) }
|
363
|
-
end
|
364
|
-
|
355
|
+
def vanish(...)
|
356
|
+
capture(...)
|
365
357
|
nil
|
366
358
|
end
|
367
359
|
|
@@ -569,14 +561,20 @@ class Phlex::SGML
|
|
569
561
|
attributes.each do |k, v|
|
570
562
|
next unless v
|
571
563
|
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
564
|
+
if (root_key = (:_ == k))
|
565
|
+
name = ""
|
566
|
+
original_base_name = base_name
|
567
|
+
base_name = base_name.delete_suffix("-")
|
568
|
+
else
|
569
|
+
name = case k
|
570
|
+
when String then k
|
571
|
+
when Symbol then k.name.tr("_", "-")
|
572
|
+
else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols")
|
573
|
+
end
|
577
574
|
|
578
|
-
|
579
|
-
|
575
|
+
if name.match?(/[<>&"']/)
|
576
|
+
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
577
|
+
end
|
580
578
|
end
|
581
579
|
|
582
580
|
case v
|
@@ -600,6 +598,10 @@ class Phlex::SGML
|
|
600
598
|
raise Phlex::ArgumentError.new("Invalid attribute value #{v.inspect}.")
|
601
599
|
end
|
602
600
|
|
601
|
+
if root_key
|
602
|
+
base_name = original_base_name
|
603
|
+
end
|
604
|
+
|
603
605
|
buffer
|
604
606
|
end
|
605
607
|
end
|
data/lib/phlex/svg.rb
CHANGED
data/lib/phlex/version.rb
CHANGED
data/lib/phlex.rb
CHANGED
@@ -2,26 +2,22 @@
|
|
2
2
|
|
3
3
|
require "erb"
|
4
4
|
require "set"
|
5
|
+
require "zeitwerk"
|
5
6
|
|
6
7
|
module Phlex
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
autoload :Error, "phlex/error"
|
21
|
-
autoload :NameError, "phlex/errors/name_error"
|
22
|
-
autoload :RuntimeError, "phlex/errors/runtime_error"
|
23
|
-
autoload :ArgumentError, "phlex/errors/argument_error"
|
24
|
-
autoload :DoubleRenderError, "phlex/errors/double_render_error"
|
8
|
+
Loader = Zeitwerk::Loader.for_gem.tap do |loader|
|
9
|
+
loader.push_dir("lib/phlex/errors", namespace: Phlex)
|
10
|
+
loader.inflector.inflect(
|
11
|
+
"csv" => "CSV",
|
12
|
+
"fifo" => "FIFO",
|
13
|
+
"fifo_cache_store" => "FIFOCacheStore",
|
14
|
+
"html" => "HTML",
|
15
|
+
"sgml" => "SGML",
|
16
|
+
"svg" => "SVG",
|
17
|
+
)
|
18
|
+
|
19
|
+
loader.setup
|
20
|
+
end
|
25
21
|
|
26
22
|
Escape = ERB::Escape
|
27
23
|
|
@@ -36,17 +32,6 @@ module Phlex
|
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
39
|
-
def self.eager_load
|
40
|
-
queue = [self]
|
41
|
-
|
42
|
-
while (mod = queue.shift)
|
43
|
-
mod.constants.each do |const_name|
|
44
|
-
const = mod.const_get(const_name)
|
45
|
-
queue << const if Module === const
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
35
|
# Generate an HTML string using Phlex’ HTML DSL
|
51
36
|
def self.html(&block)
|
52
37
|
HTML.call do |component|
|
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: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Drapper
|
8
8
|
- Will Cosgrove
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
12
|
-
dependencies:
|
11
|
+
date: 2025-04-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: zeitwerk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
description: Build HTML, SVG and CSV views with Ruby classes.
|
14
28
|
email:
|
15
29
|
- joel@drapper.me
|
@@ -40,7 +54,6 @@ files:
|
|
40
54
|
- lib/phlex/sgml/state.rb
|
41
55
|
- lib/phlex/svg.rb
|
42
56
|
- lib/phlex/svg/standard_elements.rb
|
43
|
-
- lib/phlex/vanish.rb
|
44
57
|
- lib/phlex/version.rb
|
45
58
|
homepage: https://www.phlex.fun
|
46
59
|
licenses:
|
@@ -65,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
78
|
- !ruby/object:Gem::Version
|
66
79
|
version: '0'
|
67
80
|
requirements: []
|
68
|
-
rubygems_version: 3.6.
|
81
|
+
rubygems_version: 3.6.6
|
69
82
|
specification_version: 4
|
70
83
|
summary: Object-oriented views in Ruby.
|
71
84
|
test_files: []
|
data/lib/phlex/vanish.rb
DELETED