rsl-stringex 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +74 -0
  3. data/Rakefile +28 -0
  4. data/init.rb +7 -0
  5. data/lib/lucky_sneaks/acts_as_url.rb +82 -0
  6. data/lib/lucky_sneaks/string_extensions.rb +165 -0
  7. data/lib/lucky_sneaks/unidecoder.rb +48 -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/stringex.gemspec +208 -0
  189. data/test/acts_as_url_test.rb +140 -0
  190. data/test/string_extensions_test.rb +138 -0
  191. data/test/unidecoder_test.rb +68 -0
  192. metadata +245 -0
data/MIT-LICENSE ADDED
@@ -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.
data/README.rdoc ADDED
@@ -0,0 +1,74 @@
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>:sync_url</tt>:: If set to true, the url field will be updated when changes are made to the
17
+ attribute it is based on. Default is false.
18
+
19
+ In order to use the generated url attribute, you will probably want to override <tt>to_param</tt> like so, in your Model:
20
+
21
+ def to_param
22
+ url # or whatever you set :url_attribute to
23
+ end
24
+
25
+ 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>.
26
+
27
+ 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:
28
+
29
+ # A simple prelude
30
+ "simple English".to_url => "simple-english"
31
+ "it's nothing at all".to_url => "its-nothing-at-all"
32
+ "rock & roll".to_url => "rock-and-roll"
33
+
34
+ # Let's show off
35
+ "$12 worth of Ruby power".to_url => "12-dollars-worth-of-ruby-power"
36
+ "10% off if you act now".to_url => "10-percent-off-if-you-act-now"
37
+
38
+ # You don't even wanna trust Iconv for this next part
39
+ "kick it en Français".to_url => "kick-it-en-francais"
40
+ "rock it Español style".to_url => "rock-it-espanol-style"
41
+ "tell your readers 你好".to_url => "tell-your-readers-ni-hao"
42
+
43
+ Compare those results with the ones produced on my Intel Mac by a leading permalink plugin:
44
+
45
+ "simple English" # => "simple-english"
46
+ "it's nothing at all" # => "it-s-nothing-at-all"
47
+ "rock & roll" # => "rock-roll"
48
+
49
+ "$12 worth of Ruby power" # => "12-worth-of-ruby-power"
50
+ "10% off if you act now" # => "10-off-if-you-act-now"
51
+
52
+ "kick it en Français" # => "kick-it-en-francais"
53
+ "rock it Español style" # => "rock-it-espan-ol-style"
54
+ "tell your readers 你好" # => "tell-your-readers"
55
+
56
+ Not so great, actually.
57
+
58
+ Note: No offense is intended to the author[s] of whatever plugins might produce such results. It's not your faults Iconv sucks.
59
+
60
+ == Unidecoder
61
+
62
+ 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])
63
+
64
+ 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.
65
+
66
+ == StringExtensions
67
+
68
+ 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.
69
+
70
+ == Thanks & Acknowledgements
71
+
72
+ 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/].
73
+
74
+ copyright (c) 2008 Lucky Sneaks, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => [:refresh_db, :test]
7
+
8
+ desc 'Remove old sqlite file'
9
+ task :refresh_db do
10
+ `rm -f #{File.dirname(__FILE__)}/test/acts_as_url.sqlite3`
11
+ end
12
+
13
+ desc 'Test the stringex plugin.'
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.libs << 'lib'
16
+ t.pattern = 'test/**/*_test.rb'
17
+ t.verbose = true
18
+ end
19
+
20
+ desc 'Generate documentation for the stringex plugin.'
21
+ Rake::RDocTask.new(:rdoc) do |rdoc|
22
+ rdoc.rdoc_dir = 'doc'
23
+ rdoc.title = 'Stringex: A String Extension Pack'
24
+ rdoc.options << '--line-numbers' << '--inline-source'
25
+ rdoc.options << '--charset' << 'utf-8'
26
+ rdoc.rdoc_files.include('README.rdoc')
27
+ rdoc.rdoc_files.include('lib/**/*.rb')
28
+ end
data/init.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'lucky_sneaks/acts_as_url'
2
+ require 'lucky_sneaks/string_extensions'
3
+ require 'lucky_sneaks/unidecoder'
4
+
5
+ String.send :include, LuckySneaks::StringExtensions
6
+
7
+ ActiveRecord::Base.send :include, LuckySneaks::ActsAsUrl
@@ -0,0 +1,82 @@
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>:sync_url</tt>:: If set to true, the url field will be updated when changes are made to the
25
+ # attribute it is based on. Default is false.
26
+ def acts_as_url(attribute, options = {})
27
+ cattr_accessor :attribute_to_urlify
28
+ cattr_accessor :scope_for_url
29
+ cattr_accessor :url_attribute # The attribute on the DB
30
+
31
+ if options[:sync_url]
32
+ before_validation :ensure_unique_url
33
+ else
34
+ before_validation_on_create :ensure_unique_url
35
+ end
36
+
37
+ self.attribute_to_urlify = attribute
38
+ self.scope_for_url = options[:scope]
39
+ self.url_attribute = options[:url_attribute] || "url"
40
+ end
41
+
42
+ # Initialize the url fields for the records that need it. Designed for people who add
43
+ # <tt>acts_as_url</tt> support once there's already development/production data they'd
44
+ # like to keep around.
45
+ #
46
+ # Note: This method can get very expensive, very fast. If you're planning on using this
47
+ # on a large selection, you will get much better results writing your own version with
48
+ # using pagination.
49
+ def initialize_urls
50
+ find(:all, :conditions => {self.url_attribute => nil}).each do |instance|
51
+ instance.send :ensure_unique_url
52
+ instance.save
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+ def ensure_unique_url
59
+ url_attribute = self.class.url_attribute
60
+ base_url = self.send(self.class.attribute_to_urlify).to_s.to_url
61
+ conditions = ["#{url_attribute} LIKE ?", base_url+'%']
62
+ unless new_record?
63
+ conditions.first << " and id != ?"
64
+ conditions << id
65
+ end
66
+ if self.class.scope_for_url
67
+ conditions.first << " and #{self.class.scope_for_url} = ?"
68
+ conditions << send(self.class.scope_for_url)
69
+ end
70
+ url_owners = self.class.find(:all, :conditions => conditions)
71
+ if url_owners.size > 0
72
+ n = 1
73
+ while url_owners.detect{|u| u.send(url_attribute) == "#{base_url}-#{n}"}
74
+ n = n.succ
75
+ end
76
+ write_attribute url_attribute, "#{base_url}-#{n}"
77
+ else
78
+ write_attribute url_attribute, base_url
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,165 @@
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 or
9
+ # self 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
+ self
29
+ end
30
+ end
31
+
32
+ # Create a URI-friendly representation of the string. This is used internally by
33
+ # acts_as_url[link:classes/LuckySneaks/ActsAsUrl/ClassMethods.html#M000012]
34
+ # but can be called manually in order to generate an URI-friendly version of any string.
35
+ def to_url
36
+ remove_formatting.downcase.replace_whitespace("-").collapse("-")
37
+ end
38
+
39
+ # Performs multiple text manipulations. Essentially a shortcut for typing them all. View source
40
+ # below to see which methods are run.
41
+ def remove_formatting
42
+ to_ascii.strip_html_tags.convert_accented_entities.convert_misc_entities.convert_misc_characters.collapse
43
+ end
44
+
45
+ # Removes HTML tags from text. This code is simplified from Tobias Luettke's regular expression
46
+ # in Typo[http://typosphere.org].
47
+ def strip_html_tags(leave_whitespace = false)
48
+ name = /[\w:_-]+/
49
+ value = /([A-Za-z0-9]+|('[^']*?'|"[^"]*?"))/
50
+ attr = /(#{name}(\s*=\s*#{value})?)/
51
+ rx = /<[!\/?\[]?(#{name}|--)(\s+(#{attr}(\s+#{attr})*))?\s*([!\/?\]]+|--)?>/
52
+ (leave_whitespace) ? gsub(rx, "").strip : gsub(rx, "").gsub(/\s+/, " ").strip
53
+ end
54
+
55
+ # Converts HTML entities into the respective non-accented letters. Examples:
56
+ #
57
+ # "&aacute;".convert_accented_entities # => "a"
58
+ # "&ccedil;".convert_accented_entities # => "c"
59
+ # "&egrave;".convert_accented_entities # => "e"
60
+ # "&icirc;".convert_accented_entities # => "i"
61
+ # "&oslash;".convert_accented_entities # => "o"
62
+ # "&uuml;".convert_accented_entities # => "u"
63
+ #
64
+ # Note: This does not do any conversion of Unicode/Ascii accented-characters. For that
65
+ # functionality please use <tt>to_ascii</tt>.
66
+ def convert_accented_entities
67
+ gsub(/&([A-Za-z])(grave|acute|circ|tilde|uml|ring|cedil|slash);/, '\1')
68
+ end
69
+
70
+ # Converts HTML entities (taken from common Textile/RedCloth formattings) into plain text formats.
71
+ #
72
+ # Note: This isn't an attempt at complete conversion of HTML entities, just those most likely
73
+ # to be generated by Textile.
74
+ def convert_misc_entities
75
+ dummy = dup
76
+ {
77
+ "#822[01]" => "\"",
78
+ "#821[67]" => "'",
79
+ "#8230" => "...",
80
+ "#8211" => "-",
81
+ "#8212" => "--",
82
+ "#215" => "x",
83
+ "gt" => ">",
84
+ "lt" => "<",
85
+ "(#8482|trade)" => "(tm)",
86
+ "(#174|reg)" => "(r)",
87
+ "(#169|copy)" => "(c)",
88
+ "(#38|amp)" => "and",
89
+ "nbsp" => " ",
90
+ "(#162|cent)" => " cent",
91
+ "(#163|pound)" => " pound",
92
+ "(#188|frac14)" => "one fourth",
93
+ "(#189|frac12)" => "half",
94
+ "(#190|frac34)" => "three fourths",
95
+ "(#176|deg)" => " degrees"
96
+ }.each do |textiled, normal|
97
+ dummy.gsub!(/&#{textiled};/, normal)
98
+ end
99
+ dummy.gsub(/&[^;]+;/, "")
100
+ end
101
+
102
+ # Converts various common plaintext characters to a more URI-friendly representation.
103
+ # Examples:
104
+ #
105
+ # "foo & bar".convert_misc_characters # => "foo and bar"
106
+ # "Chanel #9".convert_misc_characters # => "Chanel number nine"
107
+ # "user@host".convert_misc_characters # => "user at host"
108
+ # "google.com".convert_misc_characters # => "google dot com"
109
+ # "$10".convert_misc_characters # => "10 dollars"
110
+ # "*69".convert_misc_characters # => "star 69"
111
+ # "100%".convert_misc_characters # => "100 percent"
112
+ # "windows/mac/linux".convert_misc_characters # => "windows slash mac slash linux"
113
+ #
114
+ # Note: Because this method will convert any & symbols to the string "and",
115
+ # you should run any methods which convert HTML entities (convert_html_entities and convert_misc_entities)
116
+ # before running this method.
117
+ def convert_misc_characters
118
+ dummy = dup.gsub(/\.{3,}/, " dot dot dot ") # Catch ellipses before single dot rule!
119
+ {
120
+ /\s*&\s*/ => "and",
121
+ /\s*#/ => "number",
122
+ /\s*@\s*/ => "at",
123
+ /(\S|^)\.(\S)/ => '\1 dot \2',
124
+ /(\s|^)\$(\d*)(\s|$)/ => '\2 dollars',
125
+ /\s*\*\s*/ => "star",
126
+ /\s*%\s*/ => "percent",
127
+ /\s*(\\|\/)\s*/ => "slash",
128
+ }.each do |found, replaced|
129
+ replaced = " #{replaced} " unless replaced =~ /\\1/
130
+ dummy.gsub!(found, replaced)
131
+ end
132
+ dummy = dummy.gsub(/(^|\w)'(\w|$)/, '\1\2').gsub(/[\.,:;()\[\]\/\?!\^'"_]/, " ")
133
+ end
134
+
135
+ # Replace runs of whitespace in string. Defaults to a single space but any replacement
136
+ # string may be specified as an argument. Examples:
137
+ #
138
+ # "Foo bar".replace_whitespace # => "Foo bar"
139
+ # "Foo bar".replace_whitespace("-") # => "Foo-bar"
140
+ def replace_whitespace(replace = " ")
141
+ gsub(/\s+/, replace)
142
+ end
143
+
144
+ # Removes specified character from the beginning and/or end of the string and then performs
145
+ # <tt>String#squeeze(character)</tt>, condensing runs of the character within the string.
146
+ #
147
+ # Note: This method has been superceded by ActiveSupport's squish method.
148
+ def collapse(character = " ")
149
+ sub(/^#{character}*/, "").sub(/#{character}*$/, "").squeeze(character)
150
+ end
151
+
152
+ module ClassMethods
153
+ # Returns string of random characters with a length matching the specified limit. Excludes 0
154
+ # to avoid confusion between 0 and O.
155
+ def random(limit)
156
+ strong_alphanumerics = %w{
157
+ 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
158
+ 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
159
+ 1 2 3 4 5 6 7 8 9
160
+ }
161
+ Array.new(limit, "").collect{strong_alphanumerics[rand(61)]}.join
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,48 @@
1
+ require "yaml"
2
+
3
+ module LuckySneaks
4
+ module Unidecoder
5
+ # Contains Unicode codepoints, loading as needed from YAML files
6
+ CODEPOINTS = Hash.new { |h, k|
7
+ h[k] = YAML::load_file(File.join(File.dirname(__FILE__), "unidecoder_data", "#{k}.yml"))
8
+ } unless defined?(CODEPOINTS)
9
+
10
+ class << self
11
+ # Returns string with its UTF-8 characters transliterated to ASCII ones
12
+ #
13
+ # You're probably better off just using the added String#to_ascii
14
+ def decode(string)
15
+ string.gsub(/[^\x00-\x7f]/u) do |codepoint|
16
+ begin
17
+ CODEPOINTS[code_group(codepoint)][grouped_point(codepoint)]
18
+ rescue
19
+ # Hopefully this won't come up much
20
+ "?"
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+ # Returns the Unicode codepoint grouping for the given character
27
+ def code_group(character)
28
+ "x%02x" % (character.unpack("U")[0] >> 8)
29
+ end
30
+
31
+ # Returns the index of the given character in the YAML file for its codepoint group
32
+ def grouped_point(character)
33
+ character.unpack("U")[0] & 255
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ module LuckySneaks
40
+ module StringExtensions
41
+ # Returns string with its UTF-8 characters transliterated to ASCII ones. Example:
42
+ #
43
+ # "⠋⠗⠁⠝⠉⠑".to_ascii #=> "braille"
44
+ def to_ascii
45
+ LuckySneaks::Unidecoder::decode(self)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,257 @@
1
+ ---
2
+ - "\z"
3
+ - "\x01"
4
+ - "\x02"
5
+ - "\x03"
6
+ - "\x04"
7
+ - "\x05"
8
+ - "\x06"
9
+ - "\a"
10
+ - "\x08"
11
+ - ' '
12
+ - "\n"
13
+ - "\v"
14
+ - "\f"
15
+ - "\r"
16
+ - "\x0e"
17
+ - "\x0f"
18
+ - "\x10"
19
+ - "\x11"
20
+ - "\x12"
21
+ - "\x13"
22
+ - "\x14"
23
+ - "\x15"
24
+ - "\x16"
25
+ - "\x17"
26
+ - "\x18"
27
+ - "\x19"
28
+ - "\x1a"
29
+ - "\e"
30
+ - "\x1c"
31
+ - "\x1d"
32
+ - "\x1e"
33
+ - "\x1f"
34
+ - ' '
35
+ - '!'
36
+ - '"'
37
+ - '#'
38
+ - $
39
+ - '%'
40
+ - '&'
41
+ - "'"
42
+ - (
43
+ - )
44
+ - '*'
45
+ - +
46
+ - ','
47
+ - -
48
+ - .
49
+ - /
50
+ - 0
51
+ - 1
52
+ - 2
53
+ - 3
54
+ - 4
55
+ - 5
56
+ - 6
57
+ - 7
58
+ - 8
59
+ - 9
60
+ - ':'
61
+ - ;
62
+ - <
63
+ - =
64
+ - '>'
65
+ - '?'
66
+ - '@'
67
+ - A
68
+ - B
69
+ - C
70
+ - D
71
+ - E
72
+ - F
73
+ - G
74
+ - H
75
+ - I
76
+ - J
77
+ - K
78
+ - L
79
+ - M
80
+ - N
81
+ - O
82
+ - P
83
+ - Q
84
+ - R
85
+ - S
86
+ - T
87
+ - U
88
+ - V
89
+ - W
90
+ - X
91
+ - Y
92
+ - Z
93
+ - ']'
94
+ - \
95
+ - ']'
96
+ - '^'
97
+ - _
98
+ - '`'
99
+ - a
100
+ - b
101
+ - c
102
+ - d
103
+ - e
104
+ - f
105
+ - g
106
+ - h
107
+ - i
108
+ - j
109
+ - k
110
+ - l
111
+ - m
112
+ - n
113
+ - o
114
+ - p
115
+ - q
116
+ - r
117
+ - s
118
+ - t
119
+ - u
120
+ - v
121
+ - w
122
+ - x
123
+ - y
124
+ - z
125
+ - '{'
126
+ - '|'
127
+ - '}'
128
+ - '~'
129
+ - 
130
+ - ''
131
+ - ''
132
+ - ''
133
+ - ''
134
+ - ''
135
+ - ''
136
+ - ''
137
+ - ''
138
+ - ''
139
+ - ''
140
+ - ''
141
+ - ''
142
+ - ''
143
+ - ''
144
+ - ''
145
+ - ''
146
+ - ''
147
+ - ''
148
+ - ''
149
+ - ''
150
+ - ''
151
+ - ''
152
+ - ''
153
+ - ''
154
+ - ''
155
+ - ''
156
+ - ''
157
+ - ''
158
+ - ''
159
+ - ''
160
+ - ''
161
+ - ''
162
+ - ' '
163
+ - '!'
164
+ - C/
165
+ - PS
166
+ - $?
167
+ - Y=
168
+ - '|'
169
+ - SS
170
+ - '"'
171
+ - (c)
172
+ - a
173
+ - <<
174
+ - '!'
175
+ - ''
176
+ - (r)
177
+ - -
178
+ - deg
179
+ - +-
180
+ - 2
181
+ - 3
182
+ - "'"
183
+ - u
184
+ - P
185
+ - '*'
186
+ - ','
187
+ - 1
188
+ - o
189
+ - '>>'
190
+ - 1/4
191
+ - 1/2
192
+ - 3/4
193
+ - '?'
194
+ - A
195
+ - A
196
+ - A
197
+ - A
198
+ - A
199
+ - A
200
+ - AE
201
+ - C
202
+ - E
203
+ - E
204
+ - E
205
+ - E
206
+ - I
207
+ - I
208
+ - I
209
+ - I
210
+ - D
211
+ - N
212
+ - O
213
+ - O
214
+ - O
215
+ - O
216
+ - O
217
+ - x
218
+ - O
219
+ - U
220
+ - U
221
+ - U
222
+ - U
223
+ - U
224
+ - Th
225
+ - ss
226
+ - a
227
+ - a
228
+ - a
229
+ - a
230
+ - a
231
+ - a
232
+ - ae
233
+ - c
234
+ - e
235
+ - e
236
+ - e
237
+ - e
238
+ - i
239
+ - i
240
+ - i
241
+ - i
242
+ - d
243
+ - n
244
+ - o
245
+ - o
246
+ - o
247
+ - o
248
+ - o
249
+ - /
250
+ - o
251
+ - u
252
+ - u
253
+ - u
254
+ - u
255
+ - y
256
+ - th
257
+ - y