require 'rubygems' require 'yaml' require 'erb' require 'redcloth' require 'syntaxi' require 'builder' require 'time' class BlogBuilder attr_reader :entries def initialize( entries_yaml, layout_template ) @title = "free software by daniel choi" @entries = [] @layout_template = layout_template file = File.open( entries_yaml ) YAML::load_documents( file ) do |ydoc| # instantiate entries entry = Entry.new [:body, :title, :uri, :date, :draft, :ad].each do |field| entry.send( (field.to_s + "=").to_sym, ydoc[field.to_s] ) end # fix uri if it needs an html suffix unless entry.uri =~ /.html$/ entry.uri += ".html" end @entries << entry end @entries.reverse! process_bodies end def generate_index_page template = File.read( @layout_template ) entries = @entries.select {|e| e.draft.nil?} index_page = true title = @title erb = ERB.new( template ) File.open( "index.html", "w") do |file| puts "writing index.html" file.write erb.result( binding ) end end def generate_entries template = File.read( @layout_template ) erb = ERB.new( template ) index_page = false @entries.collect do |entry| entries = [entry] title = entry.title File.open( entry.uri, "w") do |file| puts "writing #{entry.uri}" file.write erb.result( binding ) end end end def generate_atom_feed File.open("index.atom", "w") do |target| xml = Builder::XmlMarkup.new :target => target, :indent => 2 xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8" xml.feed "xml:lang" => "en-US", "xmlns" => "http://www.w3.org/2005/Atom" do xml.id "http://danielchoi.com/software/index.atom" xml.link(:rel => "alternate", :type => "text/html", :href => "http://danielchoi.com/software") xml.link(:rel => "self", :href => "http://danielchoi.com/software/index.atom") xml.title "software by daniel choi" xml.subtitle "I like plain text more than HTML" xml.author do xml.name "Daniel Choi" xml.email "dhchoi@gmail.com" xml.uri "/" end xml.link :href => "/software" xml.link :rel => "license", :href => "http://creativecommons.org/licenses/BSD/" xml.updated atom_time(Time.now.utc) for e in @entries.select {|e| e.published?} xml.entry do xml.id atom_id(e.date, "/software/" + e.title) xml.link :rel => "alternate", :type => "text/html", :href => "http://danielchoi.com/software/" + e.uri xml.title e.title xml.summary(e.summary) xml.updated atom_time(Time.parse(e.date)) xml.published atom_time(Time.parse(e.date)) end end end end puts "writing index.atom" end def atom_time(time) "#{time.strftime("%Y-%m-%dT%H:%M:%S")}Z" end def atom_id(time, title) time = Time.parse(time).strftime("%Y-%m-%d") title = title.gsub(" ", "-").downcase "tag:danielchoi.com,%s:%s" % [time, title] end # this needed to make Synatxi work with RedCloth REGEX = /\[code.*?code\]/m #Syntaxi.line_number_method = 'floating' # Syntaxi.wrap_enabled = false Syntaxi.wrap_at_column = 78 # # retrieves code in [code][/code] blocks def get_code_blocks(contents) code_blocks = [] code_block = contents.slice(REGEX) if (!code_block.nil?) code_blocks << code_block while code_block = $'.slice(REGEX) code_blocks << code_block end end code_blocks end # This processes the body textile markup (RedCloth) def process_bodies @entries.each do |entry| entry.summary = entry.body.split(/^\s*$/)[0,2].join("\n\n") # takes the first two paragraphs entry.plain_text_body = entry.body code_blocks = get_code_blocks(entry.body) red_clothed = RedCloth.new(entry.body.gsub(REGEX, '${code_block}')).to_html code_blocks.each { |c| c = Syntaxi.new(c).process red_clothed.sub!(/\$\{code_block\}/, c) } entry.body = red_clothed #entry.body = RedCloth.new( entry.body ).to_html end end end class Entry attr_accessor :body, :summary, :plain_text_body, :title, :uri, :date, :draft, :ad def published? draft.nil? end end if __FILE__ == $0 builder = BlogBuilder.new("entries.yml", "layout.html.erb") builder.generate_index_page builder.generate_entries builder.generate_atom_feed end