sass 3.2.0.alpha.53 → 3.2.0.alpha.54

Sign up to get free protection for your applications and to get access to all the features.
data/REVISION CHANGED
@@ -1 +1 @@
1
- d73070e1f6966118f181117faaf9c4cdd6a7d2a0
1
+ 594a6d23b2e7b60d1b522c1c2575c9db8681e9f7
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.53
1
+ 3.2.0.alpha.54
@@ -1,7 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../sass'
2
2
  require 'sass/tree/node'
3
3
  require 'sass/scss/css_parser'
4
- require 'strscan'
5
4
 
6
5
  module Sass
7
6
  # This class converts CSS documents into Sass or SCSS templates.
@@ -1,4 +1,3 @@
1
- require 'strscan'
2
1
  require 'set'
3
2
  require 'digest/sha1'
4
3
  require 'sass/cache_stores'
@@ -570,7 +569,7 @@ WARNING
570
569
  end
571
570
 
572
571
  def parse_property_or_rule(line)
573
- scanner = StringScanner.new(line.text)
572
+ scanner = Sass::Util::MultibyteStringScanner.new(line.text)
574
573
  hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
575
574
  parser = Sass::SCSS::SassParser.new(scanner, @options[:filename], @line)
576
575
 
@@ -758,7 +757,7 @@ WARNING
758
757
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
759
758
  :line => @line + 1) unless line.children.empty?
760
759
 
761
- scanner = StringScanner.new(value)
760
+ scanner = Sass::Util::MultibyteStringScanner.new(value)
762
761
  values = []
763
762
 
764
763
  loop do
@@ -1,4 +1,3 @@
1
- require 'strscan'
2
1
  require 'sass/script/node'
3
2
  require 'sass/script/variable'
4
3
  require 'sass/script/funcall'
@@ -1,7 +1,5 @@
1
1
  require 'sass/scss/rx'
2
2
 
3
- require 'strscan'
4
-
5
3
  module Sass
6
4
  module Script
7
5
  # The lexical analyzer for SassScript.
@@ -126,7 +124,7 @@ module Sass
126
124
  # @param options [{Symbol => Object}] An options hash;
127
125
  # see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
128
126
  def initialize(str, line, offset, options)
129
- @scanner = str.is_a?(StringScanner) ? str : StringScanner.new(str)
127
+ @scanner = str.is_a?(StringScanner) ? str : Sass::Util::MultibyteStringScanner.new(str)
130
128
  @line = line
131
129
  @offset = offset
132
130
  @options = options
@@ -1,4 +1,3 @@
1
- require 'strscan'
2
1
  require 'set'
3
2
 
4
3
  module Sass
@@ -50,7 +49,7 @@ module Sass
50
49
  if @template.is_a?(StringScanner)
51
50
  @template
52
51
  else
53
- StringScanner.new(@template.gsub("\r", ""))
52
+ Sass::Util::MultibyteStringScanner.new(@template.gsub("\r", ""))
54
53
  end
55
54
  end
56
55
 
@@ -915,7 +914,7 @@ MESSAGE
915
914
  if @throw_err
916
915
  throw :_sass_parser_error, err
917
916
  else
918
- @scanner = StringScanner.new(@scanner.string)
917
+ @scanner = Sass::Util::MultibyteStringScanner.new(@scanner.string)
919
918
  @scanner.pos = err[:pos]
920
919
  @line = err[:line]
921
920
  @expected = err[:expected]
@@ -1,5 +1,3 @@
1
- require 'strscan'
2
-
3
1
  module Sass
4
2
  # This module contains functionality that's shared between Haml and Sass.
5
3
  module Shared
@@ -16,7 +14,7 @@ module Sass
16
14
  # @yieldparam scan [StringScanner] The scanner scanning through the string
17
15
  # @return [String] The text remaining in the scanner after all `#{`s have been processed
18
16
  def handle_interpolation(str)
19
- scan = StringScanner.new(str)
17
+ scan = Sass::Util::MultibyteStringScanner.new(str)
20
18
  yield scan while scan.scan(/(.*?)(\\*)\#\{/m)
21
19
  scan.rest
22
20
  end
@@ -40,7 +38,7 @@ module Sass
40
38
  # `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above.
41
39
  def balance(scanner, start, finish, count = 0)
42
40
  str = ''
43
- scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner
41
+ scanner = Sass::Util::MultibyteStringScanner.new(scanner) unless scanner.is_a? StringScanner
44
42
  regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
45
43
  while scanner.scan(regexp)
46
44
  str << scanner.matched
@@ -2,7 +2,6 @@ require 'erb'
2
2
  require 'set'
3
3
  require 'enumerator'
4
4
  require 'stringio'
5
- require 'strscan'
6
5
  require 'rbconfig'
7
6
 
8
7
  require 'sass/root'
@@ -719,3 +718,5 @@ MSG
719
718
  end
720
719
  end
721
720
  end
721
+
722
+ require 'sass/util/multibyte_string_scanner'
@@ -0,0 +1,134 @@
1
+ require 'strscan'
2
+
3
+ if Sass::Util.ruby1_8?
4
+ Sass::Util::MultibyteStringScanner = StringScanner
5
+ else
6
+ # A wrapper of the native StringScanner class that works correctly with
7
+ # multibyte character encodings. The native class deals only in bytes, not
8
+ # characters, for methods like [#pos] and [#matched_size]. This class deals
9
+ # only in characters, instead.
10
+ class Sass::Util::MultibyteStringScanner < StringScanner
11
+ def self.new(str)
12
+ return StringScanner.new(str) if str.ascii_only?
13
+ super
14
+ end
15
+
16
+ def initialize(str)
17
+ super
18
+ @mb_pos = 0
19
+ @mb_matched_size = nil
20
+ @mb_last_pos = nil
21
+ end
22
+
23
+ alias_method :byte_pos, :pos
24
+ alias_method :byte_matched_size, :matched_size
25
+
26
+ def check(pattern); _match super; end
27
+ def check_until(pattern); _matched super; end
28
+ def getch; _forward _match super; end
29
+ def match?(pattern); _size check(pattern); end
30
+ def matched_size; @mb_matched_size; end
31
+ def peek(len); string[@mb_pos, len]; end
32
+ alias_method :peep, :peek
33
+ def pos; @mb_pos; end
34
+ alias_method :pointer, :pos
35
+ def rest_size; rest.size; end
36
+ def scan(pattern); _forward _match super; end
37
+ def scan_until(pattern); _forward _matched super; end
38
+ def skip(pattern); _size scan(pattern); end
39
+ def skip_until(pattern); _matched _size scan_until(pattern); end
40
+
41
+ def get_byte
42
+ raise "MultibyteStringScanner doesn't support #get_byte."
43
+ end
44
+
45
+ def getbyte
46
+ raise "MultibyteStringScanner doesn't support #getbyte."
47
+ end
48
+
49
+ def pos=(n)
50
+ @mb_last_pos = nil
51
+
52
+ # We set position kind of a lot during parsing, so we want it to be as
53
+ # efficient as possible. This is complicated by the fact that UTF-8 is a
54
+ # variable-length encoding, so it's difficult to find the byte length that
55
+ # corresponds to a given character length.
56
+ #
57
+ # Our heuristic here is to try to count the fewest possible characters. So
58
+ # if the new position is close to the current one, just count the
59
+ # characters between the two; if the new position is closer to the
60
+ # beginning of the string, just count the characters from there.
61
+ if @mb_pos - n < @mb_pos / 2
62
+ # New position is close to old position
63
+ byte_delta = @mb_pos > n ? -string[n...@mb_pos].bytesize : string[@mb_pos...n].bytesize
64
+ super(byte_pos + byte_delta)
65
+ else
66
+ # New position is close to BOS
67
+ super(string[0...n].bytesize)
68
+ end
69
+ @mb_pos = n
70
+ end
71
+
72
+ def reset
73
+ @mb_pos = 0
74
+ @mb_matched_size = nil
75
+ @mb_last_pos = nil
76
+ super
77
+ end
78
+
79
+ def scan_full(pattern, advance_pointer_p, return_string_p)
80
+ res = _match super(pattern, advance_pointer_p, true)
81
+ _forward res if advance_pointer_p
82
+ return res if return_string_p
83
+ end
84
+
85
+ def search_full(pattern, advance_pointer_p, return_string_p)
86
+ res = super(pattern, advance_pointer_p, true)
87
+ _forward res if advance_pointer_p
88
+ _matched((res if return_string_p))
89
+ end
90
+
91
+ def string=(str)
92
+ @mb_pos = 0
93
+ @mb_matched_size = nil
94
+ @mb_last_pos = nil
95
+ super
96
+ end
97
+
98
+ def terminate
99
+ @mb_pos = string.size
100
+ @mb_matched_size = nil
101
+ @mb_last_pos = nil
102
+ super
103
+ end
104
+ alias_method :clear, :terminate
105
+
106
+ def unscan
107
+ super
108
+ @mb_pos = @mb_last_pos
109
+ @mb_last_pos = @mb_matched_size = nil
110
+ end
111
+
112
+ private
113
+
114
+ def _size(str)
115
+ str && str.size
116
+ end
117
+
118
+ def _match(str)
119
+ @mb_matched_size = str && str.size
120
+ str
121
+ end
122
+
123
+ def _matched(res)
124
+ _match matched
125
+ res
126
+ end
127
+
128
+ def _forward(str)
129
+ @mb_last_pos = @mb_pos
130
+ @mb_pos += str.size if str
131
+ str
132
+ end
133
+ end
134
+ end
@@ -2545,6 +2545,31 @@ CSS
2545
2545
  a: b
2546
2546
  SASS
2547
2547
  end
2548
+
2549
+ # Encoding Regression Test
2550
+
2551
+ def test_multibyte_prop_name
2552
+ assert_equal(<<CSS, render(<<SASS))
2553
+ @charset "UTF-8";
2554
+ #bar {
2555
+ cölor: blue; }
2556
+ CSS
2557
+ #bar
2558
+ cölor: blue
2559
+ SASS
2560
+ end
2561
+
2562
+ def test_multibyte_and_interpolation
2563
+ assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
2564
+ #bar {
2565
+ background: a 0%; }
2566
+ CSS
2567
+ #bar {
2568
+ // 
2569
+ background: \#{a} 0%;
2570
+ }
2571
+ SCSS
2572
+ end
2548
2573
  end
2549
2574
 
2550
2575
  def test_original_filename_set
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/../../test_helper'
4
+
5
+ class MultibyteStringScannerTest < Test::Unit::TestCase
6
+ def setup
7
+ @scanner = Sass::Util::MultibyteStringScanner.new("cölorfül")
8
+ end
9
+
10
+ def test_initial
11
+ assert_scanner_state 0, 0, nil, nil
12
+ end
13
+
14
+ def test_check
15
+ assert_equal 'cö', @scanner.check(/../)
16
+ assert_scanner_state 0, 0, 2, 3
17
+ assert_equal 0, @scanner.pos
18
+ assert_equal 0, @scanner.pos
19
+ assert_equal 2, @scanner.matched_size
20
+ assert_equal 3, @scanner.byte_matched_size
21
+ end
22
+
23
+ def test_check_until
24
+ assert_equal 'cölorfü', @scanner.check_until(/f./)
25
+ assert_scanner_state 0, 0, 2, 3
26
+ end
27
+
28
+ def test_getch
29
+ assert_equal 'c', @scanner.getch
30
+ assert_equal 'ö', @scanner.getch
31
+ assert_scanner_state 2, 3, 1, 2
32
+ end
33
+
34
+ def test_match?
35
+ assert_equal 2, @scanner.match?(/../)
36
+ assert_scanner_state 0, 0, 2, 3
37
+ end
38
+
39
+ def test_peek
40
+ assert_equal 'cö', @scanner.peek(2)
41
+ assert_scanner_state 0, 0, nil, nil
42
+ end
43
+
44
+ def test_rest_size
45
+ assert_equal 'cö', @scanner.scan(/../)
46
+ assert_equal 6, @scanner.rest_size
47
+ end
48
+
49
+ def test_scan
50
+ assert_equal 'cö', @scanner.scan(/../)
51
+ assert_scanner_state 2, 3, 2, 3
52
+ end
53
+
54
+ def test_scan_until
55
+ assert_equal 'cölorfü', @scanner.scan_until(/f./)
56
+ assert_scanner_state 7, 9, 2, 3
57
+ end
58
+
59
+ def test_skip
60
+ assert_equal 2, @scanner.skip(/../)
61
+ assert_scanner_state 2, 3, 2, 3
62
+ end
63
+
64
+ def test_skip_until
65
+ assert_equal 7, @scanner.skip_until(/f./)
66
+ assert_scanner_state 7, 9, 2, 3
67
+ end
68
+
69
+ def test_set_pos
70
+ @scanner.pos = 7
71
+ assert_scanner_state 7, 9, nil, nil
72
+ @scanner.pos = 6
73
+ assert_scanner_state 6, 7, nil, nil
74
+ @scanner.pos = 1
75
+ assert_scanner_state 1, 1, nil, nil
76
+ end
77
+
78
+ def test_reset
79
+ @scanner.scan(/../)
80
+ @scanner.reset
81
+ assert_scanner_state 0, 0, nil, nil
82
+ end
83
+
84
+ def test_scan_full
85
+ assert_equal 'cö', @scanner.scan_full(/../, true, true)
86
+ assert_scanner_state 2, 3, 2, 3
87
+
88
+ @scanner.reset
89
+ assert_equal 'cö', @scanner.scan_full(/../, false, true)
90
+ assert_scanner_state 0, 0, 2, 3
91
+
92
+ @scanner.reset
93
+ assert_nil @scanner.scan_full(/../, true, false)
94
+ assert_scanner_state 2, 3, 2, 3
95
+
96
+ @scanner.reset
97
+ assert_nil @scanner.scan_full(/../, false, false)
98
+ assert_scanner_state 0, 0, 2, 3
99
+ end
100
+
101
+ def test_search_full
102
+ assert_equal 'cölorfü', @scanner.search_full(/f./, true, true)
103
+ assert_scanner_state 7, 9, 2, 3
104
+
105
+ @scanner.reset
106
+ assert_equal 'cölorfü', @scanner.search_full(/f./, false, true)
107
+ assert_scanner_state 0, 0, 2, 3
108
+
109
+ @scanner.reset
110
+ assert_nil @scanner.search_full(/f./, true, false)
111
+ assert_scanner_state 7, 9, 2, 3
112
+
113
+ @scanner.reset
114
+ assert_nil @scanner.search_full(/f./, false, false)
115
+ assert_scanner_state 0, 0, 2, 3
116
+ end
117
+
118
+ def test_set_string
119
+ @scanner.scan(/../)
120
+ @scanner.string = 'föóbâr'
121
+ assert_scanner_state 0, 0, nil, nil
122
+ end
123
+
124
+ def test_terminate
125
+ @scanner.scan(/../)
126
+ @scanner.terminate
127
+ assert_scanner_state 8, 10, nil, nil
128
+ end
129
+
130
+ def test_unscan
131
+ @scanner.scan(/../)
132
+ @scanner.scan_until(/f./)
133
+ @scanner.unscan
134
+ assert_scanner_state 2, 3, nil, nil
135
+ end
136
+
137
+ private
138
+
139
+ def assert_scanner_state(pos, byte_pos, matched_size, byte_matched_size)
140
+ assert_equal pos, @scanner.pos, 'pos'
141
+ assert_equal byte_pos, @scanner.byte_pos, 'byte_pos'
142
+ assert_equal matched_size, @scanner.matched_size, 'matched_size'
143
+ assert_equal byte_matched_size, @scanner.byte_matched_size, 'byte_matched_size'
144
+ end
145
+ 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: 592302967
4
+ hash: 592302961
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
9
  - 0
10
10
  - alpha
11
- - 53
12
- version: 3.2.0.alpha.53
11
+ - 54
12
+ version: 3.2.0.alpha.54
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: 2012-01-04 00:00:00 -05:00
22
+ date: 2012-01-05 00:00:00 -05:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -164,6 +164,7 @@ files:
164
164
  - lib/sass/tree/while_node.rb
165
165
  - lib/sass/util.rb
166
166
  - lib/sass/util/subset_map.rb
167
+ - lib/sass/util/multibyte_string_scanner.rb
167
168
  - lib/sass/version.rb
168
169
  - vendor/fssm/Gemfile
169
170
  - vendor/fssm/LICENSE
@@ -306,6 +307,7 @@ files:
306
307
  - test/sass/templates/warn_imported.sass
307
308
  - test/sass/test_helper.rb
308
309
  - test/sass/util/subset_map_test.rb
310
+ - test/sass/util/multibyte_string_scanner_test.rb
309
311
  - test/sass/util_test.rb
310
312
  - test/test_helper.rb
311
313
  - extra/update_watch.rb
@@ -374,4 +376,5 @@ test_files:
374
376
  - test/sass/scss/rx_test.rb
375
377
  - test/sass/scss/scss_test.rb
376
378
  - test/sass/util/subset_map_test.rb
379
+ - test/sass/util/multibyte_string_scanner_test.rb
377
380
  - test/sass/util_test.rb