roda 1.0.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG +34 -0
- data/README.rdoc +18 -13
- data/Rakefile +8 -0
- data/doc/conventions.rdoc +163 -0
- data/doc/release_notes/1.1.0.txt +226 -0
- data/lib/roda.rb +51 -22
- data/lib/roda/plugins/assets.rb +613 -0
- data/lib/roda/plugins/caching.rb +215 -0
- data/lib/roda/plugins/chunked.rb +278 -0
- data/lib/roda/plugins/error_email.rb +112 -0
- data/lib/roda/plugins/flash.rb +3 -3
- data/lib/roda/plugins/hooks.rb +1 -1
- data/lib/roda/plugins/indifferent_params.rb +3 -3
- data/lib/roda/plugins/middleware.rb +3 -8
- data/lib/roda/plugins/multi_route.rb +110 -18
- data/lib/roda/plugins/not_allowed.rb +3 -3
- data/lib/roda/plugins/path.rb +38 -0
- data/lib/roda/plugins/render.rb +18 -16
- data/lib/roda/plugins/render_each.rb +0 -2
- data/lib/roda/plugins/streaming.rb +1 -2
- data/lib/roda/plugins/view_subdirs.rb +7 -1
- data/lib/roda/version.rb +1 -1
- data/spec/assets/css/app.scss +1 -0
- data/spec/assets/css/no_access.css +1 -0
- data/spec/assets/css/raw.css +1 -0
- data/spec/assets/js/head/app.js +1 -0
- data/spec/integration_spec.rb +95 -3
- data/spec/matchers_spec.rb +2 -2
- data/spec/plugin/assets_spec.rb +413 -0
- data/spec/plugin/caching_spec.rb +335 -0
- data/spec/plugin/chunked_spec.rb +182 -0
- data/spec/plugin/default_headers_spec.rb +6 -5
- data/spec/plugin/error_email_spec.rb +76 -0
- data/spec/plugin/multi_route_spec.rb +120 -0
- data/spec/plugin/not_allowed_spec.rb +14 -3
- data/spec/plugin/path_spec.rb +29 -0
- data/spec/plugin/render_each_spec.rb +6 -1
- data/spec/plugin/symbol_matchers_spec.rb +7 -2
- data/spec/request_spec.rb +10 -0
- data/spec/response_spec.rb +47 -0
- data/spec/views/about.erb +1 -0
- data/spec/views/about.str +1 -0
- data/spec/views/content-yield.erb +1 -0
- data/spec/views/home.erb +2 -0
- data/spec/views/home.str +2 -0
- data/spec/views/layout-alternative.erb +2 -0
- data/spec/views/layout-yield.erb +3 -0
- data/spec/views/layout.erb +2 -0
- data/spec/views/layout.str +2 -0
- metadata +57 -2
@@ -24,8 +24,6 @@ class Roda
|
|
24
24
|
# not set a local variable inside the template.
|
25
25
|
module RenderEach
|
26
26
|
module InstanceMethods
|
27
|
-
EMPTY_STRING = ''.freeze
|
28
|
-
|
29
27
|
# For each value in enum, render the given template using the
|
30
28
|
# given opts. The template and options hash are passed to +render+.
|
31
29
|
# Additional options supported:
|
@@ -6,7 +6,7 @@ class Roda
|
|
6
6
|
# use, and template names that do not contain a slash will
|
7
7
|
# automatically use that view subdirectory. Example:
|
8
8
|
#
|
9
|
-
# plugin :render
|
9
|
+
# plugin :render, :layout=>'./layout'
|
10
10
|
# plugin :view_subdirs
|
11
11
|
#
|
12
12
|
# route do |r|
|
@@ -25,6 +25,12 @@ class Roda
|
|
25
25
|
#
|
26
26
|
# This plugin should be loaded after the render plugin, since
|
27
27
|
# it works by overriding parts of the render plugin.
|
28
|
+
#
|
29
|
+
# Note that when a view subdirectory is set, the layout will
|
30
|
+
# also be looked up in the subdirectory unless it contains
|
31
|
+
# a slash. So if you want to use a view subdirectory for
|
32
|
+
# templates but have a shared layout, you should make sure your
|
33
|
+
# layout contains a slash, similar to the example above.
|
28
34
|
module ViewSubdirs
|
29
35
|
module InstanceMethods
|
30
36
|
# Set the view subdirectory to use. This can be set to nil
|
data/lib/roda/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
body { color: red; }
|
@@ -0,0 +1 @@
|
|
1
|
+
no access
|
@@ -0,0 +1 @@
|
|
1
|
+
body { color: blue; }
|
@@ -0,0 +1 @@
|
|
1
|
+
console.log('test')
|
data/spec/integration_spec.rb
CHANGED
@@ -18,7 +18,7 @@ describe "integration" do
|
|
18
18
|
|
19
19
|
end
|
20
20
|
|
21
|
-
it "should setup middleware using use
|
21
|
+
it "should setup middleware using use" do
|
22
22
|
c = @c
|
23
23
|
app(:bare) do
|
24
24
|
use c, "First", "Second" do
|
@@ -35,7 +35,24 @@ describe "integration" do
|
|
35
35
|
body('/hello').should == 'D First Second Block'
|
36
36
|
end
|
37
37
|
|
38
|
-
it "should
|
38
|
+
it "should support adding middleware using use after route block setup" do
|
39
|
+
c = @c
|
40
|
+
app(:bare) do
|
41
|
+
route do |r|
|
42
|
+
r.get "hello" do
|
43
|
+
"D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
use c, "First", "Second" do
|
48
|
+
"Block"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
body('/hello').should == 'D First Second Block'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should inherit middleware in subclass" do
|
39
56
|
c = @c
|
40
57
|
@app = Class.new(app(:bare){use(c, '1', '2'){"3"}})
|
41
58
|
@app.route do |r|
|
@@ -47,7 +64,55 @@ describe "integration" do
|
|
47
64
|
body('/hello').should == 'D 1 2 3'
|
48
65
|
end
|
49
66
|
|
50
|
-
it "should
|
67
|
+
it "should inherit route in subclass" do
|
68
|
+
c = @c
|
69
|
+
app(:bare) do
|
70
|
+
use(c, '1', '2'){"3"}
|
71
|
+
route do |r|
|
72
|
+
r.get "hello" do
|
73
|
+
"D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
@app = Class.new(app)
|
78
|
+
|
79
|
+
body('/hello').should == 'D 1 2 3'
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should use instance of subclass when inheriting routes" do
|
83
|
+
c = @c
|
84
|
+
obj = nil
|
85
|
+
app(:bare) do
|
86
|
+
use(c, '1', '2'){"3"}
|
87
|
+
route do |r|
|
88
|
+
r.get "hello" do
|
89
|
+
obj = self
|
90
|
+
"D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
@app = Class.new(app)
|
95
|
+
|
96
|
+
body('/hello').should == 'D 1 2 3'
|
97
|
+
obj.should be_a_kind_of(@app)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should handle middleware added to subclass using superclass route" do
|
101
|
+
c = @c
|
102
|
+
app(:bare) do
|
103
|
+
route do |r|
|
104
|
+
r.get "hello" do
|
105
|
+
"D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
@app = Class.new(app)
|
110
|
+
@app.use(c, '1', '2'){"3"}
|
111
|
+
|
112
|
+
body('/hello').should == 'D 1 2 3'
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should not have future middleware additions to superclass affect subclass" do
|
51
116
|
c = @c
|
52
117
|
a = app
|
53
118
|
@app = Class.new(a)
|
@@ -60,4 +125,31 @@ describe "integration" do
|
|
60
125
|
|
61
126
|
body('/hello').should == 'D '
|
62
127
|
end
|
128
|
+
|
129
|
+
it "should not have future middleware additions to subclass affect superclass" do
|
130
|
+
c = @c
|
131
|
+
a = app do |r|
|
132
|
+
r.get "hello" do
|
133
|
+
"D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
@app = Class.new(a)
|
137
|
+
@app.use(c, '1', '2'){"3"}
|
138
|
+
@app = a
|
139
|
+
|
140
|
+
body('/hello').should == 'D '
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should have app return the rack application to call" do
|
144
|
+
app(:bare){}.app.should == nil
|
145
|
+
app.route{|r|}
|
146
|
+
app.app.should be_a_kind_of(Proc)
|
147
|
+
c = Class.new{def initialize(app) @app = app end; def call(env) @app.call(env) end}
|
148
|
+
app.use c
|
149
|
+
app.app.should be_a_kind_of(c)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should have route_block return the route block" do
|
153
|
+
app{|r| 1}.route_block.call(nil).should == 1
|
154
|
+
end
|
63
155
|
end
|
data/spec/matchers_spec.rb
CHANGED
@@ -104,7 +104,7 @@ describe "r.is" do
|
|
104
104
|
|
105
105
|
it "matches regexps" do
|
106
106
|
app do |r|
|
107
|
-
r.is
|
107
|
+
r.is(/(\w+)/) do |id|
|
108
108
|
id
|
109
109
|
end
|
110
110
|
end
|
@@ -458,7 +458,7 @@ describe "path matchers" do
|
|
458
458
|
|
459
459
|
it "a path with some regex captures" do
|
460
460
|
app do |r|
|
461
|
-
r.on
|
461
|
+
r.on(/user(\d+)/) do |uid|
|
462
462
|
uid
|
463
463
|
end
|
464
464
|
end
|
@@ -0,0 +1,413 @@
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
begin
|
5
|
+
for lib in %w'tilt sass'
|
6
|
+
require lib
|
7
|
+
end
|
8
|
+
run_tests = true
|
9
|
+
rescue LoadError
|
10
|
+
warn "#{lib} not installed, skipping assets plugin test"
|
11
|
+
end
|
12
|
+
|
13
|
+
if run_tests
|
14
|
+
metadata_file = 'spec/assets/tmp/precompiled.json'
|
15
|
+
js_file = 'spec/assets/js/head/app.js'
|
16
|
+
css_file = 'spec/assets/css/no_access.css'
|
17
|
+
js_mtime = File.mtime(js_file)
|
18
|
+
js_atime = File.atime(js_file)
|
19
|
+
css_mtime = File.mtime(css_file)
|
20
|
+
css_atime = File.atime(css_file)
|
21
|
+
describe 'assets plugin' do
|
22
|
+
before do
|
23
|
+
app(:bare) do
|
24
|
+
plugin :assets,
|
25
|
+
:css => ['app.scss', 'raw.css'],
|
26
|
+
:js => { :head => ['app.js'] },
|
27
|
+
:path => 'spec/assets',
|
28
|
+
:public => 'spec',
|
29
|
+
:css_opts => {:cache=>false}
|
30
|
+
|
31
|
+
route do |r|
|
32
|
+
r.assets
|
33
|
+
|
34
|
+
r.is 'test' do
|
35
|
+
"#{assets(:css)}\n#{assets([:js, :head])}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
after do
|
41
|
+
File.utime(js_atime, js_mtime, js_file)
|
42
|
+
File.utime(css_atime, css_mtime, css_file)
|
43
|
+
File.delete(metadata_file) if File.file?(metadata_file)
|
44
|
+
end
|
45
|
+
after(:all) do
|
46
|
+
FileUtils.rm_r('spec/assets/tmp') if File.directory?('spec/assets/tmp')
|
47
|
+
FileUtils.rm_r('spec/public') if File.directory?('spec/public')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'assets_opts should use correct paths given options' do
|
51
|
+
keys = [:js_path, :css_path, :compiled_js_path, :compiled_css_path, :js_prefix, :css_prefix, :compiled_js_prefix, :compiled_css_prefix]
|
52
|
+
app.assets_opts.values_at(*keys).should == %w"spec/assets/js/ spec/assets/css/ spec/assets/app spec/assets/app assets/js/ assets/css/ assets/app assets/app"
|
53
|
+
|
54
|
+
app.plugin :assets, :path=>'bar/', :public=>'foo/', :prefix=>'as/', :js_dir=>'j/', :css_dir=>'c/', :compiled_name=>'a'
|
55
|
+
app.assets_opts.values_at(*keys).should == %w"bar/j/ bar/c/ foo/as/a foo/as/a as/j/ as/c/ as/a as/a"
|
56
|
+
|
57
|
+
app.plugin :assets, :path=>'bar', :public=>'foo', :prefix=>'as', :js_dir=>'j', :css_dir=>'c', :compiled_name=>'a'
|
58
|
+
app.assets_opts.values_at(*keys).should == %w"bar/j/ bar/c/ foo/as/a foo/as/a as/j/ as/c/ as/a as/a"
|
59
|
+
|
60
|
+
app.plugin :assets, :compiled_js_dir=>'cj', :compiled_css_dir=>'cs', :compiled_path=>'cp'
|
61
|
+
app.assets_opts.values_at(*keys).should == %w"bar/j/ bar/c/ foo/cp/cj/a foo/cp/cs/a as/j/ as/c/ as/cj/a as/cs/a"
|
62
|
+
|
63
|
+
app.plugin :assets, :compiled_js_route=>'cjr', :compiled_css_route=>'ccr', :js_route=>'jr', :css_route=>'cr'
|
64
|
+
app.assets_opts.values_at(*keys).should == %w"bar/j/ bar/c/ foo/cp/cj/a foo/cp/cs/a as/jr/ as/cr/ as/cjr/a as/ccr/a"
|
65
|
+
|
66
|
+
app.plugin :assets, :compiled_js_route=>'cj', :compiled_css_route=>'cs', :js_route=>'j', :css_route=>'c'
|
67
|
+
app.assets_opts.values_at(*keys).should == %w"bar/j/ bar/c/ foo/cp/cj/a foo/cp/cs/a as/j/ as/c/ as/cj/a as/cs/a"
|
68
|
+
|
69
|
+
app.plugin :assets
|
70
|
+
app.assets_opts.values_at(*keys).should == %w"bar/j/ bar/c/ foo/cp/cj/a foo/cp/cs/a as/j/ as/c/ as/cj/a as/cs/a"
|
71
|
+
|
72
|
+
app.plugin :assets, :compiled_js_dir=>'', :compiled_css_dir=>nil, :compiled_js_route=>nil, :compiled_css_route=>nil
|
73
|
+
app.assets_opts.values_at(*keys).should == %w"bar/j/ bar/c/ foo/cp/a foo/cp/a as/j/ as/c/ as/a as/a"
|
74
|
+
|
75
|
+
app.plugin :assets, :js_dir=>'', :css_dir=>nil, :js_route=>nil, :css_route=>nil
|
76
|
+
app.assets_opts.values_at(*keys).should == %w"bar/ bar/ foo/cp/a foo/cp/a as/ as/ as/a as/a"
|
77
|
+
|
78
|
+
app.plugin :assets, :public=>''
|
79
|
+
app.assets_opts.values_at(*keys).should == %w"bar/ bar/ cp/a cp/a as/ as/ as/a as/a"
|
80
|
+
|
81
|
+
app.plugin :assets, :path=>'', :compiled_path=>nil
|
82
|
+
app.assets_opts.values_at(*keys).should == ['', '', 'a', 'a', 'as/', 'as/', 'as/a', 'as/a']
|
83
|
+
|
84
|
+
app.plugin :assets, :prefix=>''
|
85
|
+
app.assets_opts.values_at(*keys).should == ['', '', 'a', 'a', '', '', 'a', 'a']
|
86
|
+
|
87
|
+
app.plugin :assets, :compiled_name=>nil
|
88
|
+
app.assets_opts.values_at(*keys).should == ['', '', '', '', '', '', '', '']
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'assets_opts should use headers and dependencies given options' do
|
92
|
+
keys = [:css_headers, :js_headers, :dependencies]
|
93
|
+
app.assets_opts.values_at(*keys).should == [{'Content-Type'=>"text/css; charset=UTF-8"}, {'Content-Type'=>"application/javascript; charset=UTF-8"}, {}]
|
94
|
+
|
95
|
+
app.plugin :assets, :headers=>{'A'=>'B'}, :dependencies=>{'a'=>'b'}
|
96
|
+
app.assets_opts.values_at(*keys).should == [{'Content-Type'=>"text/css; charset=UTF-8", 'A'=>'B'}, {'Content-Type'=>"application/javascript; charset=UTF-8", 'A'=>'B'}, {'a'=>'b'}]
|
97
|
+
|
98
|
+
app.plugin :assets, :css_headers=>{'C'=>'D'}, :js_headers=>{'E'=>'F'}, :dependencies=>{'c'=>'d'}
|
99
|
+
app.assets_opts.values_at(*keys).should == [{'Content-Type'=>"text/css; charset=UTF-8", 'A'=>'B', 'C'=>'D'}, {'Content-Type'=>"application/javascript; charset=UTF-8", 'A'=>'B', 'E'=>'F'}, {'a'=>'b', 'c'=>'d'}]
|
100
|
+
|
101
|
+
app.plugin :assets
|
102
|
+
app.assets_opts.values_at(*keys).should == [{'Content-Type'=>"text/css; charset=UTF-8", 'A'=>'B', 'C'=>'D'}, {'Content-Type'=>"application/javascript; charset=UTF-8", 'A'=>'B', 'E'=>'F'}, {'a'=>'b', 'c'=>'d'}]
|
103
|
+
|
104
|
+
app.plugin :assets
|
105
|
+
app.assets_opts.values_at(*keys).should == [{'Content-Type'=>"text/css; charset=UTF-8", 'A'=>'B', 'C'=>'D'}, {'Content-Type'=>"application/javascript; charset=UTF-8", 'A'=>'B', 'E'=>'F'}, {'a'=>'b', 'c'=>'d'}]
|
106
|
+
|
107
|
+
app.plugin :assets, :headers=>{'Content-Type'=>'C', 'E'=>'G'}
|
108
|
+
app.assets_opts.values_at(*keys).should == [{'Content-Type'=>"C", 'A'=>'B', 'C'=>'D', 'E'=>'G'}, {'Content-Type'=>"C", 'A'=>'B', 'E'=>'F'}, {'a'=>'b', 'c'=>'d'}]
|
109
|
+
|
110
|
+
app.plugin :assets, :css_headers=>{'A'=>'B1'}, :js_headers=>{'E'=>'F1'}, :dependencies=>{'c'=>'d1'}
|
111
|
+
app.assets_opts.values_at(*keys).should == [{'Content-Type'=>"C", 'A'=>'B1', 'C'=>'D', 'E'=>'G'}, {'Content-Type'=>"C", 'A'=>'B', 'E'=>'F1'}, {'a'=>'b', 'c'=>'d1'}]
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should handle rendering assets, linking to them, and accepting requests for them when not compiling' do
|
115
|
+
html = body('/test')
|
116
|
+
html.scan(/<link/).length.should == 2
|
117
|
+
html =~ %r{href="(/assets/css/app\.scss)"}
|
118
|
+
css = body($1)
|
119
|
+
html =~ %r{href="(/assets/css/raw\.css)"}
|
120
|
+
css2 = body($1)
|
121
|
+
html.scan(/<script/).length.should == 1
|
122
|
+
html =~ %r{src="(/assets/js/head/app\.js)"}
|
123
|
+
js = body($1)
|
124
|
+
css.should =~ /color: red;/
|
125
|
+
css2.should =~ /color: blue;/
|
126
|
+
js.should include('console.log')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should handle rendering assets, linking to them, and accepting requests for them when not compiling, with different options' do
|
130
|
+
app.plugin :assets, :path=>'spec/', :js_dir=>'assets/js', :css_dir=>'assets/css', :prefix=>'a',
|
131
|
+
:js_route=>'foo', :css_route=>'bar', :add_suffix=>true, :css_opts=>{:style=>:compressed}
|
132
|
+
html = body('/test')
|
133
|
+
html.scan(/<link/).length.should == 2
|
134
|
+
html =~ %r{href="(/a/bar/app\.scss.css)"}
|
135
|
+
css = body($1)
|
136
|
+
html =~ %r{href="(/a/bar/raw\.css.css)"}
|
137
|
+
css2 = body($1)
|
138
|
+
html.scan(/<script/).length.should == 1
|
139
|
+
html =~ %r{src="(/a/foo/head/app\.js.js)"}
|
140
|
+
js = body($1)
|
141
|
+
css.should =~ /color:red\}/
|
142
|
+
css2.should =~ /color: blue;/
|
143
|
+
js.should include('console.log')
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should handle rendering assets, linking to them, and accepting requests for them when not compiling with a multi-level hash' do
|
147
|
+
app.plugin :assets, :path=>'spec', :js_dir=>nil, :css_dir=>nil, :prefix=>nil,
|
148
|
+
:css=>{:assets=>{:css=>%w'app.scss raw.css'}}, :js=>{:assets=>{:js=>{:head=>'app.js'}}}
|
149
|
+
app.route do |r|
|
150
|
+
r.assets
|
151
|
+
r.is 'test' do
|
152
|
+
"#{assets([:css, :assets, :css])}\n#{assets([:js, :assets, :js, :head])}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
html = body('/test')
|
156
|
+
html.scan(/<link/).length.should == 2
|
157
|
+
html =~ %r{href="(/assets/css/app\.scss)"}
|
158
|
+
css = body($1)
|
159
|
+
html =~ %r{href="(/assets/css/raw\.css)"}
|
160
|
+
css2 = body($1)
|
161
|
+
html.scan(/<script/).length.should == 1
|
162
|
+
html =~ %r{src="(/assets/js/head/app\.js)"}
|
163
|
+
js = body($1)
|
164
|
+
css.should =~ /color: red;/
|
165
|
+
css2.should =~ /color: blue;/
|
166
|
+
js.should include('console.log')
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should handle :group_subdirs => false' do
|
170
|
+
app.plugin :assets, :path=>'spec', :js_dir=>nil, :css_dir=>nil, :prefix=>nil, :group_subdirs=>false,
|
171
|
+
:css=>{:assets=>{:css=>%w'assets/css/app.scss assets/css/raw.css'}}, :js=>{:assets=>{:js=>{:head=>'assets/js/head/app.js'}}}
|
172
|
+
app.route do |r|
|
173
|
+
r.assets
|
174
|
+
r.is 'test' do
|
175
|
+
"#{assets([:css, :assets, :css])}\n#{assets([:js, :assets, :js, :head])}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
html = body('/test')
|
179
|
+
html.scan(/<link/).length.should == 2
|
180
|
+
html =~ %r{href="(/assets/css/app\.scss)"}
|
181
|
+
css = body($1)
|
182
|
+
html =~ %r{href="(/assets/css/raw\.css)"}
|
183
|
+
css2 = body($1)
|
184
|
+
html.scan(/<script/).length.should == 1
|
185
|
+
html =~ %r{src="(/assets/js/head/app\.js)"}
|
186
|
+
js = body($1)
|
187
|
+
css.should =~ /color: red;/
|
188
|
+
css2.should =~ /color: blue;/
|
189
|
+
js.should include('console.log')
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should handle compiling assets, linking to them, and accepting requests for them' do
|
193
|
+
app.compile_assets
|
194
|
+
html = body('/test')
|
195
|
+
html.scan(/<link/).length.should == 1
|
196
|
+
html =~ %r{href="(/assets/app\.[a-f0-9]{40}\.css)"}
|
197
|
+
css = body($1)
|
198
|
+
html.scan(/<script/).length.should == 1
|
199
|
+
html =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
|
200
|
+
js = body($1)
|
201
|
+
css.should =~ /color: ?red/
|
202
|
+
css.should =~ /color: ?blue/
|
203
|
+
js.should include('console.log')
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should handle compiling assets, linking to them, and accepting requests for them, with different options' do
|
207
|
+
app.plugin :assets, :compiled_path=>nil, :js_dir=>'assets/js', :css_dir=>'assets/css', :prefix=>'a',
|
208
|
+
:public=>'spec/assets', :path=>'spec', :compiled_js_route=>'foo', :compiled_css_route=>'bar'
|
209
|
+
app.compile_assets
|
210
|
+
html = body('/test')
|
211
|
+
html.scan(/<link/).length.should == 1
|
212
|
+
html =~ %r{href="(/a/bar/app\.[a-f0-9]{40}\.css)"}
|
213
|
+
css = body($1)
|
214
|
+
html.scan(/<script/).length.should == 1
|
215
|
+
html =~ %r{src="(/a/foo/app\.head\.[a-f0-9]{40}\.js)"}
|
216
|
+
js = body($1)
|
217
|
+
css.should =~ /color: ?red/
|
218
|
+
css.should =~ /color: ?blue/
|
219
|
+
js.should include('console.log')
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'should handle rendering assets, linking to them, and accepting requests for them when not compiling with a multi-level hash' do
|
223
|
+
app.plugin :assets, :path=>'spec', :js_dir=>nil, :css_dir=>nil, :compiled_js_dir=>nil, :compiled_css_dir=>nil,
|
224
|
+
:css=>{:assets=>{:css=>%w'app.scss raw.css'}}, :js=>{:assets=>{:js=>{:head=>'app.js'}}}
|
225
|
+
app.compile_assets
|
226
|
+
app.route do |r|
|
227
|
+
r.assets
|
228
|
+
r.is 'test' do
|
229
|
+
"#{assets([:css, :assets, :css])}\n#{assets([:js, :assets, :js, :head])}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
html = body('/test')
|
233
|
+
html.scan(/<link/).length.should == 1
|
234
|
+
html =~ %r{href="(/assets/app\.assets\.css\.[a-f0-9]{40}\.css)"}
|
235
|
+
css = body($1)
|
236
|
+
html.scan(/<script/).length.should == 1
|
237
|
+
html =~ %r{src="(/assets/app\.assets\.js\.head\.[a-f0-9]{40}\.js)"}
|
238
|
+
js = body($1)
|
239
|
+
css.should =~ /color: ?red/
|
240
|
+
css.should =~ /color: ?blue/
|
241
|
+
js.should include('console.log')
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should handle :group_subdirs => false when compiling' do
|
245
|
+
app.plugin :assets, :path=>'spec', :js_dir=>nil, :css_dir=>nil, :compiled_js_dir=>nil, :compiled_css_dir=>nil, :group_subdirs=>false,
|
246
|
+
:css=>{:assets=>{:css=>%w'assets/css/app.scss assets/css/raw.css'}}, :js=>{:assets=>{:js=>{:head=>'assets/js/head/app.js'}}}
|
247
|
+
app.compile_assets
|
248
|
+
app.route do |r|
|
249
|
+
r.assets
|
250
|
+
r.is 'test' do
|
251
|
+
"#{assets([:css, :assets, :css])}\n#{assets([:js, :assets, :js, :head])}"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
html = body('/test')
|
255
|
+
html.scan(/<link/).length.should == 1
|
256
|
+
html =~ %r{href="(/assets/app\.assets\.css\.[a-f0-9]{40}\.css)"}
|
257
|
+
css = body($1)
|
258
|
+
html.scan(/<script/).length.should == 1
|
259
|
+
html =~ %r{src="(/assets/app\.assets\.js\.head\.[a-f0-9]{40}\.js)"}
|
260
|
+
js = body($1)
|
261
|
+
css.should =~ /color: ?red/
|
262
|
+
css.should =~ /color: ?blue/
|
263
|
+
js.should include('console.log')
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'should handle automatically creating directories when compiling assets' do
|
267
|
+
app.plugin :assets, :public=>'spec/public'
|
268
|
+
app.compile_assets
|
269
|
+
html = body('/test')
|
270
|
+
html.scan(/<link/).length.should == 1
|
271
|
+
html =~ %r{href="(/assets/app\.[a-f0-9]{40}\.css)"}
|
272
|
+
css = body($1)
|
273
|
+
html.scan(/<script/).length.should == 1
|
274
|
+
html =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
|
275
|
+
js = body($1)
|
276
|
+
css.should =~ /color: ?red/
|
277
|
+
css.should =~ /color: ?blue/
|
278
|
+
js.should include('console.log')
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'should handle compiling only css assets' do
|
282
|
+
app.compile_assets(:css)
|
283
|
+
html = body('/test')
|
284
|
+
html.scan(/<link/).length.should == 1
|
285
|
+
html =~ %r{href="(/assets/app\.[a-f0-9]{40}\.css)"}
|
286
|
+
css = body($1)
|
287
|
+
html.scan(/<script/).length.should == 0
|
288
|
+
css.should =~ /color: ?red/
|
289
|
+
css.should =~ /color: ?blue/
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'should handle compiling only js assets' do
|
293
|
+
app.compile_assets(:js)
|
294
|
+
html = body('/test')
|
295
|
+
html.scan(/<link/).length.should == 0
|
296
|
+
html.scan(/<script/).length.should == 1
|
297
|
+
html =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
|
298
|
+
js = body($1)
|
299
|
+
js.should include('console.log')
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'should handle compiling asset subfolders' do
|
303
|
+
app.compile_assets([:js, :head])
|
304
|
+
html = body('/test')
|
305
|
+
html.scan(/<link/).length.should == 0
|
306
|
+
html.scan(/<script/).length.should == 1
|
307
|
+
html =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
|
308
|
+
js = body($1)
|
309
|
+
js.should include('console.log')
|
310
|
+
end
|
311
|
+
|
312
|
+
it 'should handle compiling assets when only a single asset type is present' do
|
313
|
+
app.plugin :assets, :css=>nil
|
314
|
+
app.compile_assets
|
315
|
+
html = body('/test')
|
316
|
+
html.scan(/<link/).length.should == 0
|
317
|
+
html.scan(/<script/).length.should == 1
|
318
|
+
html =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
|
319
|
+
js = body($1)
|
320
|
+
js.should include('console.log')
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'should handle compiling assets when an empty array is used' do
|
324
|
+
app.plugin :assets, :css=>[]
|
325
|
+
app.compile_assets
|
326
|
+
html = body('/test')
|
327
|
+
html.scan(/<link/).length.should == 0
|
328
|
+
html.scan(/<script/).length.should == 1
|
329
|
+
html =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
|
330
|
+
js = body($1)
|
331
|
+
js.should include('console.log')
|
332
|
+
end
|
333
|
+
|
334
|
+
it '#assets should include attributes given' do
|
335
|
+
app.new.assets([:js, :head], 'a'=>'b').should == '<script type="text/javascript" a="b" src="/assets/js/head/app.js"></script>'
|
336
|
+
end
|
337
|
+
|
338
|
+
it '#assets should escape attribute values given' do
|
339
|
+
app.new.assets([:js, :head], 'a'=>'b"e').should == '<script type="text/javascript" a="b"e" src="/assets/js/head/app.js"></script>'
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'requests for assets should return 304 if the asset has not been modified' do
|
343
|
+
loc = '/assets/js/head/app.js'
|
344
|
+
lm = header('Last-Modified', loc)
|
345
|
+
status(loc, 'HTTP_IF_MODIFIED_SINCE'=>lm).should == 304
|
346
|
+
body(loc, 'HTTP_IF_MODIFIED_SINCE'=>lm).should == ''
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'requests for assets should not return 304 if the asset has been modified' do
|
350
|
+
loc = '/assets/js/head/app.js'
|
351
|
+
lm = header('Last-Modified', loc)
|
352
|
+
File.utime(js_atime, js_mtime+1, js_file)
|
353
|
+
status(loc, 'HTTP_IF_MODIFIED_SINCE'=>lm).should == 200
|
354
|
+
body(loc, 'HTTP_IF_MODIFIED_SINCE'=>lm).should include('console.log')
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'requests for assets should return 304 if the dependency of an asset has not been modified' do
|
358
|
+
app.plugin :assets, :dependencies=>{js_file=>css_file}
|
359
|
+
loc = '/assets/js/head/app.js'
|
360
|
+
lm = header('Last-Modified', loc)
|
361
|
+
status(loc, 'HTTP_IF_MODIFIED_SINCE'=>lm).should == 304
|
362
|
+
body(loc, 'HTTP_IF_MODIFIED_SINCE'=>lm).should == ''
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'requests for assets should return 200 if the dependency of an asset has been modified' do
|
366
|
+
app.plugin :assets, :dependencies=>{js_file=>css_file}
|
367
|
+
loc = '/assets/js/head/app.js'
|
368
|
+
lm = header('Last-Modified', loc)
|
369
|
+
File.utime(css_atime, [css_mtime+1, js_mtime+1].max, css_file)
|
370
|
+
status(loc, 'HTTP_IF_MODIFIED_SINCE'=>lm).should == 200
|
371
|
+
body(loc, 'HTTP_IF_MODIFIED_SINCE'=>lm).should include('console.log')
|
372
|
+
end
|
373
|
+
|
374
|
+
it 'should do a terminal match for assets' do
|
375
|
+
status('/assets/css/app.scss/foo').should == 404
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'should only allow files that you specify' do
|
379
|
+
status('/assets/css/no_access.css').should == 404
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'should not add routes for empty asset types' do
|
383
|
+
app.plugin :assets, :css=>nil
|
384
|
+
a = app::RodaRequest.assets_matchers
|
385
|
+
a.length.should == 1
|
386
|
+
a.first.length.should == 2
|
387
|
+
a.first.first.should == 'js'
|
388
|
+
'assets/js/head/app.js'.should =~ a.first.last
|
389
|
+
'assets/js/head/app2.js'.should_not =~ a.first.last
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'should not add routes if no asset types' do
|
393
|
+
app.plugin :assets, :js=>nil, :css=>nil
|
394
|
+
app::RodaRequest.assets_matchers.should == []
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'should support :precompiled option' do
|
398
|
+
app.plugin :assets, :precompiled=>metadata_file
|
399
|
+
File.exist?(metadata_file).should == false
|
400
|
+
app.new.assets([:js, :head]).should == '<script type="text/javascript" src="/assets/js/head/app.js"></script>'
|
401
|
+
|
402
|
+
app.compile_assets
|
403
|
+
File.exist?(metadata_file).should == true
|
404
|
+
app.new.assets([:js, :head]).should =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
|
405
|
+
|
406
|
+
app.plugin :assets, :compiled=>false, :precompiled=>false
|
407
|
+
app.new.assets([:js, :head]).should == '<script type="text/javascript" src="/assets/js/head/app.js"></script>'
|
408
|
+
|
409
|
+
app.plugin :assets, :precompiled=>metadata_file
|
410
|
+
app.new.assets([:js, :head]).should =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|