presser 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ test/dont_git*
6
+ presser_config_file.yml
data/.presser ADDED
@@ -0,0 +1,11 @@
1
+ verbose: false
2
+ username: WaltKelly
3
+ password: pogo
4
+ url: http://wordpress/wp/xmlrpc.php
5
+ file_to_upload:
6
+ upload_file: false
7
+ pretend: false
8
+ post_file: false
9
+ file_to_post:
10
+ make_config_file: true
11
+ config_file_name: .presser
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm gemset use presser
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in presser.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Presser
2
+
3
+ Presser is a command-line program to post and upload to a Wordpress blog.
4
+
5
+ It's pretty raw, but it (barely) scratches my itch, so it might not get updated for a bit.
6
+
7
+ To run it: either install it as a gem ("rake -T" to see the rake options to do that) and run "presser", or run the bin/presser script.
8
+
9
+ The command "presser -h" will get you a list of options.
10
+
11
+ ## Configuration
12
+
13
+ In order to talk to WordPress, presser needs to talk to your WordPress's xmlrpc.php file, and will need your username and password.
14
+
15
+ You can provide those on the command line, or make a .presser file in your home directoru. Running:
16
+
17
+ presser -c
18
+
19
+ will get presser to create a sample .presser file for you. You will then need to edit it, but it's a simple file, and should be self-explanatory. The sample file will contain more options than presser will actually read. (Like I said, it's pretty raw.) But just set the username, password, and url, and either ignore or delete the rest.
20
+
21
+ ## Uploading files
22
+
23
+ Presser will upload a file for you. Use this command:
24
+
25
+ presser -U filename
26
+
27
+ Presser will upload the file and print out the url where the uploaded file can be found.
28
+
29
+ ## New posts
30
+
31
+ Use the post_template.txt file as a template for new posts. Shocker.
32
+
33
+ Copy the file and edit it. Then post it with:
34
+
35
+ presser -o filename
36
+
37
+ Edit it some more. Update the post with the same command.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ namespace :specs do
5
+ Rspec = "rspec --tty --color"
6
+
7
+ desc "Run all specs"
8
+ task :all do |t|
9
+ sh "#{Rspec} spec/*.rb"
10
+ end
11
+
12
+ desc "Run doc specs"
13
+ task :docs do |t|
14
+ sh "#{Rspec} spec/presser_doc_spec.rb"
15
+ end
16
+
17
+ desc "Run config specs"
18
+ task :config do |t|
19
+ sh "#{Rspec} spec/yaml_spec.rb"
20
+ sh "#{Rspec} spec/presser_opts_spec.rb"
21
+ end
22
+
23
+ end
data/bin/presser ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+
4
+ $: << File.expand_path(File.dirname(__FILE__) + "/../lib")
5
+
6
+ require "presser"
7
+
8
+
9
+ wp = Presser::Presser.new ARGV
10
+ wp.run
data/lib/blog_post.rb ADDED
@@ -0,0 +1,134 @@
1
+
2
+ module Presser
3
+ class BlogPost
4
+ attr_accessor :title, :body, :link, :categories, :postid, :post_status
5
+
6
+ def initialize
7
+ @categories = []
8
+ @post_status = ""
9
+ @postid = "-1"
10
+ @link = "http://www.google.com"
11
+ @reading_header = true
12
+ @post_file_items = {}
13
+ end
14
+
15
+ def self.from_filename filename
16
+ bp = BlogPost.new
17
+ bp.load_from_file filename
18
+ bp
19
+ end
20
+
21
+ def self.make_file_from_struct presserDoc
22
+ File.open(BlogPost.new_post_filename, "w") do |f|
23
+ f.puts presserDoc.to_s
24
+ end
25
+ BlogPost.new_post_filename
26
+ end
27
+
28
+ def load_from_file filename
29
+ parse_all_lines filename
30
+ @title = @post_file_items["title"] || ""
31
+ @body = @post_file_items["body"] || ""
32
+ @link = @post_file_items["link"] || ""
33
+ @postid = @post_file_items["postid"] || ""
34
+ end
35
+
36
+ # get the values from a metaWeblog struct
37
+ def parse_struct struct
38
+ @title = struct["title"] || ""
39
+ @body = struct["body"] || ""
40
+ @link = struct["link"] || ""
41
+ @postid = struct["postid"] || ""
42
+ @post_status = struct["post_status"] || ""
43
+ @categories = struct["categories"] || ""
44
+ end
45
+
46
+ def parse_string str
47
+ lines = str.split("\n")
48
+ parse_all_lines lines
49
+ end
50
+
51
+ # Read through a file
52
+ # put all the items describing its post into @post_file_items
53
+ def parse_all_lines filename
54
+ lines = []
55
+ File.readlines(filename).each do |line|
56
+ lines << line
57
+ end
58
+ parse_array_of_lines lines
59
+ end
60
+
61
+ def parse_array_of_lines lines
62
+ body = ""
63
+ lines.each do |line|
64
+ line = line.strip
65
+ if @reading_header
66
+ parse_header_line line
67
+ else
68
+ body << line << "\n"
69
+ end
70
+ end
71
+ # puts "post_file_items: #{@post_file_items}"
72
+ @title = @post_file_items["title"] || "Default title"
73
+ @post_file_items["body"] = body
74
+ end
75
+
76
+ def parse_header_line line
77
+ if line == "# End of header"
78
+ @reading_header = false
79
+ else
80
+ if line =~ /(.*):(.*)/
81
+ # puts "match: #{line}"
82
+ key = $1.strip
83
+ val = $2.strip
84
+ @post_file_items[key] = val
85
+ else
86
+ # puts "No match: #{line}"
87
+ end
88
+ end
89
+ end
90
+
91
+ def to_s
92
+ str = %Q{# Beginning of header
93
+ title: #{@title}
94
+ link: #{@link}
95
+ categories: #{@categories}
96
+ postid: #{@postid}
97
+ post_status: #{@post_status}
98
+ # End of header
99
+ #{@body}}
100
+ end
101
+
102
+ def save_new_post
103
+ str = %Q{# Beginning of header
104
+ title: #{@title}
105
+ categories: #{@categories}
106
+ # End of header
107
+
108
+ }
109
+ # File.open(BlogPost.new_post_filename, "w") { |file| file.puts str }
110
+ f = File.open(BlogPost.new_post_filename, "w")
111
+ f.puts str
112
+ f.flush
113
+ f.close
114
+ BlogPost.new_post_filename
115
+ end
116
+
117
+ def self.new_post_filename
118
+ prefix = "presser_post_"
119
+ @numfiles ||= Dir.glob(prefix + "*").length
120
+ @new_file_name ||= prefix + (@numfiles + 1).to_s + ".md"
121
+ end
122
+
123
+ def save_to_file filename
124
+ File.open(filename, "w") { |file| file.puts to_s }
125
+ end
126
+
127
+ def dumpself
128
+ puts "Dumping self"
129
+ puts "title: #{@title}"
130
+ puts "body: #{@body}"
131
+ puts "link: #{@link}"
132
+ end
133
+ end
134
+ end
data/lib/local_file.rb ADDED
@@ -0,0 +1,44 @@
1
+
2
+ module Presser
3
+ class LocalFile
4
+ attr_accessor :title, :body, :params
5
+ def initialize filename
6
+ @in_header = true
7
+ @body = ""
8
+ @filename = filename
9
+ @params = {}
10
+ parse_all_lines
11
+ # puts "The title: #{@title}"
12
+ end
13
+
14
+ def parse_all_lines
15
+ File.readlines(@filename).each do |line|
16
+ line = line.strip
17
+ if @in_header
18
+ parse_line line
19
+ else
20
+ # puts "Body: '#{line}'"
21
+ body << line << "\n"
22
+ end
23
+ end
24
+ # puts "params: #{@params}"
25
+ @title = params["title"] || "Default title"
26
+ end
27
+
28
+ def parse_line line
29
+ if line == "# End of header"
30
+ @in_header = false
31
+ else
32
+ if line =~ /(.*):(.*)/
33
+ # puts "match: #{line}"
34
+ key = $1.strip
35
+ val = $2.strip
36
+ @params[key] = val
37
+ else
38
+ # puts "No match: #{line}"
39
+ end
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module Presser
2
+ VERSION = "0.1.1"
3
+ end
data/lib/presser.rb ADDED
@@ -0,0 +1,117 @@
1
+ require 'presser_opts'
2
+ require 'net/http'
3
+ require 'xmlrpc/client'
4
+ require 'presser_xmlrpc'
5
+ require 'fileutils'
6
+
7
+ module Presser
8
+
9
+ class Presser
10
+ CONFIGFILE = "#{ENV['HOME']}/.presser"
11
+ def initialize(args, filename=nil)
12
+ @args = args
13
+
14
+ filename ||= CONFIGFILE
15
+ load_config_file filename
16
+ end
17
+
18
+ def load_config_file filename
19
+ @options = PresserOpts.new Array.new @args
20
+ if File.exists? filename
21
+ @options.load_file filename
22
+ # @options.parse Array.new @args
23
+ end
24
+ @options
25
+ end
26
+
27
+ def parsed_options
28
+ @options.parsed
29
+ end
30
+
31
+ def response
32
+ @response.body
33
+ end
34
+
35
+ def do_getPostStatus
36
+ rpc = PresserXmlrpc.new @options.parsed
37
+ result = rpc.call_xmlrpc rpc.options_for_getPostStatus
38
+ result
39
+ end
40
+
41
+ def get_post postid
42
+ rpc = PresserXmlrpc.new @options.parsed
43
+ struct = rpc.get_post postid
44
+ filename = BlogPost.make_file_from_struct struct
45
+ end
46
+
47
+ def delete_post postid
48
+ rpc = PresserXmlrpc.new @options.parsed
49
+ rpc.delete_post postid
50
+ end
51
+
52
+ def run
53
+
54
+ # if @options.parsed.use_config_file
55
+ # load_config_file @options.parsed.config_file_name
56
+ # end
57
+
58
+ rpc = PresserXmlrpc.new @options.parsed
59
+
60
+ if @options.parsed.upload_file
61
+ puts rpc.upload_file @options.parsed.file_to_upload
62
+ end
63
+
64
+ if @options.parsed.get_post
65
+ filename = get_post @options.parsed.postid
66
+ run_vim filename
67
+ end
68
+
69
+ if @options.parsed.post_file
70
+ filename = @options.parsed.file_to_post
71
+
72
+ postid = rpc.post_file filename
73
+ # When doing a new pots, we want to get the info after
74
+ # WP creates the post ... mostly, we want to put the
75
+ # postid into our local source file.
76
+ # The get_post call throws an exception if we're
77
+ # just updating a post, rather than doing a new post.
78
+ # But in that case, we don't need to get the post id,
79
+ # so we can safely ignore the exception.
80
+ begin
81
+ struct = rpc.get_post postid
82
+ File.open(filename, "w") { |file| file.puts struct.to_s }
83
+ rescue
84
+ end
85
+
86
+ if not postid == true
87
+ puts postid
88
+ end
89
+ end
90
+
91
+ if @options.parsed.make_new_post
92
+ bp = BlogPost.new
93
+ filename = bp.save_new_post
94
+ run_vim filename
95
+ end
96
+
97
+ if @options.parsed.make_config_file
98
+ puts @options.save_to_file
99
+ end
100
+
101
+ if @options.parsed.delete_post
102
+ delete_post @options.parsed.postid
103
+ end
104
+
105
+ if @options.parsed.show_config
106
+ puts @options.to_yaml
107
+ end
108
+ end
109
+
110
+ def run_vim filename
111
+ return unless @options.parsed.use_vim
112
+ puts "run vim with file: #{filename}"
113
+ system("mvim #{filename}")
114
+ end
115
+ end
116
+ end
117
+
@@ -0,0 +1,43 @@
1
+ require 'rexml/document'
2
+
3
+ module Presser
4
+
5
+ class PresserDoc
6
+ attr_accessor :categories, :postid, :post_status
7
+ def initialize *args
8
+ @title = args[0] || "This is the title"
9
+ @link = args[1] || "http://www.google.com"
10
+ @description = args[2] || "This is the description"
11
+ end
12
+
13
+ def to_s
14
+ str = %Q{# Beginning of header
15
+ title: #{@title}
16
+ link: #{@link}
17
+ postid: #{postid}
18
+ post_status: #{post_status}
19
+ # End of header
20
+ #{@description}}
21
+ end
22
+
23
+ def new_doc
24
+ doc = REXML::Document.new
25
+ item = doc.add_element "struct"
26
+ title = item.add_element 'title'
27
+ link = item.add_element "link"
28
+ description = item.add_element "description"
29
+
30
+ description.text = @description
31
+ title.text = @title
32
+ link.text = @link
33
+
34
+ # str = ""
35
+ # doc.write(str, 2)
36
+ # puts str
37
+ str = ""
38
+ doc.write str
39
+ str
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,177 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+ require 'yaml'
4
+
5
+ # Usage: presser [options]
6
+ # -h, --help Print out this message
7
+ # -c, --configfile [STRING] create a config file
8
+ # -d, --deletepost INTEGER delete a post
9
+ # -g, --getpost INTEGER delete a post
10
+ # -o, --post STRING Post the named file
11
+ # -p, --password STRING WordPress admin password
12
+ # -u, --username STRING WordPress admin username
13
+ # -U, --upload STRING Upload a file
14
+ # -r, --url STRING WordPress xmlrpc url
15
+
16
+
17
+ module Presser
18
+ class PresserOpts
19
+ def initialize(args, path="")
20
+ @parsed = OpenStruct.new
21
+ parse(args)
22
+ if not path == ""
23
+ @parsed.config_file_name = path
24
+ end
25
+ end
26
+
27
+ def load_yaml yaml_string
28
+ # new_opts = PresserOpts.new []
29
+ yaml = YAML::load(yaml_string)
30
+
31
+ @parsed.username = yaml["username"]
32
+ @parsed.password = yaml["password"]
33
+ @parsed.url = yaml["url"]
34
+ end
35
+
36
+ def to_yaml
37
+ str = "verbose: #{parsed.verbose}\n"
38
+ str << "username: #{parsed.username}\n"
39
+ str << "password: #{parsed.password}\n"
40
+ str << "url: #{parsed.url}\n"
41
+ str << "file_to_upload: #{parsed.file_to_upload}\n"
42
+ str << "upload_file: #{parsed.upload_file}\n"
43
+ str << "pretend: #{parsed.pretend}\n"
44
+ str << "post_file: #{parsed.post_file}\n"
45
+ str << "file_to_post: #{parsed.file_to_post}\n"
46
+ str << "make_config_file: #{parsed.make_config_file}\n"
47
+ str << "config_file_name: #{parsed.config_file_name}\n"
48
+ str
49
+ end
50
+
51
+ def config_file_name= filename
52
+ @parsed.config_file_name = filename
53
+ end
54
+
55
+ def parsed= val
56
+ @parsed = val
57
+ end
58
+
59
+ def parsed
60
+ @parsed
61
+ end
62
+
63
+ def save_to_file
64
+ File.open(@parsed.config_file_name, 'w+') do |file|
65
+ file.puts to_yaml
66
+ end
67
+ end
68
+
69
+ def load_file filename
70
+ yaml = File.new(filename).read
71
+ load_yaml yaml
72
+ end
73
+
74
+ def config_file_contents
75
+ str = ""
76
+ str << "username: #{@parsed.username}\n"
77
+ str << "password: #{@parsed.password}\n"
78
+ str << "url: #{@parsed.url}"
79
+ end
80
+
81
+ def parse(args)
82
+ @parsed.verbose ||= false
83
+ @parsed.username ||= "WaltKelly"
84
+ @parsed.password ||= "pogo"
85
+ @parsed.url ||= "http://wordpress/wp/xmlrpc.php"
86
+ @parsed.file_to_upload ||= ""
87
+ @parsed.upload_file ||= false
88
+ @parsed.pretend ||= false
89
+ @parsed.post_file ||= false
90
+ @parsed.file_to_post ||= ""
91
+ @parsed.make_config_file ||= false
92
+ @parsed.make_new_post ||= false
93
+ @parsed.use_config_file ||= true
94
+ @parsed.config_file_name ||= "#{ENV['HOME']}/.presser"
95
+ @parsed.delete_post ||= false
96
+ @parsed.get_post ||= false
97
+ @parsed.postid ||= ""
98
+ @parsed.show_config ||= false
99
+ @parsed.use_vim ||= false
100
+
101
+ @optionParser = OptionParser.new do |opts|
102
+ opts.banner = "Usage: presser [options]"
103
+ # opts.separator = ""
104
+
105
+ opts.on('-h', "--help", "Print out this message") do |url|
106
+ puts opts
107
+ end
108
+
109
+ opts.on("-c", "--configfile [STRING]", "create a config file") do |filename|
110
+ @parsed.make_config_file = true
111
+ if filename
112
+ @parsed.config_file_name = filename.strip
113
+ end
114
+ end
115
+
116
+ opts.on("-d", "--deletepost INTEGER", "delete a post") do |postid|
117
+ @parsed.delete_post = true
118
+ @parsed.postid = postid
119
+ end
120
+
121
+ opts.on("-f", "--useconfigfile [STRING]", "use a config file") do |filename|
122
+ @parsed.use_config_file = true
123
+ if filename
124
+ @parsed.config_file_name = filename.strip
125
+ end
126
+ end
127
+
128
+ opts.on("-g", "--getpost INTEGER", "get a post") do |postid|
129
+ @parsed.get_post = true
130
+ @parsed.postid = postid
131
+ end
132
+
133
+ opts.on("-n", "--new", "Make a new blank post file") do |postid|
134
+ @parsed.make_new_post = true
135
+ @parsed.postid = postid
136
+ end
137
+
138
+ opts.on("-o", "--post STRING", "Post the named file") do |filename|
139
+ @parsed.post_file = true
140
+ @parsed.file_to_post = filename.strip
141
+ end
142
+
143
+ opts.on('-s', '--show', 'Show the current configuration') do |password|
144
+ puts "PresserOpts: show config is true"
145
+ @parsed.show_config = true
146
+ end
147
+
148
+ opts.on('-p', '--password STRING', 'WordPress admin password') do |password|
149
+ @parsed.password = password.strip
150
+ end
151
+
152
+ opts.on('-u', '--username STRING', 'WordPress admin username') do |username|
153
+ @parsed.username = username.strip
154
+ end
155
+
156
+ opts.on('-U', '--upload STRING', 'Upload a file') do |filename|
157
+ @parsed.upload_file = true
158
+ @parsed.file_to_upload = filename.strip
159
+ end
160
+
161
+ opts.on('-r STRING', '--url STRING', 'WordPress xmlrpc url') do |url|
162
+ @parsed.url = url.strip
163
+ end
164
+
165
+ opts.on('-v', '--vim', 'Open vim') do |url|
166
+ @parsed.use_vim = true
167
+ end
168
+
169
+ end
170
+
171
+ @optionParser.parse!(args)
172
+ @parsed
173
+ end
174
+
175
+
176
+ end
177
+ end
@@ -0,0 +1,172 @@
1
+ require 'xmlrpc/client'
2
+ require 'local_file'
3
+ require 'blog_post'
4
+ require 'presser_doc'
5
+
6
+ module Presser
7
+
8
+ class PresserXmlrpc
9
+
10
+ def initialize(opts)
11
+ @opt = opts
12
+ end
13
+
14
+ def call_xmlrpc(opts)
15
+ # puts "call_xmlrpc: opts = #{opts}"
16
+ server = XMLRPC::Client.new2(opts[:url])
17
+ result = server.call(opts[:method], opts[:options])
18
+ end
19
+
20
+ def blog_id
21
+ # Return the id for the first blog
22
+ @blogid ||= getUsersBlogs[0]["blogid"]
23
+ @blogid
24
+ end
25
+
26
+ def getUsersBlogs
27
+ options = { :url => @opt.url, :method => "wp.getUsersBlogs",
28
+ :options => [@opt.username, @opt.password] }
29
+ call_xmlrpc options
30
+ end
31
+ def getPostStatusList
32
+ options = { :url => @opt.url, :method => "wp.getPostStatusList",
33
+ :options => [blog_id, @opt.username, @opt.password] }
34
+ call_xmlrpc options
35
+ end
36
+ def getTags
37
+ options = { :url => @opt.url, :method => "wp.getTags",
38
+ :options => [blog_id, @opt.username, @opt.password] }
39
+ call_xmlrpc options
40
+ end
41
+ def getRecentPosts
42
+ options = { :url => @opt.url, :method => "metaWeblog.getRecentPosts",
43
+ :options => [blog_id, @opt.username, @opt.password] }
44
+ result = call_xmlrpc options
45
+ result
46
+ end
47
+ def getPageList
48
+ options = { :url => @opt.url, :method => "wp.getPageList",
49
+ :options => [blog_id, @opt.username, @opt.password] }
50
+ result = call_xmlrpc options
51
+ result
52
+ end
53
+
54
+ def upload_file filename
55
+ struct = {
56
+ "name" => File.basename(filename),
57
+ "type" => file_type_from_name(filename),
58
+ "bits" => encode64(filename),
59
+ "overwrite" => false
60
+ }
61
+ options = { :url => @opt.url, :method => "wp.uploadFile",
62
+ :options => [blog_id, @opt.username, @opt.password, struct] }
63
+ result = call_xmlrpc options
64
+ result = result["url"]
65
+ end
66
+
67
+ def file_type_from_name filename
68
+ ext = File.extname(filename).sub(/\./, '').downcase
69
+
70
+ # http://www.w3schools.com/media/media_mimeref.asp
71
+ types = {
72
+ "txt" => "text/plain",
73
+ "jpg" => "image/jpeg",
74
+ "jpeg" => "image/jpeg",
75
+ "png" => "image/png",
76
+ "gif" => "image/gif",
77
+ "tif" => "image/tif",
78
+ "tiff" => "image/tiff",
79
+ "pdf" => "application/pdf",
80
+ "doc" => "application/msword",
81
+ "rtf" => "application/rtf",
82
+ "xls" => "application/vnd.ms-excel",
83
+ "mp3" => "audo/mpeg"
84
+ }
85
+ types[ext]
86
+ end
87
+
88
+ def encode64 filename
89
+ # http://perfectionlabstips.wordpress.com/2008/11/20/encoding-files-to-base64-representation-directly-from-command-line/
90
+ # ruby -e 'print [IO.read(File.join(Dir.pwd, ARGV[0]))].pack("m")'
91
+ # XMLRPC::Base64.new([IO.read(filename)].pack("m0"))
92
+ # http://blog.bitcrowd.net/upload-a-file-to-a-wordpress-blog-via-xml-rpc-wp-uploadfile/
93
+ XMLRPC::Base64.new(File.open(filename).read)
94
+ end
95
+
96
+ def post_file(filename, publish = true)
97
+ bp = BlogPost.from_filename filename
98
+
99
+ struct = {
100
+ "title" => bp.title,
101
+ "link" => bp.link,
102
+ "categories" => [],
103
+ #"categories" => bp.categories,
104
+ # "postid" => bp.postid,
105
+ "post_status" => bp.post_status,
106
+ "description" => bp.body
107
+ }
108
+ if bp.postid == ""
109
+ options = { :url => @opt.url, :method => "metaWeblog.newPost",
110
+ :options => [blog_id, @opt.username, @opt.password,
111
+ struct, publish] }
112
+ else
113
+ # struct["postid"] = bp.postid
114
+ options = { :url => @opt.url, :method => "metaWeblog.editPost",
115
+ :options => [bp.postid.to_i, @opt.username, @opt.password, struct, publish] }
116
+ end
117
+ postid = call_xmlrpc options
118
+ postid
119
+ end
120
+
121
+ # This returns a PresserDoc with the post contents
122
+ # I've put a sample of the struct returned by wordpress at the end of this file
123
+ def get_post(postid)
124
+ options = { :url => @opt.url, :method => "metaWeblog.getPost",
125
+ :options => [postid, @opt.username, @opt.password] }
126
+
127
+ struct = call_xmlrpc options
128
+ doc = PresserDoc.new struct["title"], struct["link"], struct["description"]
129
+ doc.categories = struct["categories"]
130
+ doc.postid = struct["postid"]
131
+ doc.post_status = struct["post_status"]
132
+ doc
133
+ end
134
+
135
+ def delete_post(postid)
136
+ options = { :url => @opt.url, :method => "blogger.deletePost",
137
+ :options => ["", postid, @opt.username, @opt.password, ""] }
138
+
139
+ result = call_xmlrpc options
140
+ result
141
+ end
142
+
143
+ end
144
+ end
145
+
146
+ # Struct returned by metaWeblog.getPost:
147
+ # {
148
+ # "dateCreated"=>#<XMLRPC::DateTime:0x00000100d96d80 @year=2011, @month=3, @day=5, @hour=2, @min=40, @sec=4>,
149
+ # "userid"=>"1",
150
+ # "postid"=>119,
151
+ # "description"=>"This is the body\nof the file.\n\nThis is [a link](http://www.google.com).",
152
+ # "title"=>"Put your title here",
153
+ # "link"=>"http://wordpress/wp/?p=119",
154
+ # "permaLink"=>"http://wordpress/wp/?p=119",
155
+ # "categories"=>["Uncategorized"],
156
+ # "mt_excerpt"=>"",
157
+ # "mt_text_more"=>"",
158
+ # "mt_allow_comments"=>1,
159
+ # "mt_allow_pings"=>1,
160
+ # "mt_keywords"=>"",
161
+ # "wp_slug"=>"put-your-title-here-7",
162
+ # "wp_password"=>"",
163
+ # "wp_author_id"=>"1",
164
+ # "wp_author_display_name"=>"jeff",
165
+ # "date_created_gmt"=>#<XMLRPC::DateTime:0x00000100db5ac8 @year=2011, @month=3, @day=5, @hour=2, @min=40, @sec=4>,
166
+ # "post_status"=>"publish",
167
+ # "custom_fields"=>[{"id"=>"180", "key"=>"_encloseme", "value"=>"1"}],
168
+ # "wp_post_format"=>"standard",
169
+ # "sticky"=>false
170
+ # }
171
+ #
172
+
data/post_template.txt ADDED
@@ -0,0 +1,12 @@
1
+ # Beginning of header
2
+ title: A newer title
3
+ link: http://www.jeffroush.com/technotes/2011/10/23/a-newer-title/
4
+ postid: 1247
5
+ post_status: publish
6
+ # End of header
7
+ This is the body
8
+ of the file.
9
+
10
+ This is [a link](http://www.google.com).
11
+
12
+ And it works. Woo hoo!
data/presser.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "presser/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "presser"
7
+ s.version = Presser::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = "Jeff Roush"
10
+ s.email = "jeff@jeffroush.com"
11
+ s.homepage = ""
12
+ s.summary = %q{A Ruby-based cli WordPress client}
13
+ s.description = %q{Nothing concrete yet -- just noodling.}
14
+
15
+ s.rubyforge_project = "presser"
16
+
17
+ s.add_development_dependency "rspec"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = "presser"
22
+ s.require_paths = ["lib"]
23
+ end
@@ -0,0 +1,14 @@
1
+ # Keep sensitive data (oh, cute ... sensitive!) out of git
2
+ module Presser
3
+ class NoGit
4
+ def self.username
5
+ "jeff"
6
+ end
7
+ def self.password
8
+ "calvin"
9
+ end
10
+ def self.url
11
+ "http://wordpress/wp/xmlrpc.php"
12
+ end
13
+ end
14
+ end
data/spec/post_spec.rb ADDED
@@ -0,0 +1,143 @@
1
+ require 'presser_xmlrpc'
2
+ require 'presser'
3
+
4
+ module Presser
5
+
6
+ # This assumes that you've created a config file with
7
+ # valid blog connection data, and that
8
+ # the string sample_post_filename specifies it.
9
+ describe BlogPost do
10
+ before(:each) do
11
+ end
12
+
13
+ after(:each) do
14
+ delete_sample_file
15
+ end
16
+
17
+ it "should read the source text file correctly" do
18
+ make_sample_file
19
+ bp = BlogPost.from_filename sample_post_filename
20
+ bp.title.should eql("Put your title here")
21
+ bp.postid.should eql("")
22
+
23
+ lines = sample_post_text.split("\n")
24
+ # puts lines.inspect
25
+ # Make sure that posting increases the line count
26
+ # Parse the returned string, and get the post id
27
+ end
28
+
29
+ it "should parse a metaWeblog struct" do
30
+ bp = BlogPost.new
31
+ bp.parse_struct sample_metaWeblog_struct
32
+ bp.title.should eql("Put your title here")
33
+ # bp.postid.should eql(119)
34
+ end
35
+
36
+ it "should update the source text file" do
37
+ make_sample_file
38
+ bp_initial = BlogPost.from_filename sample_post_filename
39
+
40
+ post_sample_file
41
+
42
+ bp_result = BlogPost.from_filename sample_post_filename
43
+
44
+ bp_result.title.should eql bp_initial.title
45
+ bp_result.postid.should_not eql ""
46
+ end
47
+
48
+ it "should delete a post when told to" do
49
+ make_sample_file
50
+ post_sample_file
51
+ bp_result = BlogPost.from_filename sample_post_filename
52
+
53
+ postid = bp_result.postid
54
+ delete_result = delete_post postid
55
+ delete_result.should be_true # always returns true. Even for failure.
56
+
57
+ null_post = get_post postid
58
+ null_post.should be_nil
59
+ end
60
+
61
+ it "should read the config file correctly" do
62
+ make_sample_file
63
+ presser = Presser.new ["-o #{sample_post_filename}"], config_file_name
64
+ presser.parsed_options.username.should eql("jeff")
65
+ end
66
+
67
+ it "should create a new post for a new file"
68
+
69
+ def make_sample_file
70
+ File.open(sample_post_filename, "w") { |file| file.puts sample_post_text }
71
+ end
72
+
73
+ def post_sample_file
74
+ presser = Presser.new ["-o #{sample_post_filename}"], config_file_name
75
+ presser.run
76
+ end
77
+
78
+ def get_post postid
79
+ presser = Presser.new ["-g #{postid}"], config_file_name
80
+ presser.run
81
+ end
82
+
83
+ def delete_post postid
84
+ presser = Presser.new ["-d #{postid}"], config_file_name
85
+ presser.delete_post postid
86
+ end
87
+
88
+ def delete_sample_file
89
+ `rm -f #{sample_post_filename}`
90
+ end
91
+
92
+ def sample_post_filename
93
+ "sample_post.md"
94
+ end
95
+
96
+ def sample_post_text
97
+ %Q{# Beginning of header
98
+ title: Put your title here
99
+ # End of header
100
+
101
+ This is the body
102
+ of the file.
103
+
104
+ This is [a link](http://www.google.com).
105
+ }
106
+ end
107
+
108
+ def config_file_name
109
+ "presser_config_file.yml"
110
+ end
111
+
112
+
113
+ # "dateCreated"=>#<XMLRPC::DateTime:0x00000100d96d80 @year=2011, @month=3, @day=5, @hour=2, @min=40, @sec=4>,
114
+ def sample_metaWeblog_struct
115
+ {
116
+ "dateCreated"=>"01/01/2011",
117
+ "userid"=>"1",
118
+ "description"=>"This is the body\nof the file.\n\nThis is [a link](http://www.google.com).",
119
+ "title"=>"Put your title here",
120
+ "link"=>"http://wordpress/wp/?p=119",
121
+ "permaLink"=>"http://wordpress/wp/?p=119",
122
+ "categories"=>["Uncategorized"],
123
+ "mt_excerpt"=>"",
124
+ "mt_text_more"=>"",
125
+ "mt_allow_comments"=>1,
126
+ "mt_allow_pings"=>1,
127
+ "mt_keywords"=>"",
128
+ "wp_slug"=>"put-your-title-here-7",
129
+ "wp_password"=>"",
130
+ "wp_author_id"=>"1",
131
+ "wp_author_display_name"=>"jeff",
132
+ "post_status"=>"publish",
133
+ "custom_fields"=>[{"id"=>"180", "key"=>"_encloseme", "value"=>"1"}],
134
+ "wp_post_format"=>"standard",
135
+ "sticky"=>false
136
+ }
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+
143
+ # Struct returned by metaWeblog.getPost:
@@ -0,0 +1,12 @@
1
+ require 'presser_doc'
2
+
3
+ describe "Presser defaults" do
4
+ it "should have a default doc" do
5
+ # doc = Presser::PresserDoc.new "title", "link", "desc"
6
+ doc = Presser::PresserDoc.new "title"
7
+ doc.new_doc
8
+ #doc.should eql(" ")
9
+ end
10
+ end
11
+
12
+
@@ -0,0 +1,38 @@
1
+ require 'presser'
2
+ require 'presser_opts'
3
+ require 'dont_git_this'
4
+
5
+ describe "Presser defaults" do
6
+ before(:each) do
7
+ @pr = Presser::Presser.new([""])
8
+ @config_filename = "temp_config.txt"
9
+ `rm -f #{@config_filename}`
10
+ end
11
+
12
+ it "should have default username of WaltKelly" do
13
+ @pr.parsed_options.username.should eql('WaltKelly')
14
+ end
15
+
16
+ it "should have default password of pogo" do
17
+ @pr.parsed_options.password.should eql('pogo')
18
+ end
19
+
20
+ it "should have default url of my test machine" do
21
+ @pr.parsed_options.url = "http://wordpress/wp/xmlrpc.php"
22
+ end
23
+
24
+ it "should generate the correct options string for the config file" do
25
+ argv = ["-u #{Presser::NoGit.username}",
26
+ "-p #{Presser::NoGit.password}",
27
+ "-U #{Presser::NoGit.url}"]
28
+
29
+ str = %Q{username: #{Presser::NoGit.username}
30
+ password: #{Presser::NoGit.password}
31
+ url: #{Presser::NoGit.url}}
32
+
33
+ opts = Presser::PresserOpts.new argv
34
+ opts.config_file_contents.should eql(str)
35
+ end
36
+
37
+ end
38
+
@@ -0,0 +1,14 @@
1
+ require 'presser'
2
+
3
+ describe "Presser defaults" do
4
+ before(:each) do
5
+ end
6
+
7
+ it "should override saved options with command line" do
8
+ pr = Presser::Presser.new(["-U foo", "-p mikey"], "presser_config_file.yml")
9
+ pr.parsed_options.url.should eql("foo")
10
+ pr.parsed_options.username.should eql("jeff")
11
+ pr.parsed_options.password.should eql("mikey")
12
+ end
13
+ end
14
+
@@ -0,0 +1,24 @@
1
+ require 'presser'
2
+ require 'presser_xmlrpc'
3
+ require 'dont_git_this'
4
+
5
+ describe "Presser net access" do
6
+ before(:each) do
7
+ # @pr = Presser::Presser.new(["-u #{Presser::NoGit.username}", "-p #{Presser::NoGit.password}"])
8
+ @pr = Presser::Presser.new(["-U foo", "-u mikey"], "presser_config_file.yml")
9
+
10
+ # @rpc = Presser::PresserXmlrpc.new @pr.parsed_options
11
+ end
12
+
13
+ it "should be an xmlrpc client" do
14
+ # puts "@pr: #{@pr.parsed_options.inspect}"
15
+ # @rpc.getUsersBlogs.length.should eql(1)
16
+ # @rpc.getPostStatusList.length.should eql(4)
17
+ # @rpc.getTags.length.should eql(0)
18
+ # @rpc.getPageList.length.should eql(1)
19
+ # @rpc.getRecentPosts.length.should eql(2)
20
+ # @rpc.newPost
21
+ end
22
+ end
23
+
24
+
data/spec/yaml_spec.rb ADDED
@@ -0,0 +1,64 @@
1
+ require 'presser_opts'
2
+
3
+ module Presser
4
+ describe PresserOpts do
5
+
6
+ before(:each) do
7
+ `rm -f #{test_config_file}`
8
+ @opts = PresserOpts.from_yaml dummy_yaml
9
+ end
10
+
11
+ after(:each) do
12
+ `rm -f #{test_config_file}`
13
+ end
14
+
15
+ it "should restore from yaml string" do
16
+ @opts.parsed.password.should eql("foo")
17
+ end
18
+ it "should generate a yaml string" do
19
+ @opts.to_yaml.should eql(dummy_yaml)
20
+ end
21
+
22
+ it "should save the config to a file" do
23
+
24
+ @opts.parsed.config_file_name.should eql(test_config_file)
25
+ File.exists?(@opts.parsed.config_file_name).should be_false
26
+ @opts.save_to_file
27
+ File.exists?(@opts.parsed.config_file_name).should be_true
28
+
29
+ File.new(test_config_file).read.should eql dummy_yaml
30
+ end
31
+
32
+ it "should load from a config file" do
33
+ @opts.save_to_file
34
+ opts2 = PresserOpts.from_file test_config_file
35
+
36
+ @opts.parsed.config_file_name.should eql(opts2.parsed.config_file_name)
37
+ end
38
+
39
+
40
+ # ******************************************************
41
+ # Define some strings for testing
42
+ #
43
+ def test_config_file
44
+ "temp_config_file.txt"
45
+ end
46
+
47
+ def dummy_yaml
48
+ %Q{verbose: false
49
+ username: WaltKelly
50
+ password: foo
51
+ url: http://wordpress/wp/xmlrpc.php
52
+ file_to_upload:
53
+ upload_file: false
54
+ pretend: false
55
+ post_file: false
56
+ file_to_post:
57
+ make_config_file: false
58
+ config_file_name: #{test_config_file}
59
+ }
60
+ end
61
+
62
+ end
63
+
64
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: presser
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Jeff Roush
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-23 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :development
33
+ version_requirements: *id001
34
+ description: Nothing concrete yet -- just noodling.
35
+ email: jeff@jeffroush.com
36
+ executables:
37
+ - presser
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - .gitignore
44
+ - .presser
45
+ - .rvmrc
46
+ - Gemfile
47
+ - README.md
48
+ - Rakefile
49
+ - bin/presser
50
+ - lib/blog_post.rb
51
+ - lib/local_file.rb
52
+ - lib/presser.rb
53
+ - lib/presser/version.rb
54
+ - lib/presser_doc.rb
55
+ - lib/presser_opts.rb
56
+ - lib/presser_xmlrpc.rb
57
+ - post_template.txt
58
+ - presser.gemspec
59
+ - spec/dont_git_this.rb
60
+ - spec/post_spec.rb
61
+ - spec/presser_doc_spec.rb
62
+ - spec/presser_opts_spec.rb
63
+ - spec/presser_spec.rb
64
+ - spec/test_presser_net_spec.rb
65
+ - spec/yaml_spec.rb
66
+ homepage: ""
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options: []
71
+
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project: presser
95
+ rubygems_version: 1.8.11
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A Ruby-based cli WordPress client
99
+ test_files:
100
+ - spec/dont_git_this.rb
101
+ - spec/post_spec.rb
102
+ - spec/presser_doc_spec.rb
103
+ - spec/presser_opts_spec.rb
104
+ - spec/presser_spec.rb
105
+ - spec/test_presser_net_spec.rb
106
+ - spec/yaml_spec.rb