stringex 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +76 -0
  3. data/Rakefile +250 -0
  4. data/init.rb +1 -0
  5. data/lib/lucky_sneaks/acts_as_url.rb +88 -0
  6. data/lib/lucky_sneaks/string_extensions.rb +177 -0
  7. data/lib/lucky_sneaks/unidecoder.rb +61 -0
  8. data/lib/lucky_sneaks/unidecoder_data/x00.yml +257 -0
  9. data/lib/lucky_sneaks/unidecoder_data/x01.yml +257 -0
  10. data/lib/lucky_sneaks/unidecoder_data/x02.yml +256 -0
  11. data/lib/lucky_sneaks/unidecoder_data/x03.yml +256 -0
  12. data/lib/lucky_sneaks/unidecoder_data/x04.yml +256 -0
  13. data/lib/lucky_sneaks/unidecoder_data/x05.yml +256 -0
  14. data/lib/lucky_sneaks/unidecoder_data/x06.yml +256 -0
  15. data/lib/lucky_sneaks/unidecoder_data/x07.yml +256 -0
  16. data/lib/lucky_sneaks/unidecoder_data/x09.yml +256 -0
  17. data/lib/lucky_sneaks/unidecoder_data/x0a.yml +256 -0
  18. data/lib/lucky_sneaks/unidecoder_data/x0b.yml +256 -0
  19. data/lib/lucky_sneaks/unidecoder_data/x0c.yml +256 -0
  20. data/lib/lucky_sneaks/unidecoder_data/x0d.yml +256 -0
  21. data/lib/lucky_sneaks/unidecoder_data/x0e.yml +256 -0
  22. data/lib/lucky_sneaks/unidecoder_data/x0f.yml +256 -0
  23. data/lib/lucky_sneaks/unidecoder_data/x10.yml +256 -0
  24. data/lib/lucky_sneaks/unidecoder_data/x11.yml +256 -0
  25. data/lib/lucky_sneaks/unidecoder_data/x12.yml +257 -0
  26. data/lib/lucky_sneaks/unidecoder_data/x13.yml +256 -0
  27. data/lib/lucky_sneaks/unidecoder_data/x14.yml +257 -0
  28. data/lib/lucky_sneaks/unidecoder_data/x15.yml +257 -0
  29. data/lib/lucky_sneaks/unidecoder_data/x16.yml +256 -0
  30. data/lib/lucky_sneaks/unidecoder_data/x17.yml +256 -0
  31. data/lib/lucky_sneaks/unidecoder_data/x18.yml +256 -0
  32. data/lib/lucky_sneaks/unidecoder_data/x1e.yml +256 -0
  33. data/lib/lucky_sneaks/unidecoder_data/x1f.yml +256 -0
  34. data/lib/lucky_sneaks/unidecoder_data/x20.yml +256 -0
  35. data/lib/lucky_sneaks/unidecoder_data/x21.yml +256 -0
  36. data/lib/lucky_sneaks/unidecoder_data/x22.yml +256 -0
  37. data/lib/lucky_sneaks/unidecoder_data/x23.yml +256 -0
  38. data/lib/lucky_sneaks/unidecoder_data/x24.yml +256 -0
  39. data/lib/lucky_sneaks/unidecoder_data/x25.yml +256 -0
  40. data/lib/lucky_sneaks/unidecoder_data/x26.yml +256 -0
  41. data/lib/lucky_sneaks/unidecoder_data/x27.yml +256 -0
  42. data/lib/lucky_sneaks/unidecoder_data/x28.yml +257 -0
  43. data/lib/lucky_sneaks/unidecoder_data/x2e.yml +256 -0
  44. data/lib/lucky_sneaks/unidecoder_data/x2f.yml +256 -0
  45. data/lib/lucky_sneaks/unidecoder_data/x30.yml +256 -0
  46. data/lib/lucky_sneaks/unidecoder_data/x31.yml +256 -0
  47. data/lib/lucky_sneaks/unidecoder_data/x32.yml +256 -0
  48. data/lib/lucky_sneaks/unidecoder_data/x33.yml +256 -0
  49. data/lib/lucky_sneaks/unidecoder_data/x4d.yml +256 -0
  50. data/lib/lucky_sneaks/unidecoder_data/x4e.yml +257 -0
  51. data/lib/lucky_sneaks/unidecoder_data/x4f.yml +257 -0
  52. data/lib/lucky_sneaks/unidecoder_data/x50.yml +257 -0
  53. data/lib/lucky_sneaks/unidecoder_data/x51.yml +257 -0
  54. data/lib/lucky_sneaks/unidecoder_data/x52.yml +257 -0
  55. data/lib/lucky_sneaks/unidecoder_data/x53.yml +257 -0
  56. data/lib/lucky_sneaks/unidecoder_data/x54.yml +257 -0
  57. data/lib/lucky_sneaks/unidecoder_data/x55.yml +257 -0
  58. data/lib/lucky_sneaks/unidecoder_data/x56.yml +257 -0
  59. data/lib/lucky_sneaks/unidecoder_data/x57.yml +257 -0
  60. data/lib/lucky_sneaks/unidecoder_data/x58.yml +257 -0
  61. data/lib/lucky_sneaks/unidecoder_data/x59.yml +257 -0
  62. data/lib/lucky_sneaks/unidecoder_data/x5a.yml +257 -0
  63. data/lib/lucky_sneaks/unidecoder_data/x5b.yml +257 -0
  64. data/lib/lucky_sneaks/unidecoder_data/x5c.yml +257 -0
  65. data/lib/lucky_sneaks/unidecoder_data/x5d.yml +257 -0
  66. data/lib/lucky_sneaks/unidecoder_data/x5e.yml +257 -0
  67. data/lib/lucky_sneaks/unidecoder_data/x5f.yml +257 -0
  68. data/lib/lucky_sneaks/unidecoder_data/x60.yml +257 -0
  69. data/lib/lucky_sneaks/unidecoder_data/x61.yml +257 -0
  70. data/lib/lucky_sneaks/unidecoder_data/x62.yml +257 -0
  71. data/lib/lucky_sneaks/unidecoder_data/x63.yml +257 -0
  72. data/lib/lucky_sneaks/unidecoder_data/x64.yml +257 -0
  73. data/lib/lucky_sneaks/unidecoder_data/x65.yml +257 -0
  74. data/lib/lucky_sneaks/unidecoder_data/x66.yml +257 -0
  75. data/lib/lucky_sneaks/unidecoder_data/x67.yml +257 -0
  76. data/lib/lucky_sneaks/unidecoder_data/x68.yml +257 -0
  77. data/lib/lucky_sneaks/unidecoder_data/x69.yml +257 -0
  78. data/lib/lucky_sneaks/unidecoder_data/x6a.yml +257 -0
  79. data/lib/lucky_sneaks/unidecoder_data/x6b.yml +257 -0
  80. data/lib/lucky_sneaks/unidecoder_data/x6c.yml +257 -0
  81. data/lib/lucky_sneaks/unidecoder_data/x6d.yml +257 -0
  82. data/lib/lucky_sneaks/unidecoder_data/x6e.yml +257 -0
  83. data/lib/lucky_sneaks/unidecoder_data/x6f.yml +257 -0
  84. data/lib/lucky_sneaks/unidecoder_data/x70.yml +257 -0
  85. data/lib/lucky_sneaks/unidecoder_data/x71.yml +257 -0
  86. data/lib/lucky_sneaks/unidecoder_data/x72.yml +257 -0
  87. data/lib/lucky_sneaks/unidecoder_data/x73.yml +257 -0
  88. data/lib/lucky_sneaks/unidecoder_data/x74.yml +257 -0
  89. data/lib/lucky_sneaks/unidecoder_data/x75.yml +257 -0
  90. data/lib/lucky_sneaks/unidecoder_data/x76.yml +257 -0
  91. data/lib/lucky_sneaks/unidecoder_data/x77.yml +257 -0
  92. data/lib/lucky_sneaks/unidecoder_data/x78.yml +257 -0
  93. data/lib/lucky_sneaks/unidecoder_data/x79.yml +257 -0
  94. data/lib/lucky_sneaks/unidecoder_data/x7a.yml +257 -0
  95. data/lib/lucky_sneaks/unidecoder_data/x7b.yml +257 -0
  96. data/lib/lucky_sneaks/unidecoder_data/x7c.yml +257 -0
  97. data/lib/lucky_sneaks/unidecoder_data/x7d.yml +257 -0
  98. data/lib/lucky_sneaks/unidecoder_data/x7e.yml +257 -0
  99. data/lib/lucky_sneaks/unidecoder_data/x7f.yml +257 -0
  100. data/lib/lucky_sneaks/unidecoder_data/x80.yml +257 -0
  101. data/lib/lucky_sneaks/unidecoder_data/x81.yml +257 -0
  102. data/lib/lucky_sneaks/unidecoder_data/x82.yml +257 -0
  103. data/lib/lucky_sneaks/unidecoder_data/x83.yml +257 -0
  104. data/lib/lucky_sneaks/unidecoder_data/x84.yml +257 -0
  105. data/lib/lucky_sneaks/unidecoder_data/x85.yml +257 -0
  106. data/lib/lucky_sneaks/unidecoder_data/x86.yml +257 -0
  107. data/lib/lucky_sneaks/unidecoder_data/x87.yml +257 -0
  108. data/lib/lucky_sneaks/unidecoder_data/x88.yml +257 -0
  109. data/lib/lucky_sneaks/unidecoder_data/x89.yml +257 -0
  110. data/lib/lucky_sneaks/unidecoder_data/x8a.yml +257 -0
  111. data/lib/lucky_sneaks/unidecoder_data/x8b.yml +257 -0
  112. data/lib/lucky_sneaks/unidecoder_data/x8c.yml +257 -0
  113. data/lib/lucky_sneaks/unidecoder_data/x8d.yml +257 -0
  114. data/lib/lucky_sneaks/unidecoder_data/x8e.yml +257 -0
  115. data/lib/lucky_sneaks/unidecoder_data/x8f.yml +257 -0
  116. data/lib/lucky_sneaks/unidecoder_data/x90.yml +257 -0
  117. data/lib/lucky_sneaks/unidecoder_data/x91.yml +257 -0
  118. data/lib/lucky_sneaks/unidecoder_data/x92.yml +257 -0
  119. data/lib/lucky_sneaks/unidecoder_data/x93.yml +257 -0
  120. data/lib/lucky_sneaks/unidecoder_data/x94.yml +257 -0
  121. data/lib/lucky_sneaks/unidecoder_data/x95.yml +257 -0
  122. data/lib/lucky_sneaks/unidecoder_data/x96.yml +257 -0
  123. data/lib/lucky_sneaks/unidecoder_data/x97.yml +257 -0
  124. data/lib/lucky_sneaks/unidecoder_data/x98.yml +257 -0
  125. data/lib/lucky_sneaks/unidecoder_data/x99.yml +257 -0
  126. data/lib/lucky_sneaks/unidecoder_data/x9a.yml +257 -0
  127. data/lib/lucky_sneaks/unidecoder_data/x9b.yml +257 -0
  128. data/lib/lucky_sneaks/unidecoder_data/x9c.yml +257 -0
  129. data/lib/lucky_sneaks/unidecoder_data/x9d.yml +257 -0
  130. data/lib/lucky_sneaks/unidecoder_data/x9e.yml +257 -0
  131. data/lib/lucky_sneaks/unidecoder_data/x9f.yml +256 -0
  132. data/lib/lucky_sneaks/unidecoder_data/xa0.yml +257 -0
  133. data/lib/lucky_sneaks/unidecoder_data/xa1.yml +257 -0
  134. data/lib/lucky_sneaks/unidecoder_data/xa2.yml +257 -0
  135. data/lib/lucky_sneaks/unidecoder_data/xa3.yml +257 -0
  136. data/lib/lucky_sneaks/unidecoder_data/xa4.yml +256 -0
  137. data/lib/lucky_sneaks/unidecoder_data/xac.yml +257 -0
  138. data/lib/lucky_sneaks/unidecoder_data/xad.yml +257 -0
  139. data/lib/lucky_sneaks/unidecoder_data/xae.yml +257 -0
  140. data/lib/lucky_sneaks/unidecoder_data/xaf.yml +257 -0
  141. data/lib/lucky_sneaks/unidecoder_data/xb0.yml +257 -0
  142. data/lib/lucky_sneaks/unidecoder_data/xb1.yml +257 -0
  143. data/lib/lucky_sneaks/unidecoder_data/xb2.yml +257 -0
  144. data/lib/lucky_sneaks/unidecoder_data/xb3.yml +257 -0
  145. data/lib/lucky_sneaks/unidecoder_data/xb4.yml +257 -0
  146. data/lib/lucky_sneaks/unidecoder_data/xb5.yml +257 -0
  147. data/lib/lucky_sneaks/unidecoder_data/xb6.yml +257 -0
  148. data/lib/lucky_sneaks/unidecoder_data/xb7.yml +257 -0
  149. data/lib/lucky_sneaks/unidecoder_data/xb8.yml +257 -0
  150. data/lib/lucky_sneaks/unidecoder_data/xb9.yml +257 -0
  151. data/lib/lucky_sneaks/unidecoder_data/xba.yml +257 -0
  152. data/lib/lucky_sneaks/unidecoder_data/xbb.yml +257 -0
  153. data/lib/lucky_sneaks/unidecoder_data/xbc.yml +257 -0
  154. data/lib/lucky_sneaks/unidecoder_data/xbd.yml +257 -0
  155. data/lib/lucky_sneaks/unidecoder_data/xbe.yml +257 -0
  156. data/lib/lucky_sneaks/unidecoder_data/xbf.yml +257 -0
  157. data/lib/lucky_sneaks/unidecoder_data/xc0.yml +257 -0
  158. data/lib/lucky_sneaks/unidecoder_data/xc1.yml +257 -0
  159. data/lib/lucky_sneaks/unidecoder_data/xc2.yml +257 -0
  160. data/lib/lucky_sneaks/unidecoder_data/xc3.yml +257 -0
  161. data/lib/lucky_sneaks/unidecoder_data/xc4.yml +257 -0
  162. data/lib/lucky_sneaks/unidecoder_data/xc5.yml +257 -0
  163. data/lib/lucky_sneaks/unidecoder_data/xc6.yml +257 -0
  164. data/lib/lucky_sneaks/unidecoder_data/xc7.yml +257 -0
  165. data/lib/lucky_sneaks/unidecoder_data/xc8.yml +257 -0
  166. data/lib/lucky_sneaks/unidecoder_data/xc9.yml +257 -0
  167. data/lib/lucky_sneaks/unidecoder_data/xca.yml +257 -0
  168. data/lib/lucky_sneaks/unidecoder_data/xcb.yml +257 -0
  169. data/lib/lucky_sneaks/unidecoder_data/xcc.yml +257 -0
  170. data/lib/lucky_sneaks/unidecoder_data/xcd.yml +257 -0
  171. data/lib/lucky_sneaks/unidecoder_data/xce.yml +257 -0
  172. data/lib/lucky_sneaks/unidecoder_data/xcf.yml +257 -0
  173. data/lib/lucky_sneaks/unidecoder_data/xd0.yml +257 -0
  174. data/lib/lucky_sneaks/unidecoder_data/xd1.yml +257 -0
  175. data/lib/lucky_sneaks/unidecoder_data/xd2.yml +257 -0
  176. data/lib/lucky_sneaks/unidecoder_data/xd3.yml +257 -0
  177. data/lib/lucky_sneaks/unidecoder_data/xd4.yml +257 -0
  178. data/lib/lucky_sneaks/unidecoder_data/xd5.yml +257 -0
  179. data/lib/lucky_sneaks/unidecoder_data/xd6.yml +257 -0
  180. data/lib/lucky_sneaks/unidecoder_data/xd7.yml +256 -0
  181. data/lib/lucky_sneaks/unidecoder_data/xf9.yml +257 -0
  182. data/lib/lucky_sneaks/unidecoder_data/xfa.yml +256 -0
  183. data/lib/lucky_sneaks/unidecoder_data/xfb.yml +257 -0
  184. data/lib/lucky_sneaks/unidecoder_data/xfc.yml +257 -0
  185. data/lib/lucky_sneaks/unidecoder_data/xfd.yml +256 -0
  186. data/lib/lucky_sneaks/unidecoder_data/xfe.yml +257 -0
  187. data/lib/lucky_sneaks/unidecoder_data/xff.yml +257 -0
  188. data/lib/stringex.rb +9 -0
  189. data/stringex.gemspec +229 -0
  190. data/test/acts_as_url_test.rb +183 -0
  191. data/test/string_extensions_test.rb +142 -0
  192. data/test/unidecoder_test.rb +90 -0
  193. metadata +250 -0
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Lucky Sneaks
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,76 @@
1
+ = Stringex
2
+
3
+ Some [hopefully] useful extensions to Ruby's String class. It is made up of three libraries: ActsAsUrl, Unidecoder, and StringExtensions.
4
+
5
+ == ActsAsUrl
6
+
7
+ This library is designed to create URI-friendly representations of an attribute, for use in generating urls from your attributes. Basic usage is just calling the method:
8
+
9
+ acts_as_url :title
10
+
11
+ which will populate the <tt>url</tt> attribute on the object with the converted contents of the <tt>title</tt> attribute. This behavior can be customized by adding the following options to the arguments of the <tt>acts_as_url</tt> method:
12
+
13
+ <tt>:url_attribute</tt>:: The name of the attribute to use for storing the generated url string.
14
+ Default is <tt>:url</tt>
15
+ <tt>:scope</tt>:: The name of model attribute to scope unique urls to. There is no default here.
16
+ <tt>:only_when_blank</tt>:: If true, the url generation will only happen when <tt>:url_attribute</tt> is
17
+ blank. Default is false (meaning url generation will happen always)
18
+ <tt>:sync_url</tt>:: If set to true, the url field will be updated when changes are made to the
19
+ attribute it is based on. Default is false.
20
+
21
+ In order to use the generated url attribute, you will probably want to override <tt>to_param</tt> like so, in your Model:
22
+
23
+ def to_param
24
+ url # or whatever you set :url_attribute to
25
+ end
26
+
27
+ 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>.
28
+
29
+ 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:
30
+
31
+ # A simple prelude
32
+ "simple English".to_url => "simple-english"
33
+ "it's nothing at all".to_url => "its-nothing-at-all"
34
+ "rock & roll".to_url => "rock-and-roll"
35
+
36
+ # Let's show off
37
+ "$12 worth of Ruby power".to_url => "12-dollars-worth-of-ruby-power"
38
+ "10% off if you act now".to_url => "10-percent-off-if-you-act-now"
39
+
40
+ # You don't even wanna trust Iconv for this next part
41
+ "kick it en Français".to_url => "kick-it-en-francais"
42
+ "rock it Español style".to_url => "rock-it-espanol-style"
43
+ "tell your readers 你好".to_url => "tell-your-readers-ni-hao"
44
+
45
+ Compare those results with the ones produced on my Intel Mac by a leading permalink plugin:
46
+
47
+ "simple English" # => "simple-english"
48
+ "it's nothing at all" # => "it-s-nothing-at-all"
49
+ "rock & roll" # => "rock-roll"
50
+
51
+ "$12 worth of Ruby power" # => "12-worth-of-ruby-power"
52
+ "10% off if you act now" # => "10-off-if-you-act-now"
53
+
54
+ "kick it en Français" # => "kick-it-en-francais"
55
+ "rock it Español style" # => "rock-it-espan-ol-style"
56
+ "tell your readers 你好" # => "tell-your-readers"
57
+
58
+ Not so great, actually.
59
+
60
+ Note: No offense is intended to the author[s] of whatever plugins might produce such results. It's not your faults Iconv sucks.
61
+
62
+ == Unidecoder
63
+
64
+ This library converts Unicode [and accented Ascii] characters to their plain-text Ascii equivalents. This is a port of Perl's Unidecode and provides eminently superior and more reliable results than Iconv. (Seriously, Iconv... A plague on both your houses! [sic])
65
+
66
+ You probably won't ever need to run Unidecoder by itself. StringExtensions adds String#to_ascii which wraps all of Unidecoder's functionality. For anyone interested, details of the implementation can be read about in the original implementation of Text::Unidecode[http://interglacial.com/~sburke/tpj/as_html/tpj22.html]. Extensive examples can be found in the tests.
67
+
68
+ == StringExtensions
69
+
70
+ A collection of extensions on Ruby's String class. Please see the documentation for string_extensions module for more information. There's not much to explain about them really.
71
+
72
+ == Thanks & Acknowledgements
73
+
74
+ If it's not obvious, some of the code for ActsAsUrl is based on Rick Olsen's permalink_fu[http://svn.techno-weenie.net/projects/plugins/permalink_fu/] plugin. Unidecoder is a Ruby port of Sean Burke's Text::Unidecode[http://interglacial.com/~sburke/tpj/as_html/tpj22.html] module for Perl. And, finally, the bulk of strip_html_tags[link:classes/LuckySneaks/StringExtensions.html#M000005] in StringExtensions was stolen from Tobias Lütke's Regex in Typo[http://typosphere.org/].
75
+
76
+ copyright (c) 2008 Lucky Sneaks, released under the MIT license
@@ -0,0 +1,250 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "stringex"
9
+ gem.authors = ["Russell Norris"]
10
+ gem.email = "rsl@luckysneaks.com"
11
+ gem.homepage = "http://github.com/rsl/stringex"
12
+ gem.rubyforge_project = "stringex"
13
+ gem.summary = "Some [hopefully] useful extensions to Ruby’s String class"
14
+ gem.description = "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]."
15
+ gem.has_rdoc = true
16
+ gem.files = %w{
17
+ init.rb
18
+ MIT-LICENSE
19
+ Rakefile
20
+ README.rdoc
21
+ stringex.gemspec
22
+ lib/stringex.rb
23
+ lib/lucky_sneaks/acts_as_url.rb
24
+ lib/lucky_sneaks/string_extensions.rb
25
+ lib/lucky_sneaks/unidecoder.rb
26
+ lib/lucky_sneaks/unidecoder_data/x00.yml
27
+ lib/lucky_sneaks/unidecoder_data/x01.yml
28
+ lib/lucky_sneaks/unidecoder_data/x02.yml
29
+ lib/lucky_sneaks/unidecoder_data/x03.yml
30
+ lib/lucky_sneaks/unidecoder_data/x04.yml
31
+ lib/lucky_sneaks/unidecoder_data/x05.yml
32
+ lib/lucky_sneaks/unidecoder_data/x06.yml
33
+ lib/lucky_sneaks/unidecoder_data/x07.yml
34
+ lib/lucky_sneaks/unidecoder_data/x09.yml
35
+ lib/lucky_sneaks/unidecoder_data/x0a.yml
36
+ lib/lucky_sneaks/unidecoder_data/x0b.yml
37
+ lib/lucky_sneaks/unidecoder_data/x0c.yml
38
+ lib/lucky_sneaks/unidecoder_data/x0d.yml
39
+ lib/lucky_sneaks/unidecoder_data/x0e.yml
40
+ lib/lucky_sneaks/unidecoder_data/x0f.yml
41
+ lib/lucky_sneaks/unidecoder_data/x10.yml
42
+ lib/lucky_sneaks/unidecoder_data/x11.yml
43
+ lib/lucky_sneaks/unidecoder_data/x12.yml
44
+ lib/lucky_sneaks/unidecoder_data/x13.yml
45
+ lib/lucky_sneaks/unidecoder_data/x14.yml
46
+ lib/lucky_sneaks/unidecoder_data/x15.yml
47
+ lib/lucky_sneaks/unidecoder_data/x16.yml
48
+ lib/lucky_sneaks/unidecoder_data/x17.yml
49
+ lib/lucky_sneaks/unidecoder_data/x18.yml
50
+ lib/lucky_sneaks/unidecoder_data/x1e.yml
51
+ lib/lucky_sneaks/unidecoder_data/x1f.yml
52
+ lib/lucky_sneaks/unidecoder_data/x20.yml
53
+ lib/lucky_sneaks/unidecoder_data/x21.yml
54
+ lib/lucky_sneaks/unidecoder_data/x22.yml
55
+ lib/lucky_sneaks/unidecoder_data/x23.yml
56
+ lib/lucky_sneaks/unidecoder_data/x24.yml
57
+ lib/lucky_sneaks/unidecoder_data/x25.yml
58
+ lib/lucky_sneaks/unidecoder_data/x26.yml
59
+ lib/lucky_sneaks/unidecoder_data/x27.yml
60
+ lib/lucky_sneaks/unidecoder_data/x28.yml
61
+ lib/lucky_sneaks/unidecoder_data/x2e.yml
62
+ lib/lucky_sneaks/unidecoder_data/x2f.yml
63
+ lib/lucky_sneaks/unidecoder_data/x30.yml
64
+ lib/lucky_sneaks/unidecoder_data/x31.yml
65
+ lib/lucky_sneaks/unidecoder_data/x32.yml
66
+ lib/lucky_sneaks/unidecoder_data/x33.yml
67
+ lib/lucky_sneaks/unidecoder_data/x4d.yml
68
+ lib/lucky_sneaks/unidecoder_data/x4e.yml
69
+ lib/lucky_sneaks/unidecoder_data/x4f.yml
70
+ lib/lucky_sneaks/unidecoder_data/x50.yml
71
+ lib/lucky_sneaks/unidecoder_data/x51.yml
72
+ lib/lucky_sneaks/unidecoder_data/x52.yml
73
+ lib/lucky_sneaks/unidecoder_data/x53.yml
74
+ lib/lucky_sneaks/unidecoder_data/x54.yml
75
+ lib/lucky_sneaks/unidecoder_data/x55.yml
76
+ lib/lucky_sneaks/unidecoder_data/x56.yml
77
+ lib/lucky_sneaks/unidecoder_data/x57.yml
78
+ lib/lucky_sneaks/unidecoder_data/x58.yml
79
+ lib/lucky_sneaks/unidecoder_data/x59.yml
80
+ lib/lucky_sneaks/unidecoder_data/x5a.yml
81
+ lib/lucky_sneaks/unidecoder_data/x5b.yml
82
+ lib/lucky_sneaks/unidecoder_data/x5c.yml
83
+ lib/lucky_sneaks/unidecoder_data/x5d.yml
84
+ lib/lucky_sneaks/unidecoder_data/x5e.yml
85
+ lib/lucky_sneaks/unidecoder_data/x5f.yml
86
+ lib/lucky_sneaks/unidecoder_data/x60.yml
87
+ lib/lucky_sneaks/unidecoder_data/x61.yml
88
+ lib/lucky_sneaks/unidecoder_data/x62.yml
89
+ lib/lucky_sneaks/unidecoder_data/x63.yml
90
+ lib/lucky_sneaks/unidecoder_data/x64.yml
91
+ lib/lucky_sneaks/unidecoder_data/x65.yml
92
+ lib/lucky_sneaks/unidecoder_data/x66.yml
93
+ lib/lucky_sneaks/unidecoder_data/x67.yml
94
+ lib/lucky_sneaks/unidecoder_data/x68.yml
95
+ lib/lucky_sneaks/unidecoder_data/x69.yml
96
+ lib/lucky_sneaks/unidecoder_data/x6a.yml
97
+ lib/lucky_sneaks/unidecoder_data/x6b.yml
98
+ lib/lucky_sneaks/unidecoder_data/x6c.yml
99
+ lib/lucky_sneaks/unidecoder_data/x6d.yml
100
+ lib/lucky_sneaks/unidecoder_data/x6e.yml
101
+ lib/lucky_sneaks/unidecoder_data/x6f.yml
102
+ lib/lucky_sneaks/unidecoder_data/x70.yml
103
+ lib/lucky_sneaks/unidecoder_data/x71.yml
104
+ lib/lucky_sneaks/unidecoder_data/x72.yml
105
+ lib/lucky_sneaks/unidecoder_data/x73.yml
106
+ lib/lucky_sneaks/unidecoder_data/x74.yml
107
+ lib/lucky_sneaks/unidecoder_data/x75.yml
108
+ lib/lucky_sneaks/unidecoder_data/x76.yml
109
+ lib/lucky_sneaks/unidecoder_data/x77.yml
110
+ lib/lucky_sneaks/unidecoder_data/x78.yml
111
+ lib/lucky_sneaks/unidecoder_data/x79.yml
112
+ lib/lucky_sneaks/unidecoder_data/x7a.yml
113
+ lib/lucky_sneaks/unidecoder_data/x7b.yml
114
+ lib/lucky_sneaks/unidecoder_data/x7c.yml
115
+ lib/lucky_sneaks/unidecoder_data/x7d.yml
116
+ lib/lucky_sneaks/unidecoder_data/x7e.yml
117
+ lib/lucky_sneaks/unidecoder_data/x7f.yml
118
+ lib/lucky_sneaks/unidecoder_data/x80.yml
119
+ lib/lucky_sneaks/unidecoder_data/x81.yml
120
+ lib/lucky_sneaks/unidecoder_data/x82.yml
121
+ lib/lucky_sneaks/unidecoder_data/x83.yml
122
+ lib/lucky_sneaks/unidecoder_data/x84.yml
123
+ lib/lucky_sneaks/unidecoder_data/x85.yml
124
+ lib/lucky_sneaks/unidecoder_data/x86.yml
125
+ lib/lucky_sneaks/unidecoder_data/x87.yml
126
+ lib/lucky_sneaks/unidecoder_data/x88.yml
127
+ lib/lucky_sneaks/unidecoder_data/x89.yml
128
+ lib/lucky_sneaks/unidecoder_data/x8a.yml
129
+ lib/lucky_sneaks/unidecoder_data/x8b.yml
130
+ lib/lucky_sneaks/unidecoder_data/x8c.yml
131
+ lib/lucky_sneaks/unidecoder_data/x8d.yml
132
+ lib/lucky_sneaks/unidecoder_data/x8e.yml
133
+ lib/lucky_sneaks/unidecoder_data/x8f.yml
134
+ lib/lucky_sneaks/unidecoder_data/x90.yml
135
+ lib/lucky_sneaks/unidecoder_data/x91.yml
136
+ lib/lucky_sneaks/unidecoder_data/x92.yml
137
+ lib/lucky_sneaks/unidecoder_data/x93.yml
138
+ lib/lucky_sneaks/unidecoder_data/x94.yml
139
+ lib/lucky_sneaks/unidecoder_data/x95.yml
140
+ lib/lucky_sneaks/unidecoder_data/x96.yml
141
+ lib/lucky_sneaks/unidecoder_data/x97.yml
142
+ lib/lucky_sneaks/unidecoder_data/x98.yml
143
+ lib/lucky_sneaks/unidecoder_data/x99.yml
144
+ lib/lucky_sneaks/unidecoder_data/x9a.yml
145
+ lib/lucky_sneaks/unidecoder_data/x9b.yml
146
+ lib/lucky_sneaks/unidecoder_data/x9c.yml
147
+ lib/lucky_sneaks/unidecoder_data/x9d.yml
148
+ lib/lucky_sneaks/unidecoder_data/x9e.yml
149
+ lib/lucky_sneaks/unidecoder_data/x9f.yml
150
+ lib/lucky_sneaks/unidecoder_data/xa0.yml
151
+ lib/lucky_sneaks/unidecoder_data/xa1.yml
152
+ lib/lucky_sneaks/unidecoder_data/xa2.yml
153
+ lib/lucky_sneaks/unidecoder_data/xa3.yml
154
+ lib/lucky_sneaks/unidecoder_data/xa4.yml
155
+ lib/lucky_sneaks/unidecoder_data/xac.yml
156
+ lib/lucky_sneaks/unidecoder_data/xad.yml
157
+ lib/lucky_sneaks/unidecoder_data/xae.yml
158
+ lib/lucky_sneaks/unidecoder_data/xaf.yml
159
+ lib/lucky_sneaks/unidecoder_data/xb0.yml
160
+ lib/lucky_sneaks/unidecoder_data/xb1.yml
161
+ lib/lucky_sneaks/unidecoder_data/xb2.yml
162
+ lib/lucky_sneaks/unidecoder_data/xb3.yml
163
+ lib/lucky_sneaks/unidecoder_data/xb4.yml
164
+ lib/lucky_sneaks/unidecoder_data/xb5.yml
165
+ lib/lucky_sneaks/unidecoder_data/xb6.yml
166
+ lib/lucky_sneaks/unidecoder_data/xb7.yml
167
+ lib/lucky_sneaks/unidecoder_data/xb8.yml
168
+ lib/lucky_sneaks/unidecoder_data/xb9.yml
169
+ lib/lucky_sneaks/unidecoder_data/xba.yml
170
+ lib/lucky_sneaks/unidecoder_data/xbb.yml
171
+ lib/lucky_sneaks/unidecoder_data/xbc.yml
172
+ lib/lucky_sneaks/unidecoder_data/xbd.yml
173
+ lib/lucky_sneaks/unidecoder_data/xbe.yml
174
+ lib/lucky_sneaks/unidecoder_data/xbf.yml
175
+ lib/lucky_sneaks/unidecoder_data/xc0.yml
176
+ lib/lucky_sneaks/unidecoder_data/xc1.yml
177
+ lib/lucky_sneaks/unidecoder_data/xc2.yml
178
+ lib/lucky_sneaks/unidecoder_data/xc3.yml
179
+ lib/lucky_sneaks/unidecoder_data/xc4.yml
180
+ lib/lucky_sneaks/unidecoder_data/xc5.yml
181
+ lib/lucky_sneaks/unidecoder_data/xc6.yml
182
+ lib/lucky_sneaks/unidecoder_data/xc7.yml
183
+ lib/lucky_sneaks/unidecoder_data/xc8.yml
184
+ lib/lucky_sneaks/unidecoder_data/xc9.yml
185
+ lib/lucky_sneaks/unidecoder_data/xca.yml
186
+ lib/lucky_sneaks/unidecoder_data/xcb.yml
187
+ lib/lucky_sneaks/unidecoder_data/xcc.yml
188
+ lib/lucky_sneaks/unidecoder_data/xcd.yml
189
+ lib/lucky_sneaks/unidecoder_data/xce.yml
190
+ lib/lucky_sneaks/unidecoder_data/xcf.yml
191
+ lib/lucky_sneaks/unidecoder_data/xd0.yml
192
+ lib/lucky_sneaks/unidecoder_data/xd1.yml
193
+ lib/lucky_sneaks/unidecoder_data/xd2.yml
194
+ lib/lucky_sneaks/unidecoder_data/xd3.yml
195
+ lib/lucky_sneaks/unidecoder_data/xd4.yml
196
+ lib/lucky_sneaks/unidecoder_data/xd5.yml
197
+ lib/lucky_sneaks/unidecoder_data/xd6.yml
198
+ lib/lucky_sneaks/unidecoder_data/xd7.yml
199
+ lib/lucky_sneaks/unidecoder_data/xf9.yml
200
+ lib/lucky_sneaks/unidecoder_data/xfa.yml
201
+ lib/lucky_sneaks/unidecoder_data/xfb.yml
202
+ lib/lucky_sneaks/unidecoder_data/xfc.yml
203
+ lib/lucky_sneaks/unidecoder_data/xfd.yml
204
+ lib/lucky_sneaks/unidecoder_data/xfe.yml
205
+ lib/lucky_sneaks/unidecoder_data/xff.yml
206
+ }
207
+ gem.test_files = %w{
208
+ test/acts_as_url_test.rb
209
+ test/string_extensions_test.rb
210
+ test/unidecoder_test.rb
211
+ }
212
+ gem.rdoc_options = %w{--main README.rdoc --charset utf-8 --line-numbers}
213
+ gem.extra_rdoc_files = %w{MIT-LICENSE README.rdoc}
214
+ end
215
+
216
+ rescue LoadError
217
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
218
+ end
219
+
220
+ desc 'Default: run unit tests.'
221
+ task :default => [:refresh_db, :test]
222
+
223
+ desc 'Remove old sqlite file.'
224
+ task :refresh_db do
225
+ `rm -f #{File.dirname(__FILE__)}/test/acts_as_url.sqlite3`
226
+ end
227
+
228
+ desc 'Test the stringex plugin.'
229
+ Rake::TestTask.new(:test) do |t|
230
+ t.libs << 'lib'
231
+ t.pattern = 'test/**/*_test.rb'
232
+ t.verbose = true
233
+ end
234
+
235
+ desc 'Generate documentation for the stringex plugin.'
236
+ Rake::RDocTask.new(:rdoc) do |rdoc|
237
+ if File.exist?('VERSION.yml')
238
+ config = YAML.load(File.read('VERSION.yml'))
239
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
240
+ else
241
+ version = ""
242
+ end
243
+
244
+ rdoc.rdoc_dir = 'doc'
245
+ rdoc.title = 'Stringex: A String Extension Pack [#{version}]'
246
+ rdoc.options << '--line-numbers' << '--inline-source'
247
+ rdoc.options << '--charset' << 'utf-8'
248
+ rdoc.rdoc_files.include('README.rdoc')
249
+ rdoc.rdoc_files.include('lib/**/*.rb')
250
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "stringex"
@@ -0,0 +1,88 @@
1
+ module LuckySneaks
2
+ module ActsAsUrl # :nodoc:
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods # :doc:
8
+ # Creates a callback to automatically create an url-friendly representation
9
+ # of the <tt>attribute</tt> argument. Example:
10
+ #
11
+ # act_as_url :title
12
+ #
13
+ # will use the string contents of the <tt>title</tt> attribute
14
+ # to create the permalink. <strong>Note:</strong> you can also use a non-database-backed
15
+ # method to supply the string contents for the permalink. Just use that method's name
16
+ # as the argument as you would an attribute.
17
+ #
18
+ # The default attribute <tt>acts_as_url</tt> uses to save the permalink is <tt>url</tt>
19
+ # but this can be changed in the options hash. Available options are:
20
+ #
21
+ # <tt>:url_attribute</tt>:: The name of the attribute to use for storing the generated url string.
22
+ # Default is <tt>:url</tt>
23
+ # <tt>:scope</tt>:: The name of model attribute to scope unique urls to. There is no default here.
24
+ # <tt>:only_when_blank</tt>:: If true, the url generation will only happen when <tt>:url_attribute</tt> is
25
+ # blank. Default is false (meaning url generation will happen always)
26
+ # <tt>:sync_url</tt>:: If set to true, the url field will be updated when changes are made to the
27
+ # attribute it is based on. Default is false.
28
+ def acts_as_url(attribute, options = {})
29
+ cattr_accessor :attribute_to_urlify
30
+ cattr_accessor :scope_for_url
31
+ cattr_accessor :url_attribute # The attribute on the DB
32
+ cattr_accessor :only_when_blank
33
+
34
+ if options[:sync_url]
35
+ before_validation :ensure_unique_url
36
+ else
37
+ before_validation_on_create :ensure_unique_url
38
+ end
39
+
40
+ self.attribute_to_urlify = attribute
41
+ self.scope_for_url = options[:scope]
42
+ self.url_attribute = options[:url_attribute] || "url"
43
+ self.only_when_blank = options[:only_when_blank] || false
44
+ end
45
+
46
+ # Initialize the url fields for the records that need it. Designed for people who add
47
+ # <tt>acts_as_url</tt> support once there's already development/production data they'd
48
+ # like to keep around.
49
+ #
50
+ # Note: This method can get very expensive, very fast. If you're planning on using this
51
+ # on a large selection, you will get much better results writing your own version with
52
+ # using pagination.
53
+ def initialize_urls
54
+ find(:all, :conditions => {self.url_attribute => nil}).each do |instance|
55
+ instance.send :ensure_unique_url
56
+ instance.save
57
+ end
58
+ end
59
+ end
60
+
61
+ private
62
+ def ensure_unique_url
63
+ url_attribute = self.class.url_attribute
64
+ base_url = self.send(url_attribute)
65
+ base_url = self.send(self.class.attribute_to_urlify).to_s.to_url if base_url.blank? || !self.only_when_blank
66
+ conditions = ["#{url_attribute} LIKE ?", base_url+'%']
67
+ unless new_record?
68
+ conditions.first << " and id != ?"
69
+ conditions << id
70
+ end
71
+ if self.class.scope_for_url
72
+ conditions.first << " and #{self.class.scope_for_url} = ?"
73
+ conditions << send(self.class.scope_for_url)
74
+ end
75
+ url_owners = self.class.find(:all, :conditions => conditions)
76
+ if url_owners.size > 0
77
+ return unless url_owners.map { |o| o.send(url_attribute) }.include?(base_url)
78
+ n = 1
79
+ while url_owners.detect{|u| u.send(url_attribute) == "#{base_url}-#{n}"}
80
+ n = n.succ
81
+ end
82
+ write_attribute url_attribute, "#{base_url}-#{n}"
83
+ else
84
+ write_attribute url_attribute, base_url
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,177 @@
1
+ module LuckySneaks
2
+ # These methods are all added on String class.
3
+ module StringExtensions
4
+ def self.included(base) # :nodoc:
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ # Returns the string converted (via Textile/RedCloth) to HTML format
9
+ # or self [with a friendly warning] if Redcloth is not available.
10
+ #
11
+ # Using <tt>:lite</tt> argument will cause RedCloth to not wrap the HTML in a container
12
+ # P element, which is useful behavior for generating header element text, etc.
13
+ # This is roughly equivalent to ActionView's <tt>textilize_without_paragraph</tt>
14
+ # except that it makes RedCloth do all the work instead of just gsubbing the return
15
+ # from RedCloth.
16
+ def to_html(lite_mode = false)
17
+ if defined?(RedCloth)
18
+ if lite_mode
19
+ RedCloth.new(self, [:lite_mode]).to_html
20
+ else
21
+ if self =~ /<pre>/
22
+ RedCloth.new(self).to_html.tr("\t", "")
23
+ else
24
+ RedCloth.new(self).to_html.tr("\t", "").gsub(/\n\n/, "")
25
+ end
26
+ end
27
+ else
28
+ warn "String#to_html was called without RedCloth being successfully required"
29
+ self
30
+ end
31
+ end
32
+
33
+ # Create a URI-friendly representation of the string. This is used internally by
34
+ # acts_as_url[link:classes/LuckySneaks/ActsAsUrl/ClassMethods.html#M000012]
35
+ # but can be called manually in order to generate an URI-friendly version of any string.
36
+ def to_url
37
+ remove_formatting.downcase.replace_whitespace("-").collapse("-")
38
+ end
39
+
40
+ # Performs multiple text manipulations. Essentially a shortcut for typing them all. View source
41
+ # below to see which methods are run.
42
+ def remove_formatting
43
+ strip_html_tags.convert_accented_entities.convert_misc_entities.convert_misc_characters.to_ascii.collapse
44
+ end
45
+
46
+ # Removes HTML tags from text. This code is simplified from Tobias Luettke's regular expression
47
+ # in Typo[http://typosphere.org].
48
+ def strip_html_tags(leave_whitespace = false)
49
+ name = /[\w:_-]+/
50
+ value = /([A-Za-z0-9]+|('[^']*?'|"[^"]*?"))/
51
+ attr = /(#{name}(\s*=\s*#{value})?)/
52
+ rx = /<[!\/?\[]?(#{name}|--)(\s+(#{attr}(\s+#{attr})*))?\s*([!\/?\]]+|--)?>/
53
+ (leave_whitespace) ? gsub(rx, "").strip : gsub(rx, "").gsub(/\s+/, " ").strip
54
+ end
55
+
56
+ # Converts HTML entities into the respective non-accented letters. Examples:
57
+ #
58
+ # "&aacute;".convert_accented_entities # => "a"
59
+ # "&ccedil;".convert_accented_entities # => "c"
60
+ # "&egrave;".convert_accented_entities # => "e"
61
+ # "&icirc;".convert_accented_entities # => "i"
62
+ # "&oslash;".convert_accented_entities # => "o"
63
+ # "&uuml;".convert_accented_entities # => "u"
64
+ #
65
+ # Note: This does not do any conversion of Unicode/Ascii accented-characters. For that
66
+ # functionality please use <tt>to_ascii</tt>.
67
+ def convert_accented_entities
68
+ gsub(/&([A-Za-z])(grave|acute|circ|tilde|uml|ring|cedil|slash);/, '\1')
69
+ end
70
+
71
+ # Converts HTML entities (taken from common Textile/RedCloth formattings) into plain text formats.
72
+ #
73
+ # Note: This isn't an attempt at complete conversion of HTML entities, just those most likely
74
+ # to be generated by Textile.
75
+ def convert_misc_entities
76
+ dummy = dup
77
+ {
78
+ "#822[01]" => "\"",
79
+ "#821[67]" => "'",
80
+ "#8230" => "...",
81
+ "#8211" => "-",
82
+ "#8212" => "--",
83
+ "#215" => "x",
84
+ "gt" => ">",
85
+ "lt" => "<",
86
+ "(#8482|trade)" => "(tm)",
87
+ "(#174|reg)" => "(r)",
88
+ "(#169|copy)" => "(c)",
89
+ "(#38|amp)" => "and",
90
+ "nbsp" => " ",
91
+ "(#162|cent)" => " cent",
92
+ "(#163|pound)" => " pound",
93
+ "(#188|frac14)" => "one fourth",
94
+ "(#189|frac12)" => "half",
95
+ "(#190|frac34)" => "three fourths",
96
+ "(#176|deg)" => " degrees"
97
+ }.each do |textiled, normal|
98
+ dummy.gsub!(/&#{textiled};/, normal)
99
+ end
100
+ dummy.gsub(/&[^;]+;/, "")
101
+ end
102
+
103
+ # Converts various common plaintext characters to a more URI-friendly representation.
104
+ # Examples:
105
+ #
106
+ # "foo & bar".convert_misc_characters # => "foo and bar"
107
+ # "Chanel #9".convert_misc_characters # => "Chanel number nine"
108
+ # "user@host".convert_misc_characters # => "user at host"
109
+ # "google.com".convert_misc_characters # => "google dot com"
110
+ # "$10".convert_misc_characters # => "10 dollars"
111
+ # "*69".convert_misc_characters # => "star 69"
112
+ # "100%".convert_misc_characters # => "100 percent"
113
+ # "windows/mac/linux".convert_misc_characters # => "windows slash mac slash linux"
114
+ #
115
+ # Note: Because this method will convert any & symbols to the string "and",
116
+ # you should run any methods which convert HTML entities (convert_html_entities and convert_misc_entities)
117
+ # before running this method.
118
+ def convert_misc_characters
119
+ dummy = dup.gsub(/\.{3,}/, " dot dot dot ") # Catch ellipses before single dot rule!
120
+ # Special rules for money
121
+ {
122
+ /(\s|^)\$(\d+)\.(\d+)(\s|$)/ => '\2 dollars \3 cents',
123
+ /(\s|^)£(\d+)\.(\d+)(\s|$)/u => '\2 pounds \3 pence',
124
+ }.each do |found, replaced|
125
+ replaced = " #{replaced} " unless replaced =~ /\\1/
126
+ dummy.gsub!(found, replaced)
127
+ end
128
+ # Back to normal rules
129
+ {
130
+ /\s*&\s*/ => "and",
131
+ /\s*#/ => "number",
132
+ /\s*@\s*/ => "at",
133
+ /(\S|^)\.(\S)/ => '\1 dot \2',
134
+ /(\s|^)\$(\d*)(\s|$)/ => '\2 dollars',
135
+ /(\s|^)£(\d*)(\s|$)/u => '\2 pounds',
136
+ /(\s|^)¥(\d*)(\s|$)/u => '\2 yen',
137
+ /\s*\*\s*/ => "star",
138
+ /\s*%\s*/ => "percent",
139
+ /\s*(\\|\/)\s*/ => "slash",
140
+ }.each do |found, replaced|
141
+ replaced = " #{replaced} " unless replaced =~ /\\1/
142
+ dummy.gsub!(found, replaced)
143
+ end
144
+ dummy = dummy.gsub(/(^|\w)'(\w|$)/, '\1\2').gsub(/[\.,:;()\[\]\/\?!\^'"_]/, " ")
145
+ end
146
+
147
+ # Replace runs of whitespace in string. Defaults to a single space but any replacement
148
+ # string may be specified as an argument. Examples:
149
+ #
150
+ # "Foo bar".replace_whitespace # => "Foo bar"
151
+ # "Foo bar".replace_whitespace("-") # => "Foo-bar"
152
+ def replace_whitespace(replace = " ")
153
+ gsub(/\s+/, replace)
154
+ end
155
+
156
+ # Removes specified character from the beginning and/or end of the string and then performs
157
+ # <tt>String#squeeze(character)</tt>, condensing runs of the character within the string.
158
+ #
159
+ # Note: This method has been superceded by ActiveSupport's squish method.
160
+ def collapse(character = " ")
161
+ sub(/^#{character}*/, "").sub(/#{character}*$/, "").squeeze(character)
162
+ end
163
+
164
+ module ClassMethods
165
+ # Returns string of random characters with a length matching the specified limit. Excludes 0
166
+ # to avoid confusion between 0 and O.
167
+ def random(limit)
168
+ strong_alphanumerics = %w{
169
+ a b c d e f g h i j k l m n o p q r s t u v w x y z
170
+ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
171
+ 1 2 3 4 5 6 7 8 9
172
+ }
173
+ Array.new(limit, "").collect{strong_alphanumerics[rand(61)]}.join
174
+ end
175
+ end
176
+ end
177
+ end