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 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.all.each{|p| p.initialize_urls}</tt>.
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
@@ -212,7 +212,7 @@ begin
212
212
  }
213
213
  gem.rdoc_options = %w{--main README.rdoc --charset utf-8 --line-numbers}
214
214
  gem.extra_rdoc_files = %w{MIT-LICENSE README.rdoc}
215
- gem.version = "1.3.2"
215
+ gem.version = "1.3.3"
216
216
  end
217
217
 
218
218
  Jeweler::GemcutterTasks.new
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
- require 'stringex/acts_as_url'
9
- ActiveRecord::Base.send :include, Stringex::ActsAsUrl
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)
@@ -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
- if url_owners.any?{|owner| owner.send(url_attribute) == base_url}
99
- n = 1
100
- while url_owners.any?{|owner| owner.send(url_attribute) == "#{base_url}#{separator}#{n}"}
101
- n = n.succ
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
+ "(&#188;|&frac14;|¼)" => "one fourth",
111
+ "(&#189;|&frac12;|½)" => "half",
112
+ "(&#190;|&frac34;|¾)" => "three fourths",
113
+ "(&#8531;|⅓)" => "one third",
114
+ "(&#8532;|⅔)" => "two thirds",
115
+ "(&#8533;|⅕)" => "one fifth",
116
+ "(&#8534;|⅖)" => "two fifths",
117
+ "(&#8535;|⅗)" => "three fifths",
118
+ "(&#8536;|⅘)" => "four fifths",
119
+ "(&#8537;|⅙)" => "one sixth",
120
+ "(&#8538;|⅚)" => "five sixths",
121
+ "(&#8539;|⅛)" => "one eighth",
122
+ "(&#8540;|⅜)" => "three eighths",
123
+ "(&#8541;|⅝)" => "five eighths",
124
+ "(&#8542;|⅞)" => "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(/(^|\w)'(\w|$)/, '\1\2').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.2"
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-02-16}
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 = [
@@ -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
+ "&frac14;" => "one fourth",
119
+ "¼" => "one fourth",
120
+ "&#188;" => "one fourth",
121
+ "&frac12;" => "half",
122
+ "½" => "half",
123
+ "&#189;" => "half",
124
+ "&frac34;" => "three fourths",
125
+ "¾" => "three fourths",
126
+ "&#190;" => "three fourths",
127
+ "⅓" => "one third",
128
+ "&#8531;" => "one third",
129
+ "⅔" => "two thirds",
130
+ "&#8532;" => "two thirds",
131
+ "⅕" => "one fifth",
132
+ "&#8533;" => "one fifth",
133
+ "⅖" => "two fifths",
134
+ "&#8534;" => "two fifths",
135
+ "⅗" => "three fifths",
136
+ "&#8535;" => "three fifths",
137
+ "⅘" => "four fifths",
138
+ "&#8536;" => "four fifths",
139
+ "⅙" => "one sixth",
140
+ "&#8537;" => "one sixth",
141
+ "⅚" => "five sixths",
142
+ "&#8538;" => "five sixths",
143
+ "⅛" => "one eighth",
144
+ "&#8539;" => "one eighth",
145
+ "⅜" => "three eighths",
146
+ "&#8540;" => "three eighths",
147
+ "⅝" => "five eighths",
148
+ "&#8541;" => "five eighths",
149
+ "⅞" => "seven eighths",
150
+ "&#8542;" => "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&#8482;" => "America(tm)",
@@ -102,7 +160,6 @@ class StringExtensionsTest < Test::Unit::TestCase
102
160
  "To be continued&#8230;" => "To be continued...",
103
161
  "Foo&nbsp;Bar" => "Foo Bar",
104
162
  "100&#163;" => "100 pound",
105
- "&frac12; a dollar" => "half a dollar",
106
163
  "35&deg;" => "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: 31
4
+ hash: 29
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 2
10
- version: 1.3.2
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-02-16 00:00:00 -05:00
18
+ date: 2012-04-24 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies: []
21
21