howl 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile.lock +34 -0
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/howl.gemspec +23 -7
- data/lib/howl/converter.rb +33 -0
- data/lib/howl/converters/markdown.rb +14 -0
- data/lib/howl/converters/sass.rb +13 -0
- data/lib/howl/core_ext.rb +13 -0
- data/lib/howl/page.rb +7 -0
- data/lib/howl/plugin.rb +49 -0
- data/lib/howl/post.rb +25 -0
- data/lib/howl/site.rb +39 -0
- data/lib/howl/template.rb +77 -0
- data/lib/howl/view.rb +19 -0
- data/lib/howl.rb +8 -120
- data/test/fixtures/pages/css/modules/colors.scss +3 -0
- data/test/fixtures/pages/css/screen.scss +7 -0
- data/test/fixtures/pages/index.html +10 -0
- data/test/fixtures/posts/markdown_post.md +5 -0
- data/test/howl_test.rb +23 -2
- data/test/teststrap.rb +7 -0
- metadata +48 -12
- data/test/fixtures/site/has_template.html +0 -9
- data/test/fixtures/site/no_yaml.html +0 -1
- data/test/fixtures/site/posts/2010/09/04/first_post.html +0 -11
- data/test/fixtures/site/posts/2010/10/16/no_date.html +0 -1
- data/test/fixtures/site/simple.html +0 -1
data/.gitignore
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
howl (0.3.0)
|
5
|
+
haml
|
6
|
+
hashie
|
7
|
+
mustache
|
8
|
+
rdiscount
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: http://rubygems.org/
|
12
|
+
specs:
|
13
|
+
haml (3.0.17)
|
14
|
+
hashie (0.4.0)
|
15
|
+
mustache (0.11.2)
|
16
|
+
nokogiri (1.4.3.1)
|
17
|
+
rdiscount (1.6.5)
|
18
|
+
riot (0.11.4)
|
19
|
+
rr
|
20
|
+
term-ansicolor
|
21
|
+
rr (1.0.0)
|
22
|
+
term-ansicolor (1.0.5)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
haml
|
29
|
+
hashie
|
30
|
+
howl!
|
31
|
+
mustache
|
32
|
+
nokogiri
|
33
|
+
rdiscount
|
34
|
+
riot (>= 0.11)
|
data/Rakefile
CHANGED
@@ -11,9 +11,11 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/crnixon/howl"
|
12
12
|
gem.authors = ["Clinton R. Nixon"]
|
13
13
|
gem.add_development_dependency "riot", ">= 0.11"
|
14
|
+
gem.add_development_dependency "nokogiri"
|
14
15
|
gem.add_runtime_dependency 'rdiscount'
|
15
16
|
gem.add_runtime_dependency 'mustache'
|
16
17
|
gem.add_runtime_dependency 'hashie'
|
18
|
+
gem.add_runtime_dependency 'haml'
|
17
19
|
end
|
18
20
|
Jeweler::GemcutterTasks.new
|
19
21
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/howl.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{howl}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Clinton R. Nixon"]
|
12
|
-
s.date = %q{2010-10-
|
12
|
+
s.date = %q{2010-10-17}
|
13
13
|
s.description = %q{Howl is a tiny static website/blog generator.}
|
14
14
|
s.email = %q{crnixon@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -19,22 +19,32 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.files = [
|
20
20
|
".gitignore",
|
21
21
|
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
22
23
|
"LICENSE",
|
23
24
|
"README.markdown",
|
24
25
|
"Rakefile",
|
25
26
|
"VERSION",
|
26
27
|
"howl.gemspec",
|
27
28
|
"lib/howl.rb",
|
29
|
+
"lib/howl/converter.rb",
|
30
|
+
"lib/howl/converters/markdown.rb",
|
31
|
+
"lib/howl/converters/sass.rb",
|
32
|
+
"lib/howl/core_ext.rb",
|
33
|
+
"lib/howl/page.rb",
|
34
|
+
"lib/howl/plugin.rb",
|
35
|
+
"lib/howl/post.rb",
|
36
|
+
"lib/howl/site.rb",
|
37
|
+
"lib/howl/template.rb",
|
38
|
+
"lib/howl/view.rb",
|
39
|
+
"test/fixtures/pages/css/modules/colors.scss",
|
40
|
+
"test/fixtures/pages/css/screen.scss",
|
28
41
|
"test/fixtures/pages/has_template.html",
|
42
|
+
"test/fixtures/pages/index.html",
|
29
43
|
"test/fixtures/pages/no_yaml.html",
|
30
44
|
"test/fixtures/pages/simple.html",
|
31
45
|
"test/fixtures/posts/first_post.html",
|
46
|
+
"test/fixtures/posts/markdown_post.md",
|
32
47
|
"test/fixtures/posts/no_date.html",
|
33
|
-
"test/fixtures/site/has_template.html",
|
34
|
-
"test/fixtures/site/no_yaml.html",
|
35
|
-
"test/fixtures/site/posts/2010/09/04/first_post.html",
|
36
|
-
"test/fixtures/site/posts/2010/10/16/no_date.html",
|
37
|
-
"test/fixtures/site/simple.html",
|
38
48
|
"test/fixtures/templates/alt.html",
|
39
49
|
"test/fixtures/templates/default.html",
|
40
50
|
"test/fixtures/templates/post.html",
|
@@ -58,20 +68,26 @@ Gem::Specification.new do |s|
|
|
58
68
|
|
59
69
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
60
70
|
s.add_development_dependency(%q<riot>, [">= 0.11"])
|
71
|
+
s.add_development_dependency(%q<nokogiri>, [">= 0"])
|
61
72
|
s.add_runtime_dependency(%q<rdiscount>, [">= 0"])
|
62
73
|
s.add_runtime_dependency(%q<mustache>, [">= 0"])
|
63
74
|
s.add_runtime_dependency(%q<hashie>, [">= 0"])
|
75
|
+
s.add_runtime_dependency(%q<haml>, [">= 0"])
|
64
76
|
else
|
65
77
|
s.add_dependency(%q<riot>, [">= 0.11"])
|
78
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
66
79
|
s.add_dependency(%q<rdiscount>, [">= 0"])
|
67
80
|
s.add_dependency(%q<mustache>, [">= 0"])
|
68
81
|
s.add_dependency(%q<hashie>, [">= 0"])
|
82
|
+
s.add_dependency(%q<haml>, [">= 0"])
|
69
83
|
end
|
70
84
|
else
|
71
85
|
s.add_dependency(%q<riot>, [">= 0.11"])
|
86
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
72
87
|
s.add_dependency(%q<rdiscount>, [">= 0"])
|
73
88
|
s.add_dependency(%q<mustache>, [">= 0"])
|
74
89
|
s.add_dependency(%q<hashie>, [">= 0"])
|
90
|
+
s.add_dependency(%q<haml>, [">= 0"])
|
75
91
|
end
|
76
92
|
end
|
77
93
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Howl
|
2
|
+
class Converter < Plugin
|
3
|
+
def self.converts(hash = nil)
|
4
|
+
@converts ||= {}
|
5
|
+
if hash
|
6
|
+
@converts.merge!(hash)
|
7
|
+
else
|
8
|
+
@converts
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.matches?(ext)
|
13
|
+
@converts.keys.any? do |matcher|
|
14
|
+
matcher.match(ext)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :extension
|
19
|
+
|
20
|
+
def initialize(template)
|
21
|
+
@template = template
|
22
|
+
ext_regexp = self.class.converts.find { |conversion| conversion[0].match(@template.extension) }
|
23
|
+
@extension = @template.extension.gsub(ext_regexp[0], ext_regexp[1])
|
24
|
+
end
|
25
|
+
|
26
|
+
def convert(text)
|
27
|
+
text
|
28
|
+
end
|
29
|
+
|
30
|
+
priority :lowest
|
31
|
+
converts /\..+$/ => '\0'
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rdiscount'
|
2
|
+
|
3
|
+
module Howl
|
4
|
+
class MarkdownConverter < Converter
|
5
|
+
converts ".md" => ".html"
|
6
|
+
converts ".mdown" => ".html"
|
7
|
+
converts ".markdown" => ".html"
|
8
|
+
priority :highest
|
9
|
+
|
10
|
+
def convert(text)
|
11
|
+
RDiscount.new(text).to_html
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'sass'
|
2
|
+
|
3
|
+
module Howl
|
4
|
+
class SassConverter < Converter
|
5
|
+
converts /\.s[ac]ss/ => '.css'
|
6
|
+
|
7
|
+
def convert(text)
|
8
|
+
sass_args = { :syntax => @template.extension.drop(1).to_sym,
|
9
|
+
:load_paths => [@template.path.dirname] }
|
10
|
+
Sass::Engine.new(text, sass_args).render
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
def drop(num)
|
3
|
+
self.dup.split(//).drop(num).join
|
4
|
+
end
|
5
|
+
|
6
|
+
def slugify
|
7
|
+
string = self.dup
|
8
|
+
string.gsub!(/[^\x00-\x7F]+/, '') # Remove anything non-ASCII entirely (e.g. diacritics).
|
9
|
+
string.gsub!(/[^a-z0-9\-_]+/i, '-')
|
10
|
+
string.downcase
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
data/lib/howl/page.rb
ADDED
data/lib/howl/plugin.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Adapted from Jekyll's Plugin class.
|
2
|
+
|
3
|
+
module Howl
|
4
|
+
class Plugin
|
5
|
+
PRIORITIES = { :lowest => -100,
|
6
|
+
:low => -10,
|
7
|
+
:normal => 0,
|
8
|
+
:high => 10,
|
9
|
+
:highest => 100 }
|
10
|
+
|
11
|
+
# Install a hook so that subclasses are recorded. This method is only
|
12
|
+
# ever called by Ruby itself.
|
13
|
+
#
|
14
|
+
# base - The Class subclass.
|
15
|
+
#
|
16
|
+
# Returns nothing.
|
17
|
+
def self.inherited(base)
|
18
|
+
subclasses << base
|
19
|
+
subclasses.sort!
|
20
|
+
end
|
21
|
+
|
22
|
+
# The list of Classes that have been subclassed.
|
23
|
+
#
|
24
|
+
# Returns an Array of Class objects.
|
25
|
+
def self.subclasses
|
26
|
+
@subclasses ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get or set the priority of this plugin. When called without an
|
30
|
+
# argument it returns the priority. When an argument is given, it will
|
31
|
+
# set the priority.
|
32
|
+
#
|
33
|
+
# priority - The Symbol priority (default: nil). Valid options are:
|
34
|
+
# :lowest, :low, :normal, :high, :highest
|
35
|
+
#
|
36
|
+
# Returns the Symbol priority.
|
37
|
+
def self.priority(priority = nil)
|
38
|
+
if priority && PRIORITIES.has_key?(priority)
|
39
|
+
@priority = priority
|
40
|
+
end
|
41
|
+
@priority || :normal
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.<=>(other)
|
45
|
+
PRIORITIES[other.priority] <=> PRIORITIES[self.priority]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/lib/howl/post.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Howl
|
2
|
+
class Post < Template
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
def date
|
6
|
+
view.date? ? Time.parse(view.date) : File.mtime(path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def <=>(other)
|
10
|
+
self.date <=> other.date
|
11
|
+
end
|
12
|
+
|
13
|
+
def output_path
|
14
|
+
site.path("site/posts") + date.strftime("%Y/%m/%d") + output_filename
|
15
|
+
end
|
16
|
+
|
17
|
+
def title
|
18
|
+
view.title || path.basename(extension).to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def dom_id
|
22
|
+
title.slugify
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/howl/site.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Howl
|
2
|
+
class Site
|
3
|
+
attr_accessor :root
|
4
|
+
|
5
|
+
def initialize(root)
|
6
|
+
@root = Pathname.new(root)
|
7
|
+
end
|
8
|
+
|
9
|
+
def path(path)
|
10
|
+
root + path
|
11
|
+
end
|
12
|
+
|
13
|
+
def pages
|
14
|
+
@pages ||= Dir[path "pages/**/*.*"].map { |path| Page.new(path, self) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def posts
|
18
|
+
@posts ||= Dir[path "posts/**/*.*"].map { |path| Post.new(path, self) }.sort
|
19
|
+
end
|
20
|
+
|
21
|
+
def templates
|
22
|
+
@templates ||= Hash[Dir[root + "templates/*"].map { |path|
|
23
|
+
[Pathname.new(path).relative_path_from(path "templates").to_s,
|
24
|
+
Template.new(path, self)]
|
25
|
+
}]
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_to_disk
|
29
|
+
FileUtils.rm_r(path "site") if File.exist?(path "site")
|
30
|
+
#raise (pages + posts).map(&:class).inspect
|
31
|
+
(pages + posts).each do |page|
|
32
|
+
FileUtils.makedirs(page.output_path.dirname)
|
33
|
+
page.output_path.open("w") do |fh|
|
34
|
+
fh.write page.render
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Howl
|
2
|
+
class Template
|
3
|
+
attr_accessor :view, :content, :site, :path, :extension
|
4
|
+
|
5
|
+
def initialize(path, site)
|
6
|
+
@site = site
|
7
|
+
@path = Pathname.new(path)
|
8
|
+
@extension = @path.extname
|
9
|
+
load_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
self.path == other.path && self.class == other.class
|
14
|
+
end
|
15
|
+
|
16
|
+
def output_filename
|
17
|
+
path.basename.sub(/#{extension}$/, converter.extension)
|
18
|
+
end
|
19
|
+
|
20
|
+
def converter
|
21
|
+
unless @converter
|
22
|
+
converter_class = Converter.subclasses.find do |converter|
|
23
|
+
converter.matches? @extension
|
24
|
+
end
|
25
|
+
converter_class ||= Converter
|
26
|
+
|
27
|
+
@converter = converter_class.new(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
@converter
|
31
|
+
end
|
32
|
+
|
33
|
+
def render(render_view = View.new)
|
34
|
+
render_view.merge!(@view)
|
35
|
+
rendered = converter.convert(Mustache.render(@content, render_view))
|
36
|
+
template = render_view.delete("template")
|
37
|
+
|
38
|
+
if template
|
39
|
+
if @site.templates[template + @extension]
|
40
|
+
rendered = @site.templates[template + @extension].render(
|
41
|
+
render_view.merge("content" => rendered))
|
42
|
+
else
|
43
|
+
puts "Warning: Template #{template + @extension} does not exist in file #{path}"
|
44
|
+
rendered
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
rendered
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def load_file
|
54
|
+
content = @path.read
|
55
|
+
view, content = content.split("\n\n", 2)
|
56
|
+
|
57
|
+
if test_for_yaml(view)
|
58
|
+
@content = content
|
59
|
+
view = YAML.load(view)
|
60
|
+
else
|
61
|
+
@content = "#{view}\n\n#{content}".strip
|
62
|
+
view = {}
|
63
|
+
end
|
64
|
+
|
65
|
+
@view = View.new(view.merge(:site => site))
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_for_yaml(view)
|
69
|
+
begin
|
70
|
+
view = YAML.load(view)
|
71
|
+
view.is_a?(Hash)
|
72
|
+
rescue ArgumentError
|
73
|
+
false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/howl/view.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
module Howl
|
4
|
+
class View < Hashie::Mash
|
5
|
+
def has_key?(key)
|
6
|
+
key?(key) || respond_to?(key)
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
super || (respond_to?(key) && send(key))
|
11
|
+
end
|
12
|
+
|
13
|
+
def posts
|
14
|
+
if site? && site.respond_to?(:posts)
|
15
|
+
site.posts
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/howl.rb
CHANGED
@@ -1,131 +1,19 @@
|
|
1
1
|
require 'yaml'
|
2
|
-
require 'rdiscount'
|
3
2
|
require 'mustache'
|
4
|
-
require 'hashie'
|
5
3
|
require 'pathname'
|
6
4
|
require 'fileutils'
|
7
5
|
require 'time'
|
8
6
|
|
9
7
|
$:.unshift File.dirname(__FILE__)
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def initialize(root)
|
16
|
-
@root = Pathname.new(root)
|
17
|
-
end
|
18
|
-
|
19
|
-
def path(path)
|
20
|
-
root + path
|
21
|
-
end
|
22
|
-
|
23
|
-
def pages
|
24
|
-
@pages ||= Dir[path "pages/*"].map { |path| Page.new(path, self) }
|
25
|
-
end
|
26
|
-
|
27
|
-
def posts
|
28
|
-
@posts ||= Dir[path "posts/*"].map { |path| Post.new(path, self) }.sort
|
29
|
-
end
|
30
|
-
|
31
|
-
def templates
|
32
|
-
@templates ||= Hash[Dir[root + "templates/*"].map { |path|
|
33
|
-
[Pathname.new(path).relative_path_from(path "templates").to_s,
|
34
|
-
Template.new(path, self)]
|
35
|
-
}]
|
36
|
-
end
|
37
|
-
|
38
|
-
def write_to_disk
|
39
|
-
FileUtils.rm_r(path "site") if File.exist?(path "site")
|
40
|
-
#raise (pages + posts).map(&:class).inspect
|
41
|
-
(pages + posts).each do |page|
|
42
|
-
FileUtils.makedirs(page.output_path.dirname)
|
43
|
-
page.output_path.open("w") do |fh|
|
44
|
-
fh.write page.render
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
class View < Hashie::Mash
|
9
|
+
def require_all(path)
|
10
|
+
Dir[File.join(File.dirname(__FILE__), path, '*.rb')].each do |f|
|
11
|
+
require f
|
51
12
|
end
|
13
|
+
end
|
52
14
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def initialize(path, site)
|
57
|
-
@site = site
|
58
|
-
@path = Pathname.new(path)
|
59
|
-
@extension = @path.extname
|
60
|
-
load_file
|
61
|
-
end
|
62
|
-
|
63
|
-
def ==(other)
|
64
|
-
self.path == other.path && self.class == other.class
|
65
|
-
end
|
66
|
-
|
67
|
-
def render(render_view = {})
|
68
|
-
render_view.merge!(@view)
|
69
|
-
rendered = Mustache.render(@content, render_view)
|
70
|
-
template = render_view.delete("template")
|
71
|
-
if template
|
72
|
-
begin
|
73
|
-
rendered = @site.templates[template + @extension].render(render_view.merge("content" => rendered))
|
74
|
-
rescue NoMethodError => ex
|
75
|
-
puts "Warning: Template #{template + @extension} does not exist in file #{path}"
|
76
|
-
rendered
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
rendered
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
def load_file
|
86
|
-
content = @path.read
|
87
|
-
view, content = content.split("\n\n", 2)
|
88
|
-
|
89
|
-
if test_for_yaml(view)
|
90
|
-
@content = content
|
91
|
-
view = YAML.load(view)
|
92
|
-
else
|
93
|
-
@content = "#{view}\n\n#{content}".strip
|
94
|
-
view = {}
|
95
|
-
end
|
96
|
-
|
97
|
-
@view = View.new(view.merge(:site => site))
|
98
|
-
end
|
99
|
-
|
100
|
-
def test_for_yaml(view)
|
101
|
-
begin
|
102
|
-
view = YAML.load(view)
|
103
|
-
view.is_a?(Hash)
|
104
|
-
rescue ArgumentError
|
105
|
-
false
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
class Page < Template
|
111
|
-
def output_path
|
112
|
-
site.path("site") + path.relative_path_from(site.path "pages")
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
class Post < Template
|
117
|
-
include Comparable
|
118
|
-
|
119
|
-
def date
|
120
|
-
view.date? ? Time.parse(view.date) : File.mtime(path)
|
121
|
-
end
|
122
|
-
|
123
|
-
def output_path
|
124
|
-
site.path("site/posts") + date.strftime("%Y/%m/%d") + path.basename
|
125
|
-
end
|
126
|
-
|
127
|
-
def <=>(other)
|
128
|
-
self.date <=> other.date
|
129
|
-
end
|
130
|
-
end
|
15
|
+
%w(core_ext plugin converter site template page post view).each do |file|
|
16
|
+
require "howl/#{file}"
|
131
17
|
end
|
18
|
+
|
19
|
+
require_all "howl/converters"
|
data/test/howl_test.rb
CHANGED
@@ -5,7 +5,7 @@ context "Site" do
|
|
5
5
|
setup { @site = Site.new(fixture_path) }
|
6
6
|
|
7
7
|
should("find all pages") {
|
8
|
-
topic.pages == Dir[fixture_path("pages
|
8
|
+
topic.pages == Dir[fixture_path("pages/**/*.*")].map { |path| Page.new(path, topic) }
|
9
9
|
}
|
10
10
|
|
11
11
|
should("write out all pages") {
|
@@ -18,7 +18,9 @@ context "Site" do
|
|
18
18
|
should("write out all posts") {
|
19
19
|
topic.write_to_disk
|
20
20
|
topic.posts.map { |post|
|
21
|
-
Dir[topic.path("site/posts") + "
|
21
|
+
Dir[topic.path("site/posts") + "**/*.*"].map { |path|
|
22
|
+
File.basename(path, File.extname(path))
|
23
|
+
}.include?(post.path.basename(post.extension).to_s)
|
22
24
|
}.all?
|
23
25
|
}
|
24
26
|
|
@@ -60,6 +62,17 @@ context "Site" do
|
|
60
62
|
</html>
|
61
63
|
].clean
|
62
64
|
end
|
65
|
+
|
66
|
+
context "index.html" do
|
67
|
+
setup { Page.new(fixture_path("pages/index.html"), @site) }
|
68
|
+
|
69
|
+
should "show all posts" do
|
70
|
+
doc = Nokogiri.parse(topic.render)
|
71
|
+
@site.posts.map { |post|
|
72
|
+
doc.search("div##{post.dom_id}").empty?
|
73
|
+
}.none?
|
74
|
+
end
|
75
|
+
end
|
63
76
|
end
|
64
77
|
|
65
78
|
context "Post" do
|
@@ -79,5 +92,13 @@ context "Site" do
|
|
79
92
|
asserts("date is equal to file's mtime") { topic.date == File.mtime(topic.path) }
|
80
93
|
end
|
81
94
|
end
|
95
|
+
|
96
|
+
context "A Post in Markdown" do
|
97
|
+
setup { Post.new(fixture_path("posts/markdown_post.md"), @site) }
|
98
|
+
|
99
|
+
should "convert to HTML" do
|
100
|
+
topic.render == RDiscount.new(topic.content).to_html
|
101
|
+
end
|
102
|
+
end
|
82
103
|
end
|
83
104
|
|
data/test/teststrap.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'riot'
|
3
|
+
require 'nokogiri'
|
3
4
|
|
4
5
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
6
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
@@ -14,3 +15,9 @@ class String
|
|
14
15
|
self.strip.gsub(/\n+/, "\n")
|
15
16
|
end
|
16
17
|
end
|
18
|
+
|
19
|
+
class Mustache
|
20
|
+
def self.raise_on_context_miss?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 3
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Clinton R. Nixon
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-10-
|
17
|
+
date: 2010-10-17 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
type: :development
|
33
33
|
version_requirements: *id001
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
35
|
+
name: nokogiri
|
36
36
|
prerelease: false
|
37
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
38
38
|
none: false
|
@@ -42,10 +42,10 @@ dependencies:
|
|
42
42
|
segments:
|
43
43
|
- 0
|
44
44
|
version: "0"
|
45
|
-
type: :
|
45
|
+
type: :development
|
46
46
|
version_requirements: *id002
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: rdiscount
|
49
49
|
prerelease: false
|
50
50
|
requirement: &id003 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
type: :runtime
|
59
59
|
version_requirements: *id003
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
|
-
name:
|
61
|
+
name: mustache
|
62
62
|
prerelease: false
|
63
63
|
requirement: &id004 !ruby/object:Gem::Requirement
|
64
64
|
none: false
|
@@ -70,6 +70,32 @@ dependencies:
|
|
70
70
|
version: "0"
|
71
71
|
type: :runtime
|
72
72
|
version_requirements: *id004
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: hashie
|
75
|
+
prerelease: false
|
76
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
type: :runtime
|
85
|
+
version_requirements: *id005
|
86
|
+
- !ruby/object:Gem::Dependency
|
87
|
+
name: haml
|
88
|
+
prerelease: false
|
89
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
type: :runtime
|
98
|
+
version_requirements: *id006
|
73
99
|
description: Howl is a tiny static website/blog generator.
|
74
100
|
email: crnixon@gmail.com
|
75
101
|
executables: []
|
@@ -82,22 +108,32 @@ extra_rdoc_files:
|
|
82
108
|
files:
|
83
109
|
- .gitignore
|
84
110
|
- Gemfile
|
111
|
+
- Gemfile.lock
|
85
112
|
- LICENSE
|
86
113
|
- README.markdown
|
87
114
|
- Rakefile
|
88
115
|
- VERSION
|
89
116
|
- howl.gemspec
|
90
117
|
- lib/howl.rb
|
118
|
+
- lib/howl/converter.rb
|
119
|
+
- lib/howl/converters/markdown.rb
|
120
|
+
- lib/howl/converters/sass.rb
|
121
|
+
- lib/howl/core_ext.rb
|
122
|
+
- lib/howl/page.rb
|
123
|
+
- lib/howl/plugin.rb
|
124
|
+
- lib/howl/post.rb
|
125
|
+
- lib/howl/site.rb
|
126
|
+
- lib/howl/template.rb
|
127
|
+
- lib/howl/view.rb
|
128
|
+
- test/fixtures/pages/css/modules/colors.scss
|
129
|
+
- test/fixtures/pages/css/screen.scss
|
91
130
|
- test/fixtures/pages/has_template.html
|
131
|
+
- test/fixtures/pages/index.html
|
92
132
|
- test/fixtures/pages/no_yaml.html
|
93
133
|
- test/fixtures/pages/simple.html
|
94
134
|
- test/fixtures/posts/first_post.html
|
135
|
+
- test/fixtures/posts/markdown_post.md
|
95
136
|
- test/fixtures/posts/no_date.html
|
96
|
-
- test/fixtures/site/has_template.html
|
97
|
-
- test/fixtures/site/no_yaml.html
|
98
|
-
- test/fixtures/site/posts/2010/09/04/first_post.html
|
99
|
-
- test/fixtures/site/posts/2010/10/16/no_date.html
|
100
|
-
- test/fixtures/site/simple.html
|
101
137
|
- test/fixtures/templates/alt.html
|
102
138
|
- test/fixtures/templates/default.html
|
103
139
|
- test/fixtures/templates/post.html
|
@@ -1 +0,0 @@
|
|
1
|
-
This page has no YAML front-matter.
|
@@ -1 +0,0 @@
|
|
1
|
-
This post has no date in its YAML front-matter.
|
@@ -1 +0,0 @@
|
|
1
|
-
<h1>This is a simple page</h1>
|