stringex 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
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