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 +1 -1
- data/VERSION +1 -1
- data/lib/sass/css.rb +0 -1
- data/lib/sass/engine.rb +2 -3
- data/lib/sass/script.rb +0 -1
- data/lib/sass/script/lexer.rb +1 -3
- data/lib/sass/scss/parser.rb +2 -3
- data/lib/sass/shared.rb +2 -4
- data/lib/sass/util.rb +2 -1
- data/lib/sass/util/multibyte_string_scanner.rb +134 -0
- data/test/sass/engine_test.rb +25 -0
- data/test/sass/util/multibyte_string_scanner_test.rb +145 -0
- metadata +7 -4
data/REVISION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
594a6d23b2e7b60d1b522c1c2575c9db8681e9f7
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.2.0.alpha.
|
1
|
+
3.2.0.alpha.54
|
data/lib/sass/css.rb
CHANGED
data/lib/sass/engine.rb
CHANGED
@@ -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 =
|
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 =
|
760
|
+
scanner = Sass::Util::MultibyteStringScanner.new(value)
|
762
761
|
values = []
|
763
762
|
|
764
763
|
loop do
|
data/lib/sass/script.rb
CHANGED
data/lib/sass/script/lexer.rb
CHANGED
@@ -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 :
|
127
|
+
@scanner = str.is_a?(StringScanner) ? str : Sass::Util::MultibyteStringScanner.new(str)
|
130
128
|
@line = line
|
131
129
|
@offset = offset
|
132
130
|
@options = options
|
data/lib/sass/scss/parser.rb
CHANGED
@@ -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
|
-
|
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 =
|
917
|
+
@scanner = Sass::Util::MultibyteStringScanner.new(@scanner.string)
|
919
918
|
@scanner.pos = err[:pos]
|
920
919
|
@line = err[:line]
|
921
920
|
@expected = err[:expected]
|
data/lib/sass/shared.rb
CHANGED
@@ -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 =
|
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 =
|
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
|
data/lib/sass/util.rb
CHANGED
@@ -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
|
data/test/sass/engine_test.rb
CHANGED
@@ -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:
|
4
|
+
hash: 592302961
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 2
|
9
9
|
- 0
|
10
10
|
- alpha
|
11
|
-
-
|
12
|
-
version: 3.2.0.alpha.
|
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-
|
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
|