From 4cc4e303abf87ee2f4b601a5c6fb2eb5bd8b8650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=A0=C5=A5astn=C3=BD=20aka=20Botanicus?= Date: Wed, 20 Oct 2010 14:42:17 +0100 Subject: [PATCH] Initial import --- .gitignore | 3 + CHANGELOG | 3 + LICENSE | 20 ++++ README.textile | 18 ++++ TODO | 1 + ace.gemspec | 53 +++++++++ ace.pre.gemspec | 6 ++ bin/ace | 76 +++++++++++++ bin/ace-gen | 32 ++++++ example/app/posts.rb | 20 ++++ example/app/tags.rb | 28 +++++ example/boot.rb | 6 ++ example/config.yml | 2 + example/content/assets/css/style.css | 1 + example/content/assets/js/application.js | 3 + example/content/index.html.haml | 5 + example/content/posts.json.rb | 0 example/content/posts/node-js.html | 29 +++++ example/content/posts/ruby.html | 21 ++++ example/layouts/base.html.haml | 5 + example/layouts/post.html.haml | 5 + example/layouts/tag.html.haml | 6 ++ example/lib/initializer.rb | 0 example/output/assets/css/style.css | 1 + example/output/assets/js/application.js | 3 + example/output/posts/node-js.html | 32 ++++++ example/output/posts/ruby.html | 24 +++++ example/output/posts/test.html | 10 ++ example/output/tags/development.html | 11 ++ example/output/tags/javascript.html | 10 ++ example/output/tags/node.js.html | 10 ++ example/output/tags/ruby.html | 10 ++ example/rules.rb | 8 ++ example/tasks.rb | 0 lib/ace.rb | 130 +++++++++++++++++++++++ lib/ace/dsl.rb | 21 ++++ lib/ace/filters.rb | 9 ++ lib/ace/filters/haml.rb | 18 ++++ lib/ace/filters/layout.rb | 19 ++++ lib/ace/version.rb | 5 + project_generator/metadata.yml | 3 + project_generator/postprocess.rb | 9 ++ project_generator/setup.rb | 9 ++ simple-templater.scope | 6 ++ 44 files changed, 691 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG create mode 100644 LICENSE create mode 100644 README.textile create mode 100644 TODO create mode 100755 ace.gemspec create mode 100755 ace.pre.gemspec create mode 100755 bin/ace create mode 100755 bin/ace-gen create mode 100644 example/app/posts.rb create mode 100644 example/app/tags.rb create mode 100755 example/boot.rb create mode 100644 example/config.yml create mode 100644 example/content/assets/css/style.css create mode 100644 example/content/assets/js/application.js create mode 100644 example/content/index.html.haml create mode 100644 example/content/posts.json.rb create mode 100644 example/content/posts/node-js.html create mode 100644 example/content/posts/ruby.html create mode 100644 example/layouts/base.html.haml create mode 100644 example/layouts/post.html.haml create mode 100644 example/layouts/tag.html.haml create mode 100644 example/lib/initializer.rb create mode 100644 example/output/assets/css/style.css create mode 100644 example/output/assets/js/application.js create mode 100644 example/output/posts/node-js.html create mode 100644 example/output/posts/ruby.html create mode 100644 example/output/posts/test.html create mode 100644 example/output/tags/development.html create mode 100644 example/output/tags/javascript.html create mode 100644 example/output/tags/node.js.html create mode 100644 example/output/tags/ruby.html create mode 100644 example/rules.rb create mode 100755 example/tasks.rb create mode 100644 lib/ace.rb create mode 100644 lib/ace/dsl.rb create mode 100644 lib/ace/filters.rb create mode 100644 lib/ace/filters/haml.rb create mode 100644 lib/ace/filters/layout.rb create mode 100644 lib/ace/version.rb create mode 100644 project_generator/metadata.yml create mode 100644 project_generator/postprocess.rb create mode 100644 project_generator/setup.rb create mode 100644 simple-templater.scope diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8265aef --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/*.gem +.DS_Store +.rvmrc diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..47d72f7 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,3 @@ += Version 0.0.1 + * Items + * Generators diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d7935b8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2010 Jakub Šťastný aka Botanicus + +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. diff --git a/README.textile b/README.textile new file mode 100644 index 0000000..08f02b7 --- /dev/null +++ b/README.textile @@ -0,0 +1,18 @@ +h1. Why you should be interested in ace? + +In Ace, every page is an instance +Typically I want to define methods, like @post.excerpt + +There are also *generators* available for easier generating items on the fly. + +Ace has *template inheritance*. I love template inheritance, it's more flexible pattern than layouts. + +Tasks for deployment included. + +h1. The boot process + +# load @boot.rb@ where the +# load the rules (controllers / globs mapping) +# load & instantiate the items: only the renderables (concrete post) +# run the filters, layoutin' ... actually this can be defined in the controller +# match the routes, write the files diff --git a/TODO b/TODO new file mode 100644 index 0000000..1ebd191 --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +- ace-gen myproject diff --git a/ace.gemspec b/ace.gemspec new file mode 100755 index 0000000..4d59a46 --- /dev/null +++ b/ace.gemspec @@ -0,0 +1,53 @@ +#!/usr/bin/env gem build +# encoding: utf-8 + +require "base64" +require File.expand_path("../lib/ace/version", __FILE__) + +Gem::Specification.new do |s| + s.name = "ace" + s.version = Ace::VERSION + s.authors = ["Jakub Šťastný aka Botanicus"] + s.homepage = "http://github.com/botanicus/ace" + s.summary = "Ace is highly flexible static pages generator with template inheritance." + s.description = "" # TODO: long description + s.cert_chain = nil + s.email = Base64.decode64("c3Rhc3RueUAxMDFpZGVhcy5jeg==\n") + s.has_rdoc = true + + # files + s.files = `git ls-files`.split("\n") + + s.executables = Dir["bin/*"].map(&File.method(:basename)) + s.default_executable = "ace" + s.require_paths = ["lib"] + + # Ruby version + # Current JRuby with --1.9 switch has RUBY_VERSION set to "1.9.2dev" + # and RubyGems don't play well with it, so we have to set minimal + # Ruby version to 1.9, even if it actually is 1.9.1 + s.required_ruby_version = ::Gem::Requirement.new("~> 1.9") + + # Dependencies + # RubyGems has runtime dependencies (add_dependency) and + # development dependencies (add_development_dependency) + # Ace isn't a monolithic framework, so you might want + # to use just one specific part of it, so it has no sense + # to specify dependencies for the whole gem. If you want + # to install everything what you need for start with Ace, + # just run gem install ace --development + + s.add_dependency "template-inheritance" + s.add_development_dependency "simple-templater", ">= 0.0.1.2" + + begin + require "changelog" + rescue LoadError + warn "You have to have changelog gem installed for post install message" + else + s.post_install_message = CHANGELOG.new.version_changes + end + + # RubyForge + s.rubyforge_project = "ace" +end diff --git a/ace.pre.gemspec b/ace.pre.gemspec new file mode 100755 index 0000000..4ddf9a5 --- /dev/null +++ b/ace.pre.gemspec @@ -0,0 +1,6 @@ +#!/usr/bin/env gem build +# encoding: utf-8 + +eval(File.read("ace.gemspec")).tap do |specification| + specification.version = "#{specification.version}.pre" +end diff --git a/bin/ace b/bin/ace new file mode 100755 index 0000000..fbb0d21 --- /dev/null +++ b/bin/ace @@ -0,0 +1,76 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +if RUBY_VERSION < "1.9.1" + abort "Ace requires Ruby 1.9." +end + +base = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__ +libdir = File.expand_path(File.join(File.dirname(base), "..", "lib")) + +# because of system installation, there is bin/../lib, but not bin/../lib/ace +if File.directory?(File.join(libdir, "ace")) + $:.unshift(libdir) unless $:.include?(libdir) +end + +require "ace" +require "ace/dsl" + +if File.join(Dir.pwd, "boot.rb") + require File.join(Dir.pwd, "boot.rb") +else + abort "No boot.rb!" +end + +if File.join(Dir.pwd, "rules.rb") + path = File.join(Dir.pwd, "rules.rb") + code = File.read(path) + rules = Ace::DSL.new + begin + rules.instance_eval(code) + rescue Exception => exception + puts "Error in DSL: #{exception.message}" + puts exception.backtrace + exit 1 + end +else + abort "No rules.rb!" +end + +rules.rules.each do |klass, files| + puts "#{klass} #{files.inspect}" + files.each do |file| + if File.binread(file).match(/^-{3,5}\s*$/) + raw_item = Ace::RawItem.new(file).tap(&:parse) + item = klass.create(raw_item.metadata, raw_item.content) + else + item = klass.create(Hash.new, File.read(file)) + end + item.original_path = file + end +end + +puts + +rules.generators.each do |generator_klass| + puts "Running #{generator_klass}" + generator = generator_klass.new + begin + if generator.respond_to?(:run) + generator.run + else + abort "Generator #{generator.inspect} doesn't respond to the #run method!" + end + rescue Exception => exception + puts "Error in generator #{generator.inspect}: #{exception.message}" + puts exception.backtrace + exit 1 + end +end + +puts + +Ace::Item.instances.each do |item| + puts "Generating #{item.output_path}" + item.save! +end diff --git a/bin/ace-gen b/bin/ace-gen new file mode 100755 index 0000000..daebe2a --- /dev/null +++ b/bin/ace-gen @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +if RUBY_VERSION < "1.9.1" + abort "Ace requires Ruby 1.9." +end + +base = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__ +libdir = File.expand_path(File.join(File.dirname(base), "..", "lib")) + +# because of system installation, there is bin/../lib, but not bin/../lib/ace +if File.directory?(File.join(libdir, "ace")) + $:.unshift(libdir) unless $:.include?(libdir) +end + +begin + require "simple-templater" +rescue LoadError + abort "You have to install simple-templater first!" +end + +begin + templater = SimpleTemplater.new(:ace) + generator = templater.find(:project) + generator.run(ARGV) +rescue SimpleTemplater::TargetAlreadyExist => exception + abort exception.message +rescue Interrupt + exit +rescue Exception => exception + abort "Exception #{exception.inspect} occured during running generator #{generator.inspect}\n#{exception.backtrace.join("\n")}" +end diff --git a/example/app/posts.rb b/example/app/posts.rb new file mode 100644 index 0000000..93a6239 --- /dev/null +++ b/example/app/posts.rb @@ -0,0 +1,20 @@ +# encoding: utf-8 + +require "nokogiri" +require "ace/filters" + +# Inheritted methods: +# - content +# - metadata +# - config +class Post < Ace::Item + before Ace::LayoutFilter, layout: "post.html" + + def document + Nokogiri::HTML(self.content) + end + + def excerpt + self.document.css("p.excerpt") + end +end diff --git a/example/app/tags.rb b/example/app/tags.rb new file mode 100644 index 0000000..12d7d7e --- /dev/null +++ b/example/app/tags.rb @@ -0,0 +1,28 @@ +# encoding: utf-8 + +class Tag < Ace::Item + before Ace::LayoutFilter, layout: "tag.html" +end + +class TagPagesGenerator + def tags + Post.instances.inject(Hash.new) do |buffer, post| + if tags = post.metadata[:tags] + tags.each do |tag| + buffer[tag] ||= Array.new + buffer[tag] << post + end + end + buffer + end + end + + def run + self.tags.each do |tag_title, items| + tag_name = tag_title.downcase.gsub(" ", "-") + metadata = {title: tag_title, timestamp: Time.now} + tag = Tag.create(metadata, items) + tag.output_path = "output/tags/#{tag_name}.html" + end + end +end diff --git a/example/boot.rb b/example/boot.rb new file mode 100755 index 0000000..c33c093 --- /dev/null +++ b/example/boot.rb @@ -0,0 +1,6 @@ +#!/usr/bin/env ace +# encoding: utf-8 + +Dir["app/**/*.rb"].each do |file| + load file +end diff --git a/example/config.yml b/example/config.yml new file mode 100644 index 0000000..d98d669 --- /dev/null +++ b/example/config.yml @@ -0,0 +1,2 @@ +title: "" +base_url: "" diff --git a/example/content/assets/css/style.css b/example/content/assets/css/style.css new file mode 100644 index 0000000..5ce768c --- /dev/null +++ b/example/content/assets/css/style.css @@ -0,0 +1 @@ +h1 { color: red; } diff --git a/example/content/assets/js/application.js b/example/content/assets/js/application.js new file mode 100644 index 0000000..51593f0 --- /dev/null +++ b/example/content/assets/js/application.js @@ -0,0 +1,3 @@ +window.onload = function () { + console.log("I don't do nothing really, I'm just pretending to be a useful asset."); +}; diff --git a/example/content/index.html.haml b/example/content/index.html.haml new file mode 100644 index 0000000..374ac54 --- /dev/null +++ b/example/content/index.html.haml @@ -0,0 +1,5 @@ +- extends "base.html" + +- Post.each do |post| + %h2= post.title + = post.excerpt diff --git a/example/content/posts.json.rb b/example/content/posts.json.rb new file mode 100644 index 0000000..e69de29 diff --git a/example/content/posts/node-js.html b/example/content/posts/node-js.html new file mode 100644 index 0000000..7cf3eb3 --- /dev/null +++ b/example/content/posts/node-js.html @@ -0,0 +1,29 @@ +--- +title: Node.js Asynchronous JavaScript Framework +timestamp: 2010-09-16 +tags: ["Development", "JavaScript", "Node.js"] +--- + +

+ Node.js is an evented I/O framework for the V8 JavaScript engine. It is intended for writing scalable network programs such as web servers. +

+ +

+ Node.js is similar in purpose to Twisted for Python, Perl Object Environment for Perl, and EventMachine for Ruby. Unlike most JavaScript, it is not executed in a web browser, but it is rather related to server-side JavaScript. Node.js implements some CommonJS specifications[1]. Node.js includes a REPL environment for interactive testing. +

+ +
+var sys = require('sys'),
+    http = require('http');
+
+http.createServer(function (request, response) {
+    response.writeHead(200, {'Content-Type': 'text/plain'});
+    response.end('Hello World\n');
+}).listen(8000);
+
+sys.puts('Server running at http://127.0.0.1:8000/');
+
+ +

+ From Wikipedia.org. +

diff --git a/example/content/posts/ruby.html b/example/content/posts/ruby.html new file mode 100644 index 0000000..54905d3 --- /dev/null +++ b/example/content/posts/ruby.html @@ -0,0 +1,21 @@ +--- +title: Ruby Programming Language +timestamp: 2010-09-14 +tags: ["Development", "Ruby"] +--- + +

+ Ruby is a dynamic, reflective, general purpose object-oriented programming language that combines syntax inspired by Perl with Smalltalk-like features. Ruby originated in Japan during the mid-1990s and was first developed and designed by Yukihiro "Matz" Matsumoto. It was influenced primarily by Perl, Smalltalk, Eiffel, and Lisp. +

+ +

+ Ruby supports multiple programming paradigms, including functional, object oriented, imperative and reflective. It also has a dynamic type system and automatic memory management; it is therefore similar in varying respects to Python, Perl, Lisp, Dylan, Pike, and CLU. +

+ +

+ The standard 1.8.7 implementation is written in C, as a single-pass interpreted language. There is currently no specification of the Ruby language, so the original implementation is considered to be the de facto reference. As of 2010[update], there are a number of complete or upcoming alternative implementations of the Ruby language, including YARV, JRuby, Rubinius, IronRuby, MacRuby, and HotRuby, each of which takes a different approach, with IronRuby, JRuby and MacRuby providing just-in-time compilation and MacRuby also providing ahead-of-time compilation. The official 1.9 branch uses YARV, as will 2.0 (development), and will eventually supersede the slower Ruby MRI. +

+ +

+ From Wikipedia.org. +

diff --git a/example/layouts/base.html.haml b/example/layouts/base.html.haml new file mode 100644 index 0000000..1adb67f --- /dev/null +++ b/example/layouts/base.html.haml @@ -0,0 +1,5 @@ +!!! +%html + %head + %body + #main= block(:body) diff --git a/example/layouts/post.html.haml b/example/layouts/post.html.haml new file mode 100644 index 0000000..7ead0d0 --- /dev/null +++ b/example/layouts/post.html.haml @@ -0,0 +1,5 @@ +- extends "base.html" + +- block(:body) do + %h1 My Coooooool Bloogiiiiseeeeek! + = item.content diff --git a/example/layouts/tag.html.haml b/example/layouts/tag.html.haml new file mode 100644 index 0000000..097b07a --- /dev/null +++ b/example/layouts/tag.html.haml @@ -0,0 +1,6 @@ +- extends "base.html" + +- block(:body) do + %h1 My Coooooool Bloogiiiiseeeeek! + - item.content.each do |post| + = post.metadata[:title] \ No newline at end of file diff --git a/example/lib/initializer.rb b/example/lib/initializer.rb new file mode 100644 index 0000000..e69de29 diff --git a/example/output/assets/css/style.css b/example/output/assets/css/style.css new file mode 100644 index 0000000..5ce768c --- /dev/null +++ b/example/output/assets/css/style.css @@ -0,0 +1 @@ +h1 { color: red; } diff --git a/example/output/assets/js/application.js b/example/output/assets/js/application.js new file mode 100644 index 0000000..51593f0 --- /dev/null +++ b/example/output/assets/js/application.js @@ -0,0 +1,3 @@ +window.onload = function () { + console.log("I don't do nothing really, I'm just pretending to be a useful asset."); +}; diff --git a/example/output/posts/node-js.html b/example/output/posts/node-js.html new file mode 100644 index 0000000..2826ee2 --- /dev/null +++ b/example/output/posts/node-js.html @@ -0,0 +1,32 @@ + + + + +
+

My Coooooool Bloogiiiiseeeeek!

+

+ Node.js is an evented I/O framework for the V8 JavaScript engine. It is intended for writing scalable network programs such as web servers. +

+ +

+ Node.js is similar in purpose to Twisted for Python, Perl Object Environment for Perl, and EventMachine for Ruby. Unlike most JavaScript, it is not executed in a web browser, but it is rather related to server-side JavaScript. Node.js implements some CommonJS specifications[1]. Node.js includes a REPL environment for interactive testing. +

+ +
+      var sys = require('sys'),
+          http = require('http');
+      
+      http.createServer(function (request, response) {
+          response.writeHead(200, {'Content-Type': 'text/plain'});
+          response.end('Hello World\n');
+      }).listen(8000);
+      
+      sys.puts('Server running at http://127.0.0.1:8000/');
+      
+ +

+ From Wikipedia.org. +

+
+ + diff --git a/example/output/posts/ruby.html b/example/output/posts/ruby.html new file mode 100644 index 0000000..b4ae395 --- /dev/null +++ b/example/output/posts/ruby.html @@ -0,0 +1,24 @@ + + + + +
+

My Coooooool Bloogiiiiseeeeek!

+

+ Ruby is a dynamic, reflective, general purpose object-oriented programming language that combines syntax inspired by Perl with Smalltalk-like features. Ruby originated in Japan during the mid-1990s and was first developed and designed by Yukihiro "Matz" Matsumoto. It was influenced primarily by Perl, Smalltalk, Eiffel, and Lisp. +

+ +

+ Ruby supports multiple programming paradigms, including functional, object oriented, imperative and reflective. It also has a dynamic type system and automatic memory management; it is therefore similar in varying respects to Python, Perl, Lisp, Dylan, Pike, and CLU. +

+ +

+ The standard 1.8.7 implementation is written in C, as a single-pass interpreted language. There is currently no specification of the Ruby language, so the original implementation is considered to be the de facto reference. As of 2010[update], there are a number of complete or upcoming alternative implementations of the Ruby language, including YARV, JRuby, Rubinius, IronRuby, MacRuby, and HotRuby, each of which takes a different approach, with IronRuby, JRuby and MacRuby providing just-in-time compilation and MacRuby also providing ahead-of-time compilation. The official 1.9 branch uses YARV, as will 2.0 (development), and will eventually supersede the slower Ruby MRI. +

+ +

+ From Wikipedia.org. +

+
+ + diff --git a/example/output/posts/test.html b/example/output/posts/test.html new file mode 100644 index 0000000..ca32b4f --- /dev/null +++ b/example/output/posts/test.html @@ -0,0 +1,10 @@ + + + + +
+

My Coooooool Bloogiiiiseeeeek!

+ content +
+ + diff --git a/example/output/tags/development.html b/example/output/tags/development.html new file mode 100644 index 0000000..4bd304b --- /dev/null +++ b/example/output/tags/development.html @@ -0,0 +1,11 @@ + + + + +
+

My Coooooool Bloogiiiiseeeeek!

+ Node.js Asynchronous JavaScript Framework + Ruby Programming Language +
+ + diff --git a/example/output/tags/javascript.html b/example/output/tags/javascript.html new file mode 100644 index 0000000..b6c4df9 --- /dev/null +++ b/example/output/tags/javascript.html @@ -0,0 +1,10 @@ + + + + +
+

My Coooooool Bloogiiiiseeeeek!

+ Node.js Asynchronous JavaScript Framework +
+ + diff --git a/example/output/tags/node.js.html b/example/output/tags/node.js.html new file mode 100644 index 0000000..b6c4df9 --- /dev/null +++ b/example/output/tags/node.js.html @@ -0,0 +1,10 @@ + + + + +
+

My Coooooool Bloogiiiiseeeeek!

+ Node.js Asynchronous JavaScript Framework +
+ + diff --git a/example/output/tags/ruby.html b/example/output/tags/ruby.html new file mode 100644 index 0000000..0fd47ae --- /dev/null +++ b/example/output/tags/ruby.html @@ -0,0 +1,10 @@ + + + + +
+

My Coooooool Bloogiiiiseeeeek!

+ Ruby Programming Language +
+ + diff --git a/example/rules.rb b/example/rules.rb new file mode 100644 index 0000000..9b2b107 --- /dev/null +++ b/example/rules.rb @@ -0,0 +1,8 @@ +# encoding: utf-8 + +# filters +rule Post, "posts/*.html" +rule Ace::Asset, "assets/**/*" + +# generators +generator TagPagesGenerator#, "/tags/:slug" diff --git a/example/tasks.rb b/example/tasks.rb new file mode 100755 index 0000000..e69de29 diff --git a/lib/ace.rb b/lib/ace.rb new file mode 100644 index 0000000..70c6d16 --- /dev/null +++ b/lib/ace.rb @@ -0,0 +1,130 @@ +# encoding: utf-8 + +# === The boot process === # +# 1) load the app +# 2) load the rules (controllers / globs mapping) +# 3) load & instantiate all the renderable items +# 4) render all the items (here the filters & layouting run) +# 5) match the routes, write the files + +require "yaml" +require "fileutils" + +module Ace + class RawItem + attr_accessor :path, :metadata, :content + def initialize(path) + @data = File.read(path) + end + + def parse + pieces = @data.split(/^-{3,5}\s*$/) + if pieces.size < 3 + raise RuntimeError.new( + "The file '#{content_filename}' appears to start with a metadata section (three or five dashes at the top) but it does not seem to be in the correct format." + ) + end + + # Parse + self.metadata = YAML.load(pieces[1]).inject(Hash.new) { |metadata, pair| metadata.merge(pair[0].to_sym => pair[1]) } || Hash.new + self.content = pieces[2..-1].join.strip + end + end + + # This class represents the items which will be + # eventually rendered like concrete posts, tags etc. + class Item + @@subclasses ||= Array.new + def self.inherited(subclass) + @@subclasses << subclass + end + + @@instances ||= Array.new + def self.instances + @@instances + end + + def self.before_filters + @before_filters ||= Array.new + end + + def self.before(filter, *args) + self.before_filters << filter.new(*args) + end + + def self.after_filters + @after_filters ||= Array.new + end + + def self.after(filter, *args) + self.after_filters << filter.new(*args) + end + + def self.create(metadata, content) + self.new(metadata, content).tap(&:register) + end + + # Content can be anything, not just a string. + attr_accessor :metadata, :content + attr_accessor :original_path + def initialize(metadata, content) + @metadata = metadata + @content = content + end + + def config + @config ||= begin + YAML::load_file("config.yml").inject(Hash.new) do |hash, pair| + hash.merge!(pair[0].to_sym => pair[1]) + end + end + end + + def register + instances = self.class.instances + unless instances.include?(self) + self.class.instances << self + end + end + + def unregister + self.class.instances.delete(self) + end + + def render + output = self.class.before_filters.inject(self.content) do |buffer, filter| + filter.call(self, buffer) + end + + self.class.after_filters.inject(output) do |buffer, filter| + filter.call(self, buffer) + end + end + + attr_writer :output_path + def output_path + @output_path ||= begin + unless self.original_path.nil? + self.original_path.sub("content", "output") + end + end + end + + def save! + content = self.render.chomp # so filters can influence output_path + + FileUtils.mkdir_p File.dirname(self.output_path) + File.open(self.output_path, "w") do |file| + file.puts content + end + end + end + + class Asset < Item + end + + module Helpers + def link_to(anchor, path_or_item, options = nil) + end + end +end diff --git a/lib/ace/dsl.rb b/lib/ace/dsl.rb new file mode 100644 index 0000000..b937d91 --- /dev/null +++ b/lib/ace/dsl.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 + +module Ace + class DSL + attr_accessor :rules, :generators + def initialize + @rules, @generators = Hash.new, Array.new + end + + def rule(klass, *globs) + paths = globs.map { |glob| Dir.glob("content/#{glob}") } + files = paths.flatten.select { |path| File.file?(path) } + self.rules[klass] ||= Array.new + self.rules[klass].push(*files) + end + + def generator(klass) + self.generators << klass + end + end +end diff --git a/lib/ace/filters.rb b/lib/ace/filters.rb new file mode 100644 index 0000000..834b15c --- /dev/null +++ b/lib/ace/filters.rb @@ -0,0 +1,9 @@ +# encoding: utf-8 + +module Ace + class Filter + def initialize(options = Hash.new) + @options = options + end + end +end diff --git a/lib/ace/filters/haml.rb b/lib/ace/filters/haml.rb new file mode 100644 index 0000000..5676c9e --- /dev/null +++ b/lib/ace/filters/haml.rb @@ -0,0 +1,18 @@ +# encoding: utf-8 + +require "haml" +require "ace/filters" + +module Ace + class HamlFilter < Filter + # http://haml.hamptoncatlin.com/docs/rdoc/classes/Haml/Engine.html + def call(item, content) + if item.output_path && item.output_path.end_with?(".haml") + item.output_path.sub!(/\.haml$/, "") + end + + engine = Haml::Engine.new(content) + engine.render(item.extend(Ace::Helpers)) + end + end +end diff --git a/lib/ace/filters/layout.rb b/lib/ace/filters/layout.rb new file mode 100644 index 0000000..6dcf769 --- /dev/null +++ b/lib/ace/filters/layout.rb @@ -0,0 +1,19 @@ +# encoding: utf-8 + +require "ace/filters" +require "template-inheritance" + +TemplateInheritance::Template.paths << File.join(Dir.pwd, "layouts") + +module Ace + class LayoutFilter < Filter + def initialize(options) + @path = options[:layout] + end + + def call(item, content) + template = TemplateInheritance::Template.new(@path) + return template.render(item: item) + end + end +end diff --git a/lib/ace/version.rb b/lib/ace/version.rb new file mode 100644 index 0000000..5982e8c --- /dev/null +++ b/lib/ace/version.rb @@ -0,0 +1,5 @@ +# encoding: utf-8 + +module Ace + VERSION = "0.0.1" +end diff --git a/project_generator/metadata.yml b/project_generator/metadata.yml new file mode 100644 index 0000000..005004e --- /dev/null +++ b/project_generator/metadata.yml @@ -0,0 +1,3 @@ +--- +:full: yes +:flat: no diff --git a/project_generator/postprocess.rb b/project_generator/postprocess.rb new file mode 100644 index 0000000..4a3c1aa --- /dev/null +++ b/project_generator/postprocess.rb @@ -0,0 +1,9 @@ +# encoding: utf-8 + +# This hook will be executed after templater finish in context of current generator object. +# Current directory is what you just generated, unless this is flat generator. + +unless RUBY_PLATFORM.match(/mswin|mingw/) + sh "chmod +x boot.rb" + sh "chmod +x tasks.rb" +end diff --git a/project_generator/setup.rb b/project_generator/setup.rb new file mode 100644 index 0000000..09b0b41 --- /dev/null +++ b/project_generator/setup.rb @@ -0,0 +1,9 @@ +# encoding: utf-8 + +# This hook will be executed in context of current generator object before templater start to generate new files. +# You can update context hash and register hooks. Don't forget to use merge! instead of merge, because you are +# manipulating with one object, rather than returning new one. + +hook do |generator, context| + # TODO +end diff --git a/simple-templater.scope b/simple-templater.scope new file mode 100644 index 0000000..6488fae --- /dev/null +++ b/simple-templater.scope @@ -0,0 +1,6 @@ +# encoding: utf-8 + +SimpleTemplater.scope(:ace) do + path = File.expand_path("../project_generator", __FILE__) + SimpleTemplater.register(:ace, :project, File.expand_path(path)) +end