stylo 0.5

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.
Files changed (53) hide show
  1. data/.document +5 -0
  2. data/.gitignore +25 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +18 -0
  5. data/Rakefile +46 -0
  6. data/TODO +4 -0
  7. data/cucumber.yml +2 -0
  8. data/features/fixtures/child.css +3 -0
  9. data/features/fixtures/child.js +3 -0
  10. data/features/fixtures/grand_parent.css +5 -0
  11. data/features/fixtures/grand_parent.js +5 -0
  12. data/features/fixtures/grand_parent_with_parent_with_child.css +11 -0
  13. data/features/fixtures/grand_parent_with_parent_with_child.js +11 -0
  14. data/features/fixtures/parent.css +5 -0
  15. data/features/fixtures/parent.js +5 -0
  16. data/features/fixtures/parent_with_child.css +7 -0
  17. data/features/fixtures/parent_with_child.js +7 -0
  18. data/features/fixtures/processed_sass_child.css +2 -0
  19. data/features/fixtures/processed_sass_which_uses_mixin.css +3 -0
  20. data/features/fixtures/sass_child.scss +4 -0
  21. data/features/fixtures/sass_mixins.scss +3 -0
  22. data/features/fixtures/sass_which_uses_mixin.scss +6 -0
  23. data/features/fixtures.rb +5 -0
  24. data/features/javascripts.feature +19 -0
  25. data/features/response_headers.feature +13 -0
  26. data/features/sass_integration.feature +13 -0
  27. data/features/step_definitions/stylo_steps.rb +24 -0
  28. data/features/stylesheets.feature +31 -0
  29. data/features/stylo_cannot_serve_asset.feature +5 -0
  30. data/features/support/env.rb +24 -0
  31. data/lib/stylo/asset_loader.rb +9 -0
  32. data/lib/stylo/combiner.rb +14 -0
  33. data/lib/stylo/config.rb +14 -0
  34. data/lib/stylo/pipeline_steps/caching.rb +11 -0
  35. data/lib/stylo/pipeline_steps/javascript.rb +15 -0
  36. data/lib/stylo/pipeline_steps/sass.rb +18 -0
  37. data/lib/stylo/pipeline_steps/stylesheet.rb +15 -0
  38. data/lib/stylo/processor.rb +47 -0
  39. data/lib/stylo/rack.rb +20 -0
  40. data/lib/stylo/railtie.rb +13 -0
  41. data/lib/stylo/response.rb +41 -0
  42. data/lib/stylo.rb +5 -0
  43. data/spec/asset_loader_spec.rb +16 -0
  44. data/spec/combiner_spec.rb +41 -0
  45. data/spec/pipeline_steps/caching_spec.rb +26 -0
  46. data/spec/pipeline_steps/javascript_spec.rb +84 -0
  47. data/spec/pipeline_steps/sass_spec.rb +94 -0
  48. data/spec/pipeline_steps/stylesheet_spec.rb +84 -0
  49. data/spec/rack_spec.rb +75 -0
  50. data/spec/spec_helper.rb +18 -0
  51. data/spec/stylo_spec_helpers.rb +30 -0
  52. data/stylo.gemspec +116 -0
  53. metadata +198 -0
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stylo::Combiner do
4
+ let(:request_path_directory) { 'assets' }
5
+ let(:combiner) { Stylo::Combiner.new(request_path_directory, /require "(.*)";/) }
6
+
7
+ describe "when the content does not contain the require pattern" do
8
+ let(:content) { "This is some text." }
9
+
10
+ it "should return the content" do
11
+ combiner.process(content).should == content
12
+ end
13
+ end
14
+
15
+ describe "when the content contains the require pattern" do
16
+ let(:content) { 'require "some_other_file"; and then some other content' }
17
+
18
+ before(:each) do
19
+ Stylo::AssetLoader.stub(:load_content).with('assets/some_other_file').and_return('the required content.')
20
+ end
21
+
22
+ it "should load required content from the asset loader" do
23
+ Stylo::AssetLoader.should_receive(:load_content).with('assets/some_other_file').and_return('the required content.')
24
+
25
+ combiner.process(content)
26
+ end
27
+
28
+ it "should return the combined content" do
29
+ combiner.process(content).should == 'the required content. and then some other content'
30
+ end
31
+
32
+ describe "and the required content has the require pattern" do
33
+ it "should combine the content recursively" do
34
+ Stylo::AssetLoader.stub(:load_content).with('assets/some_other_file').and_return('require "yet_another_file"; the required content.')
35
+ Stylo::AssetLoader.stub(:load_content).with('assets/yet_another_file').and_return('the other required content.')
36
+
37
+ combiner.process(content).should == "the other required content. the required content. and then some other content"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stylo::PipelineSteps::Caching do
4
+ describe "call" do
5
+ describe "when no response has been set" do
6
+ it "should not add a cache header" do
7
+ response = Stylo::Response.new('stylesheets/test.css')
8
+
9
+ Stylo::PipelineSteps::Caching.new().call(response)
10
+
11
+ response.headers.should be_empty
12
+ end
13
+ end
14
+
15
+ describe "when a response has been set" do
16
+ it "should add a cache header" do
17
+ response = Stylo::Response.new('stylesheets/test.css')
18
+ response.set_body('alert ("hello");', :javascript)
19
+
20
+ Stylo::PipelineSteps::Caching.new().call(response)
21
+
22
+ response.headers['Cache-Control'].should == 'public, max-age=86400'
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stylo::PipelineSteps::Javascript do
4
+ let(:step) { Stylo::PipelineSteps::Javascript.new }
5
+
6
+ describe "when the response has not already been set" do
7
+ describe "and the request is not for a javascript asset" do
8
+ it "should not set the response" do
9
+ response = Stylo::Response.new('stylesheets/test.css')
10
+ Stylo::AssetLoader.stub(:load_content).with(response.path).and_return('some-content')
11
+
12
+ step.call(response)
13
+
14
+ response.has_content?.should be_false
15
+ end
16
+ end
17
+
18
+ describe "and the request is for a javascript asset" do
19
+ let(:response) { Stylo::Response.new('javascripts/test.js') }
20
+
21
+ before(:each) do
22
+
23
+ end
24
+
25
+ it "should ask the asset loader to load the javascript content" do
26
+ Stylo::AssetLoader.should_receive(:load_content).with(response.path).and_return(nil)
27
+
28
+ step.call(response)
29
+ end
30
+
31
+ describe "and the asset does not exist" do
32
+ it "should not set the response" do
33
+ Stylo::AssetLoader.stub(:load_content).and_return(nil)
34
+
35
+ step.call(response)
36
+
37
+ response.has_content?.should be_false
38
+ end
39
+ end
40
+
41
+ describe "and the asset exists" do
42
+ let(:javascript_content) { '///require "child.js";' }
43
+ let(:combined_javascript_content) { "alert('hello world');" }
44
+ let(:combiner) { mock(:combiner) }
45
+
46
+ before(:each) do
47
+ Stylo::AssetLoader.stub(:load_content).and_return(javascript_content)
48
+ Stylo::Combiner.stub(:new).with('javascripts', /\/\/\/require "(.*)";/).and_return(combiner)
49
+ combiner.stub(:process).with(javascript_content).and_return(combined_javascript_content)
50
+ end
51
+
52
+ it "should tell the combiner to process the javascript content" do
53
+ Stylo::Combiner.should_receive(:new).with('javascripts', /\/\/\/require "(.*)";/).and_return(combiner)
54
+ combiner.should_receive(:process).with(javascript_content).and_return(combined_javascript_content)
55
+
56
+ step.call(response)
57
+ end
58
+
59
+ it "should set the body of the response to the combined javascript content" do
60
+ step.call(response)
61
+
62
+ response.body.should == combined_javascript_content
63
+ end
64
+
65
+ it "should set the content type to text/javascript" do
66
+ step.call(response)
67
+
68
+ response.headers['Content-Type'].should == 'text/javascript'
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "when the response has already been set" do
75
+ it "should not alter the response" do
76
+ response = Stylo::Response.new('javascripts/test.js')
77
+ response.set_body('some-content', :css)
78
+
79
+ step.call(response)
80
+
81
+ response.body.should == 'some-content'
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stylo::PipelineSteps::Sass do
4
+ let(:step) { Stylo::PipelineSteps::Sass.new }
5
+
6
+ describe "when the response has not already been set" do
7
+ describe "and the request is not for a stylesheet" do
8
+ it "should not set the response" do
9
+ response = Stylo::Response.new('javascripts/test.js')
10
+ Stylo::AssetLoader.stub(:load_content).with(response.path).and_return('some-content')
11
+
12
+ step.call(response)
13
+
14
+ response.has_content?.should be_false
15
+ end
16
+ end
17
+
18
+ describe "and the request is for a stylesheet" do
19
+ let(:requested_path) { 'stylesheets/test.css' }
20
+ let(:sass_path) { 'stylesheets/test.scss' }
21
+ let(:response) { Stylo::Response.new(requested_path) }
22
+
23
+ it "should ask the asset loader to load the sass stylesheet content" do
24
+ Stylo::AssetLoader.should_receive(:load_content).with(sass_path).and_return(nil)
25
+
26
+ step.call(response)
27
+ end
28
+
29
+ describe "and the asset does not exist" do
30
+ it "should not set the response" do
31
+ Stylo::AssetLoader.stub(:load_content).and_return(nil)
32
+
33
+ step.call(response)
34
+
35
+ response.has_content?.should be_false
36
+ end
37
+ end
38
+
39
+ describe "and the asset exists" do
40
+ let(:stylesheet_content) { "html { color: $color; }" }
41
+ let(:combined_stylesheet_content) { "html { color: $red; }" }
42
+ let(:processed_content) { "html { color: red; }" }
43
+ let(:sass_engine) { mock(:sass_engine) }
44
+ let(:combiner) { mock(:combiner) }
45
+
46
+ before(:each) do
47
+ Stylo::AssetLoader.stub(:load_content).and_return(stylesheet_content)
48
+ Stylo::Combiner.stub(:new).with('stylesheets', /@import "(.*)";/).and_return(combiner)
49
+ combiner.stub(:process).with(stylesheet_content).and_return(combined_stylesheet_content)
50
+ ::Sass::Engine.stub(:new).with(combined_stylesheet_content, {:syntax => :scss}).and_return(sass_engine)
51
+ sass_engine.stub(:render).and_return(processed_content)
52
+ end
53
+
54
+ it "should tell the combiner to process the stylesheet content" do
55
+ Stylo::Combiner.should_receive(:new).with('stylesheets', /@import "(.*)";/).and_return(combiner)
56
+ combiner.should_receive(:process).with(stylesheet_content).and_return(combined_stylesheet_content)
57
+
58
+ step.call(response)
59
+ end
60
+
61
+ it "should run the combined content through sass" do
62
+ ::Sass::Engine.should_receive(:new).with(combined_stylesheet_content, {:syntax => :scss}).and_return(sass_engine)
63
+ sass_engine.should_receive(:render).and_return(processed_content)
64
+
65
+ step.call(response)
66
+ end
67
+
68
+ it "should set the body of the response to the combined stylesheet content" do
69
+ step.call(response)
70
+
71
+ response.body.should == processed_content
72
+ end
73
+
74
+ it "should set the content type to text/css" do
75
+ step.call(response)
76
+
77
+ response.headers['Content-Type'].should == 'text/css'
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "when the response has already been set" do
84
+ it "should not alter the response" do
85
+ response = Stylo::Response.new('stylesheets/test.css')
86
+ response.set_body('some-content', :css)
87
+
88
+ step.call(response)
89
+
90
+ response.body.should == 'some-content'
91
+ end
92
+ end
93
+
94
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stylo::PipelineSteps::Stylesheet do
4
+ let(:step) { Stylo::PipelineSteps::Stylesheet.new }
5
+
6
+ describe "when the response has not already been set" do
7
+ describe "and the request is not for a stylesheet" do
8
+ it "should not set the response" do
9
+ response = Stylo::Response.new('javascripts/test.js')
10
+ Stylo::AssetLoader.stub(:load_content).with(response.path).and_return('some-content')
11
+
12
+ step.call(response)
13
+
14
+ response.has_content?.should be_false
15
+ end
16
+ end
17
+
18
+ describe "and the request is for a stylesheet" do
19
+ let(:response) { Stylo::Response.new('stylesheets/test.css') }
20
+
21
+ before(:each) do
22
+
23
+ end
24
+
25
+ it "should ask the asset loader to load the stylesheet content" do
26
+ Stylo::AssetLoader.should_receive(:load_content).with(response.path).and_return(nil)
27
+
28
+ step.call(response)
29
+ end
30
+
31
+ describe "and the asset does not exist" do
32
+ it "should not set the response" do
33
+ Stylo::AssetLoader.stub(:load_content).and_return(nil)
34
+
35
+ step.call(response)
36
+
37
+ response.has_content?.should be_false
38
+ end
39
+ end
40
+
41
+ describe "and the asset exists" do
42
+ let(:stylesheet_content) { "html { color: $color; }" }
43
+ let(:combined_stylesheet_content) { "html { color: red; }" }
44
+ let(:combiner) { mock(:combiner) }
45
+
46
+ before(:each) do
47
+ Stylo::AssetLoader.stub(:load_content).and_return(stylesheet_content)
48
+ Stylo::Combiner.stub(:new).with('stylesheets', /@import "(.*)";/).and_return(combiner)
49
+ combiner.stub(:process).with(stylesheet_content).and_return(combined_stylesheet_content)
50
+ end
51
+
52
+ it "should tell the combiner to process the stylesheet content" do
53
+ Stylo::Combiner.should_receive(:new).with('stylesheets', /@import "(.*)";/).and_return(combiner)
54
+ combiner.should_receive(:process).with(stylesheet_content).and_return(combined_stylesheet_content)
55
+
56
+ step.call(response)
57
+ end
58
+
59
+ it "should set the body of the response to the combined stylesheet content" do
60
+ step.call(response)
61
+
62
+ response.body.should == combined_stylesheet_content
63
+ end
64
+
65
+ it "should set the content type to text/css" do
66
+ step.call(response)
67
+
68
+ response.headers['Content-Type'].should == 'text/css'
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "when the response has already been set" do
75
+ it "should not alter the response" do
76
+ response = Stylo::Response.new('stylesheets/test.css')
77
+ response.set_body('some-content', :css)
78
+
79
+ step.call(response)
80
+
81
+ response.body.should == 'some-content'
82
+ end
83
+ end
84
+ end
data/spec/rack_spec.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stylo::Rack do
4
+ let(:app) { mock(:app) }
5
+ let(:env) { {} }
6
+
7
+ describe "call" do
8
+ let(:pipeline_steps) { [] }
9
+
10
+ before(:each) do
11
+ app.stub(:call)
12
+
13
+ Stylo::Config.stub(:pipeline).and_return(pipeline_steps)
14
+ end
15
+
16
+ it "should call each pipeline step" do
17
+ 3.times do |i|
18
+ step = mock("pipeline step #{i}")
19
+ step.should_receive(:call).with(instance_of(Stylo::Response))
20
+ pipeline_steps << step
21
+ end
22
+
23
+ Stylo::Rack.new(app).call(env)
24
+ end
25
+
26
+ describe "when no step has been able to deal with the request" do
27
+ it "should call back into the app" do
28
+ app.should_receive(:call).with(env)
29
+
30
+ Stylo::Rack.new(app).call(env)
31
+ end
32
+ end
33
+
34
+ describe "when a step has been able to deal with the request" do
35
+ let(:response) { mock(:response, :has_content? => true) }
36
+
37
+ before(:each) do
38
+ Stylo::Response.stub(:new).and_return(response)
39
+ end
40
+
41
+ it "should not call back into the app" do
42
+ app.should_not_receive(:call).with(env)
43
+ response.stub(:build)
44
+
45
+ Stylo::Rack.new(app).call(env)
46
+ end
47
+
48
+ it "should return the built response" do
49
+ response.stub(:build).and_return([200, {}, "some-content"])
50
+
51
+ Stylo::Rack.new(app).call(env).should == response.build
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ def status_code(response)
58
+ response[0]
59
+ end
60
+
61
+ def content_type(response)
62
+ response[1]['Content-Type']
63
+ end
64
+
65
+ def content_length(response)
66
+ response[1]['Content-Length']
67
+ end
68
+
69
+ def cache_control(response)
70
+ response[1]['Cache-Control']
71
+ end
72
+
73
+ def content(response)
74
+ response[2]
75
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ require 'stylo'
7
+ require 'stylo_spec_helpers'
8
+
9
+ RSpec.configure do |config|
10
+ config.include StyloSpecHelpers
11
+ config.include FileUtils
12
+
13
+ config.before(:each) do
14
+ reset_paths
15
+ end
16
+ end
17
+
18
+
@@ -0,0 +1,30 @@
1
+ module StyloSpecHelpers
2
+ def temp_path(path = '')
3
+ File.expand_path(File.join(File.dirname(__FILE__), '../tmp', path))
4
+ end
5
+
6
+ def fixture_path(path)
7
+ File.expand_path(File.join(File.dirname(__FILE__), '../features/fixtures', path))
8
+ end
9
+
10
+ def load_fixture(path)
11
+ File.read fixture_path(path)
12
+ end
13
+
14
+ def write_content(path, content)
15
+ File.open(path, 'w') do |f|
16
+ f.write(content)
17
+ end
18
+ end
19
+
20
+ def reset_paths
21
+ @stylesheets_path = temp_path('stylesheets')
22
+ @javascripts_path = temp_path('javascripts')
23
+ [@stylesheets_path, @javascripts_path].each do |path|
24
+ rm_rf path
25
+ mkdir_p path
26
+ end
27
+
28
+ Stylo::Config.asset_location = temp_path()
29
+ end
30
+ end
data/stylo.gemspec ADDED
@@ -0,0 +1,116 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{stylo}
8
+ s.version = "0.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["mwagg"]
12
+ s.date = %q{2010-10-18}
13
+ s.description = %q{Server side stylesheet combining for readonly hosting environments}
14
+ s.email = %q{michael@guerillatactics.co.uk}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".gitignore",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "TODO",
27
+ "cucumber.yml",
28
+ "features/fixtures.rb",
29
+ "features/fixtures/child.css",
30
+ "features/fixtures/child.js",
31
+ "features/fixtures/grand_parent.css",
32
+ "features/fixtures/grand_parent.js",
33
+ "features/fixtures/grand_parent_with_parent_with_child.css",
34
+ "features/fixtures/grand_parent_with_parent_with_child.js",
35
+ "features/fixtures/parent.css",
36
+ "features/fixtures/parent.js",
37
+ "features/fixtures/parent_with_child.css",
38
+ "features/fixtures/parent_with_child.js",
39
+ "features/fixtures/processed_sass_child.css",
40
+ "features/fixtures/processed_sass_which_uses_mixin.css",
41
+ "features/fixtures/sass_child.scss",
42
+ "features/fixtures/sass_mixins.scss",
43
+ "features/fixtures/sass_which_uses_mixin.scss",
44
+ "features/javascripts.feature",
45
+ "features/response_headers.feature",
46
+ "features/sass_integration.feature",
47
+ "features/step_definitions/stylo_steps.rb",
48
+ "features/stylesheets.feature",
49
+ "features/stylo_cannot_serve_asset.feature",
50
+ "features/support/env.rb",
51
+ "lib/stylo.rb",
52
+ "lib/stylo/asset_loader.rb",
53
+ "lib/stylo/combiner.rb",
54
+ "lib/stylo/config.rb",
55
+ "lib/stylo/pipeline_steps/caching.rb",
56
+ "lib/stylo/pipeline_steps/javascript.rb",
57
+ "lib/stylo/pipeline_steps/sass.rb",
58
+ "lib/stylo/pipeline_steps/stylesheet.rb",
59
+ "lib/stylo/processor.rb",
60
+ "lib/stylo/rack.rb",
61
+ "lib/stylo/railtie.rb",
62
+ "lib/stylo/response.rb",
63
+ "spec/asset_loader_spec.rb",
64
+ "spec/combiner_spec.rb",
65
+ "spec/pipeline_steps/caching_spec.rb",
66
+ "spec/pipeline_steps/javascript_spec.rb",
67
+ "spec/pipeline_steps/sass_spec.rb",
68
+ "spec/pipeline_steps/stylesheet_spec.rb",
69
+ "spec/rack_spec.rb",
70
+ "spec/spec_helper.rb",
71
+ "spec/stylo_spec_helpers.rb",
72
+ "stylo.gemspec"
73
+ ]
74
+ s.homepage = %q{http://github.com/mwagg/stylo}
75
+ s.rdoc_options = ["--charset=UTF-8"]
76
+ s.require_paths = ["lib"]
77
+ s.rubygems_version = %q{1.3.7}
78
+ s.summary = %q{Server side stylesheet combining for readonly hosting environments}
79
+ s.test_files = [
80
+ "spec/asset_loader_spec.rb",
81
+ "spec/combiner_spec.rb",
82
+ "spec/pipeline_steps/caching_spec.rb",
83
+ "spec/pipeline_steps/javascript_spec.rb",
84
+ "spec/pipeline_steps/sass_spec.rb",
85
+ "spec/pipeline_steps/stylesheet_spec.rb",
86
+ "spec/rack_spec.rb",
87
+ "spec/spec_helper.rb",
88
+ "spec/stylo_spec_helpers.rb"
89
+ ]
90
+
91
+ if s.respond_to? :specification_version then
92
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
93
+ s.specification_version = 3
94
+
95
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
96
+ s.add_development_dependency(%q<rspec>, [">= 0"])
97
+ s.add_development_dependency(%q<cucumber>, [">= 0"])
98
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
99
+ s.add_development_dependency(%q<sinatra>, [">= 0"])
100
+ s.add_runtime_dependency(%q<haml>, [">= 3.0.21"])
101
+ else
102
+ s.add_dependency(%q<rspec>, [">= 0"])
103
+ s.add_dependency(%q<cucumber>, [">= 0"])
104
+ s.add_dependency(%q<rack-test>, [">= 0"])
105
+ s.add_dependency(%q<sinatra>, [">= 0"])
106
+ s.add_dependency(%q<haml>, [">= 3.0.21"])
107
+ end
108
+ else
109
+ s.add_dependency(%q<rspec>, [">= 0"])
110
+ s.add_dependency(%q<cucumber>, [">= 0"])
111
+ s.add_dependency(%q<rack-test>, [">= 0"])
112
+ s.add_dependency(%q<sinatra>, [">= 0"])
113
+ s.add_dependency(%q<haml>, [">= 3.0.21"])
114
+ end
115
+ end
116
+