mnin-stringex 1.1.1

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.
Files changed (193) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +76 -0
  3. data/Rakefile +257 -0
  4. data/init.rb +1 -0
  5. data/lib/lucky_sneaks/acts_as_url.rb +90 -0
  6. data/lib/lucky_sneaks/string_extensions.rb +198 -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 +231 -0
  190. data/test/acts_as_url_test.rb +206 -0
  191. data/test/string_extensions_test.rb +160 -0
  192. data/test/unidecoder_test.rb +92 -0
  193. metadata +251 -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,257 @@
1
+ # coding: utf-8
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = "stringex"
11
+ gem.authors = ["Russell Norris"]
12
+ gem.email = "rsl@luckysneaks.com"
13
+ gem.homepage = "http://github.com/rsl/stringex"
14
+ gem.rubyforge_project = "stringex"
15
+ gem.summary = "Some [hopefully] useful extensions to Ruby’s String class"
16
+ 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]."
17
+ gem.has_rdoc = true
18
+ gem.files = %w{
19
+ init.rb
20
+ MIT-LICENSE
21
+ Rakefile
22
+ README.rdoc
23
+ stringex.gemspec
24
+ lib/stringex.rb
25
+ lib/lucky_sneaks/acts_as_url.rb
26
+ lib/lucky_sneaks/string_extensions.rb
27
+ lib/lucky_sneaks/unidecoder.rb
28
+ lib/lucky_sneaks/unidecoder_data/x00.yml
29
+ lib/lucky_sneaks/unidecoder_data/x01.yml
30
+ lib/lucky_sneaks/unidecoder_data/x02.yml
31
+ lib/lucky_sneaks/unidecoder_data/x03.yml
32
+ lib/lucky_sneaks/unidecoder_data/x04.yml
33
+ lib/lucky_sneaks/unidecoder_data/x05.yml
34
+ lib/lucky_sneaks/unidecoder_data/x06.yml
35
+ lib/lucky_sneaks/unidecoder_data/x07.yml
36
+ lib/lucky_sneaks/unidecoder_data/x09.yml
37
+ lib/lucky_sneaks/unidecoder_data/x0a.yml
38
+ lib/lucky_sneaks/unidecoder_data/x0b.yml
39
+ lib/lucky_sneaks/unidecoder_data/x0c.yml
40
+ lib/lucky_sneaks/unidecoder_data/x0d.yml
41
+ lib/lucky_sneaks/unidecoder_data/x0e.yml
42
+ lib/lucky_sneaks/unidecoder_data/x0f.yml
43
+ lib/lucky_sneaks/unidecoder_data/x10.yml
44
+ lib/lucky_sneaks/unidecoder_data/x11.yml
45
+ lib/lucky_sneaks/unidecoder_data/x12.yml
46
+ lib/lucky_sneaks/unidecoder_data/x13.yml
47
+ lib/lucky_sneaks/unidecoder_data/x14.yml
48
+ lib/lucky_sneaks/unidecoder_data/x15.yml
49
+ lib/lucky_sneaks/unidecoder_data/x16.yml
50
+ lib/lucky_sneaks/unidecoder_data/x17.yml
51
+ lib/lucky_sneaks/unidecoder_data/x18.yml
52
+ lib/lucky_sneaks/unidecoder_data/x1e.yml
53
+ lib/lucky_sneaks/unidecoder_data/x1f.yml
54
+ lib/lucky_sneaks/unidecoder_data/x20.yml
55
+ lib/lucky_sneaks/unidecoder_data/x21.yml
56
+ lib/lucky_sneaks/unidecoder_data/x22.yml
57
+ lib/lucky_sneaks/unidecoder_data/x23.yml
58
+ lib/lucky_sneaks/unidecoder_data/x24.yml
59
+ lib/lucky_sneaks/unidecoder_data/x25.yml
60
+ lib/lucky_sneaks/unidecoder_data/x26.yml
61
+ lib/lucky_sneaks/unidecoder_data/x27.yml
62
+ lib/lucky_sneaks/unidecoder_data/x28.yml
63
+ lib/lucky_sneaks/unidecoder_data/x2e.yml
64
+ lib/lucky_sneaks/unidecoder_data/x2f.yml
65
+ lib/lucky_sneaks/unidecoder_data/x30.yml
66
+ lib/lucky_sneaks/unidecoder_data/x31.yml
67
+ lib/lucky_sneaks/unidecoder_data/x32.yml
68
+ lib/lucky_sneaks/unidecoder_data/x33.yml
69
+ lib/lucky_sneaks/unidecoder_data/x4d.yml
70
+ lib/lucky_sneaks/unidecoder_data/x4e.yml
71
+ lib/lucky_sneaks/unidecoder_data/x4f.yml
72
+ lib/lucky_sneaks/unidecoder_data/x50.yml
73
+ lib/lucky_sneaks/unidecoder_data/x51.yml
74
+ lib/lucky_sneaks/unidecoder_data/x52.yml
75
+ lib/lucky_sneaks/unidecoder_data/x53.yml
76
+ lib/lucky_sneaks/unidecoder_data/x54.yml
77
+ lib/lucky_sneaks/unidecoder_data/x55.yml
78
+ lib/lucky_sneaks/unidecoder_data/x56.yml
79
+ lib/lucky_sneaks/unidecoder_data/x57.yml
80
+ lib/lucky_sneaks/unidecoder_data/x58.yml
81
+ lib/lucky_sneaks/unidecoder_data/x59.yml
82
+ lib/lucky_sneaks/unidecoder_data/x5a.yml
83
+ lib/lucky_sneaks/unidecoder_data/x5b.yml
84
+ lib/lucky_sneaks/unidecoder_data/x5c.yml
85
+ lib/lucky_sneaks/unidecoder_data/x5d.yml
86
+ lib/lucky_sneaks/unidecoder_data/x5e.yml
87
+ lib/lucky_sneaks/unidecoder_data/x5f.yml
88
+ lib/lucky_sneaks/unidecoder_data/x60.yml
89
+ lib/lucky_sneaks/unidecoder_data/x61.yml
90
+ lib/lucky_sneaks/unidecoder_data/x62.yml
91
+ lib/lucky_sneaks/unidecoder_data/x63.yml
92
+ lib/lucky_sneaks/unidecoder_data/x64.yml
93
+ lib/lucky_sneaks/unidecoder_data/x65.yml
94
+ lib/lucky_sneaks/unidecoder_data/x66.yml
95
+ lib/lucky_sneaks/unidecoder_data/x67.yml
96
+ lib/lucky_sneaks/unidecoder_data/x68.yml
97
+ lib/lucky_sneaks/unidecoder_data/x69.yml
98
+ lib/lucky_sneaks/unidecoder_data/x6a.yml
99
+ lib/lucky_sneaks/unidecoder_data/x6b.yml
100
+ lib/lucky_sneaks/unidecoder_data/x6c.yml
101
+ lib/lucky_sneaks/unidecoder_data/x6d.yml
102
+ lib/lucky_sneaks/unidecoder_data/x6e.yml
103
+ lib/lucky_sneaks/unidecoder_data/x6f.yml
104
+ lib/lucky_sneaks/unidecoder_data/x70.yml
105
+ lib/lucky_sneaks/unidecoder_data/x71.yml
106
+ lib/lucky_sneaks/unidecoder_data/x72.yml
107
+ lib/lucky_sneaks/unidecoder_data/x73.yml
108
+ lib/lucky_sneaks/unidecoder_data/x74.yml
109
+ lib/lucky_sneaks/unidecoder_data/x75.yml
110
+ lib/lucky_sneaks/unidecoder_data/x76.yml
111
+ lib/lucky_sneaks/unidecoder_data/x77.yml
112
+ lib/lucky_sneaks/unidecoder_data/x78.yml
113
+ lib/lucky_sneaks/unidecoder_data/x79.yml
114
+ lib/lucky_sneaks/unidecoder_data/x7a.yml
115
+ lib/lucky_sneaks/unidecoder_data/x7b.yml
116
+ lib/lucky_sneaks/unidecoder_data/x7c.yml
117
+ lib/lucky_sneaks/unidecoder_data/x7d.yml
118
+ lib/lucky_sneaks/unidecoder_data/x7e.yml
119
+ lib/lucky_sneaks/unidecoder_data/x7f.yml
120
+ lib/lucky_sneaks/unidecoder_data/x80.yml
121
+ lib/lucky_sneaks/unidecoder_data/x81.yml
122
+ lib/lucky_sneaks/unidecoder_data/x82.yml
123
+ lib/lucky_sneaks/unidecoder_data/x83.yml
124
+ lib/lucky_sneaks/unidecoder_data/x84.yml
125
+ lib/lucky_sneaks/unidecoder_data/x85.yml
126
+ lib/lucky_sneaks/unidecoder_data/x86.yml
127
+ lib/lucky_sneaks/unidecoder_data/x87.yml
128
+ lib/lucky_sneaks/unidecoder_data/x88.yml
129
+ lib/lucky_sneaks/unidecoder_data/x89.yml
130
+ lib/lucky_sneaks/unidecoder_data/x8a.yml
131
+ lib/lucky_sneaks/unidecoder_data/x8b.yml
132
+ lib/lucky_sneaks/unidecoder_data/x8c.yml
133
+ lib/lucky_sneaks/unidecoder_data/x8d.yml
134
+ lib/lucky_sneaks/unidecoder_data/x8e.yml
135
+ lib/lucky_sneaks/unidecoder_data/x8f.yml
136
+ lib/lucky_sneaks/unidecoder_data/x90.yml
137
+ lib/lucky_sneaks/unidecoder_data/x91.yml
138
+ lib/lucky_sneaks/unidecoder_data/x92.yml
139
+ lib/lucky_sneaks/unidecoder_data/x93.yml
140
+ lib/lucky_sneaks/unidecoder_data/x94.yml
141
+ lib/lucky_sneaks/unidecoder_data/x95.yml
142
+ lib/lucky_sneaks/unidecoder_data/x96.yml
143
+ lib/lucky_sneaks/unidecoder_data/x97.yml
144
+ lib/lucky_sneaks/unidecoder_data/x98.yml
145
+ lib/lucky_sneaks/unidecoder_data/x99.yml
146
+ lib/lucky_sneaks/unidecoder_data/x9a.yml
147
+ lib/lucky_sneaks/unidecoder_data/x9b.yml
148
+ lib/lucky_sneaks/unidecoder_data/x9c.yml
149
+ lib/lucky_sneaks/unidecoder_data/x9d.yml
150
+ lib/lucky_sneaks/unidecoder_data/x9e.yml
151
+ lib/lucky_sneaks/unidecoder_data/x9f.yml
152
+ lib/lucky_sneaks/unidecoder_data/xa0.yml
153
+ lib/lucky_sneaks/unidecoder_data/xa1.yml
154
+ lib/lucky_sneaks/unidecoder_data/xa2.yml
155
+ lib/lucky_sneaks/unidecoder_data/xa3.yml
156
+ lib/lucky_sneaks/unidecoder_data/xa4.yml
157
+ lib/lucky_sneaks/unidecoder_data/xac.yml
158
+ lib/lucky_sneaks/unidecoder_data/xad.yml
159
+ lib/lucky_sneaks/unidecoder_data/xae.yml
160
+ lib/lucky_sneaks/unidecoder_data/xaf.yml
161
+ lib/lucky_sneaks/unidecoder_data/xb0.yml
162
+ lib/lucky_sneaks/unidecoder_data/xb1.yml
163
+ lib/lucky_sneaks/unidecoder_data/xb2.yml
164
+ lib/lucky_sneaks/unidecoder_data/xb3.yml
165
+ lib/lucky_sneaks/unidecoder_data/xb4.yml
166
+ lib/lucky_sneaks/unidecoder_data/xb5.yml
167
+ lib/lucky_sneaks/unidecoder_data/xb6.yml
168
+ lib/lucky_sneaks/unidecoder_data/xb7.yml
169
+ lib/lucky_sneaks/unidecoder_data/xb8.yml
170
+ lib/lucky_sneaks/unidecoder_data/xb9.yml
171
+ lib/lucky_sneaks/unidecoder_data/xba.yml
172
+ lib/lucky_sneaks/unidecoder_data/xbb.yml
173
+ lib/lucky_sneaks/unidecoder_data/xbc.yml
174
+ lib/lucky_sneaks/unidecoder_data/xbd.yml
175
+ lib/lucky_sneaks/unidecoder_data/xbe.yml
176
+ lib/lucky_sneaks/unidecoder_data/xbf.yml
177
+ lib/lucky_sneaks/unidecoder_data/xc0.yml
178
+ lib/lucky_sneaks/unidecoder_data/xc1.yml
179
+ lib/lucky_sneaks/unidecoder_data/xc2.yml
180
+ lib/lucky_sneaks/unidecoder_data/xc3.yml
181
+ lib/lucky_sneaks/unidecoder_data/xc4.yml
182
+ lib/lucky_sneaks/unidecoder_data/xc5.yml
183
+ lib/lucky_sneaks/unidecoder_data/xc6.yml
184
+ lib/lucky_sneaks/unidecoder_data/xc7.yml
185
+ lib/lucky_sneaks/unidecoder_data/xc8.yml
186
+ lib/lucky_sneaks/unidecoder_data/xc9.yml
187
+ lib/lucky_sneaks/unidecoder_data/xca.yml
188
+ lib/lucky_sneaks/unidecoder_data/xcb.yml
189
+ lib/lucky_sneaks/unidecoder_data/xcc.yml
190
+ lib/lucky_sneaks/unidecoder_data/xcd.yml
191
+ lib/lucky_sneaks/unidecoder_data/xce.yml
192
+ lib/lucky_sneaks/unidecoder_data/xcf.yml
193
+ lib/lucky_sneaks/unidecoder_data/xd0.yml
194
+ lib/lucky_sneaks/unidecoder_data/xd1.yml
195
+ lib/lucky_sneaks/unidecoder_data/xd2.yml
196
+ lib/lucky_sneaks/unidecoder_data/xd3.yml
197
+ lib/lucky_sneaks/unidecoder_data/xd4.yml
198
+ lib/lucky_sneaks/unidecoder_data/xd5.yml
199
+ lib/lucky_sneaks/unidecoder_data/xd6.yml
200
+ lib/lucky_sneaks/unidecoder_data/xd7.yml
201
+ lib/lucky_sneaks/unidecoder_data/xf9.yml
202
+ lib/lucky_sneaks/unidecoder_data/xfa.yml
203
+ lib/lucky_sneaks/unidecoder_data/xfb.yml
204
+ lib/lucky_sneaks/unidecoder_data/xfc.yml
205
+ lib/lucky_sneaks/unidecoder_data/xfd.yml
206
+ lib/lucky_sneaks/unidecoder_data/xfe.yml
207
+ lib/lucky_sneaks/unidecoder_data/xff.yml
208
+ }
209
+ gem.test_files = %w{
210
+ test/acts_as_url_test.rb
211
+ test/string_extensions_test.rb
212
+ test/unidecoder_test.rb
213
+ }
214
+ gem.rdoc_options = %w{--main README.rdoc --charset utf-8 --line-numbers}
215
+ gem.extra_rdoc_files = %w{MIT-LICENSE README.rdoc}
216
+ end
217
+
218
+ Jeweler::RubyforgeTasks.new do |rubyforge|
219
+ rubyforge.doc_task = "rdoc"
220
+ end
221
+
222
+ Jeweler::GemcutterTasks.new
223
+ rescue LoadError
224
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
225
+ end
226
+
227
+ desc 'Default: run unit tests.'
228
+ task :default => [:refresh_db, :test]
229
+
230
+ desc 'Remove old sqlite file.'
231
+ task :refresh_db do
232
+ `rm -f #{File.dirname(__FILE__)}/test/acts_as_url.sqlite3`
233
+ end
234
+
235
+ desc 'Test the stringex plugin.'
236
+ Rake::TestTask.new(:test) do |t|
237
+ t.libs << 'lib'
238
+ t.pattern = 'test/**/*_test.rb'
239
+ t.verbose = true
240
+ end
241
+
242
+ desc 'Generate documentation for the stringex plugin.'
243
+ Rake::RDocTask.new(:rdoc) do |rdoc|
244
+ if File.exist?('VERSION.yml')
245
+ config = YAML.load(File.read('VERSION.yml'))
246
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
247
+ else
248
+ version = ""
249
+ end
250
+
251
+ rdoc.rdoc_dir = 'rdoc'
252
+ rdoc.title = 'Stringex: A String Extension Pack [#{version}]'
253
+ rdoc.options << '--line-numbers' << '--inline-source'
254
+ rdoc.options << '--charset' << 'utf-8'
255
+ rdoc.rdoc_files.include('README.rdoc')
256
+ rdoc.rdoc_files.include('lib/**/*.rb')
257
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "stringex"
@@ -0,0 +1,90 @@
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
+ cattr_accessor :duplicate_count_separator
34
+
35
+ if options[:sync_url]
36
+ before_validation :ensure_unique_url
37
+ else
38
+ # defined?(ActiveSupport::Callbacks) ? before_validation(:ensure_unique_url, :on => :create) :
39
+ before_validation_on_create(:ensure_unique_url)
40
+ end
41
+
42
+ self.attribute_to_urlify = attribute
43
+ self.scope_for_url = options[:scope]
44
+ self.url_attribute = options[:url_attribute] || "url"
45
+ self.only_when_blank = options[:only_when_blank] || false
46
+ self.duplicate_count_separator = options[:duplicate_count_separator] || "-"
47
+ end
48
+
49
+ # Initialize the url fields for the records that need it. Designed for people who add
50
+ # <tt>acts_as_url</tt> support once there's already development/production data they'd
51
+ # like to keep around.
52
+ #
53
+ # Note: This method can get very expensive, very fast. If you're planning on using this
54
+ # on a large selection, you will get much better results writing your own version with
55
+ # using pagination.
56
+ def initialize_urls
57
+ find(:all, :conditions => {self.url_attribute => nil}).each do |instance|
58
+ instance.send :ensure_unique_url
59
+ instance.save
60
+ end
61
+ end
62
+ end
63
+
64
+ private
65
+ def ensure_unique_url
66
+ url_attribute = self.class.url_attribute
67
+ separator = self.class.duplicate_count_separator
68
+ base_url = self.send(url_attribute)
69
+ base_url = self.send(self.class.attribute_to_urlify).to_s.to_url if base_url.blank? || !self.only_when_blank
70
+ conditions = ["#{url_attribute} LIKE ?", base_url+'%']
71
+ unless new_record?
72
+ conditions.first << " and id != ?"
73
+ conditions << id
74
+ end
75
+ if self.class.scope_for_url
76
+ conditions.first << " and #{self.class.scope_for_url} = ?"
77
+ conditions << send(self.class.scope_for_url)
78
+ end
79
+ url_owners = self.class.find(:all, :conditions => conditions)
80
+ write_attribute url_attribute, base_url
81
+ if url_owners.any?{|owner| owner.send(url_attribute) == base_url}
82
+ n = 1
83
+ while url_owners.any?{|owner| owner.send(url_attribute) == "#{base_url}#{separator}#{n}"}
84
+ n = n.succ
85
+ end
86
+ write_attribute url_attribute, "#{base_url}#{separator}#{n}"
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,198 @@
1
+ # coding: utf-8
2
+
3
+ module LuckySneaks
4
+ # These methods are all added on String class.
5
+ module StringExtensions
6
+ def self.included(base) # :nodoc:
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ # Returns the string converted (via Textile/RedCloth) to HTML format
11
+ # or self [with a friendly warning] if Redcloth is not available.
12
+ #
13
+ # Using <tt>:lite</tt> argument will cause RedCloth to not wrap the HTML in a container
14
+ # P element, which is useful behavior for generating header element text, etc.
15
+ # This is roughly equivalent to ActionView's <tt>textilize_without_paragraph</tt>
16
+ # except that it makes RedCloth do all the work instead of just gsubbing the return
17
+ # from RedCloth.
18
+ def to_html(lite_mode = false)
19
+ if defined?(RedCloth)
20
+ if lite_mode
21
+ RedCloth.new(self, [:lite_mode]).to_html
22
+ else
23
+ if self =~ /<pre>/
24
+ RedCloth.new(self).to_html.tr("\t", "")
25
+ else
26
+ RedCloth.new(self).to_html.tr("\t", "").gsub(/\n\n/, "")
27
+ end
28
+ end
29
+ else
30
+ warn "String#to_html was called without RedCloth being successfully required"
31
+ self
32
+ end
33
+ end
34
+
35
+ # Create a URI-friendly representation of the string. This is used internally by
36
+ # acts_as_url[link:classes/LuckySneaks/ActsAsUrl/ClassMethods.html#M000012]
37
+ # but can be called manually in order to generate an URI-friendly version of any string.
38
+ def to_url
39
+ remove_formatting.downcase.replace_whitespace("-").collapse("-")
40
+ end
41
+
42
+ # Performs multiple text manipulations. Essentially a shortcut for typing them all. View source
43
+ # below to see which methods are run.
44
+ def remove_formatting
45
+ strip_html_tags.
46
+ convert_german_umlauts.
47
+ convert_accented_entities.
48
+ convert_misc_entities.
49
+ convert_misc_characters.
50
+ to_ascii.collapse
51
+ end
52
+
53
+ # Removes HTML tags from text. This code is simplified from Tobias Luettke's regular expression
54
+ # in Typo[http://typosphere.org].
55
+ def strip_html_tags(leave_whitespace = false)
56
+ name = /[\w:_-]+/
57
+ value = /([A-Za-z0-9]+|('[^']*?'|"[^"]*?"))/
58
+ attr = /(#{name}(\s*=\s*#{value})?)/
59
+ rx = /<[!\/?\[]?(#{name}|--)(\s+(#{attr}(\s+#{attr})*))?\s*([!\/?\]]+|--)?>/
60
+ (leave_whitespace) ? gsub(rx, "").strip : gsub(rx, "").gsub(/\s+/, " ").strip
61
+ end
62
+
63
+ # Converts HTML entities into the respective non-accented letters. Examples:
64
+ #
65
+ # "&aacute;".convert_accented_entities # => "a"
66
+ # "&ccedil;".convert_accented_entities # => "c"
67
+ # "&egrave;".convert_accented_entities # => "e"
68
+ # "&icirc;".convert_accented_entities # => "i"
69
+ # "&oslash;".convert_accented_entities # => "o"
70
+ # "&uuml;".convert_accented_entities # => "u"
71
+ #
72
+ # Note: This does not do any conversion of Unicode/Ascii accented-characters. For that
73
+ # functionality please use <tt>to_ascii</tt>.
74
+ def convert_accented_entities
75
+ gsub(/&([A-Za-z])(grave|acute|circ|tilde|uml|ring|cedil|slash);/, '\1')
76
+ end
77
+
78
+ # Converts German Umlauts to their transliteration according to German conventions.
79
+ def convert_german_umlauts
80
+ map = {
81
+ "Ä" => "ae",
82
+ "Ö" => "oe",
83
+ "Ü" => "ue",
84
+ "ä" => "ae",
85
+ "ö" => "oe",
86
+ "ü" => "ue",
87
+ "ß" => "ss"
88
+ }
89
+ gsub(/#{map.keys.join('|')}/) { |match| map[match] }
90
+ end
91
+
92
+ # Converts HTML entities (taken from common Textile/RedCloth formattings) into plain text formats.
93
+ #
94
+ # Note: This isn't an attempt at complete conversion of HTML entities, just those most likely
95
+ # to be generated by Textile.
96
+ def convert_misc_entities
97
+ dummy = dup
98
+ {
99
+ "#822[01]" => "\"",
100
+ "#821[67]" => "'",
101
+ "#8230" => "...",
102
+ "#8211" => "-",
103
+ "#8212" => "--",
104
+ "#215" => "x",
105
+ "gt" => ">",
106
+ "lt" => "<",
107
+ "(#8482|trade)" => "(tm)",
108
+ "(#174|reg)" => "(r)",
109
+ "(#169|copy)" => "(c)",
110
+ "(#38|amp)" => "and",
111
+ "nbsp" => " ",
112
+ "(#162|cent)" => " cent",
113
+ "(#163|pound)" => " pound",
114
+ "(#188|frac14)" => "one fourth",
115
+ "(#189|frac12)" => "half",
116
+ "(#190|frac34)" => "three fourths",
117
+ "(#176|deg)" => " degrees"
118
+ }.each do |textiled, normal|
119
+ dummy.gsub!(/&#{textiled};/, normal)
120
+ end
121
+ dummy.gsub(/&[^;]+;/, "")
122
+ end
123
+
124
+ # Converts various common plaintext characters to a more URI-friendly representation.
125
+ # Examples:
126
+ #
127
+ # "foo & bar".convert_misc_characters # => "foo and bar"
128
+ # "Chanel #9".convert_misc_characters # => "Chanel number nine"
129
+ # "user@host".convert_misc_characters # => "user at host"
130
+ # "google.com".convert_misc_characters # => "google dot com"
131
+ # "$10".convert_misc_characters # => "10 dollars"
132
+ # "*69".convert_misc_characters # => "star 69"
133
+ # "100%".convert_misc_characters # => "100 percent"
134
+ # "windows/mac/linux".convert_misc_characters # => "windows slash mac slash linux"
135
+ #
136
+ # Note: Because this method will convert any & symbols to the string "and",
137
+ # you should run any methods which convert HTML entities (convert_html_entities and convert_misc_entities)
138
+ # before running this method.
139
+ def convert_misc_characters
140
+ dummy = dup.gsub(/\.{3,}/, " dot dot dot ") # Catch ellipses before single dot rule!
141
+ # Special rules for money
142
+ {
143
+ /(\s|^)\$(\d+)\.(\d+)(\s|$)/ => '\2 dollars \3 cents',
144
+ /(\s|^)£(\d+)\.(\d+)(\s|$)/u => '\2 pounds \3 pence',
145
+ }.each do |found, replaced|
146
+ replaced = " #{replaced} " unless replaced =~ /\\1/
147
+ dummy.gsub!(found, replaced)
148
+ end
149
+ # Back to normal rules
150
+ {
151
+ /\s*&\s*/ => "and",
152
+ /\s*#/ => "number",
153
+ /\s*@\s*/ => "at",
154
+ /(\.{0}|\S|^)\.(\S)/ => '\1 dot \2',
155
+ /(\s|^)\$(\d*)(\s|$)/ => '\2 dollars',
156
+ /(\s|^)£(\d*)(\s|$)/u => '\2 pounds',
157
+ /(\s|^)¥(\d*)(\s|$)/u => '\2 yen',
158
+ /\s*\*\s*/ => "star",
159
+ /\s*%\s*/ => "percent",
160
+ /\s*(\\|\/)\s*/ => "slash",
161
+ }.each do |found, replaced|
162
+ replaced = " #{replaced} " unless replaced =~ /\\1/
163
+ dummy.gsub!(found, replaced)
164
+ end
165
+ dummy = dummy.gsub(/(^|\w)'(\w|$)/, '\1\2').gsub(/[\.,:;()\[\]\/\?!\^'"_]/, " ")
166
+ end
167
+
168
+ # Replace runs of whitespace in string. Defaults to a single space but any replacement
169
+ # string may be specified as an argument. Examples:
170
+ #
171
+ # "Foo bar".replace_whitespace # => "Foo bar"
172
+ # "Foo bar".replace_whitespace("-") # => "Foo-bar"
173
+ def replace_whitespace(replace = " ")
174
+ gsub(/\s+/, replace)
175
+ end
176
+
177
+ # Removes specified character from the beginning and/or end of the string and then performs
178
+ # <tt>String#squeeze(character)</tt>, condensing runs of the character within the string.
179
+ #
180
+ # Note: This method has been superceded by ActiveSupport's squish method.
181
+ def collapse(character = " ")
182
+ sub(/^#{character}*/, "").sub(/#{character}*$/, "").squeeze(character)
183
+ end
184
+
185
+ module ClassMethods
186
+ # Returns string of random characters with a length matching the specified limit. Excludes 0
187
+ # to avoid confusion between 0 and O.
188
+ def random(limit)
189
+ strong_alphanumerics = %w{
190
+ 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
191
+ 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
192
+ 1 2 3 4 5 6 7 8 9
193
+ }
194
+ Array.new(limit, "").collect{strong_alphanumerics[rand(61)]}.join
195
+ end
196
+ end
197
+ end
198
+ end