parade 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +542 -0
  3. data/Rakefile +15 -0
  4. data/bin/parade +138 -0
  5. data/lib/parade.rb +43 -0
  6. data/lib/parade/commands/commands.rb +84 -0
  7. data/lib/parade/commands/generate_outline.rb +34 -0
  8. data/lib/parade/commands/generate_presentation.rb +34 -0
  9. data/lib/parade/commands/generate_rackup.rb +32 -0
  10. data/lib/parade/commands/html_output.rb +47 -0
  11. data/lib/parade/commands/render_from_template.rb +50 -0
  12. data/lib/parade/commands/static_html.rb +38 -0
  13. data/lib/parade/commands/static_pdf.rb +39 -0
  14. data/lib/parade/commands/unknown.rb +23 -0
  15. data/lib/parade/features/live_ruby.rb +18 -0
  16. data/lib/parade/features/pdf_presentation.rb +24 -0
  17. data/lib/parade/features/preshow.rb +11 -0
  18. data/lib/parade/helpers/encode_image.rb +24 -0
  19. data/lib/parade/helpers/template_generator.rb +130 -0
  20. data/lib/parade/metadata.rb +73 -0
  21. data/lib/parade/metadata/assignment.rb +38 -0
  22. data/lib/parade/metadata/css_classes.rb +22 -0
  23. data/lib/parade/metadata/html_id.rb +35 -0
  24. data/lib/parade/metadata/template.rb +31 -0
  25. data/lib/parade/parsers/dsl.rb +138 -0
  26. data/lib/parade/parsers/dsl_file_parser.rb +17 -0
  27. data/lib/parade/parsers/json_file_parser.rb +67 -0
  28. data/lib/parade/parsers/markdown_image_paths.rb +44 -0
  29. data/lib/parade/parsers/markdown_slide_splitter.rb +63 -0
  30. data/lib/parade/parsers/presentation_directory_parser.rb +36 -0
  31. data/lib/parade/parsers/presentation_file_parser.rb +27 -0
  32. data/lib/parade/parsers/presentation_filepath_parser.rb +35 -0
  33. data/lib/parade/parsers/slides_file_content_parser.rb +27 -0
  34. data/lib/parade/renderers/columns_renderer.rb +68 -0
  35. data/lib/parade/renderers/command_line_renderer.rb +142 -0
  36. data/lib/parade/renderers/html_with_pygments.rb +42 -0
  37. data/lib/parade/renderers/inline_images.rb +31 -0
  38. data/lib/parade/renderers/special_paragraph_renderer.rb +23 -0
  39. data/lib/parade/renderers/update_image_paths.rb +75 -0
  40. data/lib/parade/section.rb +183 -0
  41. data/lib/parade/server.rb +139 -0
  42. data/lib/parade/slide.rb +128 -0
  43. data/lib/parade/version.rb +3 -0
  44. data/lib/public/css/960.css +653 -0
  45. data/lib/public/css/fg.menu.css +114 -0
  46. data/lib/public/css/ghf_marked.css +180 -0
  47. data/lib/public/css/jquery-terminal.css +73 -0
  48. data/lib/public/css/onepage.css +62 -0
  49. data/lib/public/css/parade.css +450 -0
  50. data/lib/public/css/pdf.css +13 -0
  51. data/lib/public/css/reset.css +53 -0
  52. data/lib/public/css/spinner_bar.gif +0 -0
  53. data/lib/public/css/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png +0 -0
  54. data/lib/public/css/theme/images/ui-bg_flat_35_f0f0f0_40x100.png +0 -0
  55. data/lib/public/css/theme/images/ui-bg_glass_55_fcf0ba_1x400.png +0 -0
  56. data/lib/public/css/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png +0 -0
  57. data/lib/public/css/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png +0 -0
  58. data/lib/public/css/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png +0 -0
  59. data/lib/public/css/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png +0 -0
  60. data/lib/public/css/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png +0 -0
  61. data/lib/public/css/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png +0 -0
  62. data/lib/public/css/theme/images/ui-icons_808080_256x240.png +0 -0
  63. data/lib/public/css/theme/images/ui-icons_8DC262_256x240.png +0 -0
  64. data/lib/public/css/theme/images/ui-icons_cd0a0a_256x240.png +0 -0
  65. data/lib/public/css/theme/images/ui-icons_e7e6e4_256x240.png +0 -0
  66. data/lib/public/css/theme/images/ui-icons_eeeeee_256x240.png +0 -0
  67. data/lib/public/css/theme/images/ui-icons_ffffff_256x240.png +0 -0
  68. data/lib/public/css/theme/ui.accordion.css +9 -0
  69. data/lib/public/css/theme/ui.all.css +2 -0
  70. data/lib/public/css/theme/ui.base.css +9 -0
  71. data/lib/public/css/theme/ui.core.css +37 -0
  72. data/lib/public/css/theme/ui.datepicker.css +62 -0
  73. data/lib/public/css/theme/ui.dialog.css +13 -0
  74. data/lib/public/css/theme/ui.progressbar.css +4 -0
  75. data/lib/public/css/theme/ui.resizable.css +13 -0
  76. data/lib/public/css/theme/ui.slider.css +17 -0
  77. data/lib/public/css/theme/ui.tabs.css +9 -0
  78. data/lib/public/css/theme/ui.theme.css +245 -0
  79. data/lib/public/favicon.ico +0 -0
  80. data/lib/public/js/coffee-script.js +8 -0
  81. data/lib/public/js/fg.menu.js +645 -0
  82. data/lib/public/js/jTypeWriter.js +26 -0
  83. data/lib/public/js/jquery-1.4.2.js +6240 -0
  84. data/lib/public/js/jquery-print.js +109 -0
  85. data/lib/public/js/jquery-pubsub.js +27 -0
  86. data/lib/public/js/jquery-terminal.js +2712 -0
  87. data/lib/public/js/jquery.batchImageLoad.js +56 -0
  88. data/lib/public/js/jquery.cycle.all.js +1284 -0
  89. data/lib/public/js/keyboard.js +733 -0
  90. data/lib/public/js/parade-code-execution.js +122 -0
  91. data/lib/public/js/parade-command-input.js +16 -0
  92. data/lib/public/js/parade-command-visor.js +92 -0
  93. data/lib/public/js/parade-keyboard-input.js +54 -0
  94. data/lib/public/js/parade.js +675 -0
  95. data/lib/public/js/spine.js +904 -0
  96. data/lib/templates/config.ru.erb +4 -0
  97. data/lib/templates/showoff.erb +27 -0
  98. data/lib/templates/slides.md.erb +25 -0
  99. data/lib/views/header.erb +73 -0
  100. data/lib/views/index.erb +53 -0
  101. data/lib/views/inline_css.erb +3 -0
  102. data/lib/views/inline_js.erb +3 -0
  103. data/lib/views/onepage.erb +17 -0
  104. data/lib/views/pdf.erb +17 -0
  105. data/lib/views/slide.erb +5 -0
  106. metadata +317 -0
@@ -0,0 +1,35 @@
1
+ module Parade
2
+ class Metadata
3
+
4
+ #
5
+ # Specify the HTML id of the slide through this metadata parser. This allows
6
+ # the id to be defined like one would reference with jQuery.
7
+ #
8
+ # @example Setting the Metadata id
9
+ #
10
+ # metadata = Metadata.parse "transition=fade one two #id three tpl=template_name"
11
+ # metadata.id # => id
12
+ #
13
+ # @see Metadata
14
+ #
15
+ class HTMLId
16
+
17
+ def match?(term)
18
+ term =~ /#.+/
19
+ end
20
+
21
+ def apply(term,hash)
22
+ hash[:id] = parse(term)
23
+ hash
24
+ end
25
+
26
+ private
27
+
28
+ def parse(term)
29
+ term[1..-1]
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ module Parade
2
+ class Metadata
3
+
4
+ #
5
+ # The Template metadata allows the specification of a template to use for
6
+ # the slide. This is extremely similar to the {Assignment} parser, except
7
+ # it allows for the previously supported abbreviation *tpl* for representing
8
+ # template.
9
+ #
10
+ class Template
11
+
12
+ def match?(term)
13
+ term =~ /^(?:tpl|template)=(.+)$/
14
+ end
15
+
16
+ def apply(term,hash)
17
+ hash[:template] = parse(term)
18
+ hash
19
+ end
20
+
21
+ private
22
+
23
+ def parse(term)
24
+ term =~ /^(?:tpl|template)=(.+)$/
25
+ template_name = Regexp.last_match(1)
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,138 @@
1
+ require_relative '../section'
2
+ require_relative 'presentation_filepath_parser'
3
+
4
+ module Parade
5
+ module Parsers
6
+
7
+ class Dsl
8
+
9
+ #
10
+ # The parade DSL parse method is used to convert the parade file contents
11
+ # into executable ruby code. This method is also called recursively when
12
+ # a section contains sub-sections to properly parse that data as well.
13
+ #
14
+ # @param [String,Section] contents the string representation of the parade
15
+ # dsl contents to be parsed or the current section to be used as the
16
+ # current context.
17
+ # @param [Hash] options additional options to provide additional
18
+ # configuration to the parsing process.
19
+ #
20
+ # def self.parse(contents,options = {})
21
+ # builder = new
22
+ # builder.options = options
23
+ #
24
+ # config = Proc.new { eval(contents) }
25
+ # builder.instance_eval(&config)
26
+ #
27
+ # builder.current_section
28
+ # end
29
+
30
+ def self.parse(contents,options = {},&config)
31
+ builder = new
32
+ builder.options = options
33
+
34
+ if contents.is_a? Section
35
+ builder.current_section = contents
36
+ else
37
+ config = Proc.new { eval(contents) }
38
+ end
39
+
40
+ builder.instance_eval(&config)
41
+
42
+ builder.current_section
43
+ end
44
+
45
+ #
46
+ # This is used within the DSL to set the title of the current section.
47
+ #
48
+ # @param [String] new_title the title for the setion.
49
+ #
50
+ def title(new_title)
51
+ current_section.title = new_title
52
+ end
53
+
54
+ #
55
+ # This is used within the DSL to set the description of the current section.
56
+ #
57
+ # @param [String] new_description the description for the setion.
58
+ #
59
+ def description(new_description)
60
+ current_section.description = new_description
61
+ end
62
+
63
+ #
64
+ # This is used by the DSL to add additional sections. Adds the specified
65
+ # slides or sub-sections, defined by their filepaths, as a subsection of
66
+ # this section.
67
+ #
68
+ def section(*filepaths,&block)
69
+
70
+ if block
71
+ sub_section = Section.new :title => filepaths.flatten.compact.join(" ")
72
+ section_content = self.class.parse sub_section, options, &block
73
+ else
74
+ section_content = Array(filepaths).flatten.compact.map do |filepath|
75
+ filepath = File.join(current_path,filepath)
76
+ PresentationFilepathParser.parse(filepath,options)
77
+ end
78
+ end
79
+
80
+ current_section.add_section section_content
81
+ section_content
82
+ end
83
+
84
+ alias_method :slides, :section
85
+
86
+ def template(template_name,template_file)
87
+ current_section.add_template template_name, File.join(options[:current_path], template_file)
88
+ end
89
+
90
+ #
91
+ # This is used by the DSL to specify the resources used by the presentation
92
+ #
93
+ def resources(resource_filepath)
94
+ current_section.add_resource File.join(options[:current_path], resource_filepath)
95
+ end
96
+
97
+ def pause_message(message)
98
+ current_section.pause_message = message
99
+ end
100
+
101
+ # @return [Hash] configuration options that the DSL class will use
102
+ # and pass to other file and directory parsers to ensure the
103
+ # path information is presevered correctly.
104
+ attr_accessor :options
105
+
106
+ # @return [String] the root path where the presentation is being served
107
+ # from. This path is necessary to ensure that images have the correct
108
+ # image path built for it.
109
+ def root_path
110
+ File.directory?(options[:root_path]) ? options[:root_path] : File.dirname(options[:root_path])
111
+ end
112
+
113
+ # @return [String] the current path is the path for the current section
114
+ # this usually differs from the root_path when parsing sections defined
115
+ # within a section (a sub-section).
116
+ def current_path
117
+ if options[:current_path]
118
+ File.directory?(options[:current_path]) ? options[:current_path] : File.dirname(options[:current_path])
119
+ else
120
+ root_path
121
+ end
122
+ end
123
+
124
+ attr_writer :current_section
125
+
126
+ # @return [Section] the current section being built.
127
+ def current_section
128
+ @current_section ||= begin
129
+ new_section = Section.new
130
+ new_section.add_resource current_path
131
+ new_section
132
+ end
133
+ end
134
+
135
+ end
136
+
137
+ end
138
+ end
@@ -0,0 +1,17 @@
1
+ module Parade
2
+ module Parsers
3
+
4
+ #
5
+ # Given a DSL defined file, load the contents and then parse the contents
6
+ # with the DSL parser.
7
+ #
8
+ class DslFileParser
9
+
10
+ def self.parse(filepath,options = {})
11
+ Dsl.parse File.read(filepath), options
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,67 @@
1
+ module Parade
2
+ module Parsers
3
+
4
+ #
5
+ # Load the JSON format of a presentation, convert it to the DSL format,
6
+ # and then send it to the DSL parser. This parser is to provide backwards
7
+ # compatabiliy to the previously defined JSON format of a Parade presentation.
8
+ #
9
+ # @example parade.json format
10
+ #
11
+ # {
12
+ # "name": "Something",
13
+ # "description": "Example Presentation",
14
+ # "templates" : { "default" : "custom.tpl" },
15
+ # "sections": [
16
+ # {"section":"one"},
17
+ # {"section":"two"},
18
+ # {"section":"three"}
19
+ # ]
20
+ # }
21
+ #
22
+ class JsonFileParser
23
+
24
+ def self.parse(filepath,options = {})
25
+ parade_json = JSON.parse File.read(filepath)
26
+
27
+ dsl_content = convert_to_parade_dsl parade_json
28
+ Dsl.parse dsl_content, options
29
+ end
30
+
31
+ private
32
+
33
+ def self.convert_to_parade_dsl(content)
34
+
35
+ dsl_content = ""
36
+
37
+ dsl_content << "title '#{content['name']}'\n" if content['name']
38
+ dsl_content << "description %{#{content['description']}}\n" if content['description']
39
+ dsl_content << "pause_message %{#{content['pause_msg']}}" if content['pause_msg']
40
+
41
+ templates = content['templates'] || {}
42
+
43
+ templates.each do |template_name,template_file|
44
+ dsl_content << "template '#{template_name}', '#{template_file}'\n"
45
+ end
46
+
47
+ Array(content['sections']).each do |section|
48
+
49
+ if section.is_a?(Hash)
50
+ filename_or_folder = section['section']
51
+ else
52
+ filename_or_folder = section
53
+ end
54
+
55
+ Array(filename_or_folder).each do |file_or_folder|
56
+ dsl_content << "slides '#{file_or_folder}'\n"
57
+ end
58
+ end
59
+
60
+ dsl_content
61
+
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,44 @@
1
+ module Parade
2
+ module Parsers
3
+
4
+ #
5
+ # Within the markdown file the image paths are relative to the markdown
6
+ # file. This parser will convert any image paths specified within the
7
+ # markdown and convert them to relative to the presentation root.
8
+ #
9
+ # This parsing functionality ensures that the image path when this is
10
+ # later rendered to HTML will have the correct path.
11
+ #
12
+ # @example ![octocat](octocat.png)
13
+ #
14
+ # "![octocat](octocat.png)" # => "![octocat](section/octocat.png)"
15
+ #
16
+ class MarkdownImagePaths
17
+
18
+ #
19
+ # Convert all the image paths within the markdown content with the
20
+ # specified path parameter.
21
+ #
22
+ # @example Update all image paths to be prefixed with 'section'
23
+ #
24
+ # MarkdownImagePaths.parse(markdown_content, :path => 'section')
25
+ #
26
+ #
27
+ # @param [String] content markdown content that may or may not contain
28
+ # image tags.
29
+ # @param [Hash] options that contains parameters to help to properly
30
+ # convert the image path.
31
+ #
32
+ def self.parse(content,options = {})
33
+ return content unless options[:path]
34
+
35
+ content.gsub(/!\[([^\]]*)\]\((?!https?:\/\/)(.+)\)/) do |match|
36
+ updated_image_path = File.join(options[:path],$2)
37
+ %{![#{$1}](#{updated_image_path})}
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,63 @@
1
+ require_relative '../slide'
2
+
3
+ module Parade
4
+ module Parsers
5
+
6
+ #
7
+ # As multiple slides are contained within a markdown file, this parser
8
+ # will split the markdown along the specified slide marker.
9
+ #
10
+ # @todo this currently does too much at the moment. It should simply split
11
+ # the markdown file along the slide markers and allow another parser
12
+ # perform the work of creating the actual slide objects.
13
+ #
14
+ class MarkdownSlideSplitter
15
+
16
+ #
17
+ # Splits the markdown content into separate slide files based on the
18
+ # separator defined by this class.
19
+ #
20
+ # @param [String] content content that is markdown format
21
+ # @return [Array] slides parsed from the markdown content
22
+ def self.parse(content,options = {})
23
+
24
+ # if there are no !SLIDE markers, then make every H1 define a new slide
25
+ unless content =~ /^\<?!SLIDE/m
26
+ content = content.gsub(/^# /m, "<!SLIDE>\n# ")
27
+ end
28
+
29
+ lines = content.split("\n")
30
+
31
+ # Break the markdown apart into separate markdown files based on the
32
+ # separator
33
+
34
+ slides = []
35
+ current_slide = Slide.new
36
+ slides << current_slide
37
+
38
+ until lines.empty?
39
+ line = lines.shift
40
+
41
+ if line =~ /^<?!SLIDE(.*)>?/
42
+
43
+ # Remove the trailing > from the metadata
44
+ metadata_string = Regexp.last_match(1).gsub(/>$/,'')
45
+
46
+ metadata = Metadata.parse metadata_string
47
+
48
+ current_slide = Slide.new(:metadata => metadata)
49
+ slides << current_slide
50
+ else
51
+ current_slide << line
52
+ end
53
+
54
+ end
55
+
56
+ slides.delete_if {|slide| slide.empty? }
57
+ slides.each_with_index {|slide,index| slide.sequence = (index + 1) }
58
+
59
+ end
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,36 @@
1
+ require_relative 'presentation_file_parser'
2
+ require_relative 'slides_file_content_parser'
3
+
4
+ module Parade
5
+ module Parsers
6
+
7
+ module PresentationDirectoryParser
8
+
9
+ SLIDE_SEARCH_PATTERN = File.join('**','*.md')
10
+
11
+ def self.parse(filepath,options = {})
12
+
13
+ parade_file = Array(options[:parade_file]).find do |relative_filepath|
14
+ parade_file = File.join(filepath,relative_filepath)
15
+ File.exists? parade_file
16
+ end
17
+
18
+ if parade_file
19
+ PresentationFileParser.parse File.join(filepath,parade_file), options
20
+ else
21
+
22
+ slides = Dir[File.join(filepath,SLIDE_SEARCH_PATTERN)].map do |slide_filepath|
23
+ SlidesFileContentParser.parse slide_filepath, options
24
+ end
25
+
26
+ section = Section.new
27
+ section.add_section slides
28
+ section
29
+
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'dsl_file_parser'
2
+ require_relative 'json_file_parser'
3
+
4
+ module Parade
5
+ module Parsers
6
+
7
+ #
8
+ # The Presentation File Parser allows for the JSON formatted file or the
9
+ # DSL formatted files. The determination of which to use is solely based
10
+ # on the file extension.
11
+ #
12
+ class PresentationFileParser
13
+
14
+ def self.parse(filepath,options = {})
15
+ options = options.merge(:current_path => File.dirname(filepath))
16
+
17
+ if File.extname(filepath) == ".json"
18
+ JsonFileParser.parse(filepath,options)
19
+ else
20
+ DslFileParser.parse(filepath,options)
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end