khaleesi 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +7 -0
- data/LICENSE +22 -0
- data/bin/khaleesi +10 -0
- data/khaleesi.gemspec +18 -0
- data/lib/khaleesi.rb +12 -0
- data/lib/khaleesi/about.rb +23 -0
- data/lib/khaleesi/cli.rb +641 -0
- data/lib/khaleesi/generator.rb +635 -0
- data/test/khaleesi_commands_test.rb +50 -0
- data/test/khaleesi_test.rb +171 -0
- data/test/resources/java-samplecode +9 -0
- data/test/resources/test_parse_single_file.md +26 -0
- data/test/resources/test_parse_single_file_enable_linenumbers_result +25 -0
- data/test/resources/test_parse_single_file_without_linenumbers_result +20 -0
- data/test/resources/test_site/_decorators/basic.html +25 -0
- data/test/resources/test_site/_decorators/code_snippet.html +8 -0
- data/test/resources/test_site/_decorators/post.html +6 -0
- data/test/resources/test_site/_decorators/theme.html +15 -0
- data/test/resources/test_site/_pages/index.html +49 -0
- data/test/resources/test_site/_pages/javasmpcode.md +11 -0
- data/test/resources/test_site/_pages/posts/2013/netroid-introduction.md +11 -0
- data/test/resources/test_site/_pages/posts/2014/khaleesi-introduction.md +8 -0
- data/test/resources/test_site/_pages/studio/cameras/camera1.md +6 -0
- data/test/resources/test_site/_pages/studio/cameras/camera2.md +6 -0
- data/test/resources/test_site/_pages/studio/cameras/camera3.md +6 -0
- data/test/resources/test_site/_pages/studio/cameras/camera4.md +6 -0
- data/test/resources/test_site/_pages/themes/base16_solarized.md +119 -0
- data/test/resources/test_site/_pages/themes/base16_solarized_dark.md +117 -0
- data/test/resources/test_site/_pages/themes/github.md +272 -0
- data/test/resources/test_site/_pages/themes_illustrates/base16_solarized.html +4 -0
- data/test/resources/test_site/_pages/themes_illustrates/base16_solarized_dark.html +4 -0
- data/test/resources/test_site/_pages/themes_illustrates/github.html +4 -0
- data/test/resources/test_site/_pages/themes_illustrates/monokai.html +4 -0
- data/test/resources/test_site/_pages/themes_illustrates/monokai_sublime.html +4 -0
- data/test/resources/test_site/_raw/css/site.css +340 -0
- data/test/resources/test_site/expected_base16_solarized_dark_html +146 -0
- data/test/resources/test_site/expected_base16_solarized_html +150 -0
- data/test/resources/test_site/expected_github_html +301 -0
- data/test/resources/test_site/expected_index_html +373 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9e0a8fd44c75e9c7d937f4efd82ebc9ce7933c7e
|
4
|
+
data.tar.gz: 393d25d665231d57aa39c05d300593a5817abd60
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6830c6e5ccff0c45ff75431a4fccb22c75c09ffb1e9b26976338b95efec91cf70b27c9504870dd267e2f12872289b36c284291501d88c78cb720066a45eb7acf
|
7
|
+
data.tar.gz: 69ce1fb7261c8de29ab512c7a9cc2bcd160a88e565c20dabcc6cd4c672e9b73ceae8691e033e3b97b2d10672a83531d42f7b59d4a046f54b5a69d9338a7b591e
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Vince-Styling
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/bin/khaleesi
ADDED
data/khaleesi.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'khaleesi/about'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'khaleesi'
|
7
|
+
spec.version = Khaleesi::version
|
8
|
+
spec.authors = Khaleesi::author
|
9
|
+
spec.date = Khaleesi::date
|
10
|
+
spec.email = 'lingyunxiao@qq.com'
|
11
|
+
spec.summary = Khaleesi::summary
|
12
|
+
spec.description = 'Khaleesi is a blog-aware or documentation-aware static site generator write in Ruby, supports markdown parser, series of decorators wrapping, code syntax highlighting, simple page script programming, page including, dataset traversing etc.'
|
13
|
+
spec.homepage = Khaleesi::site
|
14
|
+
spec.rubyforge_project = 'khaleesi'
|
15
|
+
spec.files = Dir['Gemfile', 'LICENSE', 'khaleesi.gemspec', 'lib/**/*.rb', 'bin/khaleesi', 'test/**/*']
|
16
|
+
spec.executables = %w(khaleesi)
|
17
|
+
spec.license = 'MIT (see LICENSE file)'
|
18
|
+
end
|
data/lib/khaleesi.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Khaleesi
|
2
|
+
def self.version
|
3
|
+
'0.1.0'
|
4
|
+
end
|
5
|
+
def self.author
|
6
|
+
'vince styling'
|
7
|
+
end
|
8
|
+
def self.date
|
9
|
+
'2014-09-17'
|
10
|
+
end
|
11
|
+
def self.site
|
12
|
+
'http://khaleesi.vincestyling.com/'
|
13
|
+
end
|
14
|
+
def self.summary
|
15
|
+
'Khaleesi is a static site generator write in Ruby.'
|
16
|
+
end
|
17
|
+
def self.about
|
18
|
+
puts self.summary
|
19
|
+
puts "site : #{self.site}."
|
20
|
+
puts "author : #{self.author}."
|
21
|
+
puts "version : #{self.version}."
|
22
|
+
end
|
23
|
+
end
|
data/lib/khaleesi/cli.rb
ADDED
@@ -0,0 +1,641 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Khaleesi
|
4
|
+
class CLI
|
5
|
+
def self.doc
|
6
|
+
return enum_for(:doc) unless block_given?
|
7
|
+
|
8
|
+
yield 'usage: khaleesi [command] [args...]'
|
9
|
+
yield ''
|
10
|
+
yield 'where <command> is one of:'
|
11
|
+
yield %| help\|h #{Help.desc}|
|
12
|
+
yield %| version\|v #{Version.desc}|
|
13
|
+
yield %| about #{About.desc}|
|
14
|
+
yield %| produce\|p #{Produce.desc}|
|
15
|
+
yield %| construction\|c #{Construction.desc}|
|
16
|
+
yield %| createpost\|cp #{CreatePost.desc}|
|
17
|
+
yield %| generate\|g #{Generate.desc}|
|
18
|
+
yield %| build\|b #{Build.desc}|
|
19
|
+
yield ''
|
20
|
+
yield 'See `khaleesi help <command>` for more info.'
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(options={})
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.parse(argv=ARGV)
|
27
|
+
argv = normalize_syntax(argv)
|
28
|
+
|
29
|
+
mode = argv.shift
|
30
|
+
|
31
|
+
klass = class_from_arg(mode)
|
32
|
+
klass.parse(argv)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.class_from_arg(arg)
|
36
|
+
case arg
|
37
|
+
when 'construction', 'c'
|
38
|
+
Construction
|
39
|
+
when 'createpost', 'cp'
|
40
|
+
CreatePost
|
41
|
+
when 'generate', 'g'
|
42
|
+
Generate
|
43
|
+
when 'version', 'v'
|
44
|
+
Version
|
45
|
+
when 'produce', 'p'
|
46
|
+
Produce
|
47
|
+
when 'build', 'b'
|
48
|
+
Build
|
49
|
+
when 'help', 'h'
|
50
|
+
Help
|
51
|
+
else
|
52
|
+
About
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Version < CLI
|
57
|
+
def self.desc
|
58
|
+
'print the khaleesi version number'
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.parse(*)
|
62
|
+
; new;
|
63
|
+
end
|
64
|
+
|
65
|
+
def run
|
66
|
+
puts "Khaleesi : #{Khaleesi.version}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class About < CLI
|
71
|
+
def self.desc
|
72
|
+
'print about khaleesi\'s information'
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.parse(*)
|
76
|
+
; new;
|
77
|
+
end
|
78
|
+
|
79
|
+
def run
|
80
|
+
puts Khaleesi.about
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Produce < CLI
|
85
|
+
def self.desc
|
86
|
+
'produce html code for specify markdown file'
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.doc
|
90
|
+
return enum_for(:doc) unless block_given?
|
91
|
+
|
92
|
+
yield 'usage: khaleesi produce <filename>'
|
93
|
+
yield ''
|
94
|
+
yield '<filename> specify a file to read'
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.parse(argv)
|
98
|
+
opts = {:input_file => nil}
|
99
|
+
|
100
|
+
until argv.empty?
|
101
|
+
opts[:input_file] = argv.shift
|
102
|
+
end
|
103
|
+
|
104
|
+
puts 'unspecific markdown file' unless opts[:input_file]
|
105
|
+
|
106
|
+
new(opts)
|
107
|
+
end
|
108
|
+
|
109
|
+
def input_stream
|
110
|
+
@input_stream ||= FileReader.new(@input_file)
|
111
|
+
end
|
112
|
+
|
113
|
+
def input
|
114
|
+
@input ||= input_stream.read
|
115
|
+
end
|
116
|
+
|
117
|
+
attr_reader :input_file
|
118
|
+
|
119
|
+
def initialize(opts={})
|
120
|
+
@input_file = opts[:input_file]
|
121
|
+
end
|
122
|
+
|
123
|
+
def run
|
124
|
+
return unless @input_file
|
125
|
+
print Generator.new.handle_markdown(input)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class CreatePost < CLI
|
130
|
+
def self.desc
|
131
|
+
'create a new page in pwd with an unique identifier which composed by 20 characters like "b36446316f29e2b97a7d"'
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.doc
|
135
|
+
return enum_for(:doc) unless block_given?
|
136
|
+
|
137
|
+
yield 'usage: khaleesi createpost <filename>'
|
138
|
+
yield ''
|
139
|
+
yield '<filename> specify a page file name (exclude extension)'
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.parse(argv)
|
143
|
+
opts = {:page_name => nil}
|
144
|
+
|
145
|
+
until argv.empty?
|
146
|
+
opts[:page_name] = argv.shift
|
147
|
+
end
|
148
|
+
|
149
|
+
puts 'unspecific page name' unless opts[:page_name]
|
150
|
+
|
151
|
+
new(opts)
|
152
|
+
end
|
153
|
+
|
154
|
+
attr_reader :page_name
|
155
|
+
|
156
|
+
def initialize(opts={})
|
157
|
+
@page_name = opts[:page_name]
|
158
|
+
end
|
159
|
+
|
160
|
+
def run
|
161
|
+
return unless @page_name
|
162
|
+
|
163
|
+
page_path = "#{Dir.pwd}/#{@page_name}.md"
|
164
|
+
open(page_path, 'w') do |f|
|
165
|
+
f.puts 'title: <input page title>'
|
166
|
+
f.puts 'decorator: <input page decorator>'
|
167
|
+
f.puts "identifier: #{SecureRandom.hex(10)}"
|
168
|
+
f.puts '‡‡‡‡‡‡‡‡‡‡‡‡‡‡'
|
169
|
+
f.puts 'here is page content.'
|
170
|
+
end
|
171
|
+
|
172
|
+
puts "A post page was created : #{page_path}."
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
class Construction < CLI
|
177
|
+
def self.desc
|
178
|
+
'create a site directory with whole structure at present working directory(pwd)'
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.doc
|
182
|
+
return enum_for(:doc) unless block_given?
|
183
|
+
|
184
|
+
yield 'usage: khaleesi construction <directory_name>'
|
185
|
+
yield ''
|
186
|
+
yield '<directory_name> specify a directory name of site'
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.parse(argv)
|
190
|
+
opts = {:directory_name => nil}
|
191
|
+
|
192
|
+
until argv.empty?
|
193
|
+
opts[:directory_name] = argv.shift
|
194
|
+
end
|
195
|
+
|
196
|
+
puts 'unspecific directory name' unless opts[:directory_name]
|
197
|
+
|
198
|
+
new(opts)
|
199
|
+
end
|
200
|
+
|
201
|
+
attr_reader :directory_name
|
202
|
+
|
203
|
+
def initialize(opts={})
|
204
|
+
@directory_name = opts[:directory_name]
|
205
|
+
end
|
206
|
+
|
207
|
+
def run
|
208
|
+
return unless @directory_name
|
209
|
+
|
210
|
+
root_dir = "#{Dir.pwd}/#{@directory_name}"
|
211
|
+
|
212
|
+
gen_site = "#{root_dir}/gen_site"
|
213
|
+
execute_script = create_file_p(root_dir, @directory_name, '')
|
214
|
+
open(execute_script, 'w') do |f|
|
215
|
+
f.puts '#!/bin/bash'
|
216
|
+
f.puts ''
|
217
|
+
f.puts "src_dir=#{root_dir}"
|
218
|
+
f.puts "dest_dir=#{gen_site}"
|
219
|
+
f.puts 'line_numbers="false"'
|
220
|
+
f.puts 'css_class="highlight"'
|
221
|
+
f.puts 'time_pattern="%Y-%m-%d %H:%M"'
|
222
|
+
f.puts 'date_pattern="%F"'
|
223
|
+
f.puts 'highlighter=""'
|
224
|
+
f.puts '# highlighter="pygments"'
|
225
|
+
f.puts 'toc_selection="h1,h2,h3"'
|
226
|
+
f.puts '# toc_selection="h1,h2,h3[unique]"'
|
227
|
+
f.puts ''
|
228
|
+
|
229
|
+
f.puts 'if [[ "$1" == "generate" ]]; then'
|
230
|
+
f.puts ' diff=$([ "$2" == \'diff\' ] && echo "true" || echo "false")'
|
231
|
+
f.puts ' khaleesi generate --src-dir "$src_dir" --dest-dir "$dest_dir" --line-numbers $line_numbers \\'
|
232
|
+
f.puts ' --css-class $css_class --time-pattern "$time_pattern" --date-pattern "$date_pattern" \\'
|
233
|
+
f.puts ' --diff-plus "$diff" --highlighter "$highlighter" --toc-selection "$toc_selection"'
|
234
|
+
f.puts ''
|
235
|
+
f.puts 'elif [[ "$1" == "build" ]]; then'
|
236
|
+
f.puts ' temperary_dest_dir=~/tmp_site'
|
237
|
+
f.puts ' mkdir $temperary_dest_dir'
|
238
|
+
f.puts ''
|
239
|
+
f.puts ' cd $src_dir'
|
240
|
+
f.puts ''
|
241
|
+
f.puts ' git checkout master'
|
242
|
+
f.puts ''
|
243
|
+
f.puts ' khaleesi build --src-dir "$src_dir" --dest-dir "$dest_dir" --line-numbers $line_numbers \\'
|
244
|
+
f.puts ' --css-class $css_class --time-pattern "$time_pattern" --date-pattern "$date_pattern" \\'
|
245
|
+
f.puts ' --highlighter "$highlighter" --toc-selection "$toc_selection"'
|
246
|
+
f.puts ''
|
247
|
+
f.puts ' git checkout gh-pages'
|
248
|
+
f.puts ''
|
249
|
+
f.puts ' rsync -acv $temperary_dest_dir/ .'
|
250
|
+
f.puts ''
|
251
|
+
f.puts ' rm -fr $temperary_dest_dir'
|
252
|
+
f.puts ''
|
253
|
+
f.puts 'elif [[ "$1" == "serve" ]]; then'
|
254
|
+
f.puts ' ruby -run -e httpd $dest_dir -p 9090'
|
255
|
+
f.puts ''
|
256
|
+
f.puts 'fi'
|
257
|
+
end
|
258
|
+
File.chmod(0755, execute_script)
|
259
|
+
FileUtils.mkdir_p(gen_site)
|
260
|
+
|
261
|
+
css_dir = "#{root_dir}/_raw/css"
|
262
|
+
css_file = create_file_p(css_dir, 'site', 'css')
|
263
|
+
open(css_file, 'w') do |f|
|
264
|
+
f.puts '* {margin:0; padding:0;}'
|
265
|
+
f.puts 'body {margin:40px auto; width:940px; line-height:1.8em;}'
|
266
|
+
|
267
|
+
f.puts 'a {color:#149ad4; text-decoration:none;}'
|
268
|
+
f.puts 'a:hover {text-decoration:underline;}'
|
269
|
+
|
270
|
+
f.puts '.header { font-size: 18px; padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid #ddd; box-shadow: 0 1px 0 rgba(255,255,255,0.5);}'
|
271
|
+
f.puts '.content { font-size: 20px; padding-bottom: 10px; }'
|
272
|
+
|
273
|
+
f.puts '.content .primary .post_list {'
|
274
|
+
f.puts ' list-style-type: none;'
|
275
|
+
f.puts '}'
|
276
|
+
|
277
|
+
f.puts '.content .primary .post_list li {'
|
278
|
+
f.puts ' border: 1px solid #ddd;'
|
279
|
+
f.puts ' margin-bottom: 10px;'
|
280
|
+
f.puts ' padding: 10px;'
|
281
|
+
f.puts '}'
|
282
|
+
|
283
|
+
f.puts '.content .primary .post_list li p {'
|
284
|
+
f.puts ' color: #5c5855;'
|
285
|
+
f.puts ' font-size: 16px;'
|
286
|
+
f.puts '}'
|
287
|
+
|
288
|
+
f.puts '.content .primary .post_list li span {'
|
289
|
+
f.puts ' color: #60E;'
|
290
|
+
f.puts ' font-size: 12px;'
|
291
|
+
f.puts '}'
|
292
|
+
|
293
|
+
f.puts '.content .post_title {'
|
294
|
+
f.puts ' margin: 10px 0;'
|
295
|
+
f.puts ' font-size: 32px;'
|
296
|
+
f.puts ' text-align: center;'
|
297
|
+
f.puts '}'
|
298
|
+
|
299
|
+
f.puts '.footer {'
|
300
|
+
f.puts ' width: 100%;'
|
301
|
+
f.puts ' margin: 0 auto;'
|
302
|
+
f.puts ' border-top: 2px solid #d5d5d5;'
|
303
|
+
f.puts ' font-size: 13px;'
|
304
|
+
f.puts ' color: #666;'
|
305
|
+
f.puts ' padding-top: 10px;'
|
306
|
+
f.puts ' padding-bottom: 60px;'
|
307
|
+
f.puts ' line-height: 1.8em;'
|
308
|
+
f.puts '}'
|
309
|
+
|
310
|
+
f.puts '.footer .left {'
|
311
|
+
f.puts ' float: left;'
|
312
|
+
f.puts '}'
|
313
|
+
|
314
|
+
f.puts '.footer .right {'
|
315
|
+
f.puts ' float: right;'
|
316
|
+
f.puts '}'
|
317
|
+
|
318
|
+
f.puts '.footer .right div {'
|
319
|
+
f.puts ' text-align: right;'
|
320
|
+
f.puts '}'
|
321
|
+
end
|
322
|
+
|
323
|
+
FileUtils.mkdir_p("#{root_dir}/_raw/images")
|
324
|
+
|
325
|
+
|
326
|
+
decorators_dir = "#{root_dir}/_decorators"
|
327
|
+
decorator_file = create_file_p(decorators_dir, 'basic', 'html')
|
328
|
+
open(decorator_file, 'w') do |f|
|
329
|
+
f.puts '<!DOCTYPE html>'
|
330
|
+
f.puts '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">'
|
331
|
+
f.puts ' <head>'
|
332
|
+
f.puts ' <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
|
333
|
+
f.puts ' <link rel="stylesheet" href="/css/site.css" type="text/css" media="screen">'
|
334
|
+
f.puts ' <title>${variable:title}</title>'
|
335
|
+
f.puts ' </head>'
|
336
|
+
f.puts ' <body>'
|
337
|
+
f.puts ' <div class="header">'
|
338
|
+
f.puts ' A khaleesi demonstration site'
|
339
|
+
f.puts ' </div>'
|
340
|
+
f.puts ' <div class="content">'
|
341
|
+
f.puts ' ${decorator:content}'
|
342
|
+
f.puts ' </div>'
|
343
|
+
f.puts ' <div class="footer">'
|
344
|
+
f.puts ' <div class="left">'
|
345
|
+
f.puts ' <div>Licensed under the <a href="http://choosealicense.com/licenses/mit/">MIT License</a></div>'
|
346
|
+
f.puts ' </div>'
|
347
|
+
f.puts ' <div class="right">'
|
348
|
+
f.puts ' <div>A pure-ruby static site generator</div>'
|
349
|
+
f.puts ' <div>Find <a href="https://github.com/vince-styling/khaleesi">khaleesi</a> in github</div>'
|
350
|
+
f.puts ' </div>'
|
351
|
+
f.puts ' </div>'
|
352
|
+
f.puts ' </body>'
|
353
|
+
f.puts '</html>'
|
354
|
+
end
|
355
|
+
|
356
|
+
decorator_file = create_file_p(decorators_dir, 'post', 'html')
|
357
|
+
open(decorator_file, 'w') do |f|
|
358
|
+
f.puts 'decorator: basic'
|
359
|
+
f.puts '‡‡‡‡‡‡‡‡‡‡‡‡‡‡'
|
360
|
+
f.puts '<h1 class="post_title">${variable:title}</h1>'
|
361
|
+
f.puts '<div class="post-thumb">'
|
362
|
+
f.puts ' ${decorator:content}'
|
363
|
+
f.puts '</div>'
|
364
|
+
end
|
365
|
+
|
366
|
+
|
367
|
+
pages_dir = "#{root_dir}/_pages"
|
368
|
+
index_file = create_file_p(pages_dir, 'index', 'html')
|
369
|
+
open(index_file, 'w') do |f|
|
370
|
+
f.puts 'title: Khaleesi Index'
|
371
|
+
f.puts 'decorator: basic'
|
372
|
+
f.puts 'slug: index.html'
|
373
|
+
f.puts '‡‡‡‡‡‡‡‡‡‡‡‡‡‡'
|
374
|
+
f.puts '<div class="primary">'
|
375
|
+
f.puts ' <ul class="post_list">'
|
376
|
+
f.puts ' #foreach ($post : $posts)'
|
377
|
+
f.puts ' <li title="${post:title}">'
|
378
|
+
f.puts ' <a href="${post:link}">${post:title}</a>'
|
379
|
+
f.puts ' <span>(${post:createtime})</span>'
|
380
|
+
f.puts ' <p>${post:description}</p>'
|
381
|
+
f.puts ' </li>'
|
382
|
+
f.puts ' #end'
|
383
|
+
f.puts ' </ul>'
|
384
|
+
f.puts '</div>'
|
385
|
+
end
|
386
|
+
|
387
|
+
pages_dir << '/posts'
|
388
|
+
post_file = create_file_p("#{pages_dir}/2014", 'khaleesi-introduction', 'md')
|
389
|
+
open(post_file, 'w') do |f|
|
390
|
+
f.puts 'title: khaleesi\'s introduction'
|
391
|
+
f.puts 'decorator: post'
|
392
|
+
f.puts 'description: Khaleesi is a static site generator that write by ruby.'
|
393
|
+
f.puts '‡‡‡‡‡‡‡‡‡‡‡‡‡‡'
|
394
|
+
f.puts ''
|
395
|
+
f.puts 'Khaleesi is a static site generator that write by ruby, supported markdown parser, multiple decorators inheritance, simple page programming, page including, page dataset configurable etc.'
|
396
|
+
f.puts ''
|
397
|
+
f.puts 'please check [this](http://khaleesi.vincestyling.com/) for more details.'
|
398
|
+
end
|
399
|
+
|
400
|
+
post_file = create_file_p("#{pages_dir}/2013", 'netroid-introduction', 'md')
|
401
|
+
open(post_file, 'w') do |f|
|
402
|
+
f.puts 'title: netroid\'s introduction'
|
403
|
+
f.puts 'decorator: post'
|
404
|
+
f.puts 'description: Netroid is a Http Framework for Android that based on Volley.'
|
405
|
+
f.puts '‡‡‡‡‡‡‡‡‡‡‡‡‡‡'
|
406
|
+
f.puts ''
|
407
|
+
f.puts 'Netroid library for Android'
|
408
|
+
f.puts '---------------------------'
|
409
|
+
f.puts ''
|
410
|
+
f.puts 'Netroid is a http library for Android that based on Volley, That purpose is make your android development easier than before, provide fast, handly, useful way to do async http operation by background thread.'
|
411
|
+
f.puts ''
|
412
|
+
f.puts 'please check [this](https://github.com/vince-styling/Netroid) for more details.'
|
413
|
+
end
|
414
|
+
|
415
|
+
puts "A sample site of Khaleesi was built in #{root_dir}."
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
class Generate < CLI
|
420
|
+
def self.desc
|
421
|
+
"#{cmd_name} whole site for specify directory"
|
422
|
+
end
|
423
|
+
|
424
|
+
def self.cmd_name
|
425
|
+
self.name.to_s[/(.+)::(.+)/, 2].downcase
|
426
|
+
end
|
427
|
+
|
428
|
+
def self.doc
|
429
|
+
return enum_for(:doc) unless block_given?
|
430
|
+
|
431
|
+
yield "usage: khaleesi #{cmd_name} [options...]"
|
432
|
+
yield ''
|
433
|
+
yield '--src-dir required, specify a source directory path(must be absolutely), khaleesi shall generating via this site source.'
|
434
|
+
yield ''
|
435
|
+
yield '--dest-dir required, specify a destination directory path(must be absolutely), all generated file will put there.'
|
436
|
+
yield ''
|
437
|
+
yield '--line-numbers (true|false) enable or disable output source code line numbers.'
|
438
|
+
yield ' the default value is "false", which means no line numbers at all.'
|
439
|
+
yield ''
|
440
|
+
yield '--css-class specify source code syntax highlight\'s css class, default is \'highlight\'.'
|
441
|
+
yield ''
|
442
|
+
yield '--time-pattern specify which time pattern would be used, If not provided, khaleesi will use \'%a %e %b %H:%M %Y\' as default,'
|
443
|
+
yield ' see http://www.ruby-doc.org/core-2.1.2/Time.html#strftime-method for pattern details.'
|
444
|
+
yield ''
|
445
|
+
yield '--date-pattern specify which date pattern would be used, If not provided, khaleesi will use \'%F\' as default,'
|
446
|
+
yield ' see http://www.ruby-doc.org/core-2.1.2/Time.html#strftime-method for pattern details.'
|
447
|
+
yield ''
|
448
|
+
yield '--diff-plus (true|false) if given the value is \'true\', khaleesi will only generate local repository(git) changed'
|
449
|
+
yield ' but has not yet been versionadded\'s pages. If the whole site was too many pages or some pages had time-consuming'
|
450
|
+
yield ' operation in building, it would be expensively when you want just focusing on those pages you frequently changing on,'
|
451
|
+
yield ' e.g you are writing a new post, you probably just care what looks would post be at all,'
|
452
|
+
yield ' so this setting let\'s avoid to generating extra pages which never changes.'
|
453
|
+
yield ''
|
454
|
+
yield '--highlighter (pygments|rouge) tells khaleesi what syntax highlighter you prefer to use,'
|
455
|
+
yield ' every value except \'pygments\' means the same as \'rouge\'.'
|
456
|
+
yield ''
|
457
|
+
yield '--toc-selection specify which headers will generate an "Table of Contents" id,'
|
458
|
+
yield ' default is empty, that means disable TOC generation.'
|
459
|
+
yield ' Enable values including "h1,h2,h3,h4,h5,h6", use comma as separator'
|
460
|
+
yield ' to tell Khaleesi which html headers you want to have ids.'
|
461
|
+
yield ' If enable to generate ids, Khaleesi will deal with header\'s text finally produce an id'
|
462
|
+
yield ' that only contain [lowercase-alpha, digit, dashes, underscores] characters.'
|
463
|
+
yield ' According this rule, Khaleesi may hunting down your texts when they don\'t write correctly.'
|
464
|
+
yield ' That shall cause the generated text become meaningless and even very easy to being duplicate.'
|
465
|
+
yield ' In case your texts aren\'t write in a good form, you still have a setting to force Khaleesi'
|
466
|
+
yield ' to generate an unique ids instead that uncomfortable generated texts.'
|
467
|
+
yield ' Just append "[unique]" identifier at the end, e.g "h1,h2[unique]", Khaleesi will generating'
|
468
|
+
yield ' ids like these : "header-1", "header-2", "header-3", "header-4".'
|
469
|
+
end
|
470
|
+
|
471
|
+
def self.parse(argv)
|
472
|
+
opts = {}
|
473
|
+
argv = normalize_syntax(argv)
|
474
|
+
until argv.empty?
|
475
|
+
arg = argv.shift
|
476
|
+
case arg
|
477
|
+
when 'src-dir'
|
478
|
+
opts[:src_dir] = argv.shift.dup
|
479
|
+
when 'dest-dir'
|
480
|
+
opts[:dest_dir] = argv.shift.dup
|
481
|
+
when 'line-numbers'
|
482
|
+
opts[:line_numbers] = argv.shift.dup
|
483
|
+
when 'css-class'
|
484
|
+
opts[:css_class] = argv.shift.dup
|
485
|
+
when 'time-pattern'
|
486
|
+
opts[:time_pattern] = argv.shift.dup
|
487
|
+
when 'date-pattern'
|
488
|
+
opts[:date_pattern] = argv.shift.dup
|
489
|
+
when 'diff-plus'
|
490
|
+
opts[:diff_plus] = argv.shift.dup
|
491
|
+
when 'highlighter'
|
492
|
+
opts[:highlighter] = argv.shift.dup
|
493
|
+
when 'toc-selection'
|
494
|
+
opts[:toc_selection] = argv.shift.dup
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
new(opts)
|
499
|
+
end
|
500
|
+
|
501
|
+
def initialize(opts={})
|
502
|
+
@opts = opts
|
503
|
+
end
|
504
|
+
|
505
|
+
def run
|
506
|
+
details = " Please point \"khaleesi help #{self.class.to_s[/(.+)::(.+)/, 2].downcase}\" in terminal for more details."
|
507
|
+
|
508
|
+
dest_dir = @opts[:dest_dir]
|
509
|
+
src_dir = @opts[:src_dir]
|
510
|
+
|
511
|
+
unless src_dir and File.directory?(src_dir) and File.readable?(src_dir)
|
512
|
+
abort "Source directory : #{src_dir} invalid." << details
|
513
|
+
end
|
514
|
+
|
515
|
+
unless dest_dir and File.directory?(dest_dir) and File.writable?(dest_dir)
|
516
|
+
abort "Destination directory : #{dest_dir} invalid." << details
|
517
|
+
end
|
518
|
+
|
519
|
+
site_dir = src_dir + '/_decorators'
|
520
|
+
unless File.directory?(site_dir)
|
521
|
+
abort "Source directory : #{src_dir} haven't _decorators folder."
|
522
|
+
end
|
523
|
+
|
524
|
+
site_dir = src_dir + '/_pages'
|
525
|
+
unless File.directory?(site_dir)
|
526
|
+
abort "Source directory : #{src_dir} haven't _pages folder."
|
527
|
+
end
|
528
|
+
|
529
|
+
site_dir = src_dir + '/_raw'
|
530
|
+
unless File.directory?(site_dir)
|
531
|
+
abort "Source directory : #{src_dir} haven't _raw folder."
|
532
|
+
end
|
533
|
+
|
534
|
+
Generator.new(@opts).generate
|
535
|
+
handle_raw_files(site_dir)
|
536
|
+
end
|
537
|
+
|
538
|
+
def handle_raw_files(raw_dir)
|
539
|
+
# make symbolic links of "_raw" directory
|
540
|
+
Dir.chdir(@opts[:dest_dir]) do
|
541
|
+
%x[ln -sf #{raw_dir << '/*'} .]
|
542
|
+
end
|
543
|
+
# FileUtils.ln_s site_dir << '/*', @dest_dir, :verbose => true
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
class Build < Generate
|
548
|
+
def handle_raw_files(raw_dir)
|
549
|
+
FileUtils.cp_r raw_dir << '/.', @opts[:dest_dir], :verbose => false
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
class Help < CLI
|
554
|
+
def self.desc
|
555
|
+
'print help info'
|
556
|
+
end
|
557
|
+
|
558
|
+
def self.doc
|
559
|
+
return enum_for(:doc) unless block_given?
|
560
|
+
|
561
|
+
yield 'usage: khaleesi help <command>'
|
562
|
+
yield ''
|
563
|
+
yield 'print help info for <command>.'
|
564
|
+
end
|
565
|
+
|
566
|
+
def self.parse(argv)
|
567
|
+
opts = {:mode => CLI}
|
568
|
+
until argv.empty?
|
569
|
+
arg = argv.shift
|
570
|
+
klass = class_from_arg(arg)
|
571
|
+
if klass
|
572
|
+
opts[:mode] = klass
|
573
|
+
next
|
574
|
+
end
|
575
|
+
end
|
576
|
+
new(opts)
|
577
|
+
end
|
578
|
+
|
579
|
+
def initialize(opts={})
|
580
|
+
@mode = opts[:mode]
|
581
|
+
end
|
582
|
+
|
583
|
+
def run
|
584
|
+
@mode.doc.each(&method(:puts))
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
class FileReader
|
589
|
+
attr_reader :input
|
590
|
+
def initialize(input)
|
591
|
+
@input = input
|
592
|
+
end
|
593
|
+
|
594
|
+
def file
|
595
|
+
case input
|
596
|
+
when '-'
|
597
|
+
$stdin
|
598
|
+
when String
|
599
|
+
File.new(input)
|
600
|
+
when ->(i){ i.respond_to? :read }
|
601
|
+
input
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
def read
|
606
|
+
@read ||= begin
|
607
|
+
file.read
|
608
|
+
rescue => e
|
609
|
+
$stderr.puts "unable to open #{input}: #{e.message}"
|
610
|
+
exit 1
|
611
|
+
ensure
|
612
|
+
file.close
|
613
|
+
end
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
def create_file_p(dir, name, extension)
|
618
|
+
unless File.directory?(dir)
|
619
|
+
FileUtils.mkdir_p(dir)
|
620
|
+
end
|
621
|
+
|
622
|
+
"#{dir}/#{name}" + (extension.empty? ? '' : ".#{extension}")
|
623
|
+
end
|
624
|
+
|
625
|
+
def self.normalize_syntax(argv)
|
626
|
+
out = []
|
627
|
+
argv.each do |arg|
|
628
|
+
case arg
|
629
|
+
when /^(-{,2})(\p{Graph}+)=(.*)$/
|
630
|
+
out << $2 << $3
|
631
|
+
when /^(-{,2})(\p{Graph}+)$/
|
632
|
+
out << $2
|
633
|
+
else
|
634
|
+
out << arg
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
out
|
639
|
+
end
|
640
|
+
end
|
641
|
+
end
|