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 CHANGED
@@ -1 +1 @@
1
- 77ed5f71b755020c48ab0243b667a064b0510efb
1
+ 4e515ab6a46507013fcbe426a5ecfa061b4ae571
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.0.alpha.354
1
+ 3.3.0.alpha.364
data/VERSION_DATE CHANGED
@@ -1 +1 @@
1
- 05 October 2013 01:29:09 GMT
1
+ 05 October 2013 16:04:57 GMT
@@ -1,28 +1,80 @@
1
1
  require 'set'
2
2
 
3
3
  module Sass
4
- # The lexical environment for SassScript.
5
- # This keeps track of variable, mixin, and function definitions.
6
- #
7
- # A new environment is created for each level of Sass nesting.
8
- # This allows variables to be lexically scoped.
9
- # The new environment refers to the environment in the upper scope,
10
- # so it has access to variables defined in enclosing scopes,
11
- # but new variables are defined locally.
12
- #
13
- # Environment also keeps track of the {Engine} options
14
- # so that they can be made available to {Sass::Script::Functions}.
15
- class Environment
16
- # The enclosing environment,
17
- # or nil if this is the global environment.
18
- #
19
- # @return [Environment]
20
- attr_reader :parent
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 environmnet. This is naturally only set
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
- private
75
-
76
- class << self
77
-
78
- private
79
-
80
- UNDERSCORE, DASH = '_', '-'
81
-
82
- # Note: when updating this,
83
- # update sass/yard/inherited_hash.rb as well.
84
- def inherited_hash(name)
85
- class_eval <<RUBY, __FILE__, __LINE__ + 1
86
- def #{name}(name)
87
- _#{name}(name.tr(UNDERSCORE, DASH))
88
- end
89
-
90
- def _#{name}(name)
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
- inherited_hash :var
147
+ inherited_hash_writer :var
148
+
124
149
  # mixin
125
150
  # Sass::Callable
126
- inherited_hash :mixin
151
+ inherited_hash_writer :mixin
152
+
127
153
  # function
128
154
  # Sass::Callable
129
- inherited_hash :function
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
@@ -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: 592302537
4
+ hash: 592302549
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 3
9
9
  - 0
10
10
  - alpha
11
- - 354
12
- version: 3.3.0.alpha.354
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-04 00:00:00 -04:00
22
+ date: 2013-10-05 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency