typepad_to_jekyll 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ License Terms
2
+ =============
3
+
4
+ Distributed under the user's choice of the [GPL Version 2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) (see COPYING for details) or the
5
+ [Ruby software license](http://www.ruby-lang.org/en/LICENSE.txt) by
6
+ Chris Stansbury.
7
+
8
+ Feel free to email [Chris Stansbury](mailto:chris@koozie.org) with any questions.
@@ -0,0 +1,47 @@
1
+ Typepad to Jekyll
2
+ =================
3
+
4
+ by Chris Stansbury
5
+
6
+ Description
7
+ -----------
8
+
9
+ TypepadToJekyll is a Ruby command line application to convert a MoveableType or Typepad blog
10
+ backup file, [MTIF format], into Jekyll blog posts. Post files will be stored in the _posts
11
+ and the _drafts sub directories under your jekyll directory.
12
+
13
+
14
+ Install
15
+ -------
16
+
17
+
18
+ gem install typepad_to_jekyll
19
+ gem install thor
20
+
21
+
22
+ Examples
23
+ --------
24
+
25
+ $ typepad_to jekyll <typepad_backup_filename> <jekyll_directory>
26
+
27
+
28
+ Requirements
29
+ ------------
30
+
31
+ Ruby
32
+ Ruby Gems: Thor
33
+
34
+
35
+ Supported Platforms
36
+ -------------------
37
+
38
+ Known to work on
39
+
40
+ 1.9.3
41
+
42
+
43
+
44
+ Questions and/or Comments
45
+ -------------------------
46
+
47
+ Feel free to email [Chris Stansbury](mailto:chris@koozie.org) with any questions.
@@ -0,0 +1,19 @@
1
+
2
+ require "rake/testtask"
3
+ require "rake/clean"
4
+
5
+ CLEAN.include('*.gem')
6
+ CLOBBER.include(FileList['.yardoc/*','doc/*'].exclude('.gitignore'))
7
+
8
+ task :default => [:test]
9
+
10
+ Rake::TestTask.new do |test|
11
+ test.libs << "test"
12
+ test.test_files = Dir[ "test/test_*.rb" ]
13
+ test.verbose = true
14
+ end
15
+
16
+ desc "Build Gem"
17
+ task :build do
18
+ sh "gem build typepad_to_jekyll.gemspec"
19
+ end
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
4
+
5
+ require 'typepad_to_jekyll'
6
+ require 'thor'
7
+
8
+
9
+ class Application < Thor
10
+
11
+ attr_reader :jekyll_dir, :posts_dir, :drafts_dir
12
+
13
+ desc "jekyll BACKUP DIRECTORY", "Convert Typepad Backup file to Jekyll blog posts and store in _posts sub directory"
14
+ long_desc <<-LONGDESC
15
+ `typepad_to jekyll` will parse a TypePad backup file in the MTIF file format and genereate blog posts
16
+ which will be stored in the jekyll sub directory of _posts of _drafts.
17
+
18
+ typepad_to jekyll BACKUP JEKYLL-DIRECTORY
19
+ \x5 BACKUP: the filename of your TypePad backup file.
20
+ \x5 JEKYLL-DIRECTORY: path to your Jekyll directory.
21
+ LONGDESC
22
+ def jekyll(typepad_backup_filename, jekyll_directory)
23
+ abort "ERROR: [#{jekyll_directory}] is not a directory. " unless File.directory?(jekyll_directory)
24
+ app = TypepadToJekyll::Converter.new(typepad_backup_filename, jekyll_directory)
25
+ app.process
26
+ end
27
+
28
+ private
29
+ end
30
+
31
+ Application.start(ARGV)
32
+
33
+
34
+
@@ -0,0 +1,12 @@
1
+
2
+
3
+
4
+ module TypepadToJekyll
5
+ VERSION = "0.0.1".freeze if not defined?(TypepadToJekyll::VERSION)
6
+ end
7
+
8
+ require 'typepad_to_jekyll/post'
9
+ require 'typepad_to_jekyll/parser'
10
+ require 'typepad_to_jekyll/converter'
11
+
12
+
@@ -0,0 +1,58 @@
1
+ require 'fileutils'
2
+
3
+ module TypepadToJekyll
4
+
5
+ # Convert Typepad Backup (MTIF Format) to
6
+ # Jekyll posts. MTIF -> Jekyll _posts
7
+ class Converter
8
+ attr_reader :jekyll_base_dir, :posts_dir, :drafts_dir
9
+ attr_reader :typepad_backup_filename
10
+ attr_accessor :posts
11
+
12
+ def initialize(backup_filename, jekyll_base_directory)
13
+ @typepad_backup_filename = backup_filename
14
+ @jekyll_base_dir = jekyll_base_directory
15
+ @posts_dir = File.join(jekyll_base_dir, '_posts')
16
+ @drafts_dir = File.join(jekyll_base_dir, '_drafts')
17
+ @posts = []
18
+ end
19
+
20
+ def process
21
+ setup_sub_dirs
22
+ parse_backup_file
23
+ write_posts
24
+ end
25
+
26
+ private
27
+
28
+ def parse_backup_file
29
+ app = TypepadToJekyll::Parser.new
30
+ app.source_filename = typepad_backup_filename
31
+ app.process
32
+ @posts = app.posts
33
+ end
34
+
35
+ #write post to _posts directory in jekyll format
36
+ def write_posts
37
+ posts.each do |post|
38
+ if post.status == :publish
39
+ dir = posts_dir
40
+ else
41
+ dir = drafts_dir
42
+ end
43
+ fname = File.join(dir, post.filename)
44
+ File.open(fname, 'w') do |file|
45
+ file.puts post.to_jekyll
46
+ end
47
+ end
48
+ end
49
+
50
+ def setup_sub_dirs
51
+ dirs = [posts_dir, drafts_dir]
52
+ dirs.each do |dir|
53
+ FileUtils.mkdir_p(dir) if not File.directory?(dir)
54
+ end
55
+ end
56
+
57
+ end # class
58
+ end # module
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require 'date'
5
+
6
+ module TypepadToJekyll
7
+
8
+ # Convert Typepad Backup (MTIF Format) to
9
+ # Jekyll posts. MTIF -> Jekyll _posts
10
+ class Parser
11
+
12
+ attr_accessor :source_filename
13
+ attr_reader :import_status, :current_line, :last_line
14
+ attr_reader :current_post, :posts
15
+ attr_reader :current_comment
16
+
17
+ def initialize
18
+ setup
19
+ end
20
+
21
+ def process
22
+ setup
23
+ process_typepad_file
24
+ end
25
+
26
+ private
27
+
28
+ def process_typepad_file
29
+ new_post
30
+ File.open(source_filename,'r') do |file|
31
+ file.each do |line|
32
+ @last_line = current_line
33
+ @current_line = line
34
+ process_line
35
+ end
36
+ end
37
+ end
38
+
39
+ def new_post
40
+ @import_status = :post_header #:post_header, :body, :extended_body, :excerpt, :keywords, :boundary_5
41
+ @current_post = Post.new
42
+ end
43
+
44
+ def check_boundary
45
+ @import_status = :boundary_5 if current_line =~ /^-----/
46
+ @import_status = :boundary_7 if current_line =~ /^-------/
47
+ end
48
+
49
+ def process_line
50
+ check_boundary
51
+ case import_status
52
+ when :post_header
53
+ process_header_line
54
+ when :comment_header
55
+ process_comment_line
56
+ when :comment_body
57
+ process_comment_body
58
+ when :body
59
+ process_body
60
+ when :extended_body
61
+ process_extended_body
62
+ when :excerpt
63
+ process_excerpt
64
+ when :boundary_7
65
+ #write_post
66
+ posts << current_post
67
+ new_post
68
+ when :boundary_5
69
+ process_boundary5_item
70
+ end
71
+ end
72
+
73
+ def process_boundary5_item
74
+ case current_line
75
+ when /^BODY/
76
+ @import_status = :body
77
+ when /^EXTENDED BODY/
78
+ @import_status = :extended_body
79
+ when /^EXCERPT/
80
+ @import_status = :excerpt
81
+ when /^KEYWORDS/
82
+ @import_status = :keywords
83
+ when /^COMMENT/
84
+ @import_status = :comment_header
85
+ @current_comment = current_post.new_comment
86
+ end
87
+ end
88
+
89
+ def process_body
90
+ current_post.body += current_line
91
+ end
92
+
93
+ def process_extended_body
94
+ current_post.extended_body += current_line
95
+ end
96
+
97
+ def process_excerpt
98
+ current_post.excerpt += current_line if current_line.strip.chomp.size > 0
99
+ end
100
+
101
+ def process_comment_body
102
+ current_comment.body += current_line
103
+ end
104
+
105
+ def process_comment_line
106
+ return if current_line.strip == ""
107
+ case current_line
108
+ when /^AUTHOR/
109
+ current_comment.author = current_line.split('AUTHOR:').last.strip
110
+ when /^EMAIL/
111
+ current_comment.email = current_line.split('EMAIL:').last.strip
112
+ when /^IP/
113
+ current_comment.ip = current_line.split('IP:').last.strip
114
+ when /^URL/
115
+ current_comment.url = current_line.split('URL:').last.strip
116
+ when /^DATE/
117
+ d_str = current_line.split('DATE:').last.strip
118
+ current_comment.date = DateTime.strptime(d_str, "%m/%d/%Y %I:%M:%S %p")
119
+ @import_status = :comment_body #comment body follows directly after comment date
120
+ end
121
+ end
122
+
123
+ def process_header_line
124
+ return if current_line.strip == ""
125
+ case current_line
126
+ when /^AUTHOR/
127
+ current_post.author = current_line.split('AUTHOR:').last.strip
128
+ when /^TITLE/
129
+ current_post.title = current_line.split('TITLE:').last.strip
130
+ when /^STATUS/
131
+ current_post.status = current_line.split('STATUS:').last.strip.downcase.to_sym
132
+ when /^ALLOW COMMENTS/
133
+ current_post.allow_comments = current_line.split('ALLOW COMMENTS:').last.strip == '1' ? true : false
134
+ when /^CONVERT BREAKS/
135
+ current_post.convert_breaks = current_line.split('CONVERT BREAKS:').last.strip
136
+ when /^ALLOW PINGS/
137
+ current_post.allow_pings = current_line.split('ALLOW PINGS:').last.strip == '1' ? true : false
138
+ when /^BASENAME/
139
+ current_post.basename = current_line.split('BASENAME:').last.strip
140
+ when /^CATEGORY/
141
+ category_name = current_line.split('CATEGORY:').last.strip
142
+ current_post.categories << clean_category_name(category_name)
143
+ when /^UNIQUE URL/
144
+ current_post.unique_url = current_line.split('UNIQUE URL:').last.strip
145
+ when /^DATE/
146
+ d_str = current_line.split('DATE:').last.strip
147
+ current_post.date = DateTime.strptime(d_str, "%m/%d/%Y %I:%M:%S %p")
148
+ end
149
+ end
150
+
151
+ def clean_category_name(cat)
152
+ cat.downcase.gsub(/ /,'-')
153
+ end
154
+
155
+ def setup
156
+ @posts = []
157
+ @current_line = ''
158
+ @last_line = ''
159
+ end
160
+
161
+ end # class
162
+ end # module
163
+
164
+ __END__
165
+
166
+
167
+ dirs = [destination_dir, posts_dir, drafts_dir]
168
+ dirs.each do |dir|
169
+ if not File.directory?(dir)
170
+ puts "Not a directory [#{dir}]"
171
+ exit 1
172
+ end
173
+ end
174
+
175
+
176
+
177
+
178
+
179
+ #write post to _posts directory in jekyll format
180
+ def write_post
181
+ if current_post.status == :publish
182
+ dir = posts_dir
183
+ else
184
+ dir = drafts_dir
185
+ end
186
+ fname = File.join(dir, current_post.filename)
187
+ File.open(fname, 'w') do |file|
188
+ file.puts current_post.to_yaml
189
+ end
190
+ end
191
+
@@ -0,0 +1,68 @@
1
+ module TypepadToJekyll
2
+ class Comment
3
+ attr_accessor :author, :email, :ip, :url, :date, :body
4
+
5
+ def initialize
6
+ @body = ''
7
+ end
8
+ end
9
+ end
10
+
11
+
12
+ module TypepadToJekyll
13
+ class Post
14
+ attr_accessor :author, :title, :status, :allow_comments, :convert_breaks
15
+ attr_accessor :allow_pings, :basename, :unique_url, :date, :body
16
+ attr_accessor :extended_body, :excerpt
17
+
18
+ attr_reader :categories, :keywords, :comments
19
+
20
+ def initialize
21
+ @categories = []
22
+ @keywords = []
23
+ @comments = []
24
+ @body = ''
25
+ @extended_body = ''
26
+ @excerpt = ''
27
+ end
28
+
29
+ def filename
30
+ "#{date.strftime("%Y-%m-%d")}-#{basename}.html"
31
+ end
32
+
33
+ def to_jekyll
34
+ str = []
35
+ str << '---'
36
+ str << 'layout: post'
37
+ str << 'title: ' + clean_yaml(title)
38
+ str << "date: #{date.strftime("%Y-%m-%d %H:%M:%S")}"
39
+ if categories.size == 1
40
+ str << "category: #{categories.first}"
41
+ elsif categories.size > 1
42
+ str << "categories: #{categories.join(' ')}"
43
+ end
44
+ str << '---'
45
+ str << body
46
+ str << extended_body
47
+
48
+ return str.join("\n")
49
+ end
50
+
51
+ #handle colons, quotes, and double quotes in string
52
+ def clean_yaml(str)
53
+ if str.include?(':') or str.include?("'") or str.include?('"')
54
+ #return "'" + str.gsub(/"/, '\"').gsub(/'/, "''") + "'"
55
+ return "'" + str.gsub(/'/, "''") + "'"
56
+ else
57
+ return str
58
+ end
59
+ end
60
+
61
+ def new_comment
62
+ c = Comment.new
63
+ comments << c
64
+ return c
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,113 @@
1
+ AUTHOR: Chris
2
+ TITLE: First Post
3
+ STATUS: Draft
4
+ ALLOW COMMENTS: 1
5
+ CONVERT BREAKS: __default__
6
+ ALLOW PINGS: 0
7
+ BASENAME: first_post
8
+
9
+ UNIQUE URL: http://www.example.org/2003/05/first_post.html
10
+ DATE: 05/29/2003 01:02:06 AM
11
+ -----
12
+ BODY:
13
+ <p>This should be my first post to Moveable Type. I'm still trying to figure this system out. </p>
14
+
15
+ <p>Jerry</p>
16
+ -----
17
+ EXTENDED BODY:
18
+ <p>IDEAS:</p>
19
+
20
+ <p>crayons<br />
21
+ Good Technology<br />
22
+ ONIX File Format<br />
23
+ 419 Scams<br />
24
+ Blat Utility<br />
25
+ Digital Camera Stuff</p>
26
+ -----
27
+ EXCERPT:
28
+
29
+ -----
30
+ KEYWORDS:
31
+
32
+ -----
33
+ COMMENT:
34
+ AUTHOR: Troy Aikman
35
+ EMAIL: troy@example.com
36
+ IP: 208.201.230.101
37
+ URL: http://troy.example.com/
38
+ DATE: 05/30/2003 01:32:14 PM
39
+ Easy, ain't it? :)
40
+ laters
41
+ -----
42
+ --------
43
+ AUTHOR: John Franklin McEnroe
44
+ TITLE: Home Wi-Fi
45
+ STATUS: Publish
46
+ ALLOW COMMENTS: 1
47
+ CONVERT BREAKS: __default__
48
+ ALLOW PINGS: 1
49
+ BASENAME: home_wifi
50
+ CATEGORY: Hardware
51
+
52
+ UNIQUE URL: http://blog.example.org/2003/01/home_wifi.html
53
+ DATE: 01/10/2003 01:39:35 PM
54
+ -----
55
+ BODY:
56
+ <p>I put in <a href="http://www.linksys.com/Products/product.asp?grid=33&scid=35&prid=508">Linksys wireless router/access point</a> on my home network one week ago. I quickly configured the router using its web based configuration tool. I've also been able to get a descent signal ALL over the house.</p>
57
+
58
+ <p>Wireless is just plain cool. I can't believe I waited so long to use it. </p>
59
+
60
+ <p>-Chris</p>
61
+ -----
62
+ EXTENDED BODY:
63
+
64
+ -----
65
+ EXCERPT:
66
+
67
+ -----
68
+ KEYWORDS:
69
+
70
+ -----
71
+ COMMENT:
72
+ AUTHOR: Fred Mike Jones
73
+ EMAIL: fmj@example.com
74
+ IP: 68.166.91.157
75
+ URL: http://www.example.com/blog
76
+ DATE: 08/10/2003 02:54:44 PM
77
+ Yeah, wireless is the way to go. Mrs. Noded has here own laptop. It makes it so much easier. Here, there and everywhere.
78
+
79
+ You posting from the backyard?
80
+ -----
81
+ COMMENT:
82
+ AUTHOR: mike
83
+ EMAIL: mike@example.org
84
+ IP: 65.70.200.35
85
+ URL: http://www.example.org
86
+ DATE: 08/10/2003 03:17:23 PM
87
+ It's to freaking HOT here to be outside longer than 5 minutes. We had tempeartures up to 108 degrees. Maybe I'll try the outside thing this fall.
88
+ -----
89
+ COMMENT:
90
+ AUTHOR: mike
91
+ EMAIL: mike@example.net
92
+ IP: 193.195.87.146
93
+ URL: http://example.net
94
+ DATE: 08/12/2003 08:58:00 AM
95
+ Just wait until your wireless access point dies (just like mine did this week) and then you REALLY realise how much you thought of it. I got good coverage all over the house and the garden. Now I'm stuck to sitting in the office tied by a long piece of cat5 cable :-(
96
+ -----
97
+ COMMENT:
98
+ AUTHOR: Mike
99
+ EMAIL: mike@example.org
100
+ IP: 207.8.15.210
101
+ URL: http://www.example.org
102
+ DATE: 08/12/2003 12:07:13 PM
103
+ Before I had wireless, I connected two 25' cat5 cables together so I could work in the living room instead of the office. :-)
104
+ -----
105
+ COMMENT:
106
+ AUTHOR: Jerry McGuire
107
+ EMAIL: blog@example.net
108
+ IP: 81.86.172.239
109
+ URL: http://example.net
110
+ DATE: 08/13/2003 04:00:09 AM
111
+ I had something similar - a LONG piece of cable through a hole drilled in the ceiling from the upstairs office into the living room and then coiled in a big loop so it would reach anywhere downstairs if stretched across the room....that changed when I got married :-)
112
+ -----
113
+ --------
@@ -0,0 +1,43 @@
1
+ AUTHOR: Chris
2
+ TITLE: First Post
3
+ STATUS: Draft
4
+ ALLOW COMMENTS: 1
5
+ CONVERT BREAKS: __default__
6
+ ALLOW PINGS: 0
7
+ BASENAME: first_post
8
+
9
+ UNIQUE URL: http://www.example.org/2003/05/first_post.html
10
+ DATE: 05/29/2003 01:02:06 AM
11
+ -----
12
+ BODY:
13
+ <p>This should be my first post to Moveable Type. I'm still trying to figure this system out. </p>
14
+
15
+ <p>Jerry</p>
16
+ -----
17
+ EXTENDED BODY:
18
+ <p>IDEAS:</p>
19
+
20
+ <p>crayons<br />
21
+ Good Technology<br />
22
+ ONIX File Format<br />
23
+ 419 Scams<br />
24
+ Blat Utility<br />
25
+ Digital Camera Stuff</p>
26
+ -----
27
+ EXCERPT:
28
+
29
+ -----
30
+ KEYWORDS:
31
+
32
+ -----
33
+ COMMENT:
34
+ AUTHOR: Troy Aikman
35
+ EMAIL: troy@example.com
36
+ IP: 208.201.230.101
37
+ URL: http://troy.example.com/
38
+ DATE: 05/30/2003 01:32:14 PM
39
+ Easy, ain't it? :)
40
+ laters
41
+ -----
42
+ --------
43
+
@@ -0,0 +1,103 @@
1
+ AUTHOR: Frank
2
+ TITLE: Junk Faxes: Redux
3
+ STATUS: Draft
4
+ ALLOW COMMENTS: 1
5
+ CONVERT BREAKS: __default__
6
+ ALLOW PINGS: 1
7
+ BASENAME: junk_faxes
8
+ CATEGORY: SPAM
9
+
10
+ UNIQUE URL: http://www.koozie.org/2003/11/junk_faxes.html
11
+ DATE: 11/06/2003 05:04:49 PM
12
+ -----
13
+ BODY:
14
+ <p>I found some interesting sites today about the piles and piles of junk faxes I seemed to be collecting these days.</p>
15
+
16
+ <p>800-390-1403 is the so-called removal number.</p>
17
+
18
+ <p>1st ad 800-891-2682 Medical Insurance<br />
19
+ 2nd ad pumps some stocks, by OTC Analysis.</p>
20
+
21
+ <p>http://www.junkfaxes.org/</p>
22
+ -----
23
+ EXTENDED BODY:
24
+
25
+ -----
26
+ EXCERPT:
27
+
28
+ -----
29
+ KEYWORDS:
30
+
31
+ -----
32
+ --------
33
+ AUTHOR: Chris
34
+ TITLE: All about Frank's "MIDI" Files
35
+ STATUS: Publish
36
+ ALLOW COMMENTS: 1
37
+ CONVERT BREAKS: __default__
38
+ ALLOW PINGS: 1
39
+ BASENAME: midi_files
40
+ CATEGORY: General IT
41
+ CATEGORY: Programming
42
+
43
+ UNIQUE URL: http://www.koozie.org/2003/11/midi_files.html
44
+ DATE: 11/04/2003 12:07:24 PM
45
+ -----
46
+ BODY:
47
+ <p>I've been busy at work and at home with two daughters, wife and dog. I have managed to squeeze in some playing time on the new piano. I found a couple of articles to help me understand midi files, which is how music is stored in my digital piano. The best analogy I found on describing midi was midi files are like music paper rolls for player pianos.</p>
48
+
49
+ <p>-Chris</p>
50
+
51
+ <p><a href="http://mp3.about.com/library/weekly/aa021797.htm">What is MIDI, Anyway?</a></p>
52
+
53
+ <p><a href="http://mp3.about.com/library/weekly/aa072699.htm">MIDI and MP3: What's the Difference?</a></p>
54
+
55
+ <p><a href="http://mp3.about.com/b/a/037484.htm">How to Convert MIDI to MP3 or CD</a></p>
56
+ -----
57
+ EXTENDED BODY:
58
+
59
+ -----
60
+ EXCERPT:
61
+
62
+ -----
63
+ KEYWORDS:
64
+
65
+ -----
66
+ --------
67
+ AUTHOR: Chris
68
+ TITLE: Comment Spam: Here it comes again, Sue's List of "Crazy" Items
69
+ STATUS: Publish
70
+ ALLOW COMMENTS: 1
71
+ CONVERT BREAKS: __default__
72
+ ALLOW PINGS: 1
73
+ BASENAME: first_comment_s
74
+ CATEGORY: General IT
75
+
76
+ UNIQUE URL: http://www.koozie.org/2003/11/first_comment_s.html
77
+ DATE: 11/04/2003 11:54:18 AM
78
+ -----
79
+ BODY:
80
+ <p>I finally received my first comment spam on MT.</p>
81
+
82
+ <blockquote>
83
+ IP Address: 209.208.9.254
84
+ Name: debt-consolidation
85
+ Email Address: gangastrotagati[at]yahoo.com
86
+ URL: http://www.karmicdebtconsolidation[dot]com/
87
+
88
+ <p>Comments:</p>
89
+
90
+ <p>Marvelous<br />
91
+
92
+
93
+ -----
94
+ EXTENDED BODY:
95
+
96
+ -----
97
+ EXCERPT:
98
+
99
+ -----
100
+ KEYWORDS:
101
+
102
+ -----
103
+ --------
@@ -0,0 +1,123 @@
1
+ gem 'minitest'
2
+ require 'minitest/autorun'
3
+ require 'typepad_to_jekyll'
4
+
5
+ class ParserTestOne < Minitest::Test
6
+
7
+ def setup
8
+ @fn = File.join(File.dirname(__FILE__),'data','typepad_one_post.txt')
9
+ @app = TypepadToJekyll::Parser.new
10
+ @app.source_filename = @fn
11
+ @app.process
12
+ end
13
+
14
+ def test_one_post_front_matter
15
+ assert_equal @fn, @app.source_filename
16
+
17
+ post = @app.posts.first
18
+ assert_equal 'Chris', post.author
19
+ assert_equal 'First Post', post.title
20
+ assert_equal :draft, post.status
21
+ assert_equal 'http://www.example.org/2003/05/first_post.html', post.unique_url
22
+ assert_equal '05/29/2003 01:02:06 AM', post.date.strftime("%m/%d/%Y %I:%M:%S %p")
23
+ end
24
+
25
+ def test_comment_one_post
26
+ post = @app.posts.first
27
+ assert_equal 1, post.comments.size
28
+ comment = post.comments.first
29
+ assert_equal 'Troy Aikman', comment.author
30
+ assert_equal 'troy@example.com', comment.email
31
+ assert_equal '208.201.230.101', comment.ip
32
+ assert_equal '05/30/2003 01:32:14 PM', comment.date.strftime("%m/%d/%Y %I:%M:%S %p")
33
+ assert_equal "Easy, ain't it? :)\nlaters\n", comment.body
34
+ end
35
+ end
36
+
37
+ class ParserTestMultilePosts < Minitest::Test
38
+ def setup
39
+ @fn = File.join(File.dirname(__FILE__),'data','typepad_multiple_posts.txt')
40
+ @app = TypepadToJekyll::Parser.new
41
+ @app.source_filename = @fn
42
+ @app.process
43
+ end
44
+
45
+ def test_last_post_front_matter
46
+ post = @app.posts.last
47
+ assert_equal 'John Franklin McEnroe', post.author
48
+ assert_equal 'Home Wi-Fi', post.title
49
+ assert_equal :publish, post.status
50
+ assert_equal 'http://blog.example.org/2003/01/home_wifi.html', post.unique_url
51
+ assert_equal '01/10/2003 01:39:35 PM', post.date.strftime("%m/%d/%Y %I:%M:%S %p")
52
+ end
53
+
54
+ def test_all_comments_parse_last_post
55
+ post = @app.posts.last
56
+ assert_equal 5, post.comments.size
57
+ end
58
+
59
+ def test_last_comment_from_last_post
60
+ post = @app.posts.last
61
+ comment = post.comments.last
62
+ assert_equal 'Jerry McGuire', comment.author
63
+ assert_equal 'blog@example.net', comment.email
64
+ assert_equal '81.86.172.239', comment.ip
65
+ assert_equal '08/13/2003 04:00:09 AM', comment.date.strftime("%m/%d/%Y %I:%M:%S %p")
66
+ assert_equal "I had something similar - a LONG piece of cable through a hole drilled in the ceiling from the upstairs office into the living room and then coiled in a big loop so it would reach anywhere downstairs if stretched across the room....that changed when I got married :-)\n", comment.body
67
+ end
68
+ end
69
+
70
+
71
+ # Tests for checking blog post title where ' or " or : appears in title
72
+ require 'yaml'
73
+ class ParserTestPostTileYamlIssues < Minitest::Test
74
+ def setup
75
+ @fn = File.join(File.dirname(__FILE__),'data','typepad_posts_yaml.txt')
76
+ @app = TypepadToJekyll::Parser.new
77
+ @app.source_filename = @fn
78
+ @app.process
79
+ end
80
+
81
+ def test_first_post_front_matter
82
+ post = @app.posts.first
83
+ assert_equal 'Junk Faxes: Redux', post.title
84
+ post_yaml = YAML.load(post.to_jekyll)
85
+ assert_equal post_yaml['title'], post.title
86
+ end
87
+
88
+ def test_second_post_front_matter
89
+ post = @app.posts[1]
90
+ assert_equal 'All about Frank\'s "MIDI" Files', post.title
91
+ post_yaml = YAML.load(post.to_jekyll)
92
+ #assert_equal 'All about Frank\'s \"MIDI\" Files' ,post_yaml['title']
93
+ assert_equal 'All about Frank\'s "MIDI" Files' ,post_yaml['title']
94
+ end
95
+ end
96
+
97
+
98
+ # Tests for checking category single or categories multiple
99
+ require 'yaml'
100
+ class ParserTestCategories < Minitest::Test
101
+ def setup
102
+ @fn = File.join(File.dirname(__FILE__),'data','typepad_posts_yaml.txt')
103
+ @app = TypepadToJekyll::Parser.new
104
+ @app.source_filename = @fn
105
+ @app.process
106
+ end
107
+
108
+ def test_first_post_category_single
109
+ post = @app.posts.first
110
+ post_yaml = YAML.load(post.to_jekyll)
111
+ key = 'category'
112
+ assert post_yaml.key?(key)
113
+ assert post_yaml[key].split(' ').size == 1
114
+ end
115
+
116
+ def test_first_post_category_single
117
+ post = @app.posts[1]
118
+ post_yaml = YAML.load(post.to_jekyll)
119
+ key = 'categories'
120
+ assert post_yaml.key?(key)
121
+ assert post_yaml[key].split(' ').size == 2
122
+ end
123
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typepad_to_jekyll
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Stansbury
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-07-04 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A commandline application to convert Typepad and Moveabletype backup
15
+ files into Jekyll posts. Posts to be stored in either the _posts or _drafts directory
16
+ email: Chris@koozie.org
17
+ executables:
18
+ - typepad_to
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - Rakefile
23
+ - bin/typepad_to
24
+ - lib/typepad_to_jekyll/converter.rb
25
+ - lib/typepad_to_jekyll/parser.rb
26
+ - lib/typepad_to_jekyll/post.rb
27
+ - lib/typepad_to_jekyll.rb
28
+ - test/data/typepad_multiple_posts.txt
29
+ - test/data/typepad_one_post.txt
30
+ - test/data/typepad_posts_yaml.txt
31
+ - test/test_converter.rb
32
+ - README.md
33
+ - LICENSE
34
+ homepage: https://github.com/koozie/typepad_to_jekyll
35
+ licenses:
36
+ - GPL-2
37
+ - Ruby Software License
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 1.8.23.2
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: ! '''Typepad to Jekyll'' is a ruby library and commandline app that converts
60
+ a Typepad backup file (MTIF format) into Jekyll post files'
61
+ test_files: []