presser 0.1.1

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/.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