css_parser 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []