Allow configuration of typographical replacements, e.g. smart quotes
If you're living in a non-UTF-8 character set, then you can configure what quotes are smartly changed. If my regexes are messing things up, you can also turn this off with smart_quotes: false Also updated docs. This closes #50dev
parent
beb46a9e1c
commit
063d5156d6
26
README.md
26
README.md
|
|
@ -250,7 +250,21 @@ If you want to do specialized formatting within a given string, Squib has lots o
|
||||||
* Apostraphes are converted to curly as well.
|
* Apostraphes are converted to curly as well.
|
||||||
* LaTeX-style quotes are explicitly converted (<tt>``like this''</tt>)
|
* LaTeX-style quotes are explicitly converted (<tt>``like this''</tt>)
|
||||||
* Em-dash and en-dash are converted with triple and double-dashes respectively (<tt>--</tt> is an en-dash, and <tt>---</tt> becomes an em-dash.)
|
* Em-dash and en-dash are converted with triple and double-dashes respectively (<tt>--</tt> is an en-dash, and <tt>---</tt> becomes an em-dash.)
|
||||||
* Ellipses can be specified with <tt>...</tt>. Note that this is entirely different from the `ellipsize` option (which determines what to do with overflowing text).
|
* Ellipses can be specified with <tt>...</tt>. Note that this is entirely different from the `ellipsize` option, which is determining what to do with overflowing text.
|
||||||
|
|
||||||
|
The above replacements assume you are using the UTF-8 character set. If you wish to change the characters, set the following configuration options in your `config.yml`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
lsquote: "\u2018" #note that Yaml wants double quotes here to use escape chars
|
||||||
|
rsquote: "\u2019"
|
||||||
|
ldquote: "\u201C"
|
||||||
|
rdquote: "\u201D"
|
||||||
|
em_dash: "\u2014"
|
||||||
|
en_dash: "\u2013"
|
||||||
|
ellipsis: "\u2026"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also disable the auto-quoting mechanism by setting `smart_quotes: false` in your config. Explicit replacements will still be performed.
|
||||||
|
|
||||||
### Text Samples
|
### Text Samples
|
||||||
|
|
||||||
|
|
@ -258,10 +272,18 @@ Examples of all of the above are crammed into the `text_options.rb` sample [foun
|
||||||
|
|
||||||
{include:file:samples/text_options.rb}
|
{include:file:samples/text_options.rb}
|
||||||
|
|
||||||
Also, the `embed_text.rb` sample has more examples of embedding text, which can be [found here](https://github.com/andymeneely/squib/tree/master/samples/embed_text.rb).
|
The `embed_text.rb` sample has more examples of embedding text, which can be [found here](https://github.com/andymeneely/squib/tree/master/samples/embed_text.rb).
|
||||||
|
|
||||||
{include:file:samples/embed_text.rb}
|
{include:file:samples/embed_text.rb}
|
||||||
|
|
||||||
|
The `config_text_markup.rb` sample demonstrates how quoting can be configured, [found here](https://github.com/andymeneely/squib/tree/master/samples/config_text_markup.rb)
|
||||||
|
|
||||||
|
{include:file:samples/config_text_markup.rb}
|
||||||
|
|
||||||
|
{include:file:samples/config_text_markup.yml}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Custom Layouts
|
## Custom Layouts
|
||||||
|
|
||||||
Working with x-y coordinates all the time can be tiresome, and ideally everything in a game prototype should be data-driven and easily changed. For this, many Squib methods allow for a `layout` to be set. In essence, layouts are a way of setting default values for any argument given to the command.
|
Working with x-y coordinates all the time can be tiresome, and ideally everything in a game prototype should be data-driven and easily changed. For this, many Squib methods allow for a `layout` to be set. In essence, layouts are a way of setting default values for any argument given to the command.
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,27 @@ module Squib
|
||||||
end
|
end
|
||||||
|
|
||||||
def process(str)
|
def process(str)
|
||||||
[
|
str = explicit_replacements(str)
|
||||||
:left_curly,
|
str = smart_quotes(str) if @config['smart_quotes']
|
||||||
:right_curly,
|
str
|
||||||
:apostraphize,
|
end
|
||||||
|
|
||||||
|
def explicit_replacements(str)
|
||||||
|
[ :left_curly, :right_curly, :apostraphize,
|
||||||
|
:ellipsificate, :em_dash, :en_dash ].each do |sym|
|
||||||
|
str = each_non_tag(str) do |token|
|
||||||
|
self.method(sym).call(token)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
def smart_quotes(str)
|
||||||
|
[ :single_inside_double_quote,
|
||||||
:right_double_quote,
|
:right_double_quote,
|
||||||
:left_double_quote,
|
:left_double_quote,
|
||||||
:right_single_quote,
|
:right_single_quote,
|
||||||
:left_single_quote,
|
:left_single_quote].each do |sym|
|
||||||
:ellipsificate,
|
|
||||||
:em_dash,
|
|
||||||
:en_dash ].each do |sym|
|
|
||||||
str = each_non_tag(str) do |token|
|
str = each_non_tag(str) do |token|
|
||||||
self.method(sym).call(token)
|
self.method(sym).call(token)
|
||||||
end
|
end
|
||||||
|
|
@ -43,52 +53,58 @@ module Squib
|
||||||
|
|
||||||
# Straightforward replace
|
# Straightforward replace
|
||||||
def left_curly(str)
|
def left_curly(str)
|
||||||
str.gsub('``', "\u201C")
|
str.gsub('``', @config['ldquote'])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Straightforward replace
|
# Straightforward replace
|
||||||
def right_curly(str)
|
def right_curly(str)
|
||||||
str.gsub(%{''}, "\u201D")
|
str.gsub(%{''}, @config['rdquote'])
|
||||||
end
|
end
|
||||||
|
|
||||||
# A quote between two letters is an apostraphe
|
# A quote between two letters is an apostraphe
|
||||||
def apostraphize(str)
|
def apostraphize(str)
|
||||||
str.gsub(/(\w)(\')(\w)/, '\1' + "\u2019" + '\3')
|
str.gsub(/(\w)(\')(\w)/, '\1' + @config['rsquote'] + '\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
|
end
|
||||||
|
|
||||||
# Straightforward replace
|
# Straightforward replace
|
||||||
def ellipsificate(str)
|
def ellipsificate(str)
|
||||||
str.gsub('...', "\u2026")
|
str.gsub('...', @config['ellipsis'])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Straightforward replace
|
# Straightforward replace
|
||||||
def en_dash(str)
|
def en_dash(str)
|
||||||
str.gsub('--', "\u2013")
|
str.gsub('--', @config['en_dash'])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Straightforward replace
|
# Straightforward replace
|
||||||
def em_dash(str)
|
def em_dash(str)
|
||||||
str.gsub('---', "\u2014")
|
str.gsub('---', @config['em_dash'])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Quote next to non-whitespace curls
|
||||||
|
def right_double_quote(str)
|
||||||
|
str.gsub(/(\S)(\")/, '\1' + @config['rdquote'])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Quote next to non-whitespace curls
|
||||||
|
def left_double_quote(str)
|
||||||
|
str.gsub(/(\")(\S)/, @config['ldquote'] + '\2')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Handle the cases where a double quote is next to a single quote
|
||||||
|
def single_inside_double_quote(str)
|
||||||
|
str.gsub(/(\")(\')(\S)/, @config['ldquote'] + @config['lsquote'] + '\3')
|
||||||
|
.gsub(/(\")(\')(\S)/, '\1' + @config['rsquote'] + @config['rdquote'])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Quote next to non-whitespace curls
|
||||||
|
def right_single_quote(str)
|
||||||
|
str.gsub(/(\S)(\')/, '\1' + @config['rsquote'])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Quote next to non-whitespace curls
|
||||||
|
def left_single_quote(str)
|
||||||
|
str.gsub(/(\')(\S)/, @config['lsquote'] + '\2')
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,14 @@ module Squib
|
||||||
'hint' => :none,
|
'hint' => :none,
|
||||||
'img_dir' => '.',
|
'img_dir' => '.',
|
||||||
'progress_bar' => false,
|
'progress_bar' => false,
|
||||||
|
'ldquote' => "\u201C", # UTF8 chars
|
||||||
|
'rdquote' => "\u201D",
|
||||||
|
'lsquote' => "\u2018",
|
||||||
|
'rsquote' => "\u2019",
|
||||||
|
'em_dash' => "\u2014",
|
||||||
|
'en_dash' => "\u2013",
|
||||||
|
'ellipsis' => "\u2026",
|
||||||
|
'smart_quotes' => true,
|
||||||
}
|
}
|
||||||
|
|
||||||
#Translate the hints to the methods.
|
#Translate the hints to the methods.
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ module Squib
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
# @api private
|
# @api private
|
||||||
attr_reader :layout, :config
|
attr_reader :layout, :config, :quote_chars
|
||||||
|
|
||||||
attr_reader :dir, :prefix, :count_format
|
attr_reader :dir, :prefix, :count_format
|
||||||
|
|
||||||
|
|
@ -70,6 +70,7 @@ module Squib
|
||||||
@dir = SYSTEM_DEFAULTS[:dir]
|
@dir = SYSTEM_DEFAULTS[:dir]
|
||||||
@prefix = SYSTEM_DEFAULTS[:prefix]
|
@prefix = SYSTEM_DEFAULTS[:prefix]
|
||||||
@count_format = SYSTEM_DEFAULTS[:count_format]
|
@count_format = SYSTEM_DEFAULTS[:count_format]
|
||||||
|
@quote_chars = CONFIG_DEFAULTS.select {|k,v| %w(lsquote rsquote ldquote rdquote smart_quotes).include?(k) }
|
||||||
show_info(config, layout)
|
show_info(config, layout)
|
||||||
load_config(config)
|
load_config(config)
|
||||||
@width = Args::UnitConversion.parse width, dpi
|
@width = Args::UnitConversion.parse width, dpi
|
||||||
|
|
@ -111,6 +112,10 @@ module Squib
|
||||||
@prefix = config['prefix']
|
@prefix = config['prefix']
|
||||||
@count_format = config['count_format']
|
@count_format = config['count_format']
|
||||||
@antialias = config['antialias']
|
@antialias = config['antialias']
|
||||||
|
@quote_chars ||= {}
|
||||||
|
%w(lsquote rsquote ldquote rdquote smart_quotes em_dash en_dash ellipsis).each do |key|
|
||||||
|
@quote_chars[key] = config[key]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ module Squib
|
||||||
layout.font_description = font_desc
|
layout.font_description = font_desc
|
||||||
layout.text = str
|
layout.text = str
|
||||||
if markup
|
if markup
|
||||||
str = Args::Typographer.new(@deck.config).process(layout.text)
|
str = Args::Typographer.new(@deck.quote_chars).process(layout.text)
|
||||||
layout.markup = str
|
layout.markup = str
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,3 +25,16 @@
|
||||||
# Use a SVG cairo back end, instead of an in-memory buffer
|
# Use a SVG cairo back end, instead of an in-memory buffer
|
||||||
# backend: :memory # default
|
# backend: :memory # default
|
||||||
# backend: :svg # can create scalable pdfs, but rendering done at the printer level is not as good as Cairo.
|
# backend: :svg # can create scalable pdfs, but rendering done at the printer level is not as good as Cairo.
|
||||||
|
|
||||||
|
# Configure what text markup uses replace characters
|
||||||
|
# Below are the defaults
|
||||||
|
# lsquote: "\u2018" #note that Yaml wants double quotes here to use escape chars
|
||||||
|
# rsquote: "\u2019"
|
||||||
|
# ldquote: "\u201C"
|
||||||
|
# rdquote: "\u201D"
|
||||||
|
# em_dash: "\u2014"
|
||||||
|
# en_dash: "\u2013"
|
||||||
|
# ellipsis: "\u2026"
|
||||||
|
|
||||||
|
# We can also disallow smart quotes and only allow explicit replacements with ``LaTeX-style'' quotes.
|
||||||
|
# smart_quotes: false
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# If we want to disable smart quoting and only allow explicit quoting within markup,
|
||||||
|
# use this option
|
||||||
|
smart_quotes: false
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
require 'squib'
|
||||||
|
|
||||||
|
Squib::Deck.new(config: 'config_text_markup.yml') do
|
||||||
|
text str: %{"'Yaml ain't markup', he says"},
|
||||||
|
x: 10, y: 10, width: 300, height: 200, font: 'Serif 20',
|
||||||
|
markup: true, hint: :cyan
|
||||||
|
save_png prefix: 'config_text_'
|
||||||
|
end
|
||||||
|
|
||||||
|
Squib::Deck.new(config: 'config_disable_quotes.yml') do
|
||||||
|
text str: %{This has typographic sugar --- and ``explicit'' quotes --- but the quotes are "dumb"},
|
||||||
|
x: 10, y: 10, width: 300, height: 200, font: 'Serif 20',
|
||||||
|
markup: true, hint: :cyan
|
||||||
|
save_png prefix: 'config_disable_text_'
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# We can configure what characters actually get replaced by quoting them with unicode code points.
|
||||||
|
lsquote: "\u2018" #note that Yaml wants double quotes here to use escape chars
|
||||||
|
rsquote: "\u2019"
|
||||||
|
ldquote: "\u201C"
|
||||||
|
rdquote: "\u201D"
|
||||||
|
em_dash: "\u2014"
|
||||||
|
en_dash: "\u2013"
|
||||||
|
ellipsis: "\u2026"
|
||||||
|
|
@ -45,7 +45,7 @@ describe Squib::Args::Typographer do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "single quotes inside double quotes" do
|
it "single quotes inside double quotes" do
|
||||||
expect(t.process(%{"'I can't do that', he said"})).to eq(%{\u201C\u2019I can\u2019t do that\u2019, he said\u201D})
|
expect(t.process(%{"'I can't do that', he said"})).to eq(%{\u201C\u2018I can\u2019t do that\u2019, he said\u201D})
|
||||||
end
|
end
|
||||||
|
|
||||||
it "replaces the straightforward ones" do
|
it "replaces the straightforward ones" do
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
cairo: antialias=(["subpixel"])
|
||||||
|
cairo: save([])
|
||||||
|
cairo: set_source_color([:black])
|
||||||
|
cairo: translate([10, 10])
|
||||||
|
cairo: rotate([0])
|
||||||
|
cairo: move_to([0, 0])
|
||||||
|
pango: font_description=([MockDouble])
|
||||||
|
pango: text=(["\"'Yaml ain't markup', he says\""])
|
||||||
|
pango: markup=(["foo"])
|
||||||
|
pango: width=([307200])
|
||||||
|
pango: height=([204800])
|
||||||
|
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
|
||||||
|
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
|
||||||
|
pango: alignment=([#<Pango::Layout::Alignment left>])
|
||||||
|
pango: justify=([false])
|
||||||
|
pango: spacing=([0])
|
||||||
|
cairo: update_pango_layout([MockDouble])
|
||||||
|
cairo: move_to([0, 0])
|
||||||
|
cairo: update_pango_layout([MockDouble])
|
||||||
|
cairo: show_pango_layout([MockDouble])
|
||||||
|
cairo: rounded_rectangle([0, 0, 0, 0, 0, 0])
|
||||||
|
cairo: set_source_color([:cyan])
|
||||||
|
cairo: set_line_width([2.0])
|
||||||
|
cairo: stroke([])
|
||||||
|
cairo: restore([])
|
||||||
|
surface: write_to_png(["_output/config_text_00.png"])
|
||||||
|
cairo: antialias=(["subpixel"])
|
||||||
|
cairo: save([])
|
||||||
|
cairo: set_source_color([:black])
|
||||||
|
cairo: translate([10, 10])
|
||||||
|
cairo: rotate([0])
|
||||||
|
cairo: move_to([0, 0])
|
||||||
|
pango: font_description=([MockDouble])
|
||||||
|
pango: text=(["This has typographic sugar --- and ``explicit'' quotes --- but the quotes are \"dumb\""])
|
||||||
|
pango: markup=(["foo"])
|
||||||
|
pango: width=([307200])
|
||||||
|
pango: height=([204800])
|
||||||
|
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
|
||||||
|
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
|
||||||
|
pango: alignment=([#<Pango::Layout::Alignment left>])
|
||||||
|
pango: justify=([false])
|
||||||
|
pango: spacing=([0])
|
||||||
|
cairo: update_pango_layout([MockDouble])
|
||||||
|
cairo: move_to([0, 0])
|
||||||
|
cairo: update_pango_layout([MockDouble])
|
||||||
|
cairo: show_pango_layout([MockDouble])
|
||||||
|
cairo: rounded_rectangle([0, 0, 0, 0, 0, 0])
|
||||||
|
cairo: set_source_color([:cyan])
|
||||||
|
cairo: set_line_width([2.0])
|
||||||
|
cairo: stroke([])
|
||||||
|
cairo: restore([])
|
||||||
|
surface: write_to_png(["_output/config_disable_text_00.png"])
|
||||||
|
|
@ -51,6 +51,7 @@ describe "Squib samples" do
|
||||||
basic.rb
|
basic.rb
|
||||||
cairo_access.rb
|
cairo_access.rb
|
||||||
csv_import.rb
|
csv_import.rb
|
||||||
|
config_text_markup.rb
|
||||||
custom_config.rb
|
custom_config.rb
|
||||||
draw_shapes.rb
|
draw_shapes.rb
|
||||||
embed_text.rb
|
embed_text.rb
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,10 @@
|
||||||
"name": "rake run[draw_shapes]",
|
"name": "rake run[draw_shapes]",
|
||||||
"shell_cmd": "rake run[draw_shapes]",
|
"shell_cmd": "rake run[draw_shapes]",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "rake run[config_text_markup]",
|
||||||
|
"shell_cmd": "rake run[config_text_markup]",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "rspec spec/samples/samples_regression_spec.rb",
|
"name": "rspec spec/samples/samples_regression_spec.rb",
|
||||||
"shell_cmd": "rspec spec/samples/samples_regression_spec.rb",
|
"shell_cmd": "rspec spec/samples/samples_regression_spec.rb",
|
||||||
|
|
@ -39,6 +43,7 @@
|
||||||
"shell_cmd": "rspec spec/graphics/graphics_text_spec.rb",
|
"shell_cmd": "rspec spec/graphics/graphics_text_spec.rb",
|
||||||
"working_dir": "${project_path:${folder}}"
|
"working_dir": "${project_path:${folder}}"
|
||||||
},
|
},
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue