mattt-staticmatic 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ == 0.10.0 2009-01-01
2
+
3
+ * Refactoring for forthcoming improvements
4
+ * Improved Error Reporting
5
+ * More useful error pages
6
+ * Removed Haml specific error handling
@@ -0,0 +1,24 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ bin/staticmatic
6
+ lib/staticmatic.rb
7
+ lib/staticmatic/base.rb
8
+ lib/staticmatic/configuration.rb
9
+ lib/staticmatic/error.rb
10
+ lib/staticmatic/helpers.rb
11
+ lib/staticmatic/mixins/build.rb
12
+ lib/staticmatic/mixins/helpers.rb
13
+ lib/staticmatic/mixins/render.rb
14
+ lib/staticmatic/mixins/server.rb
15
+ lib/staticmatic/mixins/setup.rb
16
+ lib/staticmatic/server.rb
17
+ lib/staticmatic/templates/default/application.haml
18
+ lib/staticmatic/templates/default/application.sass
19
+ lib/staticmatic/templates/default/index.haml
20
+ lib/staticmatic/templates/default/index.haml
21
+ lib/staticmatic/templates/rescues/default.haml
22
+ lib/staticmatic/templates/rescues/template.haml
23
+ lib/staticmatic/template_error.rb
24
+ lib/staticmatic/mixins/rescue.rb
@@ -0,0 +1,50 @@
1
+ # StaticMatic
2
+
3
+ *For information on Haml & Sass please see [haml.hamptoncatlin.com](http://haml.hamptoncatlin.com)*.
4
+
5
+ ## What's it all about?
6
+
7
+ CMS is overrated. A lot of the time, clients want us to do what we do
8
+ best - well designed pages with structured, accessible and maintainable markup & styling.
9
+
10
+ CMSs are often perfect for this, but sometimes they can be restrictive and more cumbersome
11
+ than just working with good ol' source code. At the same time we want our code to be
12
+ structured, DRY and flexible.
13
+
14
+ Enter **StaticMatic**.
15
+
16
+ ## Usage
17
+
18
+ StaticMatic will set up a basic site structure for you with this command:
19
+
20
+ staticmatic setup <directory>
21
+
22
+ After this command you'll have the following files:
23
+
24
+ <directory>/
25
+ site/
26
+ images/
27
+ stylesheets/
28
+ javascripts/
29
+ src/
30
+ helpers/
31
+ layouts/
32
+ application.haml
33
+ pages/
34
+ index.haml
35
+ stylesheets/
36
+ application.sass
37
+
38
+ StaticMatic sets you up with a sample layout, stylesheet and page file. Once you've
39
+ edited the pages and stylesheets, you can generate the static site:
40
+
41
+ staticmatic build <directory>
42
+
43
+ All of the pages are parsed and wrapped up in application.haml and put into the site directory.
44
+
45
+ ## Templates
46
+
47
+ StaticMatic adds a few helpers to the core Haml helpers:
48
+
49
+ = link 'Title', 'url'
50
+ = img 'my_image.jpg'
@@ -0,0 +1,31 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen hoe].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/staticmatic'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('staticmatic', StaticMatic::VERSION) do |p|
7
+ p.developer('Stephen Bartholomew', 'steve@curve21.com')
8
+ p.rubyforge_name = p.name
9
+ p.extra_deps = [
10
+ ['haml','>= 2.0'],
11
+ ['mongrel','>= 1.0']
12
+ ]
13
+ p.extra_dev_deps = [
14
+ ['newgem', ">= #{::Newgem::VERSION}"]
15
+ ]
16
+
17
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
18
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
19
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
20
+ p.rsync_args = '-av --delete --ignore-errors'
21
+ end
22
+
23
+ require 'newgem/tasks' # load /tasks/*.rake
24
+ Dir['tasks/**/*.rake'].each { |t| load t }
25
+
26
+
27
+ desc "Run all unit tests"
28
+ Rake::TestTask.new(:test) do |t|
29
+ t.test_files = Dir.glob("test/*_test.rb")
30
+ t.verbose = true
31
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + '/../lib/staticmatic'
4
+
5
+ command = ARGV[0]
6
+ directory = ARGV[1]
7
+
8
+ if !command || !directory
9
+ puts "Usage: #{$0} <build|setup|preview> <directory>"
10
+ exit
11
+ end
12
+
13
+ configuration = StaticMatic::Configuration.new
14
+
15
+ config_file = "#{directory}/src/configuration.rb"
16
+
17
+ if File.exists?(config_file)
18
+ config = File.read(config_file)
19
+ eval(config)
20
+ end
21
+
22
+ staticmatic = StaticMatic::Base.new(directory, configuration)
23
+ staticmatic.run(command)
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'haml'
3
+ require 'sass'
4
+ require 'mongrel'
5
+ require 'fileutils'
6
+
7
+ module StaticMatic
8
+ VERSION = '0.10.1'
9
+ end
10
+
11
+ ["render", "build", "setup", "server", "helpers", "rescue"].each do |mixin|
12
+ require File.join(File.dirname(__FILE__), "staticmatic", "mixins", mixin)
13
+ end
14
+
15
+ ["base", "configuration", "error", "server", "helpers", "template_error"].each do |lib|
16
+ require File.join(File.dirname(__FILE__), "staticmatic", lib)
17
+ end
18
+
19
+ Haml::Helpers.class_eval("include StaticMatic::Helpers")
20
+
@@ -0,0 +1,87 @@
1
+ module StaticMatic
2
+ # Directories generated for a new site setup
3
+ BASE_DIRS = %w{
4
+ site/
5
+ site/stylesheets
6
+ site/images
7
+ site/javascripts
8
+ src/
9
+ src/pages/
10
+ src/layouts
11
+ src/stylesheets
12
+ src/helpers
13
+ }
14
+
15
+ # Templates for setup and their location
16
+ TEMPLATES = {
17
+ 'application.haml' => 'layouts',
18
+ 'application.sass' => 'stylesheets',
19
+ 'index.haml' => 'pages'
20
+ }
21
+
22
+ class Base
23
+
24
+ include StaticMatic::RenderMixin
25
+ include StaticMatic::BuildMixin
26
+ include StaticMatic::SetupMixin
27
+ include StaticMatic::HelpersMixin
28
+ include StaticMatic::ServerMixin
29
+ include StaticMatic::RescueMixin
30
+
31
+ attr_accessor :configuration
32
+ attr_reader :current_page, :src_dir, :site_dir
33
+
34
+ def current_file
35
+ @current_file_stack[0] || ""
36
+ end
37
+
38
+ def initialize(base_dir, configuration = Configuration.new)
39
+ @configuration = configuration
40
+ @current_page = nil
41
+ @current_file_stack = []
42
+ @base_dir = base_dir
43
+ @src_dir = "#{@base_dir}/src"
44
+ @site_dir = "#{@base_dir}/site"
45
+ @templates_dir = File.dirname(__FILE__) + '/templates/default/'
46
+ @layout = "application"
47
+ @scope = Object.new
48
+ @scope.instance_variable_set("@staticmatic", self)
49
+ load_helpers
50
+ end
51
+
52
+ def base_dir
53
+ @base_dir
54
+ end
55
+
56
+ def run(command)
57
+ if %w(build setup preview).include?(command)
58
+ send(command)
59
+ else
60
+ puts "#{command} is not a valid StaticMatic command"
61
+ end
62
+ end
63
+
64
+ # TODO: DRY this _exists? section up
65
+ def template_exists?(name, dir = '')
66
+ File.exists?(File.join(@src_dir, 'pages', dir, "#{name}.haml")) || File.exists?(File.join(@src_dir, 'stylesheets', "#{name}.sass"))
67
+ end
68
+
69
+ def layout_exists?(name)
70
+ File.exists? full_layout_path(name)
71
+ end
72
+
73
+ def template_directory?(path)
74
+ File.directory?(File.join(@src_dir, 'pages', path))
75
+ end
76
+
77
+ def full_layout_path(name)
78
+ "#{@src_dir}/layouts/#{name}.haml"
79
+ end
80
+
81
+ class << self
82
+ def base_dirs
83
+ StaticMatic::BASE_DIRS
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,16 @@
1
+ module StaticMatic
2
+ class Configuration
3
+ attr_accessor :preview_server_port
4
+
5
+ attr_accessor :preview_server_host
6
+
7
+ attr_accessor :use_extensions_for_page_links
8
+ attr_accessor :sass_options
9
+
10
+ def initialize
11
+ self.preview_server_port = 3000
12
+ self.use_extensions_for_page_links = true
13
+ self.sass_options = {}
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module StaticMatic
2
+ class Error < StandardError
3
+ attr_reader :line
4
+
5
+ attr_reader :filename
6
+
7
+ def initialize(lineno, filename, message)
8
+ @line = lineno
9
+ @filename = filename
10
+ @message = message
11
+ end
12
+
13
+ def message
14
+ "#{@filename}, line #{@line}: #{@message}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,197 @@
1
+ module StaticMatic
2
+ module Helpers
3
+ self.extend self
4
+
5
+ # Generates links to all stylesheets in the source directory
6
+ # = stylesheets
7
+ # or specific stylesheets in a specific order
8
+ # = stylesheets :reset, :application
9
+ # Can also pass options hash in at the end so you can specify :media => :print
10
+ def stylesheets(*params)
11
+ options = {}
12
+ if params.last.is_a?(Hash)
13
+ options = params.last
14
+ params.slice!(-1, 1)
15
+ end
16
+ options[:media] = 'all' unless options.has_key?(:media)
17
+ options[:rel] = 'stylesheet'; options[:type] = 'text/css'
18
+
19
+ relative_path = current_page_relative_path
20
+
21
+ output = ""
22
+ if params.length == 0
23
+ # no specific files requested so include all in no particular order
24
+ stylesheet_dir = File.join(@staticmatic.src_dir, 'stylesheets')
25
+ stylesheet_directories = Dir[File.join(stylesheet_dir, '**','*.sass')]
26
+
27
+ # Bit of a hack here - adds any stylesheets that exist in the site/ dir that haven't been generated from source sass
28
+ Dir[File.join(@staticmatic.site_dir, 'stylesheets', '*.css')].each do |filename|
29
+ search_filename = File.basename(filename).chomp(File.extname(filename))
30
+
31
+ already_included = false
32
+ stylesheet_directories.each do |path|
33
+ if File.basename(path).include?(search_filename)
34
+ already_included = true
35
+ break
36
+ end
37
+ end
38
+
39
+ stylesheet_directories << filename unless already_included
40
+ end
41
+
42
+ stylesheet_directories.each do |path|
43
+ filename_without_extension = File.basename(path).chomp(File.extname(path))
44
+
45
+ options[:href] = "#{relative_path}stylesheets/#{filename_without_extension}.css"
46
+ output << tag(:link, options)
47
+ end
48
+ else
49
+ #specific files requested and in a specific order
50
+ params.each do |file|
51
+ if File.exist?(File.join(@staticmatic.src_dir, 'stylesheets', "#{file}.sass")) ||
52
+ File.exist?(File.join(@staticmatic.site_dir, 'stylesheets', "#{file}.css"))
53
+ options[:href] = "#{relative_path}stylesheets/#{file}.css"
54
+ output << tag(:link, options)
55
+ end
56
+ end
57
+ end
58
+
59
+ output
60
+ end
61
+
62
+ # Generate javascript source tags for the specified files
63
+ #
64
+ # javascripts('test') -> <script language="javascript" src="javascripts/test.js"></script>
65
+ #
66
+ def javascripts(*files)
67
+ relative_path = current_page_relative_path
68
+
69
+ output = ""
70
+ files.each do |file|
71
+ file_str = file.to_s
72
+ src = file_str.match(%r{^((\.\.?)?/|https?://)}) ? file_str : "#{relative_path}javascripts/#{file_str}.js"
73
+ output << tag(:script, :language => 'javascript', :src => src, :type => "text/javascript") { "" }
74
+ end
75
+ output
76
+ end
77
+
78
+ # Generates a form text field
79
+ #
80
+ def text_field(name, value, options = {})
81
+ options.merge!(:type => "text", :name => name, :value => value)
82
+ tag(:input, options)
83
+ end
84
+
85
+ # Generate a form textarea
86
+ #
87
+ def text_area(name, value, options = {})
88
+ options.merge!(:name => name)
89
+ tag(:textarea, options) { value }
90
+ end
91
+
92
+ # Generate an HTML link
93
+ #
94
+ # If only the title is passed, it will automatically
95
+ # create a link from this value:
96
+ #
97
+ # link('Test') -> <a href="test.html">Test</a>
98
+ #
99
+ def link(title, href = "", options = {})
100
+ if href.is_a?(Hash)
101
+ options = href
102
+ href = ""
103
+ end
104
+
105
+ if href.nil? || href.strip.length < 1
106
+ path_prefix = ''
107
+ if title.match(/^(\.\.?)?\//)
108
+ # starts with relative path so strip it off and prepend it to the urlified title
109
+ path_prefix_match = title.match(/^[^\s]*\//)
110
+ path_prefix = path_prefix_match[0] if path_prefix_match
111
+ title = title[path_prefix.length, title.length]
112
+ end
113
+ href = path_prefix + urlify(title) + ".html"
114
+ end
115
+
116
+ options[:href] = "#{current_page_relative_path(href)}#{href}"
117
+
118
+ local_page = (options[:href].match(/^(\#|.+?\:)/) == nil)
119
+ unless @staticmatic.configuration.use_extensions_for_page_links || !local_page
120
+ options[:href].chomp!(".html")
121
+ options[:href].chomp!("index") if options[:href][-5, 5] == 'index'
122
+ end
123
+
124
+ tag(:a, options) { title }
125
+ end
126
+ alias link_to link
127
+
128
+ # Generates an image tag always relative to the current page unless absolute path or http url specified.
129
+ #
130
+ # img('test_image.gif') -> <img src="/images/test_image.gif" alt="Test image"/>
131
+ # img('contact/test_image.gif') -> <img src="/images/contact/test_image.gif" alt="Test image"/>
132
+ # img('http://localhost/test_image.gif') -> <img src="http://localhost/test_image.gif" alt="Test image"/>
133
+ def img(name, options = {})
134
+ options[:src] = name.match(%r{^((\.\.?)?/|https?://)}) ? name : "#{current_page_relative_path}images/#{name}"
135
+ options[:alt] ||= name.split('/').last.split('.').first.capitalize.gsub(/_|-/, ' ')
136
+ tag :img, options
137
+ end
138
+
139
+ # Generates HTML tags:
140
+ #
141
+ # tag(:br) -> <br/>
142
+ # tag(:a, :href => 'test.html') { "Test" } -> <a href="test.html">Test</a>
143
+ #
144
+ def tag(name, options = {}, &block)
145
+ options[:id] ||= options[:name] if options[:name]
146
+ output = "<#{name}"
147
+ options.keys.sort { |a, b| a.to_s <=> b.to_s }.each do |key|
148
+ output << " #{key}=\"#{options[key]}\"" if options[key]
149
+ end
150
+
151
+ if block_given?
152
+ output << ">"
153
+ output << yield
154
+ output << "</#{name}>"
155
+ else
156
+ output << "/>"
157
+ end
158
+ output
159
+ end
160
+
161
+ # Generates a URL friendly string from the value passed:
162
+ #
163
+ # "We love Haml" -> "we_love_haml"
164
+ # "Elf & Ham" -> "elf_and_ham"
165
+ # "Stephen's gem" -> "stephens_gem"
166
+ #
167
+ def urlify(string)
168
+ string.tr(" ", "_").
169
+ sub("&", "and").
170
+ sub("@", "at").
171
+ tr("^A-Za-z0-9_", "").
172
+ sub(/_{2,}/, "_").
173
+ downcase
174
+ end
175
+
176
+ # Include a partial template
177
+ def partial(name, options = {})
178
+ @staticmatic.generate_partial(name, options)
179
+ end
180
+
181
+ def current_page
182
+ @staticmatic.current_page
183
+ end
184
+
185
+ private
186
+
187
+ def current_page_relative_path(current_path = nil)
188
+ if current_path.nil? || current_path.match(/^((\.\.?)?\/|\#|.+?\:)/) == nil
189
+ current_page_depth = current_page.split('/').length - 2;
190
+ (current_page_depth > 0) ? ([ '..' ] * current_page_depth).join('/') + '/' : ''
191
+ else
192
+ ''
193
+ end
194
+ end
195
+
196
+ end
197
+ end
@@ -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
+
98
+ html.render(@scope, options) { 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,6 @@
1
+ module StaticMatic::ServerMixin
2
+ def preview
3
+ puts "StaticMatic Preview Server Starting..."
4
+ StaticMatic::Server.start(self)
5
+ end
6
+ 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,7 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title StaticMatic
5
+ = stylesheets
6
+ %body
7
+ = yield
@@ -0,0 +1,4 @@
1
+ body
2
+ :font
3
+ :family Verdana
4
+ :size 10pt
@@ -0,0 +1 @@
1
+ %h1 StaticMatic!
@@ -0,0 +1,7 @@
1
+ %h1= @exception.class.name
2
+
3
+ %p= @exception.message
4
+
5
+ %h2 Stack Trace
6
+
7
+ = @exception.backtrace.join("<br/>")
@@ -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/>")
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'stringio'
3
+ require 'test/unit'
4
+
5
+ require File.dirname(__FILE__) + '/../lib/staticmatic'
6
+
7
+ TEST_SITE_PATH = File.join(File.dirname(__FILE__), "sandbox", "test_site")
8
+
9
+ class Test::Unit::TestCase
10
+ def self.should(description, &block)
11
+ test_name = "test_should_#{description.gsub(/[\s]/,'_')}".to_sym
12
+ raise "#{test_name} is already defined in #{self}" if self.instance_methods.include?(test_name.to_s)
13
+ define_method(test_name, &block)
14
+ end
15
+ end
16
+
17
+ def setup_staticmatic
18
+ @staticmatic = StaticMatic::Base.new(TEST_SITE_PATH)
19
+ end
20
+
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mattt-staticmatic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.10.1
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Bartholomew
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-29 00:00:00 -08:00
13
+ default_executable: staticmatic
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: haml
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "2.0"
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: mongrel
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: "1.0"
32
+ version:
33
+ - !ruby/object:Gem::Dependency
34
+ name: newgem
35
+ version_requirement:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2.3
41
+ version:
42
+ - !ruby/object:Gem::Dependency
43
+ name: hoe
44
+ version_requirement:
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.8.3
50
+ version:
51
+ description:
52
+ email:
53
+ - steve@curve21.com
54
+ executables:
55
+ - staticmatic
56
+ extensions: []
57
+
58
+ extra_rdoc_files:
59
+ - History.txt
60
+ - Manifest.txt
61
+ files:
62
+ - History.txt
63
+ - Manifest.txt
64
+ - README.markdown
65
+ - Rakefile
66
+ - bin/staticmatic
67
+ - lib/staticmatic.rb
68
+ - lib/staticmatic/base.rb
69
+ - lib/staticmatic/configuration.rb
70
+ - lib/staticmatic/error.rb
71
+ - lib/staticmatic/helpers.rb
72
+ - lib/staticmatic/mixins/build.rb
73
+ - lib/staticmatic/mixins/helpers.rb
74
+ - lib/staticmatic/mixins/render.rb
75
+ - lib/staticmatic/mixins/server.rb
76
+ - lib/staticmatic/mixins/setup.rb
77
+ - lib/staticmatic/server.rb
78
+ - lib/staticmatic/templates/default/application.haml
79
+ - lib/staticmatic/templates/default/application.sass
80
+ - lib/staticmatic/templates/default/index.haml
81
+ - lib/staticmatic/templates/rescues/default.haml
82
+ - lib/staticmatic/templates/rescues/template.haml
83
+ - lib/staticmatic/template_error.rb
84
+ - lib/staticmatic/mixins/rescue.rb
85
+ - test/test_helper.rb
86
+ has_rdoc: true
87
+ homepage:
88
+ post_install_message:
89
+ rdoc_options:
90
+ - --main
91
+ - README.markdown
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: "0"
99
+ version:
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: "0"
105
+ version:
106
+ requirements: []
107
+
108
+ rubyforge_project: staticmatic
109
+ rubygems_version: 1.2.0
110
+ signing_key:
111
+ specification_version: 2
112
+ summary: The Lightweight Static Content framework
113
+ test_files:
114
+ - test/test_helper.rb