phlex 2.3.1 → 2.4.0.beta1

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.
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "prism"
4
+ require "refract"
5
+
6
+ module Phlex::Compiler
7
+ Error = Class.new(StandardError)
8
+
9
+ def self.compile(component)
10
+ path, line = Object.const_source_location(component.name)
11
+ return unless File.exist?(path)
12
+ source = File.read(path)
13
+ tree = Prism.parse(source).value
14
+ refract = Refract::Converter.new.visit(tree)
15
+
16
+ Compilation.new(component, path, line, source, refract).compile
17
+ end
18
+ end
data/lib/phlex/html.rb CHANGED
@@ -58,7 +58,7 @@ class Phlex::HTML < Phlex::SGML
58
58
  if (tag = StandardElements.__registered_elements__[name]) || (tag = name.name.tr("_", "-")).include?("-")
59
59
  if attributes.length > 0 # with attributes
60
60
  if block_given # with content block
61
- buffer << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes] ||= __attributes__(attributes)) << ">"
61
+ buffer << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes)) << ">"
62
62
  if tag == "svg"
63
63
  render Phlex::SVG.new(&)
64
64
  else
@@ -66,7 +66,7 @@ class Phlex::HTML < Phlex::SGML
66
66
  end
67
67
  buffer << "</#{tag}>"
68
68
  else # without content
69
- buffer << "<#{tag}" << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= __attributes__(attributes)) << "></#{tag}>"
69
+ buffer << "<#{tag}" << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes)) << "></#{tag}>"
70
70
  end
71
71
  else # without attributes
72
72
  if block_given # with content block
@@ -87,7 +87,7 @@ class Phlex::HTML < Phlex::SGML
87
87
  end
88
88
 
89
89
  if attributes.length > 0 # with attributes
90
- buffer << "<#{tag}" << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= __attributes__(attributes)) << ">"
90
+ buffer << "<#{tag}" << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= Phlex::SGML::Attributes.generate_attributes(attributes)) << ">"
91
91
  else # without attributes
92
92
  buffer << "<#{tag}>"
93
93
  end
@@ -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('"', "&quot;")
24
+ when Symbol
25
+ v.name.tr("_", "-").gsub('"', "&quot;")
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('"', "&quot;")
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('"', "&quot;")
43
+ else
44
+ generate_nested_tokens(v)
45
+ end
46
+ when Set
47
+ case k
48
+ when :style
49
+ generate_styles(v).gsub('"', "&quot;")
50
+ else
51
+ generate_nested_tokens(v.to_a)
52
+ end
53
+ when Phlex::SGML::SafeObject
54
+ v.to_s.gsub('"', "&quot;")
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('"', "&quot;") << '"'
131
+ when Symbol
132
+ buffer << " " << base_name << name << '="' << v.name.tr("_", "-").gsub('"', "&quot;") << '"'
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('"', "&quot;") << '"'
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('"', "&quot;")
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
@@ -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] = __nested_tokens__(srcset_attribute, ", ")
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] = __nested_tokens__(media_attribute, ", ")
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] = __nested_tokens__(sizes_attribute, ", ")
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] = __nested_tokens__(imagesrcset_attribute, ", ")
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] = __nested_tokens__(accept_attribute, ", ")
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] ||= __attributes__(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] ||= __attributes__(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] ||= __attributes__(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,261 +459,10 @@ class Phlex::SGML
462
459
  true
463
460
  end
464
461
 
465
- private def __attributes__(attributes, buffer = +"")
466
- attributes.each do |k, v|
467
- next unless v
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('"', "&quot;")
480
- when Symbol
481
- v.name.tr("_", "-").gsub('"', "&quot;")
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('"', "&quot;")
492
- else
493
- __nested_attributes__(v, "#{name}-", buffer)
494
- end
495
- when Array
496
- case k
497
- when :style
498
- __styles__(v).gsub('"', "&quot;")
499
- else
500
- __nested_tokens__(v)
501
- end
502
- when Set
503
- case k
504
- when :style
505
- __styles__(v).gsub('"', "&quot;")
506
- else
507
- __nested_tokens__(v.to_a)
508
- end
509
- when Phlex::SGML::SafeObject
510
- v.to_s.gsub('"', "&quot;")
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('"', "&quot;") << '"'
587
- when Symbol
588
- buffer << " " << base_name << name << '="' << v.name.tr("_", "-").gsub('"', "&quot;") << '"'
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('"', "&quot;") << '"'
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
609
- end
610
-
611
- private def __nested_tokens__(tokens, sep = " ")
612
- buffer = +""
613
-
614
- i, length = 0, tokens.length
615
-
616
- while i < length
617
- token = tokens[i]
618
-
619
- case token
620
- when String
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}.")
650
- end
651
-
652
- i += 1
653
- end
654
-
655
- buffer.gsub('"', "&quot;")
656
- end
657
-
658
- # Result is **unsafe**, so it should be escaped!
659
- private def __styles__(styles)
660
- case styles
661
- when Array, Set
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
693
-
694
- value = case v
695
- when String
696
- v
697
- when Symbol
698
- v.name.tr("_", "-")
699
- when Integer, Float, Phlex::SGML::SafeObject
700
- v.to_s
701
- when nil
702
- nil
703
- else
704
- raise Phlex::ArgumentError.new("Invalid style value: #{v.inspect}")
705
- 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
- end
717
-
718
- buffer
719
- 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))
720
466
  end
721
467
 
722
468
  private_class_method def self.method_added(method_name)
@@ -726,8 +472,13 @@ class Phlex::SGML
726
472
  if location[0] in "/" | "."
727
473
  Phlex.__expand_attribute_cache__(location)
728
474
  end
729
- else
730
- super
731
475
  end
476
+
477
+ super
478
+ end
479
+
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
732
483
  end
733
484
  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] ||= __attributes__(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] ||= __attributes__(attributes)) << "></#{tag}>"
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Phlex
4
- VERSION = "2.3.1"
4
+ VERSION = "2.4.0.beta1"
5
5
  end