2006-12-04 02:47:37 +00:00
|
|
|
require 'sass/engine'
|
|
|
|
require 'rubygems'
|
|
|
|
require 'action_controller'
|
|
|
|
|
2007-01-16 21:13:55 +00:00
|
|
|
RAILS_ROOT = '. 'unless self.class.const_defined?('RAILS_ROOT')
|
|
|
|
RAILS_ENV = 'production' unless self.class.const_defined?('RAILS_ENV')
|
2007-01-07 04:08:48 +00:00
|
|
|
|
2006-12-04 02:47:37 +00:00
|
|
|
module Sass
|
2006-12-17 16:45:07 +00:00
|
|
|
# This module contains methods that ActionController calls
|
|
|
|
# to automatically update Sass templates that need updating.
|
|
|
|
# It wasn't designed to be used outside of the context of ActionController.
|
2006-12-04 02:47:37 +00:00
|
|
|
module Plugin
|
|
|
|
class << self
|
|
|
|
@@options = {
|
2006-12-04 10:39:06 +00:00
|
|
|
:template_location => RAILS_ROOT + '/public/stylesheets/sass',
|
2006-12-04 10:42:22 +00:00
|
|
|
:css_location => RAILS_ROOT + '/public/stylesheets',
|
2006-12-04 02:47:37 +00:00
|
|
|
:always_update => false,
|
2007-02-06 03:34:49 +00:00
|
|
|
:always_check => RAILS_ENV != "production"
|
2006-12-04 02:47:37 +00:00
|
|
|
}
|
|
|
|
|
2006-12-18 01:31:11 +00:00
|
|
|
# Gets various options for Sass. See README for details.
|
2006-12-04 02:47:37 +00:00
|
|
|
#--
|
|
|
|
# TODO: *DOCUMENT OPTIONS*
|
|
|
|
#++
|
|
|
|
def options
|
|
|
|
@@options
|
|
|
|
end
|
|
|
|
|
|
|
|
# Sets various options for Sass.
|
|
|
|
def options=(value)
|
|
|
|
@@options.merge!(value)
|
|
|
|
end
|
2007-08-28 05:10:48 +00:00
|
|
|
|
2006-12-17 16:45:07 +00:00
|
|
|
# Checks each stylesheet in <tt>options[:css_location]</tt>
|
|
|
|
# to see if it needs updating,
|
|
|
|
# and updates it using the corresponding template
|
|
|
|
# from <tt>options[:templates]</tt>
|
|
|
|
# if it does.
|
2006-12-04 02:47:37 +00:00
|
|
|
def update_stylesheets
|
2007-05-03 09:04:20 +00:00
|
|
|
Dir.glob(File.join(options[:template_location], "**", "*.sass")).entries.each do |file|
|
2007-08-28 05:10:48 +00:00
|
|
|
|
2007-05-03 09:04:20 +00:00
|
|
|
# Get the relative path to the file with no extension
|
|
|
|
name = file.sub(options[:template_location] + "/", "")[0...-5]
|
2007-08-28 05:10:48 +00:00
|
|
|
|
2007-08-28 05:33:57 +00:00
|
|
|
if !forbid_update?(name) && (options[:always_update] || stylesheet_needs_update?(name))
|
2006-12-04 02:47:37 +00:00
|
|
|
css = css_filename(name)
|
|
|
|
File.delete(css) if File.exists?(css)
|
2007-08-28 05:10:48 +00:00
|
|
|
|
2007-02-02 06:15:28 +00:00
|
|
|
filename = template_filename(name)
|
2007-03-01 05:06:54 +00:00
|
|
|
l_options = @@options.dup
|
|
|
|
l_options[:filename] = filename
|
2007-03-25 08:20:33 +00:00
|
|
|
l_options[:load_paths] = (l_options[:load_paths] || []) + [l_options[:template_location]]
|
2007-03-01 05:06:54 +00:00
|
|
|
engine = Engine.new(File.read(filename), l_options)
|
2007-08-28 05:10:48 +00:00
|
|
|
result = begin
|
|
|
|
engine.render
|
|
|
|
rescue Exception => e
|
|
|
|
exception_string(e)
|
|
|
|
end
|
|
|
|
|
2007-05-03 09:04:20 +00:00
|
|
|
# Create any directories that might be necessary
|
|
|
|
dirs = [l_options[:css_location]]
|
|
|
|
name.split("/")[0...-1].each { |dir| dirs << "#{dirs[-1]}/#{dir}" }
|
|
|
|
dirs.each { |dir| Dir.mkdir(dir) unless File.exist?(dir) }
|
2007-08-28 05:10:48 +00:00
|
|
|
|
2007-05-03 09:04:20 +00:00
|
|
|
# Finally, write the file
|
2006-12-04 02:47:37 +00:00
|
|
|
File.open(css, 'w') do |file|
|
|
|
|
file.print(result)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2007-08-28 05:10:48 +00:00
|
|
|
|
2006-12-04 02:47:37 +00:00
|
|
|
private
|
2007-08-28 05:10:48 +00:00
|
|
|
|
|
|
|
def exception_string(e)
|
|
|
|
if RAILS_ENV != "production"
|
|
|
|
e_string = "#{e.class}: #{e.message}"
|
|
|
|
|
|
|
|
if e.is_a? Sass::SyntaxError
|
|
|
|
e_string << "\non line #{e.sass_line}"
|
|
|
|
|
|
|
|
if e.sass_filename
|
|
|
|
e_string << " of #{e.sass_filename}"
|
|
|
|
|
|
|
|
if File.exists?(e.sass_filename)
|
|
|
|
e_string << "\n\n"
|
|
|
|
|
|
|
|
min = [e.sass_line - 5, 0].max
|
|
|
|
File.read(e.sass_filename).rstrip.split("\n")[
|
|
|
|
min .. e.sass_line + 5
|
|
|
|
].each_with_index do |line, i|
|
|
|
|
e_string << "#{min + i + 1}: #{line}\n"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
"/*\n#{e_string}\n\nBacktrace:\n#{e.backtrace.join("\n")}\n*/"
|
|
|
|
else
|
|
|
|
"/* Internal stylesheet error */"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-12-04 02:47:37 +00:00
|
|
|
def template_filename(name)
|
|
|
|
"#{@@options[:template_location]}/#{name}.sass"
|
|
|
|
end
|
2007-08-28 05:10:48 +00:00
|
|
|
|
2006-12-04 02:47:37 +00:00
|
|
|
def css_filename(name)
|
|
|
|
"#{@@options[:css_location]}/#{name}.css"
|
|
|
|
end
|
2007-08-28 05:10:48 +00:00
|
|
|
|
2007-08-28 05:33:57 +00:00
|
|
|
def forbid_update?(name)
|
|
|
|
name[0] == ?_
|
|
|
|
end
|
|
|
|
|
2006-12-04 02:47:37 +00:00
|
|
|
def stylesheet_needs_update?(name)
|
|
|
|
!File.exists?(css_filename(name)) || (File.mtime(template_filename(name)) - 2) > File.mtime(css_filename(name))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-12-17 16:45:07 +00:00
|
|
|
# This module refers to the ActionController module that's part of Ruby on Rails.
|
|
|
|
# Sass can be used as an alternate templating engine for Rails,
|
|
|
|
# and includes some modifications to make this more doable.
|
|
|
|
# The documentation can be found
|
|
|
|
# here[http://rubyonrails.org/api/classes/ActionController/Base.html].
|
2006-12-04 02:47:37 +00:00
|
|
|
module ActionController
|
2006-12-17 16:45:07 +00:00
|
|
|
class Base # :nodoc:
|
2006-12-04 02:47:37 +00:00
|
|
|
alias_method :sass_old_process, :process
|
|
|
|
def process(*args)
|
|
|
|
Sass::Plugin.update_stylesheets if Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
|
|
|
|
sass_old_process(*args)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|