stringex 1.3.2 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +8 -3
- data/Rakefile +1 -1
- data/lib/stringex.rb +3 -4
- data/lib/stringex/acts_as_url.rb +9 -5
- data/lib/stringex/string_extensions.rb +34 -7
- data/stringex.gemspec +2 -2
- data/test/acts_as_url_test.rb +14 -0
- data/test/string_extensions_test.rb +59 -2
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -14,11 +14,16 @@ which will populate the <tt>url</tt> attribute on the object with the converted
|
|
14
14
|
<tt>:url_attribute</tt>:: The name of the attribute to use for storing the generated url string.
|
15
15
|
Default is <tt>:url</tt>
|
16
16
|
<tt>:scope</tt>:: The name of model attribute to scope unique urls to. There is no default here.
|
17
|
-
<tt>:only_when_blank</tt>:: If true, the url generation will only happen when <tt>:url_attribute</tt> is
|
18
|
-
blank. Default is false (meaning url generation will happen always)
|
17
|
+
<tt>:only_when_blank</tt>:: If set to true, the url generation will only happen when <tt>:url_attribute</tt> is
|
18
|
+
blank. Default is false (meaning url generation will happen always).
|
19
19
|
<tt>:sync_url</tt>:: If set to true, the url field will be updated when changes are made to the
|
20
20
|
attribute it is based on. Default is false.
|
21
21
|
<tt>:allow_slash</tt>:: If set to true, the url field will not convert slashes. Default is false.
|
22
|
+
<tt>:allow_duplicates</tt>:: If set to true, unique urls will not be enforced.
|
23
|
+
Default is false. <em>NOTE: This is strongly not recommended
|
24
|
+
if you are routing solely on the generated slug as you will no longer
|
25
|
+
be guaranteed to lookup the expected record based on a duplicate slug.</em>
|
26
|
+
|
22
27
|
|
23
28
|
In order to use the generated url attribute, you will probably want to override <tt>to_param</tt> like so, in your Model:
|
24
29
|
|
@@ -29,7 +34,7 @@ In order to use the generated url attribute, you will probably want to override
|
|
29
34
|
|
30
35
|
Routing called via named routes like <tt>foo_path(@foo)</tt> will automatically use the url. In your controllers you will need to call <tt>Foo.find_by_url(params[:id])</tt> instead of the regular find. Don't look for <tt>params[:url]</tt> unless you set it explicitly in the routing, <tt>to_param</tt> will generate <tt>params[:id]</tt>.
|
31
36
|
|
32
|
-
Note that if you add <tt>acts_as_url</tt> to an old model, the <tt>url</tt> database column will inititally be blank. To set this column for your old instances, you can use the <tt>initialize_urls</tt> method. So if your class is <tt>Post</tt>, just say <tt>Post.
|
37
|
+
Note that if you add <tt>acts_as_url</tt> to an old model, the <tt>url</tt> database column will inititally be blank. To set this column for your old instances, you can use the <tt>initialize_urls</tt> method. So if your class is <tt>Post</tt>, just say <tt>Post.initialize_urls</tt>.
|
33
38
|
|
34
39
|
Unlike other permalink solutions, ActsAsUrl doesn't rely on Iconv (which is inconsistent across platforms and doesn't provide great transliteration as is) but instead uses a transliteration scheme (see the code for Unidecoder) which produces much better results for Unicode characters. It also mixes in some custom helpers to translate common characters into a more URI-friendly format rather than just dump them completely. Examples:
|
35
40
|
|
data/Rakefile
CHANGED
data/lib/stringex.rb
CHANGED
@@ -4,7 +4,6 @@ require 'stringex/unidecoder'
|
|
4
4
|
|
5
5
|
String.send :include, Stringex::StringExtensions
|
6
6
|
|
7
|
-
if defined?(ActiveRecord)
|
8
|
-
|
9
|
-
|
10
|
-
end
|
7
|
+
require 'stringex/acts_as_url' if defined?(ActiveRecord) || defined?(Mongoid::Document)
|
8
|
+
|
9
|
+
ActiveRecord::Base.send :include, Stringex::ActsAsUrl if defined?(ActiveRecord)
|
data/lib/stringex/acts_as_url.rb
CHANGED
@@ -33,6 +33,7 @@ module Stringex
|
|
33
33
|
cattr_accessor :only_when_blank
|
34
34
|
cattr_accessor :duplicate_count_separator
|
35
35
|
cattr_accessor :allow_slash
|
36
|
+
cattr_accessor :allow_duplicates
|
36
37
|
|
37
38
|
if options[:sync_url]
|
38
39
|
before_validation(:ensure_unique_url)
|
@@ -50,6 +51,7 @@ module Stringex
|
|
50
51
|
self.only_when_blank = options[:only_when_blank] || false
|
51
52
|
self.duplicate_count_separator = options[:duplicate_count_separator] || "-"
|
52
53
|
self.allow_slash = options[:allow_slash] || false
|
54
|
+
self.allow_duplicates = options[:allow_duplicates] || false
|
53
55
|
|
54
56
|
class_eval <<-"END"
|
55
57
|
def #{url_attribute}
|
@@ -95,12 +97,14 @@ module Stringex
|
|
95
97
|
end
|
96
98
|
url_owners = self.class.find(:all, :conditions => conditions)
|
97
99
|
write_attribute url_attribute, base_url
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
100
|
+
unless self.class.allow_duplicates
|
101
|
+
if url_owners.any?{|owner| owner.send(url_attribute) == base_url}
|
102
|
+
n = 1
|
103
|
+
while url_owners.any?{|owner| owner.send(url_attribute) == "#{base_url}#{separator}#{n}"}
|
104
|
+
n = n.succ
|
105
|
+
end
|
106
|
+
write_attribute url_attribute, "#{base_url}#{separator}#{n}"
|
102
107
|
end
|
103
|
-
write_attribute url_attribute, "#{base_url}#{separator}#{n}"
|
104
108
|
end
|
105
109
|
end
|
106
110
|
end
|
@@ -42,7 +42,7 @@ module Stringex
|
|
42
42
|
# Performs multiple text manipulations. Essentially a shortcut for typing them all. View source
|
43
43
|
# below to see which methods are run.
|
44
44
|
def remove_formatting(options = {})
|
45
|
-
strip_html_tags.convert_smart_punctuation.convert_accented_entities.convert_misc_entities.convert_misc_characters(options).to_ascii.collapse
|
45
|
+
strip_html_tags.convert_smart_punctuation.convert_accented_entities.convert_vulgar_fractions.convert_misc_entities.convert_misc_characters(options).to_ascii.collapse
|
46
46
|
end
|
47
47
|
|
48
48
|
# Removes HTML tags from text. This code is simplified from Tobias Luettke's regular expression
|
@@ -67,7 +67,7 @@ module Stringex
|
|
67
67
|
# Note: This does not do any conversion of Unicode/ASCII accented-characters. For that
|
68
68
|
# functionality please use <tt>to_ascii</tt>.
|
69
69
|
def convert_accented_entities
|
70
|
-
gsub(/&([A-Za-z])(grave|acute|circ|tilde|uml|ring|cedil|slash);/, '\1')
|
70
|
+
gsub(/&([A-Za-z])(grave|acute|circ|tilde|uml|ring|cedil|slash);/, '\1').strip
|
71
71
|
end
|
72
72
|
|
73
73
|
# Converts HTML entities (taken from common Textile/RedCloth formattings) into plain text formats.
|
@@ -95,11 +95,37 @@ module Stringex
|
|
95
95
|
"(#188|frac14)" => "one fourth",
|
96
96
|
"(#189|frac12)" => "half",
|
97
97
|
"(#190|frac34)" => "three fourths",
|
98
|
-
"(#176|deg)" => " degrees"
|
98
|
+
"(#176|deg)" => " degrees "
|
99
99
|
}.each do |textiled, normal|
|
100
100
|
dummy.gsub!(/&#{textiled};/, normal)
|
101
101
|
end
|
102
|
-
dummy.gsub(/&[^;]+;/, "")
|
102
|
+
dummy.gsub(/&[^;]+;/, "").strip
|
103
|
+
end
|
104
|
+
|
105
|
+
# Converts vulgar fractions from supported html entities and unicode to
|
106
|
+
# plain text formats.
|
107
|
+
def convert_vulgar_fractions
|
108
|
+
dummy = dup
|
109
|
+
{
|
110
|
+
"(¼|¼|¼)" => "one fourth",
|
111
|
+
"(½|½|½)" => "half",
|
112
|
+
"(¾|¾|¾)" => "three fourths",
|
113
|
+
"(⅓|⅓)" => "one third",
|
114
|
+
"(⅔|⅔)" => "two thirds",
|
115
|
+
"(⅕|⅕)" => "one fifth",
|
116
|
+
"(⅖|⅖)" => "two fifths",
|
117
|
+
"(⅗|⅗)" => "three fifths",
|
118
|
+
"(⅘|⅘)" => "four fifths",
|
119
|
+
"(⅙|⅙)" => "one sixth",
|
120
|
+
"(⅚|⅚)" => "five sixths",
|
121
|
+
"(⅛|⅛)" => "one eighth",
|
122
|
+
"(⅜|⅜)" => "three eighths",
|
123
|
+
"(⅝|⅝)" => "five eighths",
|
124
|
+
"(⅞|⅞)" => "seven eighths"
|
125
|
+
}.each do |textiled, normal|
|
126
|
+
dummy.gsub!(/#{textiled}/, normal)
|
127
|
+
end
|
128
|
+
dummy
|
103
129
|
end
|
104
130
|
|
105
131
|
# Converts MS Word 'smart punctuation' to ASCII
|
@@ -114,7 +140,7 @@ module Stringex
|
|
114
140
|
}.each do |smart, normal|
|
115
141
|
dummy.gsub!(/#{smart}/, normal)
|
116
142
|
end
|
117
|
-
dummy
|
143
|
+
dummy.strip
|
118
144
|
end
|
119
145
|
|
120
146
|
# Converts various common plaintext characters to a more URI-friendly representation.
|
@@ -155,14 +181,15 @@ module Stringex
|
|
155
181
|
/\s*\*\s*/ => "star",
|
156
182
|
/\s*%\s*/ => "percent",
|
157
183
|
/(\s*=\s*)/ => " equals ",
|
158
|
-
/\s*\+\s*/ => "plus"
|
184
|
+
/\s*\+\s*/ => "plus",
|
185
|
+
/\s*°\s*/ => "degrees"
|
159
186
|
}
|
160
187
|
misc_characters[/\s*(\\|\/)\s*/] = 'slash' unless options[:allow_slash]
|
161
188
|
misc_characters.each do |found, replaced|
|
162
189
|
replaced = " #{replaced} " unless replaced =~ /\\1/
|
163
190
|
dummy.gsub!(found, replaced)
|
164
191
|
end
|
165
|
-
dummy = dummy.gsub(/(
|
192
|
+
dummy = dummy.gsub(/(^|[[:alpha:]])'([[:alpha:]]|$)/, '\1\2').gsub(/[\.,:;()\[\]\/\?!\^'ʼ"_]/, " ").strip
|
166
193
|
end
|
167
194
|
|
168
195
|
# Replace runs of whitespace in string. Defaults to a single space but any replacement
|
data/stringex.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{stringex}
|
8
|
-
s.version = "1.3.
|
8
|
+
s.version = "1.3.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Russell Norris"]
|
12
|
-
s.date = %q{2012-
|
12
|
+
s.date = %q{2012-04-24}
|
13
13
|
s.description = %q{Some [hopefully] useful extensions to Ruby's String class. Stringex is made up of three libraries: ActsAsUrl [permalink solution with better character translation], Unidecoder [Unicode to ASCII transliteration], and StringExtensions [miscellaneous helper methods for the String class].}
|
14
14
|
s.email = %q{rsl@luckysneaks.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/acts_as_url_test.rb
CHANGED
@@ -49,6 +49,10 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
49
49
|
create_table :validatuments, :force => true do |t|
|
50
50
|
t.string :title, :url, :other
|
51
51
|
end
|
52
|
+
|
53
|
+
create_table :ununiquments, :force => true do |t|
|
54
|
+
t.string :title, :url, :other
|
55
|
+
end
|
52
56
|
end
|
53
57
|
ActiveRecord::Migration.verbose = true
|
54
58
|
|
@@ -89,6 +93,10 @@ class Validatument < ActiveRecord::Base
|
|
89
93
|
validates_presence_of :title
|
90
94
|
end
|
91
95
|
|
96
|
+
class Ununiqument < ActiveRecord::Base
|
97
|
+
acts_as_url :title, :allow_duplicates => true
|
98
|
+
end
|
99
|
+
|
92
100
|
class ActsAsUrlTest < Test::Unit::TestCase
|
93
101
|
def test_should_create_url
|
94
102
|
@doc = Document.create(:title => "Let's Make a Test Title, <em>Okay</em>?")
|
@@ -100,6 +108,12 @@ class ActsAsUrlTest < Test::Unit::TestCase
|
|
100
108
|
@other_doc = Document.create!(:title => "Unique")
|
101
109
|
assert_equal "unique-1", @other_doc.url
|
102
110
|
end
|
111
|
+
|
112
|
+
def test_should_not_create_unique_url
|
113
|
+
@doc = Ununiqument.create!(:title => "I am not a clone")
|
114
|
+
@other_doc = Ununiqument.create!(:title => "I am not a clone")
|
115
|
+
assert_equal "i-am-not-a-clone", @other_doc.url
|
116
|
+
end
|
103
117
|
|
104
118
|
def test_should_not_succ_on_repeated_saves
|
105
119
|
@doc = Document.new(:title => "Continuous or Constant")
|
@@ -49,8 +49,26 @@ class StringExtensionsTest < Test::Unit::TestCase
|
|
49
49
|
"im-just-making-sure-theres-nothing-wrong-with-things",
|
50
50
|
"foo = bar and bar=foo" =>
|
51
51
|
"foo-equals-bar-and-bar-equals-foo",
|
52
|
+
"Period.period" =>
|
53
|
+
"period-dot-period",
|
52
54
|
"Will…This Work?" =>
|
53
|
-
"will-dot-dot-dot-this-work"
|
55
|
+
"will-dot-dot-dot-this-work",
|
56
|
+
"¼ pound with cheese" =>
|
57
|
+
"one-fourth-pound-with-cheese",
|
58
|
+
"Will's Ferrel" =>
|
59
|
+
"wills-ferrel",
|
60
|
+
"Капитал" =>
|
61
|
+
"kapital",
|
62
|
+
"Ελλάδα" =>
|
63
|
+
"ellada",
|
64
|
+
"中文" =>
|
65
|
+
"zhong-wen",
|
66
|
+
"Paul Cézanne" =>
|
67
|
+
"paul-cezanne",
|
68
|
+
"21'17ʼ51" =>
|
69
|
+
"21-17-51",
|
70
|
+
"ITCZ 1 (21°17ʼ51.78”N / 89°35ʼ28.18”O / 26-04-08 / 09:00 am)" =>
|
71
|
+
"itcz-1-21-degrees-17-51-dot-78-n-slash-89-degrees-35-28-dot-18-o-slash-26-04-08-slash-09-00-am"
|
54
72
|
}.each do |html, plain|
|
55
73
|
assert_equal plain, html.to_url
|
56
74
|
end
|
@@ -95,6 +113,46 @@ class StringExtensionsTest < Test::Unit::TestCase
|
|
95
113
|
end
|
96
114
|
end
|
97
115
|
|
116
|
+
def test_convert_vulgar_fractions
|
117
|
+
{
|
118
|
+
"¼" => "one fourth",
|
119
|
+
"¼" => "one fourth",
|
120
|
+
"¼" => "one fourth",
|
121
|
+
"½" => "half",
|
122
|
+
"½" => "half",
|
123
|
+
"½" => "half",
|
124
|
+
"¾" => "three fourths",
|
125
|
+
"¾" => "three fourths",
|
126
|
+
"¾" => "three fourths",
|
127
|
+
"⅓" => "one third",
|
128
|
+
"⅓" => "one third",
|
129
|
+
"⅔" => "two thirds",
|
130
|
+
"⅔" => "two thirds",
|
131
|
+
"⅕" => "one fifth",
|
132
|
+
"⅕" => "one fifth",
|
133
|
+
"⅖" => "two fifths",
|
134
|
+
"⅖" => "two fifths",
|
135
|
+
"⅗" => "three fifths",
|
136
|
+
"⅗" => "three fifths",
|
137
|
+
"⅘" => "four fifths",
|
138
|
+
"⅘" => "four fifths",
|
139
|
+
"⅙" => "one sixth",
|
140
|
+
"⅙" => "one sixth",
|
141
|
+
"⅚" => "five sixths",
|
142
|
+
"⅚" => "five sixths",
|
143
|
+
"⅛" => "one eighth",
|
144
|
+
"⅛" => "one eighth",
|
145
|
+
"⅜" => "three eighths",
|
146
|
+
"⅜" => "three eighths",
|
147
|
+
"⅝" => "five eighths",
|
148
|
+
"⅝" => "five eighths",
|
149
|
+
"⅞" => "seven eighths",
|
150
|
+
"⅞" => "seven eighths"
|
151
|
+
}.each do |entitied, plain|
|
152
|
+
assert_equal plain, entitied.convert_vulgar_fractions
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
98
156
|
def test_convert_misc_entities
|
99
157
|
{
|
100
158
|
"America™" => "America(tm)",
|
@@ -102,7 +160,6 @@ class StringExtensionsTest < Test::Unit::TestCase
|
|
102
160
|
"To be continued…" => "To be continued...",
|
103
161
|
"Foo Bar" => "Foo Bar",
|
104
162
|
"100£" => "100 pound",
|
105
|
-
"½ a dollar" => "half a dollar",
|
106
163
|
"35°" => "35 degrees"
|
107
164
|
}.each do |entitied, plain|
|
108
165
|
assert_equal plain, entitied.convert_misc_entities
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stringex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 3
|
10
|
+
version: 1.3.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Russell Norris
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-04-24 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|