Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 833bcf5858
Fetching contributors…

Cannot retrieve contributors at this time

144 lines (123 sloc) 4.686 kb
# Less::More provides methods for parsing LESS files in a rails application to CSS target files.
#
# When Less::More.parse is called, all files in Less::More.source_path will be parsed using LESS
# and saved as CSS files in Less::More.destination_path. If Less::More.compression is set to true,
# extra line breaks will be removed to compress the CSS files.
#
# By default, Less::More.parse will be called for each request in `development` environment and on
# application initialization in `production` environment.
begin
require 'less'
rescue LoadError => e
e.message << " (You may need to install the less gem)"
raise e
end
class Less::More
HEADER = %{/*\n\n\n\n\n\tThis file was auto generated by Less (http://lesscss.org). To change the contents of this file, edit %s instead.\n\n\n\n\n*/}
class << self
# Less::More.compression = true/false --- compress generated css ? (default: false)
# Less::More.header = true/false --- insert editing warning into css ? (default: true)
# Less::More.destination_path = 'css' --- put css into public/??? (default: stylesheets)
# Less::More.source_path = 'public/stylesheets/less' --- where do less files live? (default: app/stylesheets)
attr_writer :compression, :header, :destination_path, :source_path
def header
@header.nil? ? true : @header
end
def destination_path
@destination_path || File.join(Rails.root, 'public', 'stylesheets')
end
def source_path
@source_path || File.join(Rails.root, 'app', 'stylesheets')
end
def compression
@compression
end
# Generates the .css from a .less or .lss file in Less::More.source_path matching
# the given parameters.
#
# Less::More.generate("screen.less")
# Less::More.generate("subdirectories/here/homepage.less")
def generate(source)
generated = to_dot_css(path_to_destination(source))
path_to_source = File.join(source_path, source)
# check if the destination file exists, and compare the modified times to see if it needs to be written
if mtime(generated) >= mtime_including_imports(path_to_source)
# up to date, nothing to do!
else
# css file does not exist or is out of date
css = if File.extname(path_to_source) == ".css"
# vanilla css nothing to do!
File.read(path_to_source)
else
# less or lss file, compile it
css = compile(path_to_source)
css.delete!("\n") if compression # TODO: use real compression !
css = (HEADER % [File.join(source_path, source)]) << css if header
css
end
# write the css
FileUtils.mkdir_p File.dirname(generated)
File.open(generated, "w"){|f| f.write css }
end
end
# Generates all the .css files
def generate_all
all_less_files.each do |path|
generate(relative_to_source_path(path))
end
end
# Removes all generated css files.
def remove_all_generated
all_less_files.each do |path|
css_path = to_dot_css(relative_to_source_path(path))
css_file = path_to_destination(css_path)
File.delete(css_file) if File.file?(css_file)
end
end
# Array of paths of less source files.
def all_less_files
all = Dir[File.join(source_path, "**", "*.{css,less,lss}")]
all.reject{|path| File.basename(path) =~ /^_/ }
end
private
def mtime(file)
return 0 unless File.file?(file)
File.mtime(file).to_i
end
# consider imports for mtime
# just 1 level deep so we do not get any looping/nesting errors
def mtime_including_imports(file)
mtimes = [mtime(file)]
File.readlines(file).each do |line|
if line =~ /^\s*@import ['"]([^'"]+)/
imported = File.join(File.dirname(file), $1)
mtimes << if imported =~ /\.le?ss$/ # complete path given ?
mtime(imported)
else # we need to add .less or .lss
[mtime("#{imported}.less"), mtime("#{imported}.lss")].max
end
end
end
mtimes.max
end
def compile(file)
begin
parser = Less::Parser.new :paths => [source_path]
tree = parser.parse File.read(file)
tree.to_css
rescue Exception => e
e.message << "\nFrom #{file}"
raise e
end
end
def to_dot_css(path)
path.to_s.sub(/(le?|c)ss$/, "css")
end
def path_to_destination(path)
File.join(destination_path, path)
end
def relative_to_source_path(path)
File.expand_path(path.to_s).sub(File.expand_path(source_path), '')[1..-1]
end
end
end
Jump to Line
Something went wrong with that request. Please try again.