slideshow 0.8.5 → 0.9

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.
@@ -0,0 +1,143 @@
1
+ # builtin text filters
2
+ # called before text_to_html
3
+ #
4
+ # use web filters for processing html/hypertext
5
+
6
+ module TextFilter
7
+
8
+ def comments_percent_style( content )
9
+ # remove comments
10
+ # % comments
11
+ # %begin multiline comment
12
+ # %end multiline comment
13
+
14
+ # track statistics
15
+ comments_multi = 0
16
+ comments_single = 0
17
+ comments_end = 0
18
+
19
+ # remove multi-line comments
20
+ content.gsub!(/^%begin.*?%end/m) do |match|
21
+ comments_multi += 1
22
+ ""
23
+ end
24
+
25
+ # remove everyting starting w/ %end (note, can only be once in file)
26
+ content.sub!(/^%end.*/m) do |match|
27
+ comments_end += 1
28
+ ""
29
+ end
30
+
31
+ # remove single-line comments
32
+ content.gsub!(/^%.*/ ) do |match|
33
+ comments_single += 1
34
+ ""
35
+ end
36
+
37
+ puts " Removing comments (#{comments_single} %-lines, " +
38
+ "#{comments_multi} %begin/%end-blocks, #{comments_end} %end-blocks)..."
39
+
40
+ content
41
+ end
42
+
43
+ def skip_end_directive( content )
44
+ # codex-style __SKIP__, __END__ directive
45
+ # ruby note: .*? is non-greedy (shortest-possible) regex match
46
+ content.gsub!(/__SKIP__.*?__END__/m, '')
47
+ content.sub!(/__END__.*/m, '')
48
+ content
49
+ end
50
+
51
+ def include_helper_hack( content )
52
+ # note: include is a ruby keyword; rename to __include__ so we can use it
53
+
54
+ include_counter = 0
55
+
56
+ content.gsub!( /<%=[ \t]*include/ ) do |match|
57
+ include_counter += 1
58
+ '<%= __include__'
59
+ end
60
+
61
+ puts " Patching embedded Ruby (erb) code aliases (#{include_counter} include)..."
62
+
63
+ content
64
+ end
65
+
66
+ # allow plugins/helpers; process source (including header) using erb
67
+ def erb( content )
68
+ puts " Running embedded Ruby (erb) code/helpers..."
69
+
70
+ content = ERB.new( content ).result( binding() )
71
+ content
72
+ end
73
+
74
+ def erb_django_style( content )
75
+
76
+ # replace expressions (support for single lines only)
77
+ # {{ expr }} -> <%= expr %>
78
+ # {% stmt %} -> <% stmt %> !! add in do if missing (for convenience)
79
+
80
+ erb_expr = 0
81
+ erb_stmt_beg = 0
82
+ erb_stmt_end = 0
83
+
84
+ content.gsub!( /\{\{([^{}\n]+?)\}\}/ ) do |match|
85
+ erb_expr += 1
86
+ "<%= #{$1} %>"
87
+ end
88
+
89
+ content.gsub!( /\{%[ \t]*end[ \t]*%\}/ ) do |match|
90
+ erb_stmt_end += 1
91
+ "<% end %>"
92
+ end
93
+
94
+ content.gsub!( /\{%([^%\n]+?)%\}/ ) do |match|
95
+ erb_stmt_beg += 1
96
+ if $1.include?('do')
97
+ "<% #{$1} %>"
98
+ else
99
+ "<% #{$1} do %>"
100
+ end
101
+ end
102
+
103
+ puts " Patching embedded Ruby (erb) code Django-style (#{erb_expr} {{-expressions," +
104
+ " #{erb_stmt_beg}/#{erb_stmt_end} {%-statements)..."
105
+
106
+ content
107
+ end
108
+
109
+ def code_block_curly_style( content )
110
+ # replace {{{ w/ <pre class='code'>
111
+ # replace }}} w/ </pre>
112
+
113
+ # track statistics
114
+ code_begin = 0
115
+ code_end = 0
116
+
117
+ content.gsub!( "{{{{{{", "<pre class='code'>_S9BEGIN_" )
118
+ content.gsub!( "}}}}}}", "_S9END_</pre>" )
119
+
120
+ content.gsub!( "{{{" ) do |match|
121
+ code_begin += 1
122
+ "<pre class='code'>"
123
+ end
124
+
125
+ content.gsub!( "}}}" ) do |match|
126
+ code_end += 1
127
+ "</pre>"
128
+ end
129
+
130
+ # restore escaped {{{}}}
131
+ content.gsub!( "_S9BEGIN_", "{{{" )
132
+ content.gsub!( "_S9END_", "}}}" )
133
+
134
+ puts " Patching code blocks (#{code_begin}/#{code_end} {{{/}}}-lines)..."
135
+
136
+ content
137
+ end
138
+
139
+ end
140
+
141
+ class Slideshow::Gen
142
+ include TextFilter
143
+ end
@@ -1,38 +1,15 @@
1
-
2
-
3
-
4
1
  module Slideshow
5
2
 
6
- class Slide < Struct.new(:header, :content)
7
- end
8
-
9
3
  class Gen
10
-
11
- KNOWN_TEXTILE_EXTNAMES = [ '.textile', '.t' ]
12
- KNOWN_MARKDOWN_EXTNAMES = [ '.markdown', '.m', '.mark', '.mkdn', '.md', '.txt', '.text' ]
13
- KNOWN_EXTNAMES = KNOWN_TEXTILE_EXTNAMES + KNOWN_MARKDOWN_EXTNAMES
14
-
15
- # note: only kramdown is listed as a dependency in gem specs (because it's Ruby only and, thus, easy to install)
16
- # if you want to use other markdown libs install the required/desired lib e.g.
17
- # use gem install rdiscount for rdiscount and so on
18
- #
19
- # also note for now the first present markdown library gets used
20
- # the search order is first come, first serve, that is: rdiscount, rpeg-markdown, maruku, bluecloth, kramdown (fallback, always present)
21
- KNOWN_MARKDOWN_LIBS = [
22
- [ 'rdiscount', lambda { |content| RDiscount.new( content ).to_html } ],
23
- [ 'rpeg-markdown', lambda { |content| PEGMarkdown.new( content ).to_html } ],
24
- [ 'maruku', lambda { |content| Maruku.new( content, {:on_error => :raise} ).to_html } ],
25
- [ 'bluecloth', lambda { |content| BlueCloth.new( content ).to_html } ],
26
- [ 'kramdown', lambda { |content| Kramdown::Document.new( content ).to_html } ]
27
- ]
28
4
 
29
5
  def initialize
30
6
  @logger = Logger.new(STDOUT)
31
7
  @logger.level = Logger::INFO
32
- @opts = Opts.new
8
+ @opts = Opts.new
9
+ @config = Config.new
33
10
  end
34
11
 
35
- attr_reader :logger, :opts
12
+ attr_reader :logger, :opts, :config
36
13
  attr_reader :session # give helpers/plugins a session-like hash
37
14
 
38
15
  def headers
@@ -47,42 +24,47 @@ class Gen
47
24
  # try to require each lib and remove any not installed
48
25
  @markdown_libs = []
49
26
 
50
- KNOWN_MARKDOWN_LIBS.each do |lib|
27
+ config.known_markdown_libs.each do |lib|
51
28
  begin
52
- require lib[0]
29
+ require lib
53
30
  @markdown_libs << lib
54
31
  rescue LoadError => ex
55
- logger.debug "Markdown library #{lib[0]} not found. Use gem install #{lib[0]} to install."
32
+ logger.debug "Markdown library #{lib} not found. Use gem install #{lib} to install."
56
33
  end
57
34
  end
58
35
 
59
- logger.debug "Installed Markdown libraries: #{@markdown_libs.map{ |lib| lib[0] }.join(', ')}"
60
- logger.debug "Using Markdown library #{@markdown_libs.first[0]}."
36
+ puts " Found #{@markdown_libs.length} Markdown libraries: #{@markdown_libs.join(', ')}"
61
37
  end
38
+
62
39
 
63
- # todo: move to filter (for easier reuse)
64
40
  def markdown_to_html( content )
65
- @markdown_libs.first[1].call( content )
66
- end
67
-
68
- # todo: move to filter (for easier reuse)
69
- def textile_to_html( content )
41
+ # call markdown filter; turn markdown lib name into method_name (mn)
42
+ # eg. rpeg-markdown => rpeg_markdown_to_html
70
43
 
71
- # JRuby workaround for RedCloth 4 multi-byte character bug
72
- # see http://jgarber.lighthouseapp.com/projects/13054/tickets/149-redcloth-4-doesnt-support-multi-bytes-content
73
- # basically convert non-ascii chars (>127) to html entities
74
-
75
- if RedCloth::EXTENSION_LANGUAGE == "Java"
76
- content = content.chars.map{ |x| x.size > 1 ? "&##{x.unpack("U*")};" : x }.join
44
+ puts " Converting Markdown-text (#{content.length} bytes) to HTML using library '#{@markdown_libs.first}'..."
45
+
46
+ mn = @markdown_libs.first.downcase.tr( '-', '_' )
47
+ mn = "#{mn}_to_html".to_sym
48
+ send mn, content # call 1st configured markdown engine e.g. kramdown_to_html( content )
49
+ end
50
+
51
+ # uses configured markup processor (textile,markdown) to generate html
52
+ def text_to_html( content )
53
+ content = case @markup_type
54
+ when :markdown
55
+ markdown_to_html( content )
56
+ when :textile
57
+ textile_to_html( content )
77
58
  end
78
-
79
- # turn off hard line breaks
80
- # turn off span caps (see http://rubybook.ca/2008/08/16/redcloth)
81
- red = RedCloth.new( content, [:no_span_caps] )
82
- red.hard_breaks = false
83
- content = red.to_html
59
+ content
84
60
  end
85
-
61
+
62
+ def guard_text( text )
63
+ # todo/fix: remove wrap_markup; replace w/ guard_text
64
+ # why: text might be css, js, not just html
65
+ wrap_markup( text )
66
+ end
67
+
86
68
  def wrap_markup( text )
87
69
  if markup_type == :textile
88
70
  # saveguard with notextile wrapper etc./no further processing needed
@@ -97,7 +79,7 @@ class Gen
97
79
  end
98
80
 
99
81
  def win32_cache_dir
100
- unless File.exists?(home = ENV['HOMEDRIVE'] + ENV['HOMEPATH'])
82
+ unless ENV['HOMEDRIVE'] && ENV['HOMEPATH'] && File.exists?(home = ENV['HOMEDRIVE'] + ENV['HOMEPATH'])
101
83
  puts "No HOMEDRIVE or HOMEPATH environment variable. Set one to save a" +
102
84
  "local cache of stylesheets for syntax highlighting and more."
103
85
  return false
@@ -277,9 +259,14 @@ class Gen
277
259
  logger.debug "using direct net http access; no proxy configured"
278
260
  proxy = OpenStruct.new # all fields return nil (e.g. proxy.host, etc.)
279
261
  end
262
+
263
+ # same as short-cut: http_proxy.get_respone( uri )
264
+ # use full code for easier changes
280
265
 
281
- http = Net::HTTP::Proxy( proxy.host, proxy.port, proxy.user, proxy.password )
282
- response = http.get_response( uri )
266
+ http_proxy = Net::HTTP::Proxy( proxy.host, proxy.port, proxy.user, proxy.password )
267
+ http = http_proxy.new( uri.host, uri.port )
268
+ request = Net::HTTP::Get.new( uri.request_uri )
269
+ response = http.request( request )
283
270
 
284
271
  unless response.code == '200' # note: responsoe.code is a string
285
272
  msg = "#{response.code} #{response.message}"
@@ -306,7 +293,21 @@ class Gen
306
293
  def fetch_slideshow_templates
307
294
  logger.debug "fetch_uri=#{opts.fetch_uri}"
308
295
 
309
- src = opts.fetch_uri
296
+ src = opts.fetch_uri
297
+
298
+ ## check for builtin shortcut (assume no / or \)
299
+ if src.index( '/' ).nil? && src.index( '\\' ).nil?
300
+ shortcut = src.clone
301
+ src = config.map_fetch_shortcut( src )
302
+
303
+ if src.nil?
304
+ puts "** Error: No mapping found for fetch shortcut '#{shortcut}'."
305
+ return
306
+ end
307
+ puts " Mapping fetch shortcut '#{shortcut}' to: #{src}"
308
+ end
309
+
310
+
310
311
  # src = 'http://github.com/geraldb/slideshow/raw/d98e5b02b87ee66485431b1bee8fb6378297bfe4/code/templates/fullerscreen.txt'
311
312
  # src = 'http://github.com/geraldb/sandbox/raw/13d4fec0908fbfcc456b74dfe2f88621614b5244/s5blank/s5blank.txt'
312
313
  uri = URI.parse( src )
@@ -409,6 +410,11 @@ class Gen
409
410
  def create_slideshow( fn )
410
411
 
411
412
  manifest_path_or_name = opts.manifest
413
+
414
+ # add .txt file extension if missing (for convenience)
415
+ manifest_path_or_name << ".txt" if File.extname( manifest_path_or_name ).empty?
416
+
417
+
412
418
  logger.debug "manifest=#{manifest_path_or_name}"
413
419
 
414
420
  # check if file exists (if yes use custom template package!) - allows you to override builtin package with same name
@@ -455,7 +461,7 @@ class Gen
455
461
  if extname.empty? then
456
462
  extname = ".textile" # default to .textile
457
463
 
458
- KNOWN_EXTNAMES.each do |e|
464
+ config.known_extnames.each do |e|
459
465
  logger.debug "File.exists? #{dirname}/#{basename}#{e}"
460
466
  if File.exists?( "#{dirname}/#{basename}#{e}" ) then
461
467
  extname = e
@@ -465,7 +471,7 @@ class Gen
465
471
  end
466
472
  end
467
473
 
468
- if KNOWN_MARKDOWN_EXTNAMES.include?( extname )
474
+ if config.known_markdown_extnames.include?( extname )
469
475
  @markup_type = :markdown
470
476
  else
471
477
  @markup_type = :textile
@@ -482,113 +488,94 @@ class Gen
482
488
 
483
489
  logger.debug "inname=#{inname}"
484
490
 
485
- content_with_headers = File.read( inname )
491
+ content = File.read( inname )
486
492
 
487
- # todo: read headers before command line options (lets you override options using commandline switch)?
488
-
489
- # read source document; split off optional header from source
490
- # strip leading optional headers (key/value pairs) including optional empty lines
493
+ # fix: add to comment text filter as first rule!!
494
+ # check for !SLIDE alias %slide (needs to get coverted to ! otherwise
495
+ # it gets removed as a comment)
496
+ content.gsub!(/^%slide/, '!SLIDE' )
491
497
 
492
- read_headers = true
493
- content = ""
498
+ # run text filters
494
499
 
495
- # fix: allow comments in header too (#)
496
-
497
- content_with_headers.each_line do |line|
498
- if read_headers && line =~ /^\s*(\w[\w-]*)[ \t]*:[ \t]*(.*)/
499
- key = $1.downcase
500
- value = $2.strip
501
-
502
- logger.debug " adding option: key=>#{key}< value=>#{value}<"
503
- opts.put( key, value )
504
- elsif line =~ /^\s*$/
505
- content << line unless read_headers
506
- else
507
- read_headers = false
508
- content << line
509
- end
500
+ config.text_filters.each do |filter|
501
+ mn = filter.tr( '-', '_' ).to_sym # construct method name (mn)
502
+ content = send( mn, content ) # call filter e.g. include_helper_hack( content )
510
503
  end
511
504
 
512
- opts.set_defaults
513
-
514
- # ruby note: .*? is non-greedy (shortest-possible) regex match
515
- content.gsub!(/__SKIP__.*?__END__/m, '')
516
- content.sub!(/__END__.*/m, '')
517
-
518
- # allow plugins/helpers; process source (including header) using erb
505
+ # check for !SLIDE markers; change to HTML comments
519
506
 
520
- # note: include is a ruby keyword; rename to __include__ so we can use it
521
- content.gsub!( /<%=[ \t]*include/, '<%= __include__' )
507
+ # -- slide marker stats
508
+ slide_markers = 0
522
509
 
523
- content = ERB.new( content ).result( binding )
510
+ ## todo: use html processing instruction <?s9 slide ?>
511
+ content.gsub!(/^!SLIDE(.*)/ ) do |match|
512
+ slide_markers += 1
513
+ "<!-- _S9SLIDE_ #{$1} -->"
514
+ end
524
515
 
525
- # run pre-filters (built-in macros)
526
- # o replace {{{ w/ <pre class='code'>
527
- # o replace }}} w/ </pre>
528
- content.gsub!( "{{{{{{", "<pre class='code'>_S9BEGIN_" )
529
- content.gsub!( "}}}}}}", "_S9END_</pre>" )
530
- content.gsub!( "{{{", "<pre class='code'>" )
531
- content.gsub!( "}}}", "</pre>" )
532
- # restore escaped {{{}}} I'm sure there's a better way! Rubyize this! Anyone?
533
- content.gsub!( "_S9BEGIN_", "{{{" )
534
- content.gsub!( "_S9END_", "}}}" )
516
+ puts " Processing directives (#{slide_markers} !SLIDE-directives)..."
517
+
535
518
 
536
519
  # convert light-weight markup to hypertext
537
520
 
538
- content = case @markup_type
539
- when :markdown
540
- markdown_to_html( content )
541
- when :textile
542
- textile_to_html( content )
543
- end
544
-
521
+ content = text_to_html( content )
522
+
545
523
  # post-processing
546
524
 
547
525
  slide_counter = 0
548
- content2 = ''
549
-
550
- ## todo: move this to a filter (for easier reuse)
551
526
 
552
527
  slides = []
553
528
  slide_source = ""
554
529
 
555
530
  # wrap h1's in slide divs; note: use just <h1 since some processors add ids e.g. <h1 id='x'>
556
531
  content.each_line do |line|
557
- if line.include?( '<h1' ) then
532
+ if line.include?( '<h1' ) || line.include?( '<!-- _S9SLIDE_' ) then
558
533
  if slide_counter > 0 then # found start of new slide (and, thus, end of last slide)
559
- content2 << "</div>\n"
560
534
  slides << slide_source # add slide to slide stack
561
- slide_source = "" # reset slide source buffer
535
+ slide_source = "" # reset slide source buffer
562
536
  end
563
- content2 << "<div class='slide'>\n"
564
537
  slide_counter += 1
565
538
  end
566
- content2 << line
567
539
  slide_source << line
568
540
  end
569
541
 
570
542
  if slide_counter > 0 then
571
- content2 << "</div>\n"
572
543
  slides << slide_source # add slide to slide stack
573
544
  slide_source = "" # reset slide source buffer
574
545
  end
575
546
 
576
547
  ## split slide source into header (optional) and content/body
548
+ ## plus check for classes
577
549
 
578
550
  slides2 = []
579
551
  slides.each do |slide_source|
580
552
  slide = Slide.new
581
- if slide_source =~ /^\s*(<h.+?>.*?<\/h\d>)\s+(.*)/m # try to cut off header using non-greedy .+? pattern; tip test regex online at rubular.com
553
+
554
+ ## check for css style class
555
+ if slide_source =~ /<!-- _S9SLIDE_(.*?)-->/
556
+ slide.classes = $1.strip
557
+ logger.debug " adding css classes: #{slide.classes}"
558
+ end
559
+
560
+ if slide_source =~ /^\s*(<h1.+?>.*?<\/h\d>)\s*(.*)/m # try to cut off header using non-greedy .+? pattern; tip test regex online at rubular.com
582
561
  slide.header = $1
583
- slide.content = $2
562
+ slide.content = ($2 ? $2 : "")
584
563
  logger.debug " adding slide with header:\n#{slide.header}"
585
- else
564
+ else
586
565
  slide.content = slide_source
587
566
  logger.debug " adding slide with *no* header"
588
567
  end
589
568
  slides2 << slide
590
569
  end
591
570
 
571
+ # for convenience create a string w/ all in-one-html
572
+ # no need to wrap slides in divs etc.
573
+
574
+ content2 = ""
575
+ slides2.each do |slide|
576
+ content2 << slide.to_classic_html
577
+ end
578
+
592
579
  # make content2 and slide2 available to erb template
593
580
  # -- todo: cleanup variable names and use attr_readers for content and slide
594
581
 
@@ -653,19 +640,13 @@ def run( args )
653
640
 
654
641
  cmd.on( '-o', '--output PATH', 'Output Path' ) { |s| opts.put( 'output', s ) }
655
642
 
656
- cmd.on( '-g', '--generate', 'Generate Slide Show Templates' ) { opts.put( 'generate', true ) }
643
+ cmd.on( '-g', '--generate', 'Generate Slide Show Templates (Using Built-In S6 Pack)' ) { opts.put( 'generate', true ) }
657
644
 
658
645
  cmd.on( "-t", "--template MANIFEST", "Template Manifest" ) do |t|
659
646
  # todo: do some checks on passed in template argument
660
647
  opts.put( 'manifest', t )
661
648
  end
662
649
 
663
- # shortcut: same as -t s5.txt
664
- cmd.on( '--s5', 'S5-Compatible Slide Show (same as -t s5.txt)' ) { opts.put( 's5', true ); opts.put( 'manifest', 's5.txt' ) }
665
-
666
- # shortcut: same as -t fullerscreen.txt
667
- cmd.on( '--fullerscreen', 'FullerScreen-Compatible Slide Show (same as -t fullerscreen.txt)' ) { opts.put( 'fuller', true ); opts.put( 'manifest', 'fullerscreen.txt' ) }
668
-
669
650
  # ?? opts.on( "-s", "--style STYLE", "Select Stylesheet" ) { |s| $options[:style]=s }
670
651
  # ?? opts.on( "--version", "Show version" ) {}
671
652
 
@@ -695,19 +676,16 @@ def run( args )
695
676
  puts
696
677
  puts "Examples:"
697
678
  puts " slideshow microformats"
698
- puts " slideshow microformats.textile"
679
+ puts " slideshow microformats.textile # Process slides using Textile"
680
+ puts " slideshow microformats.text # Process slides using Markdown"
699
681
  puts " slideshow -o slides microformats # Output slideshow to slides folder"
700
- puts " slideshow --s5 microformats # Use S5-compatible slide show templates"
701
- puts " slideshow --fullerscreen microformats # Use FullerScreen-compatible slide show templates"
702
682
  puts
703
683
  puts "More examles:"
704
- puts " slideshow -g # Generate slide show templates"
705
- puts " slideshow -g --s5 # Generate S5 compatible slide show templates"
706
- puts " slideshow -g --fullerscreen # Generate FullerScreen compatible slide show templates"
684
+ puts " slideshow -g # Generate slide show templates using built-in S6 pack"
707
685
  puts
708
686
  puts " slideshow -l # List installed slide show templates"
709
687
  puts " slideshow -f s5blank # Fetch (install) S5 blank starter template from internet"
710
- puts " slideshow -t s5blank.txt microformats # Use your own slide show templates (e.g. s5blank.txt)"
688
+ puts " slideshow -t s5blank microformats # Use your own slide show templates (e.g. s5blank)"
711
689
  puts
712
690
  puts "Further information:"
713
691
  puts " http://slideshow.rubyforge.org"
@@ -716,6 +694,8 @@ def run( args )
716
694
  end
717
695
 
718
696
  opt.parse!( args )
697
+
698
+ config.load
719
699
 
720
700
  puts "Slide Show (S9) Version: #{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
721
701