presser 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.presser +11 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README.md +37 -0
- data/Rakefile +23 -0
- data/bin/presser +10 -0
- data/lib/blog_post.rb +134 -0
- data/lib/local_file.rb +44 -0
- data/lib/presser/version.rb +3 -0
- data/lib/presser.rb +117 -0
- data/lib/presser_doc.rb +43 -0
- data/lib/presser_opts.rb +177 -0
- data/lib/presser_xmlrpc.rb +172 -0
- data/post_template.txt +12 -0
- data/presser.gemspec +23 -0
- data/spec/dont_git_this.rb +14 -0
- data/spec/post_spec.rb +143 -0
- data/spec/presser_doc_spec.rb +12 -0
- data/spec/presser_opts_spec.rb +38 -0
- data/spec/presser_spec.rb +14 -0
- data/spec/test_presser_net_spec.rb +24 -0
- data/spec/yaml_spec.rb +64 -0
- metadata +106 -0
data/.gitignore
ADDED
data/.presser
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm gemset use presser
|
data/Gemfile
ADDED
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
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
|
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
|
+
|
data/lib/presser_doc.rb
ADDED
@@ -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
|
data/lib/presser_opts.rb
ADDED
@@ -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
|
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,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
|