phlex 2.3.1 → 2.4.0.beta2
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/compiler/class_compiler.rb +47 -0
- data/lib/phlex/compiler/compactor.rb +74 -0
- data/lib/phlex/compiler/file_compiler.rb +52 -0
- data/lib/phlex/compiler/method_compiler.rb +579 -0
- data/lib/phlex/compiler.rb +59 -0
- data/lib/phlex/html.rb +3 -3
- data/lib/phlex/sgml/attributes.rb +280 -0
- data/lib/phlex/sgml/elements.rb +8 -8
- data/lib/phlex/sgml.rb +22 -257
- data/lib/phlex/svg.rb +2 -2
- data/lib/phlex/version.rb +1 -1
- data/lib/phlex.rb +2 -0
- metadata +23 -3
@@ -0,0 +1,280 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex::SGML::Attributes
|
4
|
+
extend self
|
5
|
+
|
6
|
+
UNSAFE_ATTRIBUTES = Set.new(%w[srcdoc sandbox http-equiv]).freeze
|
7
|
+
REF_ATTRIBUTES = Set.new(%w[href src action formaction lowsrc dynsrc background ping]).freeze
|
8
|
+
|
9
|
+
def generate_attributes(attributes, buffer = +"")
|
10
|
+
attributes.each do |k, v|
|
11
|
+
next unless v
|
12
|
+
|
13
|
+
name = case k
|
14
|
+
when String then k
|
15
|
+
when Symbol then k.name.tr("_", "-")
|
16
|
+
else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols.")
|
17
|
+
end
|
18
|
+
|
19
|
+
value = case v
|
20
|
+
when true
|
21
|
+
true
|
22
|
+
when String
|
23
|
+
v.gsub('"', """)
|
24
|
+
when Symbol
|
25
|
+
v.name.tr("_", "-").gsub('"', """)
|
26
|
+
when Integer, Float
|
27
|
+
v.to_s
|
28
|
+
when Date
|
29
|
+
v.iso8601
|
30
|
+
when Time
|
31
|
+
v.respond_to?(:iso8601) ? v.iso8601 : v.strftime("%Y-%m-%dT%H:%M:%S%:z")
|
32
|
+
when Hash
|
33
|
+
case k
|
34
|
+
when :style
|
35
|
+
generate_styles(v).gsub('"', """)
|
36
|
+
else
|
37
|
+
generate_nested_attributes(v, "#{name}-", buffer)
|
38
|
+
end
|
39
|
+
when Array
|
40
|
+
case k
|
41
|
+
when :style
|
42
|
+
generate_styles(v).gsub('"', """)
|
43
|
+
else
|
44
|
+
generate_nested_tokens(v)
|
45
|
+
end
|
46
|
+
when Set
|
47
|
+
case k
|
48
|
+
when :style
|
49
|
+
generate_styles(v).gsub('"', """)
|
50
|
+
else
|
51
|
+
generate_nested_tokens(v.to_a)
|
52
|
+
end
|
53
|
+
when Phlex::SGML::SafeObject
|
54
|
+
v.to_s.gsub('"', """)
|
55
|
+
else
|
56
|
+
raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
|
57
|
+
end
|
58
|
+
|
59
|
+
lower_name = name.downcase
|
60
|
+
|
61
|
+
unless Phlex::SGML::SafeObject === v
|
62
|
+
normalized_name = lower_name.delete("^a-z-")
|
63
|
+
|
64
|
+
if value != true && REF_ATTRIBUTES.include?(normalized_name)
|
65
|
+
case value
|
66
|
+
when String
|
67
|
+
if value.downcase.delete("^a-z:").start_with?("javascript:")
|
68
|
+
# We just ignore these because they were likely not specified by the developer.
|
69
|
+
next
|
70
|
+
end
|
71
|
+
else
|
72
|
+
raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if normalized_name.bytesize > 2 && normalized_name.start_with?("on") && !normalized_name.include?("-")
|
77
|
+
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
78
|
+
end
|
79
|
+
|
80
|
+
if UNSAFE_ATTRIBUTES.include?(normalized_name)
|
81
|
+
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
if name.match?(/[<>&"']/)
|
86
|
+
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
87
|
+
end
|
88
|
+
|
89
|
+
if lower_name.to_sym == :id && k != :id
|
90
|
+
raise Phlex::ArgumentError.new(":id attribute should only be passed as a lowercase symbol.")
|
91
|
+
end
|
92
|
+
|
93
|
+
case value
|
94
|
+
when true
|
95
|
+
buffer << " " << name
|
96
|
+
when String
|
97
|
+
buffer << " " << name << '="' << value << '"'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
buffer
|
102
|
+
end
|
103
|
+
|
104
|
+
# Provides the nested-attributes case for serializing out attributes.
|
105
|
+
# This allows us to skip many of the checks the `__attributes__` method must perform.
|
106
|
+
def generate_nested_attributes(attributes, base_name, buffer = +"")
|
107
|
+
attributes.each do |k, v|
|
108
|
+
next unless v
|
109
|
+
|
110
|
+
if (root_key = (:_ == k))
|
111
|
+
name = ""
|
112
|
+
original_base_name = base_name
|
113
|
+
base_name = base_name.delete_suffix("-")
|
114
|
+
else
|
115
|
+
name = case k
|
116
|
+
when String then k
|
117
|
+
when Symbol then k.name.tr("_", "-")
|
118
|
+
else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols")
|
119
|
+
end
|
120
|
+
|
121
|
+
if name.match?(/[<>&"']/)
|
122
|
+
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
case v
|
127
|
+
when true
|
128
|
+
buffer << " " << base_name << name
|
129
|
+
when String
|
130
|
+
buffer << " " << base_name << name << '="' << v.gsub('"', """) << '"'
|
131
|
+
when Symbol
|
132
|
+
buffer << " " << base_name << name << '="' << v.name.tr("_", "-").gsub('"', """) << '"'
|
133
|
+
when Integer, Float
|
134
|
+
buffer << " " << base_name << name << '="' << v.to_s << '"'
|
135
|
+
when Hash
|
136
|
+
generate_nested_attributes(v, "#{base_name}#{name}-", buffer)
|
137
|
+
when Array
|
138
|
+
if (value = generate_nested_tokens(v))
|
139
|
+
buffer << " " << base_name << name << '="' << value << '"'
|
140
|
+
end
|
141
|
+
when Set
|
142
|
+
if (value = generate_nested_tokens(v.to_a))
|
143
|
+
buffer << " " << base_name << name << '="' << value << '"'
|
144
|
+
end
|
145
|
+
when Phlex::SGML::SafeObject
|
146
|
+
buffer << " " << base_name << name << '="' << v.to_s.gsub('"', """) << '"'
|
147
|
+
else
|
148
|
+
raise Phlex::ArgumentError.new("Invalid attribute value #{v.inspect}.")
|
149
|
+
end
|
150
|
+
|
151
|
+
if root_key
|
152
|
+
base_name = original_base_name
|
153
|
+
end
|
154
|
+
|
155
|
+
buffer
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def generate_nested_tokens(tokens, sep = " ", gsub_from = nil, gsub_to = "")
|
160
|
+
buffer = +""
|
161
|
+
|
162
|
+
i, length = 0, tokens.length
|
163
|
+
|
164
|
+
while i < length
|
165
|
+
token = tokens[i]
|
166
|
+
|
167
|
+
case token
|
168
|
+
when String
|
169
|
+
token = token.gsub(gsub_from, gsub_to) if gsub_from
|
170
|
+
if i > 0
|
171
|
+
buffer << sep << token
|
172
|
+
else
|
173
|
+
buffer << token
|
174
|
+
end
|
175
|
+
when Symbol
|
176
|
+
if i > 0
|
177
|
+
buffer << sep << token.name.tr("_", "-")
|
178
|
+
else
|
179
|
+
buffer << token.name.tr("_", "-")
|
180
|
+
end
|
181
|
+
when Integer, Float, Phlex::SGML::SafeObject
|
182
|
+
if i > 0
|
183
|
+
buffer << sep << token.to_s
|
184
|
+
else
|
185
|
+
buffer << token.to_s
|
186
|
+
end
|
187
|
+
when Array
|
188
|
+
if token.length > 0 && (value = generate_nested_tokens(token, sep, gsub_from, gsub_to))
|
189
|
+
if i > 0
|
190
|
+
buffer << sep << value
|
191
|
+
else
|
192
|
+
buffer << value
|
193
|
+
end
|
194
|
+
end
|
195
|
+
when Set
|
196
|
+
if token.length > 0 && (value = generate_nested_tokens(token.to_a, sep, gsub_from, gsub_to))
|
197
|
+
if i > 0
|
198
|
+
buffer << sep << value
|
199
|
+
else
|
200
|
+
buffer << value
|
201
|
+
end
|
202
|
+
end
|
203
|
+
when nil
|
204
|
+
# Do nothing
|
205
|
+
else
|
206
|
+
raise Phlex::ArgumentError.new("Invalid token type: #{token.class}.")
|
207
|
+
end
|
208
|
+
|
209
|
+
i += 1
|
210
|
+
end
|
211
|
+
|
212
|
+
return if buffer.empty?
|
213
|
+
|
214
|
+
buffer.gsub('"', """)
|
215
|
+
end
|
216
|
+
|
217
|
+
# The result is unsafe so should be escaped.
|
218
|
+
def generate_styles(styles)
|
219
|
+
case styles
|
220
|
+
when Array, Set
|
221
|
+
styles.filter_map do |s|
|
222
|
+
case s
|
223
|
+
when String
|
224
|
+
if s == "" || s.end_with?(";")
|
225
|
+
s
|
226
|
+
else
|
227
|
+
"#{s};"
|
228
|
+
end
|
229
|
+
when Phlex::SGML::SafeObject
|
230
|
+
value = s.to_s
|
231
|
+
value.end_with?(";") ? value : "#{value};"
|
232
|
+
when Hash
|
233
|
+
next generate_styles(s)
|
234
|
+
when nil
|
235
|
+
next nil
|
236
|
+
else
|
237
|
+
raise Phlex::ArgumentError.new("Invalid style: #{s.inspect}.")
|
238
|
+
end
|
239
|
+
end.join(" ")
|
240
|
+
when Hash
|
241
|
+
buffer = +""
|
242
|
+
i = 0
|
243
|
+
styles.each do |k, v|
|
244
|
+
prop = case k
|
245
|
+
when String
|
246
|
+
k
|
247
|
+
when Symbol
|
248
|
+
k.name.tr("_", "-")
|
249
|
+
else
|
250
|
+
raise Phlex::ArgumentError.new("Style keys should be Strings or Symbols.")
|
251
|
+
end
|
252
|
+
|
253
|
+
value = case v
|
254
|
+
when String
|
255
|
+
v
|
256
|
+
when Symbol
|
257
|
+
v.name.tr("_", "-")
|
258
|
+
when Integer, Float, Phlex::SGML::SafeObject
|
259
|
+
v.to_s
|
260
|
+
when nil
|
261
|
+
nil
|
262
|
+
else
|
263
|
+
raise Phlex::ArgumentError.new("Invalid style value: #{v.inspect}")
|
264
|
+
end
|
265
|
+
|
266
|
+
if value
|
267
|
+
if i == 0
|
268
|
+
buffer << prop << ": " << value << ";"
|
269
|
+
else
|
270
|
+
buffer << " " << prop << ": " << value << ";"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
i += 1
|
275
|
+
end
|
276
|
+
|
277
|
+
buffer
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
data/lib/phlex/sgml/elements.rb
CHANGED
@@ -4,16 +4,16 @@ module Phlex::SGML::Elements
|
|
4
4
|
COMMA_SEPARATED_TOKENS = {
|
5
5
|
img: <<~RUBY,
|
6
6
|
if Array === (srcset_attribute = attributes[:srcset])
|
7
|
-
attributes[:srcset] =
|
7
|
+
attributes[:srcset] = Phlex::SGML::Attributes.generate_nested_tokens(srcset_attribute, ", ", ",", "%2C")
|
8
8
|
end
|
9
9
|
RUBY
|
10
10
|
link: <<~RUBY,
|
11
11
|
if Array === (media_attribute = attributes[:media])
|
12
|
-
attributes[:media] =
|
12
|
+
attributes[:media] = Phlex::SGML::Attributes.generate_nested_tokens(media_attribute, ", ", ",", "%2C")
|
13
13
|
end
|
14
14
|
|
15
15
|
if Array === (sizes_attribute = attributes[:sizes])
|
16
|
-
attributes[:sizes] =
|
16
|
+
attributes[:sizes] = Phlex::SGML::Attributes.generate_nested_tokens(sizes_attribute, ", ", ",", "%2C")
|
17
17
|
end
|
18
18
|
|
19
19
|
if Array === (imagesrcset_attribute = attributes[:imagesrcset])
|
@@ -21,7 +21,7 @@ module Phlex::SGML::Elements
|
|
21
21
|
as_attribute = attributes[:as] || attributes["as"]
|
22
22
|
|
23
23
|
if ("preload" == rel_attribute || :preload == rel_attribute) && ("image" == as_attribute || :image == as_attribute)
|
24
|
-
attributes[:imagesrcset] =
|
24
|
+
attributes[:imagesrcset] = Phlex::SGML::Attributes.generate_nested_tokens(imagesrcset_attribute, ", ", ",", "%2C")
|
25
25
|
end
|
26
26
|
end
|
27
27
|
RUBY
|
@@ -30,7 +30,7 @@ module Phlex::SGML::Elements
|
|
30
30
|
type_attribute = attributes[:type] || attributes["type"]
|
31
31
|
|
32
32
|
if "file" == type_attribute || :file == type_attribute
|
33
|
-
attributes[:accept] =
|
33
|
+
attributes[:accept] = Phlex::SGML::Attributes.generate_nested_tokens(accept_attribute, ", ", ",", "%2C")
|
34
34
|
end
|
35
35
|
end
|
36
36
|
RUBY
|
@@ -59,7 +59,7 @@ module Phlex::SGML::Elements
|
|
59
59
|
buffer << "<#{tag}"
|
60
60
|
begin
|
61
61
|
#{COMMA_SEPARATED_TOKENS[method_name]}
|
62
|
-
buffer << (Phlex::ATTRIBUTE_CACHE[attributes] ||=
|
62
|
+
buffer << (Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes))
|
63
63
|
ensure
|
64
64
|
buffer << ">"
|
65
65
|
end
|
@@ -90,7 +90,7 @@ module Phlex::SGML::Elements
|
|
90
90
|
buffer << "<#{tag}"
|
91
91
|
begin
|
92
92
|
#{COMMA_SEPARATED_TOKENS[method_name]}
|
93
|
-
buffer << (::Phlex::ATTRIBUTE_CACHE[attributes] ||=
|
93
|
+
buffer << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes))
|
94
94
|
ensure
|
95
95
|
buffer << "></#{tag}>"
|
96
96
|
end
|
@@ -152,7 +152,7 @@ module Phlex::SGML::Elements
|
|
152
152
|
buffer << "<#{tag}"
|
153
153
|
begin
|
154
154
|
#{COMMA_SEPARATED_TOKENS[method_name]}
|
155
|
-
buffer << (::Phlex::ATTRIBUTE_CACHE[attributes] ||=
|
155
|
+
buffer << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes))
|
156
156
|
ensure
|
157
157
|
buffer << ">"
|
158
158
|
end
|
data/lib/phlex/sgml.rb
CHANGED
@@ -2,9 +2,6 @@
|
|
2
2
|
|
3
3
|
# **Standard Generalized Markup Language** for behaviour common to {HTML} and {SVG}.
|
4
4
|
class Phlex::SGML
|
5
|
-
UNSAFE_ATTRIBUTES = Set.new(%w[srcdoc sandbox http-equiv]).freeze
|
6
|
-
REF_ATTRIBUTES = Set.new(%w[href src action formaction lowsrc dynsrc background ping]).freeze
|
7
|
-
|
8
5
|
ERBCompiler = ERB::Compiler.new("<>").tap do |compiler|
|
9
6
|
compiler.pre_cmd = [""]
|
10
7
|
compiler.put_cmd = "@_state.buffer.<<"
|
@@ -462,272 +459,40 @@ class Phlex::SGML
|
|
462
459
|
true
|
463
460
|
end
|
464
461
|
|
465
|
-
private def
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
name = case k
|
470
|
-
when String then k
|
471
|
-
when Symbol then k.name.tr("_", "-")
|
472
|
-
else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols.")
|
473
|
-
end
|
474
|
-
|
475
|
-
value = case v
|
476
|
-
when true
|
477
|
-
true
|
478
|
-
when String
|
479
|
-
v.gsub('"', """)
|
480
|
-
when Symbol
|
481
|
-
v.name.tr("_", "-").gsub('"', """)
|
482
|
-
when Integer, Float
|
483
|
-
v.to_s
|
484
|
-
when Date
|
485
|
-
v.iso8601
|
486
|
-
when Time
|
487
|
-
v.respond_to?(:iso8601) ? v.iso8601 : v.strftime("%Y-%m-%dT%H:%M:%S%:z")
|
488
|
-
when Hash
|
489
|
-
case k
|
490
|
-
when :style
|
491
|
-
__styles__(v).gsub('"', """)
|
492
|
-
else
|
493
|
-
__nested_attributes__(v, "#{name}-", buffer)
|
494
|
-
end
|
495
|
-
when Array
|
496
|
-
case k
|
497
|
-
when :style
|
498
|
-
__styles__(v).gsub('"', """)
|
499
|
-
else
|
500
|
-
__nested_tokens__(v)
|
501
|
-
end
|
502
|
-
when Set
|
503
|
-
case k
|
504
|
-
when :style
|
505
|
-
__styles__(v).gsub('"', """)
|
506
|
-
else
|
507
|
-
__nested_tokens__(v.to_a)
|
508
|
-
end
|
509
|
-
when Phlex::SGML::SafeObject
|
510
|
-
v.to_s.gsub('"', """)
|
511
|
-
else
|
512
|
-
raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
|
513
|
-
end
|
514
|
-
|
515
|
-
lower_name = name.downcase
|
516
|
-
|
517
|
-
unless Phlex::SGML::SafeObject === v
|
518
|
-
normalized_name = lower_name.delete("^a-z-")
|
519
|
-
|
520
|
-
if value != true && REF_ATTRIBUTES.include?(normalized_name)
|
521
|
-
case value
|
522
|
-
when String
|
523
|
-
if value.downcase.delete("^a-z:").start_with?("javascript:")
|
524
|
-
# We just ignore these because they were likely not specified by the developer.
|
525
|
-
next
|
526
|
-
end
|
527
|
-
else
|
528
|
-
raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
|
529
|
-
end
|
530
|
-
end
|
531
|
-
|
532
|
-
if normalized_name.bytesize > 2 && normalized_name.start_with?("on") && !normalized_name.include?("-")
|
533
|
-
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
534
|
-
end
|
535
|
-
|
536
|
-
if UNSAFE_ATTRIBUTES.include?(normalized_name)
|
537
|
-
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
538
|
-
end
|
539
|
-
end
|
540
|
-
|
541
|
-
if name.match?(/[<>&"']/)
|
542
|
-
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
543
|
-
end
|
544
|
-
|
545
|
-
if lower_name.to_sym == :id && k != :id
|
546
|
-
raise Phlex::ArgumentError.new(":id attribute should only be passed as a lowercase symbol.")
|
547
|
-
end
|
548
|
-
|
549
|
-
case value
|
550
|
-
when true
|
551
|
-
buffer << " " << name
|
552
|
-
when String
|
553
|
-
buffer << " " << name << '="' << value << '"'
|
554
|
-
end
|
555
|
-
end
|
556
|
-
|
557
|
-
buffer
|
558
|
-
end
|
559
|
-
|
560
|
-
# Provides the nested-attributes case for serializing out attributes.
|
561
|
-
# This allows us to skip many of the checks the `__attributes__` method must perform.
|
562
|
-
private def __nested_attributes__(attributes, base_name, buffer = +"")
|
563
|
-
attributes.each do |k, v|
|
564
|
-
next unless v
|
565
|
-
|
566
|
-
if (root_key = (:_ == k))
|
567
|
-
name = ""
|
568
|
-
original_base_name = base_name
|
569
|
-
base_name = base_name.delete_suffix("-")
|
570
|
-
else
|
571
|
-
name = case k
|
572
|
-
when String then k
|
573
|
-
when Symbol then k.name.tr("_", "-")
|
574
|
-
else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols")
|
575
|
-
end
|
576
|
-
|
577
|
-
if name.match?(/[<>&"']/)
|
578
|
-
raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
|
579
|
-
end
|
580
|
-
end
|
581
|
-
|
582
|
-
case v
|
583
|
-
when true
|
584
|
-
buffer << " " << base_name << name
|
585
|
-
when String
|
586
|
-
buffer << " " << base_name << name << '="' << v.gsub('"', """) << '"'
|
587
|
-
when Symbol
|
588
|
-
buffer << " " << base_name << name << '="' << v.name.tr("_", "-").gsub('"', """) << '"'
|
589
|
-
when Integer, Float
|
590
|
-
buffer << " " << base_name << name << '="' << v.to_s << '"'
|
591
|
-
when Hash
|
592
|
-
__nested_attributes__(v, "#{base_name}#{name}-", buffer)
|
593
|
-
when Array
|
594
|
-
buffer << " " << base_name << name << '="' << __nested_tokens__(v) << '"'
|
595
|
-
when Set
|
596
|
-
buffer << " " << base_name << name << '="' << __nested_tokens__(v.to_a) << '"'
|
597
|
-
when Phlex::SGML::SafeObject
|
598
|
-
buffer << " " << base_name << name << '="' << v.to_s.gsub('"', """) << '"'
|
599
|
-
else
|
600
|
-
raise Phlex::ArgumentError.new("Invalid attribute value #{v.inspect}.")
|
601
|
-
end
|
602
|
-
|
603
|
-
if root_key
|
604
|
-
base_name = original_base_name
|
605
|
-
end
|
606
|
-
|
607
|
-
buffer
|
608
|
-
end
|
462
|
+
private def __render_attributes__(attributes)
|
463
|
+
state = @_state
|
464
|
+
return unless state.should_render?
|
465
|
+
state.buffer << (Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes))
|
609
466
|
end
|
610
467
|
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
i, length = 0, tokens.length
|
615
|
-
|
616
|
-
while i < length
|
617
|
-
token = tokens[i]
|
468
|
+
private_class_method def self.method_added(method_name)
|
469
|
+
if method_name == :view_template
|
470
|
+
location = instance_method(method_name).source_location[0]
|
618
471
|
|
619
|
-
|
620
|
-
|
621
|
-
if i > 0
|
622
|
-
buffer << sep << token
|
623
|
-
else
|
624
|
-
buffer << token
|
625
|
-
end
|
626
|
-
when Symbol
|
627
|
-
if i > 0
|
628
|
-
buffer << sep << token.name.tr("_", "-")
|
629
|
-
else
|
630
|
-
buffer << token.name.tr("_", "-")
|
631
|
-
end
|
632
|
-
when Integer, Float, Phlex::SGML::SafeObject
|
633
|
-
if i > 0
|
634
|
-
buffer << sep << token.to_s
|
635
|
-
else
|
636
|
-
buffer << token.to_s
|
637
|
-
end
|
638
|
-
when Array
|
639
|
-
if token.length > 0
|
640
|
-
if i > 0
|
641
|
-
buffer << sep << __nested_tokens__(token, sep)
|
642
|
-
else
|
643
|
-
buffer << __nested_tokens__(token, sep)
|
644
|
-
end
|
645
|
-
end
|
646
|
-
when nil
|
647
|
-
# Do nothing
|
648
|
-
else
|
649
|
-
raise Phlex::ArgumentError.new("Invalid token type: #{token.class}.")
|
472
|
+
if location[0] in "/" | "."
|
473
|
+
Phlex.__expand_attribute_cache__(location)
|
650
474
|
end
|
651
|
-
|
652
|
-
i += 1
|
653
475
|
end
|
654
476
|
|
655
|
-
|
477
|
+
super
|
656
478
|
end
|
657
479
|
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
styles.filter_map do |s|
|
663
|
-
case s
|
664
|
-
when String
|
665
|
-
if s == "" || s.end_with?(";")
|
666
|
-
s
|
667
|
-
else
|
668
|
-
"#{s};"
|
669
|
-
end
|
670
|
-
when Phlex::SGML::SafeObject
|
671
|
-
value = s.to_s
|
672
|
-
value.end_with?(";") ? value : "#{value};"
|
673
|
-
when Hash
|
674
|
-
next __styles__(s)
|
675
|
-
when nil
|
676
|
-
next nil
|
677
|
-
else
|
678
|
-
raise Phlex::ArgumentError.new("Invalid style: #{s.inspect}.")
|
679
|
-
end
|
680
|
-
end.join(" ")
|
681
|
-
when Hash
|
682
|
-
buffer = +""
|
683
|
-
i = 0
|
684
|
-
styles.each do |k, v|
|
685
|
-
prop = case k
|
686
|
-
when String
|
687
|
-
k
|
688
|
-
when Symbol
|
689
|
-
k.name.tr("_", "-")
|
690
|
-
else
|
691
|
-
raise Phlex::ArgumentError.new("Style keys should be Strings or Symbols.")
|
692
|
-
end
|
480
|
+
def self.__compile__(method_name)
|
481
|
+
path, line = instance_method(method_name).source_location
|
482
|
+
Phlex::Compiler::Method.new(self, path, line, method_name).compile
|
483
|
+
end
|
693
484
|
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
when Integer, Float, Phlex::SGML::SafeObject
|
700
|
-
v.to_s
|
701
|
-
when nil
|
702
|
-
nil
|
485
|
+
def __map_exception__(exception)
|
486
|
+
exception.set_backtrace(
|
487
|
+
exception.backtrace_locations.map do |loc|
|
488
|
+
if ((map = Phlex::Compiler::MAP[loc.path]) && (line = map[loc.lineno]))
|
489
|
+
"[Phlex] #{loc.path}:#{line}:#{loc.label}"
|
703
490
|
else
|
704
|
-
|
491
|
+
"#{loc.path}:#{loc.lineno}:#{loc.label}"
|
705
492
|
end
|
706
|
-
|
707
|
-
if value
|
708
|
-
if i == 0
|
709
|
-
buffer << prop << ": " << value << ";"
|
710
|
-
else
|
711
|
-
buffer << " " << prop << ": " << value << ";"
|
712
|
-
end
|
713
|
-
end
|
714
|
-
|
715
|
-
i += 1
|
716
493
|
end
|
494
|
+
)
|
717
495
|
|
718
|
-
|
719
|
-
end
|
720
|
-
end
|
721
|
-
|
722
|
-
private_class_method def self.method_added(method_name)
|
723
|
-
if method_name == :view_template
|
724
|
-
location = instance_method(method_name).source_location[0]
|
725
|
-
|
726
|
-
if location[0] in "/" | "."
|
727
|
-
Phlex.__expand_attribute_cache__(location)
|
728
|
-
end
|
729
|
-
else
|
730
|
-
super
|
731
|
-
end
|
496
|
+
exception
|
732
497
|
end
|
733
498
|
end
|
data/lib/phlex/svg.rb
CHANGED
@@ -44,11 +44,11 @@ class Phlex::SVG < Phlex::SGML
|
|
44
44
|
if (tag = StandardElements.__registered_elements__[name]) || (tag = name.name.tr("_", "-")).include?("-")
|
45
45
|
if attributes.length > 0 # with attributes
|
46
46
|
if block_given # with content block
|
47
|
-
buffer << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes] ||=
|
47
|
+
buffer << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes)) << ">"
|
48
48
|
__yield_content__(&)
|
49
49
|
buffer << "</#{tag}>"
|
50
50
|
else # without content
|
51
|
-
buffer << "<#{tag}" << (::Phlex::ATTRIBUTE_CACHE[attributes] ||=
|
51
|
+
buffer << "<#{tag}" << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes)) << "></#{tag}>"
|
52
52
|
end
|
53
53
|
else # without attributes
|
54
54
|
if block_given # with content block
|
data/lib/phlex/version.rb
CHANGED
data/lib/phlex.rb
CHANGED
@@ -27,6 +27,8 @@ module Phlex
|
|
27
27
|
CACHED_FILES = Set.new
|
28
28
|
ATTRIBUTE_CACHE = FIFO.new
|
29
29
|
|
30
|
+
UNBOUND_INSTANCE_METHOD_METHOD = Module.instance_method(:instance_method)
|
31
|
+
|
30
32
|
def self.__expand_attribute_cache__(file_path)
|
31
33
|
unless CACHED_FILES.include?(file_path)
|
32
34
|
CACHED_FILES << file_path
|