Permalink
Browse files

Initial commit.

  • Loading branch information...
jgm committed Jul 19, 2009
0 parents commit 2fcfcf1da59deb1efdd15ab2b959f311de72f1f2
@@ -0,0 +1,23 @@
+# -*- ruby -*-
+
+require 'autotest/restart'
+
+# Autotest.add_hook :initialize do |at|
+# at.extra_files << "../some/external/dependency.rb"
+#
+# at.libs << ":../some/external"
+#
+# at.add_exception 'vendor'
+#
+# at.add_mapping(/dependency.rb/) do |f, _|
+# at.files_matching(/test_.*rb$/)
+# end
+#
+# %w(TestA TestB).each do |klass|
+# at.extra_class_map[klass] = "test/test_misc.rb"
+# end
+# end
+
+# Autotest.add_hook :run_command do |at|
+# system "rake build"
+# end
@@ -0,0 +1,3 @@
+=== 0.1 / 2009-07-19
+
+* Initial release
@@ -0,0 +1,16 @@
+History.txt
+Manifest.txt
+README.txt
+Rakefile
+bin/ecstatic
+lib/ecstatic.rb
+samplesite/events.rbhtml
+samplesite/events.yaml
+samplesite/standard.rbhtml
+samplesite/siteindex.yaml
+samplesite/Rakefile
+samplesite/README
+samplesite/models/models.rb
+samplesite/files/css/print.css
+samplesite/files/css/screen.css
+samplesite/files/Ukulele.jpg
@@ -0,0 +1,79 @@
+= ecstatic
+
+* http://github.com/jgm/ecstatic
+
+== DESCRIPTION:
+
+ecstatic helps you manage a static website. Pages are generated
+from tenjin templates and YAML data files.
+
+== FEATURES:
+
+* Generates a static site, for high performance and security
+* Separation of data and presentation, as in a dynamic web framework,
+ but with data in text files rather than databases
+* Supports markdown
+* Supports output in HTML, plain text, and LaTeX
+
+== SYNOPSIS:
+
+First, generate a site skeleton:
+
+ ecstatic mysite
+
+See what has been done:
+
+ cd mysite
+ ls
+
+To build the site (in the <tt>site</tt> directory):
+
+ rake
+
+Try modifying the layout (<tt>standard.rbhtml</tt>),
+the data (<tt>events.yaml</tt>), or the template
+(<tt>events.rbhtml</tt>). Recompile the site with rake.
+
+If you want to add new pages, just add templates and
+datafiles, and register the pages in <tt>siteindex.yaml</tt>.
+Put any static files in <tt>files</tt>; these will be copied
+verbatim into the site.
+
+If a page has no dynamic elements (other than the ones handled
+by the layout), you can use a markdown file instead of a
+template. Just give it the extension <tt>.markdown</tt>
+
+== REQUIREMENTS:
+
+* rpeg-markdown
+* tenjin
+* activesupport
+
+== INSTALL:
+
+* sudo gem install ecstatic
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) 2009 John MacFarlane
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,11 @@
+# -*- ruby -*-
+
+require 'rubygems'
+require 'hoe'
+
+Hoe.spec 'ecstatic' do
+ developer('John MacFarlane', 'jgm@berkeley.edu')
+ # self.rubyforge_name = 'ecstaticx' # if different than 'ecstatic'
+end
+
+# vim: syntax=ruby
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+require 'fileutils'
+
+if ARGV.length != 1
+ $stderr.puts "Usage: ecstatic PATH - create skeleton site in PATH\n"
+ exit 1
+end
+
+target = ARGV[0]
+
+sampledir = File.join File.dirname(__FILE__), "../samplesite"
+FileUtils.cp_r("#{sampledir}/.", target)
+
+puts "Created skeleton in #{target}."
+puts "To make your site:"
+puts " cd #{target}"
+puts " rake"
+
+exit 0
@@ -0,0 +1,22 @@
+Gem::Specification.new do |s|
+ s.name = "ecstatic"
+ s.version = "0.1"
+ s.date = "2009-07-19"
+ s.summary = "Framework for maintaining a static website from templates and data in YAML files."
+ s.email = "jgm@berkeley.edu"
+ s.homepage = "http://github.com/jgm/cloudlib"
+ s.description = "Ecstatic is a framework for maintaining a static website from templates and data in YAML files."
+ s.has_rdoc = true
+ s.authors = ["John MacFarlane"]
+ s.bindir = "bin"
+ s.executables = ["ecstatic"]
+ s.default_executable = "ecstatic"
+ s.files = File.open("Manifest.txt").readlines.map {|x| x.chomp}
+ s.test_files = []
+ s.rdoc_options = ["--main", "README.txt", "--inline-source"]
+ s.extra_rdoc_files = ["README.txt"]
+ s.add_dependency("activesupport", [">= 1.1"])
+ s.add_dependency("rpeg-markdown", [">= 0.2"])
+ s.add_dependency("tenjin", [">= 0.6.1"])
+end
+
@@ -0,0 +1,109 @@
+require 'rubygems'
+require 'tenjin'
+require 'optparse'
+require 'yaml'
+require 'markdown'
+require 'activesupport'
+
+module Ecstatic
+ class Page
+ attr_accessor :contexthash, :layoutfile, :templatefile
+
+ def initialize(templatefile = nil, datafiles = [], layoutfile = nil)
+ @templatefile = templatefile
+ @layoutfile = layoutfile
+ # get context from data files
+ @contexthash = {}
+ datafiles.each do |file|
+ yamltext = File.open(file).read
+ yaml = YAML::load(yamltext)
+ # if YAML is not a hash, make a hash with file's basename as key:
+ unless yaml.class == Hash
+ yaml = {File.basename(file, File.extname(file)) => yaml}
+ end
+ yaml.each_pair do |key,val|
+ model = key.singularize.capitalize
+ begin
+ @contexthash[key] = Object.const_get(model).from_array(val)
+ rescue
+ $stderr.puts("Unable to initialize " + key + " from model " + model)
+ @contexthash[key] = val
+ end
+ end
+ end
+ end
+
+ def escapefun(format)
+ case
+ when format == :html
+ return 'Ecstatic.markdown_to_compact_html'
+ when format == :latex
+ return 'Ecstatic.markdown_to_latex'
+ else
+ return 'escape'
+ end
+ end
+
+ def to_format(format)
+ engine = Tenjin::Engine.new(:cache => false, :escapefunc => escapefun(format))
+
+ if File.extname(self.templatefile) == '.markdown'
+ contents = File.open(self.templatefile).read
+ output = case
+ when format == :html
+ markdown_to_compact_html(contents)
+ when format == :latex
+ markdown_to_latex(contents)
+ else
+ escape(contents)
+ end
+ else
+ context = Tenjin::Context.new(self.contexthash)
+ output = engine.render(self.templatefile, context)
+ end
+
+ if self.layoutfile
+ supercontext = Tenjin::Context.new({'_contents' => output})
+ superoutput = engine.render(self.layoutfile, {'_contents' => output})
+ return superoutput
+ else
+ return output
+ end
+ end
+
+ def to_html
+ self.to_format(:html)
+ end
+
+ def to_latex
+ self.to_format(:latex)
+ end
+
+ def to_plain
+ self.to_format(:plain)
+ end
+ end
+
+ # escape functions
+
+ def markdown_to_html(str)
+ Markdown.new(str, :smart).to_html
+ end
+
+ def markdown_to_compact_html(str)
+ res = markdown_to_html(str)
+ if (res =~ /<p>.*<p>/)
+ return res
+ else # only one paragraph
+ return res.gsub(/<\/?p>/,"")
+ end
+ end
+
+ def markdown_to_latex(str)
+ Markdown.new(str, :smart).to_latex
+ end
+
+ alias m markdown_to_html
+ module_function :markdown_to_html, :markdown_to_compact_html, :markdown_to_latex, :m
+end
+
@@ -0,0 +1 @@
+To be completed.
@@ -0,0 +1,66 @@
+require 'rake/clean'
+require 'ecstatic'
+require 'find'
+
+# load user-defined data models
+Find.find('models') do |f|
+ require f unless f == 'models'
+end
+
+SITEDIR = "site"
+CLEAN.include(SITEDIR)
+
+LAYOUT = "standard.rbhtml"
+
+siteindex = YAML::load File.read("siteindex.yaml")
+SITETITLE = siteindex['sitetitle']
+
+# construct list of pages
+PAGES = {}
+siteindex['pages'].each do |p|
+ dest = File.join SITEDIR, p['url']
+ PAGES[dest] = {
+ :title => p['title'],
+ :template => p['template'],
+ :data => if p['data'].class == Array
+ p['data']
+ elsif p['data'].class == String
+ [p['data']]
+ else
+ []
+ end }
+end
+
+# construct hash of files
+FILESDIR = "files"
+FILES = {}
+Find.find(FILESDIR) do |f|
+ if f != FILESDIR
+ base = f.gsub(/^[^\/]*\//,"")
+ FILES[File.join(SITEDIR, base)] = f
+ end
+end
+
+task :default => :all
+task :all => [SITEDIR] + PAGES.keys + FILES.keys
+
+directory SITEDIR
+
+FILES.each_pair do |dest,src|
+ file dest => src do
+ d = File.dirname dest
+ if ! File.exists? d
+ mkdir_p(File.dirname(dest))
+ end
+ cp src, dest
+ end
+end
+
+PAGES.each_pair do |dest,page|
+
+ file dest => ([page[:template], LAYOUT] + page[:data]) do
+ output = Ecstatic::Page.new(page[:template], page[:data], LAYOUT).to_html
+ File.open(dest, 'w').write(output)
+ end
+
+end
@@ -0,0 +1,9 @@
+<h1>Events</h1>
+<img src="Ukulele.jpg"/>
+<ul>
+<?rb for event in @events.sort_by {|e| e.date}.reverse ?>
+ <li>
+ ${event.speaker}, ${event.title} (${event.date.to_s("%B %d, %Y")})
+ </li>
+<?rb end ?>
+</ul>
@@ -0,0 +1,14 @@
+events:
+
+- title: Why Static Sites Are Best
+ speaker: Sam Spade
+ date:
+ start: 2009-04-08
+ end : 2009-04-09
+
+- title: Ruby vs. Haskell
+ speaker:
+ - Sam Spade
+ - John Doe
+ date: 2009-05-09
+
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1 @@
+/* CSS for printing here */
@@ -0,0 +1 @@
+/* CSS for screen display here */
Oops, something went wrong.

0 comments on commit 2fcfcf1

Please sign in to comment.