sass 3.2.10 → 3.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +2 -2
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass/cache_stores/filesystem.rb +1 -1
- data/lib/sass/exec.rb +10 -3
- data/lib/sass/plugin/staleness_checker.rb +19 -5
- data/lib/sass/script/functions.rb +18 -3
- data/lib/sass/script/list.rb +2 -1
- data/lib/sass/script/operation.rb +0 -1
- data/lib/sass/script/unary_operation.rb +8 -3
- data/lib/sass/scss/parser.rb +1 -0
- data/lib/sass/selector.rb +18 -15
- data/lib/sass/selector/sequence.rb +1 -1
- data/lib/sass/selector/simple.rb +1 -1
- data/lib/sass/selector/simple_sequence.rb +15 -8
- data/lib/sass/tree/visitors/cssize.rb +4 -4
- data/lib/sass/tree/visitors/to_css.rb +0 -1
- data/lib/sass/util.rb +23 -0
- data/test/sass/conversion_test.rb +17 -0
- data/test/sass/extend_test.rb +35 -0
- data/test/sass/functions_test.rb +6 -0
- data/test/sass/util_test.rb +48 -0
- metadata +2 -2
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Sass
|
1
|
+
# Sass [](http://badge.fury.io/rb/sass)
|
2
2
|
|
3
3
|
**Sass makes CSS fun again**. Sass is an extension of CSS3,
|
4
4
|
adding nested rules, variables, mixins, selector inheritance, and more.
|
@@ -56,7 +56,7 @@ to `config.ru`.
|
|
56
56
|
Then any Sass files in `public/stylesheets/sass`
|
57
57
|
will be compiled into CSS files in `public/stylesheets` on every request.
|
58
58
|
|
59
|
-
To use Sass
|
59
|
+
To use Sass programmatically,
|
60
60
|
check out the [YARD documentation](http://sass-lang.com/docs/yardoc/).
|
61
61
|
|
62
62
|
## Formatting
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.2.
|
1
|
+
3.2.11
|
data/VERSION_DATE
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
28 September 2013 01:15:19 UTC
|
@@ -36,7 +36,7 @@ module Sass
|
|
36
36
|
# return if File.exists?(File.dirname(compiled_filename)) && !File.writable?(File.dirname(compiled_filename))
|
37
37
|
# return if File.exists?(compiled_filename) && !File.writable?(compiled_filename)
|
38
38
|
FileUtils.mkdir_p(File.dirname(compiled_filename))
|
39
|
-
|
39
|
+
Sass::Util.atomic_create_and_write_file(compiled_filename) do |f|
|
40
40
|
f.puts(version)
|
41
41
|
f.puts(sha)
|
42
42
|
f.write(contents)
|
data/lib/sass/exec.rb
CHANGED
@@ -293,8 +293,16 @@ END
|
|
293
293
|
@options[:for_engine][:cache] = false
|
294
294
|
end
|
295
295
|
|
296
|
-
|
297
|
-
|
296
|
+
encoding_desc = if ::Sass::Util.ruby1_8?
|
297
|
+
'Does not work in ruby 1.8.'
|
298
|
+
else
|
299
|
+
'Specify the default encoding for Sass files.'
|
300
|
+
end
|
301
|
+
opts.on('-E encoding', encoding_desc) do |encoding|
|
302
|
+
if ::Sass::Util.ruby1_8?
|
303
|
+
$stderr.puts "Specifying the encoding is not supported in ruby 1.8."
|
304
|
+
exit 1
|
305
|
+
else
|
298
306
|
Encoding.default_external = encoding
|
299
307
|
end
|
300
308
|
end
|
@@ -612,7 +620,6 @@ END
|
|
612
620
|
end
|
613
621
|
@options[:output] ||= @options[:input]
|
614
622
|
|
615
|
-
from = @options[:from]
|
616
623
|
if @options[:to] == @options[:from] && !@options[:in_place]
|
617
624
|
fmt = @options[:from]
|
618
625
|
raise "Error: converting from #{fmt} to #{fmt} without --in-place"
|
@@ -24,11 +24,13 @@ module Sass
|
|
24
24
|
# as its instance-level caches are never explicitly expired.
|
25
25
|
class StalenessChecker
|
26
26
|
@dependencies_cache = {}
|
27
|
+
@dependency_cache_mutex = Mutex.new
|
27
28
|
|
28
29
|
class << self
|
29
30
|
# TODO: attach this to a compiler instance.
|
30
31
|
# @private
|
31
32
|
attr_accessor :dependencies_cache
|
33
|
+
attr_reader :dependency_cache_mutex
|
32
34
|
end
|
33
35
|
|
34
36
|
# Creates a new StalenessChecker
|
@@ -37,8 +39,6 @@ module Sass
|
|
37
39
|
# @param options [{Symbol => Object}]
|
38
40
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
39
41
|
def initialize(options)
|
40
|
-
@dependencies = self.class.dependencies_cache
|
41
|
-
|
42
42
|
# URIs that are being actively checked for staleness. Protects against
|
43
43
|
# import loops.
|
44
44
|
@actively_checking = Set.new
|
@@ -131,7 +131,7 @@ module Sass
|
|
131
131
|
begin
|
132
132
|
mtime = importer.mtime(uri, @options)
|
133
133
|
if mtime.nil?
|
134
|
-
|
134
|
+
with_dependency_cache {|cache| cache.delete([uri, importer])}
|
135
135
|
nil
|
136
136
|
else
|
137
137
|
mtime
|
@@ -140,11 +140,14 @@ module Sass
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def dependencies(uri, importer)
|
143
|
-
stored_mtime, dependencies =
|
143
|
+
stored_mtime, dependencies =
|
144
|
+
with_dependency_cache {|cache| Sass::Util.destructure(cache[[uri, importer]])}
|
144
145
|
|
145
146
|
if !stored_mtime || stored_mtime < mtime(uri, importer)
|
146
147
|
dependencies = compute_dependencies(uri, importer)
|
147
|
-
|
148
|
+
with_dependency_cache do |cache|
|
149
|
+
cache[[uri, importer]] = [mtime(uri, importer), dependencies]
|
150
|
+
end
|
148
151
|
end
|
149
152
|
|
150
153
|
dependencies
|
@@ -178,6 +181,17 @@ module Sass
|
|
178
181
|
def tree(uri, importer)
|
179
182
|
@parse_trees[[uri, importer]] ||= importer.find(uri, @options).to_tree
|
180
183
|
end
|
184
|
+
|
185
|
+
# Get access to the global dependency cache in a threadsafe manner.
|
186
|
+
# Inside the block, no other thread can access the dependency cache.
|
187
|
+
#
|
188
|
+
# @yieldparam cache [Hash] The hash that is the global dependency cache
|
189
|
+
# @return The value returned by the block to which this method yields
|
190
|
+
def with_dependency_cache
|
191
|
+
StalenessChecker.dependency_cache_mutex.synchronize do
|
192
|
+
yield StalenessChecker.dependencies_cache
|
193
|
+
end
|
194
|
+
end
|
181
195
|
end
|
182
196
|
end
|
183
197
|
end
|
@@ -36,7 +36,7 @@ module Sass::Script
|
|
36
36
|
# : Creates a {Color} from hue, saturation, and lightness values.
|
37
37
|
#
|
38
38
|
# \{#hsla hsla($hue, $saturation, $lightness, $alpha)}
|
39
|
-
# : Creates a {Color} from hue, saturation, lightness,
|
39
|
+
# : Creates a {Color} from hue, saturation, lightness, and alpha
|
40
40
|
# values.
|
41
41
|
#
|
42
42
|
# \{#hue hue($color)}
|
@@ -461,7 +461,7 @@ module Sass::Script
|
|
461
461
|
end
|
462
462
|
declare :hsl, [:hue, :saturation, :lightness]
|
463
463
|
|
464
|
-
# Creates a {Color} from hue, saturation, lightness,
|
464
|
+
# Creates a {Color} from hue, saturation, lightness, and alpha
|
465
465
|
# values. Uses the algorithm from the [CSS3 spec][].
|
466
466
|
#
|
467
467
|
# [CSS3 spec]: http://www.w3.org/TR/css3-color/#hsl-color
|
@@ -1488,7 +1488,7 @@ module Sass::Script
|
|
1488
1488
|
end
|
1489
1489
|
declare :if, [:condition, :if_true, :if_false]
|
1490
1490
|
|
1491
|
-
# This function only exists as a workaround for IE7's [`content:counter`
|
1491
|
+
# This function only exists as a workaround for IE7's [`content: counter`
|
1492
1492
|
# bug][bug]. It works identically to any other plain-CSS function, except it
|
1493
1493
|
# avoids adding spaces between the argument commas.
|
1494
1494
|
#
|
@@ -1503,6 +1503,21 @@ module Sass::Script
|
|
1503
1503
|
end
|
1504
1504
|
declare :counter, [], :var_args => true
|
1505
1505
|
|
1506
|
+
# This function only exists as a workaround for IE7's [`content: counters`
|
1507
|
+
# bug][bug]. It works identically to any other plain-CSS function, except it
|
1508
|
+
# avoids adding spaces between the argument commas.
|
1509
|
+
#
|
1510
|
+
# [bug]: http://jes.st/2013/ie7s-css-breaking-content-counter-bug/
|
1511
|
+
#
|
1512
|
+
# @example
|
1513
|
+
# counters(item, ".") => counters(item,".")
|
1514
|
+
# @overload counters($args...)
|
1515
|
+
# @return [String]
|
1516
|
+
def counters(*args)
|
1517
|
+
Sass::Script::String.new("counters(#{args.map {|a| a.to_s(options)}.join(',')})")
|
1518
|
+
end
|
1519
|
+
declare :counters, [], :var_args => true
|
1520
|
+
|
1506
1521
|
private
|
1507
1522
|
|
1508
1523
|
# This method implements the pattern of transforming a numeric value into
|
data/lib/sass/script/list.rb
CHANGED
@@ -49,7 +49,8 @@ module Sass::Script
|
|
49
49
|
return "()" if value.empty?
|
50
50
|
precedence = Sass::Script::Parser.precedence_of(separator)
|
51
51
|
value.reject {|e| e.is_a?(Null)}.map do |v|
|
52
|
-
if v.is_a?(List) && Sass::Script::Parser.precedence_of(v.separator) <= precedence
|
52
|
+
if v.is_a?(List) && Sass::Script::Parser.precedence_of(v.separator) <= precedence ||
|
53
|
+
separator == :space && v.is_a?(UnaryOperation) && (v.operator == :minus || v.operator == :plus)
|
53
54
|
"(#{v.to_sass(opts)})"
|
54
55
|
else
|
55
56
|
v.to_sass(opts)
|
@@ -4,9 +4,14 @@ module Sass::Script
|
|
4
4
|
#
|
5
5
|
# Currently only `-`, `/`, and `not` are unary operators.
|
6
6
|
class UnaryOperation < Node
|
7
|
-
# @
|
8
|
-
|
9
|
-
|
7
|
+
# @return [Symbol] The operation to perform
|
8
|
+
attr_reader :operator
|
9
|
+
|
10
|
+
# @return [Script::Node] The parse-tree node for the object of the operator
|
11
|
+
attr_reader :operand
|
12
|
+
|
13
|
+
# @param operand [Script::Node] See \{#operand}
|
14
|
+
# @param operator [Symbol] See \{#operator}
|
10
15
|
def initialize(operand, operator)
|
11
16
|
@operand = operand
|
12
17
|
@operator = operator
|
data/lib/sass/scss/parser.rb
CHANGED
@@ -1045,6 +1045,7 @@ MESSAGE
|
|
1045
1045
|
:qualified_name => "identifier",
|
1046
1046
|
:expr => "expression (e.g. 1px, bold)",
|
1047
1047
|
:_selector => "selector",
|
1048
|
+
:selector_comma_sequence => "selector",
|
1048
1049
|
:simple_selector_sequence => "selector",
|
1049
1050
|
:import_arg => "file to import (string or url())",
|
1050
1051
|
:moz_document_function => "matching function (e.g. url-prefix(), domain())",
|
data/lib/sass/selector.rb
CHANGED
@@ -346,19 +346,19 @@ module Sass
|
|
346
346
|
# A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`) selector.
|
347
347
|
# It can have arguments (e.g. `:nth-child(2n+1)`).
|
348
348
|
class Pseudo < Simple
|
349
|
-
#
|
350
|
-
#
|
351
|
-
#
|
349
|
+
# Some psuedo-class-syntax selectors are actually considered
|
350
|
+
# pseudo-elements and must be treated differently. This is a list of such
|
351
|
+
# selectors
|
352
352
|
#
|
353
|
-
# @return [
|
354
|
-
|
353
|
+
# @return [Array<String>]
|
354
|
+
ACTUALLY_ELEMENTS = %w[after before first-line first-letter]
|
355
355
|
|
356
|
-
#
|
357
|
-
#
|
358
|
-
#
|
356
|
+
# Like \{#type}, but returns the type of selector this looks like, rather
|
357
|
+
# than the type it is semantically. This only differs from type for
|
358
|
+
# selectors in \{ACTUALLY\_ELEMENTS}.
|
359
359
|
#
|
360
|
-
# @return [
|
361
|
-
|
360
|
+
# @return [Symbol]
|
361
|
+
attr_reader :syntactic_type
|
362
362
|
|
363
363
|
# The name of the selector.
|
364
364
|
#
|
@@ -380,18 +380,22 @@ module Sass
|
|
380
380
|
# @param arg [nil, Array<String, Sass::Script::Node>] The argument to the selector,
|
381
381
|
# or nil if no argument was given
|
382
382
|
def initialize(type, name, arg)
|
383
|
-
@
|
383
|
+
@syntactic_type = type
|
384
384
|
@name = name
|
385
385
|
@arg = arg
|
386
386
|
end
|
387
387
|
|
388
|
-
|
389
|
-
|
388
|
+
# The type of the selector. `:class` if this is a pseudoclass selector,
|
389
|
+
# `:element` if it's a pseudoelement.
|
390
|
+
#
|
391
|
+
# @return [Symbol]
|
392
|
+
def type
|
393
|
+
ACTUALLY_ELEMENTS.include?(name.first) ? :element : syntactic_type
|
390
394
|
end
|
391
395
|
|
392
396
|
# @see Selector#to_a
|
393
397
|
def to_a
|
394
|
-
res = [
|
398
|
+
res = [syntactic_type == :class ? ":" : "::"] + @name
|
395
399
|
(res << "(").concat(Sass::Util.strip_string_array(@arg)) << ")" if @arg
|
396
400
|
res
|
397
401
|
end
|
@@ -405,7 +409,6 @@ module Sass
|
|
405
409
|
sel.is_a?(Pseudo) && sel.type == :element &&
|
406
410
|
(sel.name != self.name || sel.arg != self.arg)
|
407
411
|
end
|
408
|
-
return sels + [self] if final?
|
409
412
|
super
|
410
413
|
end
|
411
414
|
|
@@ -255,7 +255,7 @@ module Sass
|
|
255
255
|
# is a supersequence of the other, use that, otherwise give up.
|
256
256
|
lcs = Sass::Util.lcs(ops1, ops2)
|
257
257
|
return unless lcs == ops1 || lcs == ops2
|
258
|
-
res.unshift
|
258
|
+
res.unshift(*(ops1.size > ops2.size ? ops1 : ops2).reverse)
|
259
259
|
return res
|
260
260
|
end
|
261
261
|
|
data/lib/sass/selector/simple.rb
CHANGED
@@ -85,7 +85,7 @@ module Sass
|
|
85
85
|
sels_with_ix = Sass::Util.enum_with_index(sels)
|
86
86
|
_, i =
|
87
87
|
if self.is_a?(Pseudo) || self.is_a?(SelectorPseudoClass)
|
88
|
-
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && (sels.last.
|
88
|
+
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && (sels.last.type == :element)}
|
89
89
|
else
|
90
90
|
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) || sel.is_a?(SelectorPseudoClass)}
|
91
91
|
end
|
@@ -37,11 +37,16 @@ module Sass
|
|
37
37
|
@base ||= (members.first if members.first.is_a?(Element) || members.first.is_a?(Universal))
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
def pseudo_elements
|
41
|
+
@pseudo_elements ||= (members - [base]).
|
42
|
+
select {|sel| sel.is_a?(Pseudo) && sel.type == :element}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the non-base, non-pseudo-class selectors in this sequence.
|
41
46
|
#
|
42
47
|
# @return [Set<Simple>]
|
43
48
|
def rest
|
44
|
-
@rest ||= Set.new(
|
49
|
+
@rest ||= Set.new(members - [base] - pseudo_elements)
|
45
50
|
end
|
46
51
|
|
47
52
|
# Whether or not this compound selector is the subject of the parent
|
@@ -129,9 +134,9 @@ module Sass
|
|
129
134
|
# by the time extension and unification happen,
|
130
135
|
# this exception will only ever be raised as a result of programmer error
|
131
136
|
def unify(sels, other_subject)
|
132
|
-
return unless sseq = members.inject(sels) do |
|
133
|
-
return unless
|
134
|
-
sel.unify(
|
137
|
+
return unless sseq = members.inject(sels) do |member, sel|
|
138
|
+
return unless member
|
139
|
+
sel.unify(member)
|
135
140
|
end
|
136
141
|
SimpleSequence.new(sseq, other_subject || subject?)
|
137
142
|
end
|
@@ -145,7 +150,9 @@ module Sass
|
|
145
150
|
# @param sseq [SimpleSequence]
|
146
151
|
# @return [Boolean]
|
147
152
|
def superselector?(sseq)
|
148
|
-
(base.nil? || base.eql?(sseq.base)) &&
|
153
|
+
(base.nil? || base.eql?(sseq.base)) &&
|
154
|
+
pseudo_elements.eql?(sseq.pseudo_elements) &&
|
155
|
+
rest.subset?(sseq.rest)
|
149
156
|
end
|
150
157
|
|
151
158
|
# @see Simple#to_a
|
@@ -197,8 +204,8 @@ WARNING
|
|
197
204
|
end
|
198
205
|
|
199
206
|
def _eql?(other)
|
200
|
-
other.base.eql?(self.base) &&
|
201
|
-
other.subject? == self.subject?
|
207
|
+
other.base.eql?(self.base) && other.pseudo_elements == pseudo_elements &&
|
208
|
+
Sass::Util.set_eql?(other.rest, self.rest) && other.subject? == self.subject?
|
202
209
|
end
|
203
210
|
end
|
204
211
|
end
|
@@ -124,12 +124,12 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
124
124
|
end
|
125
125
|
|
126
126
|
sel = sseq.members
|
127
|
-
parent.resolved_rules.members.each do |
|
128
|
-
if !
|
129
|
-
raise Sass::SyntaxError.new("#{
|
127
|
+
parent.resolved_rules.members.each do |member|
|
128
|
+
if !member.members.last.is_a?(Sass::Selector::SimpleSequence)
|
129
|
+
raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
|
130
130
|
end
|
131
131
|
|
132
|
-
@extends[sel] = Extend.new(
|
132
|
+
@extends[sel] = Extend.new(member, sel, node, @parent_directives.dup, :not_found)
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
@@ -160,7 +160,6 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
160
160
|
|
161
161
|
to_return = ''
|
162
162
|
old_spaces = ' ' * @tabs
|
163
|
-
spaces = ' ' * (@tabs + 1)
|
164
163
|
if node.style != :compressed
|
165
164
|
if node.options[:debug_info] && !@in_directive
|
166
165
|
to_return << visit(debug_info_rule(node.debug_info, node.options)) << "\n"
|
data/lib/sass/util.rb
CHANGED
@@ -868,6 +868,29 @@ MSG
|
|
868
868
|
end
|
869
869
|
end
|
870
870
|
|
871
|
+
# This creates a temp file and yields it for writing. When the
|
872
|
+
# write is complete, the file is moved into the desired location.
|
873
|
+
# The atomicity of this operation is provided by the filesystem's
|
874
|
+
# rename operation.
|
875
|
+
#
|
876
|
+
# @param filename [String] The file to write to.
|
877
|
+
# @yieldparam tmpfile [Tempfile] The temp file that can be written to.
|
878
|
+
# @return The value returned by the block.
|
879
|
+
def atomic_create_and_write_file(filename)
|
880
|
+
require 'tempfile'
|
881
|
+
tmpfile = Tempfile.new(File.basename(filename), File.dirname(filename))
|
882
|
+
tmp_path = tmpfile.path
|
883
|
+
tmpfile.binmode if tmpfile.respond_to?(:binmode)
|
884
|
+
result = yield tmpfile
|
885
|
+
File.rename tmpfile.path, filename
|
886
|
+
result
|
887
|
+
ensure
|
888
|
+
# close and remove the tempfile if it still exists,
|
889
|
+
# presumably due to an error during write
|
890
|
+
tmpfile.close if tmpfile
|
891
|
+
tmpfile.unlink if tmpfile
|
892
|
+
end
|
893
|
+
|
871
894
|
private
|
872
895
|
|
873
896
|
# Calculates the memoization table for the Least Common Subsequence algorithm.
|
@@ -1692,6 +1692,23 @@ foo {
|
|
1692
1692
|
SCSS
|
1693
1693
|
end
|
1694
1694
|
|
1695
|
+
def test_ambiguous_negation
|
1696
|
+
assert_renders(<<SASS, <<SCSS, :indent => ' ')
|
1697
|
+
foo
|
1698
|
+
ok: -$foo
|
1699
|
+
comma: 10px, -$foo
|
1700
|
+
needs-parens: 10px (-$foo)
|
1701
|
+
no-parens: a 50px + 60px b
|
1702
|
+
SASS
|
1703
|
+
foo {
|
1704
|
+
ok: -$foo;
|
1705
|
+
comma: 10px, -$foo;
|
1706
|
+
needs-parens: 10px (-$foo);
|
1707
|
+
no-parens: a 50px + 60px b;
|
1708
|
+
}
|
1709
|
+
SCSS
|
1710
|
+
end
|
1711
|
+
|
1695
1712
|
private
|
1696
1713
|
|
1697
1714
|
def assert_sass_to_sass(sass, options = {})
|
data/test/sass/extend_test.rb
CHANGED
@@ -1172,6 +1172,41 @@ SCSS
|
|
1172
1172
|
|
1173
1173
|
# Regression Tests
|
1174
1174
|
|
1175
|
+
def test_pseudo_element_superselector
|
1176
|
+
# Pseudo-elements shouldn't be removed in superselector calculations.
|
1177
|
+
assert_equal <<CSS, render(<<SCSS)
|
1178
|
+
a#bar, a#bar::fblthp {
|
1179
|
+
a: b; }
|
1180
|
+
CSS
|
1181
|
+
%x#bar {a: b} // Add an id to make the results have high specificity
|
1182
|
+
%y, %y::fblthp {@extend %x}
|
1183
|
+
a {@extend %y}
|
1184
|
+
SCSS
|
1185
|
+
|
1186
|
+
# Pseudo-classes can be removed when the second law allows.
|
1187
|
+
assert_equal <<CSS, render(<<SCSS)
|
1188
|
+
a#bar {
|
1189
|
+
a: b; }
|
1190
|
+
CSS
|
1191
|
+
%x#bar {a: b}
|
1192
|
+
%y, %y:fblthp {@extend %x}
|
1193
|
+
a {@extend %y}
|
1194
|
+
SCSS
|
1195
|
+
|
1196
|
+
# A few pseudo-elements can be written as pseudo-elements for historical
|
1197
|
+
# reasons. See http://www.w3.org/TR/selectors4/#pseudo-elements.
|
1198
|
+
%w[first-line first-letter before after].each do |pseudo|
|
1199
|
+
assert_equal <<CSS, render(<<SCSS)
|
1200
|
+
a#bar, a#bar:#{pseudo} {
|
1201
|
+
a: b; }
|
1202
|
+
CSS
|
1203
|
+
%x#bar {a: b}
|
1204
|
+
%y, %y:#{pseudo} {@extend %x}
|
1205
|
+
a {@extend %y}
|
1206
|
+
SCSS
|
1207
|
+
end
|
1208
|
+
end
|
1209
|
+
|
1175
1210
|
def test_nested_sibling_extend
|
1176
1211
|
assert_equal <<CSS, render(<<SCSS)
|
1177
1212
|
.parent .bar, .parent .foo {
|
data/test/sass/functions_test.rb
CHANGED
@@ -1046,6 +1046,12 @@ MSG
|
|
1046
1046
|
assert_equal('counter(item,".")', evaluate('counter(item,".")'))
|
1047
1047
|
end
|
1048
1048
|
|
1049
|
+
def test_counters
|
1050
|
+
assert_equal("counters(foo)", evaluate("counters(foo)"))
|
1051
|
+
assert_equal('counters(item,".")', evaluate('counters(item, ".")'))
|
1052
|
+
assert_equal('counters(item,".")', evaluate('counters(item,".")'))
|
1053
|
+
end
|
1054
|
+
|
1049
1055
|
def test_keyword_args_rgb
|
1050
1056
|
assert_equal(%Q{white}, evaluate("rgb($red: 255, $green: 255, $blue: 255)"))
|
1051
1057
|
end
|
data/test/sass/util_test.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require File.dirname(__FILE__) + '/../test_helper'
|
3
3
|
require 'pathname'
|
4
|
+
require 'tmpdir'
|
4
5
|
|
5
6
|
class UtilTest < Test::Unit::TestCase
|
6
7
|
include Sass::Util
|
@@ -310,4 +311,51 @@ class UtilTest < Test::Unit::TestCase
|
|
310
311
|
"UtilTest::FooBar must implement #foo") {FooBar.new.foo}
|
311
312
|
end
|
312
313
|
|
314
|
+
def test_atomic_writes
|
315
|
+
# when using normal writes, this test fails about 90% of the time.
|
316
|
+
filename = File.join(Dir.tmpdir, "test_atomic")
|
317
|
+
5.times do
|
318
|
+
writes_to_perform = %w(1 2 3 4 5 6 7 8 9).map {|i| "#{i}\n" * 100_000}
|
319
|
+
threads = writes_to_perform.map do |to_write|
|
320
|
+
Thread.new do
|
321
|
+
# To see this test fail with a normal write,
|
322
|
+
# change to the standard file open mechanism:
|
323
|
+
# open(filename, "w") do |f|
|
324
|
+
atomic_create_and_write_file(filename) do |f|
|
325
|
+
f.write(to_write)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
loop do
|
330
|
+
contents = File.exist?(filename) ? File.read(filename) : nil
|
331
|
+
next if contents.nil? || contents.size == 0
|
332
|
+
unless writes_to_perform.include?(contents)
|
333
|
+
if contents.size != writes_to_perform.first.size
|
334
|
+
fail "Incomplete write detected: was #{contents.size} characters, " +
|
335
|
+
"should have been #{writes_to_perform.first.size}"
|
336
|
+
else
|
337
|
+
fail "Corrupted read/write detected"
|
338
|
+
end
|
339
|
+
end
|
340
|
+
break if threads.all? {|t| !t.alive?}
|
341
|
+
end
|
342
|
+
threads.each {|t| t.join}
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
class FakeError < RuntimeError; end
|
347
|
+
|
348
|
+
def test_atomic_writes_handles_exceptions
|
349
|
+
filename = File.join(Dir.tmpdir, "test_atomic_exception")
|
350
|
+
FileUtils.rm_f(filename)
|
351
|
+
tmp_filename = nil
|
352
|
+
assert_raises FakeError do
|
353
|
+
atomic_create_and_write_file(filename) do |f|
|
354
|
+
tmp_filename = f.path
|
355
|
+
raise FakeError.new "Borken"
|
356
|
+
end
|
357
|
+
end
|
358
|
+
assert !File.exist?(filename)
|
359
|
+
assert !File.exist?(tmp_filename)
|
360
|
+
end
|
313
361
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-
|
14
|
+
date: 2013-09-28 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: yard
|