sass 3.3.0.alpha.354 → 3.3.0.alpha.364
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/REVISION +1 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass/environment.rb +116 -67
- data/lib/sass/script/functions.rb +85 -0
- data/lib/sass/script/tree/funcall.rb +1 -0
- data/test/sass/functions_test.rb +105 -2
- metadata +4 -4
data/REVISION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
4e515ab6a46507013fcbe426a5ecfa061b4ae571
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.3.0.alpha.
|
1
|
+
3.3.0.alpha.364
|
data/VERSION_DATE
CHANGED
@@ -1 +1 @@
|
|
1
|
-
05 October 2013
|
1
|
+
05 October 2013 16:04:57 GMT
|
data/lib/sass/environment.rb
CHANGED
@@ -1,28 +1,80 @@
|
|
1
1
|
require 'set'
|
2
2
|
|
3
3
|
module Sass
|
4
|
-
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
4
|
+
|
5
|
+
# The abstract base class for lexical environments for SassScript.
|
6
|
+
class BaseEnvironment
|
7
|
+
class << self
|
8
|
+
# Note: when updating this,
|
9
|
+
# update sass/yard/inherited_hash.rb as well.
|
10
|
+
def inherited_hash_accessor(name)
|
11
|
+
inherited_hash_reader(name)
|
12
|
+
inherited_hash_writer(name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def inherited_hash_reader(name)
|
16
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
17
|
+
def #{name}(name)
|
18
|
+
_#{name}(name.tr('_', '-'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def _#{name}(name)
|
22
|
+
(@#{name}s && @#{name}s[name]) || @parent && @parent._#{name}(name)
|
23
|
+
end
|
24
|
+
protected :_#{name}
|
25
|
+
RUBY
|
26
|
+
end
|
27
|
+
|
28
|
+
def inherited_hash_writer(name)
|
29
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
30
|
+
def set_#{name}(name, value)
|
31
|
+
name = name.tr('_', '-')
|
32
|
+
@#{name}s[name] = value unless try_set_#{name}(name, value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def try_set_#{name}(name, value)
|
36
|
+
@#{name}s ||= {}
|
37
|
+
if @#{name}s.include?(name)
|
38
|
+
@#{name}s[name] = value
|
39
|
+
true
|
40
|
+
elsif @parent
|
41
|
+
@parent.try_set_#{name}(name, value)
|
42
|
+
else
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
protected :try_set_#{name}
|
47
|
+
|
48
|
+
def set_local_#{name}(name, value)
|
49
|
+
@#{name}s ||= {}
|
50
|
+
@#{name}s[name.tr('_', '-')] = value
|
51
|
+
end
|
52
|
+
RUBY
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# The options passed to the Sass Engine.
|
21
57
|
attr_reader :options
|
58
|
+
|
59
|
+
# [Environment] The caller environment
|
22
60
|
attr_writer :caller
|
61
|
+
|
62
|
+
# [Environment] The content environment
|
23
63
|
attr_writer :content
|
24
64
|
attr_writer :selector
|
25
65
|
|
66
|
+
# variable
|
67
|
+
# Script::Value
|
68
|
+
inherited_hash_reader :var
|
69
|
+
|
70
|
+
# mixin
|
71
|
+
# Sass::Callable
|
72
|
+
inherited_hash_reader :mixin
|
73
|
+
|
74
|
+
# function
|
75
|
+
# Sass::Callable
|
76
|
+
inherited_hash_reader :function
|
77
|
+
|
26
78
|
# @param options [{Symbol => Object}] The options hash. See
|
27
79
|
# {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
28
80
|
# @param parent [Environment] See \{#parent}
|
@@ -38,7 +90,7 @@ module Sass
|
|
38
90
|
@caller || (@parent && @parent.caller)
|
39
91
|
end
|
40
92
|
|
41
|
-
# The content passed to this
|
93
|
+
# The content passed to this environment. This is naturally only set
|
42
94
|
# for mixin body environments with content passed in.
|
43
95
|
# @return {Environment?}
|
44
96
|
def content
|
@@ -70,62 +122,59 @@ module Sass
|
|
70
122
|
def stack
|
71
123
|
@stack || global_env.stack
|
72
124
|
end
|
125
|
+
end
|
73
126
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
(@#{name}s && @#{name}s[name]) || @parent && @parent._#{name}(name)
|
92
|
-
end
|
93
|
-
protected :_#{name}
|
94
|
-
|
95
|
-
def set_#{name}(name, value)
|
96
|
-
name = name.tr(UNDERSCORE, DASH)
|
97
|
-
@#{name}s[name] = value unless try_set_#{name}(name, value)
|
98
|
-
end
|
99
|
-
|
100
|
-
def try_set_#{name}(name, value)
|
101
|
-
@#{name}s ||= {}
|
102
|
-
if @#{name}s.include?(name)
|
103
|
-
@#{name}s[name] = value
|
104
|
-
true
|
105
|
-
elsif @parent
|
106
|
-
@parent.try_set_#{name}(name, value)
|
107
|
-
else
|
108
|
-
false
|
109
|
-
end
|
110
|
-
end
|
111
|
-
protected :try_set_#{name}
|
112
|
-
|
113
|
-
def set_local_#{name}(name, value)
|
114
|
-
@#{name}s ||= {}
|
115
|
-
@#{name}s[name.tr(UNDERSCORE, DASH)] = value
|
116
|
-
end
|
117
|
-
RUBY
|
118
|
-
end
|
119
|
-
end
|
127
|
+
# The lexical environment for SassScript.
|
128
|
+
# This keeps track of variable, mixin, and function definitions.
|
129
|
+
#
|
130
|
+
# A new environment is created for each level of Sass nesting.
|
131
|
+
# This allows variables to be lexically scoped.
|
132
|
+
# The new environment refers to the environment in the upper scope,
|
133
|
+
# so it has access to variables defined in enclosing scopes,
|
134
|
+
# but new variables are defined locally.
|
135
|
+
#
|
136
|
+
# Environment also keeps track of the {Engine} options
|
137
|
+
# so that they can be made available to {Sass::Script::Functions}.
|
138
|
+
class Environment < BaseEnvironment
|
139
|
+
# The enclosing environment,
|
140
|
+
# or nil if this is the global environment.
|
141
|
+
#
|
142
|
+
# @return [Environment]
|
143
|
+
attr_reader :parent
|
120
144
|
|
121
145
|
# variable
|
122
146
|
# Script::Value
|
123
|
-
|
147
|
+
inherited_hash_writer :var
|
148
|
+
|
124
149
|
# mixin
|
125
150
|
# Sass::Callable
|
126
|
-
|
151
|
+
inherited_hash_writer :mixin
|
152
|
+
|
127
153
|
# function
|
128
154
|
# Sass::Callable
|
129
|
-
|
155
|
+
inherited_hash_writer :function
|
156
|
+
end
|
157
|
+
|
158
|
+
# A read-only wrapper for a lexical environment for SassScript.
|
159
|
+
class ReadOnlyEnvironment < BaseEnvironment
|
160
|
+
# The read-only environment of the caller of this environment's mixin or function.
|
161
|
+
#
|
162
|
+
# @see BaseEnvironment#caller
|
163
|
+
# @return {ReadOnlyEnvironment}
|
164
|
+
def caller
|
165
|
+
return @caller if @caller
|
166
|
+
env = super
|
167
|
+
@caller ||= env.is_a?(ReadOnlyEnvironment) ? env : ReadOnlyEnvironment.new(env, env.options)
|
168
|
+
end
|
169
|
+
|
170
|
+
# The read-only content passed to this environment.
|
171
|
+
#
|
172
|
+
# @see BaseEnvironment#content
|
173
|
+
# @return {ReadOnlyEnvironment}
|
174
|
+
def content
|
175
|
+
return @content if @content
|
176
|
+
env = super
|
177
|
+
@content ||= env.is_a?(ReadOnlyEnvironment) ? env : ReadOnlyEnvironment.new(env, env.options)
|
178
|
+
end
|
130
179
|
end
|
131
180
|
end
|
@@ -207,6 +207,18 @@ module Sass::Script
|
|
207
207
|
# \{#feature_exists feature-exists($feature)}
|
208
208
|
# : Returns whether a feature exists in the current Sass runtime.
|
209
209
|
#
|
210
|
+
# \{#variable_exists variable-exists($name)}
|
211
|
+
# : Returns whether a variable with the given name exists in the current scope.
|
212
|
+
#
|
213
|
+
# \{#global_variable_exists global-variable-exists($name)}
|
214
|
+
# : Returns whether a variable with the given name exists in the global scope.
|
215
|
+
#
|
216
|
+
# \{#function_exists function-exists($name)}
|
217
|
+
# : Returns whether a function with the given name exists.
|
218
|
+
#
|
219
|
+
# \{#mixin_exists mixin-exists($name)}
|
220
|
+
# : Returns whether a mixin with the given name exists.
|
221
|
+
#
|
210
222
|
# \{#type_of type-of($value)}
|
211
223
|
# : Returns the type of a value.
|
212
224
|
#
|
@@ -2033,6 +2045,79 @@ module Sass::Script
|
|
2033
2045
|
end
|
2034
2046
|
declare :counters, [], :var_args => true
|
2035
2047
|
|
2048
|
+
# Check whether a variable with the given name exists in the current
|
2049
|
+
# scope or in the global scope.
|
2050
|
+
#
|
2051
|
+
# @example
|
2052
|
+
# $a-false-value: false;
|
2053
|
+
# variable-exists(a-false-value) => true
|
2054
|
+
#
|
2055
|
+
# variable-exists(nonexistent) => false
|
2056
|
+
# @param name [Sass::Script::String] The name of the variable to
|
2057
|
+
# check. The name should not include the `$`.
|
2058
|
+
# @return [Sass::Script::Bool] Whether the variable is defined in
|
2059
|
+
# the current scope.
|
2060
|
+
def variable_exists(name)
|
2061
|
+
assert_type name, :String
|
2062
|
+
Sass::Script::Value::Bool.new(environment.caller.var(name.value))
|
2063
|
+
end
|
2064
|
+
declare :variable_exists, [:name]
|
2065
|
+
|
2066
|
+
# Check whether a variable with the given name exists in the global
|
2067
|
+
# scope (at the top level of the file).
|
2068
|
+
#
|
2069
|
+
# @example
|
2070
|
+
# $a-false-value: false;
|
2071
|
+
# global-variable-exists(a-false-value) => true
|
2072
|
+
#
|
2073
|
+
# .foo {
|
2074
|
+
# $some-var: false;
|
2075
|
+
# @if global-variable-exists(some-var) { /* false, doesn't run */ }
|
2076
|
+
# }
|
2077
|
+
# @param name [Sass::Script::String] The name of the variable to
|
2078
|
+
# check. The name should not include the `$`.
|
2079
|
+
# @return [Sass::Script::Bool] Whether the variable is defined in
|
2080
|
+
# the global scope.
|
2081
|
+
def global_variable_exists(name)
|
2082
|
+
assert_type name, :String
|
2083
|
+
Sass::Script::Value::Bool.new(environment.global_env.var(name.value))
|
2084
|
+
end
|
2085
|
+
declare :global_variable_exists, [:name]
|
2086
|
+
|
2087
|
+
# Check whether a function with the given name exists.
|
2088
|
+
#
|
2089
|
+
# @example
|
2090
|
+
# function-exists(lighten) => true
|
2091
|
+
#
|
2092
|
+
# @function myfunc { @return "something"; }
|
2093
|
+
# function-exists(myfunc) => true
|
2094
|
+
# @param name [Sass::Script::String] The name of the function to
|
2095
|
+
# check.
|
2096
|
+
# @return [Sass::Script::Bool] Whether the function is defined.
|
2097
|
+
def function_exists(name)
|
2098
|
+
assert_type name, :String
|
2099
|
+
exists = Sass::Script::Functions.callable?(name.value.tr("-", "_"))
|
2100
|
+
exists ||= environment.function(name.value)
|
2101
|
+
Sass::Script::Value::Bool.new(exists)
|
2102
|
+
end
|
2103
|
+
declare :function_exists, [:name]
|
2104
|
+
|
2105
|
+
# Check whether a mixin with the given name exists.
|
2106
|
+
#
|
2107
|
+
# @example
|
2108
|
+
# mixin-exists(nonexistent) => false
|
2109
|
+
#
|
2110
|
+
# @mixin red-text { color: red; }
|
2111
|
+
# mixin-exists(red-text) => true
|
2112
|
+
# @param name [Sass::Script::String] The name of the mixin to
|
2113
|
+
# check.
|
2114
|
+
# @return [Sass::Script::Bool] Whether the mixin is defined.
|
2115
|
+
def mixin_exists(name)
|
2116
|
+
assert_type name, :String
|
2117
|
+
Sass::Script::Value::Bool.new(environment.mixin(name.value))
|
2118
|
+
end
|
2119
|
+
declare :mixin_exists, [:name]
|
2120
|
+
|
2036
2121
|
private
|
2037
2122
|
|
2038
2123
|
# This method implements the pattern of transforming a numeric value into
|
@@ -131,6 +131,7 @@ module Sass::Script::Tree
|
|
131
131
|
|
132
132
|
if Sass::Script::Functions.callable?(ruby_name)
|
133
133
|
local_environment = Sass::Environment.new(environment.global_env, environment.options)
|
134
|
+
local_environment.caller = Sass::ReadOnlyEnvironment.new(environment, environment.options)
|
134
135
|
opts(Sass::Script::Functions::EvaluationContext.new(
|
135
136
|
local_environment).send(ruby_name, *args))
|
136
137
|
else
|
data/test/sass/functions_test.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'test/unit'
|
3
3
|
require File.dirname(__FILE__) + '/../test_helper'
|
4
|
+
require File.dirname(__FILE__) + '/test_helper'
|
4
5
|
require 'sass/script'
|
6
|
+
require 'mock_importer'
|
5
7
|
|
6
8
|
module Sass::Script::Functions
|
7
9
|
def no_kw_args
|
@@ -1450,6 +1452,100 @@ WARNING
|
|
1450
1452
|
assert_error_message "$color: 3px is not a color for `lighten'", "call(lighten, 3px, 5%)"
|
1451
1453
|
end
|
1452
1454
|
|
1455
|
+
def test_variable_exists
|
1456
|
+
assert_equal <<CSS, render(<<SCSS)
|
1457
|
+
.test {
|
1458
|
+
false: false;
|
1459
|
+
true: true;
|
1460
|
+
true: true;
|
1461
|
+
true: true;
|
1462
|
+
true: true; }
|
1463
|
+
CSS
|
1464
|
+
$global-var: has-value;
|
1465
|
+
.test {
|
1466
|
+
false: variable-exists(foo);
|
1467
|
+
$foo: has-value;
|
1468
|
+
true: variable-exists(foo);
|
1469
|
+
true: variable-exists($name: foo);
|
1470
|
+
true: variable-exists(global-var);
|
1471
|
+
true: variable-exists($name: global-var);
|
1472
|
+
}
|
1473
|
+
SCSS
|
1474
|
+
end
|
1475
|
+
|
1476
|
+
def test_global_variable_exists
|
1477
|
+
assert_equal <<CSS, render(<<SCSS)
|
1478
|
+
.test {
|
1479
|
+
false: false;
|
1480
|
+
false: false;
|
1481
|
+
true: true;
|
1482
|
+
true: true;
|
1483
|
+
false: false;
|
1484
|
+
true: true;
|
1485
|
+
true: true; }
|
1486
|
+
CSS
|
1487
|
+
$g: something;
|
1488
|
+
$h: null;
|
1489
|
+
$false: global-variable-exists(foo);
|
1490
|
+
$true: global-variable-exists(g);
|
1491
|
+
$named: global-variable-exists($name: g);
|
1492
|
+
.test {
|
1493
|
+
$foo: locally-defined;
|
1494
|
+
false: global-variable-exists(foo);
|
1495
|
+
false: global-variable-exists(foo2);
|
1496
|
+
true: global-variable-exists(g);
|
1497
|
+
true: global-variable-exists(h);
|
1498
|
+
false: $false;
|
1499
|
+
true: $true;
|
1500
|
+
true: $named;
|
1501
|
+
}
|
1502
|
+
SCSS
|
1503
|
+
end
|
1504
|
+
|
1505
|
+
def test_function_exists
|
1506
|
+
# built-ins
|
1507
|
+
assert_equal "true", evaluate("function-exists(lighten)")
|
1508
|
+
# with named argument
|
1509
|
+
assert_equal "true", evaluate("function-exists($name: lighten)")
|
1510
|
+
# user-defined
|
1511
|
+
assert_equal <<CSS, render(<<SCSS)
|
1512
|
+
.test {
|
1513
|
+
foo-exists: true;
|
1514
|
+
bar-exists: false; }
|
1515
|
+
CSS
|
1516
|
+
@function foo() { @return "foo" }
|
1517
|
+
.test {
|
1518
|
+
foo-exists: function-exists(foo);
|
1519
|
+
bar-exists: function-exists(bar);
|
1520
|
+
}
|
1521
|
+
SCSS
|
1522
|
+
end
|
1523
|
+
|
1524
|
+
def test_mixin_exists
|
1525
|
+
assert_equal "false", evaluate("mixin-exists(foo)")
|
1526
|
+
# with named argument
|
1527
|
+
assert_equal "false", evaluate("mixin-exists($name: foo)")
|
1528
|
+
assert_equal <<CSS, render(<<SCSS)
|
1529
|
+
.test {
|
1530
|
+
foo-exists: true;
|
1531
|
+
bar-exists: false; }
|
1532
|
+
CSS
|
1533
|
+
@mixin foo() { foo: exists }
|
1534
|
+
.test {
|
1535
|
+
foo-exists: mixin-exists(foo);
|
1536
|
+
bar-exists: mixin-exists(bar);
|
1537
|
+
}
|
1538
|
+
SCSS
|
1539
|
+
end
|
1540
|
+
|
1541
|
+
def test_existence_functions_check_argument_type
|
1542
|
+
assert_error_message("2px is not a string for `function-exists'", "function-exists(2px)")
|
1543
|
+
assert_error_message("2px is not a string for `mixin-exists'", "mixin-exists(2px)")
|
1544
|
+
assert_error_message("2px is not a string for `global-variable-exists'", "global-variable-exists(2px)")
|
1545
|
+
assert_error_message("2px is not a string for `variable-exists'", "variable-exists(2px)")
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
|
1453
1549
|
## Regression Tests
|
1454
1550
|
|
1455
1551
|
def test_saturation_bounds
|
@@ -1457,8 +1553,8 @@ WARNING
|
|
1457
1553
|
end
|
1458
1554
|
|
1459
1555
|
private
|
1460
|
-
def env(hash = {})
|
1461
|
-
env = Sass::Environment.new
|
1556
|
+
def env(hash = {}, parent = nil)
|
1557
|
+
env = Sass::Environment.new(parent)
|
1462
1558
|
hash.each {|k, v| env.set_var(k, v)}
|
1463
1559
|
env
|
1464
1560
|
end
|
@@ -1473,6 +1569,13 @@ WARNING
|
|
1473
1569
|
Sass::Script::Parser.parse(value, 0, 0).perform(environment)
|
1474
1570
|
end
|
1475
1571
|
|
1572
|
+
def render(sass, options = {})
|
1573
|
+
options[:syntax] ||= :scss
|
1574
|
+
munge_filename options
|
1575
|
+
options[:importer] ||= MockImporter.new
|
1576
|
+
Sass::Engine.new(sass, options).render
|
1577
|
+
end
|
1578
|
+
|
1476
1579
|
def assert_error_message(message, value)
|
1477
1580
|
evaluate(value)
|
1478
1581
|
flunk("Error message expected but not raised: #{message}")
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 592302549
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 3
|
9
9
|
- 0
|
10
10
|
- alpha
|
11
|
-
-
|
12
|
-
version: 3.3.0.alpha.
|
11
|
+
- 364
|
12
|
+
version: 3.3.0.alpha.364
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Nathan Weizenbaum
|
@@ -19,7 +19,7 @@ autorequire:
|
|
19
19
|
bindir: bin
|
20
20
|
cert_chain: []
|
21
21
|
|
22
|
-
date: 2013-10-
|
22
|
+
date: 2013-10-05 00:00:00 -04:00
|
23
23
|
default_executable:
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|