Complete overhaul of smart quotes to "typographer"
See README for details Contributes to #50
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
require 'squib/api/text_embed'
|
||||
require 'squib/args/smart_quotes'
|
||||
|
||||
module Squib
|
||||
class Deck
|
||||
@@ -26,7 +25,7 @@ module Squib
|
||||
# @option opts x [Integer] (0) the x-coordinate to place. Supports Unit Conversion, see {file:README.md#Units Units}.
|
||||
# @option opts y [Integer] (0) the y-coordinate to place. Supports Unit Conversion, see {file:README.md#Units Units}.
|
||||
# @option opts color [String] (:black) the color the font will render to. Gradients supported. See {file:README.md#Specifying_Colors___Gradients Specifying Colors}
|
||||
# @option opts markup: [Boolean] (false) Enable markup parsing of `str` using the HTML-like Pango Markup syntax, defined [here](http://ruby-gnome2.sourceforge.jp/hiki.cgi?pango-markup) and [here](https://developer.gnome.org/pango/stable/PangoMarkupFormat.html).
|
||||
# @option opts markup: [Boolean] (false) Enable markup parsing of `str` using the HTML-like Pango Markup syntax, defined [here](http://ruby-gnome2.sourceforge.jp/hiki.cgi?pango-markup) and [here](https://developer.gnome.org/pango/stable/PangoMarkupFormat.html). Also does other replacements, such as smart quotes, curly apostraphes, en- and em-dashes, and explict ellipses (not to be confused with ellipsize option). See README for full explanation.
|
||||
# @option opts width [Integer, :native] (:native) the width of the box the string will be placed in. Stretches to the content by default.. Supports Unit Conversion, see {file:README.md#Units Units}.
|
||||
# @option opts height [Integer, :native] the height of the box the string will be placed in. Stretches to the content by default. Supports Unit Conversion, see {file:README.md#Units Units}.
|
||||
# @option opts layout [String, Symbol] (nil) entry in the layout to use as defaults for this command. See {file:README.md#Custom_Layouts Custom Layouts}
|
||||
@@ -39,7 +38,6 @@ module Squib
|
||||
# @option opts ellipsize [:none, :start, :middle, :end, true, false] (:end) When width and height are set, determines the behavior of overflowing text. Also: `true` maps to `:end` and `false` maps to `:none`. Default `:end`
|
||||
# @option opts angle [FixNum] (0) Rotation of the text in radians. Note that this rotates around the upper-left corner of the text box, making the placement of x-y coordinates slightly tricky.
|
||||
# @option opts hint [String] (:nil) draw a rectangle around the text with the given color. Overrides global hints (see {Deck#hint}).
|
||||
# @options ops quotes [:smart, :dumb, or Array]. Convert straight ("dumb") quotes to curly ("smart") quotes. The 'smart' option assumes UTF-8 characters. If you supply a two-element array of characters, those will be used (first is left, second is right). Smart quoting looks for a quote next to a letter, word, number, or underscore character. Default is to show straight quotes.
|
||||
# @return [Array] Returns an Array of hashes keyed by :width and :height that mark the ink extents of the text rendered.
|
||||
# @api public
|
||||
def text(opts = {})
|
||||
@@ -50,8 +48,7 @@ module Squib
|
||||
yield(embed) if block_given? #store the opts for later use
|
||||
extents = Array.new(@cards.size)
|
||||
opts[:range].each do |i|
|
||||
str = Args::SmartQuotes.new.process(opts[:str][i], opts[:quotes][i])
|
||||
extents[i] = @cards[i].text(embed, str,
|
||||
extents[i] = @cards[i].text(embed, opts[:str][i],
|
||||
opts[:font][i], opts[:font_size][i], opts[:color][i],
|
||||
opts[:x][i], opts[:y][i], opts[:width][i], opts[:height][i],
|
||||
opts[:markup][i], opts[:justify][i], opts[:wrap][i],
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
module Squib
|
||||
module Args
|
||||
class SmartQuotes
|
||||
|
||||
def process(str, opt)
|
||||
clean_opt = opt.to_s.downcase.strip
|
||||
return str if clean_opt.eql? 'dumb'
|
||||
if clean_opt.eql? 'smart'
|
||||
quotify(str) # default to UTF-8
|
||||
else
|
||||
quotify(str, opt) # supplied quotes
|
||||
end
|
||||
end
|
||||
|
||||
# Convert regular quotes to smart quotes by looking for
|
||||
# a boundary between a word character (letters, numbers, underscore)
|
||||
# and a quote. Replaces with the UTF-8 equivalent.
|
||||
# :nodoc:
|
||||
# @api private
|
||||
def quotify(str, quote_chars = ["\u201C", "\u201D"])
|
||||
left_regex = /(\")(\w)/
|
||||
right_regex = /(\w)(\")/
|
||||
str.gsub(left_regex, quote_chars[0] + '\2')
|
||||
.gsub(right_regex, '\1' + quote_chars[1])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
require 'squib/constants'
|
||||
module Squib
|
||||
module Args
|
||||
class Typographer
|
||||
|
||||
def initialize(config = CONFIG_DEFAULTS)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def process(str)
|
||||
[
|
||||
:left_curly,
|
||||
:right_curly,
|
||||
:apostraphize,
|
||||
:right_double_quote,
|
||||
:left_double_quote,
|
||||
:right_single_quote,
|
||||
:left_single_quote,
|
||||
:ellipsificate,
|
||||
:em_dash,
|
||||
:en_dash ].each do |sym|
|
||||
str = each_non_tag(str) do |token|
|
||||
self.method(sym).call(token)
|
||||
end
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
# Iterate over each non-tag for processing
|
||||
# Allows us to ignore anything inside < and >
|
||||
def each_non_tag(str)
|
||||
full_str = ''
|
||||
tag_delimit = /(<(?:(?!<).)*>)/ # use non-capturing group w/ negative lookahead
|
||||
str.split(tag_delimit).each do |token|
|
||||
if token.start_with? '<'
|
||||
full_str << token # don't process tags
|
||||
else
|
||||
full_str << yield(token)
|
||||
end
|
||||
end
|
||||
return full_str
|
||||
end
|
||||
|
||||
# Straightforward replace
|
||||
def left_curly(str)
|
||||
str.gsub('``', "\u201C")
|
||||
end
|
||||
|
||||
# Straightforward replace
|
||||
def right_curly(str)
|
||||
str.gsub(%{''}, "\u201D")
|
||||
end
|
||||
|
||||
# A quote between two letters is an apostraphe
|
||||
def apostraphize(str)
|
||||
str.gsub(/(\w)(\')(\w)/, '\1' + "\u2019" + '\3')
|
||||
end
|
||||
|
||||
# Quote next to non-whitespace curls
|
||||
def right_double_quote(str)
|
||||
str.gsub(/(\S)(\")/, '\1' + "\u201D")
|
||||
end
|
||||
|
||||
# Quote next to non-whitespace curls
|
||||
def left_double_quote(str)
|
||||
str.gsub(/(\")(\S)/, "\u201C" + '\2')
|
||||
end
|
||||
|
||||
# Quote next to non-whitespace curls
|
||||
def right_single_quote(str)
|
||||
str.gsub(/(\S)(\')/, '\1' + "\u2019")
|
||||
end
|
||||
|
||||
# Quote next to non-whitespace curls
|
||||
def left_single_quote(str)
|
||||
str.gsub(/(\')(\S)/, "\u2018" + '\2')
|
||||
end
|
||||
|
||||
# Straightforward replace
|
||||
def ellipsificate(str)
|
||||
str.gsub('...', "\u2026")
|
||||
end
|
||||
|
||||
# Straightforward replace
|
||||
def en_dash(str)
|
||||
str.gsub('--', "\u2013")
|
||||
end
|
||||
|
||||
# Straightforward replace
|
||||
def em_dash(str)
|
||||
str.gsub('---', "\u2014")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,5 @@
|
||||
require 'pango'
|
||||
require 'squib/args/typographer'
|
||||
|
||||
module Squib
|
||||
class Card
|
||||
@@ -153,7 +154,9 @@ module Squib
|
||||
layout = cc.create_pango_layout
|
||||
layout.font_description = font_desc
|
||||
layout.text = str
|
||||
layout.markup = str if markup
|
||||
if markup
|
||||
layout.markup = Args::Typographer.new(@deck.config).process(layout.text)
|
||||
end
|
||||
|
||||
set_wh!(layout, width, height)
|
||||
set_wrap!(layout, wrap)
|
||||
|
||||
Reference in New Issue
Block a user