phlex 2.3.2 → 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.
data/lib/phlex/sgml.rb CHANGED
@@ -2,15 +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 xlinkhref]).freeze
7
- NAMED_CHARACTER_REFERENCES = {
8
- "colon" => ":",
9
- "tab" => "\t",
10
- "newline" => "\n",
11
- }.freeze
12
- UNSAFE_ATTRIBUTE_NAME_CHARS = %r([<>&"'/=\s\x00])
13
-
14
5
  ERBCompiler = ERB::Compiler.new("<>").tap do |compiler|
15
6
  compiler.pre_cmd = [""]
16
7
  compiler.put_cmd = "@_state.buffer.<<"
@@ -468,284 +459,10 @@ class Phlex::SGML
468
459
  true
469
460
  end
470
461
 
471
- private def __attributes__(attributes, buffer = +"")
472
- attributes.each do |k, v|
473
- next unless v
474
-
475
- name = case k
476
- when String then k
477
- when Symbol then k.name.tr("_", "-")
478
- else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols.")
479
- end
480
-
481
- value = case v
482
- when true
483
- true
484
- when String
485
- v.gsub('"', "&quot;")
486
- when Symbol
487
- v.name.tr("_", "-").gsub('"', "&quot;")
488
- when Integer, Float
489
- v.to_s
490
- when Date
491
- v.iso8601
492
- when Time
493
- v.respond_to?(:iso8601) ? v.iso8601 : v.strftime("%Y-%m-%dT%H:%M:%S%:z")
494
- when Hash
495
- case k
496
- when :style
497
- __styles__(v).gsub('"', "&quot;")
498
- else
499
- __nested_attributes__(v, "#{name}-", buffer)
500
- end
501
- when Array
502
- case k
503
- when :style
504
- __styles__(v).gsub('"', "&quot;")
505
- else
506
- __nested_tokens__(v)
507
- end
508
- when Set
509
- case k
510
- when :style
511
- __styles__(v).gsub('"', "&quot;")
512
- else
513
- __nested_tokens__(v.to_a)
514
- end
515
- when Phlex::SGML::SafeObject
516
- v.to_s.gsub('"', "&quot;")
517
- else
518
- raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
519
- end
520
-
521
- lower_name = name.downcase
522
-
523
- unless Phlex::SGML::SafeObject === v
524
- normalized_name = lower_name.delete("^a-z-")
525
-
526
- if value != true && REF_ATTRIBUTES.include?(normalized_name)
527
- case value
528
- when String
529
- decoded_value = decode_html_character_references(value)
530
-
531
- if decoded_value.downcase.delete("^a-z:").start_with?("javascript:")
532
- # We just ignore these because they were likely not specified by the developer.
533
- next
534
- end
535
- else
536
- raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
537
- end
538
- end
539
-
540
- if normalized_name.bytesize > 2 && normalized_name.start_with?("on") && !normalized_name.include?("-")
541
- raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
542
- end
543
-
544
- if UNSAFE_ATTRIBUTES.include?(normalized_name)
545
- raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
546
- end
547
- end
548
-
549
- if name.match?(UNSAFE_ATTRIBUTE_NAME_CHARS)
550
- raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
551
- end
552
-
553
- if lower_name.to_sym == :id && k != :id
554
- raise Phlex::ArgumentError.new(":id attribute should only be passed as a lowercase symbol.")
555
- end
556
-
557
- case value
558
- when true
559
- buffer << " " << name
560
- when String
561
- buffer << " " << name << '="' << value << '"'
562
- end
563
- end
564
-
565
- buffer
566
- end
567
-
568
- # Provides the nested-attributes case for serializing out attributes.
569
- # This allows us to skip many of the checks the `__attributes__` method must perform.
570
- private def __nested_attributes__(attributes, base_name, buffer = +"")
571
- attributes.each do |k, v|
572
- next unless v
573
-
574
- if (root_key = (:_ == k))
575
- name = ""
576
- original_base_name = base_name
577
- base_name = base_name.delete_suffix("-")
578
- else
579
- name = case k
580
- when String then k
581
- when Symbol then k.name.tr("_", "-")
582
- else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols")
583
- end
584
-
585
- if name.match?(UNSAFE_ATTRIBUTE_NAME_CHARS)
586
- raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
587
- end
588
- end
589
-
590
- case v
591
- when true
592
- buffer << " " << base_name << name
593
- when String
594
- buffer << " " << base_name << name << '="' << v.gsub('"', "&quot;") << '"'
595
- when Symbol
596
- buffer << " " << base_name << name << '="' << v.name.tr("_", "-").gsub('"', "&quot;") << '"'
597
- when Integer, Float
598
- buffer << " " << base_name << name << '="' << v.to_s << '"'
599
- when Hash
600
- __nested_attributes__(v, "#{base_name}#{name}-", buffer)
601
- when Array
602
- buffer << " " << base_name << name << '="' << __nested_tokens__(v) << '"'
603
- when Set
604
- buffer << " " << base_name << name << '="' << __nested_tokens__(v.to_a) << '"'
605
- when Phlex::SGML::SafeObject
606
- buffer << " " << base_name << name << '="' << v.to_s.gsub('"', "&quot;") << '"'
607
- else
608
- raise Phlex::ArgumentError.new("Invalid attribute value #{v.inspect}.")
609
- end
610
-
611
- if root_key
612
- base_name = original_base_name
613
- end
614
-
615
- buffer
616
- end
617
- end
618
-
619
- private def __nested_tokens__(tokens, sep = " ")
620
- buffer = +""
621
-
622
- i, length = 0, tokens.length
623
-
624
- while i < length
625
- token = tokens[i]
626
-
627
- case token
628
- when String
629
- if i > 0
630
- buffer << sep << token
631
- else
632
- buffer << token
633
- end
634
- when Symbol
635
- if i > 0
636
- buffer << sep << token.name.tr("_", "-")
637
- else
638
- buffer << token.name.tr("_", "-")
639
- end
640
- when Integer, Float, Phlex::SGML::SafeObject
641
- if i > 0
642
- buffer << sep << token.to_s
643
- else
644
- buffer << token.to_s
645
- end
646
- when Array
647
- if token.length > 0
648
- if i > 0
649
- buffer << sep << __nested_tokens__(token, sep)
650
- else
651
- buffer << __nested_tokens__(token, sep)
652
- end
653
- end
654
- when nil
655
- # Do nothing
656
- else
657
- raise Phlex::ArgumentError.new("Invalid token type: #{token.class}.")
658
- end
659
-
660
- i += 1
661
- end
662
-
663
- buffer.gsub('"', "&quot;")
664
- end
665
-
666
- private def decode_html_character_references(value)
667
- value
668
- .gsub(/&#x([0-9a-f]+);?/i) {
669
- begin
670
- [$1.to_i(16)].pack("U*")
671
- rescue
672
- ""
673
- end
674
- }
675
- .gsub(/&#(\d+);?/) {
676
- begin
677
- [$1.to_i].pack("U*")
678
- rescue
679
- ""
680
- end
681
- }
682
- .gsub(/&([a-z][a-z0-9]+);?/i) {
683
- NAMED_CHARACTER_REFERENCES[$1.downcase] || ""
684
- }
685
- end
686
-
687
- # Result is **unsafe**, so it should be escaped!
688
- private def __styles__(styles)
689
- case styles
690
- when Array, Set
691
- styles.filter_map do |s|
692
- case s
693
- when String
694
- if s == "" || s.end_with?(";")
695
- s
696
- else
697
- "#{s};"
698
- end
699
- when Phlex::SGML::SafeObject
700
- value = s.to_s
701
- value.end_with?(";") ? value : "#{value};"
702
- when Hash
703
- next __styles__(s)
704
- when nil
705
- next nil
706
- else
707
- raise Phlex::ArgumentError.new("Invalid style: #{s.inspect}.")
708
- end
709
- end.join(" ")
710
- when Hash
711
- buffer = +""
712
- i = 0
713
- styles.each do |k, v|
714
- prop = case k
715
- when String
716
- k
717
- when Symbol
718
- k.name.tr("_", "-")
719
- else
720
- raise Phlex::ArgumentError.new("Style keys should be Strings or Symbols.")
721
- end
722
-
723
- value = case v
724
- when String
725
- v
726
- when Symbol
727
- v.name.tr("_", "-")
728
- when Integer, Float, Phlex::SGML::SafeObject
729
- v.to_s
730
- when nil
731
- nil
732
- else
733
- raise Phlex::ArgumentError.new("Invalid style value: #{v.inspect}")
734
- end
735
-
736
- if value
737
- if i == 0
738
- buffer << prop << ": " << value << ";"
739
- else
740
- buffer << " " << prop << ": " << value << ";"
741
- end
742
- end
743
-
744
- i += 1
745
- end
746
-
747
- buffer
748
- 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))
749
466
  end
750
467
 
751
468
  private_class_method def self.method_added(method_name)
@@ -755,8 +472,13 @@ class Phlex::SGML
755
472
  if location[0] in "/" | "."
756
473
  Phlex.__expand_attribute_cache__(location)
757
474
  end
758
- else
759
- super
760
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
761
483
  end
762
484
  end
data/lib/phlex/svg.rb CHANGED
@@ -41,14 +41,14 @@ class Phlex::SVG < Phlex::SGML
41
41
  raise Phlex::ArgumentError.new("Expected the tag name to be a Symbol.")
42
42
  end
43
43
 
44
- if (tag = StandardElements.__registered_elements__[name]) || ((tag = name.name.tr("_", "-")).include?("-") && tag.match?(/\A[a-z0-9-]+\z/))
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.2"
4
+ VERSION = "2.4.0.beta1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phlex
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.2
4
+ version: 2.4.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Drapper
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: refract
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
27
41
  description: Build HTML, SVG and CSV views with Ruby classes.
28
42
  email:
29
43
  - joel@drapper.me
@@ -34,6 +48,11 @@ files:
34
48
  - LICENSE.txt
35
49
  - README.md
36
50
  - lib/phlex.rb
51
+ - lib/phlex/compiler.rb
52
+ - lib/phlex/compiler/class_compiler.rb
53
+ - lib/phlex/compiler/compilation.rb
54
+ - lib/phlex/compiler/file_compiler.rb
55
+ - lib/phlex/compiler/method_compiler.rb
37
56
  - lib/phlex/csv.rb
38
57
  - lib/phlex/error.rb
39
58
  - lib/phlex/errors/argument_error.rb
@@ -48,6 +67,7 @@ files:
48
67
  - lib/phlex/html/void_elements.rb
49
68
  - lib/phlex/kit.rb
50
69
  - lib/phlex/sgml.rb
70
+ - lib/phlex/sgml/attributes.rb
51
71
  - lib/phlex/sgml/elements.rb
52
72
  - lib/phlex/sgml/safe_object.rb
53
73
  - lib/phlex/sgml/safe_value.rb
@@ -79,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
99
  - !ruby/object:Gem::Version
80
100
  version: '0'
81
101
  requirements: []
82
- rubygems_version: 4.0.3
102
+ rubygems_version: 3.6.7
83
103
  specification_version: 4
84
104
  summary: Object-oriented views in Ruby.
85
105
  test_files: []