Class: ShowOff
- Inherits:
-
Sinatra::Application
- Object
- Sinatra::Application
- ShowOff
- Defined in:
- lib/showoff.rb
Instance Attribute Summary collapse
-
#cached_image_size ⇒ Object
readonly
Returns the value of attribute cached_image_size.
Class Method Summary collapse
- .do_static(args) ⇒ Object
-
.flush ⇒ Object
save stats to disk.
- .pres_dir_current ⇒ Object
Instance Method Summary collapse
- #authorized? ⇒ Boolean
-
#get_code_from_slide(path, index) ⇒ Object
Load a slide file from disk, parse it and return the text of a code block by index.
- #guid ⇒ Object
-
#initialize(app = nil) ⇒ ShowOff
constructor
A new instance of ShowOff.
-
#protected! ⇒ Object
Basic auth boilerplate.
- #require_ruby_files ⇒ Object
- #valid_cookie ⇒ Object
Constructor Details
#initialize(app = nil) ⇒ ShowOff
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/showoff.rb', line 58 def initialize(app=nil) super(app) @logger = Logger.new(STDOUT) @logger.formatter = proc { |severity,datetime,progname,msg| "#{progname} #{msg}\n" } @logger.level = settings.verbose ? Logger::DEBUG : Logger::WARN @review = settings.review @execute = settings.execute dir = File.(File.join(File.dirname(__FILE__), '..')) @logger.debug(dir) showoff_dir = File.(File.join(File.dirname(__FILE__), '..')) settings.pres_dir ||= Dir.pwd @root_path = "." # Load up the default keymap, then merge in any customizations keymapfile = File.(File.join('~', '.showoff', 'keymap.json')) @keymap = Keymap.default @keymap.merge! JSON.parse(File.read(keymapfile)) rescue {} settings.pres_dir = File.(settings.pres_dir) if (settings.pres_file) ShowOffUtils.presentation_config_file = settings.pres_file end # Load configuration for page size and template from the # configuration JSON file if File.exists?(ShowOffUtils.presentation_config_file) showoff_json = JSON.parse(File.read(ShowOffUtils.presentation_config_file)) settings.showoff_config = showoff_json # Set options for encoding, template and page size settings.encoding = showoff_json["encoding"] settings.page_size = showoff_json["page-size"] || "Letter" settings.pres_template = showoff_json["templates"] end # code execution timeout settings.showoff_config['timeout'] ||= 15 # highlightjs syntax style @highlightStyle = settings.showoff_config['highlight'] || 'default' # variables used for building section numbering and title = 0 @section_major = 0 @section_minor = 0 @section_title = settings.showoff_config['name'] rescue 'Showoff Presentation' @logger.debug settings.pres_template @cached_image_size = {} @logger.debug settings.pres_dir @pres_name = settings.pres_dir.split('/').pop require_ruby_files # Default asset path @asset_path = "./" # Create stats directory FileUtils.mkdir settings.statsdir unless File.directory? settings.statsdir # Page view time accumulator. Tracks how often slides are viewed by the audience begin @@counter = JSON.parse(File.read("#{settings.statsdir}/#{settings.viewstats}")) # port old format stats unless @@counter.has_key? 'user_agents' @@counter = { 'user_agents' => {}, 'pageviews' => @@counter } end rescue @@counter = { 'user_agents' => {}, 'pageviews' => {} } end # keeps track of form responses. In memory to avoid concurrence issues. begin @@forms = JSON.parse(File.read("#{settings.statsdir}/#{settings.forms}")) rescue @@forms = Hash.new end @@downloads = Hash.new # Track downloadable files = nil # presenter cookie. Identifies the presenter for control messages @@current = Hash.new # The current slide that the presenter is viewing @@cache = nil # Cache slide content for subsequent hits # flush stats to disk periodically Thread.new do loop do sleep 30 ShowOff.flush end end # Initialize Markdown Configuration MarkdownConfig::setup(settings.pres_dir) end |
Instance Attribute Details
#cached_image_size ⇒ Object (readonly)
Returns the value of attribute cached_image_size.
31 32 33 |
# File 'lib/showoff.rb', line 31 def cached_image_size @cached_image_size end |
Class Method Details
.do_static(args) ⇒ Object
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 |
# File 'lib/showoff.rb', line 1048 def self.do_static(args) args ||= [] # handle nil arguments what = args[0] || "index" opt = args[1] # Sinatra now aliases new to new! # https://github.com/sinatra/sinatra/blob/v1.3.3/lib/sinatra/base.rb#L1369 showoff = ShowOff.new! name = showoff.instance_variable_get(:@pres_name) path = showoff.instance_variable_get(:@root_path) logger = showoff.instance_variable_get(:@logger) if what == 'supplemental' data = showoff.send(what, opt, true) else data = showoff.send(what, true) end if data.is_a?(File) FileUtils.cp(data.path, "#{name}.pdf") else out = File.("#{path}/static") # First make a directory FileUtils.makedirs(out) # Then write the html file = File.new("#{out}/index.html", "w") file.puts(data) file.close # Now copy all the js and css my_path = File.join( File.dirname(__FILE__), '..', 'public') ["js", "css"].each { |dir| FileUtils.copy_entry("#{my_path}/#{dir}", "#{out}/#{dir}", false, false, true) } # And copy the directory Dir.glob("#{my_path}/#{name}/*").each { |subpath| base = File.basename(subpath) next if "static" == base next unless File.directory?(subpath) || base.match(/\.(css|js)$/) FileUtils.copy_entry(subpath, "#{out}/#{base}") } # Set up file dir file_dir = File.join(out, 'file') FileUtils.makedirs(file_dir) pres_dir = showoff.settings.pres_dir # ..., copy all user-defined styles and javascript files Dir.glob("#{pres_dir}/*.{css,js}").each { |path| FileUtils.copy(path, File.join(file_dir, File.basename(path))) } # ... and copy all needed image files [/img src=[\"\'].\/file\/(.*?)[\"\']/, /style=[\"\']background: url\(\'file\/(.*?)'/].each do |regex| data.scan(regex).flatten.each do |path| dir = File.dirname(path) FileUtils.makedirs(File.join(file_dir, dir)) begin FileUtils.copy(File.join(pres_dir, path), File.join(file_dir, path)) rescue Errno::ENOENT => e puts "Missing source file: #{path}" end end end # copy images from css too Dir.glob("#{pres_dir}/*.css").each do |css_path| File.open(css_path) do |file| data = file.read data.scan(/url\([\"\']?(?!https?:\/\/)(.*?)[\"\']?\)/).flatten.each do |path| path.gsub!(/(\#.*)$/, '') # get rid of the anchor path.gsub!(/(\?.*)$/, '') # get rid of the query logger.debug path dir = File.dirname(path) FileUtils.makedirs(File.join(file_dir, dir)) begin FileUtils.copy(File.join(pres_dir, path), File.join(file_dir, path)) rescue Errno::ENOENT => e puts "Missing source file: #{path}" end end end end end end |
.flush ⇒ Object
save stats to disk
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/showoff.rb', line 158 def self.flush if defined?(@@counter) and not @@counter.empty? File.open("#{settings.statsdir}/#{settings.viewstats}", 'w') do |f| if settings.verbose then f.write(JSON.pretty_generate(@@counter)) else f.write(@@counter.to_json) end end end if defined?(@@forms) and not @@forms.empty? File.open("#{settings.statsdir}/#{settings.forms}", 'w') do |f| if settings.verbose then f.write(JSON.pretty_generate(@@forms)) else f.write(@@forms.to_json) end end end end |
.pres_dir_current ⇒ Object
180 181 182 183 |
# File 'lib/showoff.rb', line 180 def self.pres_dir_current opt = {:pres_dir => Dir.pwd} ShowOff.set opt end |
Instance Method Details
#authorized? ⇒ Boolean
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 |
# File 'lib/showoff.rb', line 1152 def if not settings.showoff_config.has_key? 'password' # if no password is set, then default to allowing access to localhost request.env['REMOTE_HOST'] == 'localhost' or request.ip == '127.0.0.1' else auth ||= Rack::Auth::Basic::Request.new(request.env) user = settings.showoff_config['user'] || '' password = settings.showoff_config['password'] auth.provided? && auth.basic? && auth.credentials && auth.credentials == [user, password] end end |
#get_code_from_slide(path, index) ⇒ Object
Load a slide file from disk, parse it and return the text of a code block by index
1134 1135 1136 1137 1138 1139 1140 1141 1142 |
# File 'lib/showoff.rb', line 1134 def (path, index) = "#{path}.md" return unless File.exists? html = process_markdown(, File.read(), {}) doc = Nokogiri::HTML::DocumentFragment.parse(html) return doc.css('code.execute')[index.to_i].text rescue 'Invalid code block index' end |
#guid ⇒ Object
1164 1165 1166 1167 |
# File 'lib/showoff.rb', line 1164 def guid # this is a terrifyingly simple GUID generator (0..15).to_a.map{|a| rand(16).to_s(16)}.join end |
#protected! ⇒ Object
Basic auth boilerplate
1145 1146 1147 1148 1149 1150 |
# File 'lib/showoff.rb', line 1145 def protected! unless response['WWW-Authenticate'] = %(Basic realm="#{@title}: Protected Area") throw(:halt, [401, "Not authorized\n"]) end end |
#require_ruby_files ⇒ Object
185 186 187 |
# File 'lib/showoff.rb', line 185 def require_ruby_files Dir.glob("#{settings.pres_dir}/*.rb").map { |path| require path } end |
#valid_cookie ⇒ Object
1169 1170 1171 |
# File 'lib/showoff.rb', line 1169 def (request.['presenter'] == ) end |