css_parser 1.1.1 → 1.1.2

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.
@@ -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