snack 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../lib/snack', __FILE__)
3
+
4
+ command = ARGV[0] || 'serve'
5
+ directory = ARGV[1] || '_source'
6
+
7
+ if %w[ build serve new ].include?(command)
8
+ abort "-: Snack :- Unable to locate: '#{directory}'" unless command == 'new' || File.exists?(directory)
9
+ puts "-: Snack :- App root is: '#{directory}'"
10
+ @app = Snack::Application.new(:root => directory)
11
+ @app.send(command)
12
+ else
13
+ puts "'#{command}' is not a valid snack command"
14
+ puts "Usage: snack {build,serve,new} <directory>"
15
+ end
@@ -0,0 +1,120 @@
1
+ %w[ rubygems ostruct rack tilt ].each{ |s| require s }
2
+
3
+ module Snack
4
+ class Application
5
+ attr_accessor :settings, :builder
6
+
7
+ def initialize(options = {})
8
+ @settings = OpenStruct.new(options)
9
+ @settings.output_dir ||= '../'
10
+
11
+ app = self
12
+ @builder = Rack::Builder.new do
13
+ use Rack::CommonLogger
14
+ use Rack::ShowStatus # Nice looking 404s and other messages
15
+ use Rack::ShowExceptions # Nice looking errors
16
+ run Snack::Server.new app
17
+ end
18
+ end
19
+
20
+ def method_missing(sym)
21
+ settings.send sym
22
+ end
23
+
24
+ def serve
25
+ Rack::Handler::Thin.run @builder, :Port => 9393
26
+ end
27
+
28
+ def new
29
+ FileUtils.mkdir root unless File.exists? root
30
+ FileUtils.cd root do
31
+ File.open('index.html.haml', 'w') { |f| f.puts 'Hello from snack!' }
32
+ end
33
+ end
34
+
35
+ def build
36
+ FileUtils.cd root do
37
+ # collect all files that don't start with '_'
38
+ files = Dir[File.join('**', '*')].reject{ |f| f.include?('/_') || f.start_with?('_') }
39
+
40
+ files.each do |file|
41
+ new_path = File.join(output_dir, file)
42
+
43
+ if File.directory?(file)
44
+ FileUtils.mkdir(new_path) unless File.exists?(new_path)
45
+ elsif Tilt.registered?(File.extname(file).gsub('.', ''))
46
+ body = View.new(file).render
47
+ new_path = new_path.gsub(File.extname(new_path), '') # trim template extension
48
+ File.open(new_path, 'w') { |f| f.write(body) }
49
+ else
50
+ FileUtils.cp(file, new_path)
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+
58
+ class Server
59
+ def initialize(app)
60
+ @app = app
61
+ end
62
+
63
+ def call(env)
64
+ body = render File.join(@app.root, env['PATH_INFO'])
65
+ if body
66
+ [200, {"Content-Type" => Rack::Mime.mime_type(File.extname(env['PATH_INFO']), 'text/html')}, [body]]
67
+ else
68
+ [404, {"Content-Type" => "text/plain"}, "Not Found"]
69
+ end
70
+ end
71
+
72
+ def render(template_path)
73
+ return File.read template_path if File.file? template_path
74
+
75
+ # default to index if path to directory
76
+ template_path = File.join(template_path, 'index') if File.directory? template_path
77
+
78
+ # return the first filename that matches file
79
+ template = Dir[File.join(template_path + '*')].first
80
+ return View.new(template).render if template
81
+ end
82
+
83
+ end
84
+
85
+ # Basically take a template and render a string from it
86
+ class View
87
+ def initialize(template)
88
+ @template = template
89
+ end
90
+
91
+ # return the path to a valid layout file
92
+ def layout
93
+ Dir[File.join(File.dirname(@template), @layout) + '*'].first if @layout
94
+ end
95
+
96
+ def partial(path, locals = {})
97
+ pieces = path.to_s.split('/')
98
+ name = '_' + pieces.pop
99
+ filepath = File.join(File.dirname(@template), pieces, name)
100
+ template = Dir[filepath + '*'].first
101
+
102
+ if template
103
+ Tilt.new(template).render(self, locals)
104
+ else
105
+ raise "-: Snack :- Unable to locate partial at: '#{filepath}'"
106
+ end
107
+ end
108
+
109
+ # return a view body or nil if adequate template cannot be found
110
+ def render
111
+ template_body = Tilt.new(@template).render(self)
112
+ if layout
113
+ @body = Tilt.new(layout).render(self) { template_body }
114
+ elsif @layout # user changed; alert them to fails
115
+ raise "-: Snack :- Unable to locate layout at: '#{@layout}'"
116
+ end
117
+ @body || template_body
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,72 @@
1
+ # TODO: test build and new commands?
2
+ require 'rubygems'
3
+ require 'minitest/spec'
4
+ require 'rack/test'
5
+ require File.expand_path('../../lib/snack', __FILE__)
6
+
7
+ MiniTest::Unit.autorun
8
+
9
+ describe Snack::Server do
10
+ include Rack::Test::Methods
11
+
12
+ def app
13
+ @app = Snack::Application.new(:root => "#{File.dirname(__FILE__)}/test_app").builder
14
+ end
15
+
16
+ it "should respond with 404 on bad requests" do
17
+ get('/foo')
18
+ last_response.status.must_equal 404
19
+ end
20
+
21
+ it "should serve file directly first if a file matches the request" do
22
+ get('/public/style.css')
23
+ last_response.body.must_equal "body {\n\tbackground: blue;\n}"
24
+ end
25
+
26
+ it "should serve sass files compiled through tilt if request path exists with sass extension" do
27
+ get('/public/sass_style.css')
28
+ last_response.body.must_equal "body {\n background: blue; }\n"
29
+ end
30
+
31
+ it "should serve coffeescript files compiled through tilt if request path exists with coffee extension" do
32
+ get('/public/application.js')
33
+ last_response.body.must_equal "(function() {\n $(document).ready(function() {\n return alert('hello from snack');\n });\n})();\n"
34
+ end
35
+
36
+ it "should default to index.html if directory is requested" do
37
+ direct = get('/index.html')
38
+ response = get('/')
39
+
40
+ last_response.status.must_equal direct.status
41
+ last_response.body.must_equal direct.body
42
+ end
43
+
44
+ # partials
45
+ it "should render partials if found" do
46
+ get('/pages/partial-normal.html')
47
+ last_response.body.must_equal "This is a partial!\n"
48
+ end
49
+
50
+ it "should error if partial not found" do
51
+ get('/pages/partial-failing.html')
52
+ last_response.status.must_equal 500
53
+ end
54
+
55
+ # layouts
56
+ it "should render a page within a layout if layout exists" do
57
+ get('/pages/layout-normal.html')
58
+ last_response.body.must_equal "<div id='content'>\n <h1>Page Content</h1>\n</div>\n"
59
+ end
60
+
61
+ it "should error if user set layout and layout not found" do
62
+ get('/pages/layout-failing.html')
63
+ last_response.status.must_equal 500
64
+ end
65
+
66
+ # variables
67
+ it "should pass variables defined in the page to the layout" do
68
+ get('/pages/variable-normal.html')
69
+ last_response.body.must_equal "happy\nsad\nmad\n"
70
+ end
71
+
72
+ end
@@ -0,0 +1,2 @@
1
+ - @layout = nil
2
+ %h1 Just Testing
@@ -0,0 +1 @@
1
+ #footer= @footer
@@ -0,0 +1,2 @@
1
+ #content
2
+ = yield
@@ -0,0 +1,2 @@
1
+ - @emotions.each do |emotion|
2
+ = emotion
@@ -0,0 +1 @@
1
+ This is a partial!
@@ -0,0 +1,2 @@
1
+ - @layout = '_layouts/does_not_exist'
2
+ %h1 Failing Page Content
@@ -0,0 +1,2 @@
1
+ - @layout = '_layouts/normal'
2
+ %h1 Page Content
@@ -0,0 +1 @@
1
+ = partial :does_not_exist
@@ -0,0 +1,2 @@
1
+ - @layout = nil
2
+ = partial :test
@@ -0,0 +1,2 @@
1
+ - @layout = '_layouts/variable'
2
+ - @emotions = %w[happy sad mad]
@@ -0,0 +1,2 @@
1
+ $(document).ready () ->
2
+ alert('hello from snack')
@@ -0,0 +1,2 @@
1
+ body
2
+ background: blue
@@ -0,0 +1,3 @@
1
+ body {
2
+ background: blue;
3
+ }
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snack
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Rob Law
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-10-17 00:00:00 -07:00
17
+ default_executable: snack
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: rack
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: tilt
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :development
44
+ version_requirements: *id002
45
+ - !ruby/object:Gem::Dependency
46
+ name: minitest
47
+ prerelease: false
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ type: :development
57
+ version_requirements: *id003
58
+ - !ruby/object:Gem::Dependency
59
+ name: haml
60
+ prerelease: false
61
+ requirement: &id004 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 2
68
+ - 2
69
+ - 11
70
+ version: 2.2.11
71
+ type: :development
72
+ version_requirements: *id004
73
+ - !ruby/object:Gem::Dependency
74
+ name: coffee-script
75
+ prerelease: false
76
+ requirement: &id005 !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ type: :development
85
+ version_requirements: *id005
86
+ description: Snack is a small framework for building static websites.
87
+ email: rob@varietyour.com
88
+ executables:
89
+ - snack
90
+ extensions: []
91
+
92
+ extra_rdoc_files: []
93
+
94
+ files:
95
+ - bin/snack
96
+ - lib/snack.rb
97
+ - test/snack_test.rb
98
+ - test/test_app/index.html.haml
99
+ - test/test_app/pages/_layouts/capture.html.haml
100
+ - test/test_app/pages/_layouts/normal.html.haml
101
+ - test/test_app/pages/_layouts/variable.html.haml
102
+ - test/test_app/pages/_test.html.haml
103
+ - test/test_app/pages/layout-failing.html.haml
104
+ - test/test_app/pages/layout-normal.html.haml
105
+ - test/test_app/pages/partial-failing.html.haml
106
+ - test/test_app/pages/partial-normal.html.haml
107
+ - test/test_app/pages/variable-normal.html.haml
108
+ - test/test_app/public/application.js.coffee
109
+ - test/test_app/public/sass_style.css.sass
110
+ - test/test_app/public/style.css
111
+ has_rdoc: true
112
+ homepage: http://github.com/robinator/snack/
113
+ licenses: []
114
+
115
+ post_install_message:
116
+ rdoc_options: []
117
+
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ segments:
126
+ - 1
127
+ - 8
128
+ - 7
129
+ version: 1.8.7
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ segments:
136
+ - 1
137
+ - 3
138
+ - 6
139
+ version: 1.3.6
140
+ requirements: []
141
+
142
+ rubyforge_project:
143
+ rubygems_version: 1.3.7
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: A static website framework.
147
+ test_files: []
148
+