Complete overhaul of smart quotes to "typographer"

See README for details

Contributes to #50
This commit is contained in:
Andy Meneely
2015-04-07 00:16:06 -04:00
parent 674397c005
commit a5d1cb60f2
11 changed files with 259 additions and 95 deletions
+2 -5
View File
@@ -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],
-29
View File
@@ -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
+96
View File
@@ -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
+4 -1
View File
@@ -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)