khaleesi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +7 -0
  3. data/LICENSE +22 -0
  4. data/bin/khaleesi +10 -0
  5. data/khaleesi.gemspec +18 -0
  6. data/lib/khaleesi.rb +12 -0
  7. data/lib/khaleesi/about.rb +23 -0
  8. data/lib/khaleesi/cli.rb +641 -0
  9. data/lib/khaleesi/generator.rb +635 -0
  10. data/test/khaleesi_commands_test.rb +50 -0
  11. data/test/khaleesi_test.rb +171 -0
  12. data/test/resources/java-samplecode +9 -0
  13. data/test/resources/test_parse_single_file.md +26 -0
  14. data/test/resources/test_parse_single_file_enable_linenumbers_result +25 -0
  15. data/test/resources/test_parse_single_file_without_linenumbers_result +20 -0
  16. data/test/resources/test_site/_decorators/basic.html +25 -0
  17. data/test/resources/test_site/_decorators/code_snippet.html +8 -0
  18. data/test/resources/test_site/_decorators/post.html +6 -0
  19. data/test/resources/test_site/_decorators/theme.html +15 -0
  20. data/test/resources/test_site/_pages/index.html +49 -0
  21. data/test/resources/test_site/_pages/javasmpcode.md +11 -0
  22. data/test/resources/test_site/_pages/posts/2013/netroid-introduction.md +11 -0
  23. data/test/resources/test_site/_pages/posts/2014/khaleesi-introduction.md +8 -0
  24. data/test/resources/test_site/_pages/studio/cameras/camera1.md +6 -0
  25. data/test/resources/test_site/_pages/studio/cameras/camera2.md +6 -0
  26. data/test/resources/test_site/_pages/studio/cameras/camera3.md +6 -0
  27. data/test/resources/test_site/_pages/studio/cameras/camera4.md +6 -0
  28. data/test/resources/test_site/_pages/themes/base16_solarized.md +119 -0
  29. data/test/resources/test_site/_pages/themes/base16_solarized_dark.md +117 -0
  30. data/test/resources/test_site/_pages/themes/github.md +272 -0
  31. data/test/resources/test_site/_pages/themes_illustrates/base16_solarized.html +4 -0
  32. data/test/resources/test_site/_pages/themes_illustrates/base16_solarized_dark.html +4 -0
  33. data/test/resources/test_site/_pages/themes_illustrates/github.html +4 -0
  34. data/test/resources/test_site/_pages/themes_illustrates/monokai.html +4 -0
  35. data/test/resources/test_site/_pages/themes_illustrates/monokai_sublime.html +4 -0
  36. data/test/resources/test_site/_raw/css/site.css +340 -0
  37. data/test/resources/test_site/expected_base16_solarized_dark_html +146 -0
  38. data/test/resources/test_site/expected_base16_solarized_html +150 -0
  39. data/test/resources/test_site/expected_github_html +301 -0
  40. data/test/resources/test_site/expected_index_html +373 -0
  41. 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
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'pygments.rb', '~> 0.6.0'
6
+ gem 'redcarpet', '~> 3.1.2'
7
+ gem 'rouge', '~> 1.6.1'
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
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+ require 'fileutils'
5
+
6
+ ROOT_DIR = Pathname.new(__FILE__).dirname.parent
7
+
8
+ load ROOT_DIR.join('lib/khaleesi.rb')
9
+
10
+ Khaleesi::CLI.parse(ARGV).run
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,12 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+
4
+ require 'redcarpet'
5
+ require 'pygments'
6
+ require 'rouge'
7
+ require 'time'
8
+ require 'cgi'
9
+
10
+ Dir[__dir__ + '/khaleesi/*.rb'].each do |file|
11
+ require file
12
+ end
@@ -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
@@ -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