chisel 0.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/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
|
+
|