hassle 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009, Pedro Belo, Nick Quaranto
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,105 @@
1
+ h1. Hassle
2
+
3
+ Making "SASS":http://sass-lang.com/ less of a hassle on read only filesystems. (like "Heroku":http://heroku.com)
4
+
5
+ h2. Usage
6
+
7
+ By default, SASS compiles CSS into the @public/@ directory. On platforms like Heroku, "this won't work.":http://docs.heroku.com/constraints#read-only-filesystem Instead, Hassle compiles the SASS for you into @tmp/@ and serves it up via a @Rack::Static@ middleware.
8
+
9
+ Hassle assumes a few basic things about your setup: There's going to be a @tmp/@ directory where it can write to, and @public/@ is where you store your css. A simple example:
10
+
11
+ <pre>
12
+ $ tree
13
+ .
14
+ |-- config.ru
15
+ |-- public
16
+ | `-- stylesheets
17
+ | `-- sass
18
+ | `-- application.sass
19
+ `-- tmp
20
+ `-- hassle
21
+ `-- stylesheets
22
+ `-- application.css
23
+ </pre>
24
+
25
+ With a basic SASS file in @public/stylesheets/sass/application.sass@, you can include it in your views with:
26
+
27
+ <pre>
28
+ <link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
29
+ </pre>
30
+
31
+ Hassle will look at the default sass directory (@public/stylesheets/sass@) and other input directories given in @Sass::Plugin.options[:template_location]@. CSS files are then compiled into @tmp/@ one directory higher than where you specified. Here's a small example of customization:
32
+
33
+ <pre>
34
+ Sass::Plugin.options[:template_location] = "./public/css/templates"
35
+ </pre>
36
+
37
+ And after Hassle runs...
38
+
39
+ <pre>
40
+ $ tree
41
+ .
42
+ |-- config.ru
43
+ |-- public
44
+ | `-- css
45
+ | `-- templates
46
+ | `-- screen.sass
47
+ `-- tmp
48
+ `-- hassle
49
+ `-- css
50
+ `-- screen.css
51
+ </pre>
52
+
53
+ Include this in your views with:
54
+
55
+ <pre>
56
+ <link href="/css/screen.css" media="screen" rel="stylesheet" type="text/css" />
57
+ </pre>
58
+
59
+ h2. Integration
60
+
61
+ Here's how to integrate it with your favorite web framework:
62
+
63
+ h3. Rails
64
+
65
+ For Rails: @script/plugin install git://github.com/pedro/hassle@. Done. Once you're in production mode, Hassle will kick in and prepare your SASS for all to enjoy.
66
+
67
+ h3. Sinatra
68
+
69
+ Here's a sample config.ru that's running here:"http://hassle-sinatra.heroku.com":
70
+
71
+ <pre>
72
+ require 'sinatra'
73
+ require 'hassle'
74
+ require 'haml'
75
+
76
+ get '/' do
77
+ haml <<EOF
78
+ %html
79
+ %head
80
+ %link{:rel => 'stylesheet', :href => "stylesheets/application.css"}
81
+ %body
82
+ %h1 Hassle!
83
+ EOF
84
+ end
85
+
86
+ use Hassle
87
+ run Sinatra::Application
88
+ </pre>
89
+
90
+ And its wonderful SASS file:
91
+
92
+ <pre>
93
+ $ cat public/stylesheets/sass/application.sass
94
+ h1
95
+ font-size: 11em
96
+ color: purple
97
+ </pre>
98
+
99
+ h2. Bugs
100
+
101
+ Found some problems? Post 'em in "Issues":http://github.com/pedro/hassle/issues.
102
+
103
+ h2. License
104
+
105
+ Hassle uses the MIT license. Please check the LICENSE file for more details.
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ if RAILS_ENV == 'production'
2
+ ActionController::Dispatcher.middleware.use Hassle
3
+ end
@@ -0,0 +1,68 @@
1
+ require 'rack'
2
+ require 'sass'
3
+ require 'sass/plugin'
4
+
5
+ class Hassle
6
+ def initialize(app)
7
+ compiler = Hassle::Compiler.new
8
+ compiler.compile
9
+ @static = Rack::Static.new(app,
10
+ :urls => compiler.stylesheets,
11
+ :root => compiler.compile_location)
12
+ end
13
+
14
+ def call(env)
15
+ @static.call(env)
16
+ end
17
+ end
18
+
19
+ class Hassle::Compiler
20
+ def options
21
+ Sass::Plugin.options
22
+ end
23
+
24
+ def css_location(path)
25
+ expanded = File.expand_path(path)
26
+ public_dir = File.join(File.expand_path(Dir.pwd), "public")
27
+
28
+ File.expand_path(compile_location(expanded.gsub(public_dir, ''), '..'))
29
+ end
30
+
31
+ def compile_location(*subdirs)
32
+ File.join(Dir.pwd, "tmp", "hassle", subdirs)
33
+ end
34
+
35
+ def normalize
36
+ template_location = options[:template_location]
37
+
38
+ if template_location.is_a?(Hash) || template_location.is_a?(Array)
39
+ options[:template_location] = template_location.to_a.map do |input, output|
40
+ [input, css_location(input)]
41
+ end
42
+ else
43
+ default_location = File.join(options[:css_location], "sass")
44
+ options[:template_location] = {default_location => css_location(default_location)}
45
+ end
46
+ end
47
+
48
+ def prepare
49
+ options.merge!(:cache => false,
50
+ :never_update => false)
51
+
52
+ options[:template_location].to_a.each do |location|
53
+ FileUtils.mkdir_p(location.last)
54
+ end
55
+ end
56
+
57
+ def stylesheets
58
+ options[:template_location].to_a.map do |location|
59
+ Dir[File.join(location.last, "**", "*.css")].map { |css| css.gsub(compile_location, "/") }
60
+ end.flatten.sort
61
+ end
62
+
63
+ def compile
64
+ normalize
65
+ prepare
66
+ Sass::Plugin.update_stylesheets
67
+ end
68
+ end
@@ -0,0 +1,42 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'rack/test'
4
+
5
+ require File.dirname(__FILE__) + '/../lib/hassle'
6
+
7
+ SASS_OPTIONS = Sass::Plugin.options.dup
8
+
9
+ def write_sass(location, css_file = "screen")
10
+ FileUtils.mkdir_p(location)
11
+ sass_path = File.join(location, "#{css_file}.sass")
12
+ File.open(sass_path, "w") do |f|
13
+ f.write <<EOF
14
+ %h1
15
+ font-size: 42em
16
+ EOF
17
+ end
18
+
19
+ File.join(@hassle.css_location(location), "#{css_file}.css") if @hassle
20
+ end
21
+
22
+ def be_compiled
23
+ simple_matcher("exist") { |given| File.exists?(given) }
24
+ simple_matcher("contain compiled sass") { |given| File.read(given) =~ /h1 \{/ }
25
+ end
26
+
27
+ def have_tmp_dir_removed(*stylesheets)
28
+ simple_matcher("remove tmp dir") do |given|
29
+ given == stylesheets.map { |css| css.gsub(File.join(Dir.pwd, "tmp", "hassle"), "") }
30
+ end
31
+ end
32
+
33
+ def have_served_sass
34
+ simple_matcher("return success") { |given| given.status == 200 }
35
+ simple_matcher("compiled sass") { |given| given.body.should =~ /h1 \{/ }
36
+ end
37
+
38
+ def reset
39
+ Sass::Plugin.options.clear
40
+ Sass::Plugin.options = SASS_OPTIONS
41
+ FileUtils.rm_rf([File.join(Dir.pwd, "public"), File.join(Dir.pwd, "tmp")])
42
+ end
@@ -0,0 +1,104 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ describe Hassle::Compiler do
4
+ before do
5
+ reset
6
+ @hassle = Hassle::Compiler.new
7
+ end
8
+
9
+ it "dumps css into separate folders" do
10
+ @hassle.css_location("./public/stylesheets/sass").should ==
11
+ File.join(Dir.pwd, "tmp", "hassle", "stylesheets")
12
+
13
+ @hassle.css_location("./public/css/compiled").should ==
14
+ File.join(Dir.pwd, "tmp", "hassle", "css")
15
+
16
+ @hassle.css_location("./public/styles/posts/sass").should ==
17
+ File.join(Dir.pwd, "tmp", "hassle", "styles", "posts")
18
+ end
19
+
20
+ describe "compiling sass" do
21
+ before do
22
+ @default_location = Sass::Plugin.options[:css_location]
23
+ end
24
+
25
+ it "moves css into tmp directory with default settings" do
26
+ sass = write_sass(File.join(@default_location, "sass"))
27
+
28
+ @hassle.compile
29
+
30
+ sass.should be_compiled
31
+ @hassle.stylesheets.should have_tmp_dir_removed(sass)
32
+ end
33
+
34
+ it "should not create sass cache" do
35
+ write_sass(File.join(@default_location, "sass"))
36
+ Sass::Plugin.options[:cache] = true
37
+
38
+ @hassle.compile
39
+
40
+ File.exists?(".sass-cache").should be_false
41
+ end
42
+
43
+ it "should compile sass even if disabled with never_update" do
44
+ sass = write_sass(File.join(@default_location, "sass"))
45
+ Sass::Plugin.options[:never_update] = true
46
+
47
+ @hassle.compile
48
+
49
+ sass.should be_compiled
50
+ end
51
+
52
+ it "should compile sass if template location is a hash" do
53
+ new_location = "public/css/sass"
54
+ Sass::Plugin.options[:template_location] = {new_location => "public/css"}
55
+ sass = write_sass(new_location)
56
+
57
+ @hassle.compile
58
+
59
+ sass.should be_compiled
60
+ end
61
+
62
+ it "should compile sass if template location is a hash with multiple locations" do
63
+ location_one = "public/css/sass"
64
+ location_two = "public/stylesheets/sass"
65
+ Sass::Plugin.options[:template_location] = {location_one => "public/css", location_two => "public/css"}
66
+ sass_one = write_sass(location_one, "one")
67
+ sass_two = write_sass(location_two, "two")
68
+
69
+ @hassle.compile
70
+
71
+ sass_one.should be_compiled
72
+ sass_two.should be_compiled
73
+ @hassle.stylesheets.should have_tmp_dir_removed(sass_one, sass_two)
74
+ end
75
+
76
+ it "should compile sass if template location is an array with multiple locations" do
77
+ location_one = "public/css/sass"
78
+ location_two = "public/stylesheets/sass"
79
+ Sass::Plugin.options[:template_location] = [[location_one, "public/css"], [location_two, "public/css"]]
80
+ sass_one = write_sass(location_one, "one")
81
+ sass_two = write_sass(location_two, "two")
82
+
83
+ @hassle.compile
84
+
85
+ sass_one.should be_compiled
86
+ sass_two.should be_compiled
87
+ @hassle.stylesheets.should have_tmp_dir_removed(sass_one, sass_two)
88
+ end
89
+
90
+ it "should not overwrite similarly name files in different directories" do
91
+ location_one = "public/css/sass"
92
+ location_two = "public/stylesheets/sass"
93
+ Sass::Plugin.options[:template_location] = {location_one => "public/css", location_two => "public/css"}
94
+ sass_one = write_sass(location_one, "screen")
95
+ sass_two = write_sass(location_two, "screen")
96
+
97
+ @hassle.compile
98
+
99
+ sass_one.should be_compiled
100
+ sass_two.should be_compiled
101
+ @hassle.stylesheets.should have_tmp_dir_removed(sass_one, sass_two)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Hassle do
4
+ include Rack::Test::Methods
5
+
6
+ def app
7
+ Rack::Builder.new do
8
+ use Hassle
9
+ run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "hello!"]}
10
+ end
11
+ end
12
+
13
+ before do
14
+ reset
15
+ end
16
+
17
+ it "sends through basic responses" do
18
+ get '/'
19
+ last_response.status.should == 200
20
+ last_response.body.should =~ /hello!/
21
+ end
22
+
23
+ describe "a basic setup" do
24
+ before do
25
+ write_sass("./public/stylesheets/sass")
26
+ end
27
+
28
+ it "serves up some sass" do
29
+ get '/stylesheets/screen.css'
30
+ last_response.should have_served_sass
31
+ end
32
+ end
33
+
34
+ describe "a slightly more complex setup" do
35
+ before do
36
+ @location_one = "./public/css/sass"
37
+ @location_two = "./public/stylesheets/sass"
38
+ Sass::Plugin.options[:template_location] = { @location_one => "public/css",
39
+ @location_two => "public/css"}
40
+ write_sass(@location_one, "style")
41
+ write_sass(@location_two, "application")
42
+ end
43
+
44
+ it "serves up some sass from the normal location" do
45
+ get '/stylesheets/application.css'
46
+ last_response.should have_served_sass
47
+ end
48
+
49
+ it "serves up some sass from a different location" do
50
+ get '/css/style.css'
51
+ last_response.should have_served_sass
52
+ end
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hassle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Pedro Belo
8
+ - Nick Quaranto
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-10-16 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rack
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: sass
28
+ type: :runtime
29
+ version_requirement:
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ version:
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ type: :development
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: cucumber
48
+ type: :development
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ - !ruby/object:Gem::Dependency
57
+ name: rack-test
58
+ type: :development
59
+ version_requirement:
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ description: Makes SASS less of a hassle on read-only filesystems by compiling and serving it up for you
67
+ email:
68
+ executables: []
69
+
70
+ extensions: []
71
+
72
+ extra_rdoc_files:
73
+ - LICENSE
74
+ - README.textile
75
+ files:
76
+ - LICENSE
77
+ - README.textile
78
+ - init.rb
79
+ - lib/hassle.rb
80
+ has_rdoc: true
81
+ homepage: http://github.com/pedro/hassle
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options:
86
+ - --charset=UTF-8
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ version:
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 1.3.5
100
+ version:
101
+ requirements: []
102
+
103
+ rubyforge_project:
104
+ rubygems_version: 1.3.5
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Make SASS less of a hassle
108
+ test_files:
109
+ - spec/base.rb
110
+ - spec/hassle_compiler_spec.rb
111
+ - spec/hassle_spec.rb