css_parser 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/css_parser/parser.rb +63 -26
- data/lib/css_parser.rb +3 -1
- data/test/test_css_parser_loading.rb +18 -4
- data/test/test_css_parser_misc.rb +0 -1
- metadata +4 -4
data/lib/css_parser/parser.rb
CHANGED
@@ -23,11 +23,7 @@ module CssParser
|
|
23
23
|
# Initial parsing
|
24
24
|
RE_AT_IMPORT_RULE = /\@import\s*(?:url\s*)?(?:\()?(?:\s*)["']?([^'"\s\)]*)["']?\)?([\w\s\,^\])]*)\)?[;\n]?/
|
25
25
|
|
26
|
-
|
27
|
-
# RE_AT_IMPORT_RULE = Regexp.new('@import[\s]*(' + RE_STRING.to_s + ')([\w\s\,]*)[;]?', Regexp::IGNORECASE) -- should handle url() even though it is not allowed
|
28
|
-
#++
|
29
|
-
|
30
|
-
# Array of CSS files that have been loaded.
|
26
|
+
# Array of CSS files that have been loaded.
|
31
27
|
attr_reader :loaded_uris
|
32
28
|
|
33
29
|
#attr_reader :rules
|
@@ -199,7 +195,7 @@ module CssParser
|
|
199
195
|
options = {:media_types => :all}.merge(options)
|
200
196
|
media_types = options[:media_types]
|
201
197
|
|
202
|
-
in_declarations =
|
198
|
+
in_declarations = 0
|
203
199
|
|
204
200
|
block_depth = 0
|
205
201
|
|
@@ -219,13 +215,25 @@ module CssParser
|
|
219
215
|
in_string = !in_string
|
220
216
|
end
|
221
217
|
|
222
|
-
if in_declarations
|
218
|
+
if in_declarations > 0
|
219
|
+
|
220
|
+
# too deep, malformed declaration block
|
221
|
+
if in_declarations > 1
|
222
|
+
in_declarations -= 1 if token =~ /\}/
|
223
|
+
next
|
224
|
+
end
|
225
|
+
|
226
|
+
if token =~ /\{/
|
227
|
+
in_declarations += 1
|
228
|
+
next
|
229
|
+
end
|
230
|
+
|
223
231
|
current_declarations += token
|
224
232
|
|
225
233
|
if token =~ /\}/ and not in_string
|
226
234
|
current_declarations.gsub!(/\}[\s]*$/, '')
|
227
235
|
|
228
|
-
in_declarations
|
236
|
+
in_declarations -= 1
|
229
237
|
|
230
238
|
unless current_declarations.strip.empty?
|
231
239
|
#puts "SAVING #{current_selectors} -> #{current_declarations}"
|
@@ -257,7 +265,7 @@ module CssParser
|
|
257
265
|
if token =~ /\{/ and not in_string
|
258
266
|
current_selectors.gsub!(/^[\s]*/, '')
|
259
267
|
current_selectors.gsub!(/[\s]*$/, '')
|
260
|
-
in_declarations
|
268
|
+
in_declarations += 1
|
261
269
|
else
|
262
270
|
current_selectors += token
|
263
271
|
end
|
@@ -267,13 +275,18 @@ module CssParser
|
|
267
275
|
end
|
268
276
|
|
269
277
|
# Load a remote CSS file.
|
278
|
+
#
|
279
|
+
# You can also pass in file://test.css
|
270
280
|
def load_uri!(uri, base_uri = nil, media_types = :all)
|
281
|
+
uri = URI.parse(uri) unless uri.respond_to? :scheme
|
282
|
+
if uri.scheme == 'file' or uri.scheme.nil?
|
283
|
+
uri.path = File.expand_path(uri.path)
|
284
|
+
uri.scheme = 'file'
|
285
|
+
end
|
271
286
|
base_uri = uri if base_uri.nil?
|
272
287
|
|
273
288
|
src, charset = read_remote_file(uri)
|
274
|
-
|
275
|
-
add_block!(src, {:media_types => media_types, :base_uri => base_uri})
|
276
|
-
end
|
289
|
+
add_block!(src, {:media_types => media_types, :base_uri => base_uri})
|
277
290
|
end
|
278
291
|
|
279
292
|
# Load a local CSS file.
|
@@ -321,27 +334,51 @@ module CssParser
|
|
321
334
|
|
322
335
|
@loaded_uris << uri.to_s
|
323
336
|
|
324
|
-
|
325
|
-
#fh = open(uri, 'rb')
|
326
|
-
fh = open(uri, 'rb', 'User-Agent' => USER_AGENT, 'Accept-Encoding' => 'gzip')
|
337
|
+
src = '', charset = nil
|
327
338
|
|
328
|
-
|
329
|
-
|
339
|
+
begin
|
340
|
+
uri = URI.parse(uri.to_s)
|
341
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
342
|
+
|
343
|
+
if uri.scheme == 'file'
|
344
|
+
# local file
|
345
|
+
fh = open(uri.path, 'rb')
|
346
|
+
src = fh.read
|
347
|
+
fh.close
|
330
348
|
else
|
331
|
-
|
332
|
-
|
349
|
+
# remote file
|
350
|
+
if uri.scheme == 'https'
|
351
|
+
http.use_ssl = true
|
352
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
353
|
+
end
|
333
354
|
|
334
|
-
|
355
|
+
res, src = http.get(uri.path, {'User-Agent' => USER_AGENT, 'Accept-Encoding' => 'gzip'})
|
356
|
+
charset = fh.respond_to?(:charset) ? fh.charset : 'utf-8'
|
335
357
|
|
336
|
-
|
337
|
-
|
358
|
+
if res.code.to_i >= 400
|
359
|
+
raise RemoteFileError if @options[:io_exceptions]
|
360
|
+
return '', nil
|
361
|
+
end
|
338
362
|
|
339
|
-
|
340
|
-
|
341
|
-
|
363
|
+
case res['content-encoding']
|
364
|
+
when 'gzip'
|
365
|
+
io = Zlib::GzipReader.new(StringIO.new(res.body))
|
366
|
+
src = io.read
|
367
|
+
when 'deflate'
|
368
|
+
io = Zlib::Inflate.new
|
369
|
+
src = io.inflate(res.body)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
if charset
|
374
|
+
ic = Iconv.new('UTF-8//IGNORE', charset)
|
375
|
+
src = ic.iconv(src)
|
376
|
+
end
|
377
|
+
rescue
|
342
378
|
raise RemoteFileError if @options[:io_exceptions]
|
343
|
-
return '', nil
|
344
379
|
end
|
380
|
+
|
381
|
+
return src, charset
|
345
382
|
end
|
346
383
|
|
347
384
|
private
|
data/lib/css_parser.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'net/https'
|
2
3
|
require 'open-uri'
|
3
4
|
require 'digest/md5'
|
4
5
|
require 'zlib'
|
6
|
+
require 'stringio'
|
5
7
|
require 'iconv'
|
6
8
|
|
7
9
|
module CssParser
|
8
|
-
VERSION = '1.1.
|
10
|
+
VERSION = '1.1.2'
|
9
11
|
|
10
12
|
# Merge multiple CSS RuleSets by cascading according to the CSS 2.1 cascading rules
|
11
13
|
# (http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order).
|
@@ -11,10 +11,10 @@ class CssParserLoadingTests < Test::Unit::TestCase
|
|
11
11
|
|
12
12
|
@uri_base = 'http://localhost:12000'
|
13
13
|
|
14
|
-
www_root = File.dirname(__FILE__) + '/fixtures/'
|
14
|
+
@www_root = File.dirname(__FILE__) + '/fixtures/'
|
15
15
|
|
16
16
|
@server_thread = Thread.new do
|
17
|
-
s = WEBrick::HTTPServer.new(:Port => 12000, :DocumentRoot => www_root, :Logger => Log.new(nil, BasicLog::FATAL), :AccessLog => [])
|
17
|
+
s = WEBrick::HTTPServer.new(:Port => 12000, :DocumentRoot => @www_root, :Logger => Log.new(nil, BasicLog::FATAL), :AccessLog => [])
|
18
18
|
@port = s.config[:Port]
|
19
19
|
begin
|
20
20
|
s.start
|
@@ -25,24 +25,38 @@ class CssParserLoadingTests < Test::Unit::TestCase
|
|
25
25
|
|
26
26
|
sleep 1 # ensure the server has time to load
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def teardown
|
30
30
|
@server_thread.kill
|
31
31
|
@server_thread.join(5)
|
32
32
|
@server_thread = nil
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def test_loading_a_local_file
|
36
36
|
file_name = File.dirname(__FILE__) + '/fixtures/simple.css'
|
37
37
|
@cp.load_file!(file_name)
|
38
38
|
assert_equal 'margin: 0px;', @cp.find_by_selector('p').join(' ')
|
39
39
|
end
|
40
40
|
|
41
|
+
def test_loading_a_local_file_with_scheme
|
42
|
+
file_name = 'file://' + File.dirname(__FILE__) + '/fixtures/simple.css'
|
43
|
+
@cp.load_uri!(file_name)
|
44
|
+
assert_equal 'margin: 0px;', @cp.find_by_selector('p').join(' ')
|
45
|
+
end
|
46
|
+
|
41
47
|
def test_loading_a_remote_file
|
42
48
|
@cp.load_uri!("#{@uri_base}/simple.css")
|
43
49
|
assert_equal 'margin: 0px;', @cp.find_by_selector('p').join(' ')
|
44
50
|
end
|
45
51
|
|
52
|
+
# http://github.com/alexdunae/css_parser/issues#issue/4
|
53
|
+
def test_loading_a_remote_file_over_ssl
|
54
|
+
# TODO: test SSL locally
|
55
|
+
@cp.load_uri!("https://www.expresspardons.com/inc/screen.css")
|
56
|
+
assert_match /margin\: 0\;/, @cp.find_by_selector('body').join(' ')
|
57
|
+
end
|
58
|
+
|
59
|
+
|
46
60
|
def test_following_at_import_rules_local
|
47
61
|
base_dir = File.dirname(__FILE__) + '/fixtures'
|
48
62
|
@cp.load_file!('import1.css', base_dir)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: css_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 1.1.
|
9
|
+
- 2
|
10
|
+
version: 1.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Alex Dunae
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-10-
|
18
|
+
date: 2010-10-28 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|