# # Program Name: SlideySlide-nn.rb, A simple Hackety Hack Application for Viewing home-made presentations "Slides" # # Initial Program Author: Brian DeLacey # Kind contributions: Eli Brody # Design Consultants: The kids # # Objectives: 1) Make a useful application for Hackety Hack, 2) Demonstrate useful Ruby / HH techniques # # How it works: layout your slides in outline format, it's easy to follow the example, but it's # # Your part: # Create and organize your slide content # Outline it using a format called YAML - sort of a hipper and more human-friendly markup than XML # # SlideySlide's part: # Read in your slide content and assemble it all into into HTML format # Creates the bits you need to easily view and share these slides at your next class project # # HacketyHack's part: # Provides a Web Popup which allows you to easily navigate your presentation pages # # Requirements: # # YAML - presentation file storage (and definition) # Markaby - mark-up (had toyed with RedCloth but defer on that for now) # the _why stack - you know, there's a ton of other stuff this relies on created by _why # # Special thanks to Eli Brody for his many valualbe insights, and all the creators and contributors of Ruby # # Special thanks to _why for Hackety Hack and all these other pieces of his software - the _why hack stack! # # ########################################################################################################### # # Identify the libraries required # ########################################################################################################### # these are for reading input files and generating HTML for output require 'yaml' require 'markaby' # the following are used with hpricot require 'rubygems' require 'hpricot' require 'open-uri' ########################################################################################################### # # Establish Key Initial Settings # ########################################################################################################### Markaby::Builder.set(:indent, 2) # set the indent levels for the HTML that is output ########################################################################################################### # There's something called CSS. It's an acronym for Cascading Style Sheets. # All good web designers have heeps of knowledge about this, but the rest of us can learn to. # It's a wonderful language for laying out text and graphic images on a browser page. # It's a great way to present your information, and that's something we want to do with SlideySlide # You can load all this into a file - "site.css" is one of the CSS files used by _why in HH # That's a terrific start to borrow and learn from someone else. Let's make our own for SlideySlide # Here are the 17 colors that are easy to see on most all kinds of typical personal computer monitors color_choice = %[aqua black blue fuchsia gray green lime maroon navy olive orange purple red silver teal white yellow] # There are some other choices we can make - for font, style, size etc. font_choice = %["italic 2em Times, serif" "bold 2 em Helvetica, sans-serif"] text_decoration = %[underline ov] ########################################################################################################### # # Something that people do a lot in computing is build/manage data structures. Ruby handles this beautifully. # Actually, though, I haven't seen a ton of sample code using data structures, so it's a big part of this "sample" # # EACH SLIDE HAS A STRUCTURE, IT'S AN OBJECT, AND THESE ARE THE IMPORTANT PARTS # # Define it! (You'll notice, it's pretty easy to modify this - by adding/moving different parts of the structure # ########################################################################################################### SlideStructure = Struct.new( :slide_sequence, # system keeps track of physical slide sequence :slide_name, # What's the main point? :background_image, # the background image for this slide :background_color, # the background color for this slide :background_audio, # just a little sound to "ding" when this slide appears :transition_type, # would love to add in some JavaScripty - JQuery transitions :slide_author, # Given credit where credit is due :bullet_array, # These are the main points on each slide :bullet_URL, # Provide a URL if you want to link to/document this bullet :speaker_notes, # Speaker notes - so you don't forget the main points :) :display_speaker_notes # Whether or not to show the speaker notes ) ######################################################################################################### # # Computer programming can be a real treasure hunt of mathematical buried treasures, so herewith is one: # # "In mathematics, a prime number (or a prime) is a natural number that has exactly two (distinct) # natural number divisors, which are 1 and the prime number itself." # Source: http://en.wikipedia.org/wiki/Prime_number # # Besides being interesting, we can use it in testing the SlideySlide! # ########################################################################################################### class Fixnum # Algorithm from http://rubysnips.com/, Prime Numbers, March 23rd 2007 def prime? ('1' * self) !~ /^1?$|^(11+?)\1+$/ end end ######################################################################################################### # # Load up the presentation definition file # # there's a handy description of loading multiple documents from one YML file at # http://yaml4r.sourceforge.net/doc/page/loading_yaml_documents.htm # ########################################################################################################### ## You Write This def load_presentation_file(file) require 'yaml' slideStructure = SlideStructure.new # this is what one slide looks like slideObjectArray = Array.new # we'll have a bunch of slides, maybe # let's read in the presentation file data, in it's glorious YAML format presentationFile = File.open( file ) slideCounter = 0 # this is so we can keep count of how many slides yp = YAML::load_documents( presentationFile ) { |slide| testMode = true if testMode puts "load presentation file: #{slide['slide_sequence']} #{slide['slide_name']} #{slide['background_image']} #{slide['background_color']} #{slide['background_audio']} #{slide['transition_type']} #{slide['slide_author']} #{slide['bullet_array']} #{slide['bullet_URL']} #{slide['speaker_notes']} #{slide['display_speaker_notes']}" end # # There must be a nice way to drink all this in one gulp and map it to the "SlideStructure" data structure? # A good way to handle this is to read in and populate every piece of the "SlideStructure" data structure. # slideObjectArray[slideCounter] = SlideStructure.new slideObjectArray[slideCounter].slide_sequence=slide['slide_sequence'] # what number this is slideObjectArray[slideCounter].slide_name= slide['slide_name'] # make sure it has a name slideObjectArray[slideCounter].background_image = nil # "mypict.jpg" or "mypict.png" you can specificy your own slideObjectArray[slideCounter].background_color = "Cornsilk" # http://en.wikipedia.org/wiki/Web_colors slideObjectArray[slideCounter].background_audio = nil # the silence is deafening :) slideObjectArray[slideCounter].transition_type = nil # some kind of JavaScript whizzy stuff? slideObjectArray[slideCounter].slide_author = slide['slide_author'] # who created and / or contributed the content? slideObjectArray[slideCounter].bullet_array = slide['bullet_array'] slideObjectArray[slideCounter].bullet_URL = slide['bullet_URL'] slideObjectArray[slideCounter].slide_author = slide['speaker_notes'] slideObjectArray[slideCounter].slide_author = slide['display_speaker_notes'] slideCounter += 1 # go get another slide if any exist } return slideObjectArray # this array now has all the data for our slide structures end def printOutYAML(slideObjectArray) #################################################################################### # # PRINT OUT THE DATA IN YAML FORMAT - FOR LEARNING PURPOSES # THIS IS A GOOD EXAMPLE OF WHAT THE INPUT FILE FORMAT LOOKS LIKE # ##################################################################################### # The following produces an example of what that YAML would look like. slideObjectArray.each do |s| yaml_obj = YAML::dump(s) puts yaml_obj end puts " " puts " " end ######################################################################################################### # # Normally, your presentation data will be input from a file # For easy testing, though, we can Use the following pre-loaded data # ########################################################################################################### def createPresentationTestFile() slideObjectArray = Array.new # make an array to store away all our slide objects for i in 0..3 do # okay, start slow with 4 slides slideObjectArray[i] = SlideStructure.new slideObjectArray[i].slide_sequence = i # what number this is slideObjectArray[i].slide_name = "slide #{i}" # make sure it has a name slideObjectArray[i].background_image = nil # "mypict.jpg" or "mypict.png" you can specificy your own slideObjectArray[i].background_color = "Cornsilk" # http://en.wikipedia.org/wiki/Web_colors slideObjectArray[i].background_audio = nil # the silence is deafening :) slideObjectArray[i].transition_type = nil # some kind of JavaScript whizzy stuff? slideObjectArray[i].slide_author = "we" # who created and / or contributed the content? slideObjectArray[i].bullet_array = Array.new # Each slide object needs a bucket to hold its bullet points. slideObjectArray[i].bullet_URL = Array.new for j in 0..3 do # don't overload each slide - just give 'em four points each slideObjectArray[i].bullet_array[j] = "This is slide #{i} and bullet point #{j}" end for j in 0..3 do # don't overload each slide - just give 'em a few links case j when 0 then slideObjectArray[i].bullet_URL[j] = "http://www.ruby-lang.org" when 1 then slideObjectArray[i].bullet_URL[j] = "http://www.cnn.com" else slideObjectArray[i].bullet_URL[j] = nil end end slideObjectArray[i].speaker_notes = "Wow, that was a lot of important stuff to share. D'you like this slide?" if i.prime? # Display the speakers notes for the slides with a prime number for their sequenc slideObjectArray[i].display_speaker_notes = true # sometimes you want to display the notes, but just when they're prime else slideObjectArray[i].display_speaker_notes = false end end printOutYAML(slideObjectArray) # see what the data looks like return slideObjectArray end #################################################################################### # # SlideySlide will now follow your every command # and turn all your hard work into fancy slides # The slides we create are all HTML files - easy for viewing all over the world # and on any device with a browser (they're making more of 'em all the time.) # ##################################################################################### def generateSlides(slideObjectArray) slideCount = 0 slideHtmlFileArray = Array.new slideObjectArray.each do |s| # process every slide - by that we mean create the HTML shadow of it mab = Markaby::Builder.new mab.html do head do tag! :link, :rel=> "stylesheet", :type=> "text/css", :href => "SlideySlide.css", :title => "#{s.slide_name}" end body do # create the HTML body of your slides # name it h1 s.slide_name # navigate it a "first", :href => "MySlides#{0}.html" a "last", :href => "MySlides#{slideObjectArray.size-1}.html" next_slide = slideObjectArray[slideCount].slide_sequence + 1 if next_slide == slideObjectArray.size # array size is one greater than last element since zero based next_slide = 0 # reset so it is back to zero end previous_slide = slideObjectArray[slideCount].slide_sequence - 1 if previous_slide < 0 previous_slide = slideObjectArray.size-1 # reset to last entry, which is one less than size since base=0 end a "next", :href => "MySlides#{next_slide}.html" a "previous", :href => "MySlides#{previous_slide}.html" # color it tag! :body, :bgcolor => s.background_color # space it tag! :br # this just leaves a bit of space tag! :br # bulletize it; attach a URL for any of the bullets where one is provided bullet_count = 0 s.bullet_array.each do |b| if s.bullet_URL[bullet_count] == nil # no URL provided, so just show the bullet ul do li b end else ul do # sure enough, there is a URL linked to this bullet so let it be seen li { a b, :href => "#{s.bullet_URL[bullet_count]}"} end end bullet_count += 1 end # bullet array end tag! :br # this just leaves a bit of space tag! :br # if you want your speaker notes displayed in the HTML, we have a handy way to do that if (slideObjectArray[slideCount].display_speaker_notes == true) h1 slideObjectArray[slideCount].speaker_notes end end # body end end # mab.html end # write it! # # write out the files - there is one HTML file for each slide # we should get fancy and have a title page too. What else would have to change? # File.open("MySlides#{slideCount}.html", "w") do |f| f << mab.to_s # when using a block, the file gets closed automatically, otherwise use f.close slideHtmlFileArray << "MySlides#{slideCount}.html" # add the cover page to our array of files puts mab.to_s # just put the slide content to the console for review end slideCount += 1 # congratulations! SlideySlide finished another - go see if any more need be done end # slide array end # Write out the master page, the main navigation page slideArrayName = Array.new slideArrayFile = Array.new slideCounter = 0 slideObjectArray.each do |s| slideArrayName[slideCounter] = slideObjectArray[slideCounter].slide_name slideArrayFile[slideCounter] = "MySlides"+"#{slideCounter}.html" slideCounter += 1 end mab = Markaby::Builder.new mab.html do head { title "SlideySlide" } body do h1 "SlideySlide Control Panel" ul do # li {a "CNN", :href => "http://www.cnn.com"} # just an example of out-linking # li {a "Google", :href => "http://www.google.com"} # just an example of out-linking for i in 0..slideObjectArray.size-1 li {a "#{slideObjectArray[i].slide_name}", :href => "MySlides"+"#{i}.html"} end end # ul do end # body do end # mab.html do puts mab.to_s File.open("MySlidesCoverPage.html", "w") do |f| f << mab.to_s end slideHtmlFileArray << "MySlidesCoverPage.html" # add the cover page to our array of files return slideHtmlFileArray end testMode = false if testMode slideObjectArray = createPresentationTestFile() # run with simple test data; don't load_presentation_file end #################################################################################### # # RUN SlideySlide # ##################################################################################### slideObjectArray = load_presentation_file("BostonRubyHHv02.yml") # load a live file from disk slideHtmlFileArray = generateSlides(slideObjectArray) # convert & export slides into nice looking HTML detailMode = false if detailMode printOutYAML(slideObjectArray) # this is just to show what is loaded in the console end ####################################################################################################### # # Add some spice within HH # # Here's where I can add some things that only Hackety Hack can really handle nicely # ######################################################################################################## #Web.popup do # # head { title "SlideySlide" } # body do # h1 "SlideySlide Control Panel" # ul do # li {a "CNN", :href => "http://www.cnn.com"} # li {a "Google", :href => "http://www.google.com"} # # for i in 0..slideObjectArray.size-1 # # li {a "#{slideObjectArray[i].slide_name}", :href => "file:MySlides"+"#{i}.html"} # # end # # end # ul do # # end # body do #end #################################################################################### # # THE EPILOGUE # ##################################################################################### # Often, writing programs is a lot of work and rework. Sometimes, you discover stuff that's new. # It's sort of a shame to dispose of those discoveries. They might be useful sometime, and # discoveries are handy to keep around. Here are a bunch of loose ends. None of this is working code # but it is thinking code and commentary that might be worth a quick scan. # # At first I was toying with the idea of creating the mark-up in RedCloth, but # I switched to using Markaby given it seems to be the native markup language of HH # # good examples of RedCloth at http://whytheluckystiff.net/ruby/redcloth/ # # require 'redcloth' < this is needed and you'd need to do a gem install ... # for example r = RedCloth.new "*strong text* and _emphasized text_" # puts r.to_html # gives nice looking HTML to do just waht you want # Eventually, we may get to a point where we have a nice presentation creation language # so we can create a SlideySlide object / class and do things like this: # SlideySlide.presentation do # build_slide "Slide 1" do # bullet_list "Point 1", "Point 2", "Point 3" # end # # build_slide "Slide 2" do # paragraph "This is an example of a full paragraph" # end # end