def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end try_require 'rubygems' require 'erb' require 'fileutils' require 'yaml' try_require 'bluecloth' try_require 'erubis' try_require 'redcloth' try_require 'rubypants' try_require 'markaby' try_require 'liquid' try_require 'haml' try_require 'rdoc/markup/simple_markup' try_require 'rdoc/markup/simple_markup/to_html' def handle_exception(exception, text) unless $quiet or exception.class == SystemExit $stderr.puts "ERROR: Exception occured while #{text}:\n" $stderr.puts exception $stderr.puts exception.backtrace.join("\n") end exit end class Array # Ensures that the array contains only one element def ensure_single(a_noun, a_context) if self.size != 1 $stderr.puts "ERROR: expected 1 #{a_noun}, found #{self.size} (#{a_context})" unless $quiet exit end end end module YAML # Returns the contents of an entire file interpreted as YAML and cleaned def self.load_file_and_clean(a_filename) (YAML.load_file(a_filename) || {}).clean end end class Hash # Converts all keys to symbols, and converts *_at and *_on # keys to Times and Dates, respectively def clean inject({}) do |hash, (key, value)| if key =~ /_on$/ hash[key.to_sym] = Date.parse(value) elsif key =~ /_at$/ hash[key.to_sym] = Time.parse(value) elsif value == 'true' hash[key.to_sym] = true elsif value == 'false' hash[key.to_sym] = false elsif value == 'none' hash[key.to_sym] = nil else hash[key.to_sym] = value end hash end end def symbolize_keys inject({}) do |hash, (key, value)| hash[key.intern] = value hash end end def stringify_keys inject({}) do |hash, (key, value)| hash[key.to_s] = value hash end end end class ERBContext def initialize(hash) hash.each_pair do |key, value| instance_variable_set('@' + key.to_s, value) end end def get_binding binding end end class String # Runs the string through the filters as given by the array of # filter names. Available filters include 'markdown', 'smartypants' and 'eruby'. def filter(a_filters, a_params={}) assigns = a_params[:assigns] a_filters.inject(self) do |result, filter| case filter when 'eruby' result.replace(result.eruby(:assigns => assigns)) when 'haml' result.replace(result.haml(:assigns => assigns)) when 'liquid' result.replace(result.liquid(:assigns => assigns)) when 'markaby' result.replace(result.markaby(:assigns => assigns)) when 'markdown', 'bluecloth' result.replace(result.markdown) when 'rdoc' result.replace(result.rdoc) when 'sass' result.replace(result.sass) when 'smartypants', 'rubypants' result.replace(result.smartypants) when 'textile', 'redcloth' result.replace(result.textile) end end end # Converts the string using eRuby def eruby(a_params={}) erubis(a_params) rescue NameError erb(a_params) end # Converts the string using Erubis def erubis(a_params={}) Erubis::Eruby.new(self).evaluate(a_params[:assigns] || {}) end # Converts the string using ERB def erb(a_params={}) ERB.new(self).result(ERBContext.new(a_params[:assigns] || {}).get_binding) end # Converts the string using Haml def haml(a_params={}) options = (a_params[:haml_options] || {}) options[:locals] = a_params[:assigns] unless a_params[:assigns].nil? Haml::Engine.new(self, options).to_html rescue NameError $stderr.puts 'ERROR: String#haml failed (Haml not installed?)' unless $quiet exit end # Converts the string using Liquid def liquid(a_params={}) Liquid::Template.parse(self).render((a_params[:assigns] || {}).stringify_keys) rescue NameError $stderr.puts 'ERROR: String#liquid failed (Liquid not installed?)' unless $quiet exit end # Converts the string using Markaby # TODO perhaps add support for helpers def markaby(a_params={}) Markaby::Builder.new((a_params[:assigns] || {})).instance_eval(self).to_s rescue NameError $stderr.puts 'ERROR: String#markaby failed (Markaby not installed?)' unless $quiet exit end # Converts the string to HTML using BlueCloth/Markdown. def markdown BlueCloth.new(self).to_html rescue NameError $stderr.puts 'ERROR: String#markdown failed: BlueCloth not installed' unless $quiet exit end # Converts the string using RDoc def rdoc SM::SimpleMarkup.new.convert(self, SM::ToHtml.new) end # Converts the string using Sass def sass Sass::Engine.new(self).render end # Converts the string using RedCloth/Textile def textile RedCloth.new(self).to_html rescue NameError $stderr.puts 'ERROR: String#textile failed (RedCloth not installed?)' unless $quiet exit end # Converts the string using RubyPants/SmartyPants def smartypants RubyPants.new(self).to_html rescue NameError $stderr.puts 'ERROR: String#smartypants failed (RubyPants not installed?)' unless $quiet exit end end class FileLogger COLORS = { :reset => "\e[0m", :bold => "\e[1m", :black => "\e[30m", :red => "\e[31m", :green => "\e[32m", :yellow => "\e[33m", :blue => "\e[34m", :magenta => "\e[35m", :cyan => "\e[36m", :white => "\e[37m" } ACTION_COLORS = { :create => COLORS[:bold] + COLORS[:green], :update => COLORS[:bold] + COLORS[:yellow], :move => COLORS[:bold] + COLORS[:blue], :identical => COLORS[:bold] } attr_reader :out def initialize(a_out = $stdout) @out = a_out end def log(a_action, a_path) @out.puts('%s%12s%s %s' % [ACTION_COLORS[a_action.to_sym], a_action, COLORS[:reset], a_path]) unless $quiet end private def method_missing(a_method, *a_args) log(a_method.to_s, a_args.first) end end class FileManager @@stack = [] @@logger = FileLogger.new def self.create_dir(a_name) @@stack.push(a_name) path = File.join(@@stack) unless File.directory?(path) FileUtils.mkdir_p(path) @@logger.create(path) end yield if block_given? @@stack.pop end def self.create_file(a_name) path = File.join(@@stack + [ a_name ]) FileManager.create_dir(path.sub(/\/[^\/]+$/, '')) if @@stack.empty? content = block_given? ? yield : nil if File.exist?(path) if block_given? and File.read(path) == content @@logger.identical(path) else @@logger.update(path) end else @@logger.create(path) end open(path, 'w') { |io| io.write(content) unless content.nil? } end end def render(a_name, a_context={}) assigns = a_context.merge({ :page => @page, :pages => @pages }) File.read('layouts/' + a_name.to_s + '.erb').eruby(:assigns => assigns) end