css_parser 1.2.6 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/css_parser.rb CHANGED
@@ -24,8 +24,9 @@ module CssParser
24
24
  # If no specificity is explicitly set and the RuleSet has *one* selector,
25
25
  # the specificity is calculated using that selector.
26
26
  #
27
- # If no selectors or multiple selectors are present, the specificity is
28
- # treated as 0.
27
+ # If no selectors the specificity is treated as 0.
28
+ #
29
+ # If multiple selectors are present then the greatest specificity is used.
29
30
  #
30
31
  # ==== Example #1
31
32
  # rs1 = RuleSet.new(nil, 'color: black;')
@@ -67,10 +68,10 @@ module CssParser
67
68
 
68
69
  specificity = rule_set.specificity
69
70
  unless specificity
70
- if rule_set.selectors.length == 1
71
- specificity = calculate_specificity(rule_set.selectors[0])
72
- else
71
+ if rule_set.selectors.length == 0
73
72
  specificity = 0
73
+ else
74
+ specificity = rule_set.selectors.map { |s| calculate_specificity(s) }.compact.max || 0
74
75
  end
75
76
  end
76
77
 
@@ -73,6 +73,20 @@ module CssParser
73
73
  end
74
74
  alias_method :[], :find_by_selector
75
75
 
76
+ # Finds the rule sets that match the given selectors
77
+ def find_rule_sets(selectors, media_types = :all)
78
+ rule_sets = []
79
+
80
+ selectors.each do |selector|
81
+ each_rule_set(media_types) do |rule_set|
82
+ if !rule_sets.member?(rule_set) && rule_set.selectors.member?(selector)
83
+ rule_sets << rule_set
84
+ end
85
+ end
86
+ end
87
+
88
+ rule_sets
89
+ end
76
90
 
77
91
  # Add a raw block of CSS.
78
92
  #
@@ -356,6 +370,11 @@ module CssParser
356
370
  add_block!(src, {:media_types => media_types, :base_dir => base_dir})
357
371
  end
358
372
 
373
+ # Load a local CSS string.
374
+ def load_string!(src, base_dir = nil, media_types = :all)
375
+ add_block!(src, {:media_types => media_types, :base_dir => base_dir})
376
+ end
377
+
359
378
 
360
379
 
361
380
  protected
@@ -22,6 +22,7 @@ module CssParser
22
22
 
23
23
  RE_URI = Regexp.new('(url\([\s]*([\s]*' + RE_STRING.to_s + '[\s]*)[\s]*\))|(url\([\s]*([!#$%&*\-~]|' + RE_NON_ASCII.to_s + '|' + RE_ESCAPE.to_s + ')*[\s]*)\)', Regexp::IGNORECASE | Regexp::EXTENDED | Regexp::MULTILINE, 'n')
24
24
  URI_RX = /url\(("([^"]*)"|'([^']*)'|([^)]*))\)/im
25
+ RE_GRADIENT = /[a-z\-]*gradient\([a-z ,#%0-9\(\)]*\)$/im
25
26
 
26
27
  # Initial parsing
27
28
  RE_AT_IMPORT_RULE = /\@import[\s]+(url\()?["''"]?(.[^'"\s"']*)["''"]?\)?([\w\s\,^\])]*)\)?;?/
@@ -22,7 +22,6 @@ module CssParser
22
22
  parse_declarations!(block)
23
23
  end
24
24
 
25
-
26
25
  # Get the value of a property
27
26
  def get_value(property)
28
27
  return '' unless property and not property.empty?
@@ -118,7 +117,7 @@ module CssParser
118
117
  # Return the CSS rule set as a string.
119
118
  def to_s
120
119
  decs = declarations_to_s
121
- "#{@selectors.join} { #{decs} }"
120
+ "#{@selectors.join(',')} { #{decs} }"
122
121
  end
123
122
 
124
123
  # Split shorthand declarations (e.g. +margin+ or +font+) into their constituent parts.
@@ -146,7 +145,7 @@ module CssParser
146
145
  end
147
146
  end
148
147
 
149
- split_declaration('background', 'background-image', value.slice!(Regexp.union(CssParser::URI_RX, /none/i)))
148
+ split_declaration('background', 'background-image', value.slice!(Regexp.union(CssParser::URI_RX, CssParser::RE_GRADIENT, /none/i)))
150
149
  split_declaration('background', 'background-attachment', value.slice!(CssParser::RE_SCROLL_FIXED))
151
150
  split_declaration('background', 'background-repeat', value.slice!(CssParser::RE_REPEAT))
152
151
  split_declaration('background', 'background-color', value.slice!(CssParser::RE_COLOUR))
@@ -480,7 +479,7 @@ module CssParser
480
479
  # TODO: way too simplistic
481
480
  #++
482
481
  def parse_selectors!(selectors) # :nodoc:
483
- @selectors = selectors.split(',')
482
+ @selectors = selectors.split(',').map { |s| s.strip }
484
483
  end
485
484
  end
486
485
  end
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.6
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-08 00:00:00.000000000Z
12
+ date: 2013-03-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
16
- requirement: &2160264060 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,63 +21,27 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2160264060
25
- - !ruby/object:Gem::Dependency
26
- name: rdoc
27
- requirement: &2160263460 !ruby/object:Gem::Requirement
28
- none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
32
- version: '0'
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: *2160263460
36
- - !ruby/object:Gem::Dependency
37
- name: rake
38
- requirement: &2160258520 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
39
25
  none: false
40
26
  requirements:
41
27
  - - ! '>='
42
28
  - !ruby/object:Gem::Version
43
29
  version: '0'
44
- type: :development
45
- prerelease: false
46
- version_requirements: *2160258520
47
30
  description: A set of classes for parsing CSS in Ruby.
48
31
  email: code@dunae.ca
49
32
  executables: []
50
33
  extensions: []
51
34
  extra_rdoc_files: []
52
35
  files:
53
- - lib/css_parser.rb
54
36
  - lib/css_parser/parser.rb
55
37
  - lib/css_parser/regexps.rb
56
38
  - lib/css_parser/rule_set.rb
57
- - test/fixtures/import-circular-reference.css
58
- - test/fixtures/import-with-media-types.css
59
- - test/fixtures/import1.css
60
- - test/fixtures/simple.css
61
- - test/fixtures/subdir/import2.css
62
- - test/test_css_parser_basic.rb
63
- - test/test_css_parser_loading.rb
64
- - test/test_css_parser_media_types.rb
65
- - test/test_css_parser_misc.rb
66
- - test/test_css_parser_regexps.rb
67
- - test/test_helper.rb
68
- - test/test_merging.rb
69
- - test/test_rule_set.rb
70
- - test/test_rule_set_creating_shorthand.rb
71
- - test/test_rule_set_expanding_shorthand.rb
39
+ - lib/css_parser.rb
72
40
  homepage: https://github.com/alexdunae/css_parser
73
- licenses: []
41
+ licenses:
42
+ - MIT
74
43
  post_install_message:
75
- rdoc_options:
76
- - --all
77
- - --inline-source
78
- - --line-numbers
79
- - --charset
80
- - utf-8
44
+ rdoc_options: []
81
45
  require_paths:
82
46
  - lib
83
47
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -86,26 +50,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
50
  - - ! '>='
87
51
  - !ruby/object:Gem::Version
88
52
  version: '0'
53
+ segments:
54
+ - 0
55
+ hash: 3425931588029901136
89
56
  required_rubygems_version: !ruby/object:Gem::Requirement
90
57
  none: false
91
58
  requirements:
92
59
  - - ! '>='
93
60
  - !ruby/object:Gem::Version
94
61
  version: '0'
62
+ segments:
63
+ - 0
64
+ hash: 3425931588029901136
95
65
  requirements: []
96
66
  rubyforge_project:
97
- rubygems_version: 1.8.10
67
+ rubygems_version: 1.8.25
98
68
  signing_key:
99
69
  specification_version: 3
100
70
  summary: Ruby CSS parser.
101
- test_files:
102
- - test/test_css_parser_basic.rb
103
- - test/test_css_parser_loading.rb
104
- - test/test_css_parser_media_types.rb
105
- - test/test_css_parser_misc.rb
106
- - test/test_css_parser_regexps.rb
107
- - test/test_helper.rb
108
- - test/test_merging.rb
109
- - test/test_rule_set.rb
110
- - test/test_rule_set_creating_shorthand.rb
111
- - test/test_rule_set_expanding_shorthand.rb
71
+ test_files: []
@@ -1,4 +0,0 @@
1
- @import "import-circular-reference.css";
2
-
3
- body { color: black; background: white; }
4
- p { margin: 0px; }
@@ -1,3 +0,0 @@
1
- @import "simple.css" print, tv, screen;
2
-
3
- div { color: lime; }
@@ -1,3 +0,0 @@
1
- @import 'subdir/import2.css';
2
-
3
- div { color: lime; }
@@ -1,6 +0,0 @@
1
- body {
2
- color: black;
3
- background: white;
4
- }
5
-
6
- p { margin: 0px; }
@@ -1,3 +0,0 @@
1
- @import "../simple.css";
2
-
3
- a { text-decoration: none; }
@@ -1,64 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
-
3
- # Test cases for reading and generating CSS shorthand properties
4
- class CssParserBasicTests < Test::Unit::TestCase
5
- include CssParser
6
-
7
- def setup
8
- @cp = CssParser::Parser.new
9
- @css = <<-EOT
10
- html, body, p { margin: 0px; }
11
- p { padding: 0px; }
12
- #content { font: 12px/normal sans-serif; }
13
- .content { color: red; }
14
- EOT
15
- end
16
-
17
- def test_finding_by_selector
18
- @cp.add_block!(@css)
19
- assert_equal 'margin: 0px;', @cp.find_by_selector('body').join(' ')
20
- assert_equal 'margin: 0px; padding: 0px;', @cp.find_by_selector('p').join(' ')
21
- assert_equal 'font: 12px/normal sans-serif;', @cp.find_by_selector('#content').join(' ')
22
- assert_equal 'color: red;', @cp.find_by_selector('.content').join(' ')
23
- end
24
-
25
- def test_adding_block
26
- @cp.add_block!(@css)
27
- assert_equal 'margin: 0px;', @cp.find_by_selector('body').join
28
- end
29
-
30
- def test_adding_block_without_closing_brace
31
- @cp.add_block!('p { color: red;')
32
- assert_equal 'color: red;', @cp.find_by_selector('p').join
33
- end
34
-
35
- def test_adding_a_rule
36
- @cp.add_rule!('div', 'color: blue;')
37
- assert_equal 'color: blue;', @cp.find_by_selector('div').join(' ')
38
- end
39
-
40
- def test_adding_a_rule_set
41
- rs = CssParser::RuleSet.new('div', 'color: blue;')
42
- @cp.add_rule_set!(rs)
43
- assert_equal 'color: blue;', @cp.find_by_selector('div').join(' ')
44
- end
45
-
46
- def test_toggling_uri_conversion
47
- # with conversion
48
- cp_with_conversion = Parser.new(:absolute_paths => true)
49
- cp_with_conversion.add_block!("body { background: url('../style/yellow.png?abc=123') };",
50
- :base_uri => 'http://example.org/style/basic.css')
51
-
52
- assert_equal "background: url('http://example.org/style/yellow.png?abc=123');",
53
- cp_with_conversion['body'].join(' ')
54
-
55
- # without conversion
56
- cp_without_conversion = Parser.new(:absolute_paths => false)
57
- cp_without_conversion.add_block!("body { background: url('../style/yellow.png?abc=123') };",
58
- :base_uri => 'http://example.org/style/basic.css')
59
-
60
- assert_equal "background: url('../style/yellow.png?abc=123');",
61
- cp_without_conversion['body'].join(' ')
62
- end
63
-
64
- end
@@ -1,146 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
-
3
- # Test cases for the CssParser's loading functions.
4
- class CssParserLoadingTests < Test::Unit::TestCase
5
- include CssParser
6
- include WEBrick
7
-
8
- def setup
9
- # from http://nullref.se/blog/2006/5/17/testing-with-webrick
10
- @cp = Parser.new
11
-
12
- @uri_base = 'http://localhost:12000'
13
-
14
- @www_root = File.dirname(__FILE__) + '/fixtures/'
15
-
16
- @server_thread = Thread.new do
17
- s = WEBrick::HTTPServer.new(:Port => 12000, :DocumentRoot => @www_root, :Logger => Log.new(nil, BasicLog::FATAL), :AccessLog => [])
18
- @port = s.config[:Port]
19
- begin
20
- s.start
21
- ensure
22
- s.shutdown
23
- end
24
- end
25
-
26
- sleep 1 # ensure the server has time to load
27
- end
28
-
29
- def teardown
30
- @server_thread.kill
31
- @server_thread.join(5)
32
- @server_thread = nil
33
- end
34
-
35
- def test_loading_a_local_file
36
- file_name = File.dirname(__FILE__) + '/fixtures/simple.css'
37
- @cp.load_file!(file_name)
38
- assert_equal 'margin: 0px;', @cp.find_by_selector('p').join(' ')
39
- end
40
-
41
- def test_loading_a_local_file_with_scheme
42
- file_name = 'file://' + File.expand_path(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
-
47
- def test_loading_a_remote_file
48
- @cp.load_uri!("#{@uri_base}/simple.css")
49
- assert_equal 'margin: 0px;', @cp.find_by_selector('p').join(' ')
50
- end
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://dialect.ca/inc/screen.css")
56
- assert_match /margin\: 0\;/, @cp.find_by_selector('body').join(' ')
57
- end
58
-
59
-
60
- def test_following_at_import_rules_local
61
- base_dir = File.dirname(__FILE__) + '/fixtures'
62
- @cp.load_file!('import1.css', base_dir)
63
-
64
- # from '/import1.css'
65
- assert_equal 'color: lime;', @cp.find_by_selector('div').join(' ')
66
-
67
- # from '/subdir/import2.css'
68
- assert_equal 'text-decoration: none;', @cp.find_by_selector('a').join(' ')
69
-
70
- # from '/subdir/../simple.css'
71
- assert_equal 'margin: 0px;', @cp.find_by_selector('p').join(' ')
72
- end
73
-
74
- def test_following_at_import_rules_remote
75
- @cp.load_uri!("#{@uri_base}/import1.css")
76
-
77
- # from '/import1.css'
78
- assert_equal 'color: lime;', @cp.find_by_selector('div').join(' ')
79
-
80
- # from '/subdir/import2.css'
81
- assert_equal 'text-decoration: none;', @cp.find_by_selector('a').join(' ')
82
-
83
- # from '/subdir/../simple.css'
84
- assert_equal 'margin: 0px;', @cp.find_by_selector('p').join(' ')
85
- end
86
-
87
- def test_following_badly_escaped_import_rules
88
- css_block = '@import "http://example.com/css?family=Droid+Sans:regular,bold|Droid+Serif:regular,italic,bold,bolditalic&subset=latin";'
89
-
90
- assert_nothing_raised do
91
- @cp.add_block!(css_block, :base_uri => "#{@uri_base}/subdir/")
92
- end
93
- end
94
-
95
- def test_following_at_import_rules_from_add_block
96
- css_block = '@import "../simple.css";'
97
-
98
- @cp.add_block!(css_block, :base_uri => "#{@uri_base}/subdir/")
99
-
100
- # from 'simple.css'
101
- assert_equal 'margin: 0px;', @cp.find_by_selector('p').join(' ')
102
- end
103
-
104
- def test_importing_with_media_types
105
- @cp.load_uri!("#{@uri_base}/import-with-media-types.css")
106
-
107
- # from simple.css with :screen media type
108
- assert_equal 'margin: 0px;', @cp.find_by_selector('p', :screen).join(' ')
109
- assert_equal '', @cp.find_by_selector('p', :tty).join(' ')
110
- end
111
-
112
- def test_local_circular_reference_exception
113
- assert_raise CircularReferenceError do
114
- @cp.load_file!(File.dirname(__FILE__) + '/fixtures/import-circular-reference.css')
115
- end
116
- end
117
-
118
- def test_remote_circular_reference_exception
119
- assert_raise CircularReferenceError do
120
- @cp.load_uri!("#{@uri_base}/import-circular-reference.css")
121
- end
122
- end
123
-
124
- def test_suppressing_circular_reference_exceptions
125
- cp_without_exceptions = Parser.new(:io_exceptions => false)
126
-
127
- assert_nothing_raised CircularReferenceError do
128
- cp_without_exceptions.load_uri!("#{@uri_base}/import-circular-reference.css")
129
- end
130
- end
131
-
132
- def test_toggling_not_found_exceptions
133
- cp_with_exceptions = Parser.new(:io_exceptions => true)
134
-
135
- assert_raise RemoteFileError do
136
- cp_with_exceptions.load_uri!("#{@uri_base}/no-exist.xyz")
137
- end
138
-
139
- cp_without_exceptions = Parser.new(:io_exceptions => false)
140
-
141
- assert_nothing_raised RemoteFileError do
142
- cp_without_exceptions.load_uri!("#{@uri_base}/no-exist.xyz")
143
- end
144
- end
145
-
146
- end