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.
@@ -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 = false
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 = false
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 = true
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
- unless src.empty?
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
- begin
325
- #fh = open(uri, 'rb')
326
- fh = open(uri, 'rb', 'User-Agent' => USER_AGENT, 'Accept-Encoding' => 'gzip')
337
+ src = '', charset = nil
327
338
 
328
- if fh.content_encoding.include?('gzip')
329
- remote_src = Zlib::GzipReader.new(fh).read
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
- remote_src = fh.read
332
- end
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
- #puts "reading #{uri} (#{fh.charset})"
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
- ic = Iconv.new('UTF-8//IGNORE', fh.charset)
337
- src = ic.iconv(remote_src)
358
+ if res.code.to_i >= 400
359
+ raise RemoteFileError if @options[:io_exceptions]
360
+ return '', nil
361
+ end
338
362
 
339
- fh.close
340
- return src, fh.charset
341
- rescue Exception => e
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.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)
@@ -83,7 +83,6 @@ class CssParserTests < Test::Unit::TestCase
83
83
  end
84
84
 
85
85
  def test_ignoring_malformed_declarations
86
- flunk
87
86
  # dervived from http://www.w3.org/TR/CSS21/syndata.html#parsing-errors
88
87
  css = <<-EOT
89
88
  p { color:green }
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: 17
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 1
9
- - 1
10
- version: 1.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-26 00:00:00 -07:00
18
+ date: 2010-10-28 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies: []
21
21