Skip to content

Commit

Permalink
basically a rewrite without all the caching logic, simply generate cs…
Browse files Browse the repository at this point in the history
…s for all updated less files, rake tasks is now more:generate
  • Loading branch information
grosser committed Feb 11, 2010
1 parent facbc53 commit 7990548
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 283 deletions.
30 changes: 11 additions & 19 deletions README.markdown
Expand Up @@ -73,32 +73,26 @@ Any `.css` file placed in `app/stylesheets` will be copied into `public/styleshe
Configuration
=============

To set the source path (the location of your LESS files):
Source path: the location of your LESS files (default: app/stylesheets)

Less::More.source_path = "/path/to/less/files"
Less::More.source_path = "public/stylesheets/less"

You can also set the destination path. Be careful with the formatting here, since this is in fact a route, and not a regular path.
Destination Path: where the css goes (public/destination_path) (default: stylesheets)

Less::More.destination_path = "css"

More can compress your files by removing extra line breaks. This is enabled by default in the `production` environment. To change this setting, set:
More can compress your files by removing extra line breaks (default: true)

Less::More.compression = true
Less::More.compression = false

More inserts headers in the generated CSS files, letting people know that the file is in fact generated and shouldn't be edited directly. This is by default only enabled in development mode. You can disable this behavior if you want to.
More inserts headers in the generated CSS files, letting people know that the file is in fact generated and shouldn't be edited directly. (default: true)

Less::More.header = false

To configure More for a specific environment, add configuration options into the environment file, such as `config/environments/development.rb`.

If you wish to apply the configuration to all environments, place them in `config/environment.rb`.

Heroku
======

The plugin works out-of-the-box on Heroku.

Heroku has a read-only file system, which means caching the generated CSS with page caching is not an option. Heroku supports caching with Varnish, though, which the plugin will leverage by setting Cache-Control headers so that generated CSS is cached for one month.

Tasks
=====
Expand All @@ -107,7 +101,7 @@ More provides a set of Rake tasks to help manage your CSS files.

To parse all LESS files and save the resulting CSS files to the destination path, run:

$ rake more:parse
$ rake more:generate

To delete all generated CSS files, run:

Expand All @@ -116,13 +110,10 @@ To delete all generated CSS files, run:
This task will not delete any CSS files from the destination path, that does not have a corresponding LESS file in the source path.


Git
===

If you are using git to version control your code and LESS for all your stylesheets, you can add this entry to your `.gitignore` file:

public/stylesheets
Git / SVN
=========

Check in all the generated css(destination path), they are only generated in development

Documentation
=============
Expand All @@ -134,5 +125,6 @@ Contributors
============
* August Lilleaas ([http://github.com/augustl](http://github.com/augustl))
* Logan Raarup ([http://github.com/logandk](http://github.com/logandk))
* Michael Grosser ([http://github.com/grosser](http://github.com/grosser))

LESS is maintained by Alexis Sellier [http://github.com/cloudhead](http://github.com/cloudhead)
2 changes: 1 addition & 1 deletion lib/controller_extension.rb
@@ -1,6 +1,6 @@
class ActionController::Base
def process_with_less(*args)
Less::More.parse
Less::More.generate_all
process_without_less(*args)
end

Expand Down
192 changes: 45 additions & 147 deletions lib/less/more.rb
Expand Up @@ -15,187 +15,85 @@
end

class Less::More
DEFAULTS = {
"production" => {
:compression => true,
:header => false,
:destination_path => "stylesheets"
},
"development" => {
:compression => false,
:header => true,
:destination_path => "stylesheets"
}
}

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
attr_writer :compression, :header, :page_cache, :destination_path

# Returns true if compression is enabled. By default, compression is enabled in the production environment
# and disabled in the development and test environments. This value can be changed using:
#
# Less::More.compression = true
#
# You can put this line into config/environments/development.rb to enable compression for the development environments
def compression?
get_cvar(:compression)
end
# 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

# Check wether or not we should page cache the generated CSS
def page_cache?
(not heroku?) && page_cache_enabled_in_environment_configuration?
end

# For easy mocking.
def page_cache_enabled_in_environment_configuration?
Rails.configuration.action_controller.perform_caching
end

# Tells the plugin to prepend HEADER to all generated CSS, informing users
# opening raw .css files that the file is auto-generated and that the
# .less file should be edited instead.
#
# Less::More.header = false
def header?
get_cvar(:header)
def header
@header.nil? ? true : @header
end

# The path, or route, where you want your .css files to live.

def destination_path
get_cvar(:destination_path)
@destination_path || 'stylesheets'
end

# Gets user set values or DEFAULTS. User set values gets precedence.
def get_cvar(cvar)
instance_variable_get("@#{cvar}") || (DEFAULTS[Rails.env] || DEFAULTS["production"])[cvar]
end

# Returns true if the app is running on Heroku. When +heroku?+ is true,
# +page_cache?+ will always be false.
def heroku?
ENV.any? {|key, value| key =~ /^heroku/i }
end

# Returns the LESS source path, see `source_path=`

def source_path
@source_path || Rails.root.join("app", "stylesheets")
end

# Sets the source path for LESS files. This directory will be scanned recursively for all *.less files. Files prefixed
# with an underscore is considered to be partials and are not parsed directly. These files can be included using `@import`
# statements. *Example partial filename: _form.less*
#
# Default value is app/stylesheets
#
# Examples:
# Less::More.source_path = "/path/to/less/files"
# Less::More.source_path = Pathname.new("/other/path")
def source_path=(path)
@source_path = Pathname.new(path.to_s)
end

# Checks if a .less or .lss file exists in Less::More.source_path matching
# the given parameters.
#
# Less::More.exists?(["screen"])
# Less::More.exists?(["subdirectories", "here", "homepage"])
def exists?(path_as_array)
return false if path_as_array[-1].starts_with?("_")

pathname = pathname_from_array(path_as_array)
pathname && pathname.exist?
@source_path || 'app/stylesheets'
end
def cache_path
File.join(Rails.root, 'tmp', 'less-cache')

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::More.generate(["subdirectories", "here", "homepage"])
#
# Returns the CSS as a string.
def generate(path_as_array)
source = pathname_from_array(path_as_array)

# put together our destination dir and path (need dir so we can create subdirectories)
destination_dir = source.dirname.to_s.gsub(source_path, cache_path)
destination = File.join(destination_dir, source.basename.to_s.gsub('.less', '.css').gsub('.lss', '.css'))
# Less::More.generate("screen.less")
# Less::More.generate("subdirectories/here/homepage.less")
def generate(source)
generated = File.join(Rails.root, 'public', destination_path, source.sub(/\.le?ss$/, '.css'))
path_to_source = File.join(Rails.root, source_path, source)

# check if the destination file exists, and compare the modified times to see if it needs to be written
if File.exists?(destination) and File.new(destination).mtime >= File.new(source).mtime
# cached destination file is the same as the source, just return the cached file
css = File.read(destination)
if File.exists?(generated) and File.mtime(generated) >= File.mtime(path_to_source)
# up to date, nothing to do!
else
# cached file doesn't exist or it's out of date
if source.extname == ".css"
# vanilla css
css = File.read(source)
# css file does not exist or is out of date
css = if File.extname(source) == ".css"
# vanilla css nothing to do!
File.read(path_to_source)
else
# less or lss file, compile it
engine = File.open(source) {|f| Less::Engine.new(f) }
engine = File.open(path_to_source){|f| Less::Engine.new(f) }
css = engine.to_css
css.delete!("\n") if self.compression?
css = (HEADER % [source.to_s.sub(File.expand_path('.'), '')]) << css if self.header?
css.delete!("\n") if compression # TODO: use real compression !
css = (HEADER % [File.join(source_path, source)]) << css if header
css
end
# make sure the appropriate cache directory exists
FileUtils.mkdir_p destination_dir
# write the css to our cache directory
File.open(destination, "w") {|f|
f.puts css
}
end

# return the css
css
# 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 parse
# Generates all the .css files
def generate_all
Less::More.all_less_files.each do |path|
# Get path
relative_path = path.relative_path_from(Less::More.source_path)
path_as_array = relative_path.to_s.split(File::SEPARATOR)
path_as_array[-1] = File.basename(path_as_array[-1], File.extname(path_as_array[-1]))

# Generate CSS
css = Less::More.generate(path_as_array)

# Store CSS
path_as_array[-1] = path_as_array[-1] + ".css"
destination = Pathname.new(File.join(Rails.root, "public", Less::More.destination_path)).join(*path_as_array)
destination.dirname.mkpath

File.open(destination, "w") {|f|
f.puts css
}
relative_path = path.sub(File.join(Rails.root, source_path),'')[1..-1]
Less::More.generate(relative_path)
end
end

# Removes all generated css files.
def clean
def remove_all_generated
all_less_files.each do |path|
relative_path = path.relative_path_from(Less::More.source_path)
relative_path = path.sub(File.join(Rails.root, source_path), '')
css_path = relative_path.to_s.sub(/(le?|c)ss$/, "css")
css_file = File.join(Rails.root, "public", Less::More.destination_path, css_path)
css_file = File.join(Rails.root, "public", destination_path, css_path)
File.delete(css_file) if File.file?(css_file)
end
end

# Array of Pathname instances for all the less source files.
# Array of paths of less source files.
def all_less_files
Dir[Less::More.source_path.join("**", "*.{css,less,lss}").to_s].map! {|f| Pathname.new(f) }
end

# Converts ["foo", "bar"] into a `Pathname` based on Less::More.source_path.
def pathname_from_array(array)
path_spec = array.dup
path_spec[-1] = path_spec[-1] + ".{css,less,lss}"
Pathname.glob(File.join(self.source_path.to_s, *path_spec))[0]
all = Dir[File.join(Rails.root, source_path, "**", "*.{css,less,lss}")]
all.reject{|path| File.basename(path) =~ /^_/ }
end
end
end
end
10 changes: 5 additions & 5 deletions tasks/more_tasks.rake
@@ -1,16 +1,16 @@
namespace :more do
desc "Generate CSS files from LESS files"
task :parse => :environment do
puts "Parsing files from #{Less::More.source_path}."
Less::More.parse
task :generate => :environment do
puts "Generating css from less files in #{Less::More.source_path}."
Less::More.generate_all
puts "Done."

end

desc "Remove generated CSS files"
task :clean => :environment do
puts "Deleting files.."
Less::More.clean
puts "Deleting all generated css files in #{Less::More.destination_path}"
Less::More.remove_all_generated
puts "Done."
end
end

0 comments on commit 7990548

Please sign in to comment.