diff --git a/README b/README index 46c01527..20225756 100644 --- a/README +++ b/README @@ -11,11 +11,18 @@ and providing elegant, easily understandable, and powerful syntax. == Using -There are two ways to use Haml and Sass. -The easiest is as a Rails plugin: -Simply type ./script/plugin install http://hamptoncatlin.com/haml/stable +There are several ways to use Haml and Sass. +They can be used as a plugins for Rails or Merb, +or embedded on their own in other applications. +The first step of all of these is to install the Haml gem: + + gem install haml + +To install Haml and Sass as a Rails plugin, +just run haml --rails path/to/rails/app and both Haml and Sass will be installed. -Views with the .haml extension will automatically use Haml. +Views with the .haml (or .html.haml for edge) +extension will automatically use Haml. Sass is a little more complicated; .sass files should be placed in public/stylesheets/sass, where they'll be automatically compiled @@ -23,6 +30,18 @@ to corresponding CSS files in public/stylesheets when needed (the Sass template directory is customizable... see the Sass module docs for details). +For Merb, .html.haml views will work without any further modification. +To enable Sass, you also need to add it add a dependency. +To do so, just add + + dependency "haml" + +to config/dependencies.rb. +Then it'll work just like it does in Rails. + +To use Haml and Sass programatically, +check out the RDocs for the Haml and Sass modules. + == Formatting === Haml diff --git a/Rakefile b/Rakefile index 736ff1ba..a4ae223b 100644 --- a/Rakefile +++ b/Rakefile @@ -75,6 +75,7 @@ unless ARGV[0] == 'benchmark' end.to_a spec.executables = ['haml', 'html2haml', 'sass'] spec.files = FileList['lib/**/*', 'bin/*', 'test/**/*', 'Rakefile', 'init.rb'].to_a + readmes + spec.autorequire = ['haml', 'sass'] spec.homepage = 'http://haml.hamptoncatlin.com/' spec.has_rdoc = true spec.extra_rdoc_files = readmes diff --git a/lib/haml/helpers/action_view_mods.rb b/lib/haml/helpers/action_view_mods.rb index a3deea2c..4faa46e5 100644 --- a/lib/haml/helpers/action_view_mods.rb +++ b/lib/haml/helpers/action_view_mods.rb @@ -1,4 +1,5 @@ begin + raise LoadError if defined?(Merb::Plugins) require 'rubygems' require 'active_support' require 'action_controller' diff --git a/lib/sass.rb b/lib/sass.rb index 2bfa7ece..7666aa37 100644 --- a/lib/sass.rb +++ b/lib/sass.rb @@ -407,7 +407,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir) # but all constants in that file are made available in the current file. # # Sass looks for other Sass files in the working directory, -# and the Sass file directory under Rails. +# and the Sass file directory under Rails or Merb. # Additional search directories may be specified # using the :load_paths option (see below). # @@ -596,42 +596,51 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir) # [:never_update] Whether the CSS files should never be updated, # even if the template file changes. # Setting this to true may give small performance gains. -# It's never true by default, -# even in production mode. +# It always defaults to false. +# Only has meaning within Ruby on Rails or Merb. # # [:always_update] Whether the CSS files should be updated every # time a controller is accessed, # as opposed to only when the template has been modified. # Defaults to false. -# Only has meaning within Ruby on Rails. +# Only has meaning within Ruby on Rails or Merb. # # [:always_check] Whether a Sass template should be checked for updates every # time a controller is accessed, # as opposed to only when the Rails server starts. # If a Sass template has been updated, # it will be recompiled and will overwrite the corresponding CSS file. -# Defaults to false if Rails is running in production mode, -# true otherwise. -# Only has meaning within Ruby on Rails. +# Defaults to false in production mode, true otherwise. +# Only has meaning within Ruby on Rails or Merb. +# +# [:full_exception] Whether an error in the Sass code +# should cause Sass to provide a detailed description. +# If set to true, the specific error will be displayed +# along with a line number and source snippet. +# Otherwise, a simple uninformative error message will be displayed. +# Defaults to false in production mode, true otherwise. +# Only has meaning within Ruby on Rails or Merb. # # [:template_location] The directory where Sass templates should be read from. -# Defaults to RAILS_ROOT + "/public/stylesheets/sass". -# Only has meaning within Ruby on Rails. +# Defaults to RAILS_ROOT + "/public/stylesheets/sass" +# or MERB_ROOT + "/public/stylesheets/sass". +# Only has meaning within Ruby on Rails or Merb. # # [:css_location] The directory where CSS output should be written to. -# Defaults to RAILS_ROOT + "/public/stylesheets". -# Only has meaning within Ruby on Rails. +# Defaults to RAILS_ROOT + "/public/stylesheets" +# or MERB_ROOT + "/public/stylesheets". +# Only has meaning within Ruby on Rails or Merb. # # [:filename] The filename of the file being rendered. # This is used solely for reporting errors, -# and is automatically set when using Rails. +# and is automatically set when using Rails or Merb. # # [:load_paths] An array of filesystem paths which should be searched # for Sass templates imported with the "@import" directive. -# This defaults to the working directory and, in Rails, -# whatever :template_location is -# (by default RAILS_ROOT + "/public/stylesheets/sass"). +# This defaults to the working directory and, in Rails or Merb, +# whatever :template_location is. # module Sass; end require 'sass/engine' +require 'sass/plugin' if defined?(Merb::Plugins) diff --git a/lib/sass/plugin.rb b/lib/sass/plugin.rb index f238de19..a7dd346a 100644 --- a/lib/sass/plugin.rb +++ b/lib/sass/plugin.rb @@ -1,21 +1,17 @@ require 'sass/engine' -require 'rubygems' -require 'action_controller' - -RAILS_ROOT = '. 'unless self.class.const_defined?('RAILS_ROOT') -RAILS_ENV = 'production' unless self.class.const_defined?('RAILS_ENV') module Sass - # 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. + # This module contains methods to aid in using Sass + # as a stylesheet-rendering plugin for various systems. + # Currently Rails/ActionController and Merb are supported out of the box. module Plugin class << self @@options = { - :template_location => RAILS_ROOT + '/public/stylesheets/sass', - :css_location => RAILS_ROOT + '/public/stylesheets', + :template_location => './public/stylesheets/sass', + :css_location => './public/stylesheets', :always_update => false, - :always_check => RAILS_ENV != "production" + :always_check => true, + :full_exception => true } # Gets various options for Sass. See README for details. @@ -79,7 +75,7 @@ module Sass end def exception_string(e) - if RAILS_ENV != "production" + if options[:full_exception] e_string = "#{e.class}: #{e.message}" if e.is_a? Sass::SyntaxError @@ -146,17 +142,5 @@ module Sass end end -# 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]. -module ActionController - class Base # :nodoc: - 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 +require 'sass/plugin/rails' if defined?(ActionController) +require 'sass/plugin/merb' if defined?(Merb::Plugins) diff --git a/lib/sass/plugin/merb.rb b/lib/sass/plugin/merb.rb new file mode 100644 index 00000000..d89a9236 --- /dev/null +++ b/lib/sass/plugin/merb.rb @@ -0,0 +1,20 @@ +unless defined?(Sass::MERB_LOADED) + Sass::MERB_LOADED = true + + Sass::Plugin.options.merge!(:template_location => MERB_ROOT + '/public/stylesheets/sass', + :css_location => MERB_ROOT + '/public/stylesheets', + :always_check => MERB_ENV != "production", + :full_exception => MERB_ENV != "production") + config = Merb::Plugins.config[:sass] || Merb::Plugins.config["sass"] || {} + config.symbolize_keys! + Sass::Plugin.options.merge!(config) + + class MerbHandler # :nodoc: + def process_with_sass(request, response) + Sass::Plugin.update_stylesheets if Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check] + process_without_sass(request, response) + end + alias_method :process_without_sass, :process + alias_method :process, :process_with_sass + end +end diff --git a/lib/sass/plugin/rails.rb b/lib/sass/plugin/rails.rb new file mode 100644 index 00000000..f21a8f2e --- /dev/null +++ b/lib/sass/plugin/rails.rb @@ -0,0 +1,18 @@ +unless defined?(Sass::RAILS_LOADED) + Sass::RAILS_LOADED = true + + Sass::Plugin.options.merge!(:template_location => RAILS_ROOT + '/public/stylesheets/sass', + :css_location => RAILS_ROOT + '/public/stylesheets', + :always_check => RAILS_ENV != "production", + :full_exception => RAILS_ENV != "production") + + module ActionController # :nodoc: + class Base # :nodoc: + 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 +end diff --git a/test/sass/plugin_test.rb b/test/sass/plugin_test.rb index 064122c7..2cb9ece9 100644 --- a/test/sass/plugin_test.rb +++ b/test/sass/plugin_test.rb @@ -1,9 +1,14 @@ #!/usr/bin/env ruby -RAILS_ENV = 'testing' +MERB_ENV = RAILS_ENV = 'testing' +RAILS_ROOT = '.' + require 'test/unit' require 'fileutils' require File.dirname(__FILE__) + '/../../lib/sass' +require 'rubygems' + +require 'action_controller' require 'sass/plugin' class SassPluginTest < Test::Unit::TestCase @@ -14,14 +19,7 @@ class SassPluginTest < Test::Unit::TestCase def setup FileUtils.mkdir File.dirname(__FILE__) + '/tmp' - Sass::Plugin.options = { - :template_location => File.dirname(__FILE__) + '/templates', - :css_location => File.dirname(__FILE__) + '/tmp', - :style => :compact, - :load_paths => [File.dirname(__FILE__) + '/results'], - } - Sass::Plugin.options[:always_update] = true - + set_plugin_opts Sass::Plugin.update_stylesheets end @@ -56,7 +54,7 @@ class SassPluginTest < Test::Unit::TestCase assert !Sass::Plugin.stylesheet_needs_update?('import') end - def test_exception_handling + def test_full_exception_handling File.delete(tempfile_loc('bork')) Sass::Plugin.update_stylesheets File.open(tempfile_loc('bork')) do |file| @@ -65,18 +63,18 @@ class SassPluginTest < Test::Unit::TestCase File.delete(tempfile_loc('bork')) end - def test_production_exception_handling - Sass.const_set('RAILS_ENV', 'production') + def test_nonfull_exception_handling + Sass::Plugin.options[:full_exception] = false File.delete(tempfile_loc('bork')) Sass::Plugin.update_stylesheets assert_equal("/* Internal stylesheet error */", File.read(tempfile_loc('bork'))) File.delete(tempfile_loc('bork')) - Sass::Plugin.const_set('RAILS_ENV', 'testing') + Sass::Plugin.options[:full_exception] = true end - def test_controller_process + def test_rails_update File.delete(tempfile_loc('basic')) assert Sass::Plugin.stylesheet_needs_update?('basic') @@ -85,6 +83,26 @@ class SassPluginTest < Test::Unit::TestCase assert !Sass::Plugin.stylesheet_needs_update?('basic') end + def test_merb_update + begin + require 'merb' + rescue LoadError + puts "\nmerb couldn't be loaded, skipping a test" + return + end + + require 'sass/plugin/merb' + MerbHandler.send(:define_method, :process_without_sass) { |*args| } + set_plugin_opts + + File.delete(tempfile_loc('basic')) + assert Sass::Plugin.stylesheet_needs_update?('basic') + + MerbHandler.new('.').process nil, nil + + assert !Sass::Plugin.stylesheet_needs_update?('basic') + end + def test_doesnt_render_partials assert !File.exists?(tempfile_loc('_partial')) end @@ -109,6 +127,16 @@ class SassPluginTest < Test::Unit::TestCase def result_loc(name) File.dirname(__FILE__) + "/results/#{name}.css" end + + def set_plugin_opts + Sass::Plugin.options = { + :template_location => File.dirname(__FILE__) + '/templates', + :css_location => File.dirname(__FILE__) + '/tmp', + :style => :compact, + :load_paths => [File.dirname(__FILE__) + '/results'], + :always_update => true, + } + end end module Sass::Plugin