pekky 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +21 -0
- data/README +47 -0
- data/Thorfile +39 -0
- data/bin/pekky +65 -0
- data/lib/pekky/builder.rb +60 -0
- data/lib/pekky/console.rb +22 -0
- data/lib/pekky/context.rb +153 -0
- data/lib/pekky/pages.rb +104 -0
- data/lib/pekky/server.rb +25 -0
- data/lib/pekky/site_config.rb +56 -0
- data/lib/pekky/templates/helpers.rb +3 -0
- data/lib/pekky/templates/site.rb +3 -0
- data/lib/pekky/tree.rb +36 -0
- data/lib/pekky.rb +96 -0
- metadata +85 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 Luke Matthew Sutton
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
######## ######## ## ## ## ## ## ## ####
|
3
|
+
## ## ## ## ## ## ## ## ## ####
|
4
|
+
## ## ## ## ## ## ## #### ####
|
5
|
+
######## ###### ##### ##### ## ##
|
6
|
+
## ## ## ## ## ## ##
|
7
|
+
## ## ## ## ## ## ## ####
|
8
|
+
## ######## ## ## ## ## ## ####
|
9
|
+
|
10
|
+
A static site builder. It will punch your HTML... with love.
|
11
|
+
|
12
|
+
BUT WHY?!
|
13
|
+
Look, I know there are a bajillion site generators already, but this one is
|
14
|
+
mine and it does what I want. For starters, it's simple and hackable. The
|
15
|
+
actual codebase is quite small. Barring some mis-organisation on my part it
|
16
|
+
should be readable enough. Secondly, it abandons the idea of magic and instead
|
17
|
+
asks users to be explicit about what they are generating. This allows for
|
18
|
+
reuse of content across a site and other clever tricks.
|
19
|
+
|
20
|
+
|
21
|
+
FEATURES BO!
|
22
|
+
* Explicitly link content to templates and output paths, allowing reuse
|
23
|
+
* Use any templating language supported by Tilt, but see caveats below
|
24
|
+
* Generate pages from any source -- CSV files, DB contents, web API calls
|
25
|
+
|
26
|
+
|
27
|
+
QUICK START -- assuming Pekky is installed
|
28
|
+
|
29
|
+
$ pekky --generate word_up
|
30
|
+
$ cd word_up
|
31
|
+
$ pekky --server
|
32
|
+
|
33
|
+
See pekky --help for more info
|
34
|
+
|
35
|
+
|
36
|
+
TODO
|
37
|
+
* Get specs up to speed
|
38
|
+
* Write a tutorial
|
39
|
+
* Gem this motherbitch up
|
40
|
+
|
41
|
+
|
42
|
+
CAVEATS
|
43
|
+
* Not actually finished soz
|
44
|
+
* No Windows support. If someone wants to build it that’s cool, but I’m lazy.
|
45
|
+
* Limited Mustache support. It won’t play with arbitrary contexts.
|
46
|
+
* May potentially be slow
|
47
|
+
|
data/Thorfile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
class App < Thor
|
2
|
+
desc "docs", "generate Docco documentation"
|
3
|
+
def docs
|
4
|
+
if File.exists?('docs')
|
5
|
+
system('rm -rf doc/*')
|
6
|
+
else
|
7
|
+
system('mkdir docs')
|
8
|
+
end
|
9
|
+
system('rocco lib/pekky.rb -o docs')
|
10
|
+
system('rocco lib/pekky/*.rb -o docs')
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "gem", "build the gemfile"
|
14
|
+
def gem
|
15
|
+
system("gem build pekky.gemspec")
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "install", "build the gem and install it"
|
19
|
+
def install
|
20
|
+
gem
|
21
|
+
f = Dir["pekky-*.gem"][0]
|
22
|
+
system("gem install #{f}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Spec < Thor
|
27
|
+
desc "all", "runs all of the specs for Pekky"
|
28
|
+
def all
|
29
|
+
path = File.expand_path(File.dirname(__FILE__)) + '/'
|
30
|
+
Dir["spec/*_spec.rb"].each do |s|
|
31
|
+
require path + s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "single SPEC_PREFIX", "runs the specified spec file"
|
36
|
+
def single(prefix)
|
37
|
+
require "spec/#{prefix}_spec"
|
38
|
+
end
|
39
|
+
end
|
data/bin/pekky
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
lib = File.join(File.expand_path(File.dirname(__FILE__)), '../lib/pekky.rb')
|
7
|
+
if File.exists?(lib)
|
8
|
+
require lib
|
9
|
+
else
|
10
|
+
require 'pekky'
|
11
|
+
end
|
12
|
+
|
13
|
+
banner = %q{
|
14
|
+
|
15
|
+
######## ######## ## ## ## ## ## ## ####
|
16
|
+
## ## ## ## ## ## ## ## ## ####
|
17
|
+
## ## ## ## ## ## ## #### ####
|
18
|
+
######## ###### ##### ##### ## ##
|
19
|
+
## ## ## ## ## ## ##
|
20
|
+
## ## ## ## ## ## ## ####
|
21
|
+
## ######## ## ## ## ## ## ####
|
22
|
+
|
23
|
+
A static site builder. It will punch your HTML... with love.
|
24
|
+
|
25
|
+
}
|
26
|
+
|
27
|
+
options = OptionParser.new do |o|
|
28
|
+
o.banner = banner
|
29
|
+
|
30
|
+
o.on("-s", "--server [PORT]", "starts the development server") do |port|
|
31
|
+
Pekky.server(port)
|
32
|
+
end
|
33
|
+
|
34
|
+
o.on("-o", "--output", "outputs your site") do
|
35
|
+
Pekky.load
|
36
|
+
Pekky.build
|
37
|
+
puts "Site files output into ./output"
|
38
|
+
end
|
39
|
+
|
40
|
+
o.on("-g", "--generate [NAME]", "stubs out the files and folders needed for development") do |name|
|
41
|
+
Pekky.generate(name)
|
42
|
+
puts "New site generated in: #{name}"
|
43
|
+
end
|
44
|
+
|
45
|
+
o.on('-v', '--version', 'outputs the current version of Pekky') do
|
46
|
+
puts "Pekky #{Pekky::VERSION} (#{Pekky::VERSION_NAME})"
|
47
|
+
end
|
48
|
+
|
49
|
+
o.on('-c', '--console', 'starts an irb session inside of Pekky') do
|
50
|
+
Pekky.console
|
51
|
+
end
|
52
|
+
|
53
|
+
o.on('-e', '--export', 'exports the site for deployment -- this prefixes paths correctly') do
|
54
|
+
Pekky.load
|
55
|
+
Pekky.export
|
56
|
+
puts "Site files output into ./output"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if ARGV.size == 0
|
61
|
+
puts "PEKKY!\n type --help for a list of available commands"
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
options.parse!
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Pekky
|
2
|
+
module Builder
|
3
|
+
def self.build
|
4
|
+
check_for_output_dir
|
5
|
+
copy_static_assets
|
6
|
+
|
7
|
+
@pages = []
|
8
|
+
# This has to be done in three loops so we can collect the meta data and
|
9
|
+
# content for each page first, assemble them into a tree, then render.
|
10
|
+
#
|
11
|
+
# This ensures that every page will have complete access to the entire
|
12
|
+
# site and it's content as it is being rendered, calling helpers etc.
|
13
|
+
pages = SiteConfig.page_configs.collect {|p| p.prepare}
|
14
|
+
pages.flatten!
|
15
|
+
Tree.add(pages)
|
16
|
+
pages.each {|p| p.render}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.build!
|
20
|
+
clear_output_dir
|
21
|
+
Pekky.build
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.clear_output_dir
|
25
|
+
system("rm -rf '#{SiteConfig[:output_dir]}/*'") if File.exists?(SiteConfig[:output_dir])
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.check_for_output_dir
|
29
|
+
FileUtils.mkdir(SiteConfig[:output_dir]) unless File.exists?(SiteConfig[:output_dir])
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.directory(path)
|
33
|
+
unless File.directory?(File.join(SiteConfig[:output_dir], path))
|
34
|
+
parts = path.split("/")
|
35
|
+
fragment = SiteConfig[:output_dir].clone
|
36
|
+
while parts.length > 0
|
37
|
+
fragment = File.join(fragment, parts.shift)
|
38
|
+
FileUtils.mkdir(fragment) unless File.directory?(fragment)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.copy_static_assets
|
44
|
+
system("cp -fR '#{SiteConfig[:public_dir]}/.' '#{SiteConfig[:output_dir]}/.'")
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.generate(destination)
|
48
|
+
destination ||= Dir.pwd
|
49
|
+
FileUtils.mkdir(destination) unless File.exists?(destination)
|
50
|
+
dirs = %w(content views public public/stylesheets public/javascripts public/images)
|
51
|
+
dirs.each do |d|
|
52
|
+
FileUtils.mkdir(File.join(destination, d))
|
53
|
+
end
|
54
|
+
|
55
|
+
template_dir = File.expand_path("#{File.dirname(__FILE__)}/templates")
|
56
|
+
system("cp '#{template_dir}/site.rb' '#{destination}'")
|
57
|
+
system("cp '#{template_dir}/helpers.rb' '#{destination}'")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Pekky
|
2
|
+
module Console
|
3
|
+
def self.start
|
4
|
+
require 'irb'
|
5
|
+
|
6
|
+
Pekky.load
|
7
|
+
Pekky.build
|
8
|
+
puts %{
|
9
|
+
|
10
|
+
Welcome to the Pekky console
|
11
|
+
Some useful methods:
|
12
|
+
|
13
|
+
Pekky.pages An array of the page instances in the site
|
14
|
+
Pekky.build Rebuild the site
|
15
|
+
Pekky.build! Destructive rebuild -- removes all previously generated files
|
16
|
+
|
17
|
+
}
|
18
|
+
|
19
|
+
IRB.start(__FILE__)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Pekky
|
2
|
+
class Context
|
3
|
+
attr_writer :view_output, :is_layout
|
4
|
+
|
5
|
+
def initialize(page)
|
6
|
+
@page = page
|
7
|
+
@is_layout = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def config
|
11
|
+
SiteConfig
|
12
|
+
end
|
13
|
+
|
14
|
+
def text(markup, val)
|
15
|
+
case markup
|
16
|
+
when :markdown then markdown(val)
|
17
|
+
when :textile then markdown(textile)
|
18
|
+
else val
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def markdown(val)
|
23
|
+
unless Kernel.const_defined? :Markdown
|
24
|
+
require 'rdiscount'
|
25
|
+
end
|
26
|
+
|
27
|
+
Markdown.new(val, :smart).to_html
|
28
|
+
end
|
29
|
+
|
30
|
+
def textile(val)
|
31
|
+
unless Kernel.const_defined? :RedCloth
|
32
|
+
require 'RedCloth'
|
33
|
+
end
|
34
|
+
|
35
|
+
RedCloth.new(val).to_html
|
36
|
+
end
|
37
|
+
|
38
|
+
def partial(path)
|
39
|
+
file_name = "#{path}.html.#{SiteConfig[:templating]}"
|
40
|
+
path = File.join(SiteConfig[:partials_dir], file_name)
|
41
|
+
Tilt.new(path).render(self)
|
42
|
+
end
|
43
|
+
|
44
|
+
def view
|
45
|
+
if @is_layout
|
46
|
+
@view_output
|
47
|
+
else
|
48
|
+
tag('p', "You can't call #view within a view! This will break things. Tsk.")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def stylesheet(name, opts = {})
|
53
|
+
opts['media'] ||= 'screen'
|
54
|
+
opts['rel'] ||= 'stylesheet'
|
55
|
+
opts['type'] = 'text/css'
|
56
|
+
opts['href'] = "#{qualify_path("#{SiteConfig[:stylesheets_path]}/#{name}")}.css"
|
57
|
+
|
58
|
+
self_closing_tag('link', opts)
|
59
|
+
end
|
60
|
+
|
61
|
+
def javascript(name)
|
62
|
+
tag('script', '', :src => "#{qualify_path("#{SiteConfig[:javascripts_path]}/#{name}")}.js", :type => 'text/javascript')
|
63
|
+
end
|
64
|
+
|
65
|
+
def image(path, opts = {})
|
66
|
+
opts['src'] = qualify_path("#{SiteConfig[:images_path]}/#{path}")
|
67
|
+
self_closing_tag('img', opts)
|
68
|
+
end
|
69
|
+
|
70
|
+
def link(text, url, opts = {})
|
71
|
+
opts['href'] = qualify_path(url)
|
72
|
+
tag('a', text, opts)
|
73
|
+
end
|
74
|
+
|
75
|
+
def tag(type, child, opts = nil)
|
76
|
+
if opts
|
77
|
+
"<#{type} #{attrs(opts)}>#{child}</#{type}>"
|
78
|
+
else
|
79
|
+
"<#{type}>#{child}</#{type}>"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self_closing_tag(type, opts = nil)
|
84
|
+
if opts
|
85
|
+
"<#{type} #{attrs(opts)}/>"
|
86
|
+
else
|
87
|
+
"<#{type}>#{contents}/>"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def attrs(opts)
|
92
|
+
out = opts.inject([]) do |a, o|
|
93
|
+
a << "#{o[0]}=\"#{o[1]}\""
|
94
|
+
a
|
95
|
+
end
|
96
|
+
|
97
|
+
out.join(" ").chomp
|
98
|
+
end
|
99
|
+
|
100
|
+
def qualify_path(path)
|
101
|
+
if Pekky.exporting? and SiteConfig[:path_prefix]
|
102
|
+
SiteConfig[:path_prefix] + path
|
103
|
+
else
|
104
|
+
path
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def nav
|
109
|
+
Pekky.tree.pages.reject {|p| p.hidden? }
|
110
|
+
end
|
111
|
+
|
112
|
+
def pages
|
113
|
+
Pekky.tree.pages
|
114
|
+
end
|
115
|
+
|
116
|
+
def content
|
117
|
+
@page.content
|
118
|
+
end
|
119
|
+
|
120
|
+
def path
|
121
|
+
qualify_path(@page.path)
|
122
|
+
end
|
123
|
+
|
124
|
+
def children
|
125
|
+
@page.children
|
126
|
+
end
|
127
|
+
|
128
|
+
def ancestors
|
129
|
+
collect_ancestors(@page)
|
130
|
+
end
|
131
|
+
|
132
|
+
def parent
|
133
|
+
@page.parent
|
134
|
+
end
|
135
|
+
|
136
|
+
def child?
|
137
|
+
@page.child?
|
138
|
+
end
|
139
|
+
|
140
|
+
def hidden?
|
141
|
+
@page.hidden?
|
142
|
+
end
|
143
|
+
|
144
|
+
def collect_ancestors(page, ancestors = [])
|
145
|
+
if page.parent
|
146
|
+
collect_ancestors(page.parent, ancestors)
|
147
|
+
ancestors.unshift(page.parent)
|
148
|
+
else
|
149
|
+
ancestors
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/pekky/pages.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Pekky
|
2
|
+
class PageConfig
|
3
|
+
def initialize(path, content, opts = {})
|
4
|
+
@path = path
|
5
|
+
@content = content
|
6
|
+
@opts = opts
|
7
|
+
end
|
8
|
+
|
9
|
+
def prepare
|
10
|
+
Page.new(@path, @content, @opts)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Page
|
15
|
+
attr_reader :path, :children, :content, :opts, :file_name
|
16
|
+
attr_accessor :parent
|
17
|
+
|
18
|
+
def initialize(path, content, opts)
|
19
|
+
@path = path
|
20
|
+
@opts = opts
|
21
|
+
|
22
|
+
@content = if content.is_a? String
|
23
|
+
content_path = File.join(SiteConfig[:content_dir], "#{content}.yml")
|
24
|
+
YAML.load_file(content_path)
|
25
|
+
else
|
26
|
+
content
|
27
|
+
end
|
28
|
+
|
29
|
+
@file_name = "index.#{opts[:ext] || 'html'}"
|
30
|
+
|
31
|
+
@view = view(:view, opts)
|
32
|
+
@layout = view(:layout, opts)
|
33
|
+
|
34
|
+
@children = []
|
35
|
+
end
|
36
|
+
|
37
|
+
def ==(other)
|
38
|
+
path == other.path
|
39
|
+
end
|
40
|
+
|
41
|
+
def hidden?
|
42
|
+
!!opts[:hidden]
|
43
|
+
end
|
44
|
+
|
45
|
+
def child?
|
46
|
+
@path.index("/") > 0
|
47
|
+
end
|
48
|
+
|
49
|
+
def render
|
50
|
+
Builder.directory(@path)
|
51
|
+
|
52
|
+
context = Context.new(self)
|
53
|
+
view_output = @view.render(Context.new(self))
|
54
|
+
context.view_output = view_output
|
55
|
+
context.is_layout = true
|
56
|
+
|
57
|
+
File.open(File.join(SiteConfig[:output_dir], @path, @file_name), 'w') do |f|
|
58
|
+
f.write(@layout.render(context))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def view(type, opts)
|
65
|
+
if type == :view
|
66
|
+
name = opts[:view] ||= 'default'
|
67
|
+
dir = :view_dir
|
68
|
+
else
|
69
|
+
name = opts[:layout] ||= 'default'
|
70
|
+
dir = :layouts_dir
|
71
|
+
end
|
72
|
+
|
73
|
+
file_name = "#{name}.#{opts[:ext] || 'html'}.#{SiteConfig[:templating]}"
|
74
|
+
path = File.join(SiteConfig[dir], file_name)
|
75
|
+
Tilt.new(path)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class GeneratorConfig
|
80
|
+
def initialize(path, &blk)
|
81
|
+
@path = path
|
82
|
+
@blk = blk
|
83
|
+
@pages = []
|
84
|
+
matches = path.match(/:([a-zA-Z0-9_]+)/)
|
85
|
+
@path_params = matches[1..matches.length]
|
86
|
+
end
|
87
|
+
|
88
|
+
def prepare
|
89
|
+
instance_eval(&@blk)
|
90
|
+
@pages
|
91
|
+
end
|
92
|
+
|
93
|
+
def render(template, opts)
|
94
|
+
content = opts[:content] || {}
|
95
|
+
|
96
|
+
path = @path.dup
|
97
|
+
@path_params.each do |p|
|
98
|
+
path.gsub!(/:#{p}/, opts[p.to_sym].to_s)
|
99
|
+
end
|
100
|
+
|
101
|
+
@pages << Page.new(path, content, opts)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/pekky/server.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Pekky
|
2
|
+
module Server
|
3
|
+
def self.start(port)
|
4
|
+
require 'rack'
|
5
|
+
Pekky.load
|
6
|
+
app = Rack::Builder.app {
|
7
|
+
use Rack::Static, :urls => %w(/stylesheets /javascripts /images), :root => Pekky::SiteConfig[:output_dir]
|
8
|
+
run Pekky::Server
|
9
|
+
}
|
10
|
+
Rack::Handler.default.run(app, :Port => port || 3000)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.call(env)
|
14
|
+
Pekky.build
|
15
|
+
path = env['PATH_INFO']
|
16
|
+
file = File.join(SiteConfig[:output_dir], path, 'index.html')
|
17
|
+
if File.exists?(file)
|
18
|
+
output = File.open(file).read
|
19
|
+
[200, {"Content-Type" => "text/html"}, [output]]
|
20
|
+
else
|
21
|
+
[200, {"Content-Type" => "text/html"}, "Oh, file is not found; Pekky cries for you."]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Pekky
|
2
|
+
module SiteConfig
|
3
|
+
@config = {
|
4
|
+
:content_dir => '/content',
|
5
|
+
:view_dir => '/views',
|
6
|
+
:layouts_dir => '/views/layouts',
|
7
|
+
:partials_dir => '/views/partials',
|
8
|
+
:public_dir => '/public',
|
9
|
+
:output_dir => '/output',
|
10
|
+
:javascripts_path => '/javascripts',
|
11
|
+
:stylesheets_path => '/stylesheets',
|
12
|
+
:images_path => '/images',
|
13
|
+
:templating => 'haml',
|
14
|
+
:css_processor => 'sass'
|
15
|
+
}
|
16
|
+
|
17
|
+
def self.set_root(p)
|
18
|
+
@config[:root] = p
|
19
|
+
@config.each do |k, v|
|
20
|
+
if k.to_s.match(/_dir$/)
|
21
|
+
self[k] = File.join(p, v)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
@page_configs = []
|
27
|
+
|
28
|
+
def self.page_configs
|
29
|
+
@page_configs
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.[](name)
|
33
|
+
@config[name]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.[]=(name, val)
|
37
|
+
@config[name] = val
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.set(option, val)
|
41
|
+
if option.to_s.match(/_dir$/)
|
42
|
+
@config[option] = File.join(self[:root], val)
|
43
|
+
else
|
44
|
+
@config[option] = val
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.page(path, content, opts = {})
|
49
|
+
@page_configs << PageConfig.new(path, content, opts)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.generate(path, &blk)
|
53
|
+
@page_configs << GeneratorConfig.new(path, &blk)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/pekky/tree.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Pekky
|
2
|
+
module Tree
|
3
|
+
@pages = []
|
4
|
+
|
5
|
+
def self.pages
|
6
|
+
@pages
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.add(pages)
|
10
|
+
@pages.clear
|
11
|
+
pages.each {|p| add_to_tree(p, pages)}
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def self.add_to_tree(page, pages)
|
17
|
+
# Loop through the existing pages and see if the current page is a child
|
18
|
+
# of an existing one. If we get a partial match, see if it belongs
|
19
|
+
# to one of the children.
|
20
|
+
pages.each do |p|
|
21
|
+
if page.path != p.path
|
22
|
+
if page.path.match("^#{p.path}/[a-zA-Z0-9_\-]+$")
|
23
|
+
page.parent = p
|
24
|
+
p.children << page
|
25
|
+
return
|
26
|
+
elsif page.path.match("^#{p.path}/\S+")
|
27
|
+
add_to_tree(page, p.children)
|
28
|
+
return
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
# If none of the above works, just stick the page in the top level.
|
33
|
+
@pages << page
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/pekky.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# [Tilt]: http://github.com/rtomayko/tilt is used to hanndle the template
|
2
|
+
# rendering. Pekky assumes that you have the relevant template libraries
|
3
|
+
# installed.
|
4
|
+
require 'tilt'
|
5
|
+
|
6
|
+
# We need file utils for some of the generation steps, mainly adding and
|
7
|
+
# deleting directories.
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
# The actual content is stored in YAML files, so we need to require the lib.
|
11
|
+
require 'yaml'
|
12
|
+
|
13
|
+
# Require all the bits of Pekky. Without these, it is nothing. True friends!
|
14
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
15
|
+
require dir + '/pekky/site_config'
|
16
|
+
require dir + '/pekky/pages'
|
17
|
+
require dir + '/pekky/tree'
|
18
|
+
require dir + '/pekky/context'
|
19
|
+
require dir + '/pekky/builder'
|
20
|
+
require dir + '/pekky/server'
|
21
|
+
require dir + '/pekky/console'
|
22
|
+
|
23
|
+
# # Pekky!
|
24
|
+
# The main module, which contains all the various kick-off methods. The majority
|
25
|
+
# of the actual logic is defined in the other source files. This module just
|
26
|
+
# serves as a container and shortcut.
|
27
|
+
module Pekky
|
28
|
+
# The first release, dedicated to everyone's favourite washed-up super-star
|
29
|
+
VERSION = '0.1'
|
30
|
+
VERSION_NAME = "Not Rocket Fuel, But Love"
|
31
|
+
|
32
|
+
# Returns the tree module. The tree module represents the sites pages and
|
33
|
+
# contents arranged into a tree.
|
34
|
+
def self.tree
|
35
|
+
Tree
|
36
|
+
end
|
37
|
+
|
38
|
+
# Stubs out a site on disk. Is generally called with the Pekky binary.
|
39
|
+
def self.generate(destination)
|
40
|
+
Builder.generate(destination)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Starts up the server on the specified port.
|
44
|
+
def self.server(port)
|
45
|
+
Server.start(port)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Builds the site and starts a console session.
|
49
|
+
def self.console
|
50
|
+
Console.start
|
51
|
+
end
|
52
|
+
|
53
|
+
# Requires the site file and if defined the helpers file. #load can be called
|
54
|
+
# with an optional root. This is generally not necessary and is mainly used
|
55
|
+
# when testing.
|
56
|
+
def self.load(root = Dir.pwd)
|
57
|
+
SiteConfig.set_root(root)
|
58
|
+
require 'site'
|
59
|
+
require 'helpers' if File.exists?('./helpers.rb')
|
60
|
+
end
|
61
|
+
|
62
|
+
# Used by the site.rb file to define all the options in the site.
|
63
|
+
def self.site(&blk)
|
64
|
+
SiteConfig.class_eval(&blk)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Used bu the helpers.rb file to define additional helpers.
|
68
|
+
def self.helpers(&blk)
|
69
|
+
Context.class_eval(&blk)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Builds the site on disk.
|
73
|
+
def self.build
|
74
|
+
Builder.build
|
75
|
+
end
|
76
|
+
|
77
|
+
# First clears the existing output, then rebuilds the site.
|
78
|
+
def self.build!
|
79
|
+
Builder.build!
|
80
|
+
end
|
81
|
+
|
82
|
+
@exporting = false
|
83
|
+
|
84
|
+
# Creates an export of the site ready to go up onto a server.
|
85
|
+
def self.export
|
86
|
+
@exporting = true
|
87
|
+
build!
|
88
|
+
end
|
89
|
+
|
90
|
+
# Used within the app to indicate if we are doing a developmental build or a
|
91
|
+
# proper build. This will effect helpers, which will use things like the
|
92
|
+
# domain and path prefix
|
93
|
+
def self.exporting?
|
94
|
+
@exporting == true
|
95
|
+
end
|
96
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pekky
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Luke Matthew Sutton
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2010-05-09 00:00:00 +09:30
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: tilt
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
segments:
|
27
|
+
- 0
|
28
|
+
version: "0"
|
29
|
+
type: :runtime
|
30
|
+
version_requirements: *id001
|
31
|
+
description: A friendly static site builder
|
32
|
+
email: me@lukematthewsutton.com
|
33
|
+
executables:
|
34
|
+
- pekky
|
35
|
+
extensions: []
|
36
|
+
|
37
|
+
extra_rdoc_files: []
|
38
|
+
|
39
|
+
files:
|
40
|
+
- LICENSE
|
41
|
+
- README
|
42
|
+
- Thorfile
|
43
|
+
- bin/pekky
|
44
|
+
- lib/pekky.rb
|
45
|
+
- lib/pekky/builder.rb
|
46
|
+
- lib/pekky/console.rb
|
47
|
+
- lib/pekky/context.rb
|
48
|
+
- lib/pekky/pages.rb
|
49
|
+
- lib/pekky/server.rb
|
50
|
+
- lib/pekky/site_config.rb
|
51
|
+
- lib/pekky/tree.rb
|
52
|
+
- lib/pekky/templates/site.rb
|
53
|
+
- lib/pekky/templates/helpers.rb
|
54
|
+
has_rdoc: true
|
55
|
+
homepage: http://lukematthewsutton.com/pekky
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.3.6
|
81
|
+
signing_key:
|
82
|
+
specification_version: 2
|
83
|
+
summary: A friendly static site builder
|
84
|
+
test_files: []
|
85
|
+
|