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.
- data/bin/snack +15 -0
- data/lib/snack.rb +120 -0
- data/test/snack_test.rb +72 -0
- data/test/test_app/index.html.haml +2 -0
- data/test/test_app/pages/_layouts/capture.html.haml +1 -0
- data/test/test_app/pages/_layouts/normal.html.haml +2 -0
- data/test/test_app/pages/_layouts/variable.html.haml +2 -0
- data/test/test_app/pages/_test.html.haml +1 -0
- data/test/test_app/pages/layout-failing.html.haml +2 -0
- data/test/test_app/pages/layout-normal.html.haml +2 -0
- data/test/test_app/pages/partial-failing.html.haml +1 -0
- data/test/test_app/pages/partial-normal.html.haml +2 -0
- data/test/test_app/pages/variable-normal.html.haml +2 -0
- data/test/test_app/public/application.js.coffee +2 -0
- data/test/test_app/public/sass_style.css.sass +2 -0
- data/test/test_app/public/style.css +3 -0
- metadata +148 -0
data/bin/snack
ADDED
@@ -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
|
data/lib/snack.rb
ADDED
@@ -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
|
data/test/snack_test.rb
ADDED
@@ -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 @@
|
|
1
|
+
#footer= @footer
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a partial!
|
@@ -0,0 +1 @@
|
|
1
|
+
= partial :does_not_exist
|
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
|
+
|