slideshow 1.1.0.beta7 → 1.1.0.beta8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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