who-needs-wp 0.4.0 → 0.5.0

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.
data/README.md CHANGED
@@ -13,11 +13,11 @@ The main disadvantage is that user's aren't able to comment on my posts - but th
13
13
 
14
14
  ## Getting Started
15
15
 
16
- `who-needs-wp` is a small Ruby program which helps generate static web sites. To start using `who-needs-wp` you need to install Ruby. On Ubuntu enter the following into a command prompt:
16
+ who-needs-wp is a small Ruby program which helps generate static web sites. To start using who-needs-wp you need to install Ruby. On Ubuntu enter the following into a command prompt:
17
17
 
18
18
  sudo apt-get install ruby ruby-dev rubygems
19
19
 
20
- You then need to install `who-needs-wp` by running the following:
20
+ You then need to install who-needs-wp by running the following:
21
21
 
22
22
  sudo gem install who-needs-wp
23
23
 
@@ -33,7 +33,7 @@ Now create a folder which will host your web site
33
33
 
34
34
  mkdir /var/www/website/
35
35
 
36
- `who-needs-wp` stores posts in the `posts/` folder followed by a folder representing the date of the post. i.e. `posts/year/month/day`.
36
+ who-needs-wp stores posts in the `posts/` folder followed by a folder representing the date of the post. i.e. `posts/year/month/day`.
37
37
 
38
38
  Create an example post by creating a folder and creating a Markdown file.
39
39
 
@@ -46,7 +46,7 @@ Along with [Markdown Syntax][MarkdownSyntax] you can also specify the author of
46
46
 
47
47
  Author: Your Name
48
48
 
49
- Before it can generate the site `who-needs-wp` needs to be configured. Copy the following into `/var/www/website/.who-needs-wp.yaml`
49
+ Before it can generate the site who-needs-wp needs to be configured. Copy the following into `/var/www/website/.who-needs-wp.yaml`
50
50
 
51
51
  ---
52
52
  :url: /website/test
@@ -69,15 +69,15 @@ And view the blog at the following URL:
69
69
 
70
70
  ## Overriding Templates
71
71
 
72
- You will probably find that the templates used by `who-needs-wp` don't quite match your requirements. You can override any of the templates by creating a `templates` folder. You can copy the existing templates from the gem as a starting point. The templates are stored within the `/var/lib/gems/1.8/gems/who-needs-wp-0.1.0/lib/who-needs-wp/templates/`.
72
+ You will probably find that the templates used by who-needs-wp don't quite match your requirements. You can override any of the templates by creating a `templates` folder. You can copy the existing templates from the gem as a starting point. The templates are stored within the `/var/lib/gems/1.8/gems/who-needs-wp-0.1.0/lib/who-needs-wp/templates/`.
73
73
 
74
74
  ## Applying alternative styles
75
75
 
76
- You can specify an additional stylesheet by using the `-s` or `--stylesheet` option to the `who-needs-wp` command.
76
+ You can specify an additional stylesheet by using the `-s` or `--stylesheet` option to the who-needs-wp command.
77
77
 
78
78
  ## Twitter
79
79
 
80
- `who-needs-wp` can place a [Twitter][Twitter] stream in the side bar. This can either be a search or an individual user's feed.
80
+ who-needs-wp can place a [Twitter][Twitter] stream in the side bar. This can either be a search or an individual user's feed.
81
81
 
82
82
  Modifying `.who-needs-wp.yaml` and add:
83
83
 
@@ -87,7 +87,7 @@ Modifying `.who-needs-wp.yaml` and add:
87
87
 
88
88
  ## Delicious
89
89
 
90
- `who-needs-wp` can also display a list of bookmarks from [Delicious][Delicious]. Modify `.who-needs-wp.yaml` and add:
90
+ who-needs-wp can also display a list of bookmarks from [Delicious][Delicious]. Modify `.who-needs-wp.yaml` and add:
91
91
 
92
92
  :delicious:
93
93
  :user: <your delicious username>
@@ -101,11 +101,15 @@ To enable Google Analytics you need to specify your web property ID in `.who-nee
101
101
 
102
102
  ## Syntax Highlighting
103
103
 
104
- `who-needs-wp` will syntax highlight your code snippets using [Makers-Mark][MakersMark] and [Pygments][Pygments]
104
+ who-needs-wp will syntax highlight your code snippets using [Makers-Mark][MakersMark] and [Pygments][Pygments]
105
105
 
106
106
  ## Migration from Wordpress
107
107
 
108
- A simple script is in development which will convert a MySQL database to seperate Markdown pages.
108
+ Packaged with who-needs-wp is a simple script called wordpress2wnwp which aids migrating from Wordpress. wordpress2wnwp exports posts from a MySQL database and outputs them in the who-needs-wp filing structure. It also generates Apache2 `RewriteRule`s which rewrite any Wordpress URLs to who-needs-wp.
109
+
110
+ To find more information on wordpress2wnwp enter the following command:
111
+
112
+ wordpress2wnwp -h
109
113
 
110
114
  ### Copyright
111
115
 
@@ -2,24 +2,69 @@
2
2
  $: << File.expand_path(File.dirname(__FILE__) + "/../lib")
3
3
 
4
4
  require 'rubygems'
5
+ require 'choice'
5
6
  require 'who-needs-wp.rb'
6
- require 'optparse'
7
-
8
- options = {}
9
- OptionParser.new do |opts|
10
- opts.banner = "Usage: who-needs-wp [options]"
11
-
12
- opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
13
- options[:verbose] = v
7
+
8
+ PROGRAM_VERSION = "0.5.0"
9
+
10
+ if File.exists? ".who-needs-wp.yaml"
11
+ options = YAML.load_file('.who-needs-wp.yaml')
12
+ else
13
+ options = {}
14
+ end
15
+
16
+ Choice.options do
17
+ header 'A static web site generator. Generates a blog based on Markdown-formatted documents.'
18
+ header ''
19
+ header 'Options are initially read from .who-needs-wp.yaml and over-written by any of the following.'
20
+ header ''
21
+
22
+ option :stylesheet do
23
+ short '-s'
24
+ long '--stylesheet=STYLESHEET'
25
+ desc "A CSS file which will be included in every page generated. (Default: \"#{options[:stylesheet]}\")"
26
+ default options[:stylesheet]
27
+ end
28
+
29
+ option :url do
30
+ short '-u'
31
+ long '--url-prefix=URL'
32
+ desc "Prefix any generated link with the specified URL. (Default: \"#{options[:url]}\")"
33
+ default options[:url]
14
34
  end
15
35
 
16
- opts.on('-s', '--stylesheet STYLESHEET', 'Include STYLESHEET in the output') do |stylesheet|
17
- options[:stylesheet] = stylesheet
36
+ option :title do
37
+ short '-t'
38
+ long '--title=TITLE'
39
+ desc "Title of the blog (Default: \"#{options[:title]}\")"
40
+ default options[:title]
18
41
  end
19
42
 
20
- opts.on('-p', '--url-prefix PATH', 'Prefix all urls with PATH') do |url|
21
- options[:url] = url
43
+ option :author do
44
+ short '-a'
45
+ long '--author=AUTHOR'
46
+ desc "Author of the blog (Default: \"#{options[:author]}\")"
47
+ default options[:author]
22
48
  end
23
- end.parse!
24
49
 
25
- WhoNeedsWP::generate(YAML.load_file('.who-needs-wp.yaml').merge(options))
50
+ option :help do
51
+ long '--help'
52
+ desc 'Show this message'
53
+ end
54
+
55
+ option :version do
56
+ short '-v'
57
+ long '--version'
58
+ desc 'Show version'
59
+ action do
60
+ puts "v#{PROGRAM_VERSION}"
61
+ exit
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ Choice.choices.each do |key, value|
68
+ options[key.to_sym] = value
69
+ end
70
+ WhoNeedsWP::generate(options)
@@ -3,38 +3,152 @@
3
3
  require 'rubygems'
4
4
  require 'sequel'
5
5
  require 'logger'
6
-
7
6
  require 'mysql'
8
7
  require 'ftools'
8
+ require 'choice'
9
9
 
10
+ PROGRAM_VERSION=0.1
10
11
 
11
- database = ARGV[0]
12
- user = ARGV[1]
13
- password = ARGV[2]
14
- prefix = ARGV[3]
12
+ Choice.options do
13
+ header 'Converts a MySQL Wordpress database to a blog in who-needs-wp format.'
14
+ header ''
15
+ header 'Database options:'
16
+
17
+ option :host do
18
+ short '-h'
19
+ long '--host=HOST'
20
+ desc 'Hostname or IP of the MySQL server to connect to (default 127.0.0.1)'
21
+ default '127.0.0.1'
22
+ end
23
+
24
+ option :database do
25
+ short '-d'
26
+ long '--database=DATABASE'
27
+ desc 'Name of the database to use (default wordpress)'
28
+ default 'wordpress'
29
+ end
15
30
 
16
- dbh = Mysql.real_connect("localhost", user, password, database)
17
- res = dbh.query("SELECT DISTINCT post_parent FROM wp_#{prefix}_posts")
18
- posts = []
19
- while row = res.fetch_row do
20
- posts << row[0]
21
- end
22
- puts posts.inspect
23
- posts0 = []
24
- posts.each do |post_id|
25
- res = dbh.query("SELECT post_title, post_date, post_content FROM wp_#{prefix}_posts WHERE post_parent ='#{post_id}' ORDER BY ID DESC LIMIT 1")
26
- row = res.fetch_row
27
- posts0 << {
28
- :id => post_id,
29
- :title => row[0],
30
- :date => Date.parse(row[1]),
31
- :content => row[2]
32
- }
31
+ option :username do
32
+ short '-u'
33
+ long '--username=USER'
34
+ desc 'Name of the MySQL user to use (default wordpress)'
35
+ default 'wordpress'
36
+ end
37
+
38
+ option :password do
39
+ short '-p'
40
+ long '--password=PASSWORD'
41
+ desc 'Password for the MySQL user'
42
+ end
43
+
44
+ option :prefix do
45
+ long '--prefix=PREFIX'
46
+ desc 'Prefix for all Wordpress table names'
47
+ default ''
48
+ end
49
+
50
+ separator ''
51
+ separator 'Blog options: '
52
+
53
+ option :url do
54
+ long '--url=URL'
55
+ desc 'URL for new who-needs-wp blog (used for redirects)'
56
+ default '/'
57
+ end
58
+
59
+ separator ''
60
+ separator 'Common options: '
61
+
62
+ option :help do
63
+ long '--help'
64
+ desc 'Show this message'
65
+ end
66
+
67
+ option :version do
68
+ short '-v'
69
+ long '--version'
70
+ desc 'Show version'
71
+ action do
72
+ puts "wordpress2wnwp Wordpress MySQL database converter v#{PROGRAM_VERSION}"
73
+ exit
74
+ end
75
+ end
33
76
  end
34
- posts0.each do |post|
35
- dir = "#{post[:date].strftime('%Y')}/#{post[:date].strftime('%m')}/#{post[:date].strftime('%d')}"
36
- File.makedirs dir
37
- File.open(dir + "/" + post[:title].gsub(/ /, '_') + ".markdown", "w") do |file|
38
- file.puts post[:content]
77
+
78
+ class Wordpress2WNWP
79
+ # Convert a database given the options provided
80
+ def self.convert(options)
81
+ @options = options
82
+ if @options[:prefix].empty?
83
+ @table_name = "wp_posts"
84
+ else
85
+ @table_name = "wp_#{@options[:prefix]}_posts"
86
+ end
87
+ self.connect
88
+ parents = self.parent_posts
89
+ posts = self.latest_posts(parents)
90
+ self.generate_posts(posts)
91
+ self.generate_rewrites(posts)
92
+ end
93
+
94
+ # Connect to a MySQL database
95
+ def self.connect
96
+ @database = Mysql.real_connect(@options[:host], @options[:username], @options[:password], @options[:database])
97
+ end
98
+
99
+ # Returns a list of parent post identifiers
100
+ def self.parent_posts
101
+ results = @database.query("SELECT DISTINCT post_parent FROM #{@table_name}")
102
+ posts = []
103
+ while row = results.fetch_row do
104
+ posts << row[0]
105
+ end
106
+ return posts
107
+ end
108
+
109
+ # Returns the latest post from a given list of parent post identifiers
110
+ def self.latest_posts(parents)
111
+ posts = []
112
+ parents.each do |post_id|
113
+ results = @database.query("SELECT post_title, post_date, post_content FROM #{@table_name} WHERE post_parent = '#{post_id}' ORDER BY ID DESC LIMIT 1")
114
+ row = results.fetch_row
115
+ posts << {
116
+ :id => post_id,
117
+ :title => row[0],
118
+ :date => Date.parse(row[1]),
119
+ :content => row[2]
120
+ }
121
+ end
122
+ return posts
123
+ end
124
+
125
+ # Given a list of posts generate the required Markdown files
126
+ def self.generate_posts(posts)
127
+ posts.each do |post|
128
+ directory = "#{post[:date].strftime('%Y')}/#{post[:date].strftime('%m')}/#{post[:date].strftime('%d')}"
129
+ File.makedirs directory
130
+ filename = directory + "/" + post[:title].gsub(/ /, '_')
131
+ post[:filename] = filename + ".html"
132
+ File.open(filename + ".markdown", "w") do |file|
133
+ file.puts post[:content]
134
+ end
135
+ end
136
+ end
137
+
138
+ # Generate a list of Apache2 rewrite rules
139
+ def self.generate_rewrites(posts)
140
+ puts "Re-write rules for Apache2:"
141
+ posts.each do |post|
142
+ results = @database.query("SELECT guid FROM #{@table_name} WHERE post_parent='#{post[:id]}'")
143
+ while row = results.fetch_row do
144
+ if row[0] =~ /p=([0-9]+)/
145
+ guid = $1
146
+ puts "RewriteCond %{QUERY_STRING} p=#{guid}"
147
+ puts "RewriteRule ^#{@options[:url]}$ #{@options[:url]}posts/#{post[:filename]} [L]"
148
+ end
149
+ end
150
+ end
39
151
  end
40
152
  end
153
+
154
+ Wordpress2WNWP::convert(Choice.choices)
@@ -7,7 +7,7 @@ require 'open-uri'
7
7
  require 'sass'
8
8
  require 'makers-mark'
9
9
  require 'logger'
10
-
10
+ require 'rss/maker'
11
11
  require 'who-needs-wp/css.rb'
12
12
  require 'who-needs-wp/twitter.rb'
13
13
  require 'who-needs-wp/delicious.rb'
@@ -33,13 +33,15 @@ module WhoNeedsWP
33
33
  self.load_pages
34
34
  self.recentposts
35
35
  self.page_index
36
- self.twitter
37
- self.delicious
36
+ # self.twitter
37
+ # self.delicious
38
38
  self.generate_posts
39
39
  self.generate_pages
40
40
  self.index
41
41
  self.all_posts
42
42
  self.css
43
+ self.rss("posts.rss")
44
+ self.atom("posts.atom")
43
45
  end
44
46
 
45
47
  # Generate the index page for the blog
@@ -6,15 +6,23 @@ module WhoNeedsWP
6
6
  @logger.debug "Loading post #{filename}"
7
7
  match = filename.match(/([0-9]{4})\/([0-9]{2})\/([0-9]{2})\/([^\.]*)/)
8
8
  date = DateTime.new(match[1].to_i, match[2].to_i, match[3].to_i)
9
- @POSTS << {
9
+ generated_filename = File.dirname(filename) + "/" + File.basename(filename, ".markdown") + ".html"
10
+ post = {
10
11
  :filename => {
11
12
  :original => filename,
12
- :generated => File.dirname(filename) + "/" + File.basename(filename, ".markdown") + ".html"
13
+ :generated => generated_filename,
13
14
  },
14
15
  :title => match[4].gsub(/_/, ' '),
15
16
  :created_at => date
16
17
  }
18
+ # Generate a unique post ID to be used in the Atom feed
19
+ post[:id] = "#{options[:url]}#{generated_filename}".gsub!(/http:\/\//, 'tag:')
20
+ match = post[:id].match(/([^\/]*)\/(.*)/)
21
+ post[:id] = "#{match[1]},#{date.strftime('%Y-%m-%d')}:#{match[2]}" if match
22
+ # Append the post to the global list of posts
23
+ @POSTS << post
17
24
  end
25
+ # Sort the posts, newest first
18
26
  @POSTS.sort! { |a, b| a[:created_at] <=> b[:created_at] }
19
27
  @POSTS.reverse!
20
28
  end
@@ -27,6 +35,32 @@ module WhoNeedsWP
27
35
  })
28
36
  end
29
37
 
38
+ def self.options
39
+ return @options
40
+ end
41
+
42
+ def self.POSTS
43
+ return @POSTS
44
+ end
45
+
46
+ def self.rss(filename, limit=10)
47
+ file = File.open(filename, "w")
48
+ file.write @template['rss'].render(Object.new, {
49
+ :posts => @POSTS[0..limit],
50
+ :options => @options
51
+ })
52
+ file.close
53
+ end
54
+
55
+ def self.atom(filename, limit=10)
56
+ file = File.open(filename, "w")
57
+ file.write @template['atom'].render(Object.new, {
58
+ :posts => @POSTS[0..limit],
59
+ :options => @options
60
+ })
61
+ file.close
62
+ end
63
+
30
64
  def self.generate_posts
31
65
  @POSTS.each_index do |index|
32
66
  # Calculate the previous and next posts
@@ -57,6 +91,9 @@ module WhoNeedsWP
57
91
  :next_post => next_post,
58
92
  :previous_post => previous_post
59
93
  })
94
+ # Set the summary of the post to be the first paragraph
95
+ post[:summary] = $1 if post[:html] =~ (/(?:<p>)(.*?)(?:<\/p>)/)
96
+
60
97
  # Render the post as HTML
61
98
  self.render_html(post[:filename][:generated], "post", post[:html], post[:title])
62
99
  end
@@ -0,0 +1,19 @@
1
+ !!! XML utf-8
2
+ %feed{:xmlns => "http://www.w3.org/2005/Atom"}
3
+ %title= options[:title]
4
+ %id= "#{options[:url]}posts.atom"
5
+ %updated= "#{Time.now.xmlschema}"
6
+ %author
7
+ %name= options[:author]
8
+ %link{:href => "#{options[:url]}"}/
9
+ - posts.each do |post|
10
+ %entry
11
+ %title= post[:title]
12
+ %id= post[:id]
13
+ %updated= Time.parse(post[:created_at].to_s).xmlschema
14
+ %link{:href => "#{options[:url]}/#{post[:filename][:generated]}"}/
15
+ %content{:type => "text/html", :src => "#{options[:url]}/#{post[:filename][:generated]}"}/
16
+ %summary{:type => "html"}
17
+ :cdata
18
+ #{post[:summary]}
19
+
@@ -2,6 +2,8 @@
2
2
  %html
3
3
  %head
4
4
  %link{:rel => "stylesheet", :type => "text/css", :href => "#{options[:url]}/style.css"}/
5
+ %link{:rel => "alternate", :type => "application/atom+xml", :href => "#{options[:url]}/posts.atom", :title => "#{options[:title]} - Atom"}/
6
+ %link{:rel => "alternate", :type => "application/rss+xml", :href => "#{options[:url]}/posts.rss", :title => "#{options[:title]} - RSS"}/
5
7
  %title
6
8
  = options[:title]
7
9
  - if defined? title and title != nil and not title.empty?
@@ -0,0 +1,15 @@
1
+ !!! XML iso-8859-1
2
+ %rss{:version => "2.0"}
3
+ %channel
4
+ %title= options[:title]
5
+ %description= options[:description]
6
+ %link= options[:url]
7
+ - posts.each do |post|
8
+ %item
9
+ %title= post[:title]
10
+ %link= "#{options[:url]}/#{post[:filename][:generated]}"
11
+ %guid= "#{options[:url]}/#{post[:filename][:generated]}"
12
+ %pubDate= Time.parse(post[:created_at].to_s).rfc822
13
+ %description
14
+ :cdata
15
+ #{post[:summary]}
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 4
7
+ - 5
8
8
  - 0
9
- version: 0.4.0
9
+ version: 0.5.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Owen Griffin
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-19 00:00:00 +00:00
17
+ date: 2010-03-24 00:00:00 +00:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -101,6 +101,20 @@ dependencies:
101
101
  version: 0.1.1
102
102
  type: :runtime
103
103
  version_requirements: *id006
104
+ - !ruby/object:Gem::Dependency
105
+ name: choice
106
+ prerelease: false
107
+ requirement: &id007 !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ segments:
112
+ - 0
113
+ - 1
114
+ - 4
115
+ version: 0.1.4
116
+ type: :runtime
117
+ version_requirements: *id007
104
118
  description: A static web site generator.
105
119
  email: owen.griffin@gmail.com
106
120
  executables:
@@ -123,6 +137,7 @@ files:
123
137
  - lib/who-needs-wp/stylesheets/style.sass
124
138
  - lib/who-needs-wp/templates.rb
125
139
  - lib/who-needs-wp/templates/all_posts.haml
140
+ - lib/who-needs-wp/templates/atom.haml
126
141
  - lib/who-needs-wp/templates/body.haml
127
142
  - lib/who-needs-wp/templates/delicious.haml
128
143
  - lib/who-needs-wp/templates/layout.haml
@@ -130,6 +145,7 @@ files:
130
145
  - lib/who-needs-wp/templates/pageindex.haml
131
146
  - lib/who-needs-wp/templates/post.haml
132
147
  - lib/who-needs-wp/templates/recentposts.haml
148
+ - lib/who-needs-wp/templates/rss.haml
133
149
  - lib/who-needs-wp/templates/twitter.haml
134
150
  - lib/who-needs-wp/twitter.rb
135
151
  - LICENSE