potion 0.0.2
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/.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
|