big_band 0.2.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.
Files changed (54) hide show
  1. data/LICENSE +27 -0
  2. data/README.rdoc +303 -0
  3. data/README.rdoc.erb +39 -0
  4. data/Rakefile +129 -0
  5. data/big_band.gemspec +29 -0
  6. data/example/example.rb +13 -0
  7. data/example/views/index.haml +8 -0
  8. data/example/views/layout.haml +2 -0
  9. data/example/views/stylesheets/_base.sass +1 -0
  10. data/example/views/stylesheets/screen.sass +12 -0
  11. data/lib/big_band/advanced_routes.rb +184 -0
  12. data/lib/big_band/basic_extensions.rb +176 -0
  13. data/lib/big_band/compass/big_band.rb +4 -0
  14. data/lib/big_band/compass/stylesheets/_big_band.sass +1 -0
  15. data/lib/big_band/compass/stylesheets/big_band/_blueprint.sass +1 -0
  16. data/lib/big_band/compass/stylesheets/big_band/_utilities.sass +6 -0
  17. data/lib/big_band/compass/stylesheets/big_band/blueprint/_html5.sass +4 -0
  18. data/lib/big_band/compass/stylesheets/big_band/layouts/_inspector.sass +103 -0
  19. data/lib/big_band/compass/stylesheets/big_band/utilities/_border_radius.sass +27 -0
  20. data/lib/big_band/compass/stylesheets/big_band/utilities/_css3_prefix.sass +14 -0
  21. data/lib/big_band/compass/stylesheets/big_band/utilities/_fancy_buttons.sass +62 -0
  22. data/lib/big_band/compass/stylesheets/big_band/utilities/_html5.sass +3 -0
  23. data/lib/big_band/compass.rb +94 -0
  24. data/lib/big_band/files/overlay-button.png +0 -0
  25. data/lib/big_band/integration/bacon.rb +10 -0
  26. data/lib/big_band/integration/monk.rb +26 -0
  27. data/lib/big_band/integration/rake.rb +60 -0
  28. data/lib/big_band/integration/rspec.rb +11 -0
  29. data/lib/big_band/integration/test/spec.rb +2 -0
  30. data/lib/big_band/integration/test/unit.rb +2 -0
  31. data/lib/big_band/integration/test.rb +42 -0
  32. data/lib/big_band/integration/test_spec.rb +8 -0
  33. data/lib/big_band/integration/test_unit.rb +10 -0
  34. data/lib/big_band/integration/yard.rb +104 -0
  35. data/lib/big_band/integration.rb +42 -0
  36. data/lib/big_band/more_helpers.rb +50 -0
  37. data/lib/big_band/more_server/rainbows.rb +13 -0
  38. data/lib/big_band/more_server/unicorn.rb +28 -0
  39. data/lib/big_band/more_server.rb +14 -0
  40. data/lib/big_band/reloader.rb +113 -0
  41. data/lib/big_band/sass.rb +28 -0
  42. data/lib/big_band/version.rb +3 -0
  43. data/lib/big_band/web_inspector.rb +178 -0
  44. data/lib/big_band.rb +239 -0
  45. data/lib/big_bang.rb +6 -0
  46. data/lib/yard-sinatra.rb +2 -0
  47. data/spec/big_band/advanced_routes_spec.rb +70 -0
  48. data/spec/big_band/basic_extensions_spec.rb +39 -0
  49. data/spec/big_band/more_server_spec.rb +7 -0
  50. data/spec/big_band/sass_spec.rb +21 -0
  51. data/spec/spec.opts +5 -0
  52. data/spec/spec_helper.rb +4 -0
  53. data/yard-sinatra.gemspec +24 -0
  54. metadata +167 -0
@@ -0,0 +1,184 @@
1
+ require "sinatra/base"
2
+
3
+ class BigBand < Sinatra::Base
4
+
5
+ # AdvancedRoutes makes routes first class objects in Sinatra:
6
+ #
7
+ # require "sinatra"
8
+ # require "big_band"
9
+ #
10
+ # admin_route = get "/admin" do
11
+ # administrate_stuff
12
+ # end
13
+ #
14
+ # before do
15
+ # # Let's deactivate the route if we have no password file.
16
+ # if File.exists? "admin_password"
17
+ # admin_route.activate
18
+ # else
19
+ # admin_route.deactivate
20
+ # end
21
+ # end
22
+ #
23
+ # first_route = get "/:name" do
24
+ # # stuff
25
+ # end
26
+ #
27
+ # other_route = get "/foo_:name" do
28
+ # # other stuff
29
+ # end
30
+ #
31
+ # # Unfortunatly first_route will catch all the requests other_route would
32
+ # # have gotten, since it has been defined first. But wait, we can fix this!
33
+ # other_route.promote
34
+ module AdvancedRoutes
35
+
36
+ module ArrayMethods
37
+ ::Array.send :include, self
38
+
39
+ def to_route(verb, args = {})
40
+ dup.to_route! verb, args
41
+ end
42
+
43
+ def to_route!(verb, args = {})
44
+ extend BigBand::AdvancedRoutes::Route
45
+ self.verb = verb
46
+ args.each do |key, value|
47
+ send "#{key}=", value
48
+ end
49
+ self
50
+ end
51
+
52
+ def signature
53
+ self
54
+ end
55
+
56
+ end
57
+
58
+ module Route
59
+
60
+ attr_accessor :app, :verb, :file, :line, :path
61
+
62
+ def pattern; self[0]; end
63
+ def keys; self[1]; end
64
+ def conditions; self[2]; end
65
+ def block; self[3]; end
66
+ alias to_proc block
67
+
68
+ def pattern=(value); self[0] = value; end
69
+ def keys=(value); self[1] = value; end
70
+ def conditions=(value); self[2] = value; end
71
+ def block=(value); self[3] = value; end
72
+
73
+ def signature
74
+ [pattern, keys, conditions, block]
75
+ end
76
+
77
+ def active?
78
+ app.routes[verb].include? self
79
+ end
80
+
81
+ def activate(at_top = false)
82
+ also_change.each { |r| r.activate }
83
+ return if active?
84
+ meth = at_top ? :unshift : :push
85
+ (app.routes[verb] ||= []).send(meth, self)
86
+ invoke_hook :route_added, verb, path, block
87
+ invoke_hook :advanced_root_activated, self
88
+ self
89
+ end
90
+
91
+ def deactivate
92
+ also_change.each { |r| r.deactivate }
93
+ return unless active?
94
+ (app.routes[verb] ||= []).delete(signature)
95
+ invoke_hook :route_removed, verb, path, block
96
+ invoke_hook :advanced_root_deactivated, self
97
+ self
98
+ end
99
+
100
+ def promote(upwards = true)
101
+ also_change.each { |r| r.promote(upwards) }
102
+ deactivate
103
+ activate(upwards)
104
+ end
105
+
106
+ def file?
107
+ !!@file
108
+ end
109
+
110
+ def inspect
111
+ "#<BigBand::AdvancedRoutes::Route #{ivar_inspect.join ", "}>"
112
+ end
113
+
114
+ def to_route(verb, args = {})
115
+ args = args.dup
116
+ [:app, :verb, :file, :line, :path].each { |key| args[key] ||= send(key) }
117
+ super(verb, args)
118
+ end
119
+
120
+ def also_change(*other_routes)
121
+ (@also_change ||= []).push(*other_routes)
122
+ end
123
+
124
+ private
125
+
126
+ def ivar_inspect
127
+ [:signature, :verb, :app, :file, :line].map do |var|
128
+ value = send(var)
129
+ "@#{var}=#{value.inspect}" unless value.nil?
130
+ end.compact
131
+ end
132
+
133
+ def invoke_hook(*args)
134
+ app.send(:invoke_hook, *args)
135
+ end
136
+
137
+ end
138
+
139
+ module ClassMethods
140
+
141
+ def get(path, opts={}, &block)
142
+ first_route, *other_routes = capture_routes { super }
143
+ first_route.also_change(*other_routes)
144
+ first_route
145
+ end
146
+
147
+ def route(verb, path, options={}, &block)
148
+ file, line = block.source_location if block.respond_to? :source_location
149
+ file ||= caller_files.first
150
+ route = super(verb, path, options, &block)
151
+ route.to_route! verb, :app => self, :file => file.expand_path, :line => line, :path => path
152
+ invoke_hook :advanced_root_added, route
153
+ @capture_routes << route if @capture_routes
154
+ route
155
+ end
156
+
157
+ def each_route(&block)
158
+ return enum_for(:each_route) if respond_to? :enum_for and not block
159
+ routes.inject([]) { |result, (verb, list)| result.push *list.each(&block) }
160
+ end
161
+
162
+ private
163
+
164
+ def capture_routes
165
+ capture_routes_was, @capture_routes = @capture_routes, []
166
+ yield
167
+ captured, @capture_routes = @capture_routes, capture_routes_was
168
+ captured
169
+ end
170
+
171
+ end
172
+
173
+ def self.registered(klass)
174
+ klass.extend ClassMethods
175
+ klass.routes.each do |verb, routes|
176
+ routes.each do |route|
177
+ route.to_route! verb, :app => klass
178
+ klass.send :invoke_hook, :advanced_root_added, route
179
+ end
180
+ end
181
+ end
182
+
183
+ end
184
+ end
@@ -0,0 +1,176 @@
1
+ require "sinatra/base"
2
+ require "monkey-lib"
3
+
4
+ class BigBand < Sinatra::Base
5
+
6
+ CALLERS_TO_IGNORE = (class << Sinatra::Base; CALLERS_TO_IGNORE; end) unless defined? CALLERS_TO_IGNORE
7
+ Dir.chdir __FILE__.dirname.dirname do
8
+ Dir.glob("**/*.rb") { |file| CALLERS_TO_IGNORE << Regexp.new(Regexp.escape(file)) }
9
+ end
10
+
11
+ # Basic Sinatra extension (mainly extending Sinatra's standard methods, like set or register).
12
+ # Also it features a more advanced path guessing than Sinatra::Base.
13
+ # Normally you do not have to register this module manually, as the other extensions will do so
14
+ # if necessary.
15
+ module BasicExtensions
16
+ module ClassMethods
17
+
18
+ attr_writer :root, :guessed_root
19
+
20
+ # More advanced set:
21
+ # - Adds set_#{key} and set_value hooks to set.
22
+ # - Merges the old value with the new one, if both are hashes:
23
+ # set :haml, :format => :html5, :escape_html => true
24
+ # set :haml, :excape_html => false
25
+ # haml # => { :format => :html5, :escape_html => false }
26
+ # - Allowes passing a block:
27
+ # set(:foo) { Time.now }
28
+ # - Defines a helper to access #{key} and #{key}? unless a helper/method with that name already exists.
29
+ def set(key, value = self, &block)
30
+ # FIXME: refactor, refactor, refactor
31
+ if block_given?
32
+ raise ArgumentError, "both a value and a block given" if value != self
33
+ value = block
34
+ end
35
+ symbolized = (key.to_sym if key.respond_to? :to_sym)
36
+ old_value = (send(symbolized) if symbolized and respond_to? symbolized)
37
+ value = old_value.merge value if value.is_a? Hash and old_value.is_a? Hash
38
+ super(key, value)
39
+ if symbolized
40
+ method_names = instance_methods.map { |m| m.to_s }
41
+ define_method(key) { self.class.send(key) } unless method_names.include? key.to_s
42
+ define_method("#{key}?") { self.class.send("#{key}?") } unless method_names.include? "#{key}?"
43
+ end
44
+ # HACK: Sinatra::Base.set uses recursion and in the final step value always
45
+ # is a Proc. Also, if value is a Proc no step ever follows. I abuse this to
46
+ # invoke the hooks only once per set.
47
+ if value.is_a? Proc
48
+ invoke_hook "set_#{key}", self
49
+ invoke_hook :set_value, self, key
50
+ end
51
+ self
52
+ end
53
+
54
+ # More advacend register:
55
+ # - If an exntesion is registered twice, the registered hook will only be called once.
56
+ def register(*extensions, &block)
57
+ extensions.reject! { |e| self.extensions.include? e }
58
+ super(*extensions, &block)
59
+ end
60
+
61
+ # Short hand so you can skip those ugly File.expand_path(File.join(File.dirname(__FILE__), ...))
62
+ # lines.
63
+ def root_path(*args)
64
+ relative = File.join(*args)
65
+ return relative if relative.expand_path == relative
66
+ root.expand_path / relative
67
+ end
68
+
69
+ # Like root_path, but does return an array instead of a string. Optionally takes a block that will
70
+ # be called for each entry once.
71
+ #
72
+ # Example:
73
+ # class Foo < BigBand
74
+ # root_glob("app", "{models,views,controllers}", "*.rb") { |file| load file }
75
+ # end
76
+ def root_glob(*args, &block)
77
+ Dir.glob(root_path(*args), &block)
78
+ end
79
+
80
+ # Whether or not to start a webserver.
81
+ def run?
82
+ @run ||= true
83
+ @run and !@running and app_file? and $0.expand_path == app_file.expand_path
84
+ end
85
+
86
+ # Disable automatically running this class as soon it is subclassed.
87
+ def inherited
88
+ super
89
+ @run = false
90
+ end
91
+
92
+ # The application's root directory. BigBand will guess if missing.
93
+ def root
94
+ return ".".expand_path unless app_file?
95
+ return @root if @root
96
+ @guessed_root ||= begin
97
+ dir = app_file.expand_path.dirname
98
+ if dir.basename == "lib" and not (dir / "lib").directory?
99
+ dir.dirname
100
+ else
101
+ dir
102
+ end
103
+ end
104
+ end
105
+
106
+ # Returns true if the #root is known.
107
+ def root?
108
+ !!@root || app_file?
109
+ end
110
+
111
+ # Option parser for #run!
112
+ def run_option_parser
113
+ @run_option_parser ||= begin
114
+ require 'optparse'
115
+ OptionParser.new do |op|
116
+ op.on('-x') { set :lock, true }
117
+ op.on('-e env') { |val| set :environment, val.to_sym }
118
+ op.on('-s server') { |val| set :server, val }
119
+ op.on('-p port') { |val| set :port, val.to_i }
120
+ end
121
+ end
122
+ end
123
+
124
+ # Extended #run!, offers an extandable option parser for
125
+ # BigBand with the same standard options as the one of
126
+ # Sinatra#Default (see #run_option_parser).
127
+ def run!(options = {})
128
+ run_option_parser.parse!(ARGV.dup) unless ARGV.empty?
129
+ @running = true
130
+ super(options)
131
+ end
132
+
133
+ end
134
+
135
+ module InstanceMethods
136
+
137
+ # See BigBand::BasicExtentions::ClassMethods#root_path
138
+ def root_path(*args)
139
+ self.class.root_path(*args)
140
+ end
141
+
142
+ # See BigBand::BasicExtentions::ClassMethods#root_path
143
+ def root_glob(*args, &block)
144
+ self.class.root_glob(*args, &block)
145
+ end
146
+
147
+ # See BigBand::BasicExtentions::ClassMethods#root
148
+ def root
149
+ self.class.root
150
+ end
151
+
152
+ # See BigBand::BasicExtentions::ClassMethods#root?
153
+ def root?
154
+ self.class.root
155
+ end
156
+
157
+ end
158
+
159
+ def self.registered(klass)
160
+ klass.set :app_file, klass.caller_files.first.expand_path unless klass.app_file?
161
+ klass.extend ClassMethods
162
+ klass.send :include, InstanceMethods
163
+ klass.set :haml, :format => :html5, :escape_html => true
164
+ klass.use Rack::Session::Cookie
165
+ klass.enable :sessions
166
+ klass.get %r{/__big_band__/([^\.]+(\.[^\.]+)?)} do
167
+ send_file(__FILE__.expand_path.dirname / :files / params[:captures].first)
168
+ end
169
+ end
170
+
171
+ def self.set_app_file(klass)
172
+ klass.guessed_root = nil
173
+ end
174
+
175
+ end
176
+ end
@@ -0,0 +1,4 @@
1
+ require "compass"
2
+ require "big_band/compass"
3
+
4
+ Compass::Frameworks.register 'big_band', File.expand_path(File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ @import big_band/utilities.sass
@@ -0,0 +1 @@
1
+ @import blueprint/html5.sass
@@ -0,0 +1,6 @@
1
+ @import compass/reset.sass
2
+ @import compass/utilities.sass
3
+ @import utilities/border_radius.sass
4
+ @import utilities/css3_prefix.sass
5
+ @import utilities/fancy_buttons.sass
6
+ @import utilities/html5.sass
@@ -0,0 +1,4 @@
1
+ @import ../utilities/html5.sass
2
+
3
+ =blueprint_html5
4
+ +html5
@@ -0,0 +1,103 @@
1
+ @import ../utilities.sass
2
+ @import blueprint.sass
3
+ @import blueprint/screen.sass
4
+ @import blueprint/modules/fancy_type.sass
5
+ @import blueprint/modules/scaffolding.sass
6
+ @import blueprint/modules/typography.sass
7
+
8
+ =layout_inspector
9
+ +html5
10
+ +blueprint-typography
11
+ +fancy-paragraphs
12
+ body
13
+ padding: 5em 1em
14
+ background-color: #ddd
15
+ color
16
+ header
17
+ +box-shadow(0 2px 15px rgba(0, 0, 0, 0.8))
18
+ padding: 0px 10px
19
+ text-align: right
20
+ font-size: 80%
21
+ background:
22
+ color: rgba(0, 0, 0, 0.5)
23
+ image: url(/__big_band__/overlay-button.png)
24
+ repeat: repeat-x
25
+ border-bottom: solid 2px #333
26
+ color: #333
27
+ position: fixed
28
+ top: 0
29
+ right: 0
30
+ width: 100%
31
+ nav
32
+ a
33
+ +fancy-button-link(#040, 20px, 100px)
34
+ margin: 5px
35
+ h1
36
+ font:
37
+ weight: 500
38
+ size: 40px
39
+ margin: 0px
40
+ float: left
41
+ padding-left: 20px
42
+ color: #333
43
+ text-shadow: 0px 1px 2px rgba(0,0,0,0.8), -1px -1px 3px #eee, 0px 0px 8px rgba(0,0,0,0.7)
44
+ h2
45
+ font:
46
+ weight: bold
47
+ size: 130%
48
+ border-bottom: dotted 1px #bbb
49
+ width: 500px
50
+ table
51
+ +box-shadow(0px 3px 10px rgba(0,0,0,0.7))
52
+ border: solid 1px #555
53
+ background:
54
+ color: #fff
55
+ image: url(/__big_band__/overlay-button.png)
56
+ padding: 0px
57
+ width: 80%
58
+ margin: 0px 10%
59
+ tr
60
+ th, td
61
+ padding:
62
+ bottom: 0
63
+ top: 0
64
+ left: 5px
65
+ right: 20px
66
+ th
67
+ background-color: #555
68
+ color: #fff
69
+ font:
70
+ weight: bold
71
+ size: 90%
72
+ td
73
+ border:
74
+ color: #ddd
75
+ style: solid
76
+ width: 0px
77
+ left-width: 1px
78
+ min-width: 80px
79
+ footer
80
+ margin-top: 20px
81
+ +alt
82
+ a
83
+ color: #040
84
+ text-decoration: none
85
+ &:hover, &:visited
86
+ color: #040
87
+ &:hover
88
+ text-decoration: underline
89
+ .note
90
+ +box-shadow(0px 3px 10px rgba(0,0,0,0.7))
91
+ +border-radius
92
+ margin:
93
+ top: 5px
94
+ left: 10%
95
+ right: 10%
96
+ bottom: 20px
97
+ padding: 2px
98
+ background-color: #eee
99
+ text-align: center
100
+ font-size: 110%
101
+ a
102
+ font-weight: bold
103
+
@@ -0,0 +1,27 @@
1
+ @import "css3_prefix.sass"
2
+
3
+ !default_border_radius = 10px
4
+
5
+ =border-radius(!lt = "auto", !rt = "auto", !rb = "auto", !lb = "auto")
6
+ @if !lt == "auto"
7
+ !lt = !default_border_radius
8
+ @if !rt == "auto"
9
+ !rt = !lt
10
+ @if !rb == "auto"
11
+ !rb = !lt
12
+ @if !lb == "auto"
13
+ !lb = !rt
14
+ min-width = max(!lt + !rt, !lb + !rb)
15
+ min-height = max(!lt + !lb, !rt + !rb)
16
+ +border-radius-no-min-size(!lt, !rt, !rb, !lb)
17
+
18
+ =border-radius-no-min-size(!lt, !rt, !rb, !lb)
19
+ +prefixed("border-top-left-radius", !lt)
20
+ +prefixed("border-top-right-radius", !rt)
21
+ +prefixed("border-bottom-left-radius", !lb)
22
+ +prefixed("border-bottom-right-radius", !rb)
23
+ -moz-border-radius:
24
+ topleft = !lt
25
+ topright = !rt
26
+ bottomright = !rb
27
+ bottomleft = !lb
@@ -0,0 +1,14 @@
1
+ =prefixed(!attribute, !value)
2
+ -moz-#{!attribute} = !value
3
+ -webkit-#{!attribute} = !value
4
+ -khtml-#{!attribute} = !value
5
+ -ms-#{!attribute} = !value
6
+ -o-#{!attribute} = !value
7
+ #{!attribute} = !value
8
+
9
+ =box-shadow(!parameters)
10
+ +prefixed(box-shadow, !parameters)
11
+
12
+ =transition(!property, !duration)
13
+ +prefixed("transition-property", !property)
14
+ +prefixed("transition-duration", !duration)
@@ -0,0 +1,62 @@
1
+ @import border_radius.sass
2
+ @import css3_prefix.sass
3
+
4
+ !fancy_button_color = #222
5
+ !fancy_button_height = 30px
6
+ !fancy_button_width = "auto"
7
+ !fancy_button_radius = "auto"
8
+ !fancy_button_darkening = 0.3
9
+
10
+ =fancy-button(!color = !fancy_button_color, !height = !fancy_button_height, !width = !fancy_button_width, !radius = !fancy_button_radius)
11
+ @if !radius == "auto"
12
+ !radius = !height
13
+ @if !height < !radius * 2
14
+ !radius = !height / 2
15
+ +border-radius(!radius)
16
+ +box-shadow(0 1px 10px rgba(0, 0, 0, 0.6))
17
+ text-shadow = 0 -1px (!height * 0.1) rgba(0,0,0,0.7)
18
+ border-bottom: 1px solid rgba(0, 0, 0, 0.25)
19
+ background:
20
+ color = !color
21
+ image: url(/__big_band__/overlay-button.png)
22
+ repeat: repeat-x
23
+ attachment: scroll
24
+ position:
25
+ top: 0
26
+ left: 0
27
+ display: inline-block
28
+ padding = (!height * 0.1 - 1px) (!height * 0.5)
29
+ color: #fff !important
30
+ text:
31
+ decoration: none
32
+ align: center
33
+ -moz-background:
34
+ clip: border
35
+ inline-policy: continuous
36
+ font:
37
+ family: Arial,Helvetica,Helvetica Neue,Verdana,sans-serif
38
+ weight: bold
39
+ size = !height * 0.8
40
+ height = !height !important
41
+ width = !width
42
+ line-height: 1.2
43
+
44
+ =fancy-button-link(!color = !fancy_button_color, !height = !fancy_button_height, !width = !fancy_button_width, !radius = !fancy_button_radius, !darkening = !fancy_button_darkening)
45
+ !offset = !height * 0.1 + 3px
46
+ +fancy-button(!color, !height, !width, !radius)
47
+ +prefixed("transition-property", "background, left, top, box-shadow, -moz-box-shadow, -webkit-box-shadow")
48
+ +prefixed("transition-duration", "0.5s")
49
+ position: relative
50
+ top: 0
51
+ left: 0
52
+ cursor: pointer
53
+ margin = !offset
54
+ &:hover
55
+ +fancy-button(!color * !darkening, !height, !width, !radius)
56
+ +box-shadow(!offset !offset + 1px !offset + 10px rgba(0, 0, 0, 0.5))
57
+ left = -!offset
58
+ top = -!offset
59
+ &:visited, &:hover
60
+ color = !color
61
+ text-decoration: none
62
+
@@ -0,0 +1,3 @@
1
+ =html5
2
+ header, footer, nav
3
+ display: block
@@ -0,0 +1,94 @@
1
+ require "sinatra/base"
2
+ require "big_band/basic_extensions"
3
+ require "big_band/advanced_routes"
4
+ require "big_band/compass/big_band"
5
+ require "big_band/sass"
6
+
7
+ class BigBand < Sinatra::Base
8
+
9
+ # Integrates the Compass stylesheet framework with Sinatra.
10
+ #
11
+ # Usage without doing something:
12
+ #
13
+ # require "big_band"
14
+ # class Foo < BigBand; end
15
+ #
16
+ # If you create a directory called views/stylesheets and place your
17
+ # sass files in there, there you go. Just call stylesheet(name) form
18
+ # your view to get the correct stylesheet tag. The URL for your
19
+ # stylesheets will be /stylesheets/:name.css.
20
+ #
21
+ # Of course you can use any other setup. Say, you want to store your
22
+ # stylesheets in views/css and want the URL to be /css/:name.css:
23
+ #
24
+ # class Foo < BigBand
25
+ # get_compass("css")
26
+ # end
27
+ #
28
+ # But what about more complex setups?
29
+ #
30
+ # class Foo < BigBand
31
+ # set :compass, :sass_dir => "/foo/bar/blah"
32
+ # get_compass("/foo/:name.css") do
33
+ # compass :one_stylesheet
34
+ # end
35
+ # end
36
+ #
37
+ # Note that already generated routes will be deactivated by calling
38
+ # get_compass again.
39
+ module Compass
40
+
41
+ module ClassMethods
42
+ attr_reader :compass_route
43
+ def get_compass(path, &block)
44
+ block ||= Proc.new do |file|
45
+ content_type 'text/css', :charset => 'utf-8'
46
+ compass :"#{path}/#{params[:name]}"
47
+ end
48
+ set :compass, :sass_dir => klass.views / path unless compass[:sass_dir] && compass[:sass_dir].directory?
49
+ @compass_route.deactivate if @compass_route
50
+ @compass_route = get("/#{path}" / ":name.css", &block)
51
+ end
52
+ end
53
+
54
+ module InstanceMethods
55
+ def compass(file, options = {})
56
+ options.merge! ::Compass.sass_engine_options
57
+ sass file, options
58
+ end
59
+ def stylesheet(*args)
60
+ raise NotImplementedError, "yet to be implemented"
61
+ end
62
+ end
63
+
64
+ def self.registered(klass)
65
+ klass.register BasicExtensions
66
+ klass.register AdvancedRoutes
67
+ klass.extend ClassMethods
68
+ klass.send :include, InstanceMethods
69
+ klass.set :compass,
70
+ :project_path => klass.root_path, :output_style => (klass.development? ? :expanded : :compressed),
71
+ :sass_dir => klass.views / "stylesheets", :line_comments => klass.development?
72
+ set_app_file(klass) if klass.app_file?
73
+ end
74
+
75
+ def self.set_app_file(klass)
76
+ klass.set :compass, :root_path => klass.root_path
77
+ klass.get_compass("stylesheets") if (klass.views / "stylesheets").directory?
78
+ end
79
+
80
+ def self.set_compass(klass)
81
+ ::Compass.configuration do |config|
82
+ config.sass_options ||= {}
83
+ klass.compass.each do |option, value|
84
+ if config.respond_to? option
85
+ config.send "#{option}=", value
86
+ else
87
+ config.sass_options.merge! option.to_sym => value
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ end
94
+ end