staticmatic2 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/Gemfile +12 -0
  2. data/Gemfile.lock +27 -0
  3. data/LICENSE +20 -0
  4. data/README.markdown +107 -0
  5. data/Rakefile +45 -0
  6. data/VERSION.yml +5 -0
  7. data/bin/staticmatic +140 -0
  8. data/lib/staticmatic.rb +25 -0
  9. data/lib/staticmatic/base.rb +123 -0
  10. data/lib/staticmatic/compass.rb +5 -0
  11. data/lib/staticmatic/compass/app_integration.rb +18 -0
  12. data/lib/staticmatic/compass/configuration_defaults.rb +44 -0
  13. data/lib/staticmatic/compass/installer.rb +15 -0
  14. data/lib/staticmatic/configuration.rb +20 -0
  15. data/lib/staticmatic/deployers/aws-s3.rb +71 -0
  16. data/lib/staticmatic/deployers/config/amazon.yml +7 -0
  17. data/lib/staticmatic/error.rb +17 -0
  18. data/lib/staticmatic/helpers.rb +12 -0
  19. data/lib/staticmatic/helpers/assets_helper.rb +116 -0
  20. data/lib/staticmatic/helpers/current_path_helper.rb +22 -0
  21. data/lib/staticmatic/helpers/form_helper.rb +23 -0
  22. data/lib/staticmatic/helpers/render_helper.rb +13 -0
  23. data/lib/staticmatic/helpers/tag_helper.rb +35 -0
  24. data/lib/staticmatic/helpers/url_helper.rb +59 -0
  25. data/lib/staticmatic/mixins/build.rb +77 -0
  26. data/lib/staticmatic/mixins/helpers.rb +15 -0
  27. data/lib/staticmatic/mixins/render.rb +153 -0
  28. data/lib/staticmatic/mixins/rescue.rb +12 -0
  29. data/lib/staticmatic/mixins/server.rb +7 -0
  30. data/lib/staticmatic/mixins/setup.rb +16 -0
  31. data/lib/staticmatic/server.rb +86 -0
  32. data/lib/staticmatic/template_error.rb +44 -0
  33. data/lib/staticmatic/templates/rescues/default.haml +7 -0
  34. data/lib/staticmatic/templates/rescues/template.haml +18 -0
  35. data/spec/base_spec.rb +13 -0
  36. data/spec/compass_integration_spec.rb +27 -0
  37. data/spec/helpers/asset_helper_spec.rb +43 -0
  38. data/spec/helpers/custom_helper_spec.rb +18 -0
  39. data/spec/render_spec.rb +44 -0
  40. data/spec/rescue_spec.rb +36 -0
  41. data/spec/sandbox/test_site/config/compass.rb +1 -0
  42. data/spec/sandbox/test_site/config/site.rb +0 -0
  43. data/spec/sandbox/test_site/src/helpers/application_helper.rb +5 -0
  44. data/spec/sandbox/test_site/src/layouts/alternate_layout.haml +3 -0
  45. data/spec/sandbox/test_site/src/layouts/default.haml +7 -0
  46. data/spec/sandbox/test_site/src/layouts/projects.haml +1 -0
  47. data/spec/sandbox/test_site/src/pages/hello_world.erb +1 -0
  48. data/spec/sandbox/test_site/src/pages/index.haml +5 -0
  49. data/spec/sandbox/test_site/src/pages/layout_test.haml +2 -0
  50. data/spec/sandbox/test_site/src/pages/page_one.haml +3 -0
  51. data/spec/sandbox/test_site/src/pages/page_two.haml +2 -0
  52. data/spec/sandbox/test_site/src/pages/page_with_error.haml +5 -0
  53. data/spec/sandbox/test_site/src/pages/page_with_partial_error.haml +3 -0
  54. data/spec/sandbox/test_site/src/partials/menu.haml +1 -0
  55. data/spec/sandbox/test_site/src/partials/partial_with_error.haml +1 -0
  56. data/spec/sandbox/test_site/src/stylesheets/application.sass +5 -0
  57. data/spec/sandbox/test_site/src/stylesheets/css_with_error.sass +5 -0
  58. data/spec/sandbox/test_site/src/stylesheets/nested/a_nested_stylesheet.sass +0 -0
  59. data/spec/sandbox/test_site/src/stylesheets/partials/_forms.sass +2 -0
  60. data/spec/sandbox/test_site/src/stylesheets/sassy.scss +12 -0
  61. data/spec/server_spec.rb +11 -0
  62. data/spec/setup_spec.rb +22 -0
  63. data/spec/spec_helper.rb +14 -0
  64. data/spec/template_error_spec.rb +23 -0
  65. data/staticmatic.gemspec +158 -0
  66. data/website/Gemfile +1 -0
  67. data/website/config/site.rb +17 -0
  68. data/website/site/docs/compass_integration.html +70 -0
  69. data/website/site/docs/getting_started.html +49 -0
  70. data/website/site/docs/helpers.html +22 -0
  71. data/website/site/images/bycurve21.gif +0 -0
  72. data/website/site/images/curve21.jpg +0 -0
  73. data/website/site/images/homepage-build.jpg +0 -0
  74. data/website/site/images/homepage-previewing.jpg +0 -0
  75. data/website/site/images/homepage-templating.jpg +0 -0
  76. data/website/site/stylesheets/ie.css +5 -0
  77. data/website/site/stylesheets/print.css +372 -0
  78. data/website/site/stylesheets/screen.css +488 -0
  79. data/website/src/helpers/content_helper.rb +10 -0
  80. data/website/src/layouts/default.haml +15 -0
  81. data/website/src/pages/development.haml +9 -0
  82. data/website/src/pages/docs/_menu.haml +4 -0
  83. data/website/src/pages/docs/_requires_prerelease.haml +4 -0
  84. data/website/src/pages/docs/compass_integration.haml +54 -0
  85. data/website/src/pages/docs/getting_started.haml +31 -0
  86. data/website/src/pages/docs/helpers.haml +1 -0
  87. data/website/src/pages/index.haml +27 -0
  88. data/website/src/stylesheets/_base.scss +43 -0
  89. data/website/src/stylesheets/_defaults.scss +260 -0
  90. data/website/src/stylesheets/ie.scss +10 -0
  91. data/website/src/stylesheets/print.scss +33 -0
  92. data/website/src/stylesheets/screen.scss +73 -0
  93. metadata +238 -0
@@ -0,0 +1,77 @@
1
+ module StaticMatic::BuildMixin
2
+
3
+ def build
4
+ build_css
5
+ build_js
6
+ build_html
7
+ copy_images
8
+ end
9
+
10
+ # Build HTML from the source files
11
+ def build_html
12
+ src_file_paths('haml').each do |path|
13
+ file_dir, template = source_template_from_path(path.sub(/^#{@src_dir}/, ''))
14
+ save_page(File.join(file_dir, template), generate_html_with_layout(template, file_dir))
15
+ end
16
+ end
17
+
18
+ # Build CSS from the source files
19
+ def build_css
20
+ src_file_paths('sass','scss').each do |path|
21
+ file_dir, template = source_template_from_path(path.sub(/^#{@src_dir}/, ''))
22
+
23
+ if !template.match(/(^|\/)\_/)
24
+ save_stylesheet(File.join(file_dir, template), generate_css(template, file_dir))
25
+ end
26
+ end
27
+ end
28
+
29
+ def build_js
30
+ coffee_found = ENV['PATH'].split(':').inject(false) { |found, folder| found |= File.exists?("#{folder}/coffee") }
31
+ if coffee_found
32
+ src_file_paths('coffee').each do |path|
33
+ file_dir, template = source_template_from_path(path.sub(/^#{@src_dir}/, ''))
34
+ save_javascript(File.join(file_dir, template), generate_js(template, file_dir))
35
+ end
36
+ end
37
+ # copy normal javascript files over
38
+ src_file_paths('js').each do |path|
39
+ file_dir, template = source_template_from_path(path.sub(/^#{@src_dir}/, ''))
40
+ copy_file(path, File.join(@site_dir, file_dir, "#{template}.js"))
41
+ end
42
+ end
43
+
44
+ def copy_images
45
+ src_file_paths(*%w{gif jpg jpef png tiff}).each do |path|
46
+ file_dir, file_name = File.split(path.sub(/^#{@src_dir}/, ''))
47
+ copy_file(path, File.join(@site_dir, 'images', file_dir, file_name))
48
+ end
49
+ end
50
+
51
+ def copy_file(from, to)
52
+ FileUtils.mkdir_p(File.dirname(to))
53
+ FileUtils.cp(from, to)
54
+ end
55
+
56
+ def save_page(filename, content)
57
+ generate_site_file(filename, 'html', content)
58
+ end
59
+
60
+ def save_stylesheet(filename, content)
61
+ generate_site_file(filename, 'css', content)
62
+ end
63
+
64
+ def save_javascript(filename, content)
65
+ generate_site_file(filename, 'js', content)
66
+ end
67
+
68
+ def generate_site_file(filename, extension, content)
69
+ path = File.join(@site_dir,"#{filename}.#{extension}")
70
+ FileUtils.mkdir_p(File.dirname(path))
71
+ File.open(path, 'w+') do |f|
72
+ f << content
73
+ end
74
+
75
+ puts "created #{path}"
76
+ end
77
+ 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,153 @@
1
+ module StaticMatic::RenderMixin
2
+
3
+ # clear all scope variables except @staticmatic
4
+ def clear_template_variables!
5
+
6
+ @scope.instance_variables.each do |var|
7
+ @scope.instance_variable_set(var, nil) unless var == '@staticmatic' || var == :@staticmatic
8
+ end
9
+ end
10
+
11
+ def source_for_layout
12
+ if layout_exists?(determine_layout)
13
+ File.read(full_layout_path(determine_layout))
14
+ else
15
+ raise StaticMatic::Error.new("", full_layout_path(determine_layout), "Layout not found")
16
+ end
17
+ end
18
+
19
+ # Generate html from source file:
20
+ # generate_html("index")
21
+ def generate_html(source_file, source_dir = '')
22
+ full_file_path = File.join(@src_dir, source_dir, "#{source_file}.haml")
23
+
24
+ begin
25
+
26
+ html = generate_html_from_template_source(File.read(full_file_path))
27
+ rescue StaticMatic::TemplateError => e
28
+ raise e # re-raise inline errors
29
+ rescue Exception => e
30
+ raise StaticMatic::TemplateError.new(full_file_path, e)
31
+ end
32
+
33
+ html
34
+ end
35
+
36
+ def generate_html_with_layout(source, source_dir = '')
37
+ @current_page = File.join(source_dir, "#{source}.html")
38
+ @current_file_stack.unshift(File.join(source_dir, "#{source}.haml"))
39
+ begin
40
+ template_content = generate_html(source, source_dir)
41
+ generate_html_from_template_source(source_for_layout) { template_content }
42
+ rescue Exception => e
43
+ render_rescue_from_error(e)
44
+ ensure
45
+ clear_template_variables!
46
+ @current_page = nil
47
+ @current_file_stack.shift
48
+ end
49
+ end
50
+
51
+ def generate_partial(name, options = {})
52
+ partial_dir, partial_name = File.dirname(self.current_file), name # default relative to current file
53
+ partial_dir, partial_name = File.split(name) if name.index('/') # contains a path so it's absolute from src/pages dir
54
+ partial_type = partial_name[/(\.haml|\.html)$/]
55
+
56
+ partial_name = "_#{partial_name}"
57
+ partial_name += ".haml" unless partial_type
58
+
59
+ partial_path = File.join(@src_dir, partial_dir, partial_name)
60
+ unless File.exists?(partial_path)
61
+ # couldn't find it in the pages subdirectory tree so try old way (ignoring the path)
62
+ partial_dir = '_partials'
63
+ partial_name = "#{File.basename(name)}"
64
+ partial_name += ".haml" unless partial_type
65
+ partial_path = File.join(@src_dir, partial_dir, partial_name)
66
+ end
67
+
68
+ if File.exists?(partial_path)
69
+ partial_rel_path = "/#{partial_dir}/#{partial_name}".gsub(/\/+/, '/')
70
+ @current_file_stack.unshift(partial_rel_path)
71
+ begin
72
+ if partial_type == '.html'
73
+ File.read(partial_path)
74
+ else
75
+ generate_html_from_template_source(File.read(partial_path), options)
76
+ end
77
+ rescue Exception => e
78
+ raise StaticMatic::TemplateError.new(partial_path, e)
79
+ ensure
80
+ @current_file_stack.shift
81
+ end
82
+ else
83
+ raise StaticMatic::Error.new("", name, "Partial not found")
84
+ end
85
+ end
86
+
87
+ def generate_css(source, source_dir = '')
88
+ full_file_path = Dir[File.join(@src_dir, source_dir, "#{source}.{sass,scss}")].first
89
+
90
+ if full_file_path && File.exist?(full_file_path)
91
+ begin
92
+ sass_options = { :load_paths => [ @src_dir ] }.merge(self.configuration.sass_options)
93
+
94
+ if File.extname(full_file_path) == ".scss"
95
+ sass_options[:syntax] = :scss
96
+ end
97
+
98
+ stylesheet = Sass::Engine.new(File.read(full_file_path), sass_options)
99
+ stylesheet.to_css
100
+ rescue Exception => e
101
+ render_rescue_from_error(StaticMatic::TemplateError.new(full_file_path, e))
102
+ end
103
+ else
104
+ raise StaticMatic::Error.new("", source, "Stylesheet not found")
105
+ end
106
+ end
107
+
108
+ def generate_js(source, source_dir = '')
109
+ full_file_path = File.join(@src_dir, source_dir, "#{source}.coffee")
110
+
111
+ coffee_options = "#{self.configuration.coffee_options} -p"
112
+ javascript = `coffee #{coffee_options} #{full_file_path}`
113
+ end
114
+
115
+ # Generates html from the passed source string
116
+ #
117
+ # generate_html_from_template_source("%h1 Welcome to My Site") -> "<h1>Welcome to My Site</h1>"
118
+ #
119
+ # Pass a block containing a string to yield within in the passed source:
120
+ #
121
+ # generate_html_from_template_source("content:\n= yield") { "blah" } -> "content: blah"
122
+ #
123
+ def generate_html_from_template_source(source, options = {})
124
+ html = Haml::Engine.new(source, self.configuration.haml_options.merge(options))
125
+ locals = options[:locals] || {}
126
+ html.render(@scope, locals) { yield }
127
+ end
128
+
129
+ def determine_layout(dir = '')
130
+ layout_name ||= @default_layout
131
+
132
+ if @scope.instance_variable_get("@layout")
133
+ layout_name = @scope.instance_variable_get("@layout")
134
+ elsif dir
135
+ dirs = dir.split("/")
136
+ dir_layout_name = dirs[1]
137
+
138
+ if layout_exists?(dir_layout_name)
139
+ layout_name = dir_layout_name
140
+ end
141
+ end
142
+
143
+ layout_name
144
+ end
145
+
146
+ # Returns a raw template name from a source file path:
147
+ # source_template_from_path("/path/to/site/src/stylesheets/application.sass") -> "application"
148
+ def source_template_from_path(path)
149
+ file_dir, file_name = File.split(path)
150
+ file_name.chomp!(File.extname(file_name))
151
+ [ file_dir, file_name ]
152
+ end
153
+ 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,7 @@
1
+ module StaticMatic::ServerMixin
2
+ def preview
3
+ puts "StaticMatic Preview Server"
4
+ puts "Ctrl+C to exit"
5
+ StaticMatic::Server.start(self)
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ module StaticMatic::SetupMixin
2
+
3
+ def setup
4
+ Dir.mkdir(@base_dir) unless File.exists?(@base_dir)
5
+
6
+ Dir[File.join(File.dirname(__FILE__), "..", "templates", "project", "*")].each do |template|
7
+ begin
8
+ FileUtils.cp_r(template, @base_dir)
9
+ rescue Errno::EEXIST
10
+ # ignore - template exists
11
+ end
12
+ end
13
+
14
+ puts "Done"
15
+ end
16
+ end
@@ -0,0 +1,86 @@
1
+ module StaticMatic
2
+ class Server
3
+ def initialize(staticmatic, default = nil)
4
+ @files = default || Rack::File.new(staticmatic.src_dir)
5
+ @staticmatic = staticmatic
6
+
7
+
8
+ end
9
+
10
+ def call(env)
11
+ @staticmatic.load_helpers
12
+ path_info = env["PATH_INFO"]
13
+
14
+ file_dir, file_name, file_ext = expand_path(path_info)
15
+
16
+ file_dir = CGI::unescape(file_dir)
17
+ file_name = CGI::unescape(file_name)
18
+
19
+ unless file_ext && ["html", "css", "js"].include?(file_ext) &&
20
+ @staticmatic.template_exists?(file_name, file_ext, file_dir) &&
21
+ File.basename(file_name) !~ /^\_/
22
+ return @files.call(env)
23
+ end
24
+
25
+ res = Rack::Response.new
26
+ res.header["Content-Type"] = "text/#{file_ext}"
27
+
28
+ begin
29
+ if file_ext == "css"
30
+ res.write @staticmatic.generate_css(file_name, file_dir)
31
+ elsif file_ext == "js"
32
+ res.header["Content-Type"] = "text/javascript"
33
+ res.write @staticmatic.generate_js(file_name, file_dir)
34
+ else
35
+ res.write @staticmatic.generate_html_with_layout(file_name, file_dir)
36
+ end
37
+ rescue StaticMatic::Error => e
38
+ res.write e.message
39
+ end
40
+
41
+ res.finish
42
+ end
43
+
44
+ # Starts the StaticMatic preview server
45
+ def self.start(staticmatic)
46
+ [ 'INT', 'TERM' ].each do |signal|
47
+ Signal.trap(signal) do
48
+ puts
49
+ puts "Exiting"
50
+ exit!(0)
51
+ end
52
+ end
53
+ port = staticmatic.configuration.preview_server_port || 3000
54
+
55
+ host = staticmatic.configuration.preview_server_host || ""
56
+
57
+ app = Rack::Builder.new do
58
+ use Rack::ShowExceptions
59
+ run StaticMatic::Server.new(staticmatic)
60
+ end
61
+
62
+ Rack::Handler::WEBrick.run(app, :Port => port, :Host => host)
63
+ end
64
+
65
+ private
66
+
67
+ def expand_path(path_info)
68
+ dirname, basename = File.split(path_info)
69
+
70
+ extname = File.extname(path_info).sub(/^\./, '')
71
+ filename = basename.chomp(".#{extname}")
72
+
73
+ if extname.empty?
74
+ dir = File.join(dirname, filename)
75
+ is_dir = path_info[-1, 1] == '/'
76
+ if is_dir
77
+ dirname = dir
78
+ filename = 'index'
79
+ end
80
+ extname = 'html'
81
+ end
82
+
83
+ [ dirname, filename, extname ]
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,44 @@
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
+ if template
11
+ @source = File.read(template)
12
+ else
13
+ @source = ""
14
+ end
15
+ end
16
+
17
+ # TODO: Replace 'haml|sass' with any registered engines
18
+ def line_number
19
+ @line_number ||= $2 if backtrace.find { |line| line =~ /\((haml|sass|scss)\)\:(\d+)/ }
20
+ end
21
+
22
+ def filename
23
+ @template
24
+ end
25
+
26
+ def source_extract(indentation = 0)
27
+ return "" unless num = line_number
28
+ num = num.to_i
29
+
30
+ source_code = @source.split("\n")
31
+
32
+ start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
33
+ end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
34
+
35
+ indent = ' ' * indentation
36
+ line_counter = start_on_line
37
+ return unless source_code = source_code[start_on_line..end_on_line]
38
+
39
+ source_code.collect do |line|
40
+ line_counter += 1
41
+ "#{indent}#{line_counter}: #{line}\n"
42
+ end.to_s
43
+ end
44
+ end
@@ -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/>")