slideshow 1.1.0.beta7 → 1.1.0.beta8

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,13 +6,15 @@ bin/slideshow
6
6
  config/slideshow.builtin.yml
7
7
  config/slideshow.yml
8
8
  lib/slideshow.rb
9
+ lib/slideshow/commands/fetch.rb
10
+ lib/slideshow/commands/gen.rb
11
+ lib/slideshow/commands/gen_templates.rb
12
+ lib/slideshow/commands/list.rb
9
13
  lib/slideshow/config.rb
10
- lib/slideshow/fetch.rb
11
14
  lib/slideshow/filters/debug_filter.rb
12
15
  lib/slideshow/filters/headers_filter.rb
13
16
  lib/slideshow/filters/slide_filter.rb
14
17
  lib/slideshow/filters/text_filter.rb
15
- lib/slideshow/gen.rb
16
18
  lib/slideshow/headers.rb
17
19
  lib/slideshow/helpers/analytics_helper.rb
18
20
  lib/slideshow/helpers/background_helper.rb
@@ -31,6 +33,7 @@ lib/slideshow/markup/markdown.rb
31
33
  lib/slideshow/markup/rest.rb
32
34
  lib/slideshow/markup/textile.rb
33
35
  lib/slideshow/opts.rb
36
+ lib/slideshow/runner.rb
34
37
  lib/slideshow/slide.rb
35
38
  lib/slideshow/version.rb
36
39
  templates/s6.txt
@@ -42,10 +42,14 @@ require 'slideshow/version'
42
42
  require 'slideshow/opts'
43
43
  require 'slideshow/headers'
44
44
  require 'slideshow/config'
45
- require 'slideshow/gen'
46
45
  require 'slideshow/manifest'
47
- require 'slideshow/fetch'
48
46
  require 'slideshow/slide'
47
+ require 'slideshow/runner'
48
+
49
+ require 'slideshow/commands/fetch'
50
+ require 'slideshow/commands/gen'
51
+ require 'slideshow/commands/gen_templates'
52
+ require 'slideshow/commands/list'
49
53
 
50
54
  require 'slideshow/markup/textile'
51
55
  require 'slideshow/markup/markdown'
@@ -92,7 +96,7 @@ module Slideshow
92
96
  args += slideshowopt.split if slideshowopt
93
97
  args += ARGV.dup
94
98
 
95
- Gen.new.run(args)
99
+ Runner.new.run(args)
96
100
  end
97
101
 
98
102
  end # module Slideshow
@@ -1,6 +1,19 @@
1
1
  module Slideshow
2
- module Fetch
2
+
3
+ class Fetch
4
+
5
+ include Manifest # gets us methods like installed_template_manifests, etc.
6
+
7
+ ### fix: remove opts, use config (wrapped!!)
3
8
 
9
+ def initialize( logger, opts, config )
10
+ @logger = logger
11
+ @opts = opts
12
+ @config = config
13
+ end
14
+
15
+ attr_reader :logger, :opts, :config
16
+
4
17
  def fetch_file( dest, src )
5
18
 
6
19
  ## note: code moved to its own gem, that is, fetcher
@@ -11,7 +24,7 @@ module Slideshow
11
24
  end
12
25
 
13
26
 
14
- def fetch_slideshow_templates
27
+ def run
15
28
  logger.debug "fetch_uri=#{opts.fetch_uri}"
16
29
 
17
30
  src = opts.fetch_uri
@@ -35,7 +48,7 @@ module Slideshow
35
48
 
36
49
  logger.debug "scheme: #{uri.scheme}, host: #{uri.host}, port: #{uri.port}, path: #{uri.path}"
37
50
 
38
- dirname = File.dirname( uri.path )
51
+ dirname = File.dirname( uri.path )
39
52
  basename = File.basename( uri.path, '.*' ) # e.g. fullerscreen (without extension)
40
53
  filename = File.basename( uri.path ) # e.g. fullerscreen.txt (with extension)
41
54
 
@@ -43,12 +56,12 @@ module Slideshow
43
56
  logger.debug "basename: #{basename}, filename: #{filename}"
44
57
 
45
58
  dlbase = "#{uri.scheme}://#{uri.host}:#{uri.port}#{dirname}"
46
- pkgpath = File.expand_path( "#{config_dir}/templates/#{basename}" )
59
+ pkgpath = File.expand_path( "#{config.config_dir}/templates/#{basename}" )
47
60
 
48
61
  logger.debug "dlpath: #{dlbase}"
49
62
  logger.debug "pkgpath: #{pkgpath}"
50
63
 
51
- FileUtils.makedirs( pkgpath ) unless File.directory? pkgpath
64
+ FileUtils.makedirs( pkgpath ) unless File.directory? pkgpath
52
65
 
53
66
  puts "Fetching template package '#{basename}'"
54
67
  puts " : from '#{dlbase}'"
@@ -79,12 +92,10 @@ module Slideshow
79
92
  fetch_file( dest, src )
80
93
  end
81
94
  end
82
- puts "Done."
95
+ puts "Done."
83
96
  end
84
-
85
- end # module Fetch
86
- end # module Slideshow
87
97
 
88
- class Slideshow::Gen
89
- include Slideshow::Fetch
90
- end
98
+
99
+ end # class Fetch
100
+
101
+ end # module Slideshow
@@ -1,507 +1,334 @@
1
- module Slideshow
2
-
3
- class Gen
4
-
5
- def initialize
6
- @logger = Logger.new(STDOUT)
7
- @logger.level = Logger::INFO
8
-
9
- @config = Config.new
10
- @opts = Opts.new
11
- @headers = Headers.new( @config )
12
- end
13
-
14
- attr_reader :logger, :opts, :config, :headers
15
- attr_reader :session # give helpers/plugins a session-like hash
16
-
17
- attr_reader :markup_type # :textile, :markdown, :rest
18
-
19
- # uses configured markup processor (textile,markdown,rest) to generate html
20
- def text_to_html( content )
21
- content = case @markup_type
22
- when :markdown
23
- markdown_to_html( content )
24
- when :textile
25
- textile_to_html( content )
26
- when :rest
27
- rest_to_html( content )
28
- end
29
- content
30
- end
31
-
32
- def guard_text( text )
33
- # todo/fix 2: note for Textile we need to differentiate between blocks and inline
34
- # thus, to avoid runs - use guard_block (add a leading newline to avoid getting include in block that goes before)
35
-
36
- # todo/fix: remove wrap_markup; replace w/ guard_text
37
- # why: text might be css, js, not just html
38
- wrap_markup( text )
39
- end
40
-
41
- def guard_block( text )
42
- if markup_type == :textile
43
- # saveguard with notextile wrapper etc./no further processing needed
44
- # note: add leading newlines to avoid block-runons
45
- "\n\n<notextile>\n#{text}\n</notextile>\n"
46
- else
47
- text
48
- end
49
- end
50
-
51
- def guard_inline( text )
52
- wrap_markup( text )
53
- end
54
-
55
-
56
- def wrap_markup( text )
57
- if markup_type == :textile
58
- # saveguard with notextile wrapper etc./no further processing needed
59
- "<notextile>\n#{text}\n</notextile>"
60
- else
61
- text
62
- end
63
- end
64
-
65
- # todo/fix: move to Config class
66
- # - used in syntax/uv_helper (use config.cache_dir to access?)
67
-
68
- def cache_dir
69
- File.join( Env.home, '.slideshow' )
70
- end
71
-
72
-
73
- def config_dir
74
- unless @config_dir # first time? calculate config_dir value to "cache"
75
-
76
- if opts.config_path
77
- @config_dir = opts.config_path
78
- else
79
- @config_dir = cache_dir
80
- end
81
-
82
- # make sure path exists
83
- FileUtils.makedirs( @config_dir ) unless File.directory? @config_dir
84
- end
85
-
86
- @config_dir
87
- end
88
-
89
-
90
- def load_template( path )
91
- puts " Loading template #{path}..."
92
- return File.read( path )
93
- end
94
-
95
- def render_template( content, the_binding )
96
- ERB.new( content ).result( the_binding )
97
- end
98
-
99
-
100
- def with_output_path( dest, output_path )
101
- dest_full = File.expand_path( dest, output_path )
102
- logger.debug "dest_full=#{dest_full}"
103
-
104
- # make sure dest path exists
105
- dest_path = File.dirname( dest_full )
106
- logger.debug "dest_path=#{dest_path}"
107
- FileUtils.makedirs( dest_path ) unless File.directory? dest_path
108
- dest_full
109
- end
110
-
111
-
112
- def create_slideshow_templates
113
-
114
- manifest_name = opts.manifest
115
- logger.debug "manifest=#{manifest_name}"
116
-
117
- manifests = installed_generator_manifests
118
-
119
- # check for builtin generator manifests
120
- matches = manifests.select { |m| m[0] == manifest_name+".gen" }
121
-
122
- if matches.empty?
123
- puts "*** error: unknown template manifest '#{manifest_name}'"
124
- # todo: list installed manifests
125
- exit 2
126
- end
127
-
128
- manifest = load_manifest( matches[0][1] )
129
-
130
- # expand output path in current dir and make sure output path exists
131
- outpath = File.expand_path( opts.output_path )
132
- logger.debug "outpath=#{outpath}"
133
- FileUtils.makedirs( outpath ) unless File.directory? outpath
134
-
135
- manifest.each do |entry|
136
- dest = entry[0]
137
- source = entry[1]
138
-
139
- puts "Copying to #{dest} from #{source}..."
140
- FileUtils.copy( source, with_output_path( dest, outpath ) )
141
- end
142
-
143
- puts "Done."
144
- end
145
-
146
- def list_slideshow_templates
147
- manifests = installed_template_manifests
148
-
149
- puts ''
150
- puts 'Installed templates include:'
151
-
152
- manifests.each do |manifest|
153
- puts " #{manifest[0]} (#{manifest[1]})"
154
- end
155
- end
156
-
157
- # move into a filter??
158
- def post_processing_slides( content )
159
-
160
- # 1) add slide break
161
-
162
- if (@markup_type == :markdown && Markdown.lib == 'pandoc-ruby') || @markup_type == :rest
163
- content = add_slide_directive_before_div_h1( content )
164
- else
165
- content = add_slide_directive_before_h1( content )
166
- end
167
-
168
- dump_content_to_file_debug_html( content )
169
-
170
- # 2) use generic slide break processing instruction to
171
- # split content into slides
172
-
173
- slide_counter = 0
174
-
175
- slides = []
176
- slide_source = ""
177
-
178
- content.each_line do |line|
179
- if line.include?( '<!-- _S9SLIDE_' ) then
180
- if slide_counter > 0 then # found start of new slide (and, thus, end of last slide)
181
- slides << slide_source # add slide to slide stack
182
- slide_source = "" # reset slide source buffer
183
- end
184
- slide_counter += 1
185
- end
186
- slide_source << line
187
- end
188
-
189
- if slide_counter > 0 then
190
- slides << slide_source # add slide to slide stack
191
- slide_source = "" # reset slide source buffer
192
- end
193
-
194
-
195
- ## split slide source into header (optional) and content/body
196
- ## plus check for (css style) classes and data attributes
197
-
198
- slides2 = []
199
- slides.each do |slide_source|
200
- slide = Slide.new
201
-
202
- ## check for css style classes
203
- from = 0
204
- while (pos = slide_source.index( /<!-- _S9(SLIDE|STYLE)_(.*?)-->/m, from ))
205
- logger.debug " adding css classes from pi #{$1.downcase}: #{$2.strip}"
206
-
207
- from = Regexp.last_match.end(0) # continue search later from here
208
-
209
- values = $2.strip.dup
210
-
211
- # remove data values (eg. x=-20 scale=4) and store in data hash
212
- values.gsub!( /([-\w]+)[ \t]*=[ \t]*([-\w\.]+)/ ) do |_|
213
- logger.debug " adding data pair: key=>#{$1.downcase}< value=>#{$2}<"
214
- slide.data[ $1.downcase.dup ] = $2.dup
215
- " " # replace w/ space
216
- end
217
-
218
- values.strip! # remove spaces # todo: use squish or similar and check for empty string
219
-
220
- if slide.classes.nil?
221
- slide.classes = values
222
- else
223
- slide.classes << " #{values}"
224
- end
225
- end
226
-
227
- # try to cut off header using non-greedy .+? pattern; tip test regex online at rubular.com
228
- # note/fix: needs to get improved to also handle case for h1 wrapped into div
229
- # (e.g. extract h1 - do not assume it starts slide source)
230
- if slide_source =~ /^\s*(<h1.*?>.*?<\/h\d>)\s*(.*)/m
231
- slide.header = $1
232
- slide.content = ($2 ? $2 : "")
233
- logger.debug " adding slide with header:\n#{slide.header}"
234
- else
235
- slide.content = slide_source
236
- logger.debug " adding slide with *no* header:\n#{slide.content}"
237
- end
238
- slides2 << slide
239
- end
240
-
241
- # for convenience create a string w/ all in-one-html
242
- # no need to wrap slides in divs etc.
243
-
244
- content2 = ""
245
- slides2.each do |slide|
246
- content2 << slide.to_classic_html
247
- end
248
-
249
- # make content2 and slide2 available to erb template
250
- # -- todo: cleanup variable names and use attr_readers for content and slide
251
-
252
- @slides = slides2 # strutured content
253
- @content = content2 # content all-in-one
254
- end
255
-
256
-
257
- def create_slideshow( fn )
258
-
259
- manifest_path_or_name = opts.manifest
260
-
261
- # add .txt file extension if missing (for convenience)
262
- manifest_path_or_name << ".txt" if File.extname( manifest_path_or_name ).empty?
263
-
264
-
265
- logger.debug "manifest=#{manifest_path_or_name}"
266
-
267
- # check if file exists (if yes use custom template package!) - allows you to override builtin package with same name
268
- if File.exists?( manifest_path_or_name )
269
- manifest = load_manifest( manifest_path_or_name )
270
- else
271
- # check for builtin manifests
272
- manifests = installed_template_manifests
273
- matches = manifests.select { |m| m[0] == manifest_path_or_name }
274
-
275
- if matches.empty?
276
- puts "*** error: unknown template manifest '#{manifest_path_or_name}'"
277
- # todo: list installed manifests
278
- exit 2
279
- end
280
-
281
- manifest = load_manifest( matches[0][1] )
282
- end
283
-
284
- # expand output path in current dir and make sure output path exists
285
- outpath = File.expand_path( opts.output_path )
286
- logger.debug "outpath=#{outpath}"
287
- FileUtils.makedirs( outpath ) unless File.directory? outpath
288
-
289
- dirname = File.dirname( fn )
290
- basename = File.basename( fn, '.*' )
291
- extname = File.extname( fn )
292
- logger.debug "dirname=#{dirname}, basename=#{basename}, extname=#{extname}"
293
-
294
- # change working dir to sourcefile dir
295
- # todo: add a -c option to commandline? to let you set cwd?
296
-
297
- newcwd = File.expand_path( dirname )
298
- oldcwd = File.expand_path( Dir.pwd )
299
-
300
- unless newcwd == oldcwd then
301
- logger.debug "oldcwd=#{oldcwd}"
302
- logger.debug "newcwd=#{newcwd}"
303
- Dir.chdir newcwd
304
- end
305
-
306
- puts "Preparing slideshow '#{basename}'..."
307
-
308
- if extname.empty? then
309
- extname = ".textile" # default to .textile
310
-
311
- config.known_extnames.each do |e|
312
- logger.debug "File.exists? #{dirname}/#{basename}#{e}"
313
- if File.exists?( "#{dirname}/#{basename}#{e}" ) then
314
- extname = e
315
- logger.debug "extname=#{extname}"
316
- break
317
- end
318
- end
319
- end
320
-
321
- if config.known_markdown_extnames.include?( extname )
322
- @markup_type = :markdown
323
- elsif config.known_rest_extnames.include?( extname )
324
- @markup_type = :rest
325
- else
326
- @markup_type = :textile
327
- end
328
-
329
- # shared variables for templates (binding)
330
- @content_for = {} # reset content_for hash
331
-
332
- @name = basename
333
- @extname = extname
334
-
335
- @session = {} # reset session hash for plugins/helpers
336
-
337
- inname = "#{dirname}/#{basename}#{extname}"
338
-
339
- logger.debug "inname=#{inname}"
340
-
341
- content = File.read( inname )
342
-
343
- # run text filters
344
-
345
- config.text_filters.each do |filter|
346
- mn = filter.tr( '-', '_' ).to_sym # construct method name (mn)
347
- content = send( mn, content ) # call filter e.g. include_helper_hack( content )
348
- end
349
-
350
- # convert light-weight markup to hypertext
351
-
352
- content = text_to_html( content )
353
-
354
- # post-processing
355
-
356
- # make content2 and slide2 available to erb template
357
- # -- todo: cleanup variable names and use attr_readers for content and slide
358
-
359
- if @markup_type == :markdown && config.markdown_post_processing?( Markdown.lib ) == false
360
- puts " Skipping post-processing (passing content through as is)..."
361
- @content = content # content all-in-one - make it available in erb templates
362
- else
363
- # sets @content (all-in-one string) and @slides (structured content; split into slides)
364
- post_processing_slides( content )
365
- end
366
-
367
-
368
- manifest.each do |entry|
369
- outname = entry[0]
370
- if outname.include? '__file__' # process
371
- outname = outname.gsub( '__file__', basename )
372
- puts "Preparing #{outname}..."
373
-
374
- out = File.new( with_output_path( outname, outpath ), "w+" )
375
-
376
- out << render_template( load_template( entry[1] ), binding )
377
-
378
- if entry.size > 2 # more than one source file? assume header and footer with content added inbetween
379
- out << content2
380
- out << render_template( load_template( entry[2] ), binding )
381
- end
382
-
383
- out.flush
384
- out.close
385
-
386
- else # just copy verbatim if target/dest has no __file__ in name
387
- dest = entry[0]
388
- source = entry[1]
389
-
390
- puts "Copying to #{dest} from #{source}..."
391
- FileUtils.copy( source, with_output_path( dest, outpath ) )
392
- end
393
- end
394
-
395
- puts "Done."
396
- end
397
-
398
- def load_plugins
399
-
400
- patterns = []
401
- patterns << "#{config_dir}/lib/**/*.rb"
402
- patterns << 'lib/**/*.rb' unless Slideshow.root == File.expand_path( '.' ) # don't include lib if we are in repo (don't include slideshow/lib)
403
-
404
- patterns.each do |pattern|
405
- pattern.gsub!( '\\', '/') # normalize path; make sure all path use / only
406
- Dir.glob( pattern ) do |plugin|
407
- begin
408
- puts "Loading plugins in '#{plugin}'..."
409
- require( plugin )
410
- rescue Exception => e
411
- puts "** error: failed loading plugins in '#{plugin}': #{e}"
412
- end
413
- end
414
- end
415
- end
416
-
417
- def run( args )
418
-
419
- opt=OptionParser.new do |cmd|
420
-
421
- cmd.banner = "Usage: slideshow [options] name"
422
-
423
- cmd.on( '-o', '--output PATH', 'Output Path' ) { |path| opts.output_path = path }
424
-
425
- cmd.on( '-g', '--generate', 'Generate Slide Show Templates (Using Built-In S6 Pack)' ) { opts.generate = true }
426
-
427
- cmd.on( "-t", "--template MANIFEST", "Template Manifest" ) do |t|
428
- # todo: do some checks on passed in template argument
429
- opts.manifest = t
430
- end
431
-
432
- # ?? opts.on( "-s", "--style STYLE", "Select Stylesheet" ) { |s| $options[:style]=s }
433
- # ?? opts.on( "--version", "Show version" ) {}
434
-
435
- # ?? cmd.on( '-i', '--include PATH', 'Load Path' ) { |s| opts.put( 'include', s ) }
436
-
437
- cmd.on( '-f', '--fetch URI', 'Fetch Templates' ) do |uri|
438
- opts.fetch_uri = uri
439
- end
440
-
441
- cmd.on( '-c', '--config PATH', 'Configuration Path (default is ~/.slideshow)' ) do |path|
442
- opts.config_path = path
443
- end
444
-
445
- cmd.on( '-l', '--list', 'List Installed Templates' ) { opts.list = true }
446
-
447
- # todo: find different letter for debug trace switch (use v for version?)
448
- cmd.on( "-v", "--verbose", "Show debug trace" ) do
449
- logger.datetime_format = "%H:%H:%S"
450
- logger.level = Logger::DEBUG
451
- end
452
-
453
- usage =<<EOS
454
-
455
- Slide Show (S9) is a free web alternative to PowerPoint or KeyNote in Ruby
456
-
457
- #{cmd.help}
458
-
459
- Examples:
460
- slideshow microformats
461
- slideshow microformats.textile # Process slides using Textile
462
- slideshow microformats.text # Process slides using Markdown
463
- slideshow microformats.rst # Process slides using reStructuredText
464
- slideshow -o slides microformats # Output slideshow to slides folder
465
-
466
- More examles:
467
- slideshow -g # Generate slide show templates using built-in S6 pack
468
-
469
- slideshow -l # List installed slide show templates
470
- slideshow -f s5blank # Fetch (install) S5 blank starter template from internet
471
- slideshow -t s5blank microformats # Use your own slide show templates (e.g. s5blank)
472
-
473
- Further information:
474
- http://slideshow.rubyforge.org
475
-
476
- EOS
477
-
478
-
479
- cmd.on_tail( "-h", "--help", "Show this message" ) do
480
- puts usage
481
- exit
482
- end
483
- end
484
-
485
- opt.parse!( args )
486
-
487
- config.load
488
-
489
- puts Slideshow.generator
490
-
491
- if opts.list?
492
- list_slideshow_templates
493
- elsif opts.generate?
494
- create_slideshow_templates
495
- elsif opts.fetch?
496
- fetch_slideshow_templates
497
- else
498
- load_plugins # check for optional plugins/extension in ./lib folder
499
-
500
- args.each { |fn| create_slideshow( fn ) }
501
- end
502
- end
503
-
504
- end # class Gen
505
-
506
-
507
- end # module Slideshow
1
+ module Slideshow
2
+
3
+ class Gen
4
+
5
+ include Manifest # gets us methods like installed_template_manifests, etc.
6
+
7
+ ### fix: remove opts, use config (wrapped!!)
8
+
9
+ def initialize( logger, opts, config, headers )
10
+ @logger = logger
11
+ @opts = opts
12
+ @config = config
13
+ @headers = headers
14
+ end
15
+
16
+ attr_reader :logger, :opts, :config, :headers
17
+ attr_reader :session # give helpers/plugins a session-like hash
18
+
19
+ attr_reader :markup_type # :textile, :markdown, :rest
20
+
21
+ # uses configured markup processor (textile,markdown,rest) to generate html
22
+ def text_to_html( content )
23
+ content = case @markup_type
24
+ when :markdown
25
+ markdown_to_html( content )
26
+ when :textile
27
+ textile_to_html( content )
28
+ when :rest
29
+ rest_to_html( content )
30
+ end
31
+ content
32
+ end
33
+
34
+ def guard_text( text )
35
+ # todo/fix 2: note for Textile we need to differentiate between blocks and inline
36
+ # thus, to avoid runs - use guard_block (add a leading newline to avoid getting include in block that goes before)
37
+
38
+ # todo/fix: remove wrap_markup; replace w/ guard_text
39
+ # why: text might be css, js, not just html
40
+ wrap_markup( text )
41
+ end
42
+
43
+ def guard_block( text )
44
+ if markup_type == :textile
45
+ # saveguard with notextile wrapper etc./no further processing needed
46
+ # note: add leading newlines to avoid block-runons
47
+ "\n\n<notextile>\n#{text}\n</notextile>\n"
48
+ else
49
+ text
50
+ end
51
+ end
52
+
53
+ def guard_inline( text )
54
+ wrap_markup( text )
55
+ end
56
+
57
+
58
+ def wrap_markup( text )
59
+ if markup_type == :textile
60
+ # saveguard with notextile wrapper etc./no further processing needed
61
+ "<notextile>\n#{text}\n</notextile>"
62
+ else
63
+ text
64
+ end
65
+ end
66
+
67
+
68
+ def load_template( path )
69
+ puts " Loading template #{path}..."
70
+ return File.read( path )
71
+ end
72
+
73
+ def render_template( content, the_binding )
74
+ ERB.new( content ).result( the_binding )
75
+ end
76
+
77
+
78
+ def with_output_path( dest, output_path )
79
+ dest_full = File.expand_path( dest, output_path )
80
+ logger.debug "dest_full=#{dest_full}"
81
+
82
+ # make sure dest path exists
83
+ dest_path = File.dirname( dest_full )
84
+ logger.debug "dest_path=#{dest_path}"
85
+ FileUtils.makedirs( dest_path ) unless File.directory? dest_path
86
+ dest_full
87
+ end
88
+
89
+
90
+
91
+ # move into a filter??
92
+ def post_processing_slides( content )
93
+
94
+ # 1) add slide break
95
+
96
+ if (@markup_type == :markdown && Markdown.lib == 'pandoc-ruby') || @markup_type == :rest
97
+ content = add_slide_directive_before_div_h1( content )
98
+ else
99
+ content = add_slide_directive_before_h1( content )
100
+ end
101
+
102
+ dump_content_to_file_debug_html( content )
103
+
104
+ # 2) use generic slide break processing instruction to
105
+ # split content into slides
106
+
107
+ slide_counter = 0
108
+
109
+ slides = []
110
+ slide_source = ""
111
+
112
+ content.each_line do |line|
113
+ if line.include?( '<!-- _S9SLIDE_' ) then
114
+ if slide_counter > 0 then # found start of new slide (and, thus, end of last slide)
115
+ slides << slide_source # add slide to slide stack
116
+ slide_source = "" # reset slide source buffer
117
+ end
118
+ slide_counter += 1
119
+ end
120
+ slide_source << line
121
+ end
122
+
123
+ if slide_counter > 0 then
124
+ slides << slide_source # add slide to slide stack
125
+ slide_source = "" # reset slide source buffer
126
+ end
127
+
128
+
129
+ ## split slide source into header (optional) and content/body
130
+ ## plus check for (css style) classes and data attributes
131
+
132
+ slides2 = []
133
+ slides.each do |slide_source|
134
+ slide = Slide.new
135
+
136
+ ## check for css style classes
137
+ from = 0
138
+ while (pos = slide_source.index( /<!-- _S9(SLIDE|STYLE)_(.*?)-->/m, from ))
139
+ logger.debug " adding css classes from pi #{$1.downcase}: #{$2.strip}"
140
+
141
+ from = Regexp.last_match.end(0) # continue search later from here
142
+
143
+ values = $2.strip.dup
144
+
145
+ # remove data values (eg. x=-20 scale=4) and store in data hash
146
+ values.gsub!( /([-\w]+)[ \t]*=[ \t]*([-\w\.]+)/ ) do |_|
147
+ logger.debug " adding data pair: key=>#{$1.downcase}< value=>#{$2}<"
148
+ slide.data[ $1.downcase.dup ] = $2.dup
149
+ " " # replace w/ space
150
+ end
151
+
152
+ values.strip! # remove spaces # todo: use squish or similar and check for empty string
153
+
154
+ if slide.classes.nil?
155
+ slide.classes = values
156
+ else
157
+ slide.classes << " #{values}"
158
+ end
159
+ end
160
+
161
+ # try to cut off header using non-greedy .+? pattern; tip test regex online at rubular.com
162
+ # note/fix: needs to get improved to also handle case for h1 wrapped into div
163
+ # (e.g. extract h1 - do not assume it starts slide source)
164
+ if slide_source =~ /^\s*(<h1.*?>.*?<\/h\d>)\s*(.*)/m
165
+ slide.header = $1
166
+ slide.content = ($2 ? $2 : "")
167
+ logger.debug " adding slide with header:\n#{slide.header}"
168
+ else
169
+ slide.content = slide_source
170
+ logger.debug " adding slide with *no* header:\n#{slide.content}"
171
+ end
172
+ slides2 << slide
173
+ end
174
+
175
+ # for convenience create a string w/ all in-one-html
176
+ # no need to wrap slides in divs etc.
177
+
178
+ content2 = ""
179
+ slides2.each do |slide|
180
+ content2 << slide.to_classic_html
181
+ end
182
+
183
+ # make content2 and slide2 available to erb template
184
+ # -- todo: cleanup variable names and use attr_readers for content and slide
185
+
186
+ @slides = slides2 # strutured content
187
+ @content = content2 # content all-in-one
188
+ end
189
+
190
+
191
+ def create_slideshow( fn )
192
+
193
+ manifest_path_or_name = opts.manifest
194
+
195
+ # add .txt file extension if missing (for convenience)
196
+ manifest_path_or_name << ".txt" if File.extname( manifest_path_or_name ).empty?
197
+
198
+
199
+ logger.debug "manifest=#{manifest_path_or_name}"
200
+
201
+ # check if file exists (if yes use custom template package!) - allows you to override builtin package with same name
202
+ if File.exists?( manifest_path_or_name )
203
+ manifest = load_manifest( manifest_path_or_name )
204
+ else
205
+ # check for builtin manifests
206
+ manifests = installed_template_manifests
207
+ matches = manifests.select { |m| m[0] == manifest_path_or_name }
208
+
209
+ if matches.empty?
210
+ puts "*** error: unknown template manifest '#{manifest_path_or_name}'"
211
+ # todo: list installed manifests
212
+ exit 2
213
+ end
214
+
215
+ manifest = load_manifest( matches[0][1] )
216
+ end
217
+
218
+ # expand output path in current dir and make sure output path exists
219
+ outpath = File.expand_path( opts.output_path )
220
+ logger.debug "outpath=#{outpath}"
221
+ FileUtils.makedirs( outpath ) unless File.directory? outpath
222
+
223
+ dirname = File.dirname( fn )
224
+ basename = File.basename( fn, '.*' )
225
+ extname = File.extname( fn )
226
+ logger.debug "dirname=#{dirname}, basename=#{basename}, extname=#{extname}"
227
+
228
+ # change working dir to sourcefile dir
229
+ # todo: add a -c option to commandline? to let you set cwd?
230
+
231
+ newcwd = File.expand_path( dirname )
232
+ oldcwd = File.expand_path( Dir.pwd )
233
+
234
+ unless newcwd == oldcwd then
235
+ logger.debug "oldcwd=#{oldcwd}"
236
+ logger.debug "newcwd=#{newcwd}"
237
+ Dir.chdir newcwd
238
+ end
239
+
240
+ puts "Preparing slideshow '#{basename}'..."
241
+
242
+ if extname.empty? then
243
+ extname = ".textile" # default to .textile
244
+
245
+ config.known_extnames.each do |e|
246
+ logger.debug "File.exists? #{dirname}/#{basename}#{e}"
247
+ if File.exists?( "#{dirname}/#{basename}#{e}" ) then
248
+ extname = e
249
+ logger.debug "extname=#{extname}"
250
+ break
251
+ end
252
+ end
253
+ end
254
+
255
+ if config.known_markdown_extnames.include?( extname )
256
+ @markup_type = :markdown
257
+ elsif config.known_rest_extnames.include?( extname )
258
+ @markup_type = :rest
259
+ else
260
+ @markup_type = :textile
261
+ end
262
+
263
+ # shared variables for templates (binding)
264
+ @content_for = {} # reset content_for hash
265
+
266
+ @name = basename
267
+ @extname = extname
268
+
269
+ @session = {} # reset session hash for plugins/helpers
270
+
271
+ inname = "#{dirname}/#{basename}#{extname}"
272
+
273
+ logger.debug "inname=#{inname}"
274
+
275
+ content = File.read( inname )
276
+
277
+ # run text filters
278
+
279
+ config.text_filters.each do |filter|
280
+ mn = filter.tr( '-', '_' ).to_sym # construct method name (mn)
281
+ content = send( mn, content ) # call filter e.g. include_helper_hack( content )
282
+ end
283
+
284
+ # convert light-weight markup to hypertext
285
+
286
+ content = text_to_html( content )
287
+
288
+ # post-processing
289
+
290
+ # make content2 and slide2 available to erb template
291
+ # -- todo: cleanup variable names and use attr_readers for content and slide
292
+
293
+ if @markup_type == :markdown && config.markdown_post_processing?( Markdown.lib ) == false
294
+ puts " Skipping post-processing (passing content through as is)..."
295
+ @content = content # content all-in-one - make it available in erb templates
296
+ else
297
+ # sets @content (all-in-one string) and @slides (structured content; split into slides)
298
+ post_processing_slides( content )
299
+ end
300
+
301
+
302
+ manifest.each do |entry|
303
+ outname = entry[0]
304
+ if outname.include? '__file__' # process
305
+ outname = outname.gsub( '__file__', basename )
306
+ puts "Preparing #{outname}..."
307
+
308
+ out = File.new( with_output_path( outname, outpath ), "w+" )
309
+
310
+ out << render_template( load_template( entry[1] ), binding )
311
+
312
+ if entry.size > 2 # more than one source file? assume header and footer with content added inbetween
313
+ out << content2
314
+ out << render_template( load_template( entry[2] ), binding )
315
+ end
316
+
317
+ out.flush
318
+ out.close
319
+
320
+ else # just copy verbatim if target/dest has no __file__ in name
321
+ dest = entry[0]
322
+ source = entry[1]
323
+
324
+ puts "Copying to #{dest} from #{source}..."
325
+ FileUtils.copy( source, with_output_path( dest, outpath ) )
326
+ end
327
+ end
328
+
329
+ puts "Done."
330
+ end
331
+
332
+ end # class Gen
333
+
334
+ end # class Slideshow