css_parser 1.2.6 → 1.3.0

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.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