hassle 0.0.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.
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