bdimcheff-staticmatic 0.10.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/LICENSE +20 -0
- data/README.markdown +50 -0
- data/Rakefile +31 -0
- data/VERSION.yml +4 -0
- data/bin/staticmatic +23 -0
- data/lib/staticmatic.rb +20 -0
- data/lib/staticmatic/base.rb +87 -0
- data/lib/staticmatic/configuration.rb +18 -0
- data/lib/staticmatic/error.rb +17 -0
- data/lib/staticmatic/helpers.rb +197 -0
- data/lib/staticmatic/mixins/build.rb +46 -0
- data/lib/staticmatic/mixins/helpers.rb +15 -0
- data/lib/staticmatic/mixins/render.rb +125 -0
- data/lib/staticmatic/mixins/rescue.rb +12 -0
- data/lib/staticmatic/mixins/server.rb +6 -0
- data/lib/staticmatic/mixins/setup.rb +20 -0
- data/lib/staticmatic/server.rb +94 -0
- data/lib/staticmatic/template_error.rb +40 -0
- data/lib/staticmatic/templates/default/application.haml +7 -0
- data/lib/staticmatic/templates/default/application.sass +4 -0
- data/lib/staticmatic/templates/default/index.haml +1 -0
- data/lib/staticmatic/templates/rescues/default.haml +7 -0
- data/lib/staticmatic/templates/rescues/template.haml +18 -0
- data/test/base_test.rb +13 -0
- data/test/helpers_test.rb +12 -0
- data/test/render_test.rb +30 -0
- data/test/rescue_test.rb +36 -0
- data/test/sandbox/test_site/configuration.rb +0 -0
- data/test/sandbox/test_site/site/index.html +10 -0
- data/test/sandbox/test_site/site/stylesheets/application.css +2 -0
- data/test/sandbox/test_site/src/helpers/application_helper.rb +5 -0
- data/test/sandbox/test_site/src/layouts/alternate_layout.haml +3 -0
- data/test/sandbox/test_site/src/layouts/application.haml +7 -0
- data/test/sandbox/test_site/src/layouts/projects.haml +1 -0
- data/test/sandbox/test_site/src/pages/hello_world.erb +1 -0
- data/test/sandbox/test_site/src/pages/index.haml +5 -0
- data/test/sandbox/test_site/src/pages/layout_test.haml +2 -0
- data/test/sandbox/test_site/src/pages/page_with_error.haml +5 -0
- data/test/sandbox/test_site/src/pages/page_with_partial_error.haml +3 -0
- data/test/sandbox/test_site/src/partials/menu.haml +1 -0
- data/test/sandbox/test_site/src/partials/partial_with_error.haml +1 -0
- data/test/sandbox/test_site/src/stylesheets/application.sass +2 -0
- data/test/sandbox/test_site/src/stylesheets/css_with_error.sass +5 -0
- data/test/server_test.rb +12 -0
- data/test/setup_test.rb +25 -0
- data/test/template_error_test.rb +23 -0
- data/test/test_helper.rb +20 -0
- metadata +128 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module StaticMatic::BuildMixin
|
2
|
+
|
3
|
+
def build
|
4
|
+
build_css
|
5
|
+
build_html
|
6
|
+
end
|
7
|
+
|
8
|
+
# Build HTML from the source files
|
9
|
+
def build_html
|
10
|
+
Dir["#{@src_dir}/pages/**/*.haml"].each do |path|
|
11
|
+
next if File.basename(path) =~ /^\_/ # skip partials
|
12
|
+
file_dir, template = source_template_from_path(path.sub(/^#{@src_dir}\/pages/, ''))
|
13
|
+
save_page(File.join(file_dir, template), generate_html_with_layout(template, file_dir))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Build CSS from the source files
|
18
|
+
def build_css
|
19
|
+
Dir["#{@src_dir}/stylesheets/**/*.sass"].each do |path|
|
20
|
+
file_dir, template = source_template_from_path(path.sub(/^#{@src_dir}\/stylesheets/, ''))
|
21
|
+
save_stylesheet(File.join(file_dir, template), generate_css(template, file_dir))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def copy_file(from, to)
|
26
|
+
FileUtils.cp(from, to)
|
27
|
+
end
|
28
|
+
|
29
|
+
def save_page(filename, content)
|
30
|
+
generate_site_file(filename, 'html', content)
|
31
|
+
end
|
32
|
+
|
33
|
+
def save_stylesheet(filename, content)
|
34
|
+
generate_site_file(File.join('stylesheets', filename), 'css', content)
|
35
|
+
end
|
36
|
+
|
37
|
+
def generate_site_file(filename, extension, content)
|
38
|
+
path = File.join(@site_dir,"#{filename}.#{extension}")
|
39
|
+
FileUtils.mkdir_p(File.dirname(path))
|
40
|
+
File.open(path, 'w+') do |f|
|
41
|
+
f << content
|
42
|
+
end
|
43
|
+
|
44
|
+
puts "created #{path}"
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module StaticMatic::HelpersMixin
|
2
|
+
# Loads any helpers present in the helpers dir and mixes them into the template helpers
|
3
|
+
def load_helpers
|
4
|
+
|
5
|
+
Dir["#{@src_dir}/helpers/**/*_helper.rb"].each do |helper|
|
6
|
+
load_helper(helper)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def load_helper(helper)
|
11
|
+
load helper
|
12
|
+
module_name = File.basename(helper, '.rb').gsub(/(^|\_)./) { |c| c.upcase }.gsub(/\_/, '')
|
13
|
+
Haml::Helpers.class_eval("include #{module_name}")
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module StaticMatic::RenderMixin
|
2
|
+
|
3
|
+
def source_for_layout
|
4
|
+
if layout_exists?(@layout)
|
5
|
+
File.read(full_layout_path(@layout))
|
6
|
+
else
|
7
|
+
raise StaticMatic::Error.new("", full_layout_path(@layout), "Layout not found")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Generate html from source file:
|
12
|
+
# generate_html("index")
|
13
|
+
def generate_html(source_file, source_dir = '')
|
14
|
+
full_file_path = File.join(@src_dir, 'pages', source_dir, "#{source_file}.haml")
|
15
|
+
|
16
|
+
begin
|
17
|
+
# clear all scope variables except @staticmatic
|
18
|
+
@scope.instance_variables.each do |var|
|
19
|
+
@scope.instance_variable_set(var, nil) unless var == '@staticmatic'
|
20
|
+
end
|
21
|
+
html = generate_html_from_template_source(File.read(full_file_path))
|
22
|
+
|
23
|
+
@layout = determine_layout(source_dir)
|
24
|
+
rescue StaticMatic::TemplateError => e
|
25
|
+
raise e # re-raise inline errors
|
26
|
+
rescue Exception => e
|
27
|
+
raise StaticMatic::TemplateError.new(full_file_path, e)
|
28
|
+
end
|
29
|
+
|
30
|
+
html
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate_html_with_layout(source, source_dir = '')
|
34
|
+
@current_page = File.join(source_dir, "#{source}.html")
|
35
|
+
@current_file_stack.unshift(File.join(source_dir, "#{source}.haml"))
|
36
|
+
begin
|
37
|
+
template_content = generate_html(source, source_dir)
|
38
|
+
@layout = determine_layout(source_dir)
|
39
|
+
generate_html_from_template_source(source_for_layout) { template_content }
|
40
|
+
rescue Exception => e
|
41
|
+
render_rescue_from_error(e)
|
42
|
+
ensure
|
43
|
+
@current_page = nil
|
44
|
+
@current_file_stack.shift
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def generate_partial(name, options = {})
|
49
|
+
partial_dir, partial_name = File.dirname(self.current_file), name # default relative to current file
|
50
|
+
partial_dir, partial_name = File.split(name) if name.index('/') # contains a path so it's absolute from src/pages dir
|
51
|
+
partial_name = "_#{partial_name}.haml"
|
52
|
+
|
53
|
+
partial_path = File.join(@src_dir, 'pages', partial_dir, partial_name)
|
54
|
+
unless File.exists?(partial_path)
|
55
|
+
# couldn't find it in the pages subdirectory tree so try old way (ignoring the path)
|
56
|
+
partial_dir = 'partials'
|
57
|
+
partial_name = "#{File.basename(name)}.haml"
|
58
|
+
partial_path = File.join(@src_dir, partial_dir, partial_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
if File.exists?(partial_path)
|
62
|
+
partial_rel_path = "/#{partial_dir}/#{partial_name}".gsub(/\/+/, '/')
|
63
|
+
@current_file_stack.unshift(partial_rel_path)
|
64
|
+
begin
|
65
|
+
generate_html_from_template_source(File.read(partial_path), options)
|
66
|
+
rescue Exception => e
|
67
|
+
raise StaticMatic::TemplateError.new(partial_path, e)
|
68
|
+
ensure
|
69
|
+
@current_file_stack.shift
|
70
|
+
end
|
71
|
+
else
|
72
|
+
raise StaticMatic::Error.new("", name, "Partial not found")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def generate_css(source, source_dir = '')
|
77
|
+
full_file_path = File.join(@src_dir, 'stylesheets', source_dir, "#{source}.sass")
|
78
|
+
begin
|
79
|
+
sass_options = { :load_paths => [ File.join(@src_dir, 'stylesheets') ] }.merge(self.configuration.sass_options)
|
80
|
+
stylesheet = Sass::Engine.new(File.read(full_file_path), sass_options)
|
81
|
+
stylesheet.to_css
|
82
|
+
rescue Exception => e
|
83
|
+
render_rescue_from_error(StaticMatic::TemplateError.new(full_file_path, e))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Generates html from the passed source string
|
88
|
+
#
|
89
|
+
# generate_html_from_template_source("%h1 Welcome to My Site") -> "<h1>Welcome to My Site</h1>"
|
90
|
+
#
|
91
|
+
# Pass a block containing a string to yield within in the passed source:
|
92
|
+
#
|
93
|
+
# generate_html_from_template_source("content:\n= yield") { "blah" } -> "content: blah"
|
94
|
+
#
|
95
|
+
def generate_html_from_template_source(source, options = {})
|
96
|
+
html = Haml::Engine.new(source, self.configuration.haml_options.merge(options))
|
97
|
+
locals = options[:locals] || {}
|
98
|
+
html.render(@scope, locals) { yield }
|
99
|
+
end
|
100
|
+
|
101
|
+
def determine_layout(dir = '')
|
102
|
+
layout_name = "application"
|
103
|
+
|
104
|
+
if @scope.instance_variable_get("@layout")
|
105
|
+
layout_name = @scope.instance_variable_get("@layout")
|
106
|
+
elsif dir
|
107
|
+
dirs = dir.split("/")
|
108
|
+
dir_layout_name = dirs[1]
|
109
|
+
|
110
|
+
if layout_exists?(dir_layout_name)
|
111
|
+
layout_name = dir_layout_name
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
layout_name
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns a raw template name from a source file path:
|
119
|
+
# source_template_from_path("/path/to/site/src/stylesheets/application.sass") -> "application"
|
120
|
+
def source_template_from_path(path)
|
121
|
+
file_dir, file_name = File.split(path)
|
122
|
+
file_name.chomp!(File.extname(file_name))
|
123
|
+
[ file_dir, file_name ]
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module StaticMatic::RescueMixin
|
2
|
+
# Pass back an error template for the given exception
|
3
|
+
def render_rescue_from_error(exception)
|
4
|
+
rescue_template = (exception.is_a?(StaticMatic::TemplateError)) ? "template" : "default"
|
5
|
+
|
6
|
+
error_template_path = File.expand_path(File.dirname(__FILE__) + "/../templates/rescues/#{rescue_template}.haml")
|
7
|
+
|
8
|
+
@scope.instance_variable_set("@exception", exception)
|
9
|
+
|
10
|
+
generate_html_from_template_source(File.read(error_template_path))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module StaticMatic::SetupMixin
|
2
|
+
|
3
|
+
def setup
|
4
|
+
Dir.mkdir(@base_dir) unless File.exists?(@base_dir)
|
5
|
+
|
6
|
+
StaticMatic::BASE_DIRS.each do |directory|
|
7
|
+
directory = "#{@base_dir}/#{directory}"
|
8
|
+
if !File.exists?(directory)
|
9
|
+
Dir.mkdir(directory)
|
10
|
+
puts "created #{directory}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
StaticMatic::TEMPLATES.each do |template, destination|
|
15
|
+
copy_file("#{@templates_dir}/#{template}", "#{@src_dir}/#{destination}")
|
16
|
+
end
|
17
|
+
|
18
|
+
puts "Done"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module StaticMatic
|
2
|
+
class Server < Mongrel::HttpHandler
|
3
|
+
@@file_only_methods = ["GET","HEAD"]
|
4
|
+
|
5
|
+
def initialize(staticmatic)
|
6
|
+
@files = Mongrel::DirHandler.new(staticmatic.site_dir, false)
|
7
|
+
@staticmatic = staticmatic
|
8
|
+
end
|
9
|
+
|
10
|
+
def process(request, response)
|
11
|
+
@staticmatic.load_helpers
|
12
|
+
path_info = request.params[Mongrel::Const::PATH_INFO]
|
13
|
+
get_or_head = @@file_only_methods.include? request.params[Mongrel::Const::REQUEST_METHOD]
|
14
|
+
|
15
|
+
file_dir, file_name, file_ext = expand_path(path_info)
|
16
|
+
|
17
|
+
# remove stylesheets/ directory if applicable
|
18
|
+
file_dir.gsub!(/^\/stylesheets\/?/, "")
|
19
|
+
|
20
|
+
file_dir = CGI::unescape(file_dir)
|
21
|
+
file_name = CGI::unescape(file_name)
|
22
|
+
|
23
|
+
if file_ext && file_ext.match(/html|css/)
|
24
|
+
response.start(200) do |head, out|
|
25
|
+
head["Content-Type"] = "text/#{file_ext}"
|
26
|
+
output = ""
|
27
|
+
|
28
|
+
if @staticmatic.template_exists?(file_name, file_dir) && !(File.basename(file_name) =~ /^\_/)
|
29
|
+
|
30
|
+
begin
|
31
|
+
if file_ext == "css"
|
32
|
+
output = @staticmatic.generate_css(file_name, file_dir)
|
33
|
+
else
|
34
|
+
output = @staticmatic.generate_html_with_layout(file_name, file_dir)
|
35
|
+
end
|
36
|
+
rescue StaticMatic::Error => e
|
37
|
+
output = e.message
|
38
|
+
end
|
39
|
+
else
|
40
|
+
if @files.can_serve(path_info)
|
41
|
+
@files.process(request,response)
|
42
|
+
else
|
43
|
+
output = "File not Found"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
out.write output
|
47
|
+
end
|
48
|
+
else
|
49
|
+
# try to serve static file from site dir
|
50
|
+
if @files.can_serve(path_info)
|
51
|
+
@files.process(request,response)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def expand_path(path_info)
|
57
|
+
dirname, basename = File.split(path_info)
|
58
|
+
|
59
|
+
extname = File.extname(path_info).sub(/^\./, '')
|
60
|
+
filename = basename.chomp(".#{extname}")
|
61
|
+
|
62
|
+
if extname.empty?
|
63
|
+
dir = File.join(dirname, filename)
|
64
|
+
is_dir = path_info[-1, 1] == '/' || (@staticmatic.template_directory?(dir) && !@staticmatic.template_exists?(filename, dirname))
|
65
|
+
if is_dir
|
66
|
+
dirname = dir
|
67
|
+
filename = 'index'
|
68
|
+
end
|
69
|
+
extname = 'html'
|
70
|
+
end
|
71
|
+
|
72
|
+
[ dirname, filename, extname ]
|
73
|
+
end
|
74
|
+
|
75
|
+
class << self
|
76
|
+
# Starts the StaticMatic preview server
|
77
|
+
def start(staticmatic)
|
78
|
+
port = staticmatic.configuration.preview_server_port || 3000
|
79
|
+
|
80
|
+
host = staticmatic.configuration.preview_server_host || ""
|
81
|
+
|
82
|
+
config = Mongrel::Configurator.new :host => host do
|
83
|
+
puts "Running Preview of #{staticmatic.base_dir} on #{host}:#{port}"
|
84
|
+
listener :port => port do
|
85
|
+
uri "/", :handler => Server.new(staticmatic)
|
86
|
+
end
|
87
|
+
trap("INT") { stop }
|
88
|
+
run
|
89
|
+
end
|
90
|
+
config.join
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class StaticMatic::TemplateError < StandardError
|
2
|
+
SOURCE_CODE_RADIUS = 3
|
3
|
+
|
4
|
+
attr_reader :original_exception, :backtrace
|
5
|
+
|
6
|
+
def initialize(template, original_exception)
|
7
|
+
@template, @original_exception = template, original_exception
|
8
|
+
@backtrace = original_exception.backtrace
|
9
|
+
|
10
|
+
@source = File.read(template)
|
11
|
+
end
|
12
|
+
|
13
|
+
# TODO: Replace 'haml|sass' with any registered engines
|
14
|
+
def line_number
|
15
|
+
@line_number ||= $2 if backtrace.find { |line| line =~ /\((haml|sass)\)\:(\d+)/ }
|
16
|
+
end
|
17
|
+
|
18
|
+
def filename
|
19
|
+
@template
|
20
|
+
end
|
21
|
+
|
22
|
+
def source_extract(indentation = 0)
|
23
|
+
return unless num = line_number
|
24
|
+
num = num.to_i
|
25
|
+
|
26
|
+
source_code = @source.split("\n")
|
27
|
+
|
28
|
+
start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
|
29
|
+
end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
|
30
|
+
|
31
|
+
indent = ' ' * indentation
|
32
|
+
line_counter = start_on_line
|
33
|
+
return unless source_code = source_code[start_on_line..end_on_line]
|
34
|
+
|
35
|
+
source_code.collect do |line|
|
36
|
+
line_counter += 1
|
37
|
+
"#{indent}#{line_counter}: #{line}\n"
|
38
|
+
end.to_s
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
%h1 StaticMatic!
|
@@ -0,0 +1,18 @@
|
|
1
|
+
%html
|
2
|
+
%head
|
3
|
+
%style{:type => "text/css"}
|
4
|
+
body { font-family: helvetica, verdana, arial; font-size: 10pt;}
|
5
|
+
%body
|
6
|
+
%h1
|
7
|
+
= @exception.class.name
|
8
|
+
in
|
9
|
+
= @exception.filename
|
10
|
+
|
11
|
+
%p= @exception.original_exception.message
|
12
|
+
|
13
|
+
= @exception.source_extract.gsub(/\n/, "<br/>")
|
14
|
+
|
15
|
+
|
16
|
+
%h2 Backtrace
|
17
|
+
|
18
|
+
= @exception.backtrace.join("<br/>")
|
data/test/base_test.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/test_helper"
|
2
|
+
|
3
|
+
class StaticMatic::BaseTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
setup_staticmatic
|
6
|
+
end
|
7
|
+
|
8
|
+
should "set initial configuration settings" do
|
9
|
+
assert_equal true, @staticmatic.configuration.use_extensions_for_page_links
|
10
|
+
assert_equal 3000, @staticmatic.configuration.preview_server_port
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/test_helper"
|
2
|
+
|
3
|
+
class StaticMatic::HelpersTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
setup_staticmatic
|
6
|
+
end
|
7
|
+
|
8
|
+
should "include custom helper" do
|
9
|
+
content = @staticmatic.generate_html_with_layout("index")
|
10
|
+
assert_match "Hello, Steve!", content
|
11
|
+
end
|
12
|
+
end
|