chisel 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/chisel +45 -0
- data/lib/chisel/new_site/_config.yml +17 -0
- data/lib/chisel/new_site/_views/_layout/main.html.erb +18 -0
- data/lib/chisel/new_site/index.html.erb +8 -0
- data/lib/chisel/resource.rb +76 -0
- data/lib/chisel/ruby/array.rb +32 -0
- data/lib/chisel/ruby/hash.rb +20 -0
- data/lib/chisel/ruby/string.rb +49 -0
- data/lib/chisel/ruby/yaml.rb +21 -0
- data/lib/chisel/site_directory.rb +120 -0
- data/lib/chisel/templates/resource.rb +15 -0
- data/lib/chisel/templates/resource_index.html.erb +1 -0
- data/lib/chisel/view.rb +209 -0
- data/lib/chisel/view_helper.rb +61 -0
- data/lib/chisel/wrapper.rb +51 -0
- metadata +68 -0
data/bin/chisel
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'chisel/wrapper'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
module Chisel
|
7
|
+
if ARGV.count == 0
|
8
|
+
w = Wrapper.new('.')
|
9
|
+
w.run
|
10
|
+
else
|
11
|
+
|
12
|
+
case ARGV[0].downcase
|
13
|
+
|
14
|
+
when 'new'
|
15
|
+
# TODO: Add checking for existing site, with option to "force" creation
|
16
|
+
|
17
|
+
if ARGV.length == 1 then
|
18
|
+
puts 'Creating new Chisel site in the current directory...'
|
19
|
+
SiteDirectory.create('.')
|
20
|
+
puts 'Done. Run \'chisel\' to create your site.'
|
21
|
+
else
|
22
|
+
dir = ARGV[1]
|
23
|
+
puts "Creating new Chisel site in directory '#{dir}'..."
|
24
|
+
SiteDirectory.create(dir)
|
25
|
+
puts "Done. Go into \'#{dir}\' and run \'chisel\' to create your site."
|
26
|
+
end
|
27
|
+
|
28
|
+
when 'resource'
|
29
|
+
|
30
|
+
if ARGV.length == 1 then
|
31
|
+
# TODO: Something
|
32
|
+
else
|
33
|
+
site_dir = SiteDirectory.new('.')
|
34
|
+
case ARGV[1].downcase
|
35
|
+
when 'new'
|
36
|
+
site_dir.create_resource(ARGV[2])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
when 'help'
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# Chisel site configuration file
|
3
|
+
#
|
4
|
+
# For more information on the format of this configuration file:
|
5
|
+
#
|
6
|
+
# http://www.yaml.org/
|
7
|
+
#
|
8
|
+
# YAML does not use tabs for indentation! Instead, use two spaces per
|
9
|
+
# indentation level.
|
10
|
+
###############################################################################
|
11
|
+
|
12
|
+
# The output directory is the root directory where the site will be generated.
|
13
|
+
# This directory will be completely replaced every time the generator is run.
|
14
|
+
output_dir: _output
|
15
|
+
|
16
|
+
# Any further configuration options specified will be available to views in the
|
17
|
+
# variable @config.
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= title %></title>
|
5
|
+
|
6
|
+
<!--
|
7
|
+
-- Include references to stylesheets and scripts here, using the path_to() function
|
8
|
+
-- to get relative paths to the files. The paths are relative to the site root.
|
9
|
+
-->
|
10
|
+
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
|
14
|
+
<!-- Wrap your style around the content variable -->
|
15
|
+
<%= content %>
|
16
|
+
|
17
|
+
</body>
|
18
|
+
</html>
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Chisel
|
2
|
+
class Resource
|
3
|
+
|
4
|
+
@@cache = {}
|
5
|
+
|
6
|
+
def id
|
7
|
+
raise "You must implement #{self.class.name}.id"
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.all
|
11
|
+
raise "You must implement #{self.class.name}.all"
|
12
|
+
end
|
13
|
+
|
14
|
+
def resource_type
|
15
|
+
self.class.name.underscore
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
File.join(*self.id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def cache(*keys)
|
23
|
+
@cache ||= {}
|
24
|
+
cached = true
|
25
|
+
keys.each { |key| cached &= @cache.key?(key) }
|
26
|
+
return keys.map { |key| @cache[key] } if cached
|
27
|
+
if keys.size == 1
|
28
|
+
results = yield
|
29
|
+
@cache[keys[0]] == results
|
30
|
+
else
|
31
|
+
results = [*yield]
|
32
|
+
keys.each_index { |i| @cache[keys[i]] = results[i] }
|
33
|
+
end
|
34
|
+
results
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.class_cache(*keys)
|
38
|
+
cached = true
|
39
|
+
keys.each { |key| cached &= @@cache.key?(key) }
|
40
|
+
return keys.map { |key| @@cache[key] } if cached
|
41
|
+
if keys.size == 1
|
42
|
+
results = yield
|
43
|
+
@@cache[keys[0]] == results
|
44
|
+
else
|
45
|
+
results = [*yield]
|
46
|
+
keys.each_index { |i| @@cache[keys[i]] = results[i] }
|
47
|
+
end
|
48
|
+
results
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.find_in(resources, parameters={})
|
52
|
+
return resources if parameters == {}
|
53
|
+
results = []
|
54
|
+
|
55
|
+
resources.each do |resource|
|
56
|
+
matches = true
|
57
|
+
parameters.each do |param, value|
|
58
|
+
param = param.to_sym
|
59
|
+
if resource.respond_to?(param)
|
60
|
+
param_value = resource.public_send(param)
|
61
|
+
if param_value != value
|
62
|
+
matches = false
|
63
|
+
break
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
results << resource if matches
|
68
|
+
end
|
69
|
+
results
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.find(parameters={})
|
73
|
+
self.find_in(self.all, parameters)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Array
|
2
|
+
def sort_by(method_name, ascending=true)
|
3
|
+
method_name = method_name.to_sym
|
4
|
+
self.sort do |left, right|
|
5
|
+
if left.respond_to?(method_name) and right.respond_to?(method_name)
|
6
|
+
if ascending
|
7
|
+
left.public_send(method_name) <=> right.public_send(method_name)
|
8
|
+
else
|
9
|
+
right.public_send(method_name) <=> left.public_send(method_name)
|
10
|
+
end
|
11
|
+
else
|
12
|
+
raise "Could not sort items #{left} and #{right}. They do not both respond to method '#{method_name.to_s}'"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def unique(method_name)
|
18
|
+
method_name = method_name.to_sym
|
19
|
+
values = []
|
20
|
+
|
21
|
+
self.each do |item|
|
22
|
+
if item.respond_to?(method_name)
|
23
|
+
value = item.send(method_name)
|
24
|
+
values << value unless values.index(value)
|
25
|
+
else
|
26
|
+
raise "Could not pick out unique items: #{item} does not respond to method '#{method_name}'"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
values
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
def symbolize_keys
|
4
|
+
self.inject({}) do |memo,(k,v)|
|
5
|
+
if v.is_a?(Hash)
|
6
|
+
memo[k.to_sym] = v.symbolize_keys
|
7
|
+
else
|
8
|
+
memo[k.to_sym] = v
|
9
|
+
end
|
10
|
+
memo
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_binding(object = Object.new)
|
15
|
+
object.instance_eval("def binding_for(#{keys.join(",")}) binding end")
|
16
|
+
# object.instance_eval('def method_missing(method_name); nil; end')
|
17
|
+
object.binding_for(*values)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def underscored?
|
4
|
+
self[0].downcase == self[0]
|
5
|
+
end
|
6
|
+
|
7
|
+
def camelized?
|
8
|
+
self[0].upcase == self[0]
|
9
|
+
end
|
10
|
+
|
11
|
+
# Converts 'Foo::HerpDerp' to 'foo/herp_derp'
|
12
|
+
def underscore
|
13
|
+
tokens = self.split('::')
|
14
|
+
if tokens.count > 1
|
15
|
+
return (tokens.map { |token| token.underscore }).join('/')
|
16
|
+
end
|
17
|
+
|
18
|
+
result = ''
|
19
|
+
for i in (0..(self.length - 1))
|
20
|
+
result << '_' if self[i] == self[i].upcase and i != 0
|
21
|
+
result << self[i].downcase
|
22
|
+
end
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
# Converts 'foo/herp_derp' to 'Foo::HerpDerp'
|
27
|
+
def camelize
|
28
|
+
tokens = self.split('/')
|
29
|
+
if tokens.count > 1
|
30
|
+
return (tokens.map { |token| token.camelize }).join('::')
|
31
|
+
end
|
32
|
+
|
33
|
+
result = ''
|
34
|
+
capitalize = true
|
35
|
+
|
36
|
+
for i in (0..(self.length - 1))
|
37
|
+
if self[i] == '_'
|
38
|
+
capitalize = true
|
39
|
+
elsif capitalize
|
40
|
+
capitalize = false
|
41
|
+
result << self[i].upcase
|
42
|
+
else
|
43
|
+
result << self[i]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module YAML
|
2
|
+
module Syck
|
3
|
+
def YAML.remove_header(string)
|
4
|
+
matches = string.match(/---\r*\n(.*)\n---\r*\n(.*)/m)
|
5
|
+
return string unless matches and matches.size > 2
|
6
|
+
matches[2]
|
7
|
+
end
|
8
|
+
|
9
|
+
def YAML.header_string(string)
|
10
|
+
matches = string.match(/---\r*\n(.*)\r*\n---/m)
|
11
|
+
return '' unless matches and matches.size > 1
|
12
|
+
matches[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def YAML.load_header(string)
|
16
|
+
header_string = YAML.header_string(string)
|
17
|
+
return {} if header_string == ''
|
18
|
+
YAML.load(header_string)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Chisel
|
6
|
+
class SiteDirectory < Pathname
|
7
|
+
attr_accessor :config
|
8
|
+
|
9
|
+
@config = {}
|
10
|
+
|
11
|
+
def initialize(site_dir)
|
12
|
+
super
|
13
|
+
config_path = self.join('_config.yml')
|
14
|
+
if config_path.exist?
|
15
|
+
@config = YAML::load_file(config_path) || {}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def output_dir
|
20
|
+
if @config['output_dir']
|
21
|
+
dir = Pathname.new(@config['output_dir']).expand_path(self)
|
22
|
+
if dir.absolute?
|
23
|
+
return dir
|
24
|
+
else
|
25
|
+
return self.join(dir)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
return self.join('_output')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def resource_dir
|
33
|
+
self.join('_resources')
|
34
|
+
end
|
35
|
+
|
36
|
+
def view_dir
|
37
|
+
self.join('_views')
|
38
|
+
end
|
39
|
+
|
40
|
+
def layout_dir
|
41
|
+
self.view_dir.join('_layout')
|
42
|
+
end
|
43
|
+
|
44
|
+
def clear_output_dir
|
45
|
+
FileUtils.rm_r(output_dir) if File.exists?(output_dir)
|
46
|
+
FileUtils.mkdir(output_dir)
|
47
|
+
end
|
48
|
+
|
49
|
+
def require_resources
|
50
|
+
path = self.resource_dir.join("*.rb").expand_path
|
51
|
+
Dir[path].each do |resource_filename|
|
52
|
+
require resource_filename
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def resource_type_view_path(resource_type, view)
|
57
|
+
self.view_dir.join(resource_type.to_s, "#{view_with_extension(view)}.erb")
|
58
|
+
end
|
59
|
+
|
60
|
+
def resource_view_output_path(resource, view)
|
61
|
+
self.output_dir.join(*resource.id, view_with_extension(view))
|
62
|
+
end
|
63
|
+
|
64
|
+
def page_output_path(page)
|
65
|
+
page = view_with_extension(page)
|
66
|
+
self.output_dir.join(page)
|
67
|
+
end
|
68
|
+
|
69
|
+
def layout_view_path(layout_name)
|
70
|
+
self.layout_dir.join("#{view_with_extension(layout_name).to_s}.erb")
|
71
|
+
end
|
72
|
+
|
73
|
+
def view_path(view)
|
74
|
+
self.view_dir.join("#{view_with_extension(view)}.erb")
|
75
|
+
end
|
76
|
+
|
77
|
+
def view_with_extension(view)
|
78
|
+
view = "#{view}index" if view[-1] == '/'
|
79
|
+
return "#{view}.html" if File.basename(view).split('.').count < 2
|
80
|
+
view
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.create(dest)
|
84
|
+
dir = Pathname.new(__FILE__).dirname
|
85
|
+
src = dir.join('new_site')
|
86
|
+
dest = Pathname.new(dest)
|
87
|
+
|
88
|
+
FileUtils.cp_r(src.to_s + '/.', dest)
|
89
|
+
|
90
|
+
dest.join('_resources').mkpath
|
91
|
+
dest.join('_views', '_resource').mkpath
|
92
|
+
end
|
93
|
+
|
94
|
+
def create_resource(name)
|
95
|
+
name = name.underscore if name.camelized?
|
96
|
+
|
97
|
+
# Create resource.rb file
|
98
|
+
|
99
|
+
resource_template_filename = Pathname.new(__FILE__).dirname.join('templates', 'resource.rb')
|
100
|
+
resource_template = File.read(resource_template_filename)
|
101
|
+
resource_template.gsub!('{NAME}', name.camelize)
|
102
|
+
|
103
|
+
resource_filename = self.join('_resources', "#{name}.rb")
|
104
|
+
File.open(resource_filename, 'w') { |f| f.write(resource_template) }
|
105
|
+
|
106
|
+
# Create resource index.html file
|
107
|
+
|
108
|
+
self.join('_views', name).mkpath
|
109
|
+
|
110
|
+
index_template_filename = Pathname.new(__FILE__).dirname.join('templates', 'resource_index.html.erb')
|
111
|
+
index_template = File.read(index_template_filename)
|
112
|
+
index_template.gsub!('{NAME}', name.camelize)
|
113
|
+
|
114
|
+
index_filename = self.join('_views', name, 'index.html.erb')
|
115
|
+
File.open(index_filename, 'w') { |f| f.write(index_template) }
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class {NAME} < Chisel::Resource
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
# TODO: Implement a custom {NAME} resource class constructor
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.all
|
8
|
+
raise 'You must implement {NAME}.all to return an array of all {NAME} resources'
|
9
|
+
end
|
10
|
+
|
11
|
+
def id
|
12
|
+
raise 'You must implement {NAME}.id to return an array that uniquely identifies this resource'
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a placeholder index page for {NAME} resource with ID <%= resource.id.to_s %>
|
data/lib/chisel/view.rb
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'pathname'
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module Chisel
|
6
|
+
class View
|
7
|
+
|
8
|
+
MarkupExtensions = ['erb', 'md', 'textile']
|
9
|
+
|
10
|
+
attr_accessor :type, :path, :view, :site_dir, :resource, :raw_content
|
11
|
+
@@cache = []
|
12
|
+
@@output_paths = []
|
13
|
+
|
14
|
+
def self.fetch(options={})
|
15
|
+
@@cache.each do |view|
|
16
|
+
return view if view.matches(options)
|
17
|
+
end
|
18
|
+
|
19
|
+
return View.new(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(options={})
|
23
|
+
|
24
|
+
# Do not call the initializer directly; use View.fetch(options)
|
25
|
+
# to take advantage of view caching
|
26
|
+
|
27
|
+
@path = Pathname.new(options[:path]) if options[:path]
|
28
|
+
@site_dir = SiteDirectory.new(options[:site_dir]) if options[:site_dir]
|
29
|
+
|
30
|
+
if options[:resource]
|
31
|
+
@type = :resource
|
32
|
+
@resource = options[:resource]
|
33
|
+
@view = options[:view]
|
34
|
+
@path = @site_dir.resource_type_view_path(@resource, @view)
|
35
|
+
elsif options[:layout]
|
36
|
+
@type = :layout
|
37
|
+
@view = options[:layout]
|
38
|
+
@path = @site_dir.layout_view_path(@view)
|
39
|
+
elsif options[:view]
|
40
|
+
@view = options[:view]
|
41
|
+
@path = @site_dir.view_path(@view)
|
42
|
+
end
|
43
|
+
|
44
|
+
raise 'Cannot initialize view without a path' unless @path
|
45
|
+
|
46
|
+
@raw_content = File.read(@path)
|
47
|
+
@@cache << self
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def matches(options = {})
|
52
|
+
|
53
|
+
return true if options.key?(:resource) and @type == :resource and @view == options[:view] and @resource == options[:resource]
|
54
|
+
return true if options.key?(:layout) and @type == :layout and @view == options[:layout]
|
55
|
+
return true if @path == options[:path]
|
56
|
+
|
57
|
+
return false
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def run(options = {})
|
62
|
+
if options[:output_path] then
|
63
|
+
output_path = options[:output_path]
|
64
|
+
else
|
65
|
+
view_relative_dir = @path.relative_path_from(@site_dir).dirname
|
66
|
+
file_output_dir = @site_dir.output_dir.join(view_relative_dir)
|
67
|
+
file_output_dir.mkpath
|
68
|
+
output_path = file_output_dir.join(output_basename)
|
69
|
+
end
|
70
|
+
|
71
|
+
return if @@output_paths.index(output_path) or output_path.exist?
|
72
|
+
@@output_paths << output_path
|
73
|
+
|
74
|
+
FileUtils.mkdir_p(output_path.dirname)
|
75
|
+
|
76
|
+
result = evaluate(output_path, options)
|
77
|
+
|
78
|
+
f = File.new(output_path, 'w')
|
79
|
+
f.write(result)
|
80
|
+
f.close
|
81
|
+
|
82
|
+
result
|
83
|
+
end
|
84
|
+
|
85
|
+
def evaluate(output_path, options = {})
|
86
|
+
|
87
|
+
if @type == :layout
|
88
|
+
puts "Evaluating layout for #{output_path}..."
|
89
|
+
else
|
90
|
+
puts "Evaluating #{output_path}..."
|
91
|
+
end
|
92
|
+
|
93
|
+
helper = ViewHelper.new(@site_dir, output_path)
|
94
|
+
|
95
|
+
# First evaluate header as ERB if necessary
|
96
|
+
|
97
|
+
header_vars = {}
|
98
|
+
if options[:resource]
|
99
|
+
header_vars[:resource] = options[:resource]
|
100
|
+
end
|
101
|
+
|
102
|
+
header_binding = header_vars.to_binding(helper)
|
103
|
+
header_string = ERB.new(YAML.header_string(@raw_content)).result(header_binding)
|
104
|
+
if header_string == ''
|
105
|
+
header = {}
|
106
|
+
else
|
107
|
+
header = YAML.load(header_string).symbolize_keys
|
108
|
+
end
|
109
|
+
|
110
|
+
# Maintin the binding if we were passed one; otherwise,
|
111
|
+
# create a brand new binding from our header info
|
112
|
+
|
113
|
+
if options[:binding]
|
114
|
+
content_binding = options[:binding]
|
115
|
+
|
116
|
+
# Overwrite layout that was passed in
|
117
|
+
if header[:layout]
|
118
|
+
content_binding.eval("layout = '#{header[:layout]}'")
|
119
|
+
else
|
120
|
+
content_binding.eval("layout = nil")
|
121
|
+
end
|
122
|
+
|
123
|
+
else
|
124
|
+
|
125
|
+
if options[:locals]
|
126
|
+
vars = header.merge(options[:locals])
|
127
|
+
else
|
128
|
+
vars = header.clone
|
129
|
+
end
|
130
|
+
vars[:content] = nil
|
131
|
+
vars[:layout] = nil unless vars.key?(:layout)
|
132
|
+
|
133
|
+
if options[:resource]
|
134
|
+
resource_key = options[:resource].resource_type.to_sym
|
135
|
+
vars[resource_key] = options[:resource]
|
136
|
+
vars[:resource] = options[:resource] # alias as "resource"
|
137
|
+
end
|
138
|
+
|
139
|
+
content_binding = vars.to_binding(helper)
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
# Evaluate the content with appropriate markup and ERB
|
144
|
+
|
145
|
+
content = YAML.remove_header(@raw_content)
|
146
|
+
|
147
|
+
markup_extensions.reverse.each do |extension|
|
148
|
+
case extension.downcase
|
149
|
+
when 'erb'
|
150
|
+
content = ERB.new(content).result(content_binding)
|
151
|
+
when 'textile'
|
152
|
+
begin
|
153
|
+
require 'RedCloth'
|
154
|
+
rescue LoadError
|
155
|
+
puts "
|
156
|
+
The RedCloth gem is required to evaluate Textile markup. Please run:
|
157
|
+
|
158
|
+
gem install RedCloth"
|
159
|
+
exit
|
160
|
+
end
|
161
|
+
content = RedCloth.new(content).to_html
|
162
|
+
when 'md'
|
163
|
+
begin
|
164
|
+
require 'maruku'
|
165
|
+
rescue LoadError
|
166
|
+
puts "
|
167
|
+
The Maruku gem is required to evaluate Markdown markup. Please run:
|
168
|
+
|
169
|
+
gem install maruku"
|
170
|
+
exit
|
171
|
+
end
|
172
|
+
content = Maruku.new(content).to_html
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Now evaluate the layout
|
177
|
+
|
178
|
+
if content_binding.eval('layout')
|
179
|
+
content_binding.eval("content = <<EOS\n#{content}\nEOS")
|
180
|
+
layout_view = View.fetch(:layout => content_binding.eval('layout'), :site_dir => @site_dir)
|
181
|
+
content = layout_view.evaluate(output_path, :binding => content_binding)
|
182
|
+
end
|
183
|
+
|
184
|
+
content
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
|
189
|
+
def markup_extensions
|
190
|
+
tokens = Pathname.new(@path).basename.to_s.split('.')
|
191
|
+
return nil if tokens.length == 1
|
192
|
+
|
193
|
+
i = tokens.length
|
194
|
+
tokens.reverse.each do |token|
|
195
|
+
break unless MarkupExtensions.index(token)
|
196
|
+
i = i - 1
|
197
|
+
end
|
198
|
+
|
199
|
+
return tokens[i..-1].map { |t| t.downcase }
|
200
|
+
end
|
201
|
+
|
202
|
+
def output_basename
|
203
|
+
return @path.basename unless markup_extensions
|
204
|
+
extensions = '.' + markup_extensions.join('.')
|
205
|
+
return @path.basename(extensions)
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Chisel
|
2
|
+
class ViewHelper
|
3
|
+
attr_accessor :site_dir, :output_path
|
4
|
+
|
5
|
+
def initialize(site_dir, output_path)
|
6
|
+
@site_dir = site_dir
|
7
|
+
@config = @site_dir.config
|
8
|
+
@output_path = output_path
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(view, options = {})
|
12
|
+
locals = options[:locals] || {}
|
13
|
+
|
14
|
+
template = View.fetch(:view => view, :site_dir => @site_dir)
|
15
|
+
template.evaluate(@output_path, :locals => locals)
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def link_to_resource(resource, text, options = {})
|
20
|
+
view = options[:view] || 'index'
|
21
|
+
|
22
|
+
view_path = @site_dir.resource_view_output_path(resource, view)
|
23
|
+
href = view_path.relative_path_from(@output_path.dirname).to_s
|
24
|
+
|
25
|
+
# Initialize the view template
|
26
|
+
template = View.fetch(:resource => resource.resource_type, :view => view, :site_dir => @site_dir)
|
27
|
+
|
28
|
+
# Compute the output path for this specific resource
|
29
|
+
output_path = @site_dir.resource_view_output_path(resource, view)
|
30
|
+
|
31
|
+
# Now run the view template against this resource
|
32
|
+
template.run(:output_path => output_path, :resource => resource)
|
33
|
+
|
34
|
+
link_to(href, text, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def link_to_page(page, text, options = {})
|
38
|
+
page_output_path = @site_dir.page_output_path(page)
|
39
|
+
href = page_output_path.relative_path_from(@output_path.dirname).to_s
|
40
|
+
|
41
|
+
link_to(href, text, options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def path_to(site_relative_path)
|
45
|
+
@site_dir.output_dir.join(site_relative_path).relative_path_from(@output_path.dirname)
|
46
|
+
end
|
47
|
+
|
48
|
+
def link_to(href, text, options = {})
|
49
|
+
if options[:html]
|
50
|
+
attribute_string = ''
|
51
|
+
options[:html].each do |k, v|
|
52
|
+
attribute_string += " #{k}=\"#{v}\"" if LinkAttributes.index(k.to_s.downcase)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
href = href[0..-11] if href.end_with?('index.html')
|
57
|
+
|
58
|
+
"<a href=\"#{href}\"#{attribute_string}>#{text}</a>"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'json'
|
3
|
+
require 'chisel/resource'
|
4
|
+
require 'chisel/site_directory'
|
5
|
+
require 'chisel/view'
|
6
|
+
require 'chisel/view_helper'
|
7
|
+
|
8
|
+
require 'chisel/ruby/array'
|
9
|
+
require 'chisel/ruby/hash'
|
10
|
+
require 'chisel/ruby/string'
|
11
|
+
require 'chisel/ruby/yaml'
|
12
|
+
|
13
|
+
module Chisel
|
14
|
+
class Wrapper
|
15
|
+
attr_accessor :site_dir
|
16
|
+
|
17
|
+
def initialize(site_dir)
|
18
|
+
@site_dir = SiteDirectory.new(site_dir)
|
19
|
+
require_rb(@site_dir.resource_dir)
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(dir = @site_dir)
|
23
|
+
@site_dir.clear_output_dir
|
24
|
+
|
25
|
+
# Get all views in the root site directory as well
|
26
|
+
# as any subdirectories (recursive). Don't include
|
27
|
+
# any files or folders beginning with an underscore.
|
28
|
+
view_paths = Pathname.glob(@site_dir.join('[^_]*.*'))
|
29
|
+
view_paths += Pathname.glob(@site_dir.join('[^_]**/**/*.*'))
|
30
|
+
|
31
|
+
view_paths.each do |view_path|
|
32
|
+
if view_path.extname == '.erb'
|
33
|
+
view = View.fetch(:path => view_path, :site_dir => @site_dir)
|
34
|
+
view.run
|
35
|
+
else
|
36
|
+
output_path = @site_dir.output_dir.join(view_path)
|
37
|
+
output_path.dirname.mkpath
|
38
|
+
FileUtils.cp(view_path, output_path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def require_rb(path)
|
46
|
+
Dir["#{path}/*.rb"].each do |filename|
|
47
|
+
require File.expand_path(filename)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chisel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rockwell Schrock
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-06-07 00:00:00 Z
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Chisel is tool to generate simple, resource-based static Web sites.
|
17
|
+
email: schrockwell@gmail.com
|
18
|
+
executables:
|
19
|
+
- chisel
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/chisel/new_site/_config.yml
|
26
|
+
- lib/chisel/new_site/_views/_layout/main.html.erb
|
27
|
+
- lib/chisel/new_site/index.html.erb
|
28
|
+
- lib/chisel/resource.rb
|
29
|
+
- lib/chisel/ruby/array.rb
|
30
|
+
- lib/chisel/ruby/hash.rb
|
31
|
+
- lib/chisel/ruby/string.rb
|
32
|
+
- lib/chisel/ruby/yaml.rb
|
33
|
+
- lib/chisel/site_directory.rb
|
34
|
+
- lib/chisel/templates/resource.rb
|
35
|
+
- lib/chisel/templates/resource_index.html.erb
|
36
|
+
- lib/chisel/view.rb
|
37
|
+
- lib/chisel/view_helper.rb
|
38
|
+
- lib/chisel/wrapper.rb
|
39
|
+
- bin/chisel
|
40
|
+
homepage: https://github.com/schrockwell/chisel
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.8.5
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: A static Web site generator.
|
67
|
+
test_files: []
|
68
|
+
|