css_parser 1.2.2 → 1.2.3

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.
@@ -21,13 +21,11 @@ module CssParser
21
21
  STRIP_HTML_COMMENTS_RX = /\<\!\-\-|\-\-\>/m
22
22
 
23
23
  # Initial parsing
24
- RE_AT_IMPORT_RULE = /\@import\s*(?:url\s*)?(?:\()?(?:\s*)["']?([^'"\s\)]*)["']?\)?([\w\s\,^\])]*)\)?[;\n]?/
24
+ RE_AT_IMPORT_RULE = /\@import\s*(?:url\s*)?(?:\()?(?:\s*)["']?([^'"\s\)]*)["']?\)?([\w\s\,^\]\(\))]*)\)?[;\n]?/
25
25
 
26
26
  # Array of CSS files that have been loaded.
27
27
  attr_reader :loaded_uris
28
-
29
- #attr_reader :rules
30
-
28
+
31
29
  #--
32
30
  # Class variable? see http://www.oreillynet.com/ruby/blog/2007/01/nubygems_dont_use_class_variab_1.html
33
31
  #++
@@ -98,24 +96,26 @@ module CssParser
98
96
  # parser.add_block!(css)
99
97
  def add_block!(block, options = {})
100
98
  options = {:base_uri => nil, :base_dir => nil, :charset => nil, :media_types => :all, :only_media_types => :all}.merge(options)
101
- options[:media_types] = [options[:media_types]].flatten
102
- options[:only_media_types] = [options[:only_media_types]].flatten
99
+ options[:media_types] = [options[:media_types]].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
100
+ options[:only_media_types] = [options[:only_media_types]].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
103
101
 
104
102
  block = cleanup_block(block)
105
103
 
106
104
  if options[:base_uri] and @options[:absolute_paths]
107
105
  block = CssParser.convert_uris(block, options[:base_uri])
108
106
  end
109
-
107
+
110
108
  # Load @imported CSS
111
- block.scan(RE_AT_IMPORT_RULE).each do |import_rule|
109
+ block.scan(RE_AT_IMPORT_RULE).each do |import_rule|
112
110
  media_types = []
113
111
  if media_string = import_rule[-1]
114
- media_string.split(/\s|\,/).each do |t|
115
- media_types << t.to_sym unless t.empty?
112
+ media_string.split(/[,]/).each do |t|
113
+ media_types << CssParser.sanitize_media_query(t) unless t.empty?
116
114
  end
115
+ else
116
+ media_types = [:all]
117
117
  end
118
-
118
+
119
119
  next unless options[:only_media_types].include?(:all) or media_types.length < 1 or (media_types & options[:only_media_types]).length > 0
120
120
 
121
121
  import_path = import_rule[0].to_s.gsub(/['"]*/, '').strip
@@ -148,7 +148,7 @@ module CssParser
148
148
  def add_rule_set!(ruleset, media_types = :all)
149
149
  raise ArgumentError unless ruleset.kind_of?(CssParser::RuleSet)
150
150
 
151
- media_types = [media_types] if media_types.kind_of?(Symbol)
151
+ media_types = [media_types].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
152
152
 
153
153
  @rules << {:media_types => media_types, :rules => ruleset}
154
154
  end
@@ -158,7 +158,7 @@ module CssParser
158
158
  # +media_types+ can be a symbol or an array of symbols.
159
159
  def each_rule_set(media_types = :all) # :yields: rule_set
160
160
  media_types = [:all] if media_types.nil?
161
- media_types = [media_types] if media_types.kind_of?(Symbol)
161
+ media_types = [media_types].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
162
162
 
163
163
  @rules.each do |block|
164
164
  if media_types.include?(:all) or block[:media_types].any? { |mt| media_types.include?(mt) }
@@ -173,7 +173,6 @@ module CssParser
173
173
  # See RuleSet#each_selector for +options+.
174
174
  def each_selector(media_types = :all, options = {}) # :yields: selectors, declarations, specificity
175
175
  each_rule_set(media_types) do |rule_set|
176
- #puts rule_set
177
176
  rule_set.each_selector(options) do |selectors, declarations, specificity|
178
177
  yield selectors, declarations, specificity
179
178
  end
@@ -188,6 +187,21 @@ module CssParser
188
187
  end
189
188
  out
190
189
  end
190
+
191
+ # A hash of { :media_query => rule_sets }
192
+ def rules_by_media_query
193
+ rules_by_media = {}
194
+ @rules.each do |block|
195
+ block[:media_types].each do |mt|
196
+ unless rules_by_media.has_key?(mt)
197
+ rules_by_media[mt] = []
198
+ end
199
+ rules_by_media[mt] << block[:rules]
200
+ end
201
+ end
202
+
203
+ rules_by_media
204
+ end
191
205
 
192
206
  # Merge declarations with the same selector.
193
207
  def compact! # :nodoc:
@@ -197,32 +211,31 @@ module CssParser
197
211
  end
198
212
 
199
213
  def parse_block_into_rule_sets!(block, options = {}) # :nodoc:
200
- options = {:media_types => :all}.merge(options)
201
- media_types = options[:media_types]
214
+ current_media_queries = [:all]
215
+ if options[:media_types]
216
+ current_media_queries = options[:media_types].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
217
+ end
202
218
 
203
219
  in_declarations = 0
204
-
205
220
  block_depth = 0
206
221
 
207
- # @charset is ignored for now
208
- in_charset = false
222
+ in_charset = false # @charset is ignored for now
209
223
  in_string = false
210
224
  in_at_media_rule = false
225
+ in_media_block = false
211
226
 
212
227
  current_selectors = ''
228
+ current_media_query = ''
213
229
  current_declarations = ''
214
230
 
215
231
  block.scan(/([\\]?[{}\s"]|(.[^\s"{}\\]*))/).each do |matches|
216
- #block.scan(/((.[^{}"\n\r\f\s]*)[\s]|(.[^{}"\n\r\f]*)\{|(.[^{}"\n\r\f]*)\}|(.[^{}"\n\r\f]*)\"|(.*)[\s]+)/).each do |matches|
217
232
  token = matches[0]
218
233
 
219
- #puts "TOKEN: #{token}" unless token =~ /^[\s]*$/
220
234
  if token =~ /\A"/ # found un-escaped double quote
221
235
  in_string = !in_string
222
236
  end
223
237
 
224
238
  if in_declarations > 0
225
-
226
239
  # too deep, malformed declaration block
227
240
  if in_declarations > 1
228
241
  in_declarations -= 1 if token =~ /\}/
@@ -242,8 +255,7 @@ module CssParser
242
255
  in_declarations -= 1
243
256
 
244
257
  unless current_declarations.strip.empty?
245
- #puts "SAVING #{current_selectors} -> #{current_declarations}"
246
- add_rule!(current_selectors, current_declarations, media_types)
258
+ add_rule!(current_selectors, current_declarations, current_media_queries)
247
259
  end
248
260
 
249
261
  current_selectors = ''
@@ -257,9 +269,17 @@ module CssParser
257
269
  if token =~ /\{/
258
270
  block_depth = block_depth + 1
259
271
  in_at_media_rule = false
272
+ in_media_block = true
273
+ current_media_queries << CssParser.sanitize_media_query(current_media_query)
274
+ current_media_query = ''
275
+ elsif token =~ /[,]/
276
+ # new media query begins
277
+ token.gsub!(/[,]/, ' ')
278
+ current_media_query += token.strip + ' '
279
+ current_media_queries << CssParser.sanitize_media_query(current_media_query)
280
+ current_media_query = ''
260
281
  else
261
- token.gsub!(/[,\s]*/, '')
262
- media_types << token.strip.downcase.to_sym unless token.empty?
282
+ current_media_query += token.strip + ' '
263
283
  end
264
284
  elsif in_charset or token =~ /@charset/i
265
285
  # iterate until we are out of the charset declaration
@@ -267,6 +287,12 @@ module CssParser
267
287
  else
268
288
  if token =~ /\}/ and not in_string
269
289
  block_depth = block_depth - 1
290
+
291
+ # reset the current media query scope
292
+ if in_media_block
293
+ current_media_queries = []
294
+ in_media_block = false
295
+ end
270
296
  else
271
297
  if token =~ /\{/ and not in_string
272
298
  current_selectors.gsub!(/^[\s]*/, '')
@@ -281,8 +307,8 @@ module CssParser
281
307
 
282
308
  # check for unclosed braces
283
309
  if in_declarations > 0
284
- add_rule!(current_selectors, current_declarations, media_types)
285
- end
310
+ add_rule!(current_selectors, current_declarations, current_media_queries)
311
+ end
286
312
  end
287
313
 
288
314
  # Load a remote CSS file.
data/lib/css_parser.rb CHANGED
@@ -8,7 +8,7 @@ require 'stringio'
8
8
  require 'iconv'
9
9
 
10
10
  module CssParser
11
- VERSION = '1.2.2'
11
+ VERSION = '1.2.3'
12
12
 
13
13
  # Merge multiple CSS RuleSets by cascading according to the CSS 2.1 cascading rules
14
14
  # (http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order).
@@ -152,6 +152,12 @@ module CssParser
152
152
  "url('#{uri.to_s}')"
153
153
  end
154
154
  end
155
+
156
+ def self.sanitize_media_query(raw)
157
+ mq = raw.to_s.gsub(/[\s]+/, ' ').strip
158
+ mq = 'all' if mq.empty?
159
+ mq.to_sym
160
+ end
155
161
  end
156
162
 
157
163
  require File.dirname(__FILE__) + '/css_parser/rule_set'
@@ -20,12 +20,16 @@ class CssParserMediaTypesTests < Test::Unit::TestCase
20
20
  @media screen, print {
21
21
  body { line-height: 1.2 }
22
22
  }
23
+ @media screen, 3d-glasses, print and resolution > 90dpi {
24
+ body { color: blue; }
25
+ }
23
26
  EOT
24
27
 
25
28
  @cp.add_block!(css)
26
29
 
27
30
  assert_equal 'font-size: 10pt; line-height: 1.2;', @cp.find_by_selector('body', :print).join(' ')
28
- assert_equal 'font-size: 13px; line-height: 1.2;', @cp.find_by_selector('body', :screen).join(' ')
31
+ assert_equal 'font-size: 13px; line-height: 1.2; color: blue;', @cp.find_by_selector('body', :screen).join(' ')
32
+ assert_equal 'color: blue;', @cp.find_by_selector('body', 'print and resolution > 90dpi'.to_sym).join(' ')
29
33
  end
30
34
 
31
35
  def test_finding_by_multiple_media_types
@@ -70,12 +74,12 @@ class CssParserMediaTypesTests < Test::Unit::TestCase
70
74
 
71
75
  def test_adding_block_and_limiting_media_types2
72
76
  css = <<-EOT
73
- @import "import1.css", print
77
+ @import "import1.css", print and (color)
74
78
  EOT
75
79
 
76
80
  base_dir = File.dirname(__FILE__) + '/fixtures/'
77
81
 
78
- @cp.add_block!(css, :only_media_types => :print, :base_dir => base_dir)
82
+ @cp.add_block!(css, :only_media_types => 'print and (color)', :base_dir => base_dir)
79
83
  assert_match 'color: lime', @cp.find_by_selector('div').join(' ')
80
84
  end
81
85
 
@@ -85,18 +89,22 @@ class CssParserMediaTypesTests < Test::Unit::TestCase
85
89
  EOT
86
90
 
87
91
  base_dir = File.dirname(__FILE__) + '/fixtures/'
88
-
89
92
  @cp.add_block!(css, :only_media_types => :print, :base_dir => base_dir)
90
- assert_match 'color: lime', @cp.find_by_selector('div').join(' ')
93
+ assert_match '', @cp.find_by_selector('div').join(' ')
91
94
  end
92
95
 
93
-
94
96
  def test_adding_rule_set_with_media_type
95
97
  @cp.add_rule!('body', 'color: black;', [:handheld,:tty])
96
98
  @cp.add_rule!('body', 'color: blue;', :screen)
97
99
  assert_equal 'color: black;', @cp.find_by_selector('body', :handheld).join(' ')
98
100
  end
99
101
 
102
+ def test_adding_rule_set_with_media_query
103
+ @cp.add_rule!('body', 'color: black;', 'aural and (device-aspect-ratio: 16/9)')
104
+ assert_equal 'color: black;', @cp.find_by_selector('body', 'aural and (device-aspect-ratio: 16/9)').join(' ')
105
+ assert_equal 'color: black;', @cp.find_by_selector('body', :all).join(' ')
106
+ end
107
+
100
108
  def test_selecting_with_all_media_types
101
109
  @cp.add_rule!('body', 'color: black;', [:handheld,:tty])
102
110
  assert_equal 'color: black;', @cp.find_by_selector('body', :all).join(' ')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: css_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2011-09-07 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
16
- requirement: &2155990880 !ruby/object:Gem::Requirement
16
+ requirement: &2157971400 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2155990880
24
+ version_requirements: *2157971400
25
25
  description: A set of classes for parsing CSS in Ruby.
26
26
  email: code@dunae.ca
27
27
  executables: []