frank 0.2.6 → 0.3.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/Featurelist +6 -0
  2. data/README.md +44 -32
  3. data/Rakefile +3 -3
  4. data/frank.gemspec +51 -45
  5. data/lib/frank.rb +1 -0
  6. data/lib/frank/base.rb +144 -94
  7. data/lib/frank/lorem.rb +77 -36
  8. data/lib/frank/middleware/imager.rb +43 -0
  9. data/lib/frank/middleware/refresh.rb +42 -0
  10. data/lib/frank/middleware/statik.rb +41 -0
  11. data/lib/frank/output.rb +25 -37
  12. data/lib/frank/rescue.rb +13 -6
  13. data/lib/frank/template_helpers.rb +34 -3
  14. data/lib/frank/templates/404.haml +1 -0
  15. data/lib/frank/templates/500.haml +2 -0
  16. data/lib/frank/tilt.rb +389 -141
  17. data/lib/template/{dynamic/layout.haml → layouts/default.haml} +0 -0
  18. data/lib/template/settings.yml +15 -28
  19. data/spec/base_spec.rb +88 -0
  20. data/{test → spec}/helper.rb +0 -7
  21. data/spec/output_spec.rb +220 -0
  22. data/spec/render_spec.rb +106 -0
  23. data/spec/template/dynamic/500.haml +1 -0
  24. data/{test → spec}/template/dynamic/_partial.haml +0 -0
  25. data/{test → spec}/template/dynamic/builder.builder +0 -0
  26. data/{test → spec}/template/dynamic/coffee.coffee +0 -0
  27. data/{test → spec}/template/dynamic/erb.erb +0 -0
  28. data/{test → spec}/template/dynamic/helper_test.haml +0 -0
  29. data/spec/template/dynamic/index.haml +5 -0
  30. data/spec/template/dynamic/layout2_test.haml +4 -0
  31. data/{test → spec}/template/dynamic/liquid.liquid +0 -0
  32. data/spec/template/dynamic/lorem_test.haml +7 -0
  33. data/{test → spec}/template/dynamic/markdown.md +0 -0
  34. data/spec/template/dynamic/markdown_in_haml.md +4 -0
  35. data/{test → spec}/template/dynamic/mustache.mustache +0 -0
  36. data/spec/template/dynamic/nested/child.haml +1 -0
  37. data/spec/template/dynamic/nested/deeper/deep.haml +1 -0
  38. data/spec/template/dynamic/no_layout.haml +4 -0
  39. data/spec/template/dynamic/partial_test.haml +2 -0
  40. data/{test → spec}/template/dynamic/redcloth.textile +0 -0
  41. data/spec/template/dynamic/refresh.haml +1 -0
  42. data/{test → spec}/template/dynamic/sass.sass +0 -0
  43. data/{test → spec}/template/helpers.rb +0 -0
  44. data/spec/template/layouts/default.haml +3 -0
  45. data/{test/template/dynamic → spec/template/layouts/explicit}/layout2.haml +0 -0
  46. data/spec/template/layouts/nested/default.haml +2 -0
  47. data/spec/template/settings.yml +45 -0
  48. data/{test/template/static → spec/template/static/files}/static.html +0 -0
  49. data/spec/template_helpers_spec.rb +78 -0
  50. metadata +57 -49
  51. data/lib/frank/imager.rb +0 -39
  52. data/lib/frank/statik.rb +0 -39
  53. data/test/suite.rb +0 -4
  54. data/test/template/dynamic/index.haml +0 -2
  55. data/test/template/dynamic/layout.haml +0 -2
  56. data/test/template/dynamic/layout2_test.haml +0 -1
  57. data/test/template/dynamic/layout_test.haml +0 -1
  58. data/test/template/dynamic/lorem_test.haml +0 -7
  59. data/test/template/dynamic/partial_test.haml +0 -2
  60. data/test/template/settings.yml +0 -62
  61. data/test/test_base.rb +0 -81
  62. data/test/test_helpers.rb +0 -71
  63. data/test/test_output.rb +0 -160
  64. data/test/test_render.rb +0 -89
@@ -0,0 +1,6 @@
1
+ - DONE - support layouts of a different type than the rendered template
2
+ dynamically reload template changes using javascript and a slick url
3
+ dynamically reload helpers and settings
4
+ - DONE - support yaml variable definition at the top of templates
5
+ - DONE - add helper for "selected" css class, this should work with frankup and frankout
6
+ - DONE - add frankout replacement fields to lorem helpers
data/README.md CHANGED
@@ -25,22 +25,21 @@ Then `cd <project_name>` and start up the server with:
25
25
  Frank's holdin' it down...
26
26
  0.0.0.0:3601
27
27
 
28
- And you're ready to get to work. By default, dynamic templates are served from the `dynamic` folder
29
- and static files are served from the `static` folder.
28
+ And you're ready to get to work. By default, dynamic templates are served from the `dynamic` folder,
29
+ static files are served from the `static` folder, and layouts are server from the `layouts` folder.
30
30
 
31
31
  When you are finished:
32
-
33
- $ frankout <dump_dir> # compile templates
32
+ `$ frankout <dump_dir> # compile templates`
34
33
 
35
34
  or
36
35
 
37
- $ frankout --production <dump_dir> # compile and create folder structure suitable for serving from a production website
36
+ `$ frankout --production <dump_dir> # compile and create folder structure suitable for serving from a production website`
38
37
 
39
- Views & Layouts
38
+ Views & Meta Data
40
39
  -------------------------
41
40
 
42
41
  All of your templates, and less/sass/coffeescript go into `<project>/dynamic`,
43
- by default. You are more than welcome to organize them into subfolders if you've
42
+ by default. You can organize them into subfolders if you've
44
43
  got lots.
45
44
 
46
45
  ### Views
@@ -48,21 +47,36 @@ got lots.
48
47
  Writing views is simple. Say you've got a `blog.haml`, in `<project>/dynamic` just browse to
49
48
  `http://0.0.0.0:3601/blog` and your view will be parsed and returned as html.
50
49
 
51
- ### Layouts
50
+ ### Meta Data
51
+
52
+ Frank doesn't have controllers and there are times you need to pass variables around between templates and layouts.
53
+ This can be done with template Meta data. Meta data is set using YAML.
54
+
55
+ You define your fields at the top a template
56
+ a separate it from the rest of your template using the Meta delimiter: `META--------`. The delimiter can contain as
57
+ many dashes, or hyphens as you wish.
58
+
59
+ You can access your fields as local variables in the template (if the template language supports it).
60
+ For example, you might have a template and define a field `title: My Rad Template`, then inside a haml layout,
61
+ you could create a title tag with the field: `%title= title`
52
62
 
53
- Layouts are also simple with Frank. By default, just create a `layout.haml`
54
- (or whichever language you like best), that contains a `yield`, and any
63
+ Layouts (updated in 0.3)
64
+ -----------------------------
65
+
66
+ Layouts are also simple with Frank. By default, just create a `default.haml`
67
+ (or another language), inside the `layouts` folder and include a `yield` statement. Any
55
68
  views will be inserted into it at that point.
56
69
 
57
- Multiple layouts are also easy. In your `settings.yml`, do something like:
70
+ Layouts can be name spaced with folders:
71
+
72
+ a template: `dynamic_folder/blog/a-blog-post.haml`
73
+ would look for a layout: `layouts/blog/default.haml`
74
+ and if not found use the default: `layouts/default.haml`
75
+
76
+ Frank also supports defining layouts on an individual template basis using meta data
77
+ you can do this by defining a meta field `layout: my_layout.haml` You can disable layouts on a
78
+ template by using `layout: nil`
58
79
 
59
- layouts:
60
- - name: blog_layout
61
- only: [blog]
62
- - name: normal
63
- not: [blog, ajax]
64
- This tells Frank to use `blog_layout.haml` for `/blog`, and `normal.haml`
65
- for everything but `/blog' and '/ajax`.
66
80
 
67
81
 
68
82
  Partials & Helpers
@@ -93,7 +107,13 @@ to the `FrankHelpers` module; that's it. Use them just like `render_partial`.
93
107
  Built-in Helpers
94
108
  ----------------
95
109
 
96
- Frank also comes with some handy helper methods for generating placeholder content.
110
+ ### Auto Refresh
111
+
112
+ Constantly refreshing your browser can become tedious while doing work. Frank has a handy refresh helper.
113
+ It will include a bit of javascript that refreshes the browser when you save the current template or it's layout.
114
+ You can include this in a haml template like this: `= refresh`. When you `frankout`,
115
+ the template will render an empty string instead of the script tag
116
+
97
117
 
98
118
  ### Placeholder Text
99
119
 
@@ -113,7 +133,7 @@ This will return 3 sentences of standard [Lorem Ipsum][11]. `lorem` also has all
113
133
  lorem.first_name
114
134
  lorem.last_name
115
135
  lorem.email
116
-
136
+
117
137
 
118
138
  ### Placeholder Images
119
139
 
@@ -129,19 +149,11 @@ The `lorem.image` helper returns a special Frank image URL. In this case, the re
129
149
 
130
150
  If you would like to use the placeholder images in a context where the helper methods are unavailable (e.g. in static CSS or JavaScript), you can access the URL directly with `/_img/500x400.jpg`, or for random images `/_img/500x400.jpg?random`.
131
151
 
152
+ ### Replacement Text
132
153
 
133
-
134
- GET/POST params
135
- ---------------
136
-
137
- Sometimes it's nice to include user input in your mock-ups. It's especially
138
- handy when mocking-up Ajax-driven elements. For this reason, the `request`
139
- and `params` are available in your templates.
140
-
141
- For example, to use a person's name submitted through a form you might do:
142
-
143
- %h1= "Hello, #{params.name}"
144
-
154
+ All of the lorem helpers accept an optional "replacement" argument. This will be the text rendered when you `frankout`.
155
+ For example `lorem.sentence("<%= page.content %>")` will generate a lorem sentence when you view the page using the `frankup` server.
156
+ However, when you `frankout` the template will render "<%= page.content %>".
145
157
 
146
158
 
147
159
  Configuration
data/Rakefile CHANGED
@@ -4,8 +4,8 @@ begin
4
4
  require 'jeweler'
5
5
  Jeweler::Tasks.new do |gemspec|
6
6
  gemspec.name = "frank"
7
- gemspec.summary = "Stupidly Simple Static Slinger"
8
- gemspec.description = "Create/Dump static builds using whatever templating/helper languages you wish"
7
+ gemspec.summary = "Static Site Non-Framework"
8
+ gemspec.description = "Rapidly develop static sites using any supported templating language"
9
9
  gemspec.version = Frank::VERSION
10
10
  gemspec.email = "travis.dunn@thisismedium.com"
11
11
  gemspec.homepage = "http://github.com/blahed/frank"
@@ -13,7 +13,7 @@ begin
13
13
  gemspec.add_dependency 'rack', '>=1.0'
14
14
  gemspec.add_dependency 'mongrel', '>=1.0'
15
15
  gemspec.add_dependency 'haml', '>=2.0'
16
- gemspec.add_development_dependency 'shoulda', '>=2.0'
16
+ gemspec.add_development_dependency 'rspec'
17
17
  gemspec.add_development_dependency 'rack-test', '>=0.5'
18
18
 
19
19
  end
@@ -1,16 +1,16 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{frank}
8
- s.version = "0.2.6"
8
+ s.version = "0.3.0.beta"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["blahed", "nwah"]
12
- s.date = %q{2010-04-14}
13
- s.description = %q{Create/Dump static builds using whatever templating/helper languages you wish}
12
+ s.date = %q{2010-06-12}
13
+ s.description = %q{Rapidly develop static sites using any supported templating language}
14
14
  s.email = %q{travis.dunn@thisismedium.com}
15
15
  s.executables = ["frank", "frankout", "frankup"]
16
16
  s.extra_rdoc_files = [
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  ]
20
20
  s.files = [
21
21
  ".gitignore",
22
+ "Featurelist",
22
23
  "LICENSE",
23
24
  "README.md",
24
25
  "Rakefile",
@@ -28,11 +29,12 @@ Gem::Specification.new do |s|
28
29
  "frank.gemspec",
29
30
  "lib/frank.rb",
30
31
  "lib/frank/base.rb",
31
- "lib/frank/imager.rb",
32
32
  "lib/frank/lorem.rb",
33
+ "lib/frank/middleware/imager.rb",
34
+ "lib/frank/middleware/refresh.rb",
35
+ "lib/frank/middleware/statik.rb",
33
36
  "lib/frank/output.rb",
34
37
  "lib/frank/rescue.rb",
35
- "lib/frank/statik.rb",
36
38
  "lib/frank/template_helpers.rb",
37
39
  "lib/frank/templates/404.haml",
38
40
  "lib/frank/templates/500.haml",
@@ -51,51 +53,55 @@ Gem::Specification.new do |s|
51
53
  "lib/frank/tilt.rb",
52
54
  "lib/template/dynamic/css/frank.sass",
53
55
  "lib/template/dynamic/index.haml",
54
- "lib/template/dynamic/layout.haml",
55
56
  "lib/template/helpers.rb",
57
+ "lib/template/layouts/default.haml",
56
58
  "lib/template/settings.yml",
57
59
  "lib/template/static/images/frank-med.png",
58
60
  "lib/template/static/js/frank.js",
59
- "test/helper.rb",
60
- "test/suite.rb",
61
- "test/template/dynamic/_partial.haml",
62
- "test/template/dynamic/builder.builder",
63
- "test/template/dynamic/coffee.coffee",
64
- "test/template/dynamic/erb.erb",
65
- "test/template/dynamic/helper_test.haml",
66
- "test/template/dynamic/index.haml",
67
- "test/template/dynamic/layout.haml",
68
- "test/template/dynamic/layout2.haml",
69
- "test/template/dynamic/layout2_test.haml",
70
- "test/template/dynamic/layout_test.haml",
71
- "test/template/dynamic/liquid.liquid",
72
- "test/template/dynamic/lorem_test.haml",
73
- "test/template/dynamic/markdown.md",
74
- "test/template/dynamic/mustache.mustache",
75
- "test/template/dynamic/partial_test.haml",
76
- "test/template/dynamic/redcloth.textile",
77
- "test/template/dynamic/sass.sass",
78
- "test/template/helpers.rb",
79
- "test/template/settings.yml",
80
- "test/template/static/static.html",
81
- "test/test_base.rb",
82
- "test/test_helpers.rb",
83
- "test/test_output.rb",
84
- "test/test_render.rb"
61
+ "spec/base_spec.rb",
62
+ "spec/helper.rb",
63
+ "spec/output_spec.rb",
64
+ "spec/render_spec.rb",
65
+ "spec/template/dynamic/500.haml",
66
+ "spec/template/dynamic/_partial.haml",
67
+ "spec/template/dynamic/builder.builder",
68
+ "spec/template/dynamic/coffee.coffee",
69
+ "spec/template/dynamic/erb.erb",
70
+ "spec/template/dynamic/helper_test.haml",
71
+ "spec/template/dynamic/index.haml",
72
+ "spec/template/dynamic/layout2_test.haml",
73
+ "spec/template/dynamic/liquid.liquid",
74
+ "spec/template/dynamic/lorem_test.haml",
75
+ "spec/template/dynamic/markdown.md",
76
+ "spec/template/dynamic/markdown_in_haml.md",
77
+ "spec/template/dynamic/mustache.mustache",
78
+ "spec/template/dynamic/nested/child.haml",
79
+ "spec/template/dynamic/nested/deeper/deep.haml",
80
+ "spec/template/dynamic/no_layout.haml",
81
+ "spec/template/dynamic/partial_test.haml",
82
+ "spec/template/dynamic/redcloth.textile",
83
+ "spec/template/dynamic/refresh.haml",
84
+ "spec/template/dynamic/sass.sass",
85
+ "spec/template/helpers.rb",
86
+ "spec/template/layouts/default.haml",
87
+ "spec/template/layouts/explicit/layout2.haml",
88
+ "spec/template/layouts/nested/default.haml",
89
+ "spec/template/settings.yml",
90
+ "spec/template/static/files/static.html",
91
+ "spec/template_helpers_spec.rb"
85
92
  ]
86
93
  s.homepage = %q{http://github.com/blahed/frank}
87
94
  s.rdoc_options = ["--charset=UTF-8"]
88
95
  s.require_paths = ["lib"]
89
96
  s.rubygems_version = %q{1.3.6}
90
- s.summary = %q{Stupidly Simple Static Slinger}
97
+ s.summary = %q{Static Site Non-Framework}
91
98
  s.test_files = [
92
- "test/helper.rb",
93
- "test/suite.rb",
94
- "test/template/helpers.rb",
95
- "test/test_base.rb",
96
- "test/test_helpers.rb",
97
- "test/test_output.rb",
98
- "test/test_render.rb"
99
+ "spec/base_spec.rb",
100
+ "spec/helper.rb",
101
+ "spec/output_spec.rb",
102
+ "spec/render_spec.rb",
103
+ "spec/template/helpers.rb",
104
+ "spec/template_helpers_spec.rb"
99
105
  ]
100
106
 
101
107
  if s.respond_to? :specification_version then
@@ -106,20 +112,20 @@ Gem::Specification.new do |s|
106
112
  s.add_runtime_dependency(%q<rack>, [">= 1.0"])
107
113
  s.add_runtime_dependency(%q<mongrel>, [">= 1.0"])
108
114
  s.add_runtime_dependency(%q<haml>, [">= 2.0"])
109
- s.add_development_dependency(%q<shoulda>, [">= 2.0"])
115
+ s.add_development_dependency(%q<rspec>, [">= 0"])
110
116
  s.add_development_dependency(%q<rack-test>, [">= 0.5"])
111
117
  else
112
118
  s.add_dependency(%q<rack>, [">= 1.0"])
113
119
  s.add_dependency(%q<mongrel>, [">= 1.0"])
114
120
  s.add_dependency(%q<haml>, [">= 2.0"])
115
- s.add_dependency(%q<shoulda>, [">= 2.0"])
121
+ s.add_dependency(%q<rspec>, [">= 0"])
116
122
  s.add_dependency(%q<rack-test>, [">= 0.5"])
117
123
  end
118
124
  else
119
125
  s.add_dependency(%q<rack>, [">= 1.0"])
120
126
  s.add_dependency(%q<mongrel>, [">= 1.0"])
121
127
  s.add_dependency(%q<haml>, [">= 2.0"])
122
- s.add_dependency(%q<shoulda>, [">= 2.0"])
128
+ s.add_dependency(%q<rspec>, [">= 0"])
123
129
  s.add_dependency(%q<rack-test>, [">= 0.5"])
124
130
  end
125
131
  end
@@ -11,6 +11,7 @@ end
11
11
 
12
12
  require 'rubygems'
13
13
  require 'yaml'
14
+ require 'fileutils'
14
15
  require 'rack'
15
16
  require 'frank/base'
16
17
  require 'frank/output'
@@ -1,11 +1,12 @@
1
1
  require 'frank/tilt'
2
2
  require 'frank/template_helpers'
3
3
  require 'frank/rescue'
4
- require 'frank/statik'
5
- require 'frank/imager'
4
+ require 'frank/middleware/statik'
5
+ require 'frank/middleware/imager'
6
+ require 'frank/middleware/refresh'
6
7
 
7
8
  module Frank
8
- VERSION = '0.2.6'
9
+ VERSION = '0.3.0.beta'
9
10
 
10
11
  module Render; end
11
12
 
@@ -15,7 +16,13 @@ module Frank
15
16
  include Frank::TemplateHelpers
16
17
  include Frank::Render
17
18
 
18
- attr_accessor :environment, :proj_dir, :server, :static_folder, :dynamic_folder, :templates
19
+ attr_accessor :environment
20
+ attr_accessor :proj_dir
21
+ attr_accessor :server
22
+ attr_accessor :static_folder
23
+ attr_accessor :dynamic_folder
24
+ attr_accessor :layouts_folder
25
+ attr_accessor :templates
19
26
 
20
27
  def initialize(&block)
21
28
  instance_eval &block
@@ -46,9 +53,9 @@ module Frank
46
53
  # attempt to render with the request path,
47
54
  # if it cannot be found, render error page
48
55
  def process
49
- ext = File.extname(@request.path.split('/').last || '')
50
- @response['Content-Type'] = Rack::Mime.mime_type(ext, 'text/html')
51
- @response.write render_path(@request.path)
56
+ load_helpers
57
+ @response['Content-Type'] = Rack::Mime.mime_type(File.extname(@request.path), 'text/html')
58
+ @response.write render(@request.path)
52
59
  rescue Frank::TemplateError
53
60
  render_404
54
61
  rescue Exception => e
@@ -57,115 +64,158 @@ module Frank
57
64
 
58
65
  # prints requests and errors to STDOUT
59
66
  def log_request(status, excp=nil)
60
- out = "[#{Time.now.strftime('%Y-%m-%d %H:%M')}] (#{@request.request_method}) http://#{@request.host}:#{@request.port}#{@request.fullpath} - #{status}"
61
- out += "\n\n**QUACK** #{excp.message}\n\n#{excp.backtrace.join("\n")} " if excp
62
- STDOUT.puts out unless @environment == :test
67
+ out = "\033[1m[#{Time.now.strftime('%Y-%m-%d %H:%M')}]\033[22m (#{@request.request_method}) http://#{@request.host}:#{@request.port}#{@request.fullpath} - #{status}"
68
+ out << "\n\n#{excp.message}\n\n#{excp.backtrace.join("\n")} " if excp
69
+ puts out
70
+ end
71
+
72
+ def load_helpers
73
+ helpers = File.join(@proj_dir, 'helpers.rb')
74
+ if File.exist? helpers
75
+ load helpers
76
+ Frank::TemplateHelpers.class_eval("include FrankHelpers")
77
+ end
63
78
  end
64
79
 
65
80
  end
66
81
 
67
82
  module Render
68
83
 
69
- def name_ext(path)
70
- return path.split(/\.(?=[^.]+$)/)
71
- end
84
+ TMPL_EXTS = {
85
+ :html => %w[haml erb rhtml builder liquid mustache textile md mkd markdown],
86
+ :css => %w[sass less],
87
+ :js => %w[coffee]
88
+ }
72
89
 
73
- # breaks down path and renders partials, js, css without layouts
74
- def render_path(path)
75
- path.sub!(/^\//,'')
76
- template, ext = find_template_ext(path)
90
+ # render request path or template path
91
+ def render(path)
92
+ # normalize the path
93
+ path.sub!(/^\/?(.*)$/, '/\1')
94
+ path.sub!(/\/$/, '/index.html')
95
+ path.sub!(/(\/[\w-]+)$/, '\1.html')
96
+ path = to_file_path(path) if defined? @request
97
+
98
+ # regex for kinds that don't support meta
99
+ # and define the meta delimiter
100
+ nometa, delimiter = /\/_|\.(js|coffee|css|sass|less)$/, /^META-{3,}\n$/
77
101
 
78
- raise Frank::TemplateError, "Template not found #{path}" if template.nil?
79
- if template.match(/^_/) or (ext||'').match(/^(js|css)$/)
80
- render_template template
102
+ # set the layout
103
+ layout = path.match(nometa) ? nil : layout_for(path)
104
+
105
+ template_path = File.join(@proj_dir, @dynamic_folder, path)
106
+ raise Frank::TemplateError, "Template not found #{template_path}" unless File.exist? template_path
107
+
108
+ # read in the template
109
+ # check for meta and parse it if it exists
110
+ template = File.read(template_path) << "\n"
111
+ ext = File.extname(path)
112
+ template, meta = template.split(delimiter).reverse
113
+ locals = parse_meta_and_set_locals(meta, path)
114
+
115
+ # use given layout if defined as a meta field
116
+ layout = locals[:layout] == 'nil' ? nil : locals[:layout] if locals.has_key?(:layout)
117
+
118
+ # let tilt determine the template handler
119
+ # and return some template markup
120
+ if layout.nil?
121
+ tilt(ext, template, locals)
81
122
  else
82
- render_with_layout template
123
+ layout_path = File.join(@proj_dir, @layouts_folder, layout)
124
+ # add layout_path to locals
125
+ raise Frank::TemplateError, "Layout not found #{layout_path}" unless File.exist? layout_path
126
+
127
+ tilt(File.extname(layout), layout_path, locals) do
128
+ tilt(ext, template, locals)
129
+ end
83
130
  end
84
131
  end
85
132
 
86
- # renders a template
87
- def render_template(tmpl, *args)
88
- tilt(File.join(@proj_dir, @dynamic_folder, tmpl), *args) {"CONTENT"}
89
- end
90
-
91
- # if template has a layout defined, render template within layout
92
- # otherwise render template
93
- def render_with_layout(tmpl, *args)
94
- if layout = get_layout_for(tmpl)
95
- tilt(File.join(@proj_dir, @dynamic_folder, layout), *args) do
96
- render_template tmpl
133
+ # converts a request path to a template path
134
+ def to_file_path(path)
135
+ file_name = File.basename(path, File.extname(path))
136
+ file_ext = File.extname(path).sub(/^\./, '')
137
+ folder = File.join(@proj_dir, @dynamic_folder)
138
+ engine = nil
139
+
140
+ TMPL_EXTS.each do |ext, engines|
141
+ if ext.to_s == file_ext
142
+ engine = engines.reject do |eng|
143
+ !File.exist? File.join(folder, path.sub(/\.[\w-]+$/, ".#{eng}"))
144
+ end.first
97
145
  end
98
- else
99
- render_template tmpl
100
146
  end
147
+
148
+ raise Frank::TemplateError, "Template not found #{path}" if engine.nil?
149
+
150
+ path.sub(/\.[\w-]+$/, ".#{engine}")
101
151
  end
102
152
 
103
- TMPL_EXTS = { :html => %w[haml erb rhtml builder liquid mustache textile md mkd markdown],
104
- :css => %w[sass less],
105
- :js => %w[coffee] }
106
-
107
- def reverse_ext_lookup(ext)
108
- TMPL_EXTS.each do |kind, exts|
109
- return kind.to_s if exts.index(ext)
153
+ # lookup the original ext for given template path
154
+ # TODO: make non-ugly
155
+ def ext_from_handler(extension)
156
+ orig_ext = nil
157
+ TMPL_EXTS.each do |ext, engines|
158
+ orig_ext = ext.to_s if engines.include? extension[1..-1]
110
159
  end
111
- nil
160
+ orig_ext
112
161
  end
162
+
113
163
 
114
- # finds template extension based on filename
115
- # TODO: cleanup
116
- def find_template_ext(filename)
117
- name, kind = name_ext(filename)
118
- kind = reverse_ext_lookup(kind) if kind && TMPL_EXTS[kind.intern].nil?
164
+ # reverse walks the layouts folder until we find a layout
165
+ # returns nil if layout is not found
166
+ def layout_for(path)
167
+ default = "default#{File.extname(path)}"
168
+ path = path.sub /\/[\w-]+\.[\w-]+$/, ''
169
+ folders = path.split('/')
119
170
 
120
- tmpl_ext = nil
121
-
122
- TMPL_EXTS[ kind.nil? ? :html : kind.intern ].each do |ext|
123
- tmpl = "#{(name||'')}.#{ext}"
124
- default = File.join((name||''), "index.#{ext}")
125
-
126
- if File.exists? File.join(@proj_dir, @dynamic_folder, tmpl)
127
- tmpl_ext = [tmpl, ext]
128
- elsif File.exists? File.join(@proj_dir, @dynamic_folder, default)
129
- tmpl_ext = [default, ext]
171
+ until File.exist? File.join(@proj_dir, @layouts_folder, folders, default)
172
+ break if folders.empty?
173
+ folders.pop
174
+ end
175
+
176
+ if File.exist? File.join(@proj_dir, @layouts_folder, folders, default)
177
+ File.join(folders, default)
178
+ else
179
+ nil
180
+ end
181
+ end
182
+
183
+ # setup an object and extend it with TemplateHelpers and Render
184
+ # then send everything to tilt and get some template markup back
185
+ def tilt(ext, source, locals={}, &block)
186
+ obj = Object.new.extend(TemplateHelpers).extend(Render)
187
+ instance_variables.each do |var|
188
+ unless ['@response', '@env'].include? var
189
+ obj.instance_variable_set(var.intern, instance_variable_get(var))
130
190
  end
131
191
  end
132
-
133
- tmpl_ext
192
+ Tilt[ext].new(source).render(obj, locals=locals, &block)
134
193
  end
135
194
 
136
- # determines layout using layouts settings
137
- # TODO: cleanup
138
- def get_layout_for(view)
139
- view, ext = name_ext(view)
195
+ private
196
+
197
+ # parse the given meta string with yaml
198
+ # add current path
199
+ # and add instance variables
200
+ def parse_meta_and_set_locals(meta, path)
201
+ locals = {}
140
202
 
141
- layouts = @templates['layouts'] || []
142
- onlies = layouts.select {|l| l['only'] }
143
- nots = layouts.select {|l| l['not'] }
144
- blanks = layouts - onlies - nots
145
-
146
- layout = onlies.select {|l| l['only'].index(view) }.first
147
- layout = nots.reject {|l| l['not'].index(view) }.first unless layout
148
- layout = blanks.first unless layout
203
+ # parse yaml and symbolize keys
204
+ if meta.nil?
205
+ meta = {}
206
+ else
207
+ meta = YAML.load(meta).inject({}) do |options, (key, value)|
208
+ options[(key.to_sym rescue key) || key] = value
209
+ options
210
+ end
211
+ end
149
212
 
150
- # TODO: we are checking for exts in two places, consolidate soon
151
- layout = nil if !blanks.empty? && blanks.first['name'] == view
152
- layout = nil if (TMPL_EXTS[:css] + TMPL_EXTS[:js]).include?(ext)
153
-
154
- layout.nil? ? nil : layout['name'] + '.' + ext
155
- end
156
-
157
- # TODO: cleanup
158
- def tilt(file, *args, &block)
159
- locals = @request.nil? ? {} : { :request => @env, :params => @request.params }
160
- obj = Object.new.extend(TemplateHelpers).extend(Render)
161
- obj.instance_variable_set(:@proj_dir, @proj_dir)
162
- obj.instance_variable_set(:@dynamic_folder, @dynamic_folder)
163
- obj.instance_variable_set(:@templates, @templates)
164
- Tilt.new(file, 1).render(obj, locals, &block)
165
- end
166
-
167
- def remove_ext(path)
168
- path.gsub(File.extname(path), '')
213
+ # normalize current_path
214
+ # and add it to locals
215
+ current_path = path.sub(/\.[\w-]+$/, '').sub(/\/index/, '/')
216
+ locals[:current_path] = current_path
217
+
218
+ meta.merge(locals)
169
219
  end
170
220
 
171
221
  end
@@ -175,8 +225,9 @@ module Frank
175
225
  base = Base.new(&block) if block_given?
176
226
 
177
227
  builder = Rack::Builder.new do
178
- use Frank::Statik, :root => base.static_folder
179
- use Frank::Imager
228
+ use Frank::Middleware::Statik, :root => base.static_folder
229
+ use Frank::Middleware::Imager
230
+ use Frank::Middleware::Refresh, :watch => [ base.dynamic_folder, base.static_folder, base.layouts_folder ]
180
231
  run base
181
232
  end
182
233
 
@@ -201,8 +252,7 @@ module Frank
201
252
 
202
253
  # copies over the generic project template
203
254
  def self.stub(project)
204
- puts "\nFrank is..."
205
- puts " - \033[32mCreating\033[0m your project '#{project}'"
255
+ puts "\nFrank is...\n - \033[32mCreating\033[0m your project '#{project}'"
206
256
  Dir.mkdir project
207
257
  puts " - \033[32mCopying\033[0m Frank template"
208
258
  FileUtils.cp_r( Dir.glob(File.join(LIBDIR, 'template/*')), project )