1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# frozen_string_literal: true
# parser.rb: Prawn icon tag text parser (pseudo-HTML).
#
# Copyright October 2014, Jesse Doyle. All rights reserved.
#
# This is free software. Please see the LICENSE and COPYING files for details.
module Prawn
class Icon
# Provides the necessary methods to enable the parsing
# of <icon> tags from input text.
#
# = Supported Tags:
# <icon></icon>::
# Place an icon key between the tags and the output
# will be translated into: <font name="fa">unicode</font>.
#
# = Supported Attributes:
#
# Various attributes will be extracted from +<icon>+ tags:
#
# color::
# The hex representation of a color that the icon should
# be rendered as. If left nil, the document's fill color
# will be used.
#
# size::
# The font size of a particular icon. If left nil, the
# document's font size will be used.
#
class Parser
PARSER_REGEX = Regexp.new \
'<icon[^>]*>|</icon>',
Regexp::IGNORECASE |
Regexp::MULTILINE
CONTENT_REGEX = /<icon[^>]*>(?<content>[^<]*)<\/icon>/mi.freeze
TAG_REGEX = /<icon[^>]*>[^<]*<\/icon>/mi.freeze
# rubocop:disable Lint/MixedRegexpCaptureTypes
ATTR_REGEX = /(?<attr>[a-zA-Z]*)=["|'](?<val>(\w*[^["|']]))["|']/mi.freeze
# rubocop:enable Lint/MixedRegexpCaptureTypes
class << self
def format(document, string)
tokens = string.scan(PARSER_REGEX)
config = config_from_tokens(tokens)
content = string.scan(CONTENT_REGEX).flatten
icons = keys_to_unicode(document, content, config)
tags = icon_tags(icons)
string.gsub(TAG_REGEX).with_index { |_, i| tags[i] }
end
def config_from_tokens(tokens)
[].tap do |array|
tokens.each do |token|
# Skip the closing tag
next if token =~ /<\/icon>/i
# Convert [[1,2], [3,4]] to { :1 => 2, :3 => 4 }
attrs = token.scan(ATTR_REGEX).inject({}) do |k, v|
val = attr_hash(v)
k.merge!(val)
end
array << attrs
end
end
end
def icon_tags(icons)
[].tap do |tags|
icons.each do |icon|
# Mandatory
content = icon[:content]
set = icon[:set]
# Optional
color = icon[:color]
size = icon[:size]
opening = "<font name=\"#{set}\""
unless color || size
tags << "#{opening}>#{content}</font>"
next
end
opening += " size=\"#{size}\"" if size
content = "<color rgb=\"#{color}\">#{content}</color>" if color
opening += '>'
tags << "#{opening}#{content}</font>"
end
end
end
def keys_to_unicode(document, content, config)
[].tap do |icons|
content.each_with_index do |icon, index|
key = Compatibility.new(key: icon).translate
options ||= {}
options = config[index] if config.any?
info = {
set: FontData.specifier_from_key(key),
size: options[:size],
color: options[:color],
content: FontData.unicode_from_key(document, key)
}
icons << info
end
end
end
private
def attr_hash(value) # :nodoc:
# If attr == size, we must cast value to float,
# else symbolize the key and map it to value
if value[0] =~ /size/i
{ size: value[1].to_f }
else
{ value[0].to_sym => value[1] }
end
end
end
end
end
end
|