Skip to content

Commit

Permalink
Merge branch 'stable'
Browse files Browse the repository at this point in the history
Conflicts:
	test/sass/conversion_test.rb
  • Loading branch information
nex3 committed Apr 21, 2012
2 parents 9e96a84 + 91f5553 commit 05235ac
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 39 deletions.
6 changes: 3 additions & 3 deletions .gitmodules
@@ -1,3 +1,3 @@
[submodule "vendor/fssm"]
path = vendor/fssm
url = git://github.com/ttilley/fssm
[submodule "vendor/listen"]
path = vendor/listen
url = git://github.com/guard/listen.git
4 changes: 2 additions & 2 deletions Rakefile
Expand Up @@ -115,9 +115,9 @@ task :submodules do
if File.exist?(File.dirname(__FILE__) + "/.git")
sh %{git submodule sync}
sh %{git submodule update --init}
elsif !File.exist?(File.dirname(__FILE__) + "/vendor/fssm/lib")
elsif !File.exist?(File.dirname(__FILE__) + "/vendor/listen/lib")
warn <<WARN
WARNING: vendor/fssm doesn't exist, and this isn't a git repository so
WARNING: vendor/listen doesn't exist, and this isn't a git repository so
I can't get it automatically!
WARN
end
Expand Down
4 changes: 4 additions & 0 deletions doc-src/SASS_CHANGELOG.md
Expand Up @@ -148,6 +148,10 @@ that make use of `@media` and other directives dynamically.
* Support the [`@supports` directive](http://www.w3.org/TR/css3-conditional/#at-supports).
* Fix a performance issue when using `/*! */` comments with the Rails asset
pipeline.
* Support `-moz-element`.
* Properly handle empty lists in `sass-convert`.
* Move from [FSSM](https://github.com/ttilley/fssm) to
[Listen](https://github.com/guard/listen) for file-system monitoring.

## 3.1.15

Expand Down
57 changes: 25 additions & 32 deletions lib/sass/plugin/compiler.rb
Expand Up @@ -5,6 +5,7 @@
require 'sass/callbacks'
require 'sass/plugin/configuration'
require 'sass/plugin/staleness_checker'
require 'sass/plugin/listener'

module Sass::Plugin

Expand Down Expand Up @@ -218,10 +219,10 @@ def update_stylesheets(individual_files = [])
#
# Before the watching starts in earnest, `watch` calls \{#update\_stylesheets}.
#
# Note that `watch` uses the [FSSM](http://github.com/ttilley/fssm) library
# Note that `watch` uses the [Listen](http://github.com/guard/listen) library
# to monitor the filesystem for changes.
# FSSM isn't loaded until `watch` is run.
# The version of FSSM distributed with Sass is loaded by default,
# Listen isn't loaded until `watch` is run.
# The version of Listen distributed with Sass is loaded by default,
# but if another version has already been loaded that will be used instead.
#
# @param individual_files [Array<(String, String)>]
Expand All @@ -234,15 +235,15 @@ def watch(individual_files = [])
update_stylesheets(individual_files)

begin
require 'fssm'
require 'listen'
rescue LoadError => e
dir = Sass::Util.scope("vendor/fssm/lib")
dir = Sass::Util.scope("vendor/listen/lib")
if $LOAD_PATH.include?(dir)
e.message << "\n" <<
if File.exists?(scope(".git"))
'Run "git submodule update --init" to get the recommended version.'
else
'Run "gem install fssm" to get it.'
'Run "gem install listen" to get it.'
end
raise e
else
Expand All @@ -251,59 +252,51 @@ def watch(individual_files = [])
end
end

unless individual_files.empty? && FSSM::Backends::Default.name == "FSSM::Backends::FSEvents"
# As of FSSM 0.1.4, it doesn't support FSevents on individual files,
# but it also isn't smart enough to switch to polling itself.
require 'fssm/backends/polling'
Sass::Util.silence_warnings do
FSSM::Backends.const_set(:Default, FSSM::Backends::Polling)
end
end

# TODO: Keep better track of what depends on what
# so we don't have to run a global update every time anything changes.
FSSM.monitor do |mon|
Sass::Plugin::Listener.new do |l|
template_location_array.each do |template_location, css_location|
mon.path template_location do |path|
path.glob '**/*.s[ac]ss'

path.update do |base, relative|
l.directory(template_location, {
:modified => lambda do |base, relative|
next if relative !~ /\.s[ac]ss$/
run_template_modified File.join(base, relative)
update_stylesheets(individual_files)
end
end,

path.create do |base, relative|
:added => lambda do |base, relative|
next if relative !~ /\.s[ac]ss$/
run_template_created File.join(base, relative)
update_stylesheets(individual_files)
end
end,

path.delete do |base, relative|
:removed => lambda do |base, relative|
next if relative !~ /\.s[ac]ss$/
run_template_deleted File.join(base, relative)
css = File.join(css_location, relative.gsub(/\.s[ac]ss$/, '.css'))
try_delete_css css
update_stylesheets(individual_files)
end
end
})
end

individual_files.each do |template, css|
mon.file template do |path|
path.update do
l.file(template, {
:modified => lambda do
run_template_modified template
update_stylesheets(individual_files)
end
end,

path.create do
:added => lambda do
run_template_created template
update_stylesheets(individual_files)
end
end,

path.delete do
:removed => lambda do
run_template_deleted template
try_delete_css css
update_stylesheets(individual_files)
end
end
})
end
end
end
Expand Down
59 changes: 59 additions & 0 deletions lib/sass/plugin/listener.rb
@@ -0,0 +1,59 @@
# A wrapper around the Listen gem. Adds support for listening to individual
# files, as well as a somewhat cleaner event dispatch API.
#
# @private
class Sass::Plugin::Listener
def initialize
@directories = {}
yield self
begin
start!
rescue Exception => e
raise e unless e.is_a?(Interrupt)
end
end

def directory(path, events)
(@directories[path] ||= []) << events
end

def file(path, events)
file_base = File.basename(path)
directory(File.dirname(path), {
:modified => file_event_fn(events[:modified], file_base),
:added => file_event_fn(events[:added], file_base),
:removed => file_event_fn(events[:removed], file_base)
})
end

def start!
listener = Listen::MultiListener.new(*@directories.keys) do |modified, added, removed|
modified = modified.group_by {|path| File.dirname(path)}
added = added.group_by {|path| File.dirname(path)}
removed = removed.group_by {|path| File.dirname(path)}

@directories.each do |dir, events|
events.each do |e|
run_events(modified[dir], e[:modified], dir)
run_events(added[dir], e[:added], dir)
run_events(removed[dir], e[:removed], dir)
end
end
end.start
end

private

def file_event_fn(event, file_base)
lambda do |dir, base|
next unless event
next unless base == file_base
event.call
end
end

def run_events(paths, event, path)
return if paths.nil? || event.nil?
paths.each {|p| event[File.dirname(p), File.basename(p)]}
end
end
2 changes: 1 addition & 1 deletion lib/sass/script/lexer.rb
Expand Up @@ -293,7 +293,7 @@ def bool
end

def special_fun
return unless str1 = scan(/((-[\w-]+-)?calc|expression|progid:[a-z\.]*)\(/i)
return unless str1 = scan(/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
str2, _ = Sass::Shared.balance(@scanner, ?(, ?), 1)
c = str2.count("\n")
old_line = @line
Expand Down
1 change: 1 addition & 0 deletions lib/sass/script/list.rb
Expand Up @@ -46,6 +46,7 @@ def to_s(opts = {})

# @see Node#to_sass
def to_sass(opts = {})
return "()" if value.empty?
precedence = Sass::Script::Parser.precedence_of(separator)
value.map do |v|
if v.is_a?(List) && Sass::Script::Parser.precedence_of(v.separator) <= precedence
Expand Down
10 changes: 10 additions & 0 deletions test/sass/conversion_test.rb
Expand Up @@ -1515,6 +1515,16 @@ def test_indent
end


## Regression Tests

def test_empty_lists
assert_renders(<<SASS, <<SCSS)
$foo: ()
SASS
$foo: ();
SCSS
end

private

def assert_sass_to_sass(sass, options = {})
Expand Down
9 changes: 9 additions & 0 deletions test/sass/scss/css_test.rb
Expand Up @@ -412,6 +412,15 @@ def test_calc_function
SCSS
end

def test_element_function
assert_parses <<SCSS
foo {
a: -moz-element(#foo);
b: -webkit-element(#foo);
b: -foobar-element(#foo); }
SCSS
end

def test_unary_ops
assert_equal <<CSS, render(<<SCSS)
foo {
Expand Down
1 change: 0 additions & 1 deletion vendor/fssm
Submodule fssm deleted from b16f7e
1 change: 1 addition & 0 deletions vendor/listen
Submodule listen added at b48a81

0 comments on commit 05235ac

Please sign in to comment.