├── .gitignore ├── Gemfile ├── Gemfile.lock ├── MIT-LICENSE ├── README.markdown ├── Rakefile ├── init.rb ├── install.rb ├── lib ├── less │ ├── controller_extension.rb │ └── more.rb └── tasks │ └── more_tasks.rake ├── more.gemspec ├── rails └── init.rb └── test ├── controller_test.rb ├── more_test.rb └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | more (0.1.0) 5 | less (~> 2.0.1) 6 | more 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actionmailer (2.3.8) 12 | actionpack (= 2.3.8) 13 | actionpack (2.3.8) 14 | activesupport (= 2.3.8) 15 | rack (~> 1.1.0) 16 | activerecord (2.3.8) 17 | activesupport (= 2.3.8) 18 | activeresource (2.3.8) 19 | activesupport (= 2.3.8) 20 | activesupport (2.3.8) 21 | less (2.0.1) 22 | therubyracer (~> 0.9.0beta6) 23 | libv8 (3.3.10.2) 24 | rack (1.1.0) 25 | rails (2.3.8) 26 | actionmailer (= 2.3.8) 27 | actionpack (= 2.3.8) 28 | activerecord (= 2.3.8) 29 | activeresource (= 2.3.8) 30 | activesupport (= 2.3.8) 31 | rake (>= 0.8.3) 32 | rake (0.9.2) 33 | shoulda (2.10.3) 34 | therubyracer (0.9.0beta7) 35 | libv8 (~> 3.3.10) 36 | 37 | PLATFORMS 38 | ruby 39 | 40 | DEPENDENCIES 41 | actionpack (~> 2.3.8) 42 | activesupport (~> 2.3.8) 43 | more! 44 | rails (~> 2.3.8) 45 | rake 46 | shoulda 47 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Logan Raarup, August Lilleaas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | ### This repo is DEPRECATED and is only here for historical reasons. 2 | 3 | More 4 | ==== 5 | 6 | *LESS on Rails.* 7 | 8 | More is a plugin for Ruby on Rails applications. It automatically parses your applications `.less` files through LESS and outputs CSS files. 9 | 10 | In details, More does the following: 11 | 12 | * Recursively looks for LESS (`.less`) files in `app/stylesheets` 13 | * Ignores partials (prefixed with underscore: `_partial.less`) - these can be included with `@import` in your LESS files 14 | * Saves the resulting CSS files to `public/stylesheets` using the same directory structure as `app/stylesheets` 15 | 16 | LESS 17 | ---- 18 | 19 | LESS extends CSS with: variables, mixins, operations and nested rules. For more information, see [http://lesscss.org](http://lesscss.org). 20 | 21 | Upgrading from less-for-rails 22 | ======================================= 23 | 24 | The old `less-for-rails` plugin looked for `.less` files in `public/stylesheets`. This plugin looks in `app/stylesheets`. 25 | 26 | To migrate, you can either set `Less::More.source_path = Rails.root + "/public/stylesheets"`, or move your `.less` files to `app/stylesheets`. 27 | 28 | 29 | Installation 30 | ============ 31 | 32 | More depends on the LESS gem. Please install LESS first: 33 | 34 | $ gem install less 35 | 36 | Rails Plugin 37 | ------------ 38 | 39 | Use this to install as a plugin in a Ruby on Rails app: 40 | 41 | $ script/plugin install git://github.com/cloudhead/more.git 42 | 43 | Rails Plugin (using git submodules) 44 | ----------------------------------- 45 | 46 | Use this if you prefer to use git submodules for plugins: 47 | 48 | $ git submodule add git://github.com/cloudhead/more.git vendor/plugins/more 49 | $ script/runner vendor/plugins/more/install.rb 50 | 51 | 52 | Usage 53 | ===== 54 | 55 | Upon installation, a new directory will be created in `app/stylesheets`. Any LESS file placed in this directory, including subdirectories, will 56 | automatically be parsed through LESS and saved as a corresponding CSS file in `public/stylesheets`. Example: 57 | 58 | app/stylesheets/clients/screen.less => public/stylesheets/clients/screen.css 59 | 60 | If you prefix a file with an underscore, it is considered to be a partial, and will not be parsed unless included in another file. Example: 61 | 62 | 63 | @text_dark: #222; 64 | 65 | 66 | @import "partials/_form"; 67 | 68 | input { color: @text_dark; } 69 | 70 | The example above will result in a single CSS file in `public/stylesheets/clients/screen.css`. 71 | 72 | Any `.css` file placed in `app/stylesheets` will be copied into `public/stylesheets` without being parsed through LESS. 73 | 74 | 75 | Configuration 76 | ============= 77 | 78 | Source path: the location of your LESS files (default: app/stylesheets) 79 | 80 | Less::More.source_path = "public/stylesheets/less" 81 | 82 | Destination Path: where the css goes (public/destination_path) (default: stylesheets) 83 | 84 | Less::More.destination_path = "css" 85 | 86 | More can compress your files by removing extra line breaks (default: true) 87 | 88 | Less::More.compression = false 89 | 90 | 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) 91 | 92 | Less::More.header = false 93 | 94 | To configure More for a specific environment, add configuration options into the environment file, such as `config/environments/development.rb`. 95 | 96 | If you wish to apply the configuration to all environments, place them in `config/environment.rb`. 97 | 98 | 99 | Tasks 100 | ===== 101 | 102 | More provides a set of Rake tasks to help manage your CSS files. 103 | 104 | To parse all LESS files and save the resulting CSS files to the destination path, run: 105 | 106 | $ rake more:generate 107 | 108 | To delete all generated CSS files, run: 109 | 110 | $ rake more:clean 111 | 112 | This task will not delete any CSS files from the destination path, that does not have a corresponding LESS file in the source path. 113 | 114 | 115 | Git / SVN 116 | ========= 117 | 118 | Check in all the generated css(destination path), they are only generated in development 119 | 120 | Documentation 121 | ============= 122 | 123 | To view the full RDoc documentation, go to [http://rdoc.info/projects/cloudhead/more](http://rdoc.info/projects/cloudhead/more) 124 | 125 | 126 | Contributors 127 | ============ 128 | * August Lilleaas ([http://github.com/augustl](http://github.com/augustl)) 129 | * Logan Raarup ([http://github.com/logandk](http://github.com/logandk)) 130 | * Michael Grosser ([http://github.com/grosser](http://github.com/grosser)) 131 | 132 | LESS is maintained by Alexis Sellier [http://github.com/cloudhead](http://github.com/cloudhead) 133 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rake/testtask' 3 | require 'rake/rdoctask' 4 | 5 | desc 'Default: run unit tests.' 6 | task :default => :test 7 | 8 | desc 'Test the more plugin.' 9 | Rake::TestTask.new(:test) do |t| 10 | t.libs << 'lib' 11 | t.libs << 'test' 12 | t.pattern = 'test/**/*_test.rb' 13 | t.verbose = true 14 | end 15 | 16 | desc 'Generate documentation for the more plugin.' 17 | Rake::RDocTask.new(:rdoc) do |rdoc| 18 | rdoc.rdoc_dir = 'rdoc' 19 | rdoc.title = 'More' 20 | rdoc.options << '--line-numbers' << '--inline-source' 21 | rdoc.rdoc_files.include('README.markdown') 22 | rdoc.rdoc_files.include('lib/**/*.rb') 23 | end 24 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.dirname(__FILE__), 'rails', 'init') 2 | -------------------------------------------------------------------------------- /install.rb: -------------------------------------------------------------------------------- 1 | require "fileutils" 2 | include FileUtils::Verbose 3 | 4 | mkdir_p File.join(Rails.root, "app", "stylesheets") -------------------------------------------------------------------------------- /lib/less/controller_extension.rb: -------------------------------------------------------------------------------- 1 | class ActionController::Base 2 | before_filter :generate_css_from_less 3 | 4 | def generate_css_from_less 5 | Less::More.generate_all 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/less/more.rb: -------------------------------------------------------------------------------- 1 | # Less::More provides methods for parsing LESS files in a rails application to CSS target files. 2 | # 3 | # When Less::More.parse is called, all files in Less::More.source_path will be parsed using LESS 4 | # and saved as CSS files in Less::More.destination_path. If Less::More.compression is set to true, 5 | # extra line breaks will be removed to compress the CSS files. 6 | # 7 | # By default, Less::More.parse will be called for each request in `development` environment and on 8 | # application initialization in `production` environment. 9 | 10 | begin 11 | require 'less' 12 | rescue LoadError => e 13 | e.message << " (You may need to install the less gem)" 14 | raise e 15 | end 16 | 17 | class Less::More 18 | 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*/} 19 | 20 | class << self 21 | # Less::More.compression = true/false --- compress generated css ? (default: false) 22 | # Less::More.header = true/false --- insert editing warning into css ? (default: true) 23 | # Less::More.destination_path = 'css' --- put css into public/??? (default: stylesheets) 24 | # Less::More.source_path = 'public/stylesheets/less' --- where do less files live? (default: app/stylesheets) 25 | attr_writer :compression, :header, :destination_path, :source_path 26 | 27 | def header 28 | @header.nil? ? true : @header 29 | end 30 | 31 | def destination_path 32 | @destination_path || File.join(Rails.root, 'public', 'stylesheets') 33 | end 34 | 35 | def source_path 36 | @source_path || File.join(Rails.root, 'app', 'stylesheets') 37 | end 38 | 39 | def compression 40 | @compression 41 | end 42 | 43 | # Generates the .css from a .less or .lss file in Less::More.source_path matching 44 | # the given parameters. 45 | # 46 | # Less::More.generate("screen.less") 47 | # Less::More.generate("subdirectories/here/homepage.less") 48 | def generate(source) 49 | generated = to_dot_css(path_to_destination(source)) 50 | path_to_source = File.join(source_path, source) 51 | 52 | # check if the destination file exists, and compare the modified times to see if it needs to be written 53 | if mtime(generated) >= mtime_including_imports(path_to_source) 54 | # up to date, nothing to do! 55 | else 56 | # css file does not exist or is out of date 57 | css = if File.extname(path_to_source) == ".css" 58 | # vanilla css nothing to do! 59 | File.read(path_to_source) 60 | else 61 | # less or lss file, compile it 62 | css = compile(path_to_source) 63 | css.delete!("\n") if compression # TODO: use real compression ! 64 | css = (HEADER % [File.join(source_path, source)]) << css if header 65 | css 66 | end 67 | 68 | # write the css 69 | FileUtils.mkdir_p File.dirname(generated) 70 | File.open(generated, "w"){|f| f.write css } 71 | end 72 | end 73 | 74 | # Generates all the .css files 75 | def generate_all 76 | all_less_files.each do |path| 77 | generate(relative_to_source_path(path)) 78 | end 79 | end 80 | 81 | # Removes all generated css files. 82 | def remove_all_generated 83 | all_less_files.each do |path| 84 | css_path = to_dot_css(relative_to_source_path(path)) 85 | css_file = path_to_destination(css_path) 86 | File.delete(css_file) if File.file?(css_file) 87 | end 88 | end 89 | 90 | # Array of paths of less source files. 91 | def all_less_files 92 | all = Dir[File.join(source_path, "**", "*.{css,less,lss}")] 93 | all.reject{|path| File.basename(path) =~ /^_/ } 94 | end 95 | 96 | private 97 | 98 | def mtime(file) 99 | return 0 unless File.file?(file) 100 | File.mtime(file).to_i 101 | end 102 | 103 | # consider imports for mtime 104 | # just 1 level deep so we do not get any looping/nesting errors 105 | def mtime_including_imports(file) 106 | mtimes = [mtime(file)] 107 | File.readlines(file).each do |line| 108 | if line =~ /^\s*@import ['"]([^'"]+)/ 109 | imported = File.join(File.dirname(file), $1) 110 | mtimes << if imported =~ /\.le?ss$/ # complete path given ? 111 | mtime(imported) 112 | else # we need to add .less or .lss 113 | [mtime("#{imported}.less"), mtime("#{imported}.lss")].max 114 | end 115 | end 116 | end 117 | mtimes.max 118 | end 119 | 120 | def compile(file) 121 | begin 122 | parser = Less::Parser.new :paths => [source_path] 123 | tree = parser.parse File.read(file) 124 | tree.to_css 125 | rescue Exception => e 126 | e.message << "\nFrom #{file}" 127 | raise e 128 | end 129 | end 130 | 131 | def to_dot_css(path) 132 | path.to_s.sub(/(le?|c)ss$/, "css") 133 | end 134 | 135 | def path_to_destination(path) 136 | File.join(destination_path, path) 137 | end 138 | 139 | def relative_to_source_path(path) 140 | File.expand_path(path.to_s).sub(File.expand_path(source_path), '')[1..-1] 141 | end 142 | end 143 | end 144 | -------------------------------------------------------------------------------- /lib/tasks/more_tasks.rake: -------------------------------------------------------------------------------- 1 | namespace :more do 2 | desc "Generate CSS files from LESS files" 3 | task :generate => :environment do 4 | puts "Generating css from less files in #{Less::More.source_path}." 5 | Less::More.generate_all 6 | puts "Done." 7 | 8 | end 9 | 10 | desc "Remove generated CSS files" 11 | task :clean => :environment do 12 | puts "Deleting all generated css files in #{Less::More.destination_path}" 13 | Less::More.remove_all_generated 14 | puts "Done." 15 | end 16 | end -------------------------------------------------------------------------------- /more.gemspec: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | 3 | SPEC = Gem::Specification.new do |s| 4 | s.name = "more" 5 | s.summary = "LESS on Rails" 6 | s.homepage = "http://github.com/cloudhead/more" 7 | s.description = <<-EOS 8 | More is a plugin for Ruby on Rails applications. It automatically 9 | parses your applications .less files through LESS and outputs CSS files. 10 | EOS 11 | s.authors = ["August Lilleaas", "Logan Raarup"] 12 | s.version = "0.1.0" 13 | s.files = FileList["README.markdown", "MIT-LICENSE", "Rakefile", "init.rb", "lib/*.rb", "rails/init.rb", "tasks/*", "test/*"] 14 | s.has_rdoc = true 15 | 16 | s.date = '2011-06-10' 17 | 18 | s.extra_rdoc_files = [ 19 | "MIT-LICENSE", 20 | "README.markdown" 21 | ] 22 | 23 | s.require_paths = ["lib"] 24 | 25 | if s.respond_to? :specification_version then 26 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION 27 | s.specification_version = 3 28 | 29 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 30 | s.add_development_dependency(%q, ["~> 2.3.8"]) 31 | s.add_development_dependency(%q, ["~> 2.3.8"]) 32 | s.add_development_dependency(%q, ["~> 2.3.8"]) 33 | s.add_development_dependency(%q, [">= 0"]) 34 | s.add_development_dependency(%q, [">= 0"]) 35 | s.add_runtime_dependency(%q, ["~> 2.0.1"]) 36 | s.add_runtime_dependency(%q, [">= 0"]) 37 | else 38 | s.add_dependency(%q, ["~> 2.3.8"]) 39 | s.add_dependency(%q, ["~> 2.3.8"]) 40 | s.add_dependency(%q, [">= 0"]) 41 | s.add_dependency(%q, ["~> 2.0.1"]) 42 | s.add_dependency(%q, [">= 0"]) 43 | s.add_dependency(%q, ["~> 2.3.8"]) 44 | s.add_dependency(%q, [">= 0"]) 45 | s.add_dependency(%q, [">= 0"]) 46 | end 47 | else 48 | s.add_dependency(%q, ["~> 2.3.8"]) 49 | s.add_dependency(%q, ["~> 2.3.8"]) 50 | s.add_dependency(%q, [">= 0"]) 51 | s.add_dependency(%q, ["~> 2.0.1"]) 52 | s.add_dependency(%q, [">= 0"]) 53 | s.add_dependency(%q, ["~> 2.3.8"]) 54 | s.add_dependency(%q, [">= 0"]) 55 | s.add_dependency(%q, [">= 0"]) 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /rails/init.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.dirname(__FILE__), '..', 'lib', 'less', 'controller_extension') if RAILS_ENV == 'development' -------------------------------------------------------------------------------- /test/controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ExampleController < ActionController::Base 4 | def test 5 | render :text => 'OK' 6 | end 7 | end 8 | 9 | class ControllerTest < ActionController::TestCase 10 | def setup 11 | @controller = ExampleController.new 12 | @request = ActionController::TestRequest.new 13 | @response = ActionController::TestResponse.new 14 | setup_for_generate_test 15 | end 16 | 17 | def teardown 18 | teardown_for_generate_test 19 | end 20 | 21 | should "generate less files" do 22 | write_less 'xxx.less', 'a{color:red}' 23 | get :test 24 | assert_include 'a { color: red; }', read_css('xxx.css').strip 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /test/more_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class MoreTest < ActiveSupport::TestCase 4 | setup do 5 | [:compression, :header, :destination_path, :source_path].each do |variable| 6 | Less::More.send("#{variable}=", nil) 7 | end 8 | end 9 | 10 | context :header do 11 | should "be true by default" do 12 | assert_equal Less::More.header, true 13 | end 14 | 15 | should "be overwriteable" do 16 | Less::More.header = false 17 | assert_equal false, Less::More.header 18 | end 19 | end 20 | 21 | context :source_path do 22 | should "be app/stylesheets by default" do 23 | assert File.expand_path(File.join(Rails.root, 'app', 'stylesheets')), Less::More.source_path 24 | end 25 | 26 | should "be overwritteable" do 27 | Less::More.source_path = 'xxx' 28 | assert_equal 'xxx', Less::More.source_path 29 | end 30 | end 31 | 32 | context :destination_path do 33 | should "be public/stylesheets by default" do 34 | assert File.expand_path(File.join(Rails.root, 'public', 'stylesheets')), Less::More.destination_path 35 | end 36 | 37 | should "be overwritteable" do 38 | Less::More.destination_path = 'xxx' 39 | assert_equal 'xxx', Less::More.destination_path 40 | end 41 | end 42 | 43 | context :compression do 44 | should "be off by default" do 45 | assert_equal nil, Less::More.compression 46 | end 47 | 48 | should "be overwritteable" do 49 | Less::More.compression = true 50 | assert_equal true, Less::More.compression 51 | end 52 | end 53 | 54 | context :generate do 55 | setup do 56 | setup_for_generate_test 57 | end 58 | 59 | teardown do 60 | teardown_for_generate_test 61 | end 62 | 63 | should 'generate css from .less files' do 64 | write_less 'test.less', "a{color:red}" 65 | Less::More.generate_all 66 | assert_include 'a { color: red; }', read_css('test.css') 67 | end 68 | 69 | should 'generate css from .lss files' do 70 | write_less 'test.lss', "a{color:red}" 71 | Less::More.generate_all 72 | assert_include 'a { color: red; }', read_css('test.css') 73 | end 74 | 75 | should 'generate for files in subfolders' do 76 | write_less 'xxx/test.less', "a{color:red}" 77 | Less::More.generate_all 78 | assert_include 'a { color: red; }', read_css('xxx/test.css') 79 | end 80 | 81 | should "include imported partials" do 82 | write_less 'test.less', "@import '_partial';\nb{color:blue}" 83 | write_less '_partial.less', 'a{color:red}' 84 | Less::More.generate_all 85 | assert_include 'a { color: red; }', read_css('test.css') 86 | end 87 | 88 | should "not generate css from partials" do 89 | write_less '_partial.less', 'a{color:red}' 90 | Less::More.generate_all 91 | assert_equal '', `ls #{css_path}`.strip 92 | end 93 | 94 | should "not parse css" do 95 | write_less 'test.css', 'a{color:red}' 96 | Less::More.generate_all 97 | assert_include 'a{color:red}', read_css('test.css') 98 | end 99 | 100 | should "add disclaimer-header when active" do 101 | write_less 'test.less', 'a{color:red}' 102 | Less::More.header = true 103 | Less::More.generate_all 104 | assert_match /^\/\*/, read_css('test.css') 105 | end 106 | 107 | should "not include header when not set" do 108 | write_less 'test.less', 'a{color:red}' 109 | Less::More.header = false 110 | Less::More.generate_all 111 | assert_not_include '/*', read_css('test.css') 112 | end 113 | 114 | should_eventually "fail with current file when encountering an error" do 115 | # pending because Less 2.0.1 is not generating an exception 116 | write_less 'test.less', 'import xxxx;;;;;' 117 | content = begin 118 | Less::More.generate_all 119 | '!no exception was raised!' 120 | rescue Exception => e 121 | e.message 122 | end 123 | assert_include '/test.less', content 124 | end 125 | 126 | context 'mtime' do 127 | should "generate for outdated less files" do 128 | write_less 'test.less', "a{color:red}" 129 | Less::More.generate_all 130 | 131 | write_css 'test.css', 'im updated!' 132 | sleep 1 # or mtime will be still the same ... 133 | write_less 'test.less', "a{color:blue}" 134 | Less::More.generate_all 135 | 136 | assert_include 'a { color: blue; }', read_css('test.css').strip 137 | end 138 | 139 | should "not generate for up-to-date less files" do 140 | write_less 'test.less', "a{color:red}" 141 | Less::More.generate_all 142 | 143 | write_css 'test.css', 'im updated!' 144 | Less::More.generate_all 145 | 146 | assert_equal 'im updated!', read_css('test.css') 147 | end 148 | 149 | should "not generate for files with up-to-date partials" do 150 | write_less 'test.less', "@import 'xxx/_test.less';" 151 | write_less 'xxx/_test.less', "a{color:red}" 152 | Less::More.generate_all 153 | 154 | write_css 'test.css', 'im updated!' 155 | Less::More.generate_all 156 | 157 | assert_equal 'im updated!', read_css('test.css') 158 | end 159 | 160 | should "generate for files with outdated partials" do 161 | write_less 'test.less', "@import 'xxx/_test.less';" 162 | write_less 'xxx/_test.less', "a{color:red}" 163 | Less::More.generate_all 164 | 165 | write_css 'test.css', 'im updated!' 166 | sleep 1 # or mtime will be still the same ... 167 | write_less 'xxx/_test.less', "a{color:blue}" 168 | Less::More.generate_all 169 | 170 | assert_include 'a { color: blue; }', read_css('test.css').strip 171 | end 172 | 173 | should "generate for files with outdated partials that are not named .less" do 174 | write_less 'test.less', "@import 'xxx/_test';" 175 | write_less 'xxx/_test.less', "a{color:red}" 176 | Less::More.generate_all 177 | 178 | write_css 'test.css', 'im updated!' 179 | sleep 1 # or mtime will be still the same ... 180 | write_less 'xxx/_test.less', "a{color:blue}" 181 | Less::More.generate_all 182 | 183 | assert_include 'a { color: blue; }', read_css('test.css').strip 184 | end 185 | end 186 | end 187 | 188 | context :remove_all_generated do 189 | setup do 190 | setup_for_generate_test 191 | end 192 | 193 | teardown do 194 | teardown_for_generate_test 195 | end 196 | 197 | should "remove all generated css" do 198 | write_less 'xxx.less', 'a{color:red}' 199 | write_less 'yyy.css', 'a{color:red}' 200 | write_less 'xxx/yyy.css', 'a{color:red}' 201 | Less::More.generate_all 202 | Less::More.remove_all_generated 203 | # should be '' ideally, but an empty folder is no thread :) 204 | assert_equal 'xxx', `ls #{css_path}`.strip 205 | end 206 | 207 | should "not remove other files" do 208 | write_css 'xxx.css', 'a{color:red}' 209 | Less::More.generate_all 210 | Less::More.remove_all_generated 211 | assert_equal 'xxx.css', `ls #{css_path}`.strip 212 | end 213 | end 214 | end 215 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # fake Rails with loaded plugin 2 | require 'rubygems' 3 | require 'active_support' 4 | require 'action_pack' 5 | require 'action_controller' 6 | 7 | module Rails 8 | def self.root 9 | File.expand_path(File.dirname(__FILE__)) 10 | end 11 | 12 | def self.backtrace_cleaner 13 | ActiveSupport::BacktraceCleaner.new 14 | end 15 | end 16 | 17 | RAILS_ENV = 'development' 18 | 19 | # load plugin 20 | $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib') 21 | require 'less/more' 22 | load 'init.rb' 23 | 24 | # load testing libs 25 | require 'test/unit' 26 | require 'active_support/test_case' 27 | begin; require 'redgreen'; rescue LoadError; end 28 | require 'shoulda' 29 | 30 | # setup controller testing 31 | require 'action_controller/test_process' 32 | ActionController::Base.logger = nil 33 | ActionController::Routing::Routes.reload rescue nil 34 | 35 | # test helpers 36 | def css_path 37 | "#{Rails.root}/public/css" 38 | end 39 | 40 | def less_path 41 | "#{Rails.root}/less_files" 42 | end 43 | 44 | def write_less file, content 45 | write_content File.join(less_path, file), content 46 | end 47 | 48 | def write_css file, content 49 | write_content File.join(css_path, file), content 50 | end 51 | 52 | def write_content file, content 53 | `mkdir -p #{File.dirname(file)}` 54 | File.open(file,'w'){|f| f.print content } 55 | end 56 | 57 | def read_css(file) 58 | raise ArgumentError.new("#{file.inspect} missing") unless File.exist?(File.join(css_path, file)) 59 | File.read(File.join(css_path, file)) rescue nil 60 | end 61 | 62 | def assert_include(item, obj) 63 | obj_without_whitespace = obj.gsub(/\s/,'') 64 | item_without_whitespace = item.gsub(/\s/,'') 65 | assert_block("#{obj.inspect}\ndoes not include\n#{item.inspect}."){ obj_without_whitespace.include? item_without_whitespace } 66 | end 67 | 68 | def assert_not_include(item, obj) 69 | obj_without_whitespace = obj.gsub(/\s/,'') 70 | item_without_whitespace = item.gsub(/\s/,'') 71 | assert_block("#{obj.inspect}\ndoes include\n#{item.inspect}."){ !obj_without_whitespace.include? item_without_whitespace } 72 | end 73 | 74 | def setup_for_generate_test 75 | Less::More.source_path = less_path 76 | Less::More.destination_path = css_path 77 | Less::More.header = false 78 | `mkdir -p #{css_path}` 79 | end 80 | 81 | def teardown_for_generate_test 82 | `rm -rf #{css_path}` 83 | `rm -rf #{less_path}` 84 | end 85 | --------------------------------------------------------------------------------