deadweight 0.2.1 → 0.2.2

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.
@@ -1,5 +1,3 @@
1
- $LOAD_PATH.concat Dir.glob(File.expand_path('../../vendor/gems/*/lib', __FILE__))
2
-
3
1
  require 'css_parser'
4
2
  require 'nokogiri'
5
3
  require 'open-uri'
@@ -176,7 +174,9 @@ private
176
174
  end
177
175
 
178
176
  def strip(selector)
179
- selector.gsub(/::?[\w\-]+/, '')
177
+ selector = selector.gsub(/^@.*/, '') # @-webkit-keyframes ...
178
+ selector = selector.gsub(/:.*/, '') # input#x:nth-child(2):not(#z.o[type='file'])
179
+ selector
180
180
  end
181
181
 
182
182
  def log
@@ -1,5 +1,7 @@
1
1
  class Deadweight
2
2
  class RakeTask
3
+ include Rake::DSL if defined?(Rake::DSL)
4
+
3
5
  def initialize output=STDOUT, &block
4
6
  desc "run deadweight"
5
7
  task :deadweight do
metadata CHANGED
@@ -1,70 +1,103 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: deadweight
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 2
8
- - 1
9
- version: 0.2.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Aanand Prasad
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-04-18 00:00:00 +01:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2012-09-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
22
23
  prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: css_parser
32
+ requirement: !ruby/object:Gem::Requirement
24
33
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
- version: "0"
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.2.6
31
38
  type: :runtime
32
- version_requirements: *id001
33
- - !ruby/object:Gem::Dependency
34
- name: shoulda
35
39
  prerelease: false
36
- requirement: &id002 !ruby/object:Gem::Requirement
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.2.6
46
+ - !ruby/object:Gem::Dependency
47
+ name: shoulda
48
+ requirement: !ruby/object:Gem::Requirement
37
49
  none: false
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 0
43
- version: "0"
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
44
54
  type: :development
45
- version_requirements: *id002
46
- - !ruby/object:Gem::Dependency
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
47
63
  name: mechanize
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.5.1
70
+ type: :development
48
71
  prerelease: false
49
- requirement: &id003 !ruby/object:Gem::Requirement
72
+ version_requirements: !ruby/object:Gem::Requirement
50
73
  none: false
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- segments:
55
- - 0
56
- version: "0"
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.5.1
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
57
86
  type: :development
58
- version_requirements: *id003
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
59
94
  description:
60
95
  email: aanand.prasad@gmail.com
61
- executables:
96
+ executables:
62
97
  - deadweight
63
98
  extensions: []
64
-
65
99
  extra_rdoc_files: []
66
-
67
- files:
100
+ files:
68
101
  - LICENSE
69
102
  - README.md
70
103
  - bin/deadweight
@@ -74,56 +107,29 @@ files:
74
107
  - lib/deadweight/hijack/rails.rb
75
108
  - lib/deadweight/rack/capturing_middleware.rb
76
109
  - lib/deadweight/rake_task.rb
77
- - vendor/gems/css_parser-1.1.5/lib/css_parser.rb
78
- - vendor/gems/css_parser-1.1.5/lib/css_parser/parser.rb
79
- - vendor/gems/css_parser-1.1.5/lib/css_parser/regexps.rb
80
- - vendor/gems/css_parser-1.1.5/lib/css_parser/rule_set.rb
81
- - vendor/gems/css_parser-1.1.5/test/fixtures/import-circular-reference.css
82
- - vendor/gems/css_parser-1.1.5/test/fixtures/import-with-media-types.css
83
- - vendor/gems/css_parser-1.1.5/test/fixtures/import1.css
84
- - vendor/gems/css_parser-1.1.5/test/fixtures/simple.css
85
- - vendor/gems/css_parser-1.1.5/test/fixtures/subdir/import2.css
86
- - vendor/gems/css_parser-1.1.5/test/test_css_parser_basic.rb
87
- - vendor/gems/css_parser-1.1.5/test/test_css_parser_loading.rb
88
- - vendor/gems/css_parser-1.1.5/test/test_css_parser_media_types.rb
89
- - vendor/gems/css_parser-1.1.5/test/test_css_parser_misc.rb
90
- - vendor/gems/css_parser-1.1.5/test/test_css_parser_regexps.rb
91
- - vendor/gems/css_parser-1.1.5/test/test_helper.rb
92
- - vendor/gems/css_parser-1.1.5/test/test_merging.rb
93
- - vendor/gems/css_parser-1.1.5/test/test_rule_set.rb
94
- - vendor/gems/css_parser-1.1.5/test/test_rule_set_creating_shorthand.rb
95
- - vendor/gems/css_parser-1.1.5/test/test_rule_set_expanding_shorthand.rb
96
- has_rdoc: true
97
110
  homepage: http://github.com/aanand/deadweight
98
- licenses:
111
+ licenses:
99
112
  - MIT
100
113
  post_install_message:
101
114
  rdoc_options: []
102
-
103
- require_paths:
115
+ require_paths:
104
116
  - lib
105
- required_ruby_version: !ruby/object:Gem::Requirement
117
+ required_ruby_version: !ruby/object:Gem::Requirement
106
118
  none: false
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- segments:
111
- - 0
112
- version: "0"
113
- required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
124
  none: false
115
- requirements:
116
- - - ">="
117
- - !ruby/object:Gem::Version
118
- segments:
119
- - 0
120
- version: "0"
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
121
129
  requirements: []
122
-
123
130
  rubyforge_project:
124
- rubygems_version: 1.3.7
131
+ rubygems_version: 1.8.23
125
132
  signing_key:
126
133
  specification_version: 3
127
134
  summary: A coverage tool for finding unused CSS
128
135
  test_files: []
129
-
@@ -1,162 +0,0 @@
1
- require 'uri'
2
- require 'net/https'
3
- require 'open-uri'
4
- require 'digest/md5'
5
- require 'zlib'
6
- require 'stringio'
7
- require 'iconv'
8
-
9
- module CssParser
10
- VERSION = '1.1.5'
11
-
12
- # Merge multiple CSS RuleSets by cascading according to the CSS 2.1 cascading rules
13
- # (http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order).
14
- #
15
- # Takes one or more RuleSet objects.
16
- #
17
- # Returns a RuleSet.
18
- #
19
- # ==== Cascading
20
- # If a RuleSet object has its +specificity+ defined, that specificity is
21
- # used in the cascade calculations.
22
- #
23
- # If no specificity is explicitly set and the RuleSet has *one* selector,
24
- # the specificity is calculated using that selector.
25
- #
26
- # If no selectors or multiple selectors are present, the specificity is
27
- # treated as 0.
28
- #
29
- # ==== Example #1
30
- # rs1 = RuleSet.new(nil, 'color: black;')
31
- # rs2 = RuleSet.new(nil, 'margin: 0px;')
32
- #
33
- # merged = CssParser.merge(rs1, rs2)
34
- #
35
- # puts merged
36
- # => "{ margin: 0px; color: black; }"
37
- #
38
- # ==== Example #2
39
- # rs1 = RuleSet.new(nil, 'background-color: black;')
40
- # rs2 = RuleSet.new(nil, 'background-image: none;')
41
- #
42
- # merged = CssParser.merge(rs1, rs2)
43
- #
44
- # puts merged
45
- # => "{ background: none black; }"
46
- #--
47
- # TODO: declaration_hashes should be able to contain a RuleSet
48
- # this should be a Class method
49
- def CssParser.merge(*rule_sets)
50
- @folded_declaration_cache = {}
51
-
52
- # in case called like CssParser.merge([rule_set, rule_set])
53
- rule_sets.flatten! if rule_sets[0].kind_of?(Array)
54
-
55
- unless rule_sets.all? {|rs| rs.kind_of?(CssParser::RuleSet)}
56
- raise ArgumentError, "all parameters must be CssParser::RuleSets."
57
- end
58
-
59
- return rule_sets[0] if rule_sets.length == 1
60
-
61
- # Internal storage of CSS properties that we will keep
62
- properties = {}
63
-
64
- rule_sets.each do |rule_set|
65
- rule_set.expand_shorthand!
66
-
67
- specificity = rule_set.specificity
68
- unless specificity
69
- if rule_set.selectors.length == 1
70
- specificity = calculate_specificity(rule_set.selectors[0])
71
- else
72
- specificity = 0
73
- end
74
- end
75
-
76
- rule_set.each_declaration do |property, value, is_important|
77
- # Add the property to the list to be folded per http://www.w3.org/TR/CSS21/cascade.html#cascading-order
78
- if not properties.has_key?(property)
79
- properties[property] = {:value => value, :specificity => specificity, :is_important => is_important}
80
- elsif properties[property][:specificity] < specificity or properties[property][:specificity] == specificity
81
- unless properties[property][:is_important]
82
- properties[property] = {:value => value, :specificity => specificity, :is_important => is_important}
83
- end
84
- end
85
-
86
- if is_important
87
- properties[property] = {:value => value, :specificity => specificity, :is_important => is_important}
88
- end
89
- end
90
- end
91
-
92
- merged = RuleSet.new(nil, nil)
93
-
94
- properties.each do |property, details|
95
- if details[:is_important]
96
- merged[property.strip] = details[:value].strip.gsub(/\;\Z/, '') + '!important'
97
- else
98
- merged[property.strip] = details[:value].strip
99
- end
100
- end
101
-
102
- merged.create_shorthand!
103
- merged
104
- end
105
-
106
- # Calculates the specificity of a CSS selector
107
- # per http://www.w3.org/TR/CSS21/cascade.html#specificity
108
- #
109
- # Returns an integer.
110
- #
111
- # ==== Example
112
- # CssParser.calculate_specificity('#content div p:first-line a:link')
113
- # => 114
114
- #--
115
- # Thanks to Rafael Salazar and Nick Fitzsimons on the css-discuss list for their help.
116
- #++
117
- def CssParser.calculate_specificity(selector)
118
- a = 0
119
- b = selector.scan(/\#/).length
120
- c = selector.scan(NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX).length
121
- d = selector.scan(ELEMENTS_AND_PSEUDO_ELEMENTS_RX).length
122
-
123
- (a.to_s + b.to_s + c.to_s + d.to_s).to_i
124
- rescue
125
- return 0
126
- end
127
-
128
- # Make <tt>url()</tt> links absolute.
129
- #
130
- # Takes a block of CSS and returns it with all relative URIs converted to absolute URIs.
131
- #
132
- # "For CSS style sheets, the base URI is that of the style sheet, not that of the source document."
133
- # per http://www.w3.org/TR/CSS21/syndata.html#uri
134
- #
135
- # Returns a string.
136
- #
137
- # ==== Example
138
- # CssParser.convert_uris("body { background: url('../style/yellow.png?abc=123') };",
139
- # "http://example.org/style/basic.css").inspect
140
- # => "body { background: url('http://example.org/style/yellow.png?abc=123') };"
141
- def self.convert_uris(css, base_uri)
142
- out = ''
143
- base_uri = URI.parse(base_uri) unless base_uri.kind_of?(URI)
144
-
145
- out = css.gsub(URI_RX) do |s|
146
- uri = $1.to_s
147
- uri.gsub!(/["']+/, '')
148
- # Don't process URLs that are already absolute
149
- unless uri =~ /^[a-z]+\:\/\//i
150
- begin
151
- uri = base_uri.merge(uri)
152
- rescue; end
153
- end
154
- "url('" + uri.to_s + "')"
155
- end
156
- out
157
- end
158
- end
159
-
160
- require File.dirname(__FILE__) + '/css_parser/rule_set'
161
- require File.dirname(__FILE__) + '/css_parser/regexps'
162
- require File.dirname(__FILE__) + '/css_parser/parser'
@@ -1,411 +0,0 @@
1
- module CssParser
2
- # Exception class used for any errors encountered while downloading remote files.
3
- class RemoteFileError < IOError; end
4
-
5
- # Exception class used if a request is made to load a CSS file more than once.
6
- class CircularReferenceError < StandardError; end
7
-
8
-
9
- # == Parser class
10
- #
11
- # All CSS is converted to UTF-8.
12
- #
13
- # When calling Parser#new there are some configuaration options:
14
- # [<tt>absolute_paths</tt>] Convert relative paths to absolute paths (<tt>href</tt>, <tt>src</tt> and <tt>url('')</tt>. Boolean, default is <tt>false</tt>.
15
- # [<tt>import</tt>] Follow <tt>@import</tt> rules. Boolean, default is <tt>true</tt>.
16
- # [<tt>io_exceptions</tt>] Throw an exception if a link can not be found. Boolean, default is <tt>true</tt>.
17
- class Parser
18
- USER_AGENT = "Ruby CSS Parser/#{CssParser::VERSION} (http://github.com/alexdunae/css_parser)"
19
-
20
- STRIP_CSS_COMMENTS_RX = /\/\*.*?\*\//m
21
- STRIP_HTML_COMMENTS_RX = /\<\!\-\-|\-\-\>/m
22
-
23
- # Initial parsing
24
- RE_AT_IMPORT_RULE = /\@import\s*(?:url\s*)?(?:\()?(?:\s*)["']?([^'"\s\)]*)["']?\)?([\w\s\,^\])]*)\)?[;\n]?/
25
-
26
- # Array of CSS files that have been loaded.
27
- attr_reader :loaded_uris
28
-
29
- #attr_reader :rules
30
-
31
- #--
32
- # Class variable? see http://www.oreillynet.com/ruby/blog/2007/01/nubygems_dont_use_class_variab_1.html
33
- #++
34
- @folded_declaration_cache = {}
35
- class << self; attr_reader :folded_declaration_cache; end
36
-
37
- def initialize(options = {})
38
- @options = {:absolute_paths => false,
39
- :import => true,
40
- :io_exceptions => true}.merge(options)
41
-
42
- # array of RuleSets
43
- @rules = []
44
-
45
-
46
- @loaded_uris = []
47
-
48
- # unprocessed blocks of CSS
49
- @blocks = []
50
- reset!
51
- end
52
-
53
- # Get declarations by selector.
54
- #
55
- # +media_types+ are optional, and can be a symbol or an array of symbols.
56
- # The default value is <tt>:all</tt>.
57
- #
58
- # ==== Examples
59
- # find_by_selector('#content')
60
- # => 'font-size: 13px; line-height: 1.2;'
61
- #
62
- # find_by_selector('#content', [:screen, :handheld])
63
- # => 'font-size: 13px; line-height: 1.2;'
64
- #
65
- # find_by_selector('#content', :print)
66
- # => 'font-size: 11pt; line-height: 1.2;'
67
- #
68
- # Returns an array of declarations.
69
- def find_by_selector(selector, media_types = :all)
70
- out = []
71
- each_selector(media_types) do |sel, dec, spec|
72
- out << dec if sel.strip == selector.strip
73
- end
74
- out
75
- end
76
- alias_method :[], :find_by_selector
77
-
78
-
79
- # Add a raw block of CSS.
80
- #
81
- # In order to follow +@import+ rules you must supply either a
82
- # +:base_dir+ or +:base_uri+ option.
83
- #
84
- # Use the +:media_types+ option to set the media type(s) for this block. Takes an array of symbols.
85
- #
86
- # Use the +:only_media_types+ option to selectively follow +@import+ rules. Takes an array of symbols.
87
- #
88
- # ==== Example
89
- # css = <<-EOT
90
- # body { font-size: 10pt }
91
- # p { margin: 0px; }
92
- # @media screen, print {
93
- # body { line-height: 1.2 }
94
- # }
95
- # EOT
96
- #
97
- # parser = CssParser::Parser.new
98
- # parser.add_block!(css)
99
- def add_block!(block, options = {})
100
- 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
103
-
104
- block = cleanup_block(block)
105
-
106
- if options[:base_uri] and @options[:absolute_paths]
107
- block = CssParser.convert_uris(block, options[:base_uri])
108
- end
109
-
110
- # Load @imported CSS
111
- block.scan(RE_AT_IMPORT_RULE).each do |import_rule|
112
- media_types = []
113
- if media_string = import_rule[-1]
114
- media_string.split(/\s|\,/).each do |t|
115
- media_types << t.to_sym unless t.empty?
116
- end
117
- end
118
-
119
- next unless options[:only_media_types].include?(:all) or media_types.length < 1 or (media_types & options[:only_media_types]).length > 0
120
-
121
- import_path = import_rule[0].to_s.gsub(/['"]*/, '').strip
122
-
123
- if options[:base_uri]
124
- import_uri = URI.parse(options[:base_uri].to_s).merge(import_path)
125
- load_uri!(import_uri, options[:base_uri], media_types)
126
- elsif options[:base_dir]
127
- load_file!(import_path, options[:base_dir], media_types)
128
- end
129
- end
130
-
131
- # Remove @import declarations
132
- block.gsub!(RE_AT_IMPORT_RULE, '')
133
-
134
- parse_block_into_rule_sets!(block, options)
135
- end
136
-
137
- # Add a CSS rule by setting the +selectors+, +declarations+ and +media_types+.
138
- #
139
- # +media_types+ can be a symbol or an array of symbols.
140
- def add_rule!(selectors, declarations, media_types = :all)
141
- rule_set = RuleSet.new(selectors, declarations)
142
- add_rule_set!(rule_set, media_types)
143
- end
144
-
145
- # Add a CssParser RuleSet object.
146
- #
147
- # +media_types+ can be a symbol or an array of symbols.
148
- def add_rule_set!(ruleset, media_types = :all)
149
- raise ArgumentError unless ruleset.kind_of?(CssParser::RuleSet)
150
-
151
- media_types = [media_types] if media_types.kind_of?(Symbol)
152
-
153
- @rules << {:media_types => media_types, :rules => ruleset}
154
- end
155
-
156
- # Iterate through RuleSet objects.
157
- #
158
- # +media_types+ can be a symbol or an array of symbols.
159
- def each_rule_set(media_types = :all) # :yields: rule_set
160
- media_types = [:all] if media_types.nil?
161
- media_types = [media_types] if media_types.kind_of?(Symbol)
162
-
163
- @rules.each do |block|
164
- if media_types.include?(:all) or block[:media_types].any? { |mt| media_types.include?(mt) }
165
- yield block[:rules]
166
- end
167
- end
168
- end
169
-
170
- # Iterate through CSS selectors.
171
- #
172
- # +media_types+ can be a symbol or an array of symbols.
173
- # See RuleSet#each_selector for +options+.
174
- def each_selector(media_types = :all, options = {}) # :yields: selectors, declarations, specificity
175
- each_rule_set(media_types) do |rule_set|
176
- #puts rule_set
177
- rule_set.each_selector(options) do |selectors, declarations, specificity|
178
- yield selectors, declarations, specificity
179
- end
180
- end
181
- end
182
-
183
- # Output all CSS rules as a single stylesheet.
184
- def to_s(media_types = :all)
185
- out = ''
186
- each_selector(media_types) do |selectors, declarations, specificity|
187
- out << "#{selectors} {\n#{declarations}\n}\n"
188
- end
189
- out
190
- end
191
-
192
- # Merge declarations with the same selector.
193
- def compact! # :nodoc:
194
- compacted = []
195
-
196
- compacted
197
- end
198
-
199
- def parse_block_into_rule_sets!(block, options = {}) # :nodoc:
200
- options = {:media_types => :all}.merge(options)
201
- media_types = options[:media_types]
202
-
203
- in_declarations = 0
204
-
205
- block_depth = 0
206
-
207
- # @charset is ignored for now
208
- in_charset = false
209
- in_string = false
210
- in_at_media_rule = false
211
-
212
- current_selectors = ''
213
- current_declarations = ''
214
-
215
- 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
- token = matches[0]
218
- #puts "TOKEN: #{token}" unless token =~ /^[\s]*$/
219
- if token =~ /\A"/ # found un-escaped double quote
220
- in_string = !in_string
221
- end
222
-
223
- if in_declarations > 0
224
-
225
- # too deep, malformed declaration block
226
- if in_declarations > 1
227
- in_declarations -= 1 if token =~ /\}/
228
- next
229
- end
230
-
231
- if token =~ /\{/
232
- in_declarations += 1
233
- next
234
- end
235
-
236
- current_declarations += token
237
-
238
- if token =~ /\}/ and not in_string
239
- current_declarations.gsub!(/\}[\s]*$/, '')
240
-
241
- in_declarations -= 1
242
-
243
- unless current_declarations.strip.empty?
244
- #puts "SAVING #{current_selectors} -> #{current_declarations}"
245
- add_rule!(current_selectors, current_declarations, media_types)
246
- end
247
-
248
- current_selectors = ''
249
- current_declarations = ''
250
- end
251
- elsif token =~ /@media/i
252
- # found '@media', reset current media_types
253
- in_at_media_rule = true
254
- media_types = []
255
- elsif in_at_media_rule
256
- if token =~ /\{/
257
- block_depth = block_depth + 1
258
- in_at_media_rule = false
259
- else
260
- token.gsub!(/[,\s]*/, '')
261
- media_types << token.strip.downcase.to_sym unless token.empty?
262
- end
263
- elsif in_charset or token =~ /@charset/i
264
- # iterate until we are out of the charset declaration
265
- in_charset = (token =~ /;/ ? false : true)
266
- else
267
- if token =~ /\}/ and not in_string
268
- block_depth = block_depth - 1
269
- else
270
- if token =~ /\{/ and not in_string
271
- current_selectors.gsub!(/^[\s]*/, '')
272
- current_selectors.gsub!(/[\s]*$/, '')
273
- in_declarations += 1
274
- else
275
- current_selectors += token
276
- end
277
- end
278
- end
279
- end
280
- end
281
-
282
- # Load a remote CSS file.
283
- #
284
- # You can also pass in file://test.css
285
- def load_uri!(uri, base_uri = nil, media_types = :all)
286
- uri = URI.parse(uri) unless uri.respond_to? :scheme
287
- if uri.scheme == 'file' or uri.scheme.nil?
288
- uri.path = File.expand_path(uri.path)
289
- uri.scheme = 'file'
290
- end
291
- base_uri = uri if base_uri.nil?
292
-
293
- src, charset = read_remote_file(uri)
294
-
295
- if src
296
- add_block!(src, {:media_types => media_types, :base_uri => base_uri})
297
- end
298
- end
299
-
300
- # Load a local CSS file.
301
- def load_file!(file_name, base_dir = nil, media_types = :all)
302
- file_name = File.expand_path(file_name, base_dir)
303
- return unless File.readable?(file_name)
304
-
305
- src = IO.read(file_name)
306
- base_dir = File.dirname(file_name)
307
-
308
- add_block!(src, {:media_types => media_types, :base_dir => base_dir})
309
- end
310
-
311
-
312
-
313
- protected
314
- # Strip comments and clean up blank lines from a block of CSS.
315
- #
316
- # Returns a string.
317
- def cleanup_block(block) # :nodoc:
318
- # Strip CSS comments
319
- block.gsub!(STRIP_CSS_COMMENTS_RX, '')
320
-
321
- # Strip HTML comments - they shouldn't really be in here but
322
- # some people are just crazy...
323
- block.gsub!(STRIP_HTML_COMMENTS_RX, '')
324
-
325
- # Strip lines containing just whitespace
326
- block.gsub!(/^\s+$/, "")
327
-
328
- block
329
- end
330
-
331
- # Download a file into a string.
332
- #
333
- # Returns the file's data and character set in an array.
334
- #--
335
- # TODO: add option to fail silently or throw and exception on a 404
336
- #++
337
- def read_remote_file(uri) # :nodoc:
338
- if @loaded_uris.include?(uri.to_s)
339
- raise CircularReferenceError, "can't load #{uri.to_s} more than once" if @options[:io_exceptions]
340
- return '', nil
341
- end
342
-
343
- @loaded_uris << uri.to_s
344
-
345
- src = '', charset = nil
346
-
347
- begin
348
- uri = URI.parse(uri.to_s)
349
- http = Net::HTTP.new(uri.host, uri.port)
350
-
351
- if uri.scheme == 'file'
352
- # local file
353
- fh = open(uri.path, 'rb')
354
- src = fh.read
355
- fh.close
356
- else
357
- # remote file
358
- if uri.scheme == 'https'
359
- http.use_ssl = true
360
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
361
- end
362
-
363
- res, src = http.get(uri.path, {'User-Agent' => USER_AGENT, 'Accept-Encoding' => 'gzip'})
364
- charset = fh.respond_to?(:charset) ? fh.charset : 'utf-8'
365
-
366
- if res.code.to_i >= 400
367
- raise RemoteFileError if @options[:io_exceptions]
368
- return '', nil
369
- end
370
-
371
- case res['content-encoding']
372
- when 'gzip'
373
- io = Zlib::GzipReader.new(StringIO.new(res.body))
374
- src = io.read
375
- when 'deflate'
376
- io = Zlib::Inflate.new
377
- src = io.inflate(res.body)
378
- end
379
- end
380
-
381
- if charset
382
- ic = Iconv.new('UTF-8//IGNORE', charset)
383
- src = ic.iconv(src)
384
- end
385
- rescue
386
- raise RemoteFileError if @options[:io_exceptions]
387
- return nil, nil
388
- end
389
-
390
- return src, charset
391
- end
392
-
393
- private
394
- # Save a folded declaration block to the internal cache.
395
- def save_folded_declaration(block_hash, folded_declaration) # :nodoc:
396
- @folded_declaration_cache[block_hash] = folded_declaration
397
- end
398
-
399
- # Retrieve a folded declaration block from the internal cache.
400
- def get_folded_declaration(block_hash) # :nodoc:
401
- return @folded_declaration_cache[block_hash] ||= nil
402
- end
403
-
404
- def reset! # :nodoc:
405
- @folded_declaration_cache = {}
406
- @css_source = ''
407
- @css_rules = []
408
- @css_warnings = []
409
- end
410
- end
411
- end