zzot-semi-static 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/Manifest.txt +30 -0
- data/README.markdown +84 -0
- data/VERSION.yml +4 -0
- data/bin/semi +6 -0
- data/lib/semi-static.rb +30 -0
- data/lib/semi-static/base.rb +74 -0
- data/lib/semi-static/categories.rb +74 -0
- data/lib/semi-static/cli.rb +126 -0
- data/lib/semi-static/convertable.rb +94 -0
- data/lib/semi-static/core_ext/hash.rb +19 -0
- data/lib/semi-static/index.rb +12 -0
- data/lib/semi-static/layout.rb +14 -0
- data/lib/semi-static/page.rb +58 -0
- data/lib/semi-static/post.rb +133 -0
- data/lib/semi-static/posts.rb +110 -0
- data/lib/semi-static/pygmentize.rb +54 -0
- data/lib/semi-static/site.rb +232 -0
- data/lib/semi-static/snippet.rb +12 -0
- data/lib/semi-static/statistics.rb +45 -0
- data/lib/semi-static/stylesheet.rb +33 -0
- data/test/helper.rb +111 -0
- data/test/ref/test_layout/default_layout.html +35 -0
- data/test/ref/test_layout/post_layout.html +85 -0
- data/test/ref/test_output/2005-03-27.html +5 -0
- data/test/ref/test_output/2005-03.html +4 -0
- data/test/ref/test_output/2005.html +5 -0
- data/test/ref/test_output/2008-11-24.html +5 -0
- data/test/ref/test_output/2008-11-26.html +5 -0
- data/test/ref/test_output/2008-11.html +5 -0
- data/test/ref/test_output/2008-12-04.html +5 -0
- data/test/ref/test_output/2008-12.html +4 -0
- data/test/ref/test_output/2008.html +6 -0
- data/test/ref/test_page/about.html +47 -0
- data/test/ref/test_page/colophon.html +45 -0
- data/test/ref/test_post/impressions.html +102 -0
- data/test/ref/test_post/lighting-up.html +102 -0
- data/test/ref/test_post/the-working-mans-typeface.html +88 -0
- data/test/source/indices/day.erb +7 -0
- data/test/source/indices/month.erb +10 -0
- data/test/source/indices/year.erb +10 -0
- data/test/source/layouts/default.haml +25 -0
- data/test/source/layouts/post.erb +36 -0
- data/test/source/pages/about.md +38 -0
- data/test/source/pages/colophon.md +36 -0
- data/test/source/pages/feed.xml.erb +26 -0
- data/test/source/posts/2005-03-27-a-bash-script-to-mess-with-the-containing-terminalapp-window.markdown +38 -0
- data/test/source/posts/2008-11-24-lighting-up.markdown +41 -0
- data/test/source/posts/2008-11-26-impressions.md +42 -0
- data/test/source/posts/2008-12-04-the-working-mans-typeface.html +15 -0
- data/test/source/scripts/jquery-1.3.js +4241 -0
- data/test/source/scripts/jquery-1.3.min.js +19 -0
- data/test/source/semi.yml +5 -0
- data/test/source/snippets/comment-links.html +17 -0
- data/test/source/snippets/comments.html +4 -0
- data/test/source/stylesheets/layout.sass +115 -0
- data/test/source/stylesheets/post.sass +21 -0
- data/test/source/stylesheets/screen.sass +11 -0
- data/test/source/stylesheets/syntax.css +60 -0
- data/test/source/stylesheets/text.sass +25 -0
- data/test/test_layout.rb +51 -0
- data/test/test_output.rb +61 -0
- data/test/test_page.rb +68 -0
- data/test/test_post.rb +96 -0
- metadata +183 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.markdown
|
4
|
+
Rakefile
|
5
|
+
bin/semi-static
|
6
|
+
lib/semi-static.rb
|
7
|
+
lib/semi-static/base.rb
|
8
|
+
lib/semi-static/categories.rb
|
9
|
+
lib/semi-static/convertable.rb
|
10
|
+
lib/semi-static/core_ext/hash.rb
|
11
|
+
lib/semi-static/layout.rb
|
12
|
+
lib/semi-static/page.rb
|
13
|
+
lib/semi-static/post.rb
|
14
|
+
lib/semi-static/site.rb
|
15
|
+
test/helper.rb
|
16
|
+
test/ref/test_layout/default_layout.html
|
17
|
+
test/ref/test_layout/post_layout.html
|
18
|
+
test/ref/test_page/about.html
|
19
|
+
test/ref/test_page/colophon.html
|
20
|
+
test/ref/test_post/lighting-up.html
|
21
|
+
test/source/_layouts/default.haml
|
22
|
+
test/source/_layouts/post.haml
|
23
|
+
test/source/_posts/2008-11-24-lighting-up.markdown
|
24
|
+
test/source/_posts/2008-11-26-impressions.md
|
25
|
+
test/source/_posts/2008-12-04-the-working-mans-typeface.html
|
26
|
+
test/source/about.md
|
27
|
+
test/source/colophon.md
|
28
|
+
test/test_layout.rb
|
29
|
+
test/test_page.rb
|
30
|
+
test/test_post.rb
|
data/README.markdown
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
Semi-Static
|
2
|
+
===========
|
3
|
+
|
4
|
+
Semi-Static is yet another static site generator. I've been playing around
|
5
|
+
with similar systems off and on for years, but its [Jekyll][] that finally
|
6
|
+
convinced me to build (and finish) one. The main idea that I take from
|
7
|
+
Jekyll is using [Git][] as the “database”. The idea from Jekyll that I'm
|
8
|
+
ignoring completely is avoiding [Ruby][] code evaluation at all costs — I'm
|
9
|
+
not running the thing on a server like [GitHub][] [Pages][], and it
|
10
|
+
eliminates a few libraries that I want to use.
|
11
|
+
|
12
|
+
At some point Semi-Static had a sister project, Semi-Live, that would serve
|
13
|
+
up data from the data source dynamically, probably via [Rails][]. I stopped
|
14
|
+
working on it not long after I first started, so don't expect to see it
|
15
|
+
following its sister off to my [projects][] page.
|
16
|
+
|
17
|
+
Features
|
18
|
+
--------
|
19
|
+
|
20
|
+
* Layouts can be [Haml][] or [ERB][] — but not [Liquid][].
|
21
|
+
* Stylesheets can be [Sass][] or raw CSS.
|
22
|
+
* Pages and posts can be [Maruku][] or raw HTML.
|
23
|
+
* Code highlighting by [Pygments][].
|
24
|
+
|
25
|
+
Installation
|
26
|
+
------------
|
27
|
+
|
28
|
+
The easiest way to install Semi-Static is via [RubyGems][]:
|
29
|
+
|
30
|
+
$ sudo gem install zzot-semi-static -s http://gems.github.com/
|
31
|
+
|
32
|
+
Semi-Static requires the \`Haml\` and \`Maruku\` gems and the \`Pygments\`
|
33
|
+
library to be installed.
|
34
|
+
|
35
|
+
Usage
|
36
|
+
-----
|
37
|
+
|
38
|
+
$ semi source-path \[output-path\]
|
39
|
+
|
40
|
+
License
|
41
|
+
-------
|
42
|
+
|
43
|
+
(The MIT License)
|
44
|
+
|
45
|
+
Copyright (c) 2009 Josh Dady
|
46
|
+
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
48
|
+
a copy of this software and associated documentation files (the
|
49
|
+
'Software'), to deal in the Software without restriction, including
|
50
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
51
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
52
|
+
permit persons to whom the Software is furnished to do so, subject to
|
53
|
+
the following conditions:
|
54
|
+
|
55
|
+
The above copyright notice and this permission notice shall be
|
56
|
+
included in all copies or substantial portions of the Software.
|
57
|
+
|
58
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
59
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
60
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
61
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
62
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
63
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
64
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
65
|
+
|
66
|
+
[*CMS]: Content Management System
|
67
|
+
[*CSS]: Cascading Style Sheets
|
68
|
+
[*HTML]: HyperText Markup Language
|
69
|
+
|
70
|
+
[semi-static]: http://github.com/zzot/semi-static
|
71
|
+
[jekyll]: http://github.com/mojombo/jekyll
|
72
|
+
[git]: http://git-scm.com/
|
73
|
+
[github]: http://github.com/
|
74
|
+
[pages]: http://pages.github.com
|
75
|
+
[rails]: http://rubyonrails.org/
|
76
|
+
[projects]: http://github.com/zzot
|
77
|
+
[haml]: http://haml.hamptoncatlin.com/
|
78
|
+
[sass]: http://haml.hamptoncatlin.com/
|
79
|
+
[erb]: http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/
|
80
|
+
[liquid]: http://www.liquidmarkup.org/
|
81
|
+
[maruku]: http://maruku.rubyforge.org/
|
82
|
+
[pygments]: http://pygments.org/
|
83
|
+
[rubygems]: http://www.rubygems.org/
|
84
|
+
[ruby]: http://ruby-lang.org/
|
data/VERSION.yml
ADDED
data/bin/semi
ADDED
data/lib/semi-static.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Core requirements
|
2
|
+
require 'erb'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
# Gem requirements
|
7
|
+
require 'rubygems'
|
8
|
+
require 'haml'
|
9
|
+
require 'sass'
|
10
|
+
require 'maruku'
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
13
|
+
|
14
|
+
# Core extensions
|
15
|
+
require 'semi-static/core_ext/hash'
|
16
|
+
|
17
|
+
# My classes and modules
|
18
|
+
require 'semi-static/base'
|
19
|
+
require 'semi-static/pygmentize'
|
20
|
+
require 'semi-static/convertable'
|
21
|
+
require 'semi-static/layout'
|
22
|
+
require 'semi-static/stylesheet'
|
23
|
+
require 'semi-static/page'
|
24
|
+
require 'semi-static/post'
|
25
|
+
require 'semi-static/snippet'
|
26
|
+
require 'semi-static/posts'
|
27
|
+
require 'semi-static/index'
|
28
|
+
require 'semi-static/categories'
|
29
|
+
require 'semi-static/statistics'
|
30
|
+
require 'semi-static/site'
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module SemiStatic
|
2
|
+
# Base represents a single source file and its associated metadata.
|
3
|
+
# Base loads the source file, and strips and parses any metadata set
|
4
|
+
# in the file's header. It stores an absolute path to the file so we
|
5
|
+
# can refer to it later.
|
6
|
+
class Base
|
7
|
+
##
|
8
|
+
# The associated Site object
|
9
|
+
attr_reader :site
|
10
|
+
|
11
|
+
##
|
12
|
+
# The relative path to the source file
|
13
|
+
attr_reader :source_path
|
14
|
+
|
15
|
+
##
|
16
|
+
# The source file's extension
|
17
|
+
attr_reader :source_ext
|
18
|
+
|
19
|
+
##
|
20
|
+
# The source file's contents
|
21
|
+
attr_reader :source_content
|
22
|
+
|
23
|
+
##
|
24
|
+
# The metadata found in the file's header
|
25
|
+
attr_reader :source_metadata
|
26
|
+
|
27
|
+
##
|
28
|
+
# The absolute path to the source file
|
29
|
+
attr_reader :full_source_path
|
30
|
+
|
31
|
+
##
|
32
|
+
# Initializes a new Base
|
33
|
+
#
|
34
|
+
# +site+:: The Site object we belong to
|
35
|
+
# +path+:: The relative path to the source file
|
36
|
+
def initialize(site, path)
|
37
|
+
@site = site
|
38
|
+
@source_path = path
|
39
|
+
@source_ext = File.extname(source_path)
|
40
|
+
@full_source_path = File.expand_path(source_path)
|
41
|
+
@metadata = []
|
42
|
+
|
43
|
+
load
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Get the modification time of the source file.
|
48
|
+
def source_mtime
|
49
|
+
File.mtime(@full_source_path)
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
##
|
54
|
+
# Read the source file and parse any metadata in the file header.
|
55
|
+
def load
|
56
|
+
contents = File.read File.join(full_source_path)
|
57
|
+
if contents =~ /^(---\s*\n.*?)\n---\s*\n/m
|
58
|
+
@source_content, @source_metadata = contents[($1.size + 5) .. -1], YAML.load($1)
|
59
|
+
else
|
60
|
+
@source_content, @source_metadata = contents, {}
|
61
|
+
end
|
62
|
+
@source_metadata.symbolize_keys
|
63
|
+
end
|
64
|
+
|
65
|
+
def method_missing(method, *args) #:nodoc:
|
66
|
+
name = method.to_sym
|
67
|
+
if @metadata.include?(name)
|
68
|
+
return source_metadata[name]
|
69
|
+
else
|
70
|
+
super
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module SemiStatic
|
2
|
+
class Categories < Hash
|
3
|
+
def self.slugize(name)
|
4
|
+
name.to_s.gsub(/ /, '-').downcase.to_sym
|
5
|
+
end
|
6
|
+
|
7
|
+
class Category < Array
|
8
|
+
attr_reader :slug, :name
|
9
|
+
|
10
|
+
def initialize(name, slug)
|
11
|
+
@name, @slug = name, slug
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# def initialize
|
16
|
+
# super { |hash,key| hash[key] = Category.new(key) }
|
17
|
+
# end
|
18
|
+
|
19
|
+
def [](name)
|
20
|
+
slug = Categories.slugize name
|
21
|
+
category = super(slug)
|
22
|
+
if category.nil?
|
23
|
+
category = Category.new name.to_s, slug
|
24
|
+
self[slug] = category
|
25
|
+
end
|
26
|
+
return category
|
27
|
+
end
|
28
|
+
|
29
|
+
def slugs
|
30
|
+
keys.sort { |l,r| l.to_s <=> r.to_s }
|
31
|
+
end
|
32
|
+
|
33
|
+
def names
|
34
|
+
values.collect { |c| c.name }.sort { |l,r| l.to_s <=> r.to_s }
|
35
|
+
end
|
36
|
+
|
37
|
+
def nested_values
|
38
|
+
result = Hash.new { |hash,key| hash[key] = Hash.new }
|
39
|
+
values.each do |item|
|
40
|
+
parent, child = item.slug.to_s.split '/'
|
41
|
+
if child.nil?
|
42
|
+
result[parent.to_sym][nil] = item
|
43
|
+
else
|
44
|
+
result[parent.to_sym][child.to_sym] = item
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
result.collect do |parent_slug,items|
|
49
|
+
parent = items.delete(nil)
|
50
|
+
children = items.values.sort { |l,r| l.name.casecmp r.name }
|
51
|
+
|
52
|
+
class << parent
|
53
|
+
attr_accessor :slug, :children
|
54
|
+
end
|
55
|
+
parent.children = children
|
56
|
+
parent
|
57
|
+
end.sort { |l,r| l.name.casecmp r.name }
|
58
|
+
end
|
59
|
+
|
60
|
+
def each(options={}, &block)
|
61
|
+
list = case options[:order]
|
62
|
+
when :name, nil
|
63
|
+
values.sort { |l,r| l.name.casecmp r.name }
|
64
|
+
when :count
|
65
|
+
values.sort { |l,r| r.count <=> l.count }
|
66
|
+
when :tree
|
67
|
+
nested_values
|
68
|
+
else
|
69
|
+
raise ArgumentError, "Unknown order: #{options[:order]}"
|
70
|
+
end
|
71
|
+
list.each(&block)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'webrick'
|
3
|
+
require 'directory_watcher'
|
4
|
+
|
5
|
+
module SemiStatic
|
6
|
+
class CLI
|
7
|
+
include WEBrick
|
8
|
+
|
9
|
+
attr_accessor :source_dir, :output_dir
|
10
|
+
attr_accessor :clean_first
|
11
|
+
attr_accessor :start_server, :server_port
|
12
|
+
attr_accessor :show_statistics
|
13
|
+
attr_accessor :use_pygments
|
14
|
+
attr_accessor :quick_mode
|
15
|
+
attr_accessor :check_mtime
|
16
|
+
attr_accessor :start_updater
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
self.clean_first = false
|
20
|
+
self.start_server = false
|
21
|
+
self.show_statistics = false
|
22
|
+
self.use_pygments = true
|
23
|
+
self.quick_mode = false
|
24
|
+
self.check_mtime = true
|
25
|
+
self.start_updater = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run
|
29
|
+
cli = CLI.new
|
30
|
+
opts = OptionParser.new do |opts|
|
31
|
+
opts.banner = 'Usage: semi [<options>] [[<source path>] <output path>]'
|
32
|
+
opts.separator ''
|
33
|
+
opts.separator 'Options:'
|
34
|
+
|
35
|
+
opts.on('-s', '--server [PORT]', Integer,
|
36
|
+
'Start a web server (on port PORT)') do |port|
|
37
|
+
cli.start_server = true
|
38
|
+
cli.server_port = port || 4000
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on('-a', '--[no-]auto-update', 'Automatically update generated files') do |a|
|
42
|
+
cli.start_updater = a
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on('-c', '--[no-]clean', 'Clean the output dir first') do |d|
|
46
|
+
cli.clean_first = d
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on('-t', '--[no-]stats', 'Display conversion statistics') do |t|
|
50
|
+
cli.show_statistics = t
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on('-p', '--[no-]pygments', 'Use Pygments for code highlighting') do |p|
|
54
|
+
cli.use_pygments = p
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on('-q', '--[no-]quick-mode', 'Only convert a few posts (for testing)') do |q|
|
58
|
+
cli.quick_mode = q
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.on('-m', '--[no-]mtime', 'Skip files that appear to be up-to-date') do |m|
|
62
|
+
cli.check_mtime = m
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
66
|
+
puts opts
|
67
|
+
exit
|
68
|
+
end
|
69
|
+
|
70
|
+
opts.on_tail('-V', '--version', 'Show version number') do
|
71
|
+
path = File.join File.dirname(__FILE__), '..', '..', 'VERSION.yml'
|
72
|
+
version = File.open(path) { |io| YAML.load io }
|
73
|
+
puts "#{version[:major]}.#{version[:minor]}.#{version[:patch]}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
opts.parse!
|
77
|
+
|
78
|
+
case ARGV.size
|
79
|
+
when 0
|
80
|
+
cli.source_dir = '.'
|
81
|
+
cli.output_dir = 'site'
|
82
|
+
when 1
|
83
|
+
cli.source_dir = '.'
|
84
|
+
cli.output_dir = ARGV[0]
|
85
|
+
when 2
|
86
|
+
cli.source_dir = ARGV[0]
|
87
|
+
cli.output_dir = ARGV[1]
|
88
|
+
else
|
89
|
+
puts 'Invalid options. Run `semi --help` for assistance.'
|
90
|
+
exit 1
|
91
|
+
end
|
92
|
+
|
93
|
+
cli.run
|
94
|
+
end
|
95
|
+
|
96
|
+
def run
|
97
|
+
Pygmentize.enabled = use_pygments
|
98
|
+
SemiStatic::Site.open(source_dir) do |site|
|
99
|
+
site.clean_first = clean_first
|
100
|
+
site.show_statistics = show_statistics
|
101
|
+
site.quick_mode = quick_mode
|
102
|
+
site.check_mtime = check_mtime
|
103
|
+
|
104
|
+
site.output output_dir
|
105
|
+
if start_updater
|
106
|
+
updater = DirectoryWatcher.new(source_dir)
|
107
|
+
updater.interval = 1
|
108
|
+
updater.glob = '{indices,layouts,pages,posts,snippets,stylesheets}/**/*'
|
109
|
+
updater.add_observer do |*args|
|
110
|
+
puts "[#{Time.now}] #{args.length} files changed."
|
111
|
+
site.output output_dir
|
112
|
+
end
|
113
|
+
updater.start
|
114
|
+
sleep 0 unless start_server
|
115
|
+
end
|
116
|
+
if start_server
|
117
|
+
server = HTTPServer.new :DocumentRoot => output_dir,
|
118
|
+
:Port => server_port
|
119
|
+
thread = Thread.new { server.start }
|
120
|
+
trap('INT') { server.shutdown }
|
121
|
+
thread.join
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|