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.
Files changed (48) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +105 -0
  4. data/README.md +187 -0
  5. data/Rakefile +9 -0
  6. data/bin/potion +94 -0
  7. data/example_site/_config.yaml +2 -0
  8. data/example_site/_extensions/example_extension.rb +42 -0
  9. data/example_site/_layouts/default.haml +6 -0
  10. data/example_site/blog/_posts/2013-03-04-example-post-1/example-post-1.html.haml +10 -0
  11. data/example_site/blog/_posts/2013-03-04-example-post-1/kitten_and_duck.jpg +0 -0
  12. data/example_site/blog/_posts/2013-03-04-example-post-1/kitten_and_yarn.jpg +0 -0
  13. data/example_site/blog/_posts/2013-03-05-example-post-2/example-post-2.html.haml +4 -0
  14. data/example_site/index.html.haml +4 -0
  15. data/lib/potion.rb +23 -0
  16. data/lib/potion/extensions/category_helper.rb +9 -0
  17. data/lib/potion/extensions/deploy_to_gh_pages.rb +33 -0
  18. data/lib/potion/extensions/link_to_helper.rb +15 -0
  19. data/lib/potion/extensions/photo_helper.rb +21 -0
  20. data/lib/potion/extensions/photo_resize.rb +19 -0
  21. data/lib/potion/layout.rb +16 -0
  22. data/lib/potion/page.rb +2 -0
  23. data/lib/potion/post.rb +17 -0
  24. data/lib/potion/renderable.rb +78 -0
  25. data/lib/potion/site.rb +113 -0
  26. data/lib/potion/static_file.rb +33 -0
  27. data/lib/potion/version.rb +3 -0
  28. data/potion.gemspec +54 -0
  29. data/spec/extensions/category_spec.rb +15 -0
  30. data/spec/extensions/link_to_spec.rb +36 -0
  31. data/spec/fixtures/a-new-thing-2.html +4 -0
  32. data/spec/fixtures/test-site/_config.yaml +0 -0
  33. data/spec/fixtures/test-site/_extensions/test_extension.rb +0 -0
  34. data/spec/fixtures/test-site/_layouts/blog.haml +2 -0
  35. data/spec/fixtures/test-site/_layouts/main.haml +2 -0
  36. data/spec/fixtures/test-site/blog.html.haml +5 -0
  37. data/spec/fixtures/test-site/blog/_posts/2013-03-04-a-new-thing/a-new-thing.html.haml +5 -0
  38. data/spec/fixtures/test-site/blog/_posts/2013-03-04-a-new-thing/an-extra-thing.txt +0 -0
  39. data/spec/fixtures/test-site/css/main.css +0 -0
  40. data/spec/fixtures/test-site/javascript/main.js +1 -0
  41. data/spec/fixtures/test-site/portfolio/_posts/a-cool-thing/a-cool-thing.html.haml +4 -0
  42. data/spec/potion/layout_spec.rb +23 -0
  43. data/spec/potion/post_spec.rb +24 -0
  44. data/spec/potion/renderable_spec.rb +73 -0
  45. data/spec/potion/site_spec.rb +74 -0
  46. data/spec/potion/static_file_spec.rb +48 -0
  47. data/spec/spec_helper.rb +3 -0
  48. metadata +590 -0
@@ -0,0 +1,6 @@
1
+ Default Template
2
+
3
+ - category("blog").each do |post|
4
+ = link_to(post.relative_output_path, post)
5
+
6
+ = yield
@@ -0,0 +1,10 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ Example Post 1
5
+ = @metadata["layout"]
6
+ = gallery(1,2,3)
7
+ = photo(0, "A kitten and a duckling!")
8
+ = photo("yarn", "A kitten taking a nap on some yarn!")
9
+ = photo("kitten_and_duck")
10
+ = christmas_annoyance(2)
@@ -0,0 +1,4 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ Example Post 2
@@ -0,0 +1,4 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ Index
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,9 @@
1
+ module Potion::Helpers
2
+ def category(name)
3
+ posts = @site.posts.select do |post|
4
+ post.relative_output_path.split("/").select {|chunk| chunk != ""}[0] == name
5
+ end
6
+
7
+ posts.sort {|a,b| a.relative_output_path <=> b.relative_output_path}
8
+ end
9
+ end
@@ -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
@@ -0,0 +1,2 @@
1
+ class Potion::Page < Potion::Renderable
2
+ end
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Potion
2
+ VERSION = "0.0.2"
3
+ 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