git-scribe 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/{README.asc → README.asciidoc} +5 -1
- data/lib/git-scribe.rb +64 -13
- data/lib/subcommand.rb +266 -0
- metadata +6 -5
@@ -44,14 +44,18 @@ For local generation (evenutally pushing to GitHub will handle gen for you), it
|
|
44
44
|
Usage
|
45
45
|
=====
|
46
46
|
|
47
|
-
Initialize a new book with `init
|
47
|
+
Initialize a new book with `init`:
|
48
48
|
|
49
49
|
$ git scribe init
|
50
50
|
|
51
51
|
This will set up the outline for your book. All the book content goes into the 'book' subdirectory with 'book.asc' as the starting point. If you want to split the writing up into multiple files you can simply include them in the book.asc file.
|
52
52
|
|
53
|
+
Then you can generate your book content with the 'git scribe gen' command:
|
54
|
+
|
53
55
|
$ git scribe gen [site|html|pdf|epub|mobi|all]
|
54
56
|
|
57
|
+
Eventually, simply pushing to GitHub will take care of this for you.
|
58
|
+
|
55
59
|
Roadmap
|
56
60
|
=======
|
57
61
|
|
data/lib/git-scribe.rb
CHANGED
@@ -1,17 +1,40 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'nokogiri'
|
3
3
|
require 'liquid'
|
4
|
+
require 'subcommand'
|
4
5
|
|
5
6
|
require 'fileutils'
|
6
7
|
require 'pp'
|
7
8
|
|
8
9
|
class GitScribe
|
9
10
|
|
11
|
+
BOOK_FILE = 'book.asc'
|
12
|
+
OUTPUT_TYPES = ['pdf', 'epub', 'mobi', 'html', 'site']
|
10
13
|
SCRIBE_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
11
14
|
|
12
15
|
def initialize(args)
|
13
|
-
@
|
14
|
-
|
16
|
+
@options = {}
|
17
|
+
global_options do |opts|
|
18
|
+
opts.banner = "Usage: #{$0} [options] [subcommand [options]]"
|
19
|
+
opts.description = "git-scribe helps you write books with the power of Git"
|
20
|
+
opts.separator ""
|
21
|
+
opts.separator "Global options are:"
|
22
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
23
|
+
@options[:verbose] = v
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
command :init do |opts|
|
28
|
+
opts.banner = "Usage: init [options]"
|
29
|
+
opts.description = "initialize a new book layout"
|
30
|
+
opts.on("-l", "--lang", "choose a default language (en)") do |v|
|
31
|
+
@options[:lang] = lang || 'en'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
pp @options
|
36
|
+
|
37
|
+
opt_parse
|
15
38
|
end
|
16
39
|
|
17
40
|
def self.start(args)
|
@@ -28,27 +51,56 @@ class GitScribe
|
|
28
51
|
|
29
52
|
## COMMANDS ##
|
30
53
|
|
31
|
-
def help
|
32
|
-
puts "No command: #{@command}"
|
33
|
-
puts "TODO: tons of help"
|
34
|
-
end
|
35
54
|
|
36
55
|
# start a new scribe directory with skeleton structure
|
37
56
|
def init
|
57
|
+
name = ARGV.shift
|
58
|
+
die("needs a directory name") if !name
|
59
|
+
die("directory already exists") if File.exists?(name)
|
60
|
+
|
61
|
+
puts "inititalizing #{name}"
|
62
|
+
from_stdir = File.join(SCRIBE_ROOT, 'template')
|
63
|
+
FileUtils.cp_r from_stdir, name
|
38
64
|
end
|
39
65
|
|
40
66
|
# check that we have everything needed
|
41
67
|
def check
|
42
|
-
#
|
43
|
-
|
68
|
+
# check for asciidoc
|
69
|
+
if !check_can_run('asciidoc')
|
70
|
+
puts "asciidoc is not present, please install it for anything to work"
|
71
|
+
else
|
72
|
+
puts "asciidoc - ok"
|
73
|
+
end
|
44
74
|
|
45
|
-
|
75
|
+
# check for xsltproc
|
76
|
+
if !check_can_run('xsltproc --version')
|
77
|
+
puts "xsltproc is not present, please install it for html generation"
|
78
|
+
else
|
79
|
+
puts "xsltproc - ok"
|
80
|
+
end
|
46
81
|
|
47
|
-
|
82
|
+
# check for a2x - should be installed with asciidoc, but you never know
|
83
|
+
if !check_can_run('a2x')
|
84
|
+
puts "a2x is not present, please install it for epub generation"
|
85
|
+
else
|
86
|
+
puts "a2x - ok"
|
87
|
+
end
|
88
|
+
|
89
|
+
# check for fop
|
90
|
+
if !check_can_run('fop -version')
|
91
|
+
puts "fop is not present, please install for PDF generation"
|
92
|
+
else
|
93
|
+
puts "fop - ok"
|
94
|
+
end
|
95
|
+
end
|
48
96
|
|
97
|
+
def check_can_run(command)
|
98
|
+
`#{command} 2>&1`
|
99
|
+
$?.exitstatus == 0
|
100
|
+
end
|
49
101
|
# generate the new media
|
50
102
|
def gen
|
51
|
-
type =
|
103
|
+
type = ARGV.shift || 'all'
|
52
104
|
prepare_output_dir
|
53
105
|
|
54
106
|
gather_and_process
|
@@ -66,8 +118,7 @@ class GitScribe
|
|
66
118
|
end
|
67
119
|
end
|
68
120
|
# clean up
|
69
|
-
|
70
|
-
# TODO: open media (?)
|
121
|
+
`rm #{BOOK_FILE}`
|
71
122
|
end
|
72
123
|
end
|
73
124
|
|
data/lib/subcommand.rb
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
######################################
|
3
|
+
# A tiny wrapper over optparse that gives easy subcommand facility.
|
4
|
+
# It also neatly prints help for global and subcommands
|
5
|
+
# as well as summarizes subcommands in global help.
|
6
|
+
#
|
7
|
+
# Thanks to Robert Klemme for his idea on lazy loading the subcommand option parsers.
|
8
|
+
#
|
9
|
+
# @author Rahul Kumar, Jun 2010
|
10
|
+
# @date 2010-06-20 22:33
|
11
|
+
#
|
12
|
+
# @examples
|
13
|
+
# if a program has subcommands foo and baz
|
14
|
+
#
|
15
|
+
# ruby subcommand.rb help
|
16
|
+
# ruby subcommand.rb --help
|
17
|
+
# ruby subcommand.rb help foo
|
18
|
+
# ruby subcommand.rb foo --help
|
19
|
+
# ruby subcommand.rb baz --quiet "some text"
|
20
|
+
# ruby subcommand.rb --verbose foo --force file.zzz
|
21
|
+
#
|
22
|
+
# == STEPS
|
23
|
+
# 1. define global_options (optional)
|
24
|
+
#
|
25
|
+
# global_options do |opts|
|
26
|
+
# opts.banner = "Usage: #{$0} [options] [subcommand [options]]"
|
27
|
+
# opts.description = "Stupid program that does something"
|
28
|
+
# opts.separator ""
|
29
|
+
# opts.separator "Global options are:"
|
30
|
+
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
31
|
+
# options[:verbose] = v
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# 2. define commands using command().
|
36
|
+
# command :foo do |opts|
|
37
|
+
# opts.banner = "Usage: foo [options]"
|
38
|
+
# opts.description = "desc for foo"
|
39
|
+
# opts.on("-f", "--[no-]force", "force verbosely") do |v|
|
40
|
+
# options[:force] = v
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# 3. call opt_parse()
|
45
|
+
#
|
46
|
+
# 4. As before, handle ARGS and options hash.
|
47
|
+
#
|
48
|
+
# TODO: add aliases for commands
|
49
|
+
######################################
|
50
|
+
require 'optparse'
|
51
|
+
|
52
|
+
# Allow command to have a description to generate help
|
53
|
+
class OptionParser
|
54
|
+
attr_accessor :description
|
55
|
+
#attr_accessor :action
|
56
|
+
end
|
57
|
+
|
58
|
+
module Subcommands
|
59
|
+
##
|
60
|
+
# specify a single command and all its options
|
61
|
+
# If multiple names are given, they are treated as aliases.
|
62
|
+
# Do repeatedly for each command
|
63
|
+
# Yields the optionparser
|
64
|
+
def command *names
|
65
|
+
name = names.shift
|
66
|
+
@commands ||= {}
|
67
|
+
@aliases ||= {}
|
68
|
+
if names.length > 0
|
69
|
+
names.each do |n|
|
70
|
+
#puts "aliases #{n} => #{name} "
|
71
|
+
@aliases[n.to_s] = name.to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
# Thanks to Robert Klemme for the lazy loading idea.
|
75
|
+
opt = lambda { OptionParser.new do |opts|
|
76
|
+
yield opts
|
77
|
+
# append desc to banner in next line
|
78
|
+
opts.banner << "\n#{opts.description}\n" if opts.description
|
79
|
+
end }
|
80
|
+
@commands[name.to_s] = opt
|
81
|
+
end
|
82
|
+
# specify global options and banner and description
|
83
|
+
# Yields the optionparser
|
84
|
+
def global_options
|
85
|
+
if !defined? @global
|
86
|
+
@global = OptionParser.new do |opts|
|
87
|
+
yield opts
|
88
|
+
end
|
89
|
+
else
|
90
|
+
yield @global
|
91
|
+
end
|
92
|
+
end
|
93
|
+
def print_actions
|
94
|
+
cmdtext = "Commands are:"
|
95
|
+
@commands.each_pair do |c, opt|
|
96
|
+
#puts "inside opt.call loop"
|
97
|
+
desc = opt.call.description
|
98
|
+
cmdtext << "\n #{c} : #{desc}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# print aliases
|
102
|
+
unless @aliases.empty?
|
103
|
+
cmdtext << "\n\nAliases: \n"
|
104
|
+
@aliases.each_pair { |name, val| cmdtext << " #{name} - #{val}\n" }
|
105
|
+
end
|
106
|
+
|
107
|
+
cmdtext << "\n\nSee '#{$0} help COMMAND' for more information on a specific command."
|
108
|
+
end
|
109
|
+
## add text of subcommands in help and --help option
|
110
|
+
def add_subcommand_help
|
111
|
+
# user has defined some, but lets add subcommand information
|
112
|
+
|
113
|
+
cmdtext = print_actions
|
114
|
+
|
115
|
+
global_options do |opts|
|
116
|
+
# lets add the description user gave into banner
|
117
|
+
opts.banner << "\n#{opts.description}\n" if opts.description
|
118
|
+
opts.separator ""
|
119
|
+
opts.separator cmdtext
|
120
|
+
end
|
121
|
+
end
|
122
|
+
# this is so that on pressing --help he gets same subcommand help as when doing help.
|
123
|
+
# This is to be added in your main program, after defining global options
|
124
|
+
# if you want detailed help on --help. This is since optionparser's default
|
125
|
+
# --help will not print your actions/commands
|
126
|
+
def add_help_option
|
127
|
+
global_options do |opts|
|
128
|
+
opts.on("-h", "--help", "Print this help") do |v|
|
129
|
+
add_subcommand_help
|
130
|
+
puts @global
|
131
|
+
exit
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
# first parse global optinos
|
136
|
+
# then parse subcommand options if valid subcommand
|
137
|
+
# special case of "help command" so we print help of command - git style (3)
|
138
|
+
# in all invalid cases print global help
|
139
|
+
# @return command name if relevant
|
140
|
+
def opt_parse
|
141
|
+
# if user has not defined global, we need to create it
|
142
|
+
@command_name = nil
|
143
|
+
if !defined? @global
|
144
|
+
global_options do |opts|
|
145
|
+
opts.banner = "Usage: #{$0} [options] [subcommand [options]]"
|
146
|
+
opts.separator ""
|
147
|
+
opts.separator "Global options are:"
|
148
|
+
opts.on("-h", "--help", "Print this help") do |v|
|
149
|
+
add_subcommand_help
|
150
|
+
puts @global
|
151
|
+
exit
|
152
|
+
end
|
153
|
+
opts.separator ""
|
154
|
+
#opts.separator subtext # FIXME: no such variable supposed to have subcommand help
|
155
|
+
end
|
156
|
+
else
|
157
|
+
end
|
158
|
+
@global.order!
|
159
|
+
cmd = ARGV.shift
|
160
|
+
if cmd
|
161
|
+
#$stderr.puts "Command: #{cmd}, args:#{ARGV}, #{@commands.keys} "
|
162
|
+
sc = @commands[cmd]
|
163
|
+
#puts "sc: #{sc}: #{@commands}"
|
164
|
+
unless sc
|
165
|
+
# see if an alias exists
|
166
|
+
sc, cmd = _check_alias cmd
|
167
|
+
end
|
168
|
+
# if valid command parse the args
|
169
|
+
if sc
|
170
|
+
@command_name = cmd
|
171
|
+
sc.call.order!
|
172
|
+
else
|
173
|
+
# else if help <command> then print its help GIT style (3)
|
174
|
+
if !ARGV.empty? && cmd == "help"
|
175
|
+
cmd = ARGV.shift
|
176
|
+
#$stderr.puts " 110 help #{cmd}"
|
177
|
+
sc = @commands[cmd]
|
178
|
+
# if valid command print help, else print global help
|
179
|
+
unless sc
|
180
|
+
sc, cmd = _check_alias cmd
|
181
|
+
end
|
182
|
+
if sc
|
183
|
+
#puts " 111 help #{cmd}"
|
184
|
+
puts sc.call
|
185
|
+
else
|
186
|
+
# no help for this command XXX check for alias
|
187
|
+
puts "Invalid command: #{cmd}."
|
188
|
+
add_subcommand_help
|
189
|
+
puts @global
|
190
|
+
end
|
191
|
+
else
|
192
|
+
# invalid command
|
193
|
+
puts "Invalid command: #{cmd}" unless cmd == "help"
|
194
|
+
add_subcommand_help
|
195
|
+
puts @global
|
196
|
+
end
|
197
|
+
exit 0
|
198
|
+
end
|
199
|
+
end
|
200
|
+
return @command_name
|
201
|
+
end
|
202
|
+
def alias_command name, *args
|
203
|
+
@aliases[name.to_s] = args
|
204
|
+
end
|
205
|
+
def _check_alias cmd
|
206
|
+
alas = @aliases[cmd]
|
207
|
+
#$stderr.puts "195 alas: #{alas} "
|
208
|
+
if alas
|
209
|
+
case alas
|
210
|
+
when Array
|
211
|
+
cmd = alas.shift
|
212
|
+
#$stderr.puts "Array cmd: #{cmd} "
|
213
|
+
ARGV.unshift alas.shift unless alas.empty?
|
214
|
+
#$stderr.puts "ARGV #{ARGV} "
|
215
|
+
else
|
216
|
+
cmd = alas
|
217
|
+
end
|
218
|
+
end
|
219
|
+
sc = @commands[cmd] if cmd
|
220
|
+
return sc, cmd
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
if __FILE__ == $PROGRAM_NAME
|
225
|
+
include Subcommands
|
226
|
+
options = {}
|
227
|
+
appname = File.basename($0)
|
228
|
+
# global is optional
|
229
|
+
global_options do |opts|
|
230
|
+
opts.banner = "Usage: #{appname} [options] [subcommand [options]]"
|
231
|
+
opts.description = "Stupid program that does something"
|
232
|
+
opts.separator ""
|
233
|
+
opts.separator "Global options are:"
|
234
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
235
|
+
options[:verbose] = v
|
236
|
+
end
|
237
|
+
end
|
238
|
+
add_help_option
|
239
|
+
# define a command
|
240
|
+
command :foo, :goo do |opts|
|
241
|
+
opts.banner = "Usage: foo [options]"
|
242
|
+
opts.description = "desc for foo"
|
243
|
+
opts.on("-f", "--[no-]force", "force verbosely") do |v|
|
244
|
+
options[:force] = v
|
245
|
+
end
|
246
|
+
end
|
247
|
+
command :baz do |opts|
|
248
|
+
opts.banner = "Usage: baz [options]"
|
249
|
+
opts.description = "desc for baz"
|
250
|
+
opts.on("-q", "--[no-]quiet", "quietly run ") do |v|
|
251
|
+
options[:quiet] = v
|
252
|
+
end
|
253
|
+
end
|
254
|
+
alias_command :bar, 'baz'
|
255
|
+
alias_command :boo, 'foo', '--force'
|
256
|
+
alias_command :zoo, 'foo', 'ruby'
|
257
|
+
|
258
|
+
# do the parsing.
|
259
|
+
cmd = opt_parse()
|
260
|
+
|
261
|
+
puts "cmd: #{cmd}"
|
262
|
+
puts "options ......"
|
263
|
+
p options
|
264
|
+
puts "ARGV:"
|
265
|
+
p ARGV
|
266
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-scribe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Scott Chacon
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-17 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -29,8 +29,9 @@ extra_rdoc_files: []
|
|
29
29
|
|
30
30
|
files:
|
31
31
|
- LICENSE
|
32
|
-
- README.
|
32
|
+
- README.asciidoc
|
33
33
|
- lib/git-scribe.rb
|
34
|
+
- lib/subcommand.rb
|
34
35
|
- bin/git-scribe
|
35
36
|
has_rdoc: true
|
36
37
|
homepage: http://github.com/schacon/git-scribe
|