sass 3.3.0.alpha.218 → 3.3.0.alpha.222

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
- 85f7ca624f2fb7d19320e107d518d3376952bf16
1
+ 0ef77dc0e3cff821aadca09aca98cac46354093d
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.0.alpha.218
1
+ 3.3.0.alpha.222
data/VERSION_DATE CHANGED
@@ -1 +1 @@
1
- 27 July 2013 01:12:19 GMT
1
+ 30 July 2013 17:39:38 GMT
@@ -88,7 +88,7 @@ module Sass
88
88
  def parse_mixin_include_arglist
89
89
  args, keywords = [], {}
90
90
  if try_tok(:lparen)
91
- args, keywords, splat = mixin_arglist || [[], {}]
91
+ args, keywords, splat = mixin_arglist
92
92
  assert_tok(:rparen)
93
93
  end
94
94
  assert_done
@@ -343,7 +343,7 @@ RUBY
343
343
 
344
344
  def funcall
345
345
  return raw unless tok = try_tok(:funcall)
346
- args, keywords, splat = fn_arglist || [[], {}]
346
+ args, keywords, splat = fn_arglist
347
347
  assert_tok(:rparen)
348
348
  node(Script::Tree::Funcall.new(tok.value, args, keywords, splat),
349
349
  tok.source_range.start_pos, source_position)
@@ -388,10 +388,11 @@ RUBY
388
388
  end
389
389
 
390
390
  def arglist(subexpr, description)
391
- return unless e = send(subexpr)
392
-
393
391
  args = []
394
- keywords = {}
392
+ keywords = Sass::Util::NormalizedMap.new
393
+
394
+ return [args, keywords] unless e = send(subexpr)
395
+
395
396
  loop do
396
397
  if @lexer.peek && @lexer.peek.type == :colon
397
398
  name = e
@@ -399,11 +400,11 @@ RUBY
399
400
  assert_tok(:colon)
400
401
  value = assert_expr(subexpr, description)
401
402
 
402
- if keywords[name.underscored_name]
403
+ if keywords[name.name]
403
404
  raise SyntaxError.new("Keyword argument \"#{name.to_sass}\" passed more than once")
404
405
  end
405
406
 
406
- keywords[name.underscored_name] = value
407
+ keywords[name.name] = value
407
408
  else
408
409
  if !keywords.empty?
409
410
  raise SyntaxError.new("Positional arguments must come before keyword arguments.")
@@ -419,7 +420,6 @@ RUBY
419
420
  end
420
421
 
421
422
  def raw
422
- start_pos = source_position
423
423
  return special_fun unless tok = try_tok(:raw)
424
424
  literal_node(Script::Value::String.new(tok.value), tok.source_range)
425
425
  end
@@ -1,4 +1,5 @@
1
1
  require 'sass/script/functions'
2
+ require 'sass/util/normalized_map'
2
3
 
3
4
  module Sass::Script::Tree
4
5
  # A SassScript parse node representing a function call.
@@ -29,8 +30,8 @@ module Sass::Script::Tree
29
30
 
30
31
  # @param name [String] See \{#name}
31
32
  # @param args [Array<Node>] See \{#args}
33
+ # @param keywords [Sass::Util::NormalizedMap<Node>] See \{#keywords}
32
34
  # @param splat [Node] See \{#splat}
33
- # @param keywords [{String => Node}] See \{#keywords}
34
35
  def initialize(name, args, keywords, splat)
35
36
  @name = name
36
37
  @args = args
@@ -42,7 +43,7 @@ module Sass::Script::Tree
42
43
  # @return [String] A string representation of the function call
43
44
  def inspect
44
45
  args = @args.map {|a| a.inspect}.join(', ')
45
- keywords = Sass::Util.hash_to_a(@keywords).
46
+ keywords = Sass::Util.hash_to_a(@keywords.as_stored).
46
47
  map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
47
48
  if self.splat
48
49
  splat = (args.empty? && keywords.empty?) ? "" : ", "
@@ -60,7 +61,7 @@ module Sass::Script::Tree
60
61
  end
61
62
 
62
63
  args = @args.map(&arg_to_sass).join(', ')
63
- keywords = Sass::Util.hash_to_a(@keywords).
64
+ keywords = Sass::Util.hash_to_a(@keywords.as_stored).
64
65
  map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}.join(', ')
65
66
  if self.splat
66
67
  splat = (args.empty? && keywords.empty?) ? "" : ", "
@@ -83,7 +84,9 @@ module Sass::Script::Tree
83
84
  def deep_copy
84
85
  node = dup
85
86
  node.instance_variable_set('@args', args.map {|a| a.deep_copy})
86
- node.instance_variable_set('@keywords', Hash[keywords.map {|k, v| [k, v.deep_copy]}])
87
+ copied_keywords = Sass::Util::NormalizedMap.new
88
+ @keywords.as_stored.each {|k,v| copied_keywords[k] = v.deep_copy}
89
+ node.instance_variable_set('@keywords', copied_keywords)
87
90
  node
88
91
  end
89
92
 
data/lib/sass/util.rb CHANGED
@@ -30,6 +30,36 @@ module Sass
30
30
  File.join(Sass::ROOT_DIR, file)
31
31
  end
32
32
 
33
+ # Converts a hash or a list of pairs into an order-preserving hash.
34
+ #
35
+ # On Ruby 1.8.7, this uses the orderedhash gem to simulate an
36
+ # order-preserving hash. On Ruby 1.9 and up, it just uses the native Hash
37
+ # class, since that preserves the order itself.
38
+ #
39
+ # @overload ordered_hash(hash)
40
+ # @param hash [Hash] a normal hash to convert to an ordered hash
41
+ # @return [Hash]
42
+ # @overload ordered_hash(*pairs)
43
+ # @example
44
+ # ordered_hash([:foo, "bar"], [:baz, "bang"])
45
+ # #=> {:foo => "bar", :baz => "bang"}
46
+ # ordered_hash #=> {}
47
+ # @param pairs [Array<(Object, Object)>] the list of key/value pairs for
48
+ # the hash.
49
+ # @return [Hash]
50
+ def ordered_hash(*pairs_or_hash)
51
+ require 'sass/util/ordered_hash' if ruby1_8?
52
+
53
+ if pairs_or_hash.length == 1 && pairs_or_hash.first.is_a?(Hash)
54
+ hash = pairs_or_hash.first
55
+ return hash unless ruby1_8?
56
+ return OrderedHash.new.merge hash
57
+ end
58
+
59
+ return Hash[pairs_or_hash] unless ruby1_8?
60
+ return OrderedHash[*flatten(pairs_or_hash, 1)]
61
+ end
62
+
33
63
  # Converts an array of `[key, value]` pairs to a hash.
34
64
  #
35
65
  # @example
@@ -38,7 +68,7 @@ module Sass
38
68
  # @param arr [Array<(Object, Object)>] An array of pairs
39
69
  # @return [Hash] A hash
40
70
  def to_hash(arr)
41
- Hash[arr.compact]
71
+ ordered_hash(*arr.compact)
42
72
  end
43
73
 
44
74
  # Maps the keys in a hash according to a block.
@@ -1008,3 +1038,4 @@ MSG
1008
1038
  end
1009
1039
 
1010
1040
  require 'sass/util/multibyte_string_scanner'
1041
+ require 'sass/util/normalized_map'
@@ -0,0 +1,65 @@
1
+ require 'delegate'
2
+ require 'sass/util'
3
+
4
+ module Sass
5
+ module Util
6
+ # A hash that normalizes its string keys while still allowing you to get back
7
+ # to the original keys that were stored. If several different values normalize
8
+ # to the same value, whichever is stored last wins.
9
+ require 'sass/util/ordered_hash' if ruby1_8?
10
+ class NormalizedMap < DelegateClass(ruby1_8? ? OrderedHash : Hash)
11
+ # Create a normalized map
12
+ def initialize
13
+ @key_strings = {}
14
+ @map = Util.ruby1_8? ? OrderedHash.new : {}
15
+
16
+ # We delegate all hash methods that are not overridden here to @map.
17
+ super(@map)
18
+ end
19
+
20
+ # Specifies how to transform the key.
21
+ #
22
+ # This can be overridden to create other normalization behaviors.
23
+ def normalize(key)
24
+ key.tr("-", "_")
25
+ end
26
+
27
+ # @private
28
+ def []=(k, v)
29
+ normalized = normalize(k)
30
+ super(normalized, v)
31
+ @key_strings[normalized] = k
32
+ end
33
+
34
+ # @private
35
+ def [](k)
36
+ super(normalize(k))
37
+ end
38
+
39
+ # @private
40
+ def has_key?(k)
41
+ super(normalize(k))
42
+ end
43
+
44
+ # @private
45
+ def delete(k)
46
+ normalized = normalize(k)
47
+ @key_strings.delete(normalized)
48
+ super(normalized)
49
+ end
50
+
51
+ # @return [Hash] Hash with the keys as they were stored (before normalization).
52
+ def as_stored
53
+ Sass::Util.map_keys(@map) {|k| @key_strings[k]}
54
+ end
55
+
56
+ # this is magically invoked by ruby, not sure why DelegateClass doesn't take care of it.
57
+ # @private
58
+ def initialize_dup(other)
59
+ super
60
+ @map = other.instance_variable_get("@map").dup
61
+ __setobj__(@map)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,186 @@
1
+ # Copyright (c) 2005-2013 David Heinemeier Hansson
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # This class was copied from an old version of ActiveSupport.
23
+ class OrderedHash < ::Hash
24
+ # In MRI the Hash class is core and written in C. In particular, methods are
25
+ # programmed with explicit C function calls and polymorphism is not honored.
26
+ #
27
+ # For example, []= is crucial in this implementation to maintain the @keys
28
+ # array but hash.c invokes rb_hash_aset() originally. This prevents method
29
+ # reuse through inheritance and forces us to reimplement stuff.
30
+ #
31
+ # For instance, we cannot use the inherited #merge! because albeit the algorithm
32
+ # itself would work, our []= is not being called at all by the C code.
33
+
34
+ def initialize(*args, &block)
35
+ super
36
+ @keys = []
37
+ end
38
+
39
+ def self.[](*args)
40
+ ordered_hash = new
41
+
42
+ if (args.length == 1 && args.first.is_a?(Array))
43
+ args.first.each do |key_value_pair|
44
+ next unless (key_value_pair.is_a?(Array))
45
+ ordered_hash[key_value_pair[0]] = key_value_pair[1]
46
+ end
47
+
48
+ return ordered_hash
49
+ end
50
+
51
+ unless (args.size % 2 == 0)
52
+ raise ArgumentError.new("odd number of arguments for Hash")
53
+ end
54
+
55
+ args.each_with_index do |val, ind|
56
+ next if (ind % 2 != 0)
57
+ ordered_hash[val] = args[ind + 1]
58
+ end
59
+
60
+ ordered_hash
61
+ end
62
+
63
+ def initialize_copy(other)
64
+ super
65
+ # make a deep copy of keys
66
+ @keys = other.keys
67
+ end
68
+
69
+ def []=(key, value)
70
+ @keys << key unless has_key?(key)
71
+ super
72
+ end
73
+
74
+ def delete(key)
75
+ if has_key? key
76
+ index = @keys.index(key)
77
+ @keys.delete_at index
78
+ end
79
+ super
80
+ end
81
+
82
+ def delete_if
83
+ super
84
+ sync_keys!
85
+ self
86
+ end
87
+
88
+ def reject!
89
+ super
90
+ sync_keys!
91
+ self
92
+ end
93
+
94
+ def reject(&block)
95
+ dup.reject!(&block)
96
+ end
97
+
98
+ def keys
99
+ @keys.dup
100
+ end
101
+
102
+ def values
103
+ @keys.collect { |key| self[key] }
104
+ end
105
+
106
+ def to_hash
107
+ self
108
+ end
109
+
110
+ def to_a
111
+ @keys.map { |key| [ key, self[key] ] }
112
+ end
113
+
114
+ def each_key
115
+ return to_enum(:each_key) unless block_given?
116
+ @keys.each { |key| yield key }
117
+ self
118
+ end
119
+
120
+ def each_value
121
+ return to_enum(:each_value) unless block_given?
122
+ @keys.each { |key| yield self[key]}
123
+ self
124
+ end
125
+
126
+ def each
127
+ return to_enum(:each) unless block_given?
128
+ @keys.each {|key| yield [key, self[key]]}
129
+ self
130
+ end
131
+
132
+ def each_pair
133
+ return to_enum(:each_pair) unless block_given?
134
+ @keys.each {|key| yield key, self[key]}
135
+ self
136
+ end
137
+
138
+ alias_method :select, :find_all
139
+
140
+ def clear
141
+ super
142
+ @keys.clear
143
+ self
144
+ end
145
+
146
+ def shift
147
+ k = @keys.first
148
+ v = delete(k)
149
+ [k, v]
150
+ end
151
+
152
+ def merge!(other_hash)
153
+ if block_given?
154
+ other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
155
+ else
156
+ other_hash.each { |k, v| self[k] = v }
157
+ end
158
+ self
159
+ end
160
+
161
+ alias_method :update, :merge!
162
+
163
+ def merge(other_hash, &block)
164
+ dup.merge!(other_hash, &block)
165
+ end
166
+
167
+ # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
168
+ def replace(other)
169
+ super
170
+ @keys = other.keys
171
+ self
172
+ end
173
+
174
+ def invert
175
+ OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
176
+ end
177
+
178
+ def inspect
179
+ "#<OrderedHash #{super}>"
180
+ end
181
+
182
+ private
183
+ def sync_keys!
184
+ @keys.delete_if {|k| !has_key?(k)}
185
+ end
186
+ end
@@ -1714,6 +1714,34 @@ foo {
1714
1714
  SCSS
1715
1715
  end
1716
1716
 
1717
+ def test_keyword_arguments
1718
+ assert_renders(<<SASS, <<SCSS, :dasherize => true)
1719
+ $foo: foo($dash-ed: 2px)
1720
+ SASS
1721
+ $foo: foo($dash-ed: 2px);
1722
+ SCSS
1723
+ assert_scss_to_sass(<<SASS, <<SCSS, :dasherize => true)
1724
+ $foo: foo($dash-ed: 2px)
1725
+ SASS
1726
+ $foo: foo($dash_ed: 2px);
1727
+ SCSS
1728
+ assert_sass_to_scss(<<SCSS, <<SASS, :dasherize => true)
1729
+ $foo: foo($dash-ed: 2px);
1730
+ SCSS
1731
+ $foo: foo($dash_ed: 2px)
1732
+ SASS
1733
+ assert_renders(<<SASS, <<SCSS)
1734
+ $foo: foo($under_scored: 1px)
1735
+ SASS
1736
+ $foo: foo($under_scored: 1px);
1737
+ SCSS
1738
+ assert_renders(<<SASS, <<SCSS)
1739
+ $foo: foo($dash-ed: 2px, $under_scored: 1px)
1740
+ SASS
1741
+ $foo: foo($dash-ed: 2px, $under_scored: 1px);
1742
+ SCSS
1743
+ end
1744
+
1717
1745
  private
1718
1746
 
1719
1747
  def assert_sass_to_sass(sass, options = {})
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../../test_helper'
3
+ require 'sass/util/normalized_map'
4
+
5
+ class NormalizedMapTest < Test::Unit::TestCase
6
+ def test_basic_lifecycle
7
+ m = Sass::Util::NormalizedMap.new
8
+ m["a-b"] = 1
9
+ assert_equal ["a_b"], m.keys
10
+ assert_equal 1, m["a_b"]
11
+ assert_equal 1, m["a-b"]
12
+ assert m.has_key?("a_b")
13
+ assert m.has_key?("a-b")
14
+ assert_equal({"a-b" => 1}, m.as_stored)
15
+ assert_equal 1, m.delete("a-b")
16
+ assert !m.has_key?("a-b")
17
+ m["a_b"] = 2
18
+ assert_equal({"a_b" => 2}, m.as_stored)
19
+ end
20
+
21
+ def test_dup
22
+ m = Sass::Util::NormalizedMap.new
23
+ m["a-b"] = 1
24
+ m2 = m.dup
25
+ m.delete("a-b")
26
+ assert !m.has_key?("a-b")
27
+ assert m2.has_key?("a-b")
28
+ end
29
+
30
+ end
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: 592302777
4
+ hash: 592302769
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 3
9
9
  - 0
10
10
  - alpha
11
- - 218
12
- version: 3.3.0.alpha.218
11
+ - 222
12
+ version: 3.3.0.alpha.222
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-07-26 00:00:00 -04:00
22
+ date: 2013-07-30 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -195,6 +195,8 @@ files:
195
195
  - lib/sass/util/multibyte_string_scanner.rb
196
196
  - lib/sass/util/subset_map.rb
197
197
  - lib/sass/util/test.rb
198
+ - lib/sass/util/normalized_map.rb
199
+ - lib/sass/util/ordered_hash.rb
198
200
  - lib/sass/version.rb
199
201
  - lib/sass/features.rb
200
202
  - bin/sass
@@ -317,6 +319,7 @@ files:
317
319
  - test/sass/test_helper.rb
318
320
  - test/sass/util/multibyte_string_scanner_test.rb
319
321
  - test/sass/util/subset_map_test.rb
322
+ - test/sass/util/normalized_map_test.rb
320
323
  - test/sass/source_map_test.rb
321
324
  - test/test_helper.rb
322
325
  - extra/update_watch.rb
@@ -389,4 +392,5 @@ test_files:
389
392
  - test/sass/compiler_test.rb
390
393
  - test/sass/util/multibyte_string_scanner_test.rb
391
394
  - test/sass/util/subset_map_test.rb
395
+ - test/sass/util/normalized_map_test.rb
392
396
  - test/sass/source_map_test.rb