Browse Source

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 #50
dev
Andy Meneely 11 years ago
parent
commit
063d5156d6
  1. 26
      README.md
  2. 76
      lib/squib/args/typographer.rb
  3. 8
      lib/squib/constants.rb
  4. 7
      lib/squib/deck.rb
  5. 2
      lib/squib/graphics/text.rb
  6. 13
      lib/squib/project_template/config.yml
  7. 3
      samples/config_disable_quotes.yml
  8. 15
      samples/config_text_markup.rb
  9. 8
      samples/config_text_markup.yml
  10. 4
      spec/args/typographer_spec.rb
  11. 52
      spec/data/samples/config_text_markup.rb.txt
  12. 1
      spec/samples/samples_regression_spec.rb
  13. 5
      squib.sublime-project

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.

76
lib/squib/args/typographer.rb

@ -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 end
# Quote next to non-whitespace curls # Straightforward replace
def right_double_quote(str) def ellipsificate(str)
str.gsub(/(\S)(\")/, '\1' + "\u201D") str.gsub('...', @config['ellipsis'])
end end
# Quote next to non-whitespace curls # Straightforward replace
def left_double_quote(str) def en_dash(str)
str.gsub(/(\")(\S)/, "\u201C" + '\2') str.gsub('--', @config['en_dash'])
end
# Straightforward replace
def em_dash(str)
str.gsub('---', @config['em_dash'])
end end
# Quote next to non-whitespace curls # Quote next to non-whitespace curls
def right_single_quote(str) def right_double_quote(str)
str.gsub(/(\S)(\')/, '\1' + "\u2019") str.gsub(/(\S)(\")/, '\1' + @config['rdquote'])
end end
# Quote next to non-whitespace curls # Quote next to non-whitespace curls
def left_single_quote(str) def left_double_quote(str)
str.gsub(/(\')(\S)/, "\u2018" + '\2') str.gsub(/(\")(\S)/, @config['ldquote'] + '\2')
end end
# Straightforward replace # Handle the cases where a double quote is next to a single quote
def ellipsificate(str) def single_inside_double_quote(str)
str.gsub('...', "\u2026") str.gsub(/(\")(\')(\S)/, @config['ldquote'] + @config['lsquote'] + '\3')
.gsub(/(\")(\')(\S)/, '\1' + @config['rsquote'] + @config['rdquote'])
end end
# Straightforward replace # Quote next to non-whitespace curls
def en_dash(str) def right_single_quote(str)
str.gsub('--', "\u2013") str.gsub(/(\S)(\')/, '\1' + @config['rsquote'])
end end
# Straightforward replace # Quote next to non-whitespace curls
def em_dash(str) def left_single_quote(str)
str.gsub('---', "\u2014") str.gsub(/(\')(\S)/, @config['lsquote'] + '\2')
end end
end end

8
lib/squib/constants.rb

@ -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.

7
lib/squib/deck.rb

@ -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

2
lib/squib/graphics/text.rb

@ -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

13
lib/squib/project_template/config.yml

@ -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

3
samples/config_disable_quotes.yml

@ -0,0 +1,3 @@
# If we want to disable smart quoting and only allow explicit quoting within markup,
# use this option
smart_quotes: false

15
samples/config_text_markup.rb

@ -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

8
samples/config_text_markup.yml

@ -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"

4
spec/args/typographer_spec.rb

@ -44,8 +44,8 @@ describe Squib::Args::Typographer do
expect(t.process(%{can't})).to eq(%{can\u2019t}) expect(t.process(%{can't})).to eq(%{can\u2019t})
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

52
spec/data/samples/config_text_markup.rb.txt

@ -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"])

1
spec/samples/samples_regression_spec.rb

@ -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

5
squib.sublime-project vendored

@ -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…
Cancel
Save