css_parser 1.4.10 → 1.5.0.pre

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1b445faf1396f058086f3ec3654d5ebb4a2d1157
4
- data.tar.gz: 2c8b069bfff50b3e5072ba4912d52aff2ec813ee
3
+ metadata.gz: 842917dce4f3455e696297fb182f1b1783ac3a5a
4
+ data.tar.gz: ef48928b85b441a68fe9b10e3947643f90a147ec
5
5
  SHA512:
6
- metadata.gz: 95c649943ddeb1d61395107986d97d594354654647d13453c41c7cee0d2bffeb6645320e2084a56609131f29721f3f7ddb538ed2c068af43770e48947b1fee40
7
- data.tar.gz: ed26582b08c72abf29c10c8f6a45d28c5d8a12cadbaf9dd3096ff96f719251b0334d73ad68b1cb56fc3e489d184fbe53d3bc7cd24fd595d93e4f76f94b1b6250
6
+ metadata.gz: 01d11dfbc01781b5ca23598800f53062211f0d7b06074683720ca11354d85d7ea2e9cb2624bfc97265e6ee89ee3c28edb95d02361512a1407c77bd9c8b54d381
7
+ data.tar.gz: 194c4de30884cc386108ffee89cd1c0426ce4ae2bcfb467515c3fc1ff19dd387680a19306c7ace0f24854adef85846f0eeeca8a01651602c3e744a38cf72ca61
@@ -36,7 +36,8 @@ module CssParser
36
36
  def initialize(options = {})
37
37
  @options = {:absolute_paths => false,
38
38
  :import => true,
39
- :io_exceptions => true}.merge(options)
39
+ :io_exceptions => true,
40
+ :capture_offsets => false}.merge(options)
40
41
 
41
42
  # array of RuleSets
42
43
  @rules = []
@@ -117,7 +118,7 @@ module CssParser
117
118
  options[:media_types] = [options[:media_types]].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
118
119
  options[:only_media_types] = [options[:only_media_types]].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
119
120
 
120
- block = cleanup_block(block)
121
+ block = cleanup_block(block, options)
121
122
 
122
123
  if options[:base_uri] and @options[:absolute_paths]
123
124
  block = CssParser.convert_uris(block, options[:base_uri])
@@ -139,17 +140,22 @@ module CssParser
139
140
 
140
141
  import_path = import_rule[0].to_s.gsub(/['"]*/, '').strip
141
142
 
143
+ import_options = { :media_types => media_types }
144
+ import_options[:capture_offsets] = true if options[:capture_offsets]
145
+
142
146
  if options[:base_uri]
143
147
  import_uri = Addressable::URI.parse(options[:base_uri].to_s) + Addressable::URI.parse(import_path)
144
- load_uri!(import_uri, options[:base_uri], media_types)
148
+ import_options[:base_uri] = options[:base_uri]
149
+ load_uri!(import_uri, import_options)
145
150
  elsif options[:base_dir]
146
- load_file!(import_path, options[:base_dir], media_types)
151
+ import_options[:base_dir] = options[:base_dir]
152
+ load_file!(import_path, import_options)
147
153
  end
148
154
  end
149
155
  end
150
156
 
151
157
  # Remove @import declarations
152
- block.gsub!(RE_AT_IMPORT_RULE, '')
158
+ block = ignore_pattern(block, RE_AT_IMPORT_RULE, options)
153
159
 
154
160
  parse_block_into_rule_sets!(block, options)
155
161
  end
@@ -162,6 +168,16 @@ module CssParser
162
168
  add_rule_set!(rule_set, media_types)
163
169
  end
164
170
 
171
+ # Add a CSS rule by setting the +selectors+, +declarations+, +filename+, +offset+ and +media_types+.
172
+ #
173
+ # +filename+ can be a string or uri pointing to the file or url location.
174
+ # +offset+ should be Range object representing the start and end byte locations where the rule was found in the file.
175
+ # +media_types+ can be a symbol or an array of symbols.
176
+ def add_rule_with_offsets!(selectors, declarations, filename, offset, media_types = :all)
177
+ rule_set = OffsetAwareRuleSet.new(filename, offset, selectors, declarations)
178
+ add_rule_set!(rule_set, media_types)
179
+ end
180
+
165
181
  # Add a CssParser RuleSet object.
166
182
  #
167
183
  # +media_types+ can be a symbol or an array of symbols.
@@ -289,9 +305,16 @@ module CssParser
289
305
  current_media_query = ''
290
306
  current_declarations = ''
291
307
 
292
- block.scan(/(([\\]{2,})|([\\]?[{}\s"])|(.[^\s"{}\\]*))/).each do |matches|
308
+ # once we are in a rule, we will use this to store where we started if we are capturing offsets
309
+ rule_start = nil
310
+ offset = nil
311
+
312
+ block.scan(/(([\\]{2,})|([\\]?[{}\s"])|(.[^\s"{}\\]*))/) do |matches|
293
313
  token = matches[0]
294
314
 
315
+ # save the regex offset so that we know where in the file we are
316
+ offset = Regexp.last_match.offset(0) if options[:capture_offsets]
317
+
295
318
  if token =~ /\A"/ # found un-escaped double quote
296
319
  in_string = !in_string
297
320
  end
@@ -316,11 +339,18 @@ module CssParser
316
339
  in_declarations -= 1
317
340
 
318
341
  unless current_declarations.strip.empty?
319
- add_rule!(current_selectors, current_declarations, current_media_queries)
342
+ if options[:capture_offsets]
343
+ add_rule_with_offsets!(current_selectors, current_declarations, options[:filename], (rule_start..offset.last), current_media_queries)
344
+ else
345
+ add_rule!(current_selectors, current_declarations, current_media_queries)
346
+ end
320
347
  end
321
348
 
322
349
  current_selectors = ''
323
350
  current_declarations = ''
351
+
352
+ # restart our search for selectors and declarations
353
+ rule_start = nil if options[:capture_offsets]
324
354
  end
325
355
  elsif token =~ /@media/i
326
356
  # found '@media', reset current media_types
@@ -356,11 +386,14 @@ module CssParser
356
386
  end
357
387
  else
358
388
  if token =~ /\{/ and not in_string
359
- current_selectors.gsub!(/^[\s]*/, '')
360
- current_selectors.gsub!(/[\s]*$/, '')
389
+ current_selectors.strip!
361
390
  in_declarations += 1
362
391
  else
392
+ # if we are in a selector, add the token to the current selectors
363
393
  current_selectors += token
394
+
395
+ # mark this as the beginning of the selector unless we have already marked it
396
+ rule_start = offset.first if options[:capture_offsets] && rule_start.nil? && token =~ /^[^\s]+$/
364
397
  end
365
398
  end
366
399
  end
@@ -368,7 +401,11 @@ module CssParser
368
401
 
369
402
  # check for unclosed braces
370
403
  if in_declarations > 0
371
- add_rule!(current_selectors, current_declarations, current_media_queries)
404
+ if options[:capture_offsets]
405
+ add_rule_with_offsets!(current_selectors, current_declarations, options[:filename], (rule_start..offset.last), current_media_queries)
406
+ else
407
+ add_rule!(current_selectors, current_declarations, current_media_queries)
408
+ end
372
409
  end
373
410
  end
374
411
 
@@ -381,7 +418,6 @@ module CssParser
381
418
  # Deprecated: originally accepted three params: `uri`, `base_uri` and `media_types`
382
419
  def load_uri!(uri, options = {}, deprecated = nil)
383
420
  uri = Addressable::URI.parse(uri) unless uri.respond_to? :scheme
384
- #base_uri = nil, media_types = :all, options = {}
385
421
 
386
422
  opts = {:base_uri => nil, :media_types => :all}
387
423
 
@@ -399,6 +435,9 @@ module CssParser
399
435
 
400
436
  opts[:base_uri] = uri if opts[:base_uri].nil?
401
437
 
438
+ # pass on the uri if we are capturing file offsets
439
+ opts[:filename] = uri.to_s if opts[:capture_offsets]
440
+
402
441
  src, = read_remote_file(uri) # skip charset
403
442
  if src
404
443
  add_block!(src, opts)
@@ -406,20 +445,40 @@ module CssParser
406
445
  end
407
446
 
408
447
  # Load a local CSS file.
409
- def load_file!(file_name, base_dir = nil, media_types = :all)
410
- file_name = File.expand_path(file_name, base_dir)
448
+ def load_file!(file_name, options = {}, deprecated = nil)
449
+ opts = {:base_dir => nil, :media_types => :all}
450
+
451
+ if options.is_a? Hash
452
+ opts.merge!(options)
453
+ else
454
+ opts[:base_dir] = options if options.is_a? String
455
+ opts[:media_types] = deprecated if deprecated
456
+ end
457
+
458
+ file_name = File.expand_path(file_name, opts[:base_dir])
411
459
  return unless File.readable?(file_name)
412
460
  return unless circular_reference_check(file_name)
413
461
 
414
462
  src = IO.read(file_name)
415
- base_dir = File.dirname(file_name)
416
463
 
417
- add_block!(src, {:media_types => media_types, :base_dir => base_dir})
464
+ opts[:filename] = file_name if opts[:capture_offsets]
465
+ opts[:base_dir] = File.dirname(file_name)
466
+
467
+ add_block!(src, opts)
418
468
  end
419
469
 
420
470
  # Load a local CSS string.
421
- def load_string!(src, base_dir = nil, media_types = :all)
422
- add_block!(src, {:media_types => media_types, :base_dir => base_dir})
471
+ def load_string!(src, options = {}, deprecated = nil)
472
+ opts = {:base_dir => nil, :media_types => :all}
473
+
474
+ if options.is_a? Hash
475
+ opts.merge!(options)
476
+ else
477
+ opts[:base_dir] = options if options.is_a? String
478
+ opts[:media_types] = deprecated if deprecated
479
+ end
480
+
481
+ add_block!(src, opts)
423
482
  end
424
483
 
425
484
 
@@ -440,20 +499,31 @@ module CssParser
440
499
  end
441
500
  end
442
501
 
502
+ # Remove a pattern from a given string
503
+ #
504
+ # Returns a string.
505
+ def ignore_pattern(css, regex, options)
506
+ # if we are capturing file offsets, replace the characters with spaces to retail the original positions
507
+ return css.gsub(regex) { |m| ' ' * m.length } if options[:capture_offsets]
508
+
509
+ # otherwise just strip it out
510
+ css.gsub(regex, '')
511
+ end
512
+
443
513
  # Strip comments and clean up blank lines from a block of CSS.
444
514
  #
445
515
  # Returns a string.
446
- def cleanup_block(block) # :nodoc:
516
+ def cleanup_block(block, options = {}) # :nodoc:
447
517
  # Strip CSS comments
448
- utf8_block = block.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
449
- utf8_block.gsub!(STRIP_CSS_COMMENTS_RX, '')
518
+ utf8_block = block.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: ' ')
519
+ utf8_block = ignore_pattern(utf8_block, STRIP_CSS_COMMENTS_RX, options)
450
520
 
451
521
  # Strip HTML comments - they shouldn't really be in here but
452
522
  # some people are just crazy...
453
- utf8_block.gsub!(STRIP_HTML_COMMENTS_RX, '')
523
+ utf8_block = ignore_pattern(utf8_block, STRIP_HTML_COMMENTS_RX, options)
454
524
 
455
525
  # Strip lines containing just whitespace
456
- utf8_block.gsub!(/^\s+$/, "")
526
+ utf8_block.gsub!(/^\s+$/, "") unless options[:capture_offsets]
457
527
 
458
528
  utf8_block
459
529
  end
@@ -483,12 +553,16 @@ module CssParser
483
553
 
484
554
  src = '', charset = nil
485
555
 
486
- uri = Addressable::URI.parse(uri.to_s)
487
556
  begin
557
+ uri = Addressable::URI.parse(uri.to_s)
558
+
488
559
  if uri.scheme == 'file'
489
560
  # local file
490
- fh = open(uri.path, 'rb')
561
+ path = uri.path
562
+ path.gsub!(/^\//, '') if Gem.win_platform?
563
+ fh = open(path, 'rb')
491
564
  src = fh.read
565
+ charset = fh.respond_to?(:charset) ? fh.charset : 'utf-8'
492
566
  fh.close
493
567
  else
494
568
  # remote file
@@ -503,7 +577,7 @@ module CssParser
503
577
 
504
578
  res = http.get(uri.request_uri, {'User-Agent' => USER_AGENT, 'Accept-Encoding' => 'gzip'})
505
579
  src = res.body
506
- charset = fh.respond_to?(:charset) ? fh.charset : 'utf-8'
580
+ charset = res.respond_to?(:charset) ? res.encoding : 'utf-8'
507
581
 
508
582
  if res.code.to_i >= 400
509
583
  @redirect_count = nil
@@ -513,4 +513,19 @@ module CssParser
513
513
  @selectors = selectors.split(',').map { |s| s.gsub(/\s+/, ' ').strip }
514
514
  end
515
515
  end
516
+
517
+ class OffsetAwareRuleSet < RuleSet
518
+
519
+ # File offset range
520
+ attr_reader :offset
521
+
522
+ # the local or remote location
523
+ attr_accessor :filename
524
+
525
+ def initialize(filename, offset, selectors, block, specificity = nil)
526
+ super(selectors, block, specificity)
527
+ @offset = offset
528
+ @filename = filename
529
+ end
530
+ end
516
531
  end
@@ -1,3 +1,3 @@
1
1
  module CssParser
2
- VERSION = "1.4.10".freeze
2
+ VERSION = "1.5.0.pre".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: css_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.10
4
+ version: 1.5.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dunae
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-09 00:00:00.000000000 Z
11
+ date: 2017-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -51,9 +51,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
51
51
  version: '0'
52
52
  required_rubygems_version: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - ">="
54
+ - - ">"
55
55
  - !ruby/object:Gem::Version
56
- version: '0'
56
+ version: 1.3.1
57
57
  requirements: []
58
58
  rubyforge_project:
59
59
  rubygems_version: 2.6.8