loading
Generated 2024-11-26T21:18:24+00:00

All Files ( 94.34% covered at 67.16 hits/line )

18 files in total.
778 relevant lines, 734 lines covered and 44 lines missed. ( 94.34% )
1945 total branches, 580 branches covered and 1365 branches missed. ( 29.82% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/phlex.rb 100.00 % 39 28 28 0 25.96 100.00 % 2 2 0
lib/phlex/context.rb 100.00 % 60 36 36 0 182.25 100.00 % 4 4 0
lib/phlex/csv.rb 98.08 % 120 52 51 1 7.21 92.86 % 14 13 1
lib/phlex/error.rb 100.00 % 5 1 1 0 3.00 100.00 % 0 0 0
lib/phlex/errors/argument_error.rb 100.00 % 5 2 2 0 3.00 100.00 % 0 0 0
lib/phlex/errors/double_render_error.rb 100.00 % 5 2 2 0 1.00 100.00 % 0 0 0
lib/phlex/fifo.rb 100.00 % 48 26 26 0 130.85 85.71 % 7 6 1
lib/phlex/helpers.rb 100.00 % 49 23 23 0 6.57 100.00 % 15 15 0
lib/phlex/html.rb 100.00 % 41 18 18 0 2.39 100.00 % 4 4 0
lib/phlex/html/standard_elements.rb 100.00 % 1038 104 104 0 1.00 100.00 % 0 0 0
lib/phlex/html/void_elements.rb 100.00 % 110 14 14 0 1.00 100.00 % 0 0 0
lib/phlex/kit.rb 77.50 % 77 40 31 9 1.50 50.00 % 14 7 7
lib/phlex/sgml.rb 90.07 % 599 282 254 28 93.58 83.94 % 193 162 31
lib/phlex/sgml/elements.rb 91.67 % 146 72 66 6 198.89 21.69 % 1692 367 1325
lib/phlex/sgml/safe_object.rb 100.00 % 7 1 1 0 1.00 100.00 % 0 0 0
lib/phlex/sgml/safe_value.rb 100.00 % 11 5 5 0 4.40 100.00 % 0 0 0
lib/phlex/svg.rb 100.00 % 15 6 6 0 1.00 100.00 % 0 0 0
lib/phlex/svg/standard_elements.rb 100.00 % 484 66 66 0 1.00 100.00 % 0 0 0

SGML ( 90.56% covered at 113.15 hits/line )

4 files in total.
360 relevant lines, 326 lines covered and 34 lines missed. ( 90.56% )
1885 total branches, 529 branches covered and 1356 branches missed. ( 28.06% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/phlex/sgml.rb 90.07 % 599 282 254 28 93.58 83.94 % 193 162 31
lib/phlex/sgml/elements.rb 91.67 % 146 72 66 6 198.89 21.69 % 1692 367 1325
lib/phlex/sgml/safe_object.rb 100.00 % 7 1 1 0 1.00 100.00 % 0 0 0
lib/phlex/sgml/safe_value.rb 100.00 % 11 5 5 0 4.40 100.00 % 0 0 0

HTML ( 100.0% covered at 1.18 hits/line )

3 files in total.
136 relevant lines, 136 lines covered and 0 lines missed. ( 100.0% )
4 total branches, 4 branches covered and 0 branches missed. ( 100.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/phlex/html.rb 100.00 % 41 18 18 0 2.39 100.00 % 4 4 0
lib/phlex/html/standard_elements.rb 100.00 % 1038 104 104 0 1.00 100.00 % 0 0 0
lib/phlex/html/void_elements.rb 100.00 % 110 14 14 0 1.00 100.00 % 0 0 0

SVG ( 100.0% covered at 1.0 hits/line )

2 files in total.
72 relevant lines, 72 lines covered and 0 lines missed. ( 100.0% )
0 total branches, 0 branches covered and 0 branches missed. ( 100.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/phlex/svg.rb 100.00 % 15 6 6 0 1.00 100.00 % 0 0 0
lib/phlex/svg/standard_elements.rb 100.00 % 484 66 66 0 1.00 100.00 % 0 0 0

CSV ( 98.08% covered at 7.21 hits/line )

1 files in total.
52 relevant lines, 51 lines covered and 1 lines missed. ( 98.08% )
14 total branches, 13 branches covered and 1 branches missed. ( 92.86% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/phlex/csv.rb 98.08 % 120 52 51 1 7.21 92.86 % 14 13 1

Ungrouped ( 94.3% covered at 69.06 hits/line )

8 files in total.
158 relevant lines, 149 lines covered and 9 lines missed. ( 94.3% )
42 total branches, 34 branches covered and 8 branches missed. ( 80.95% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/phlex.rb 100.00 % 39 28 28 0 25.96 100.00 % 2 2 0
lib/phlex/context.rb 100.00 % 60 36 36 0 182.25 100.00 % 4 4 0
lib/phlex/error.rb 100.00 % 5 1 1 0 3.00 100.00 % 0 0 0
lib/phlex/errors/argument_error.rb 100.00 % 5 2 2 0 3.00 100.00 % 0 0 0
lib/phlex/errors/double_render_error.rb 100.00 % 5 2 2 0 1.00 100.00 % 0 0 0
lib/phlex/fifo.rb 100.00 % 48 26 26 0 130.85 85.71 % 7 6 1
lib/phlex/helpers.rb 100.00 % 49 23 23 0 6.57 100.00 % 15 15 0
lib/phlex/kit.rb 77.50 % 77 40 31 9 1.50 50.00 % 14 7 7

lib/phlex.rb

100.0% lines covered

100.0% branches covered

28 relevant lines. 28 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "erb"
  3. 1 require "set"
  4. 1 module Phlex
  5. 1 autoload :ArgumentError, "phlex/errors/argument_error"
  6. 1 autoload :Vanish, "phlex/vanish"
  7. 1 autoload :CSV, "phlex/csv"
  8. 1 autoload :Callable, "phlex/callable"
  9. 1 autoload :Context, "phlex/context"
  10. 1 autoload :DoubleRenderError, "phlex/errors/double_render_error"
  11. 1 autoload :Elements, "phlex/elements"
  12. 1 autoload :Error, "phlex/error"
  13. 1 autoload :FIFO, "phlex/fifo"
  14. 1 autoload :HTML, "phlex/html"
  15. 1 autoload :Helpers, "phlex/helpers"
  16. 1 autoload :Kit, "phlex/kit"
  17. 1 autoload :NameError, "phlex/errors/name_error"
  18. 1 autoload :SGML, "phlex/sgml"
  19. 1 autoload :SVG, "phlex/svg"
  20. 1 Escape = ERB::Escape
  21. 1 ATTRIBUTE_CACHE = FIFO.new
  22. 1 Null = Object.new.freeze
  23. 1 CACHED_FILES = Set.new
  24. 1 def self.__expand_attribute_cache__(file_path)
  25. 656 else: 633 then: 23 unless CACHED_FILES.include?(file_path)
  26. 23 CACHED_FILES << file_path
  27. 23 Phlex::ATTRIBUTE_CACHE.expand(File.size(file_path))
  28. end
  29. end
  30. end
  31. 1 def 💪
  32. 1 Phlex
  33. end

lib/phlex/context.rb

100.0% lines covered

100.0% branches covered

36 relevant lines. 36 lines covered and 0 lines missed.
4 total branches, 4 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. # @api private
  3. 1 class Phlex::Context
  4. 1 def initialize(user_context: {}, view_context: nil)
  5. 804 @buffer = +""
  6. 804 @capturing = false
  7. 804 @user_context = user_context
  8. 804 @fragments = nil
  9. 804 @in_target_fragment = false
  10. 804 @halt_signal = nil
  11. 804 @view_context = view_context
  12. end
  13. 1 attr_accessor :buffer, :capturing, :user_context, :in_target_fragment
  14. 1 attr_reader :fragments, :view_context
  15. 1 def target_fragments(fragments)
  16. 15 @fragments = fragments.to_h { |it| [it, true] }
  17. end
  18. 1 def around_render
  19. 816 then: 809 else: 7 return yield if !@fragments || @halt_signal
  20. 7 catch do |signal|
  21. 7 @halt_signal = signal
  22. 7 yield
  23. end
  24. end
  25. 1 def begin_target(id)
  26. 7 @in_target_fragment = id
  27. end
  28. 1 def end_target
  29. 7 @fragments.delete(@in_target_fragment)
  30. 7 @in_target_fragment = false
  31. 7 then: 6 else: 1 throw @halt_signal if @fragments.length == 0
  32. end
  33. 1 def capturing_into(new_buffer)
  34. 4 original_buffer = @buffer
  35. 4 original_capturing = @capturing
  36. 4 original_fragments = @fragments
  37. begin
  38. 4 @buffer = new_buffer
  39. 4 @capturing = true
  40. 4 @fragments = nil
  41. 4 yield
  42. ensure
  43. 4 @buffer = original_buffer
  44. 4 @capturing = original_capturing
  45. 4 @fragments = original_fragments
  46. end
  47. 4 new_buffer
  48. end
  49. end

lib/phlex/csv.rb

98.08% lines covered

92.86% branches covered

52 relevant lines. 51 lines covered and 1 lines missed.
14 total branches, 13 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 class Phlex::CSV
  3. 1 FORMULA_PREFIXES = Set["=", "+", "-", "@", "\t", "\r"].freeze
  4. 1 SPACE_CHARACTERS = Set[" ", "\t", "\r"].freeze
  5. 1 def initialize(collection)
  6. 6 @collection = collection
  7. 6 @_headers = []
  8. 6 @_current_row = []
  9. 6 @_current_column_index = 0
  10. 6 @_first = true
  11. end
  12. 1 attr_reader :collection
  13. 1 def call(buffer = +"", context: nil)
  14. 5 else: 4 then: 1 unless escape_csv_injection? == true || escape_csv_injection? == false
  15. 1 raise <<~MESSAGE
  16. You need to define escape_csv_injection? in #{self.class.name}, returning either `true` or `false`.
  17. CSV injection is a security vulnerability where malicious spreadsheet formulae are used to execute code or exfiltrate data when a CSV is opened in a spreadsheet program such as Microsoft Excel or Google Sheets.
  18. For more information, see https://owasp.org/www-community/attacks/CSV_Injection
  19. If you're sure this CSV will never be opened in a spreadsheet program, you can disable CSV injection escapes:
  20. def escape_csv_injection? = false
  21. This is useful when using CSVs for byte-for-byte data exchange between secure systems.
  22. Alternatively, you can enable CSV injection escapes at the cost of data integrity:
  23. def escape_csv_injection? = true
  24. Note: Enabling the CSV injection escapes will prefix any values that start with `=`, `+`, `-`, `@`, `\\t`, or `\\r` with a single quote `'` to prevent them from being interpreted as formulae by spreadsheet programs.
  25. Unfortunately, there is no one-size-fits-all solution to CSV injection. You need to decide based on your specific use case.
  26. MESSAGE
  27. end
  28. 4 each_item do |record|
  29. 8 yielder(record) do |*args, **kwargs|
  30. 8 view_template(*args, **kwargs)
  31. 8 then: 3 else: 5 if @_first && render_headers?
  32. 3 buffer << @_headers.join(",") << "\n"
  33. end
  34. 8 buffer << @_current_row.join(",") << "\n"
  35. 8 @_current_column_index = 0
  36. 8 @_current_row.clear
  37. end
  38. 8 @_first = false
  39. end
  40. 4 buffer
  41. end
  42. 1 def filename
  43. nil
  44. end
  45. 1 def content_type
  46. 1 "text/csv"
  47. end
  48. 1 private
  49. 1 def column(header = nil, value)
  50. 16 then: 8 if @_first
  51. 8 else: 8 @_headers << __escape__(header)
  52. 8 then: 0 else: 8 elsif header != @_headers[@_current_column_index]
  53. raise "Inconsistent header."
  54. end
  55. 16 @_current_row << __escape__(value)
  56. 16 @_current_column_index += 1
  57. end
  58. 1 def each_item(&)
  59. 4 collection.each(&)
  60. end
  61. 1 def yielder(record)
  62. 8 yield(record)
  63. end
  64. # Override and set to `false` to disable rendering headers.
  65. 1 def render_headers?
  66. 3 true
  67. end
  68. # Override and set to `true` to strip leading and trailing whitespace from values.
  69. 1 def trim_whitespace?
  70. 34 false
  71. end
  72. # Override and set to `false` to disable CSV injection escapes or `true` to enable.
  73. 1 def escape_csv_injection?
  74. nil
  75. end
  76. 1 def __escape__(value)
  77. 24 then: 6 else: 18 value = trim_whitespace? ? value.to_s.strip : value.to_s
  78. 24 first_char = value[0]
  79. 24 last_char = value[-1]
  80. 24 if escape_csv_injection? && FORMULA_PREFIXES.include?(first_char)
  81. # Prefix a single quote to prevent Excel, Google Docs, etc. from interpreting the value as a formula.
  82. then: 2 # See https://owasp.org/www-community/attacks/CSV_Injection
  83. 2 else: 22 %("'#{value.gsub('"', '""')}")
  84. 22 then: 1 elsif (!trim_whitespace? && (SPACE_CHARACTERS.include?(first_char) || SPACE_CHARACTERS.include?(last_char))) || value.include?('"') || value.include?(",") || value.include?("\n")
  85. 1 %("#{value.gsub('"', '""')}")
  86. else: 21 else
  87. 21 value
  88. end
  89. end
  90. end

lib/phlex/error.rb

100.0% lines covered

100.0% branches covered

1 relevant lines. 1 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. # @api private
  3. 3 module Phlex::Error
  4. end

lib/phlex/errors/argument_error.rb

100.0% lines covered

100.0% branches covered

2 relevant lines. 2 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 3 class Phlex::ArgumentError < ArgumentError
  3. 3 include Phlex::Error
  4. end

lib/phlex/errors/double_render_error.rb

100.0% lines covered

100.0% branches covered

2 relevant lines. 2 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 class Phlex::DoubleRenderError < RuntimeError
  3. 1 include Phlex::Error
  4. end

lib/phlex/fifo.rb

100.0% lines covered

85.71% branches covered

26 relevant lines. 26 lines covered and 0 lines missed.
7 total branches, 6 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. # @api private
  3. 1 class Phlex::FIFO
  4. 1 def initialize(max_bytesize: 2_000, max_value_bytesize: 2_000)
  5. 4 @store = {}
  6. 4 @max_bytesize = max_bytesize
  7. 4 @max_value_bytesize = max_value_bytesize
  8. 4 @bytesize = 0
  9. 4 @mutex = Mutex.new
  10. end
  11. 1 attr_reader :bytesize, :max_bytesize
  12. 1 def expand(bytes)
  13. 23 @mutex.synchronize do
  14. 23 @max_bytesize += bytes
  15. end
  16. end
  17. 1 def [](key)
  18. 782 k, v = @store[key.hash]
  19. 782 then: 631 else: 151 v if k == key
  20. end
  21. 1 def []=(key, value)
  22. 225 then: 1 else: 224 return if value.bytesize > @max_value_bytesize
  23. 224 digest = key.hash
  24. 224 @mutex.synchronize do
  25. # Check the key definitely doesn't exist now we have the lock
  26. 224 then: 0 else: 224 return if @store[digest]
  27. 224 @store[digest] = [key, value]
  28. 224 @bytesize += value.bytesize
  29. 224 body: 97 while @bytesize > @max_bytesize
  30. 97 k, v = @store.shift
  31. 97 @bytesize -= v[1].bytesize
  32. end
  33. end
  34. end
  35. 1 def size
  36. 2 @store.size
  37. end
  38. end

lib/phlex/helpers.rb

100.0% lines covered

100.0% branches covered

23 relevant lines. 23 lines covered and 0 lines missed.
15 total branches, 15 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. # @api private
  3. 1 module Phlex::Helpers
  4. 1 private
  5. 1 def mix(*args)
  6. 16 args.each_with_object({}) do |object, result|
  7. 32 result.merge!(object) do |_key, old, new|
  8. case [old, new]
  9. 15 in: 2 in [Array, Array] | [Set, Set]
  10. 2 old + new
  11. in: 1 in [Array, Set]
  12. 1 old + new.to_a
  13. in: 1 in [Array, String]
  14. 1 old + [new]
  15. in: 1 in [Hash, Hash]
  16. 1 mix(old, new)
  17. in: 1 in [Set, Array]
  18. 1 old.to_a + new
  19. in: 1 in [Set, String]
  20. 1 old.to_a + [new]
  21. in: 1 in [String, Array]
  22. 1 [old] + new
  23. in: 1 in [String, Set]
  24. 1 [old] + new.to_a
  25. in: 2 in [String, String]
  26. 2 "#{old} #{new}"
  27. in: 2 in [_, nil]
  28. 2 old
  29. else: 2 else
  30. 2 new
  31. end
  32. end
  33. 32 result.transform_keys! do |key|
  34. 33 then: 1 else: 32 key.end_with?("!") ? key.name.chop.to_sym : key
  35. end
  36. end
  37. end
  38. 1 def grab(**bindings)
  39. 2 then: 1 if bindings.size > 1
  40. 1 bindings.values
  41. else: 1 else
  42. 1 bindings.values.first
  43. end
  44. end
  45. end

lib/phlex/html.rb

100.0% lines covered

100.0% branches covered

18 relevant lines. 18 lines covered and 0 lines missed.
4 total branches, 4 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 class Phlex::HTML < Phlex::SGML
  3. 1 autoload :StandardElements, "phlex/html/standard_elements"
  4. 1 autoload :VoidElements, "phlex/html/void_elements"
  5. 1 extend Phlex::SGML::Elements
  6. 1 include VoidElements, StandardElements
  7. # Output an HTML doctype.
  8. 1 def doctype
  9. 5 context = @_context
  10. 5 then: 4 else: 1 return if context.fragments && !context.in_target_fragment
  11. 1 context.buffer << "<!doctype html>"
  12. nil
  13. end
  14. # Outputs an `<svg>` tag
  15. # @return [nil]
  16. # @see https://developer.mozilla.org/docs/Web/SVG/Element/svg
  17. 1 def svg(...)
  18. 6 then: 5 if block_given?
  19. 5 super do
  20. 5 render Phlex::SVG.new do |svg|
  21. 5 yield(svg)
  22. end
  23. end
  24. else: 1 else
  25. 1 super
  26. end
  27. end
  28. 1 def filename
  29. nil
  30. end
  31. 1 def content_type
  32. 1 "text/html"
  33. end
  34. end

lib/phlex/html/standard_elements.rb

100.0% lines covered

100.0% branches covered

104 relevant lines. 104 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. # Standard HTML elements accept content and always have a closing tag.
  3. 1 module Phlex::HTML::StandardElements
  4. 1 extend Phlex::SGML::Elements
  5. # Outputs an `<a>` tag.
  6. # The `<a>` element creates a hyperlink to web pages, files, email addresses, locations in the same page, or anything else a URL can address.
  7. # See https://developer.mozilla.org/docs/Web/HTML/Element/a
  8. 1 register_element def a(
  9. class: nil,
  10. href: nil,
  11. id: nil,
  12. rel: nil,
  13. target: nil,
  14. title: nil,
  15. **attributes,
  16. &content
  17. ) = nil
  18. # Outputs an `<abbr>` tag.
  19. # The `<abbr>` element represents an abbreviation or acronym.
  20. # See https://developer.mozilla.org/docs/Web/HTML/Element/abbr
  21. 1 register_element def abbr(
  22. class: nil,
  23. id: nil,
  24. title: nil,
  25. **attributes,
  26. &content
  27. ) = nil
  28. # Outputs an `<address>` tag.
  29. # The `<address>` element indicates contact information for a person or organization.
  30. # See https://developer.mozilla.org/docs/Web/HTML/Element/address
  31. 1 register_element def address(
  32. class: nil,
  33. id: nil,
  34. **attributes,
  35. &content
  36. ) = nil
  37. # Outputs an `<article>` tag.
  38. # The `<article>` element represents a self-contained composition in a document, page, application, or site.
  39. # See https://developer.mozilla.org/docs/Web/HTML/Element/article
  40. 1 register_element def article(
  41. class: nil,
  42. id: nil,
  43. **attributes,
  44. &content
  45. ) = nil
  46. # Outputs an `<aside>` tag.
  47. # The `<aside>` element represents a section of a page that consists of content that is tangentially related to the content around the aside element.
  48. # See https://developer.mozilla.org/docs/Web/HTML/Element/aside
  49. 1 register_element def aside(
  50. class: nil,
  51. id: nil,
  52. **attributes,
  53. &content
  54. ) = nil
  55. # Outputs an `<audio>` tag.
  56. # See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio
  57. 1 register_element def audio(
  58. autoplay: nil,
  59. class: nil,
  60. controls: nil,
  61. id: nil,
  62. loop: nil,
  63. src: nil,
  64. **attributes,
  65. &content
  66. ) = nil
  67. # Outputs a `<b>` tag.
  68. # See https://developer.mozilla.org/docs/Web/HTML/Element/b
  69. 1 register_element def b(
  70. class: nil,
  71. id: nil,
  72. **attributes,
  73. &content
  74. ) = nil
  75. # Outputs a `<bdi>` tag.
  76. # See https://developer.mozilla.org/docs/Web/HTML/Element/bdi
  77. 1 register_element def bdi(
  78. class: nil,
  79. id: nil,
  80. **attributes,
  81. &content
  82. ) = nil
  83. # Outputs a `<bdo>` tag.
  84. # See https://developer.mozilla.org/docs/Web/HTML/Element/bdo
  85. 1 register_element def bdo(
  86. class: nil,
  87. dir: nil,
  88. id: nil,
  89. **attributes,
  90. &content
  91. ) = nil
  92. # Outputs a `<blockquote>` tag.
  93. # See https://developer.mozilla.org/docs/Web/HTML/Element/blockquote
  94. 1 register_element def blockquote(
  95. cite: nil,
  96. class: nil,
  97. id: nil,
  98. **attributes,
  99. &content
  100. ) = nil
  101. # Outputs a `<body>` tag.
  102. # See https://developer.mozilla.org/docs/Web/HTML/Element/body
  103. 1 register_element def body(
  104. class: nil,
  105. id: nil,
  106. **attributes,
  107. &content
  108. ) = nil
  109. # Outputs a `<button>` tag.
  110. # The `<button>` element is an interactive element activated by a user with a mouse, keyboard, finger, voice command, or other assistive technology to perform an action, such as submitting a form or opening a dialog.
  111. # See https://developer.mozilla.org/docs/Web/HTML/Element/button
  112. 1 register_element def button(
  113. autofocus: nil,
  114. class: nil,
  115. disabled: nil,
  116. form: nil,
  117. formaction: nil,
  118. formmethod: nil,
  119. formtarget: nil,
  120. formvalidate: nil,
  121. id: nil,
  122. name: nil,
  123. popovertarget: nil,
  124. popovertargetaction: nil,
  125. type: nil,
  126. value: nil,
  127. **attributes,
  128. &content
  129. ) = nil
  130. # Outputs a `<canvas>` tag.
  131. # See https://developer.mozilla.org/docs/Web/HTML/Element/canvas
  132. 1 register_element def canvas(
  133. class: nil,
  134. height: nil,
  135. id: nil,
  136. width: nil,
  137. **attributes,
  138. &content
  139. ) = nil
  140. # Outputs a `<caption>` tag.
  141. # See https://developer.mozilla.org/docs/Web/HTML/Element/caption
  142. 1 register_element def caption(
  143. class: nil,
  144. id: nil,
  145. **attributes,
  146. &content
  147. ) = nil
  148. # Outputs a `<cite>` tag.
  149. # See https://developer.mozilla.org/docs/Web/HTML/Element/cite
  150. 1 register_element def cite(
  151. class: nil,
  152. id: nil,
  153. **attributes,
  154. &content
  155. ) = nil
  156. # Outputs a `<code>` tag.
  157. # See https://developer.mozilla.org/docs/Web/HTML/Element/code
  158. 1 register_element def code(
  159. class: nil,
  160. id: nil,
  161. **attributes,
  162. &content
  163. ) = nil
  164. # Outputs a `<colgroup>` tag.
  165. # See https://developer.mozilla.org/docs/Web/HTML/Element/colgroup
  166. 1 register_element def colgroup(
  167. class: nil,
  168. id: nil,
  169. span: nil,
  170. **attributes,
  171. &content
  172. ) = nil
  173. # Outputs a `<data>` tag.
  174. # See https://developer.mozilla.org/docs/Web/HTML/Element/data
  175. 1 register_element def data(
  176. class: nil,
  177. id: nil,
  178. value: nil,
  179. **attributes,
  180. &content
  181. ) = nil
  182. # Outputs a `<datalist>` tag.
  183. # See https://developer.mozilla.org/docs/Web/HTML/Element/datalist
  184. 1 register_element def datalist(
  185. class: nil,
  186. id: nil,
  187. **attributes,
  188. &content
  189. ) = nil
  190. # Outputs a `<dd>` tag.
  191. # See https://developer.mozilla.org/docs/Web/HTML/Element/dd
  192. 1 register_element def dd(
  193. class: nil,
  194. id: nil,
  195. **attributes,
  196. &content
  197. ) = nil
  198. # Outputs a `<del>` tag.
  199. # See https://developer.mozilla.org/docs/Web/HTML/Element/del
  200. 1 register_element def del(
  201. cite: nil,
  202. class: nil,
  203. datetime: nil,
  204. id: nil,
  205. **attributes,
  206. &content
  207. ) = nil
  208. # Outputs a `<details>` tag.
  209. # See https://developer.mozilla.org/docs/Web/HTML/Element/details
  210. 1 register_element def details(
  211. class: nil,
  212. id: nil,
  213. open: nil,
  214. **attributes,
  215. &content
  216. ) = nil
  217. # Outputs a `<dfn>` tag.
  218. # See https://developer.mozilla.org/docs/Web/HTML/Element/dfn
  219. 1 register_element def dfn(
  220. class: nil,
  221. id: nil,
  222. title: nil,
  223. **attributes,
  224. &content
  225. ) = nil
  226. # Outputs a `<dialog>` tag.
  227. # See https://developer.mozilla.org/docs/Web/HTML/Element/dialog
  228. 1 register_element def dialog(
  229. class: nil,
  230. id: nil,
  231. open: nil,
  232. **attributes,
  233. &content
  234. ) = nil
  235. # Outputs a `<div>` tag.
  236. # See https://developer.mozilla.org/docs/Web/HTML/Element/div
  237. 1 register_element def div(
  238. class: nil,
  239. id: nil,
  240. **attributes,
  241. &content
  242. ) = nil
  243. # Outputs a `<dl>` tag.
  244. # See https://developer.mozilla.org/docs/Web/HTML/Element/dl
  245. 1 register_element def dl(
  246. class: nil,
  247. id: nil,
  248. **attributes,
  249. &content
  250. ) = nil
  251. # Outputs a `<dt>` tag.
  252. # See https://developer.mozilla.org/docs/Web/HTML/Element/dt
  253. 1 register_element def dt(
  254. class: nil,
  255. id: nil,
  256. **attributes,
  257. &content
  258. ) = nil
  259. # Outputs an `<em>` tag.
  260. # See https://developer.mozilla.org/docs/Web/HTML/Element/em
  261. 1 register_element def em(
  262. class: nil,
  263. id: nil,
  264. **attributes,
  265. &content
  266. ) = nil
  267. # Outputs a `<fieldset>` tag.
  268. # See https://developer.mozilla.org/docs/Web/HTML/Element/fieldset
  269. 1 register_element def fieldset(
  270. class: nil,
  271. disabled: nil,
  272. form: nil,
  273. id: nil,
  274. name: nil,
  275. **attributes,
  276. &content
  277. ) = nil
  278. # Outputs a `<figcaption>` tag.
  279. # See https://developer.mozilla.org/docs/Web/HTML/Element/figcaption
  280. 1 register_element def figcaption(
  281. class: nil,
  282. id: nil,
  283. **attributes,
  284. &content
  285. ) = nil
  286. # Outputs a `<figure>` tag.
  287. # See https://developer.mozilla.org/docs/Web/HTML/Element/figure
  288. 1 register_element def figure(
  289. class: nil,
  290. id: nil,
  291. **attributes,
  292. &content
  293. ) = nil
  294. # Outputs a `<footer>` tag.
  295. # See https://developer.mozilla.org/docs/Web/HTML/Element/footer
  296. 1 register_element def footer(
  297. class: nil,
  298. id: nil,
  299. **attributes,
  300. &content
  301. ) = nil
  302. # Outputs a `<form>` tag.
  303. # See https://developer.mozilla.org/docs/Web/HTML/Element/form
  304. 1 register_element def form(
  305. action: nil,
  306. class: nil,
  307. enctype: nil,
  308. id: nil,
  309. method: nil,
  310. **attributes,
  311. &content
  312. ) = nil
  313. # Outputs an `<h1>` tag.
  314. # See https://developer.mozilla.org/docs/Web/HTML/Element/h1
  315. 1 register_element def h1(
  316. class: nil,
  317. id: nil,
  318. **attributes,
  319. &content
  320. ) = nil
  321. # Outputs an `<h2>` tag.
  322. # See https://developer.mozilla.org/docs/Web/HTML/Element/h2
  323. 1 register_element def h2(
  324. class: nil,
  325. id: nil,
  326. **attributes,
  327. &content
  328. ) = nil
  329. # Outputs an `<h3>` tag.
  330. # See https://developer.mozilla.org/docs/Web/HTML/Element/h3
  331. 1 register_element def h3(
  332. class: nil,
  333. id: nil,
  334. **attributes,
  335. &content
  336. ) = nil
  337. # Outputs an `<h4>` tag.
  338. # See https://developer.mozilla.org/docs/Web/HTML/Element/h4
  339. 1 register_element def h4(
  340. class: nil,
  341. id: nil,
  342. **attributes,
  343. &content
  344. ) = nil
  345. # Outputs an `<h5>` tag.
  346. # See https://developer.mozilla.org/docs/Web/HTML/Element/h5
  347. 1 register_element def h5(
  348. class: nil,
  349. id: nil,
  350. **attributes,
  351. &content
  352. ) = nil
  353. # Outputs an `<h6>` tag.
  354. # See https://developer.mozilla.org/docs/Web/HTML/Element/h6
  355. 1 register_element def h6(
  356. class: nil,
  357. id: nil,
  358. **attributes,
  359. &content
  360. ) = nil
  361. # Outputs a `<head>` tag.
  362. # See https://developer.mozilla.org/docs/Web/HTML/Element/head
  363. 1 register_element def head(
  364. class: nil,
  365. id: nil,
  366. **attributes,
  367. &content
  368. ) = nil
  369. # Outputs a `<header>` tag.
  370. # See https://developer.mozilla.org/docs/Web/HTML/Element/header
  371. 1 register_element def header(
  372. class: nil,
  373. id: nil,
  374. **attributes,
  375. &content
  376. ) = nil
  377. # Outputs an `<hgroup>` tag.
  378. # See https://developer.mozilla.org/docs/Web/HTML/Element/hgroup
  379. 1 register_element def hgroup(
  380. class: nil,
  381. id: nil,
  382. **attributes,
  383. &content
  384. ) = nil
  385. # Outputs an `<html>` tag.
  386. # See https://developer.mozilla.org/docs/Web/HTML/Element/html
  387. 1 register_element def html(
  388. class: nil,
  389. id: nil,
  390. lang: nil,
  391. **attributes,
  392. &content
  393. ) = nil
  394. # Outputs an `<i>` tag.
  395. # See https://developer.mozilla.org/docs/Web/HTML/Element/i
  396. 1 register_element def i(
  397. class: nil,
  398. id: nil,
  399. **attributes,
  400. &content
  401. ) = nil
  402. # Outputs an `<iframe>` tag.
  403. # See https://developer.mozilla.org/docs/Web/HTML/Element/iframe
  404. 1 register_element def iframe(
  405. class: nil,
  406. height: nil,
  407. id: nil,
  408. name: nil,
  409. src: nil,
  410. srcdoc: nil,
  411. width: nil,
  412. **attributes,
  413. &content
  414. ) = nil
  415. # Outputs an `<ins>` tag.
  416. # See https://developer.mozilla.org/docs/Web/HTML/Element/ins
  417. 1 register_element def ins(
  418. cite: nil,
  419. class: nil,
  420. datetime: nil,
  421. id: nil,
  422. **attributes,
  423. &content
  424. ) = nil
  425. # Outputs a `<kbd>` tag.
  426. # See https://developer.mozilla.org/docs/Web/HTML/Element/kbd
  427. 1 register_element def kbd(
  428. class: nil,
  429. id: nil,
  430. **attributes,
  431. &content
  432. ) = nil
  433. # Outputs a `<label>` tag.
  434. # See https://developer.mozilla.org/docs/Web/HTML/Element/label
  435. 1 register_element def label(
  436. class: nil,
  437. for: nil,
  438. form: nil,
  439. id: nil,
  440. **attributes,
  441. &content
  442. ) = nil
  443. # Outputs a `<legend>` tag.
  444. # See https://developer.mozilla.org/docs/Web/HTML/Element/legend
  445. 1 register_element def legend(
  446. class: nil,
  447. id: nil,
  448. **attributes,
  449. &content
  450. ) = nil
  451. # Outputs a `<li>` tag.
  452. # See https://developer.mozilla.org/docs/Web/HTML/Element/li
  453. 1 register_element def li(
  454. class: nil,
  455. id: nil,
  456. value: nil,
  457. **attributes,
  458. &content
  459. ) = nil
  460. # Outputs a `<main>` tag.
  461. # See https://developer.mozilla.org/docs/Web/HTML/Element/main
  462. 1 register_element def main(
  463. class: nil,
  464. id: nil,
  465. **attributes,
  466. &content
  467. ) = nil
  468. # Outputs a `<map>` tag.
  469. # See https://developer.mozilla.org/docs/Web/HTML/Element/map
  470. 1 register_element def map(
  471. class: nil,
  472. id: nil,
  473. name: nil,
  474. **attributes,
  475. &content
  476. ) = nil
  477. # Outputs a `<mark>` tag.
  478. # See https://developer.mozilla.org/docs/Web/HTML/Element/mark
  479. 1 register_element def mark(
  480. class: nil,
  481. id: nil,
  482. **attributes,
  483. &content
  484. ) = nil
  485. # Outputs a `<menu>` tag.
  486. # See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu
  487. 1 register_element def menu(
  488. class: nil,
  489. id: nil,
  490. type: nil,
  491. **attributes,
  492. &content
  493. ) = nil
  494. # Outputs a `<meter>` tag.
  495. # See https://developer.mozilla.org/docs/Web/HTML/Element/meter
  496. 1 register_element def meter(
  497. class: nil,
  498. high: nil,
  499. id: nil,
  500. low: nil,
  501. max: nil,
  502. min: nil,
  503. optimum: nil,
  504. value: nil,
  505. **attributes,
  506. &content
  507. ) = nil
  508. # Outputs a `<nav>` tag.
  509. # See https://developer.mozilla.org/docs/Web/HTML/Element/nav
  510. 1 register_element def nav(
  511. class: nil,
  512. id: nil,
  513. **attributes,
  514. &content
  515. ) = nil
  516. # Outputs a `<noscript>` tag.
  517. # See https://developer.mozilla.org/docs/Web/HTML/Element/noscript
  518. 1 register_element def noscript(
  519. class: nil,
  520. id: nil,
  521. **attributes,
  522. &content
  523. ) = nil
  524. # Outputs an `<object>` tag.
  525. # See https://developer.mozilla.org/docs/Web/HTML/Element/object
  526. 1 register_element def object(
  527. class: nil,
  528. data: nil,
  529. height: nil,
  530. id: nil,
  531. type: nil,
  532. width: nil,
  533. **attributes,
  534. &content
  535. ) = nil
  536. # Outputs an `<ol>` tag.
  537. # See https://developer.mozilla.org/docs/Web/HTML/Element/ol
  538. 1 register_element def ol(
  539. class: nil,
  540. id: nil,
  541. reversed: nil,
  542. start: nil,
  543. type: nil,
  544. **attributes,
  545. &content
  546. ) = nil
  547. # Outputs an `<optgroup>` tag.
  548. # See https://developer.mozilla.org/docs/Web/HTML/Element/optgroup
  549. 1 register_element def optgroup(
  550. class: nil,
  551. disabled: nil,
  552. id: nil,
  553. label: nil,
  554. **attributes,
  555. &content
  556. ) = nil
  557. # Outputs an `<option>` tag.
  558. # See https://developer.mozilla.org/docs/Web/HTML/Element/option
  559. 1 register_element def option(
  560. class: nil,
  561. disabled: nil,
  562. id: nil,
  563. selected: nil,
  564. value: nil,
  565. **attributes,
  566. &content
  567. ) = nil
  568. # Outputs an `<output>` tag.
  569. # See https://developer.mozilla.org/docs/Web/HTML/Element/output
  570. 1 register_element def output(
  571. class: nil,
  572. for: nil,
  573. form: nil,
  574. id: nil,
  575. name: nil,
  576. **attributes,
  577. &content
  578. ) = nil
  579. # Outputs a `<p>` tag.
  580. # See https://developer.mozilla.org/docs/Web/HTML/Element/p
  581. 1 register_element def p(
  582. class: nil,
  583. id: nil,
  584. **attributes,
  585. &content
  586. ) = nil
  587. # Outputs a `<picture>` tag.
  588. # See https://developer.mozilla.org/docs/Web/HTML/Element/picture
  589. 1 register_element def picture(
  590. class: nil,
  591. id: nil,
  592. **attributes,
  593. &content
  594. ) = nil
  595. # Outputs a `<portal>` tag. (Experimental)
  596. # See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/portal
  597. 1 register_element def portal(
  598. class: nil,
  599. id: nil,
  600. src: nil,
  601. **attributes,
  602. &content
  603. ) = nil
  604. # Outputs a `<pre>` tag.
  605. # See https://developer.mozilla.org/docs/Web/HTML/Element/pre
  606. 1 register_element def pre(
  607. class: nil,
  608. id: nil,
  609. **attributes,
  610. &content
  611. ) = nil
  612. # Outputs a `<progress>` tag.
  613. # See https://developer.mozilla.org/docs/Web/HTML/Element/progress
  614. 1 register_element def progress(
  615. class: nil,
  616. id: nil,
  617. max: nil,
  618. value: nil,
  619. **attributes,
  620. &content
  621. ) = nil
  622. # Outputs a `<q>` tag.
  623. # See https://developer.mozilla.org/docs/Web/HTML/Element/q
  624. 1 register_element def q(
  625. cite: nil,
  626. class: nil,
  627. id: nil,
  628. **attributes,
  629. &content
  630. ) = nil
  631. # Outputs an `<rp>` tag.
  632. # See https://developer.mozilla.org/docs/Web/HTML/Element/rp
  633. 1 register_element def rp(
  634. class: nil,
  635. id: nil,
  636. **attributes,
  637. &content
  638. ) = nil
  639. # Outputs an `<rt>` tag.
  640. # See https://developer.mozilla.org/docs/Web/HTML/Element/rt
  641. 1 register_element def rt(
  642. class: nil,
  643. id: nil,
  644. **attributes,
  645. &content
  646. ) = nil
  647. # Outputs a `<ruby>` tag. (The best tag ever!)
  648. # See https://developer.mozilla.org/docs/Web/HTML/Element/ruby
  649. 1 register_element def ruby(
  650. class: nil,
  651. id: nil,
  652. **attributes,
  653. &content
  654. ) = nil
  655. # Outputs an `<s>` tag.
  656. # See https://developer.mozilla.org/docs/Web/HTML/Element/s
  657. 1 register_element def s(
  658. class: nil,
  659. id: nil,
  660. **attributes,
  661. &content
  662. ) = nil
  663. # Outputs a `<samp>` tag.
  664. # See https://developer.mozilla.org/docs/Web/HTML/Element/samp
  665. 1 register_element def samp(
  666. class: nil,
  667. id: nil,
  668. **attributes,
  669. &content
  670. ) = nil
  671. # Outputs a `<script>` tag.
  672. # See https://developer.mozilla.org/docs/Web/HTML/Element/script
  673. 1 register_element def script(
  674. async: nil,
  675. class: nil,
  676. defer: nil,
  677. id: nil,
  678. src: nil,
  679. type: nil,
  680. **attributes,
  681. &content
  682. ) = nil
  683. # Outputs a `<search>` tag.
  684. # See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/search
  685. 1 register_element def search(
  686. class: nil,
  687. id: nil,
  688. **attributes,
  689. &content
  690. ) = nil
  691. # Outputs a `<section>` tag.
  692. # See https://developer.mozilla.org/docs/Web/HTML/Element/section
  693. 1 register_element def section(
  694. class: nil,
  695. id: nil,
  696. **attributes,
  697. &content
  698. ) = nil
  699. # Outputs a `<select>` tag.
  700. # See https://developer.mozilla.org/docs/Web/HTML/Element/select
  701. 1 register_element def select(
  702. class: nil,
  703. id: nil,
  704. multiple: nil,
  705. name: nil,
  706. size: nil,
  707. **attributes,
  708. &content
  709. ) = nil
  710. # Outputs a `<slot>` tag.
  711. # See https://developer.mozilla.org/docs/Web/HTML/Element/slot
  712. 1 register_element def slot(
  713. class: nil,
  714. id: nil,
  715. name: nil,
  716. **attributes,
  717. &content
  718. ) = nil
  719. # Outputs a `<small>` tag.
  720. # See https://developer.mozilla.org/docs/Web/HTML/Element/small
  721. 1 register_element def small(
  722. class: nil,
  723. id: nil,
  724. **attributes,
  725. &content
  726. ) = nil
  727. # Outputs a `<span>` tag.
  728. # See https://developer.mozilla.org/docs/Web/HTML/Element/span
  729. 1 register_element def span(
  730. class: nil,
  731. id: nil,
  732. **attributes,
  733. &content
  734. ) = nil
  735. # Outputs a `<strong>` tag.
  736. # See https://developer.mozilla.org/docs/Web/HTML/Element/strong
  737. 1 register_element def strong(
  738. class: nil,
  739. id: nil,
  740. **attributes,
  741. &content
  742. ) = nil
  743. # Outputs a `<style>` tag.
  744. # See https://developer.mozilla.org/docs/Web/HTML/Element/style
  745. 1 register_element def style(
  746. class: nil,
  747. id: nil,
  748. media: nil,
  749. type: nil,
  750. **attributes,
  751. &content
  752. ) = nil
  753. # Outputs a `<sub>` tag.
  754. # See https://developer.mozilla.org/docs/Web/HTML/Element/sub
  755. 1 register_element def sub(
  756. class: nil,
  757. id: nil,
  758. **attributes,
  759. &content
  760. ) = nil
  761. # Outputs a `<summary>` tag.
  762. # See https://developer.mozilla.org/docs/Web/HTML/Element/summary
  763. 1 register_element def summary(
  764. class: nil,
  765. id: nil,
  766. **attributes,
  767. &content
  768. ) = nil
  769. # Outputs a `<sup>` tag.
  770. # See https://developer.mozilla.org/docs/Web/HTML/Element/sup
  771. 1 register_element def sup(
  772. class: nil,
  773. id: nil,
  774. **attributes,
  775. &content
  776. ) = nil
  777. # Outputs an `<svg>` tag.
  778. # See https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
  779. 1 register_element def svg(
  780. class: nil,
  781. height: nil,
  782. id: nil,
  783. viewBox: nil,
  784. width: nil,
  785. **attributes,
  786. &content
  787. ) = nil
  788. # Outputs a `<table>` tag.
  789. # See https://developer.mozilla.org/docs/Web/HTML/Element/table
  790. 1 register_element def table(
  791. class: nil,
  792. id: nil,
  793. **attributes,
  794. &content
  795. ) = nil
  796. # Outputs a `<tbody>` tag.
  797. # See https://developer.mozilla.org/docs/Web/HTML/Element/tbody
  798. 1 register_element def tbody(
  799. class: nil,
  800. id: nil,
  801. **attributes,
  802. &content
  803. ) = nil
  804. # Outputs a `<td>` tag.
  805. # See https://developer.mozilla.org/docs/Web/HTML/Element/td
  806. 1 register_element def td(
  807. class: nil,
  808. colspan: nil,
  809. headers: nil,
  810. id: nil,
  811. rowspan: nil,
  812. **attributes,
  813. &content
  814. ) = nil
  815. # Outputs a `<template>` tag.
  816. # See https://developer.mozilla.org/docs/Web/HTML/Element/template
  817. 1 register_element def template(
  818. class: nil,
  819. id: nil,
  820. **attributes,
  821. &content
  822. ) = nil
  823. # Outputs a `<textarea>` tag.
  824. # See https://developer.mozilla.org/docs/Web/HTML/Element/textarea
  825. 1 register_element def textarea(
  826. class: nil,
  827. cols: nil,
  828. disabled: nil,
  829. id: nil,
  830. name: nil,
  831. readonly: nil,
  832. rows: nil,
  833. **attributes,
  834. &content
  835. ) = nil
  836. # Outputs a `<tfoot>` tag.
  837. # See https://developer.mozilla.org/docs/Web/HTML/Element/tfoot
  838. 1 register_element def tfoot(
  839. class: nil,
  840. id: nil,
  841. **attributes,
  842. &content
  843. ) = nil
  844. # Outputs a `<th>` tag.
  845. # See https://developer.mozilla.org/docs/Web/HTML/Element/th
  846. 1 register_element def th(
  847. class: nil,
  848. colspan: nil,
  849. headers: nil,
  850. id: nil,
  851. rowspan: nil,
  852. scope: nil,
  853. **attributes,
  854. &content
  855. ) = nil
  856. # Outputs a `<thead>` tag.
  857. # See https://developer.mozilla.org/docs/Web/HTML/Element/thead
  858. 1 register_element def thead(
  859. class: nil,
  860. id: nil,
  861. **attributes,
  862. &content
  863. ) = nil
  864. # Outputs a `<time>` tag.
  865. # See https://developer.mozilla.org/docs/Web/HTML/Element/time
  866. 1 register_element def time(
  867. class: nil,
  868. datetime: nil,
  869. id: nil,
  870. **attributes,
  871. &content
  872. ) = nil
  873. # Outputs a `<title>` tag.
  874. # See https://developer.mozilla.org/docs/Web/HTML/Element/title
  875. 1 register_element def title(
  876. class: nil,
  877. id: nil,
  878. **attributes,
  879. &content
  880. ) = nil
  881. # Outputs a `<tr>` tag.
  882. # See https://developer.mozilla.org/docs/Web/HTML/Element/tr
  883. 1 register_element def tr(
  884. class: nil,
  885. id: nil,
  886. **attributes,
  887. &content
  888. ) = nil
  889. # Outputs a `<u>` tag.
  890. # See https://developer.mozilla.org/docs/Web/HTML/Element/u
  891. 1 register_element def u(
  892. class: nil,
  893. id: nil,
  894. **attributes,
  895. &content
  896. ) = nil
  897. # Outputs a `<ul>` tag.
  898. # See https://developer.mozilla.org/docs/Web/HTML/Element/ul
  899. 1 register_element def ul(
  900. class: nil,
  901. id: nil,
  902. **attributes,
  903. &content
  904. ) = nil
  905. # Outputs a `<var>` tag.
  906. # See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/var
  907. 1 register_element def var(
  908. class: nil,
  909. id: nil,
  910. **attributes,
  911. &content
  912. ) = nil
  913. # Outputs a `<video>` tag.
  914. # See https://developer.mozilla.org/docs/Web/HTML/Element/video
  915. 1 register_element def video(
  916. autoplay: nil,
  917. class: nil,
  918. controls: nil,
  919. height: nil,
  920. id: nil,
  921. loop: nil,
  922. src: nil,
  923. width: nil,
  924. **attributes,
  925. &content
  926. ) = nil
  927. # Outputs a `<wbr>` tag.
  928. # See https://developer.mozilla.org/docs/Web/HTML/Element/wbr
  929. 1 register_element def wbr(
  930. class: nil,
  931. id: nil,
  932. **attributes,
  933. &content
  934. ) = nil
  935. end

lib/phlex/html/void_elements.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. # Void HTML elements don't accept content and never have a closing tag.
  3. 1 module Phlex::HTML::VoidElements
  4. 1 extend Phlex::SGML::Elements
  5. # Outputs an `<area>` tag.
  6. # See https://developer.mozilla.org/docs/Web/HTML/Element/area
  7. 1 __register_void_element__ def area(
  8. class: nil,
  9. id: nil,
  10. **attributes
  11. ) = nil
  12. # Outputs a `<base>` tag.
  13. # See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
  14. 1 __register_void_element__ def base(
  15. class: nil,
  16. href: nil,
  17. id: nil,
  18. target: nil,
  19. **attributes
  20. ) = nil
  21. # Outputs a `<br>` tag.
  22. # See https://developer.mozilla.org/docs/Web/HTML/Element/br
  23. 1 __register_void_element__ def br(
  24. class: nil,
  25. id: nil,
  26. **attributes
  27. ) = nil
  28. # Outputs a `<col>` tag.
  29. # See https://developer.mozilla.org/docs/Web/HTML/Element/col
  30. 1 __register_void_element__ def col(
  31. class: nil,
  32. id: nil,
  33. **attributes
  34. ) = nil
  35. # Outputs an `<embed>` tag.
  36. # See https://developer.mozilla.org/docs/Web/HTML/Element/embed
  37. 1 __register_void_element__ def embed(
  38. class: nil,
  39. id: nil,
  40. **attributes
  41. ) = nil
  42. # Outputs an `<hr>` tag.
  43. # See https://developer.mozilla.org/docs/Web/HTML/Element/hr
  44. 1 __register_void_element__ def hr(
  45. class: nil,
  46. id: nil,
  47. **attributes
  48. ) = nil
  49. # Outputs an `<img>` tag.
  50. # See https://developer.mozilla.org/docs/Web/HTML/Element/img
  51. 1 __register_void_element__ def img(
  52. alt: nil,
  53. class: nil,
  54. id: nil,
  55. src: nil,
  56. **attributes
  57. ) = nil
  58. # Outputs an `<input>` tag.
  59. # See https://developer.mozilla.org/docs/Web/HTML/Element/input
  60. 1 __register_void_element__ def input(
  61. class: nil,
  62. id: nil,
  63. name: nil,
  64. type: nil,
  65. **attributes
  66. ) = nil
  67. # Outputs a `<link>` tag.
  68. # See https://developer.mozilla.org/docs/Web/HTML/Element/link
  69. 1 __register_void_element__ def link(
  70. class: nil,
  71. id: nil,
  72. **attributes
  73. ) = nil
  74. # Outputs a `<meta>` tag.
  75. # See https://developer.mozilla.org/docs/Web/HTML/Element/meta
  76. 1 __register_void_element__ def meta(
  77. charset: nil,
  78. class: nil,
  79. id: nil,
  80. name: nil,
  81. **attributes
  82. ) = nil
  83. # Outputs a `<source>` tag.
  84. # See https://developer.mozilla.org/docs/Web/HTML/Element/source
  85. 1 __register_void_element__ def source(
  86. class: nil,
  87. id: nil,
  88. **attributes
  89. ) = nil
  90. # Outputs a `<track>` tag.
  91. # See https://developer.mozilla.org/docs/Web/HTML/Element/track
  92. 1 __register_void_element__ def track(
  93. class: nil,
  94. id: nil,
  95. **attributes
  96. ) = nil
  97. end

lib/phlex/kit.rb

77.5% lines covered

50.0% branches covered

40 relevant lines. 31 lines covered and 9 lines missed.
14 total branches, 7 branches covered and 7 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Phlex::Kit
  3. 1 module LazyLoader
  4. 1 def method_missing(name, ...)
  5. 2 mod = self.class
  6. 2 then: 2 if name[0] == name[0].upcase && mod.constants.include?(name) && mod.const_get(name) && methods.include?(name)
  7. 2 public_send(name, ...)
  8. else: 0 else
  9. super
  10. end
  11. end
  12. 1 def respond_to_missing?(name, include_private = false)
  13. mod = self.class
  14. then: 0 if name[0] == name[0].upcase && mod.constants.include?(name) && mod.const_get(name) && methods.include?(name)
  15. true
  16. else: 0 else
  17. super
  18. end
  19. end
  20. end
  21. 1 def self.extended(mod)
  22. 1 mod.include(LazyLoader)
  23. end
  24. 1 def method_missing(name, ...)
  25. 1 then: 1 if name[0] == name[0].upcase && constants.include?(name) && const_get(name) && methods.include?(name)
  26. 1 public_send(name, ...)
  27. else: 0 else
  28. super
  29. end
  30. end
  31. 1 def respond_to_missing?(name, include_private = false)
  32. then: 0 if name[0] == name[0].upcase && constants.include?(name) && const_get(name) && methods.include?(name)
  33. true
  34. else: 0 else
  35. super
  36. end
  37. end
  38. 1 def const_added(name)
  39. 5 then: 2 else: 3 return if autoload?(name)
  40. 3 me = self
  41. 3 constant = const_get(name)
  42. 3 then: 3 else: 0 if Class === constant && constant < Phlex::SGML
  43. 3 constant.include(self)
  44. 3 constant = nil
  45. 3 define_method(name) do |*args, **kwargs, &block|
  46. 3 constant = me.const_get(name)
  47. 3 render(constant.new(*args, **kwargs), &block)
  48. end
  49. 3 define_singleton_method(name) do |*args, **kwargs, &block|
  50. 2 component, fiber_id = Thread.current[:__phlex_component__]
  51. 2 then: 1 if (component && fiber_id == Fiber.current.object_id)
  52. 1 component.instance_exec do
  53. 1 constant = me.const_get(name)
  54. 1 render(constant.new(*args, **kwargs), &block)
  55. end
  56. else: 1 else
  57. 1 raise "You can't call `#{name}' outside of a Phlex rendering context."
  58. end
  59. end
  60. end
  61. 3 super
  62. end
  63. end

lib/phlex/sgml.rb

90.07% lines covered

83.94% branches covered

282 relevant lines. 254 lines covered and 28 lines missed.
193 total branches, 162 branches covered and 31 branches missed.
    
  1. # frozen_string_literal: true
  2. # **Standard Generalized Markup Language** for behaviour common to {HTML} and {SVG}.
  3. 1 class Phlex::SGML
  4. 1 UNSAFE_ATTRIBUTES = Set.new(%w[srcdoc sandbox http-equiv]).freeze
  5. 1 REF_ATTRIBUTES = Set.new(%w[href src action formaction lowsrc dynsrc background ping]).freeze
  6. 1 autoload :Elements, "phlex/sgml/elements"
  7. 1 autoload :SafeObject, "phlex/sgml/safe_object"
  8. 1 autoload :SafeValue, "phlex/sgml/safe_value"
  9. 1 include Phlex::Helpers
  10. 1 class << self
  11. # Render the view to a String. Arguments are delegated to {.new}.
  12. 1 def call(...)
  13. 644 new(...).call
  14. end
  15. # Create a new instance of the component.
  16. # @note The block will not be delegated {#initialize}. Instead, it will be sent to {#template} when rendering.
  17. 1 def new(*a, **k, &block)
  18. 819 then: 4 if block
  19. 4 object = super(*a, **k, &nil)
  20. 8 object.instance_exec { @_content_block = block }
  21. 4 object
  22. else: 815 else
  23. 815 super
  24. end
  25. end
  26. 1 def __element_method__?(method_name)
  27. then: 0 if instance_methods.include?(method_name)
  28. owner = instance_method(method_name).owner
  29. then: 0 if Phlex::SGML::Elements === owner && owner.__registered_elements__[method_name]
  30. true
  31. else: 0 else
  32. false
  33. end
  34. else: 0 else
  35. false
  36. end
  37. end
  38. end
  39. 1 def view_template
  40. 153 then: 151 else: 2 if block_given?
  41. 151 yield
  42. end
  43. end
  44. 1 def to_proc
  45. 2 proc { |c| c.render(self) }
  46. end
  47. 1 def call(buffer = +"", context: {}, view_context: nil, parent: nil, fragments: nil, &block)
  48. 818 @_buffer = buffer
  49. 818 then: 14 else: 804 @_context = phlex_context = parent&.__context__ || Phlex::Context.new(user_context: context, view_context:)
  50. 818 @_parent = parent
  51. 818 then: 1 else: 817 raise Phlex::DoubleRenderError.new("You can't render a #{self.class.name} more than once.") if @_rendered
  52. 817 @_rendered = true
  53. 817 then: 7 else: 810 if fragments
  54. 7 phlex_context.target_fragments(fragments)
  55. end
  56. 817 block ||= @_content_block
  57. 817 else: 816 then: 1 return "" unless render?
  58. 816 Thread.current[:__phlex_component__] = [self, Fiber.current.object_id]
  59. 816 phlex_context.around_render do
  60. 816 before_template(&block)
  61. 816 around_template do
  62. 816 then: 160 if block
  63. 160 view_template do |*args|
  64. 160 then: 7 if args.length > 0
  65. 7 __yield_content_with_args__(*args, &block)
  66. else: 153 else
  67. 153 __yield_content__(&block)
  68. end
  69. end
  70. else: 656 else
  71. 656 view_template
  72. end
  73. end
  74. 778 after_template(&block)
  75. end
  76. 784 else: 14 then: 770 unless parent
  77. 770 buffer << phlex_context.buffer
  78. end
  79. ensure
  80. 818 Thread.current[:__phlex_component__] = [parent, Fiber.current.object_id]
  81. end
  82. 1 protected def __context__ = @_context
  83. 1 def context
  84. @_context.user_context
  85. end
  86. # Output plain text.
  87. 1 def plain(content)
  88. 10 else: 9 then: 1 unless __text__(content)
  89. 1 raise Phlex::ArgumentError.new("You've passed an object to plain that is not handled by format_object. See https://rubydoc.info/gems/phlex/Phlex/SGML#format_object-instance_method for more information")
  90. end
  91. nil
  92. end
  93. # Output a single space character. If a block is given, a space will be output before and after the block.
  94. 1 def whitespace(&)
  95. 6 context = @_context
  96. 6 then: 4 else: 2 return if context.fragments && !context.in_target_fragment
  97. 2 buffer = context.buffer
  98. 2 buffer << " "
  99. 2 then: 1 else: 1 if block_given?
  100. 1 __yield_content__(&)
  101. 1 buffer << " "
  102. end
  103. nil
  104. end
  105. # Wrap the output in an HTML comment.
  106. #
  107. # [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Comments)
  108. 1 def comment(&)
  109. 10 context = @_context
  110. 10 then: 8 else: 2 return if context.fragments && !context.in_target_fragment
  111. 2 buffer = context.buffer
  112. 2 buffer << "<!-- "
  113. 2 __yield_content__(&)
  114. 2 buffer << " -->"
  115. nil
  116. end
  117. # Output the given safe object as-is. You may need to use `safe` to mark a string as a safe object.
  118. 1 def raw(content)
  119. 4 case content
  120. when: 1 when Phlex::SGML::SafeObject
  121. 1 context = @_context
  122. 1 then: 0 else: 1 return if context.fragments && !context.in_target_fragment
  123. 1 when: 2 context.buffer << content.to_s
  124. when nil, "" # do nothing
  125. else: 1 else
  126. 1 raise Phlex::ArgumentError.new("You passed an unsafe object to `raw`.")
  127. end
  128. nil
  129. end
  130. # Capture the output of the block and returns it as a string.
  131. 1 def capture(*args, &block)
  132. 4 else: 4 then: 0 return "" unless block
  133. 4 then: 1 if args.length > 0
  134. 2 @_context.capturing_into(+"") { __yield_content_with_args__(*args, &block) }
  135. else: 3 else
  136. 6 @_context.capturing_into(+"") { __yield_content__(&block) }
  137. end
  138. end
  139. # Mark the given string as safe for HTML output.
  140. 1 def safe(value)
  141. 5 case value
  142. when: 4 when String
  143. 4 Phlex::SGML::SafeValue.new(value)
  144. else: 1 else
  145. 1 raise Phlex::ArgumentError.new("Expected a String.")
  146. end
  147. end
  148. 1 alias_method :🦺, :safe
  149. 1 def flush
  150. 5 then: 0 else: 5 return if @_context.capturing
  151. 5 buffer = @_context.buffer
  152. 5 @_buffer << buffer.dup
  153. 5 buffer.clear
  154. end
  155. 1 def render(renderable = nil, &)
  156. 15 case renderable
  157. when: 13 when Phlex::SGML
  158. 13 renderable.call(@_buffer, parent: self, &)
  159. when: 1 when Class
  160. 1 then: 1 else: 0 if renderable < Phlex::SGML
  161. 1 renderable.new.call(@_buffer, parent: self, &)
  162. end
  163. when: 0 when Enumerable
  164. renderable.each { |r| render(r, &) }
  165. when: 0 when Proc, Method
  166. then: 0 if renderable.arity == 0
  167. __yield_content_with_no_args__(&renderable)
  168. else: 0 else
  169. __yield_content__(&renderable)
  170. end
  171. when: 0 when String
  172. plain(renderable)
  173. when: 1 when nil
  174. 1 then: 1 else: 0 __yield_content__(&) if block_given?
  175. else: 0 else
  176. raise Phlex::ArgumentError.new("You can't render a #{renderable.inspect}.")
  177. end
  178. nil
  179. end
  180. 1 private
  181. 1 def vanish(*args)
  182. else: 0 then: 0 return unless block_given?
  183. then: 0 if args.length > 0
  184. @_context.capturing_into(Phlex::Vanish) { yield(*args) }
  185. else: 0 else
  186. @_context.capturing_into(Phlex::Vanish) { yield(self) }
  187. end
  188. nil
  189. end
  190. 1 def render?
  191. 815 true
  192. end
  193. 1 def format_object(object)
  194. 5 else: 3 case object
  195. when: 2 when Float, Integer
  196. 2 object.to_s
  197. end
  198. end
  199. 1 def around_template
  200. 816 yield
  201. nil
  202. end
  203. 1 def before_template
  204. nil
  205. end
  206. 1 def after_template
  207. nil
  208. end
  209. 1 def __yield_content__
  210. 160 else: 160 then: 0 return unless block_given?
  211. 160 buffer = @_context.buffer
  212. 160 original_length = buffer.bytesize
  213. 160 content = yield(self)
  214. 128 then: 8 else: 120 __implicit_output__(content) if original_length == buffer.bytesize
  215. nil
  216. end
  217. 1 def __yield_content_with_no_args__
  218. else: 0 then: 0 return unless block_given?
  219. buffer = @_context.buffer
  220. original_length = buffer.bytesize
  221. content = yield
  222. then: 0 else: 0 __implicit_output__(content) if original_length == buffer.bytesize
  223. nil
  224. end
  225. 1 def __yield_content_with_args__(*a)
  226. 8 else: 8 then: 0 return unless block_given?
  227. 8 buffer = @_context.buffer
  228. 8 original_length = buffer.bytesize
  229. 8 content = yield(*a)
  230. 8 then: 4 else: 4 __implicit_output__(content) if original_length == buffer.bytesize
  231. nil
  232. end
  233. 1 def __implicit_output__(content)
  234. 12 context = @_context
  235. 12 then: 3 else: 9 return true if context.fragments && !context.in_target_fragment
  236. 9 case content
  237. when: 0 when Phlex::SGML::SafeObject
  238. context.buffer << content.to_s
  239. when: 7 when String
  240. 7 context.buffer << Phlex::Escape.html_escape(content)
  241. when: 0 when Symbol
  242. context.buffer << Phlex::Escape.html_escape(content.name)
  243. when: 2 when nil
  244. nil
  245. else: 0 else
  246. then: 0 if (formatted_object = format_object(content))
  247. context.buffer << Phlex::Escape.html_escape(formatted_object)
  248. else: 0 else
  249. return false
  250. end
  251. end
  252. 9 true
  253. end
  254. # same as __implicit_output__ but escapes even `safe` objects
  255. 1 def __text__(content)
  256. 10 context = @_context
  257. 10 then: 1 else: 9 return true if context.fragments && !context.in_target_fragment
  258. 9 case content
  259. when: 4 when String
  260. 4 context.buffer << Phlex::Escape.html_escape(content)
  261. when: 1 when Symbol
  262. 1 context.buffer << Phlex::Escape.html_escape(content.name)
  263. when: 1 when nil
  264. nil
  265. else: 3 else
  266. 3 then: 2 if (formatted_object = format_object(content))
  267. 2 context.buffer << Phlex::Escape.html_escape(formatted_object)
  268. else: 1 else
  269. 1 return false
  270. end
  271. end
  272. 8 true
  273. end
  274. 1 def __attributes__(attributes, buffer = +"")
  275. 151 attributes.each do |k, v|
  276. 167 else: 162 then: 5 next unless v
  277. 162 when: 14 name = case k
  278. 14 when: 147 when String then k
  279. 147 else: 1 when Symbol then k.name.tr("_", "-")
  280. 1 else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols.")
  281. end
  282. 161 value = case v
  283. when: 13 when true
  284. 13 true
  285. when: 41 when String
  286. 41 v.gsub('"', "&quot;")
  287. when: 8 when Symbol
  288. 8 v.name.tr("_", "-").gsub('"', "&quot;")
  289. when: 5 when Integer, Float
  290. 5 v.to_s
  291. when: 55 when Hash
  292. 55 case k
  293. when: 10 when :style
  294. 10 __styles__(v).gsub('"', "&quot;")
  295. else: 45 else
  296. 45 __nested_attributes__(v, "#{name}-", buffer)
  297. end
  298. when: 23 when Array
  299. 23 case k
  300. when: 8 when :style
  301. 8 __styles__(v).gsub('"', "&quot;")
  302. else: 15 else
  303. 15 __nested_tokens__(v)
  304. end
  305. when: 13 when Set
  306. 13 case k
  307. when: 2 when :style
  308. 2 __styles__(v).gsub('"', "&quot;")
  309. else: 11 else
  310. 11 __nested_tokens__(v.to_a)
  311. end
  312. when: 2 when Phlex::SGML::SafeObject
  313. 2 v.to_s.gsub('"', "&quot;")
  314. else: 1 else
  315. 1 raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
  316. end
  317. 143 lower_name = name.downcase
  318. 143 else: 2 then: 141 unless Phlex::SGML::SafeObject === v
  319. 141 normalized_name = lower_name.delete("^a-z-")
  320. 141 then: 11 else: 130 if value != true && REF_ATTRIBUTES.include?(normalized_name)
  321. 11 case value
  322. when: 10 when String
  323. 10 else: 4 if value.downcase.delete("^a-z:").start_with?("javascript:")
  324. then: 6 # We just ignore these because they were likely not specified by the developer.
  325. 6 next
  326. end
  327. else: 1 else
  328. 1 raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
  329. end
  330. end
  331. 134 then: 1 else: 133 if normalized_name.bytesize > 2 && normalized_name.start_with?("on") && !normalized_name.include?("-")
  332. 1 raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
  333. end
  334. 133 then: 0 else: 133 if UNSAFE_ATTRIBUTES.include?(normalized_name)
  335. raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
  336. end
  337. end
  338. 135 then: 5 else: 130 if name.match?(/[<>&"']/)
  339. 5 raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
  340. end
  341. 130 then: 3 else: 127 if lower_name.to_sym == :id && k != :id
  342. 3 raise Phlex::ArgumentError.new(":id attribute should only be passed as a lowercase symbol.")
  343. end
  344. 127 else: 32 case value
  345. when: 7 when true
  346. 7 buffer << " " << name
  347. when: 88 when String
  348. 88 buffer << " " << name << '="' << value << '"'
  349. end
  350. end
  351. 122 buffer
  352. end
  353. # Provides the nested-attributes case for serializing out attributes.
  354. # This allows us to skip many of the checks the `__attributes__` method must perform.
  355. 1 def __nested_attributes__(attributes, base_name, buffer = +"")
  356. 46 attributes.each do |k, v|
  357. 45 else: 43 then: 2 next unless v
  358. 43 when: 6 name = case k
  359. 6 when: 36 when String then k
  360. 36 else: 1 when Symbol then k.name.tr("_", "-")
  361. 1 else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols")
  362. end
  363. 42 then: 10 else: 32 if name.match?(/[<>&"']/)
  364. 10 raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
  365. end
  366. 32 case v
  367. when: 3 when true
  368. 3 buffer << " " << base_name << name
  369. when: 12 when String
  370. 12 buffer << " " << base_name << name << '="' << v.gsub('"', "&quot;") << '"'
  371. when: 6 when Symbol
  372. 6 buffer << " " << base_name << name << '="' << v.name.tr("_", "-").gsub('"', "&quot;") << '"'
  373. when: 6 when Integer, Float
  374. 6 buffer << " " << base_name << name << '="' << v.to_s << '"'
  375. when: 1 when Hash
  376. 1 __nested_attributes__(v, "#{base_name}#{name}-", buffer)
  377. when: 1 when Array
  378. 1 buffer << " " << base_name << name << '="' << __nested_tokens__(v) << '"'
  379. when: 1 when Set
  380. 1 buffer << " " << base_name << name << '="' << __nested_tokens__(v.to_a) << '"'
  381. when: 1 when Phlex::SGML::SafeObject
  382. 1 buffer << " " << base_name << name << '="' << v.to_s.gsub('"', "&quot;") << '"'
  383. else: 1 else
  384. 1 raise Phlex::ArgumentError.new("Invalid attribute value #{v.inspect}.")
  385. end
  386. 31 buffer
  387. end
  388. end
  389. 1 def __nested_tokens__(tokens)
  390. 30 buffer = +""
  391. 30 i, length = 0, tokens.length
  392. 30 body: 62 while i < length
  393. 62 token = tokens[i]
  394. 62 case token
  395. when: 19 when String
  396. 19 then: 9 if i > 0
  397. 9 buffer << " " << token
  398. else: 10 else
  399. 10 buffer << token
  400. end
  401. when: 16 when Symbol
  402. 16 then: 10 if i > 0
  403. 10 buffer << " " << token.name.tr("_", "-")
  404. else: 6 else
  405. 6 buffer << token.name.tr("_", "-")
  406. end
  407. when: 18 when Integer, Float, Phlex::SGML::SafeObject
  408. 18 then: 10 if i > 0
  409. 10 buffer << " " << token.to_s
  410. else: 8 else
  411. 8 buffer << token.to_s
  412. end
  413. when: 3 when Array
  414. 3 then: 2 else: 1 if token.length > 0
  415. 2 then: 1 if i > 0
  416. 1 buffer << " " << __nested_tokens__(token)
  417. else: 1 else
  418. 1 buffer << __nested_tokens__(token)
  419. end
  420. when: 4 end
  421. when nil
  422. # Do nothing
  423. else: 2 else
  424. 2 raise Phlex::ArgumentError.new("Invalid token type: #{token.class}.")
  425. end
  426. 60 i += 1
  427. end
  428. 28 buffer.gsub('"', "&quot;")
  429. end
  430. # Result is **unsafe**, so it should be escaped!
  431. 1 def __styles__(styles)
  432. 23 else: 1 case styles
  433. when: 10 when Array, Set
  434. 10 styles.filter_map do |s|
  435. 14 case s
  436. when: 5 when String
  437. 5 then: 1 if s == "" || s.end_with?(";")
  438. 1 s
  439. else: 4 else
  440. 4 "#{s};"
  441. end
  442. when: 2 when Phlex::SGML::SafeObject
  443. 2 value = s.to_s
  444. 2 then: 1 else: 1 value.end_with?(";") ? value : "#{value};"
  445. when: 2 when Hash
  446. 2 next __styles__(s)
  447. when: 4 when nil
  448. 4 next nil
  449. else: 1 else
  450. 1 raise Phlex::ArgumentError.new("Invalid style: #{s.inspect}.")
  451. end
  452. end.join(" ")
  453. when: 12 when Hash
  454. 12 buffer = +""
  455. 12 i = 0
  456. 12 styles.each do |k, v|
  457. 14 prop = case k
  458. when: 1 when String
  459. 1 k
  460. when: 12 when Symbol
  461. 12 k.name.tr("_", "-")
  462. else: 1 else
  463. 1 raise Phlex::ArgumentError.new("Style keys should be Strings or Symbols.")
  464. end
  465. 13 value = case v
  466. when: 5 when String
  467. 5 v
  468. when: 2 when Symbol
  469. 2 v.name.tr("_", "-")
  470. when: 4 when Integer, Float, Phlex::SGML::SafeObject
  471. 4 v.to_s
  472. when: 1 when nil
  473. 1 nil
  474. else: 1 else
  475. 1 raise Phlex::ArgumentError.new("Invalid style value: #{v.inspect}")
  476. end
  477. 12 then: 11 else: 1 if value
  478. 11 then: 9 if i == 0
  479. 9 buffer << prop << ": " << value << ";"
  480. else: 2 else
  481. 2 buffer << " " << prop << ": " << value << ";"
  482. end
  483. end
  484. 12 i += 1
  485. end
  486. 10 buffer
  487. end
  488. end
  489. 1 private_class_method def self.method_added(method_name)
  490. 672 then: 657 if method_name == :view_template
  491. 657 location = instance_method(method_name).source_location[0]
  492. 657 in: 656 else: 1 then: 656 else: 1 if location[0] in "/" | "."
  493. 656 Phlex.__expand_attribute_cache__(location)
  494. end
  495. else: 15 else
  496. 15 super
  497. end
  498. end
  499. end

lib/phlex/sgml/elements.rb

91.67% lines covered

21.69% branches covered

72 relevant lines. 66 lines covered and 6 lines missed.
1692 total branches, 367 branches covered and 1325 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Phlex::SGML::Elements
  3. 1 def __registered_elements__
  4. 181 @__registered_elements__ ||= {}
  5. end
  6. 1 def register_element(method_name, tag: method_name.name.tr("_", "-"))
  7. 166 class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
  8. # frozen_string_literal: true
  9. 1 def #{method_name}(**attributes)
  10. 898 context = @_context
  11. 898 buffer = context.buffer
  12. 898 fragment = context.fragments
  13. 898 target_found = false
  14. 898 block_given = block_given?
  15. 898 then: 0 else: 18 then: 0 else: 9 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 9 then: 0 else: 6 then: 0 else: 6 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 12 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 9 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 3 then: 0 else: 12 then: 0 else: 14 then: 0 else: 46 then: 0 else: 14 then: 0 else: 47 then: 0 else: 12 then: 0 else: 4 then: 0 else: 8 then: 0 else: 4 then: 0 else: 4 then: 0 else: 20 then: 10 else: 137 then: 13 else: 145 then: 0 else: 8 then: 0 else: 4 then: 0 else: 5 then: 0 else: 4 then: 0 else: 4 then: 0 else: 5 then: 0 else: 27 then: 0 else: 12 then: 0 else: 8 then: 0 else: 4 then: 0 else: 45 then: 0 else: 20 then: 0 else: 4 then: 0 else: 4 then: 0 else: 10 then: 0 else: 17 then: 5 else: 16 then: 0 else: 18 then: 0 else: 4 then: 0 else: 36 then: 0 else: 4 then: 0 else: 4 then: 0 else: 13 then: 0 else: 4 if fragment
  16. 28 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 23 then: 9 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 5 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 return if fragment.length == 0 # we found all our fragments already
  17. 28 id = attributes[:id]
  18. 28 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 10 else: 0 then: 13 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 2 else: 3 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 if !context.in_target_fragment
  19. 25 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 1 then: 4 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 if fragment[id]
  20. 5 context.begin_target(id)
  21. 5 target_found = true
  22. else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 9 else: 9 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 2 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else
  23. 20 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 9 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 2 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 yield(self) if block_given
  24. 15 return nil
  25. end
  26. end
  27. end
  28. 878 then: 24 then: 12 then: 12 then: 12 then: 3 then: 18 then: 3 then: 9 then: 6 then: 12 then: 12 then: 3 then: 9 then: 5 then: 9 then: 45 then: 14 then: 4 then: 48 then: 4 then: 12 then: 4 then: 12 then: 131 then: 51 then: 16 then: 32 then: 12 then: 4 then: 52 then: 20 then: 4 then: 12 then: 17 then: 4 then: 12 then: 56 then: 4 then: 16 then: 4 if attributes.length > 0 # with attributes
  29. 739 then: 24 then: 12 then: 12 then: 12 then: 3 then: 18 then: 3 then: 9 then: 6 then: 12 then: 12 then: 3 then: 9 then: 3 then: 9 then: 45 then: 12 then: 4 then: 48 then: 4 then: 12 then: 4 then: 12 then: 5 then: 51 then: 16 then: 32 then: 12 then: 4 then: 52 then: 20 then: 4 then: 12 then: 17 then: 4 then: 12 then: 56 then: 4 then: 16 then: 4 if block_given # with content block
  30. 609 buffer << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[attributes] ||= __attributes__(attributes)) << ">"
  31. 609 original_length = buffer.bytesize
  32. 609 content = yield(self)
  33. 609 then: 24 else: 0 then: 12 else: 0 then: 12 else: 0 then: 12 else: 0 then: 3 else: 0 then: 18 else: 0 then: 3 else: 0 then: 9 else: 0 then: 6 else: 0 then: 12 else: 0 then: 12 else: 0 then: 3 else: 0 then: 9 else: 0 then: 3 else: 0 then: 9 else: 0 then: 45 else: 0 then: 9 else: 3 then: 3 else: 1 then: 36 else: 12 then: 3 else: 1 then: 9 else: 3 then: 3 else: 1 then: 9 else: 3 then: 4 else: 1 then: 37 else: 14 then: 12 else: 4 then: 24 else: 8 then: 9 else: 3 then: 3 else: 1 then: 39 else: 13 then: 15 else: 5 then: 3 else: 1 then: 9 else: 3 then: 13 else: 4 then: 3 else: 1 then: 9 else: 3 then: 39 else: 17 then: 3 else: 1 then: 12 else: 4 then: 3 else: 1 if original_length == buffer.bytesize
  34. 501 case content
  35. when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when ::Phlex::SGML::SafeObject
  36. buffer << content.to_s
  37. when: 24 when: 12 when: 12 when: 12 when: 3 when: 18 when: 3 when: 9 when: 6 when: 12 when: 12 when: 3 when: 9 when: 3 when: 9 when: 45 when: 9 when: 3 when: 36 when: 3 when: 9 when: 3 when: 9 when: 4 when: 37 when: 12 when: 24 when: 9 when: 3 when: 39 when: 15 when: 3 when: 9 when: 12 when: 3 when: 9 when: 39 when: 3 when: 12 when: 3 when String
  38. 500 buffer << ::Phlex::Escape.html_escape(content)
  39. when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when Symbol
  40. buffer << ::Phlex::Escape.html_escape(content.name)
  41. when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when nil
  42. nil
  43. else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 1 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else
  44. 1 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 1 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 if (formatted_object = format_object(content))
  45. buffer << ::Phlex::Escape.html_escape(formatted_object)
  46. end
  47. end
  48. end
  49. 609 buffer << "</#{tag}>"
  50. else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 2 else: 0 else: 0 else: 2 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 126 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else # without content
  51. 130 buffer << "<#{tag}" << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= __attributes__(attributes)) << "></#{tag}>"
  52. end
  53. else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 1 else: 0 else: 3 else: 0 else: 0 else: 0 else: 0 else: 0 else: 7 else: 110 else: 1 else: 8 else: 0 else: 0 else: 1 else: 0 else: 0 else: 2 else: 0 else: 0 else: 3 else: 2 else: 0 else: 1 else: 0 else # without attributes
  54. 139 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 0 then: 1 then: 0 then: 3 then: 0 then: 0 then: 0 then: 0 then: 0 then: 2 then: 110 then: 1 then: 8 then: 0 then: 0 then: 1 then: 0 then: 0 then: 2 then: 0 then: 0 then: 3 then: 1 then: 0 then: 1 then: 0 if block_given # with content block
  55. 133 buffer << "<#{tag}>"
  56. 133 original_length = buffer.bytesize
  57. 133 content = yield(self)
  58. 134 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 1 then: 0 else: 0 then: 0 else: 3 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 2 else: 0 then: 110 else: 0 then: 0 else: 1 then: 7 else: 1 then: 0 else: 0 then: 0 else: 0 then: 1 else: 0 then: 0 else: 0 then: 0 else: 0 then: 1 else: 0 then: 0 else: 0 then: 0 else: 0 then: 3 else: 0 then: 0 else: 1 then: 0 else: 0 then: 1 else: 0 then: 0 else: 0 if original_length == buffer.bytesize
  59. 125 case content
  60. when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 1 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when ::Phlex::SGML::SafeObject
  61. 1 buffer << content.to_s
  62. when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 110 when: 0 when: 7 when: 0 when: 0 when: 1 when: 0 when: 0 when: 0 when: 0 when: 0 when: 3 when: 0 when: 0 when: 0 when: 0 when String
  63. 121 buffer << ::Phlex::Escape.html_escape(content)
  64. when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when Symbol
  65. buffer << ::Phlex::Escape.html_escape(content.name)
  66. when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 2 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when: 0 when nil
  67. nil
  68. else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 1 else: 0 else
  69. 1 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 0 then: 0 else: 1 then: 0 else: 0 if (formatted_object = format_object(content))
  70. buffer << ::Phlex::Escape.html_escape(formatted_object)
  71. end
  72. end
  73. end
  74. 132 buffer << "</#{tag}>"
  75. else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 5 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 0 else: 1 else: 0 else: 0 else: 0 else # without content
  76. 6 buffer << "<#{tag}></#{tag}>"
  77. end
  78. end
  79. 5 then: 1 else: 165 #{'flush' if tag == 'head'}
  80. 848 then: 0 else: 24 then: 0 else: 12 then: 0 else: 12 then: 0 else: 12 then: 0 else: 3 then: 0 else: 18 then: 0 else: 3 then: 0 else: 9 then: 0 else: 6 then: 0 else: 12 then: 0 else: 12 then: 0 else: 3 then: 0 else: 9 then: 0 else: 5 then: 0 else: 9 then: 0 else: 46 then: 0 else: 13 then: 0 else: 7 then: 0 else: 48 then: 0 else: 4 then: 0 else: 12 then: 0 else: 4 then: 0 else: 12 then: 1 else: 109 then: 4 else: 157 then: 0 else: 12 then: 0 else: 5 then: 0 else: 40 then: 0 else: 12 then: 0 else: 4 then: 0 else: 53 then: 0 else: 20 then: 0 else: 4 then: 0 else: 13 then: 0 else: 17 then: 0 else: 4 then: 0 else: 15 then: 0 else: 58 then: 0 else: 4 then: 0 else: 17 then: 0 else: 4 context.end_target if target_found
  81. nil
  82. end
  83. RUBY
  84. 166 __registered_elements__[method_name] = tag
  85. 166 method_name
  86. end
  87. 1 def __register_void_element__(method_name, tag: method_name.name.tr("_", "-"))
  88. 12 class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
  89. # frozen_string_literal: true
  90. 1 def #{method_name}(**attributes)
  91. 46 context = @_context
  92. 46 buffer = context.buffer
  93. 46 fragment = context.fragments
  94. 46 then: 9 else: 37 if fragment
  95. 9 then: 0 else: 9 then: 0 else: 0 return if fragment.length == 0 # we found all our fragments already
  96. 9 id = attributes[:id]
  97. 9 then: 6 else: 3 if !context.in_target_fragment
  98. 6 then: 2 if fragment[id]
  99. 2 context.begin_target(id)
  100. 2 target_found = true
  101. else: 4 else
  102. 4 return nil
  103. end
  104. end
  105. end
  106. 42 then: 42 if attributes.length > 0 # with attributes
  107. 42 buffer << "<#{tag}" << (::Phlex::ATTRIBUTE_CACHE[attributes] ||= __attributes__(attributes)) << ">"
  108. else: 0 else # without attributes
  109. buffer << "<#{tag}>"
  110. end
  111. 42 then: 2 else: 40 context.end_target if target_found
  112. nil
  113. end
  114. 1 alias_method :_#{method_name}, :#{method_name}
  115. RUBY
  116. 12 __registered_elements__[method_name] = tag
  117. 12 method_name
  118. end
  119. end

lib/phlex/sgml/safe_object.rb

100.0% lines covered

100.0% branches covered

1 relevant lines. 1 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. # @api private
  3. 1 module Phlex::SGML::SafeObject
  4. # This is included in objects that are safe to render in an SGML context.
  5. # They must implement a `to_s` method that returns a string.
  6. end

lib/phlex/sgml/safe_value.rb

100.0% lines covered

100.0% branches covered

5 relevant lines. 5 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 3 class Phlex::SGML::SafeValue
  3. 3 include Phlex::SGML::SafeObject
  4. 3 def initialize(to_s)
  5. 10 @to_s = to_s
  6. end
  7. 3 attr_reader :to_s
  8. end

lib/phlex/svg.rb

100.0% lines covered

100.0% branches covered

6 relevant lines. 6 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 class Phlex::SVG < Phlex::SGML
  3. 1 autoload :StandardElements, "phlex/svg/standard_elements"
  4. 1 include StandardElements
  5. 1 def content_type
  6. 1 "image/svg+xml"
  7. end
  8. 1 def filename
  9. nil
  10. end
  11. end

lib/phlex/svg/standard_elements.rb

100.0% lines covered

100.0% branches covered

66 relevant lines. 66 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Phlex::SVG::StandardElements
  3. 1 extend Phlex::SGML::Elements
  4. # Outputs an `<a>` tag.
  5. # See https://developer.mozilla.org/docs/Web/SVG/Element/a
  6. 1 register_element def a(
  7. download: nil,
  8. href: nil,
  9. hreflang: nil,
  10. ping: nil,
  11. referrerpolicy: nil,
  12. rel: nil,
  13. target: nil,
  14. type: nil,
  15. **attributes,
  16. &content
  17. ) = nil
  18. # Outputs an `<animate>` tag.
  19. # See https://developer.mozilla.org/docs/Web/SVG/Element/animate
  20. 1 register_element def animate(
  21. attributeName: nil,
  22. values: nil,
  23. dur: nil,
  24. repeatCount: nil,
  25. **attributes,
  26. &content
  27. ) = nil
  28. # Outputs an `<animateMotion>` tag.
  29. # See https://developer.mozilla.org/docs/Web/SVG/Element/animateMotion
  30. 1 register_element def animateMotion(
  31. keyPoints: nil,
  32. path: nil,
  33. rotate: nil,
  34. begin: nil,
  35. dur: nil,
  36. end: nil,
  37. repeatCount: nil,
  38. repeatDur: nil,
  39. fill: nil,
  40. calcMode: nil,
  41. values: nil,
  42. keyTimes: nil,
  43. keySplines: nil,
  44. from: nil,
  45. to: nil,
  46. by: nil,
  47. attributeName: nil,
  48. additive: nil,
  49. accumulate: nil,
  50. **attributes,
  51. &content
  52. ) = nil
  53. # Outputs an `<animateTransform>` tag.
  54. # See https://developer.mozilla.org/docs/Web/SVG/Element/animateTransform
  55. 1 register_element def animateTransform(
  56. **attributes,
  57. &content
  58. ) = nil
  59. # Outputs a `<circle>` tag.
  60. # See https://developer.mozilla.org/docs/Web/SVG/Element/circle
  61. 1 register_element def circle(
  62. **attributes,
  63. &content
  64. ) = nil
  65. # Outputs a `<clipPath>` tag.
  66. # See https://developer.mozilla.org/docs/Web/SVG/Element/clipPath
  67. 1 register_element def clipPath(
  68. **attributes,
  69. &content
  70. ) = nil
  71. # Outputs a `<defs>` tag.
  72. # See https://developer.mozilla.org/docs/Web/SVG/Element/defs
  73. 1 register_element def defs(
  74. **attributes,
  75. &content
  76. ) = nil
  77. # Outputs a `<desc>` tag.
  78. # See https://developer.mozilla.org/docs/Web/SVG/Element/desc
  79. 1 register_element def desc(
  80. **attributes,
  81. &content
  82. ) = nil
  83. # Outputs a `<discard>` tag.
  84. # See https://developer.mozilla.org/docs/Web/SVG/Element/discard
  85. 1 register_element def discard(
  86. **attributes,
  87. &content
  88. ) = nil
  89. # Outputs an `<ellipse>` tag.
  90. # See https://developer.mozilla.org/docs/Web/SVG/Element/ellipse
  91. 1 register_element def ellipse(
  92. **attributes,
  93. &content
  94. ) = nil
  95. # Outputs an `<feBlend>` tag.
  96. # See https://developer.mozilla.org/docs/Web/SVG/Element/feBlend
  97. 1 register_element def feBlend(
  98. **attributes,
  99. &content
  100. ) = nil
  101. # Outputs an `<feColorMatrix>` tag.
  102. # See https://developer.mozilla.org/docs/Web/SVG/Element/feColorMatrix
  103. 1 register_element def feColorMatrix(
  104. **attributes,
  105. &content
  106. ) = nil
  107. # Outputs an `<feComponentTransfer>` tag.
  108. # See https://developer.mozilla.org/docs/Web/SVG/Element/feComponentTransfer
  109. 1 register_element def feComponentTransfer(
  110. **attributes,
  111. &content
  112. ) = nil
  113. # Outputs an `<feComposite>` tag.
  114. # See https://developer.mozilla.org/docs/Web/SVG/Element/feComposite
  115. 1 register_element def feComposite(
  116. **attributes,
  117. &content
  118. ) = nil
  119. # Outputs an `<feConvolveMatrix>` tag.
  120. # See https://developer.mozilla.org/docs/Web/SVG/Element/feConvolveMatrix
  121. 1 register_element def feConvolveMatrix(
  122. **attributes,
  123. &content
  124. ) = nil
  125. # Outputs an `<feDiffuseLighting>` tag.
  126. # See https://developer.mozilla.org/docs/Web/SVG/Element/feDiffuseLighting
  127. 1 register_element def feDiffuseLighting(
  128. **attributes,
  129. &content
  130. ) = nil
  131. # Outputs an `<feDisplacementMap>` tag.
  132. # See https://developer.mozilla.org/docs/Web/SVG/Element/feDisplacementMap
  133. 1 register_element def feDisplacementMap(
  134. **attributes,
  135. &content
  136. ) = nil
  137. # Outputs an `<feDistantLight>` tag.
  138. # See https://developer.mozilla.org/docs/Web/SVG/Element/feDistantLight
  139. 1 register_element def feDistantLight(
  140. **attributes,
  141. &content
  142. ) = nil
  143. # Outputs an `<feDropShadow>` tag.
  144. # See https://developer.mozilla.org/docs/Web/SVG/Element/feDropShadow
  145. 1 register_element def feDropShadow(
  146. **attributes,
  147. &content
  148. ) = nil
  149. # Outputs an `<feFlood>` tag.
  150. # See https://developer.mozilla.org/docs/Web/SVG/Element/feFlood
  151. 1 register_element def feFlood(
  152. **attributes,
  153. &content
  154. ) = nil
  155. # Outputs an `<feFuncA>` tag.
  156. # See https://developer.mozilla.org/docs/Web/SVG/Element/feFuncA
  157. 1 register_element def feFuncA(
  158. **attributes,
  159. &content
  160. ) = nil
  161. # Outputs an `<feFuncB>` tag.
  162. # See https://developer.mozilla.org/docs/Web/SVG/Element/feFuncB
  163. 1 register_element def feFuncB(
  164. **attributes,
  165. &content
  166. ) = nil
  167. # Outputs an `<feFuncG>` tag.
  168. # See https://developer.mozilla.org/docs/Web/SVG/Element/feFuncG
  169. 1 register_element def feFuncG(
  170. **attributes,
  171. &content
  172. ) = nil
  173. # Outputs an `<feFuncR>` tag.
  174. # See https://developer.mozilla.org/docs/Web/SVG/Element/feFuncR
  175. 1 register_element def feFuncR(
  176. **attributes,
  177. &content
  178. ) = nil
  179. # Outputs an `<feGaussianBlur>` tag.
  180. # See https://developer.mozilla.org/docs/Web/SVG/Element/feGaussianBlur
  181. 1 register_element def feGaussianBlur(
  182. **attributes,
  183. &content
  184. ) = nil
  185. # Outputs an `<feImage>` tag.
  186. # See https://developer.mozilla.org/docs/Web/SVG/Element/feImage
  187. 1 register_element def feImage(
  188. **attributes,
  189. &content
  190. ) = nil
  191. # Outputs an `<feMerge>` tag.
  192. # See https://developer.mozilla.org/docs/Web/SVG/Element/feMerge
  193. 1 register_element def feMerge(
  194. **attributes,
  195. &content
  196. ) = nil
  197. # Outputs an `<feMergeNode>` tag.
  198. # See https://developer.mozilla.org/docs/Web/SVG/Element/feMergeNode
  199. 1 register_element def feMergeNode(
  200. **attributes,
  201. &content
  202. ) = nil
  203. # Outputs an `<feMorphology>` tag.
  204. # See https://developer.mozilla.org/docs/Web/SVG/Element/feMorphology
  205. 1 register_element def feMorphology(
  206. **attributes,
  207. &content
  208. ) = nil
  209. # Outputs an `<feOffset>` tag.
  210. # See https://developer.mozilla.org/docs/Web/SVG/Element/feOffset
  211. 1 register_element def feOffset(
  212. **attributes,
  213. &content
  214. ) = nil
  215. # Outputs an `<fePointLight>` tag.
  216. # See https://developer.mozilla.org/docs/Web/SVG/Element/fePointLight
  217. 1 register_element def fePointLight(
  218. **attributes,
  219. &content
  220. ) = nil
  221. # Outputs an `<feSpecularLighting>` tag.
  222. # See https://developer.mozilla.org/docs/Web/SVG/Element/feSpecularLighting
  223. 1 register_element def feSpecularLighting(
  224. **attributes,
  225. &content
  226. ) = nil
  227. # Outputs an `<feSpotLight>` tag.
  228. # See https://developer.mozilla.org/docs/Web/SVG/Element/feSpotLight
  229. 1 register_element def feSpotLight(
  230. **attributes,
  231. &content
  232. ) = nil
  233. # Outputs an `<feTile>` tag.
  234. # See https://developer.mozilla.org/docs/Web/SVG/Element/feTile
  235. 1 register_element def feTile(
  236. **attributes,
  237. &content
  238. ) = nil
  239. # Outputs an `<feTurbulence>` tag.
  240. # See https://developer.mozilla.org/docs/Web/SVG/Element/feTurbulence
  241. 1 register_element def feTurbulence(
  242. **attributes,
  243. &content
  244. ) = nil
  245. # Outputs a `<filter>` tag.
  246. # See https://developer.mozilla.org/docs/Web/SVG/Element/filter
  247. 1 register_element def filter(
  248. **attributes,
  249. &content
  250. ) = nil
  251. # Outputs a `<foreignObject>` tag.
  252. # See https://developer.mozilla.org/docs/Web/SVG/Element/foreignObject
  253. 1 register_element def foreignObject(
  254. **attributes,
  255. &content
  256. ) = nil
  257. # Outputs a `<g>` tag.
  258. # See https://developer.mozilla.org/docs/Web/SVG/Element/g
  259. 1 register_element def g(
  260. **attributes,
  261. &content
  262. ) = nil
  263. # Outputs an `<image>` tag.
  264. # See https://developer.mozilla.org/docs/Web/SVG/Element/image
  265. 1 register_element def image(
  266. **attributes,
  267. &content
  268. ) = nil
  269. # Outputs a `<line>` tag.
  270. # See https://developer.mozilla.org/docs/Web/SVG/Element/line
  271. 1 register_element def line(
  272. **attributes,
  273. &content
  274. ) = nil
  275. # Outputs a `<linearGradient>` tag.
  276. # See https://developer.mozilla.org/docs/Web/SVG/Element/linearGradient
  277. 1 register_element def linearGradient(
  278. **attributes,
  279. &content
  280. ) = nil
  281. # Outputs a `<marker>` tag.
  282. # See https://developer.mozilla.org/docs/Web/SVG/Element/marker
  283. 1 register_element def marker(
  284. **attributes,
  285. &content
  286. ) = nil
  287. # Outputs a `<mask>` tag.
  288. # See https://developer.mozilla.org/docs/Web/SVG/Element/mask
  289. 1 register_element def mask(
  290. **attributes,
  291. &content
  292. ) = nil
  293. # Outputs a `<metadata>` tag.
  294. # See https://developer.mozilla.org/docs/Web/SVG/Element/metadata
  295. 1 register_element def metadata(
  296. **attributes,
  297. &content
  298. ) = nil
  299. # Outputs an `<mpath>` tag.
  300. # See https://developer.mozilla.org/docs/Web/SVG/Element/mpath
  301. 1 register_element def mpath(
  302. **attributes,
  303. &content
  304. ) = nil
  305. # Outputs a `<path>` tag.
  306. # See https://developer.mozilla.org/docs/Web/SVG/Element/path
  307. 1 register_element def path(
  308. **attributes,
  309. &content
  310. ) = nil
  311. # Outputs a `<pattern>` tag.
  312. # See https://developer.mozilla.org/docs/Web/SVG/Element/pattern
  313. 1 register_element def pattern(
  314. **attributes,
  315. &content
  316. ) = nil
  317. # Outputs a `<polygon>` tag.
  318. # See https://developer.mozilla.org/docs/Web/SVG/Element/polygon
  319. 1 register_element def polygon(
  320. **attributes,
  321. &content
  322. ) = nil
  323. # Outputs a `<polyline>` tag.
  324. # See https://developer.mozilla.org/docs/Web/SVG/Element/polyline
  325. 1 register_element def polyline(
  326. **attributes,
  327. &content
  328. ) = nil
  329. # Outputs a `<radialGradient>` tag.
  330. # See https://developer.mozilla.org/docs/Web/SVG/Element/radialGradient
  331. 1 register_element def radialGradient(
  332. **attributes,
  333. &content
  334. ) = nil
  335. # Outputs a `<rect>` tag.
  336. # See https://developer.mozilla.org/docs/Web/SVG/Element/rect
  337. 1 register_element def rect(
  338. **attributes,
  339. &content
  340. ) = nil
  341. # Outputs a `<script>` tag.
  342. # See https://developer.mozilla.org/docs/Web/SVG/Element/script
  343. 1 register_element def script(
  344. **attributes,
  345. &content
  346. ) = nil
  347. # Outputs a `<set>` tag.
  348. # See https://developer.mozilla.org/docs/Web/SVG/Element/set
  349. 1 register_element def set(
  350. **attributes,
  351. &content
  352. ) = nil
  353. # Outputs a `<stop>` tag.
  354. # See https://developer.mozilla.org/docs/Web/SVG/Element/stop
  355. 1 register_element def stop(
  356. **attributes,
  357. &content
  358. ) = nil
  359. # Outputs a `<style>` tag.
  360. # See https://developer.mozilla.org/docs/Web/SVG/Element/style
  361. 1 register_element def style(
  362. **attributes,
  363. &content
  364. ) = nil
  365. # Outputs an `<svg>` tag.
  366. # See https://developer.mozilla.org/docs/Web/SVG/Element/svg
  367. 1 register_element def svg(
  368. **attributes,
  369. &content
  370. ) = nil
  371. # Outputs a `<switch>` tag.
  372. # See https://developer.mozilla.org/docs/Web/SVG/Element/switch
  373. 1 register_element def switch(
  374. **attributes,
  375. &content
  376. ) = nil
  377. # Outputs a `<symbol>` tag.
  378. # See https://developer.mozilla.org/docs/Web/SVG/Element/symbol
  379. 1 register_element def symbol(
  380. **attributes,
  381. &content
  382. ) = nil
  383. # Outputs a `<text>` tag.
  384. # See https://developer.mozilla.org/docs/Web/SVG/Element/text
  385. 1 register_element def text(
  386. **attributes,
  387. &content
  388. ) = nil
  389. # Outputs a `<textPath>` tag.
  390. # See https://developer.mozilla.org/docs/Web/SVG/Element/textPath
  391. 1 register_element def textPath(
  392. **attributes,
  393. &content
  394. ) = nil
  395. # Outputs a `<title>` tag.
  396. # See https://developer.mozilla.org/docs/Web/SVG/Element/title
  397. 1 register_element def title(
  398. **attributes,
  399. &content
  400. ) = nil
  401. # Outputs a `<tspan>` tag.
  402. # See https://developer.mozilla.org/docs/Web/SVG/Element/tspan
  403. 1 register_element def tspan(
  404. **attributes,
  405. &content
  406. ) = nil
  407. # Outputs a `<use>` tag.
  408. # See https://developer.mozilla.org/docs/Web/SVG/Element/use
  409. 1 register_element def use(
  410. **attributes,
  411. &content
  412. ) = nil
  413. # Outputs a `<view>` tag.
  414. # See https://developer.mozilla.org/docs/Web/SVG/Element/view
  415. 1 register_element def view(
  416. **attributes,
  417. &content
  418. ) = nil
  419. end