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.
- data/lib/css_parser/parser.rb +54 -28
- data/lib/css_parser.rb +7 -1
- data/test/test_css_parser_media_types.rb +14 -6
- metadata +3 -3
data/lib/css_parser/parser.rb
CHANGED
@@ -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(
|
115
|
-
media_types << t
|
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]
|
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]
|
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
|
-
|
201
|
-
|
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
|
-
|
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.
|
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,
|
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.
|
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 =>
|
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 '
|
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.
|
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: &
|
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: *
|
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: []
|