jekyll-import 0.1.0.beta3 → 0.1.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +6 -14
  2. data/History.markdown +18 -0
  3. data/README.markdown +12 -1
  4. data/jekyll-import.gemspec +31 -25
  5. data/lib/jekyll-import.rb +50 -1
  6. data/lib/jekyll-import/importer.rb +11 -0
  7. data/lib/jekyll-import/importers.rb +10 -0
  8. data/lib/jekyll-import/importers/csv.rb +50 -0
  9. data/lib/jekyll-import/importers/drupal6.rb +139 -0
  10. data/lib/jekyll-import/importers/drupal7.rb +102 -0
  11. data/lib/jekyll-import/importers/enki.rb +76 -0
  12. data/lib/jekyll-import/importers/google_reader.rb +68 -0
  13. data/lib/jekyll-import/importers/joomla.rb +83 -0
  14. data/lib/jekyll-import/importers/jrnl.rb +127 -0
  15. data/lib/jekyll-import/importers/marley.rb +72 -0
  16. data/lib/jekyll-import/importers/mephisto.rb +109 -0
  17. data/lib/jekyll-import/importers/mt.rb +169 -0
  18. data/lib/jekyll-import/importers/posterous.rb +139 -0
  19. data/lib/jekyll-import/importers/rss.rb +71 -0
  20. data/lib/jekyll-import/importers/s9y.rb +67 -0
  21. data/lib/jekyll-import/importers/textpattern.rb +76 -0
  22. data/lib/jekyll-import/importers/tumblr.rb +265 -0
  23. data/lib/jekyll-import/importers/typo.rb +89 -0
  24. data/lib/jekyll-import/importers/wordpress.rb +323 -0
  25. data/lib/jekyll-import/importers/wordpressdotcom.rb +97 -0
  26. data/lib/jekyll/commands/import.rb +1 -0
  27. data/test/helper.rb +3 -1
  28. data/test/test_jrnl_importer.rb +39 -0
  29. data/test/test_mt_importer.rb +16 -16
  30. data/test/test_tumblr_importer.rb +61 -0
  31. data/test/test_wordpress_importer.rb +1 -1
  32. data/test/test_wordpressdotcom_importer.rb +1 -1
  33. metadata +53 -32
  34. data/lib/jekyll/jekyll-import/csv.rb +0 -30
  35. data/lib/jekyll/jekyll-import/drupal6.rb +0 -112
  36. data/lib/jekyll/jekyll-import/drupal7.rb +0 -74
  37. data/lib/jekyll/jekyll-import/enki.rb +0 -49
  38. data/lib/jekyll/jekyll-import/google_reader.rb +0 -61
  39. data/lib/jekyll/jekyll-import/joomla.rb +0 -53
  40. data/lib/jekyll/jekyll-import/marley.rb +0 -52
  41. data/lib/jekyll/jekyll-import/mephisto.rb +0 -84
  42. data/lib/jekyll/jekyll-import/mt.rb +0 -142
  43. data/lib/jekyll/jekyll-import/posterous.rb +0 -122
  44. data/lib/jekyll/jekyll-import/rss.rb +0 -63
  45. data/lib/jekyll/jekyll-import/s9y.rb +0 -59
  46. data/lib/jekyll/jekyll-import/textpattern.rb +0 -58
  47. data/lib/jekyll/jekyll-import/tumblr.rb +0 -242
  48. data/lib/jekyll/jekyll-import/typo.rb +0 -69
  49. data/lib/jekyll/jekyll-import/wordpress.rb +0 -299
  50. data/lib/jekyll/jekyll-import/wordpressdotcom.rb +0 -84
@@ -1,242 +0,0 @@
1
- require 'rubygems'
2
- require 'open-uri'
3
- require 'fileutils'
4
- require 'nokogiri'
5
- require 'date'
6
- require 'json'
7
- require 'uri'
8
- require 'jekyll'
9
-
10
- module JekyllImport
11
- module Tumblr
12
- def self.process(url, format = "html", grab_images = false,
13
- add_highlights = false, rewrite_urls = true)
14
- @grab_images = grab_images
15
- FileUtils.mkdir_p "_posts/tumblr"
16
- url += "/api/read/json/"
17
- per_page = 50
18
- posts = []
19
- # Two passes are required so that we can rewrite URLs.
20
- # First pass builds up an array of each post as a hash.
21
- begin
22
- current_page = (current_page || -1) + 1
23
- feed_url = url + "?num=#{per_page}&start=#{current_page * per_page}"
24
- puts "Fetching #{feed_url}"
25
- feed = open(feed_url)
26
- json = feed.readlines.join("\n")[21...-2] # Strip Tumblr's JSONP chars.
27
- blog = JSON.parse(json)
28
- puts "Page: #{current_page + 1} - Posts: #{blog["posts"].size}"
29
- batch = blog["posts"].map { |post| post_to_hash(post, format) }
30
-
31
- # If we're rewriting, save the posts for later. Otherwise, go ahead and
32
- # dump these to disk now
33
- if rewrite_urls
34
- posts += batch
35
- else
36
- batch.each {|post| write_post(post, format == "md", add_highlights)}
37
- end
38
-
39
- end until blog["posts"].size < per_page
40
-
41
- # Rewrite URLs, create redirects and write out out posts if necessary
42
- if rewrite_urls
43
- posts = rewrite_urls_and_redirects posts
44
- posts.each {|post| write_post(post, format == "md", add_highlights)}
45
- end
46
- end
47
-
48
- private
49
-
50
- # Writes a post out to disk
51
- def self.write_post(post, use_markdown, add_highlights)
52
- content = post[:content]
53
- if use_markdown
54
- content = html_to_markdown content
55
- content = add_syntax_highlights content if add_highlights
56
- end
57
-
58
- File.open("_posts/tumblr/#{post[:name]}", "w") do |f|
59
- f.puts post[:header].to_yaml + "---\n" + content
60
- end
61
- end
62
-
63
- # Converts each type of Tumblr post to a hash with all required
64
- # data for Jekyll.
65
- def self.post_to_hash(post, format)
66
- case post['type']
67
- when "regular"
68
- title = post["regular-title"]
69
- content = post["regular-body"]
70
- when "link"
71
- title = post["link-text"] || post["link-url"]
72
- content = "<a href=\"#{post["link-url"]}\">#{title}</a>"
73
- unless post["link-description"].nil?
74
- content << "<br/>" + post["link-description"]
75
- end
76
- when "photo"
77
- title = post["photo-caption"]
78
- content = if post["photo-link-url"].nil?
79
- "<a href=\"#{post["photo-link-url"]}\">#{content}</a>"
80
- else
81
- fetch_photo post
82
- end
83
- when "audio"
84
- if !post["id3-title"].nil?
85
- title = post["id3-title"]
86
- content = post["audio-player"] + "<br/>" + post["audio-caption"]
87
- else
88
- title = post["audio-caption"]
89
- content = post["audio-player"]
90
- end
91
- when "quote"
92
- title = post["quote-text"]
93
- content = "<blockquote>#{post["quote-text"]}</blockquote>"
94
- unless post["quote-source"].nil?
95
- content << "&#8212;" + post["quote-source"]
96
- end
97
- when "conversation"
98
- title = post["conversation-title"]
99
- content = "<section><dialog>"
100
- post["conversation"].each do |line|
101
- content << "<dt>#{line['label']}</dt><dd>#{line['phrase']}</dd>"
102
- end
103
- content << "</section></dialog>"
104
- when "video"
105
- title = post["video-title"]
106
- content = post["video-player"]
107
- unless post["video-caption"].nil?
108
- content << "<br/>" + post["video-caption"]
109
- end
110
- end
111
- date = Date.parse(post['date']).to_s
112
- title = Nokogiri::HTML(title).text
113
- slug = if post["slug"] && post["slug"].strip != ""
114
- post["slug"]
115
- else
116
- slug = title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
117
- slug.length > 200 ? slug.slice(0..200) : slug
118
- end
119
- {
120
- :name => "#{date}-#{slug}.#{format}",
121
- :header => {
122
- "layout" => "post",
123
- "title" => title,
124
- "tags" => post["tags"],
125
- },
126
- :content => content,
127
- :url => post["url"],
128
- :slug => post["url-with-slug"],
129
- }
130
- end
131
-
132
- # Attempts to fetch the largest version of a photo available for a post.
133
- # If that file fails, it tries the next smaller size until all available
134
- # photo URLs are exhausted. If they all fail, the import is aborted.
135
- def self.fetch_photo(post)
136
- sizes = post.keys.map {|k| k.gsub("photo-url-", "").to_i}
137
- sizes.sort! {|a,b| b <=> a}
138
-
139
- ext_key, ext_val = post.find do |k,v|
140
- k =~ /^photo-url-/ && v.split("/").last =~ /\./
141
- end
142
- ext = "." + ext_val.split(".").last
143
-
144
- sizes.each do |size|
145
- url = post["photo-url"] || post["photo-url-#{size}"]
146
- next if url.nil?
147
- begin
148
- return "<img src=\"#{save_photo(url, ext)}\"/>"
149
- rescue OpenURI::HTTPError => err
150
- puts "Failed to grab photo"
151
- end
152
- end
153
-
154
- abort "Failed to fetch photo for post #{post['url']}"
155
- end
156
-
157
- # Create a Hash of old urls => new urls, for rewriting and
158
- # redirects, and replace urls in each post. Instantiate Jekyll
159
- # site/posts to get the correct permalink format.
160
- def self.rewrite_urls_and_redirects(posts)
161
- site = Jekyll::Site.new(Jekyll.configuration({}))
162
- urls = Hash[posts.map { |post|
163
- # Create an initial empty file for the post so that
164
- # we can instantiate a post object.
165
- File.open("_posts/tumblr/#{post[:name]}", "w")
166
- tumblr_url = URI.parse(post[:slug]).path
167
- jekyll_url = Jekyll::Post.new(site, Dir.pwd, "", "tumblr/" + post[:name]).url
168
- redirect_dir = tumblr_url.sub(/\//, "") + "/"
169
- FileUtils.mkdir_p redirect_dir
170
- File.open(redirect_dir + "index.html", "w") do |f|
171
- f.puts "<html><head><meta http-equiv='Refresh' content='0; " +
172
- "url=#{jekyll_url}'></head><body></body></html>"
173
- end
174
- [tumblr_url, jekyll_url]
175
- }]
176
- posts.map { |post|
177
- urls.each do |tumblr_url, jekyll_url|
178
- post[:content].gsub!(/#{tumblr_url}/i, jekyll_url)
179
- end
180
- post
181
- }
182
- end
183
-
184
- # Convert preserving HTML tables as per the markdown docs.
185
- def self.html_to_markdown(content)
186
- preserve = ["table", "tr", "th", "td"]
187
- preserve.each do |tag|
188
- content.gsub!(/<#{tag}/i, "$$" + tag)
189
- content.gsub!(/<\/#{tag}/i, "||" + tag)
190
- end
191
- content = Nokogiri::HTML(content.gsub("'", "''")).text
192
- preserve.each do |tag|
193
- content.gsub!("$$" + tag, "<" + tag)
194
- content.gsub!("||" + tag, "</" + tag)
195
- end
196
- content
197
- end
198
-
199
- # Adds pygments highlight tags to code blocks in posts that use
200
- # markdown format. This doesn't guess the language of the code
201
- # block, so you should modify this to suit your own content.
202
- # For example, my code block only contain Python and JavaScript,
203
- # so I can assume the block is JavaScript if it contains a
204
- # semi-colon.
205
- def self.add_syntax_highlights(content)
206
- lines = content.split("\n")
207
- block, indent, lang, start = false, /^ /, nil, nil
208
- lines.each_with_index do |line, i|
209
- if !block && line =~ indent
210
- block = true
211
- lang = "python"
212
- start = i
213
- elsif block
214
- lang = "javascript" if line =~ /;$/
215
- block = line =~ indent && i < lines.size - 1 # Also handle EOF
216
- if !block
217
- lines[start] = "{% highlight #{lang} %}"
218
- lines[i - 1] = "{% endhighlight %}"
219
- end
220
- lines[i] = lines[i].sub(indent, "")
221
- end
222
- end
223
- lines.join("\n")
224
- end
225
-
226
- def self.save_photo(url, ext)
227
- if @grab_images
228
- path = "tumblr_files/#{url.split('/').last}"
229
- path += ext unless path =~ /#{ext}$/
230
- FileUtils.mkdir_p "tumblr_files"
231
-
232
- # Don't fetch if we've already cached this file
233
- unless File.size? path
234
- puts "Fetching photo #{url}"
235
- File.open(path, "w") { |f| f.write(open(url).read) }
236
- end
237
- url = "/" + path
238
- end
239
- url
240
- end
241
- end
242
- end
@@ -1,69 +0,0 @@
1
- # Author: Toby DiPasquale <toby@cbcg.net>
2
- require 'fileutils'
3
- require 'rubygems'
4
- require 'sequel'
5
- require 'safe_yaml'
6
-
7
- module JekyllImport
8
- module Typo
9
- # This SQL *should* work for both MySQL and PostgreSQL.
10
- SQL = <<-EOS
11
- SELECT c.id id,
12
- c.title title,
13
- c.permalink slug,
14
- c.body body,
15
- c.extended extended,
16
- c.published_at date,
17
- c.state state,
18
- c.keywords keywords,
19
- COALESCE(tf.name, 'html') filter
20
- FROM contents c
21
- LEFT OUTER JOIN text_filters tf
22
- ON c.text_filter_id = tf.id
23
- EOS
24
-
25
- def self.process server, dbname, user, pass, host='localhost'
26
- FileUtils.mkdir_p '_posts'
27
- case server.intern
28
- when :postgres
29
- db = Sequel.postgres(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
30
- when :mysql
31
- db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
32
- else
33
- raise "Unknown database server '#{server}'"
34
- end
35
- db[SQL].each do |post|
36
- next unless post[:state] =~ /published/i
37
-
38
- if post[:slug] == nil
39
- post[:slug] = "no slug"
40
- end
41
-
42
- if post[:extended]
43
- post[:body] << "\n<!-- more -->\n"
44
- post[:body] << post[:extended]
45
- end
46
-
47
- name = [ sprintf("%.04d", post[:date].year),
48
- sprintf("%.02d", post[:date].month),
49
- sprintf("%.02d", post[:date].day),
50
- post[:slug].strip ].join('-')
51
-
52
- # Can have more than one text filter in this field, but we just want
53
- # the first one for this.
54
- name += '.' + post[:filter].split(' ')[0]
55
-
56
- File.open("_posts/#{name}", 'w') do |f|
57
- f.puts({ 'layout' => 'post',
58
- 'title' => (post[:title] and post[:title].to_s.force_encoding('UTF-8')),
59
- 'tags' => (post[:keywords] and post[:keywords].to_s.force_encoding('UTF-8')),
60
- 'typo_id' => post[:id]
61
- }.delete_if { |k, v| v.nil? || v == '' }.to_yaml)
62
- f.puts '---'
63
- f.puts post[:body].delete("\r")
64
- end
65
- end
66
- end
67
-
68
- end
69
- end
@@ -1,299 +0,0 @@
1
- require 'rubygems'
2
- require 'sequel'
3
- require 'fileutils'
4
- require 'safe_yaml'
5
-
6
- # NOTE: This converter requires Sequel and the MySQL gems.
7
- # The MySQL gem can be difficult to install on OS X. Once you have MySQL
8
- # installed, running the following commands should work:
9
- # $ sudo gem install sequel
10
- # $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
11
-
12
- module JekyllImport
13
- module WordPress
14
-
15
- # Main migrator function. Call this to perform the migration.
16
- #
17
- # dbname:: The name of the database
18
- # user:: The database user name
19
- # pass:: The database user's password
20
- # host:: The address of the MySQL database host. Default: 'localhost'
21
- # options:: A hash table of configuration options.
22
- #
23
- # Supported options are:
24
- #
25
- # :table_prefix:: Prefix of database tables used by WordPress.
26
- # Default: 'wp_'
27
- # :clean_entities:: If true, convert non-ASCII characters to HTML
28
- # entities in the posts, comments, titles, and
29
- # names. Requires the 'htmlentities' gem to
30
- # work. Default: true.
31
- # :comments:: If true, migrate post comments too. Comments
32
- # are saved in the post's YAML front matter.
33
- # Default: true.
34
- # :categories:: If true, save the post's categories in its
35
- # YAML front matter.
36
- # :tags:: If true, save the post's tags in its
37
- # YAML front matter.
38
- # :more_excerpt:: If true, when a post has no excerpt but
39
- # does have a <!-- more --> tag, use the
40
- # preceding post content as the excerpt.
41
- # Default: true.
42
- # :more_anchor:: If true, convert a <!-- more --> tag into
43
- # two HTML anchors with ids "more" and
44
- # "more-NNN" (where NNN is the post number).
45
- # Default: true.
46
- # :status:: Array of allowed post statuses. Only
47
- # posts with matching status will be migrated.
48
- # Known statuses are :publish, :draft, :private,
49
- # and :revision. If this is nil or an empty
50
- # array, all posts are migrated regardless of
51
- # status. Default: [:publish].
52
- #
53
- def self.process(options={})
54
- options = {
55
- :user => '',
56
- :pass => '',
57
- :host => 'localhost',
58
- :dbname => '',
59
- :table_prefix => 'wp_',
60
- :clean_entities => true,
61
- :comments => true,
62
- :categories => true,
63
- :tags => true,
64
- :more_excerpt => true,
65
- :more_anchor => true,
66
- :status => [:publish] # :draft, :private, :revision
67
- }.merge(options)
68
-
69
- if options[:clean_entities]
70
- begin
71
- require 'htmlentities'
72
- rescue LoadError
73
- STDERR.puts "Could not require 'htmlentities', so the " +
74
- ":clean_entities option is now disabled."
75
- options[:clean_entities] = false
76
- end
77
- end
78
-
79
- FileUtils.mkdir_p("_posts")
80
-
81
- db = Sequel.mysql2(options[:dbname], :user => options[:user], :password => options[:pass],
82
- :host => options[:host], :encoding => 'utf8')
83
-
84
- px = options[:table_prefix]
85
-
86
- posts_query = "
87
- SELECT
88
- posts.ID AS `id`,
89
- posts.guid AS `guid`,
90
- posts.post_type AS `type`,
91
- posts.post_status AS `status`,
92
- posts.post_title AS `title`,
93
- posts.post_name AS `slug`,
94
- posts.post_date AS `date`,
95
- posts.post_content AS `content`,
96
- posts.post_excerpt AS `excerpt`,
97
- posts.comment_count AS `comment_count`,
98
- users.display_name AS `author`,
99
- users.user_login AS `author_login`,
100
- users.user_email AS `author_email`,
101
- users.user_url AS `author_url`
102
- FROM #{px}posts AS `posts`
103
- LEFT JOIN #{px}users AS `users`
104
- ON posts.post_author = users.ID"
105
-
106
- if options[:status] and not options[:status].empty?
107
- status = options[:status][0]
108
- posts_query << "
109
- WHERE posts.post_status = '#{status.to_s}'"
110
- options[:status][1..-1].each do |status|
111
- posts_query << " OR
112
- posts.post_status = '#{status.to_s}'"
113
- end
114
- end
115
-
116
- db[posts_query].each do |post|
117
- process_post(post, db, options)
118
- end
119
- end
120
-
121
-
122
- def self.process_post(post, db, options)
123
- px = options[:table_prefix]
124
-
125
- title = post[:title]
126
- if options[:clean_entities]
127
- title = clean_entities(title)
128
- end
129
-
130
- slug = post[:slug]
131
- if !slug or slug.empty?
132
- slug = sluggify(title)
133
- end
134
-
135
- date = post[:date] || Time.now
136
- name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month,
137
- date.day, slug]
138
- content = post[:content].to_s
139
- if options[:clean_entities]
140
- content = clean_entities(content)
141
- end
142
-
143
- excerpt = post[:excerpt].to_s
144
-
145
- more_index = content.index(/<!-- *more *-->/)
146
- more_anchor = nil
147
- if more_index
148
- if options[:more_excerpt] and
149
- (post[:excerpt].nil? or post[:excerpt].empty?)
150
- excerpt = content[0...more_index]
151
- end
152
- if options[:more_anchor]
153
- more_link = "more"
154
- content.sub!(/<!-- *more *-->/,
155
- "<a id=\"more\"></a>" +
156
- "<a id=\"more-#{post[:id]}\"></a>")
157
- end
158
- end
159
-
160
- categories = []
161
- tags = []
162
-
163
- if options[:categories] or options[:tags]
164
-
165
- cquery =
166
- "SELECT
167
- terms.name AS `name`,
168
- ttax.taxonomy AS `type`
169
- FROM
170
- #{px}terms AS `terms`,
171
- #{px}term_relationships AS `trels`,
172
- #{px}term_taxonomy AS `ttax`
173
- WHERE
174
- trels.object_id = '#{post[:id]}' AND
175
- trels.term_taxonomy_id = ttax.term_taxonomy_id AND
176
- terms.term_id = ttax.term_id"
177
-
178
- db[cquery].each do |term|
179
- if options[:categories] and term[:type] == "category"
180
- if options[:clean_entities]
181
- categories << clean_entities(term[:name])
182
- else
183
- categories << term[:name]
184
- end
185
- elsif options[:tags] and term[:type] == "post_tag"
186
- if options[:clean_entities]
187
- tags << clean_entities(term[:name])
188
- else
189
- tags << term[:name]
190
- end
191
- end
192
- end
193
- end
194
-
195
- comments = []
196
-
197
- if options[:comments] and post[:comment_count].to_i > 0
198
- cquery =
199
- "SELECT
200
- comment_ID AS `id`,
201
- comment_author AS `author`,
202
- comment_author_email AS `author_email`,
203
- comment_author_url AS `author_url`,
204
- comment_date AS `date`,
205
- comment_date_gmt AS `date_gmt`,
206
- comment_content AS `content`
207
- FROM #{px}comments
208
- WHERE
209
- comment_post_ID = '#{post[:id]}' AND
210
- comment_approved != 'spam'"
211
-
212
-
213
- db[cquery].each do |comment|
214
-
215
- comcontent = comment[:content].to_s
216
- if comcontent.respond_to?(:force_encoding)
217
- comcontent.force_encoding("UTF-8")
218
- end
219
- if options[:clean_entities]
220
- comcontent = clean_entities(comcontent)
221
- end
222
- comauthor = comment[:author].to_s
223
- if options[:clean_entities]
224
- comauthor = clean_entities(comauthor)
225
- end
226
-
227
- comments << {
228
- 'id' => comment[:id].to_i,
229
- 'author' => comauthor,
230
- 'author_email' => comment[:author_email].to_s,
231
- 'author_url' => comment[:author_url].to_s,
232
- 'date' => comment[:date].to_s,
233
- 'date_gmt' => comment[:date_gmt].to_s,
234
- 'content' => comcontent,
235
- }
236
- end
237
-
238
- comments.sort!{ |a,b| a['id'] <=> b['id'] }
239
- end
240
-
241
- # Get the relevant fields as a hash, delete empty fields and
242
- # convert to YAML for the header.
243
- data = {
244
- 'layout' => post[:type].to_s,
245
- 'status' => post[:status].to_s,
246
- 'published' => (post[:status].to_s == "publish"),
247
- 'title' => title.to_s,
248
- 'author' => post[:author].to_s,
249
- 'author_login' => post[:author_login].to_s,
250
- 'author_email' => post[:author_email].to_s,
251
- 'author_url' => post[:author_url].to_s,
252
- 'excerpt' => excerpt,
253
- 'more_anchor' => more_anchor,
254
- 'wordpress_id' => post[:id],
255
- 'wordpress_url' => post[:guid].to_s,
256
- 'date' => date,
257
- 'categories' => options[:categories] ? categories : nil,
258
- 'tags' => options[:tags] ? tags : nil,
259
- 'comments' => options[:comments] ? comments : nil,
260
- }.delete_if { |k,v| v.nil? || v == '' }.to_yaml
261
-
262
- # Write out the data and content to file
263
- File.open("_posts/#{name}", "w") do |f|
264
- f.puts data
265
- f.puts "---"
266
- f.puts content
267
- end
268
- end
269
-
270
-
271
- def self.clean_entities( text )
272
- if text.respond_to?(:force_encoding)
273
- text.force_encoding("UTF-8")
274
- end
275
- text = HTMLEntities.new.encode(text, :named)
276
- # We don't want to convert these, it would break all
277
- # HTML tags in the post and comments.
278
- text.gsub!("&amp;", "&")
279
- text.gsub!("&lt;", "<")
280
- text.gsub!("&gt;", ">")
281
- text.gsub!("&quot;", '"')
282
- text.gsub!("&apos;", "'")
283
- text.gsub!("/", "&#47;")
284
- text
285
- end
286
-
287
-
288
- def self.sluggify( title )
289
- begin
290
- require 'unidecode'
291
- title = title.to_ascii
292
- rescue LoadError
293
- STDERR.puts "Could not require 'unidecode'. If your post titles have non-ASCII characters, you could get nicer permalinks by installing unidecode."
294
- end
295
- title.downcase.gsub(/[^0-9A-Za-z]+/, " ").strip.gsub(" ", "-")
296
- end
297
-
298
- end
299
- end