potion 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +105 -0
- data/README.md +187 -0
- data/Rakefile +9 -0
- data/bin/potion +94 -0
- data/example_site/_config.yaml +2 -0
- data/example_site/_extensions/example_extension.rb +42 -0
- data/example_site/_layouts/default.haml +6 -0
- data/example_site/blog/_posts/2013-03-04-example-post-1/example-post-1.html.haml +10 -0
- data/example_site/blog/_posts/2013-03-04-example-post-1/kitten_and_duck.jpg +0 -0
- data/example_site/blog/_posts/2013-03-04-example-post-1/kitten_and_yarn.jpg +0 -0
- data/example_site/blog/_posts/2013-03-05-example-post-2/example-post-2.html.haml +4 -0
- data/example_site/index.html.haml +4 -0
- data/lib/potion.rb +23 -0
- data/lib/potion/extensions/category_helper.rb +9 -0
- data/lib/potion/extensions/deploy_to_gh_pages.rb +33 -0
- data/lib/potion/extensions/link_to_helper.rb +15 -0
- data/lib/potion/extensions/photo_helper.rb +21 -0
- data/lib/potion/extensions/photo_resize.rb +19 -0
- data/lib/potion/layout.rb +16 -0
- data/lib/potion/page.rb +2 -0
- data/lib/potion/post.rb +17 -0
- data/lib/potion/renderable.rb +78 -0
- data/lib/potion/site.rb +113 -0
- data/lib/potion/static_file.rb +33 -0
- data/lib/potion/version.rb +3 -0
- data/potion.gemspec +54 -0
- data/spec/extensions/category_spec.rb +15 -0
- data/spec/extensions/link_to_spec.rb +36 -0
- data/spec/fixtures/a-new-thing-2.html +4 -0
- data/spec/fixtures/test-site/_config.yaml +0 -0
- data/spec/fixtures/test-site/_extensions/test_extension.rb +0 -0
- data/spec/fixtures/test-site/_layouts/blog.haml +2 -0
- data/spec/fixtures/test-site/_layouts/main.haml +2 -0
- data/spec/fixtures/test-site/blog.html.haml +5 -0
- data/spec/fixtures/test-site/blog/_posts/2013-03-04-a-new-thing/a-new-thing.html.haml +5 -0
- data/spec/fixtures/test-site/blog/_posts/2013-03-04-a-new-thing/an-extra-thing.txt +0 -0
- data/spec/fixtures/test-site/css/main.css +0 -0
- data/spec/fixtures/test-site/javascript/main.js +1 -0
- data/spec/fixtures/test-site/portfolio/_posts/a-cool-thing/a-cool-thing.html.haml +4 -0
- data/spec/potion/layout_spec.rb +23 -0
- data/spec/potion/post_spec.rb +24 -0
- data/spec/potion/renderable_spec.rb +73 -0
- data/spec/potion/site_spec.rb +74 -0
- data/spec/potion/static_file_spec.rb +48 -0
- data/spec/spec_helper.rb +3 -0
- metadata +590 -0
data/lib/potion.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Potion
|
2
|
+
module Helpers; end
|
3
|
+
module Deployers; end
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'bundler/setup'
|
8
|
+
|
9
|
+
require 'yaml'
|
10
|
+
require 'tilt'
|
11
|
+
require 'fileutils'
|
12
|
+
|
13
|
+
require 'potion/renderable'
|
14
|
+
require 'potion/layout'
|
15
|
+
require 'potion/static_file'
|
16
|
+
require 'potion/post'
|
17
|
+
require 'potion/page'
|
18
|
+
require 'potion/site'
|
19
|
+
|
20
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__), "/potion/extensions/*.rb"))].each do |file|
|
21
|
+
require file
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Potion::Deployers
|
2
|
+
def deploy_to_gh_pages(source_dir)
|
3
|
+
original_branch = `git status`.match(/# On branch (?<branch>\S*)/)['branch']
|
4
|
+
|
5
|
+
base_dir = `pwd`.strip
|
6
|
+
tmp_file_path = "/tmp/potion_#{Time.now.to_i}"
|
7
|
+
FileUtils.mkdir_p(tmp_file_path)
|
8
|
+
FileUtils.cp_r(File.join(source_dir, "."), tmp_file_path)
|
9
|
+
|
10
|
+
File.open(File.join(tmp_file_path, "potion_deploy.txt"), "w+") do |file|
|
11
|
+
file.puts "Built and deployed by Potion on: #{Time.now}"
|
12
|
+
end
|
13
|
+
|
14
|
+
switch_branches = `git checkout gh-pages 2>&1`.strip
|
15
|
+
raise "Could not switch branches: \n#{switch_branches}" unless switch_branches.include?("Switched to branch 'gh-pages'")
|
16
|
+
|
17
|
+
delete_current_files = `rm -rf * 2>&1`.strip
|
18
|
+
raise "Error clearing out old files: \n#{delete_current_files}" unless delete_current_files == ""
|
19
|
+
|
20
|
+
FileUtils.cp_r(File.join(tmp_file_path, "."), base_dir)
|
21
|
+
|
22
|
+
`git add .`
|
23
|
+
`git commit -a -m "Automatic commit by Potion as part of deploy: #{Time.now}"`
|
24
|
+
|
25
|
+
puts "*** Pushing to: origin/gh-pages"
|
26
|
+
`git push origin gh-pages`
|
27
|
+
|
28
|
+
puts
|
29
|
+
|
30
|
+
`git checkout #{original_branch}`
|
31
|
+
puts "\n*** Deploy complete."
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Potion::Helpers
|
2
|
+
def link_to(arg1, arg2 = nil, &block)
|
3
|
+
raise "link_to requires either an item and a block, or a content string and an item" if arg2.nil? && block.nil?
|
4
|
+
|
5
|
+
if block
|
6
|
+
content = block.call
|
7
|
+
item = arg1
|
8
|
+
else
|
9
|
+
content = arg1
|
10
|
+
item = arg2
|
11
|
+
end
|
12
|
+
|
13
|
+
"<a href=\"#{item.relative_output_path}\">#{content}</a>"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Potion::Helpers
|
2
|
+
def photo(identifier, attributes = {})
|
3
|
+
raise "\n\nERROR: The 'photo' helper only works for posts.\n\n" unless self.is_a?(Potion::Post)
|
4
|
+
|
5
|
+
extensions = [".jpg", ".jpeg", ".png", ".gif"]
|
6
|
+
photos = @static_files.select {|file| extensions.include?(File.extname(file.path).downcase)}
|
7
|
+
|
8
|
+
if identifier.is_a?(Integer)
|
9
|
+
photo = photos.sort {|a,b| a.path <=> b.path }[identifier - 1]
|
10
|
+
else
|
11
|
+
candidates = photos.select{|photo| File.split(photo.path)[1].include?(identifier)}
|
12
|
+
raise "\n\nERROR: '#{identifier}' could refer to more than one photo: #{candidates.map{|x|File.split(x.path)[1]}.inspect} in #{self.path}\n\n" unless candidates.length == 1
|
13
|
+
photo = candidates.first
|
14
|
+
end
|
15
|
+
|
16
|
+
raise "\n\nERROR: No photo matching '#{identifier}' was found in: #{@path}\n\n" if photo.nil?
|
17
|
+
attributes_string = ""
|
18
|
+
attributes.each_pair {|k,v| attributes_string << "#{k}=\"#{v}\" "}
|
19
|
+
"<img #{attributes_string} src=\"#{photo.relative_output_path}\"/>"
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'mini_magick'
|
2
|
+
|
3
|
+
class PhotoResize
|
4
|
+
def process(item)
|
5
|
+
return unless item.path.include?("_posts")
|
6
|
+
return if item.site.config["photo_resize"].nil?
|
7
|
+
return unless item.site.config["photo_resize"]["enabled"]
|
8
|
+
return if item.site.fast_build
|
9
|
+
|
10
|
+
extensions = [".jpg", ".jpeg", ".gif", ".png"]
|
11
|
+
|
12
|
+
return unless extensions.include?(File.extname(item.output_path).downcase)
|
13
|
+
image = MiniMagick::Image.read(item.content)
|
14
|
+
image.resize(item.site.config["photo_resize"]["size"])
|
15
|
+
item.content = image.to_blob
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Potion::Site.register_extension(PhotoResize)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Potion::Layout
|
2
|
+
|
3
|
+
attr_accessor :path, :name, :site, :content
|
4
|
+
|
5
|
+
def initialize(path, site)
|
6
|
+
@path = path
|
7
|
+
@site = site
|
8
|
+
@name = File.split(@path)[1].gsub(File.extname(@path), "")
|
9
|
+
@content = File.open(@path) {|stream| stream.read }
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
@path == other.path &&
|
14
|
+
@site == other.site
|
15
|
+
end
|
16
|
+
end
|
data/lib/potion/page.rb
ADDED
data/lib/potion/post.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Potion::Post < Potion::Renderable
|
2
|
+
|
3
|
+
attr_accessor :static_files
|
4
|
+
|
5
|
+
def initialize(path, site)
|
6
|
+
@static_files = Dir[File.dirname(path) + "/*.*"].reject {|x| x == path}.map {|x| Potion::StaticFile.new(x, site)}
|
7
|
+
|
8
|
+
@relative_output_path = path.gsub("_posts/", "")
|
9
|
+
|
10
|
+
super(path, site)
|
11
|
+
end
|
12
|
+
|
13
|
+
def write
|
14
|
+
@static_files.each {|file| file.write }
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class Potion::Renderable
|
2
|
+
include Potion::Helpers
|
3
|
+
|
4
|
+
attr_accessor :path, :site, :metadata, :content, :layout, :output_path, :relative_output_path
|
5
|
+
|
6
|
+
def initialize(path, site)
|
7
|
+
@path = path
|
8
|
+
@site = site
|
9
|
+
|
10
|
+
load_content_and_metadata
|
11
|
+
@layout = @site.find_layout_by_name(@metadata["layout"])
|
12
|
+
|
13
|
+
@relative_output_path ||= @path
|
14
|
+
@relative_output_path = @relative_output_path.gsub(site.base_path, "")
|
15
|
+
@relative_output_path = @relative_output_path.gsub(File.extname(path), "") unless self.is_html?
|
16
|
+
|
17
|
+
@output_path = File.join(@site.destination_path, @relative_output_path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_content_and_metadata
|
21
|
+
@content = File.open(path) {|file| file.read}
|
22
|
+
begin
|
23
|
+
@metadata = YAML.load(@content.slice!(/\A(---\s*\n.*?\n?)^(---\s*$\n?)/m, 0))
|
24
|
+
rescue Psych::SyntaxError
|
25
|
+
raise "\n\nERROR: Invalid YAML frontmatter in file: #{@path}\n\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def render
|
30
|
+
@site.class.extensions.each do |extension|
|
31
|
+
extension.new.process(self)
|
32
|
+
end
|
33
|
+
|
34
|
+
layout = Tilt.new(@layout.path) { @layout.content}
|
35
|
+
|
36
|
+
if self.is_html?
|
37
|
+
layout.render(self) do
|
38
|
+
@content
|
39
|
+
end
|
40
|
+
else
|
41
|
+
item = Tilt.new(@path) { @content }
|
42
|
+
layout.render(self) do
|
43
|
+
item.render(self)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def write
|
49
|
+
FileUtils.mkdir_p(File.split(@output_path)[0])
|
50
|
+
File.open(@output_path, "w+") do |stream|
|
51
|
+
stream.puts self.render
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def ==(other)
|
56
|
+
return false unless self.class == other.class
|
57
|
+
self.instance_variables.each do |name|
|
58
|
+
return false unless self.instance_variable_get(name) == other.instance_variable_get(name)
|
59
|
+
end
|
60
|
+
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
def title
|
65
|
+
return self.metadata["title"] unless self.metadata["title"].nil?
|
66
|
+
|
67
|
+
filename = File.split(@path)[1]
|
68
|
+
filename.gsub!(/\d+-\d+-\d+-/, "")
|
69
|
+
filename.gsub!(File.extname(filename), "")
|
70
|
+
filename.gsub!(File.extname(filename), "") unless self.is_html?
|
71
|
+
filename.gsub!("-", " ")
|
72
|
+
filename[0].upcase + filename[1..-1]
|
73
|
+
end
|
74
|
+
|
75
|
+
def is_html?
|
76
|
+
File.extname(@path) == ".html"
|
77
|
+
end
|
78
|
+
end
|
data/lib/potion/site.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
class Potion::Site
|
2
|
+
include Potion
|
3
|
+
include Potion::Deployers
|
4
|
+
attr_accessor :base_path, :config, :pages, :posts, :static_files, :layouts, :files, :destination_path, :metadata, :fast_build
|
5
|
+
|
6
|
+
@@extensions = []
|
7
|
+
|
8
|
+
def self.register_extension(klass)
|
9
|
+
@@extensions << klass
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.remove_extension(klass)
|
13
|
+
@@extensions = @@extensions - [klass]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.extensions
|
17
|
+
@@extensions
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(base_path, destination_path, fast_build = false)
|
21
|
+
@base_path = base_path
|
22
|
+
@destination_path = destination_path
|
23
|
+
@fast_build = fast_build
|
24
|
+
|
25
|
+
@config = load_config
|
26
|
+
@metadata = {}
|
27
|
+
|
28
|
+
@files = find_all_files
|
29
|
+
|
30
|
+
load_extensions
|
31
|
+
|
32
|
+
@layouts = find_layouts
|
33
|
+
@posts = find_posts
|
34
|
+
@pages = find_pages
|
35
|
+
@static_files = find_static_files
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_config
|
39
|
+
config_path = File.join(@base_path, "_config.yaml")
|
40
|
+
raise "No config file found at #{config_path}" unless File.exists?(config_path)
|
41
|
+
config = YAML.load(File.open(config_path))
|
42
|
+
return {} if config == false
|
43
|
+
config
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_all_files
|
47
|
+
Dir[@base_path + "/**/*"].reject {|x| File.directory?(x)}
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_extensions
|
52
|
+
site_extensions = @files.select {|path| path.include?("_extensions") && File.extname(path) == ".rb" }
|
53
|
+
site_extensions.each do |extension|
|
54
|
+
require extension
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_layouts
|
59
|
+
layouts = @files.select {|path| path.include? "_layouts"}
|
60
|
+
layouts.map do |layout|
|
61
|
+
Layout.new(layout, self)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_layout_by_name(name)
|
66
|
+
@layouts.select {|layout| layout.name == name}.first
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_posts
|
70
|
+
posts = @files.select {|path| path.include?("_posts")}
|
71
|
+
posts = filter_for_yaml_metadata(posts)
|
72
|
+
posts.map do |post|
|
73
|
+
Post.new(post, self)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_pages
|
78
|
+
pages = @files.reject {|path| path.include?("/_")}
|
79
|
+
pages = filter_for_yaml_metadata(pages)
|
80
|
+
pages.map do |page|
|
81
|
+
Page.new(page, self)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def find_static_files
|
86
|
+
static_files = @files.reject {|path| path.include?("/_")}
|
87
|
+
static_files = static_files - filter_for_yaml_metadata(static_files)
|
88
|
+
static_files.map do |static_file|
|
89
|
+
StaticFile.new(static_file, self)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def write
|
94
|
+
puts "*** Building...\n"
|
95
|
+
|
96
|
+
(@posts + @pages + @static_files).each do |item|
|
97
|
+
item.write
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def deploy_to(target)
|
102
|
+
self.send("deploy_to_#{target}", @destination_path)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def filter_for_yaml_metadata(files)
|
108
|
+
files.select do |file|
|
109
|
+
prefix = File.open(file) {|stream| stream.read(3)}
|
110
|
+
prefix == "---"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Potion::StaticFile
|
2
|
+
|
3
|
+
attr_accessor :path, :site, :content, :relative_output_path, :output_path
|
4
|
+
|
5
|
+
def initialize(path, site)
|
6
|
+
@path = path
|
7
|
+
@site = site
|
8
|
+
@content = File.open(path) {|stream| stream.read }
|
9
|
+
@relative_output_path = @path.gsub(@site.base_path, "").gsub("_posts/", "")
|
10
|
+
@output_path = File.join(@site.destination_path, @relative_output_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def ==(other)
|
14
|
+
self.class.name == other.class.name &&
|
15
|
+
@path == other.path &&
|
16
|
+
@site == other.site
|
17
|
+
end
|
18
|
+
|
19
|
+
def render
|
20
|
+
@site.class.extensions.each do |extension|
|
21
|
+
extension.new.process(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
@content
|
25
|
+
end
|
26
|
+
|
27
|
+
def write
|
28
|
+
FileUtils.mkdir_p(File.split(@output_path)[0])
|
29
|
+
File.open(@output_path, "w+") do |stream|
|
30
|
+
stream.puts self.render
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/potion.gemspec
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path("../lib/potion/version", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "potion"
|
6
|
+
s.version = Potion::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Aaron Gough"]
|
9
|
+
s.email = ["aaron@aarongough.com"]
|
10
|
+
s.homepage = "http://github.com/aarongough/potion"
|
11
|
+
s.summary = "A static site generator that supports code, photos and files."
|
12
|
+
s.description = "A static site generator that supports code, photos and files."
|
13
|
+
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
s.rubyforge_project = "potion"
|
16
|
+
|
17
|
+
s.add_dependency "bundler", ">= 1.0.0"
|
18
|
+
s.add_dependency "tilt", ">= 1.3.4"
|
19
|
+
s.add_dependency "commander", ">= 4.1.3"
|
20
|
+
s.add_dependency "mini_magick"
|
21
|
+
s.add_dependency "directory_watcher"
|
22
|
+
s.add_dependency "require_all"
|
23
|
+
|
24
|
+
s.add_dependency 'asciidoctor', '>= 0.1.0'
|
25
|
+
s.add_dependency 'RedCloth'
|
26
|
+
s.add_dependency 'bluecloth'
|
27
|
+
s.add_dependency 'builder'
|
28
|
+
s.add_dependency 'coffee-script'
|
29
|
+
s.add_dependency 'contest'
|
30
|
+
s.add_dependency 'creole'
|
31
|
+
s.add_dependency 'erubis'
|
32
|
+
s.add_dependency 'haml', '>= 2.2.11'
|
33
|
+
s.add_dependency 'kramdown'
|
34
|
+
s.add_dependency 'less'
|
35
|
+
s.add_dependency 'liquid'
|
36
|
+
s.add_dependency 'markaby'
|
37
|
+
s.add_dependency 'maruku'
|
38
|
+
s.add_dependency 'nokogiri'
|
39
|
+
s.add_dependency 'radius'
|
40
|
+
s.add_dependency 'rdiscount'
|
41
|
+
s.add_dependency 'rdoc'
|
42
|
+
s.add_dependency 'redcarpet'
|
43
|
+
s.add_dependency 'sass'
|
44
|
+
s.add_dependency 'wikicloth'
|
45
|
+
s.add_dependency 'yajl-ruby'
|
46
|
+
s.add_dependency 'rdoc'
|
47
|
+
|
48
|
+
s.add_development_dependency "rspec", "~> 2"
|
49
|
+
s.add_development_dependency "rake"
|
50
|
+
|
51
|
+
s.files = `git ls-files`.split("\n")
|
52
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
53
|
+
s.require_path = 'lib'
|
54
|
+
end
|