11 changed files with 259 additions and 95 deletions
@ -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,46 +0,0 @@
|
||||
require 'spec_helper' |
||||
require 'squib/args/smart_quotes' |
||||
|
||||
describe Squib::Args::SmartQuotes do |
||||
|
||||
it 'does nothing on a non-quoted string' do |
||||
expect(subject.quotify('nothing')).to eq('nothing') |
||||
end |
||||
|
||||
it 'left quotes at the beginning' do |
||||
expect(subject.quotify('"foo')).to eq("\u201Cfoo") |
||||
end |
||||
|
||||
it 'left quotes in the middle of the string' do |
||||
expect(subject.quotify('hello "foo')).to eq("hello \u201Cfoo") |
||||
end |
||||
|
||||
it 'right quotes at the end of a string' do |
||||
expect(subject.quotify('foo"')).to eq("foo\u201D") |
||||
end |
||||
|
||||
it 'handles the entire string quoted' do |
||||
expect(subject.quotify('"foo"')).to eq("\u201Cfoo\u201D") |
||||
end |
||||
|
||||
it "quotes in the middle of the string" do |
||||
expect(subject.quotify('hello "foo" world')).to eq("hello \u201Cfoo\u201D world") |
||||
end |
||||
|
||||
it "allows custom quotes for different character sets" do |
||||
expect(subject.quotify('hello "foo" world', %w({ }))).to eq("hello {foo} world") |
||||
end |
||||
|
||||
it "processes dumb quotes" do |
||||
expect(subject.process('hello "foo" world', :dumb)).to eq("hello \"foo\" world") |
||||
end |
||||
|
||||
it "processes smart quotes" do |
||||
expect(subject.process('hello "foo" world', :smart)).to eq("hello \u201Cfoo\u201D world") |
||||
end |
||||
|
||||
it "processes custom quotes" do |
||||
expect(subject.process('hello "foo" world', %w({ }))).to eq("hello {foo} world") |
||||
end |
||||
|
||||
end |
||||
@ -0,0 +1,71 @@
|
||||
require 'spec_helper' |
||||
require 'squib/args/typographer' |
||||
|
||||
describe Squib::Args::Typographer do |
||||
subject(:t) { Squib::Args::Typographer.new } |
||||
|
||||
it 'does nothing on a non-quoted string' do |
||||
expect(t.process(%{nothing})).to eq(%{nothing}) |
||||
end |
||||
|
||||
it 'left quotes at the beginning' do |
||||
expect(t.process(%{"foo})).to eq(%{\u201Cfoo}) |
||||
end |
||||
|
||||
it 'left quotes in the middle of the string' do |
||||
expect(t.process(%{hello "foo})).to eq(%{hello \u201Cfoo}) |
||||
end |
||||
|
||||
it 'right quotes at the end' do |
||||
expect(t.process(%{foo"})).to eq(%{foo\u201D}) |
||||
end |
||||
|
||||
it 'handles the entire string quoted' do |
||||
expect(t.process(%{"foo"})).to eq(%{\u201Cfoo\u201D}) |
||||
end |
||||
|
||||
it "quotes in the middle of the string" do |
||||
expect(t.process(%{hello "foo" world})).to eq(%{hello \u201Cfoo\u201D world}) |
||||
end |
||||
|
||||
it "single left quotes at the beginning" do |
||||
expect(t.process(%{'foo})).to eq(%{\u2018foo}) |
||||
end |
||||
|
||||
it "single right quotes at the end" do |
||||
expect(t.process(%{foo'})).to eq(%{foo\u2019}) |
||||
end |
||||
|
||||
it "single quotes in the middle" do |
||||
expect(t.process(%{a 'foo' bar})).to eq(%{a \u2018foo\u2019 bar}) |
||||
end |
||||
|
||||
it "handles apostraphes" do |
||||
expect(t.process(%{can't})).to eq(%{can\u2019t}) |
||||
end |
||||
|
||||
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}) |
||||
end |
||||
|
||||
it "replaces the straightforward ones" do |
||||
expect(t.process(%{``hi...'' -- ---})).to eq(%{\u201Chi\u2026\u201D \u2013 \u2014}) |
||||
end |
||||
|
||||
it "does nothing on lone quotes" do |
||||
expect(t.process(%{"})).to eq(%{"}) |
||||
expect(t.process(%{'})).to eq(%{'}) |
||||
end |
||||
|
||||
it "ignores stuff in <tags>" do |
||||
expect(t.process(%{<span weight="bold">"can't"</span>})).to eq(%{<span weight="bold">\u201Ccan\u2019t\u201D</span>}) |
||||
end |
||||
|
||||
|
||||
context 'configured' do |
||||
#TODO |
||||
end |
||||
|
||||
|
||||
|
||||
end |
||||
Loading…
Reference in new issue