color_parser 0.1.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +0 -2
  3. data/Guardfile +2 -2
  4. data/README.md +9 -18
  5. data/color_parser.gemspec +3 -3
  6. data/lib/color_parser.rb +2 -48
  7. data/lib/color_parser/page.rb +14 -57
  8. data/lib/color_parser/stylesheet.rb +27 -116
  9. data/lib/color_parser/version.rb +1 -1
  10. data/spec/fixtures/css_color/stylesheets/color_styles.css +7 -7
  11. data/spec/fixtures/css_color/stylesheets/frequency.css +9 -9
  12. data/spec/page_spec.rb +27 -182
  13. data/spec/stylesheet_spec.rb +43 -153
  14. metadata +31 -126
  15. data/lib/color_parser/color.rb +0 -154
  16. data/lib/color_parser/image.rb +0 -20
  17. data/lib/color_parser/request.rb +0 -21
  18. data/spec/color_parser_spec.rb +0 -88
  19. data/spec/color_spec.rb +0 -10
  20. data/spec/fixtures/css/absolute.html +0 -15
  21. data/spec/fixtures/css/inline.html +0 -34
  22. data/spec/fixtures/css/inline_import.html +0 -16
  23. data/spec/fixtures/css/invalid.html +0 -15
  24. data/spec/fixtures/css/relative.html +0 -15
  25. data/spec/fixtures/css/relative_root.html +0 -15
  26. data/spec/fixtures/css/stylesheets/colors.css +0 -0
  27. data/spec/fixtures/css/stylesheets/fonts.css +0 -0
  28. data/spec/fixtures/css/stylesheets/print.css +0 -3
  29. data/spec/fixtures/css/stylesheets/screen.css +0 -16
  30. data/spec/fixtures/css_images/images/apple.png +0 -0
  31. data/spec/fixtures/css_images/images/cantaloupe.png +0 -0
  32. data/spec/fixtures/css_images/images/kiwi.jpg +0 -0
  33. data/spec/fixtures/css_images/images/mango.png +0 -0
  34. data/spec/fixtures/css_images/images/pineapple.png +0 -0
  35. data/spec/fixtures/css_images/paths.html +0 -14
  36. data/spec/fixtures/css_images/stylesheets/import_paths.css +0 -4
  37. data/spec/fixtures/css_images/stylesheets/paths.css +0 -17
  38. data/spec/fixtures/css_images/stylesheets/quotes.css +0 -14
  39. data/spec/fixtures/css_import/index.html +0 -15
  40. data/spec/fixtures/css_import/stylesheets/borders.css +0 -0
  41. data/spec/fixtures/css_import/stylesheets/colors.css +0 -0
  42. data/spec/fixtures/css_import/stylesheets/fonts.css +0 -3
  43. data/spec/fixtures/css_import/stylesheets/ie.css +0 -3
  44. data/spec/fixtures/css_import/stylesheets/images.css +0 -0
  45. data/spec/fixtures/css_import/stylesheets/master.css +0 -12
  46. data/spec/fixtures/css_import/stylesheets/print.css +0 -3
  47. data/spec/fixtures/css_import/stylesheets/screen.css +0 -12
  48. data/spec/fixtures/inline_images/absolute.html +0 -14
  49. data/spec/fixtures/inline_images/images/apple.png +0 -0
  50. data/spec/fixtures/inline_images/images/kiwi.jpg +0 -0
  51. data/spec/fixtures/inline_images/relative.html +0 -14
  52. data/spec/fixtures/inline_images/relative_root.html +0 -14
  53. data/spec/image_spec.rb +0 -33
  54. data/spec/request_spec.rb +0 -12
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b64cdb42506f55875598011c744435a85be5d61ede4ead26d303349553decb2b
4
+ data.tar.gz: 609e667ff3db8104fa741b2fc02f35ccde1448f0132c5e681e848d55d65a07fe
5
+ SHA512:
6
+ metadata.gz: 74dc01bbc206a7f27a7b7979491cc1e8f1da23fb315eb5b8005fdf57ce7e760420e286a98b2f0d17600520c9e4c8a489f302fa5242167a994cff1d15668e3d01
7
+ data.tar.gz: fe6f880219b08e6433d4ee649ca93dfae57db296ac16208487cb606148b41d16d0259397b43899bd8d5ece614dff509b066ab4759b685b1761fea3a20ab5b23a
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
1
  source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in color_parser.gemspec
4
2
  gemspec
data/Guardfile CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  guard 'rspec' do
5
5
  watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/stylesheet/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
- watch('spec/spec_helper.rb') { "spec" }
6
+ watch(%r{^lib/color_parser/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
8
  end
9
9
 
data/README.md CHANGED
@@ -11,33 +11,24 @@ Get colors on a given webpage
11
11
  ```ruby
12
12
  page = ColorParser::Page.new("http://google.com/")
13
13
  colors = page.colors
14
- ```
15
-
16
- Get stylesheets on a given webpage
17
-
18
- ```ruby
19
- page = ColorParser::Page.new("http://google.com/")
20
- stylesheets = page.stylesheets
21
- ```
22
-
23
- Get images on a given webpage
14
+ => {"ffffff"=>5, "c9d7f1"=>1, "0000cc"=>2, "dd8e27"=>1, "990000"=>1,
15
+ "3366cc"=>3, "000000"=>2, "1111cc"=>5, "cccccc"=>2, "551a8b"=>1}
24
16
 
25
- ```ruby
26
- page = ColorParser::Page.new("http://google.com/")
27
- images = page.images
17
+ colors = page.colors_by_frequency
18
+ => ["ffffff", "1111cc", "3366cc", "000000", "cccccc",
19
+ "0000cc", "dd8e27", "c9d7f1", "990000", "551a8b"]
28
20
  ```
29
21
 
30
22
  ## Installation
31
23
 
32
- ```
33
- gem install color_parser
34
- ```
35
- ```
24
+ To install ColorParser, add the gem to your Gemfile:
25
+
26
+ ```ruby
36
27
  gem "color_parser"
37
28
  ```
38
29
 
39
30
  ## LICENSE
40
31
 
41
- Copyright (c) 2012 Derek DeVries
32
+ Copyright (c) 2013 Derek DeVries
42
33
 
43
34
  Released under the [MIT License](http://www.opensource.org/licenses/MIT)
@@ -20,9 +20,9 @@ Gem::Specification.new do |gem|
20
20
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
21
21
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
22
  gem.require_paths = ["lib"]
23
-
24
- gem.add_runtime_dependency("curb", "~> 0.8")
25
- gem.add_runtime_dependency("nokogiri", "~> 1.5")
23
+
24
+ gem.add_runtime_dependency("stylesheet", "~> 0.1.8")
25
+ gem.add_runtime_dependency("color_conversion", "~> 0.1.0")
26
26
 
27
27
  gem.add_development_dependency("rake")
28
28
  gem.add_development_dependency("rspec", "~> 2.9")
@@ -1,57 +1,11 @@
1
1
  require 'uri'
2
- require 'curb'
3
- require 'nokogiri'
2
+ require 'stylesheet'
3
+ require 'color_conversion'
4
4
 
5
5
  require 'color_parser/errors'
6
6
  require 'color_parser/version'
7
- require 'color_parser/request'
8
7
  require 'color_parser/page'
9
8
  require 'color_parser/stylesheet'
10
- require 'color_parser/color'
11
- require 'color_parser/image'
12
9
 
13
10
  module ColorParser
14
- # Build url of an asset based on the relative/absolute url
15
- def self.parse_asset(doc_url, asset_url)
16
- doc_host, doc_path, doc_query = self.parse_url(doc_url)
17
- asset_host, asset_path, asset_query = self.parse_url(asset_url)
18
-
19
- # absolute path
20
- host, path, query = if asset_url.include?("http")
21
- [asset_host, asset_path, asset_query]
22
-
23
- # root relative
24
- elsif asset_url[0,1] == "/"
25
- [doc_host, asset_path, asset_query]
26
-
27
- # relative
28
- else
29
- path = File.expand_path("#{doc_path.gsub(/[^\/]*$/, "")}#{asset_path}", "/")
30
- [doc_host, path, asset_query]
31
- end
32
-
33
- "http://#{host}#{path}#{"?"+query if query}"
34
- end
35
-
36
- # parse url parts
37
- def self.parse_url(url)
38
- begin
39
- uri = URI.parse(url.strip)
40
- rescue URI::InvalidURIError
41
- uri = URI.parse(URI.escape(url.strip))
42
- end
43
-
44
- [uri.host, (uri.path != "" ? uri.path : "/"), uri.query]
45
- end
46
-
47
-
48
- # Request
49
-
50
- def self.request=(request)
51
- @request = request
52
- end
53
-
54
- def self.request
55
- @request ||= Request.new
56
- end
57
11
  end
@@ -1,14 +1,19 @@
1
1
  module ColorParser
2
2
  # a webpage
3
3
  class Page
4
- attr_reader :url, :host, :path, :query, :text, :doc
4
+ attr_reader :url, :text
5
5
 
6
6
  def initialize(url)
7
- @url = url
8
- @host, @path, @query = ColorParser.parse_url(url)
7
+ @style_document = self.class.style_document.new(url)
9
8
 
10
- @text ||= ColorParser.request.get(url)
11
- @doc ||= Nokogiri::HTML(@text)
9
+ @url = @style_document.location.href
10
+ @text = @style_document.text
11
+ end
12
+
13
+ def stylesheets
14
+ @stylesheets ||= @style_document.style_sheets.map do |style_sheet|
15
+ Stylesheet.new(style_sheet)
16
+ end
12
17
  end
13
18
 
14
19
  def colors
@@ -28,61 +33,13 @@ module ColorParser
28
33
  colors.sort {|a,b| b[1]<=>a[1] }.map {|clr| clr.first }
29
34
  end
30
35
 
31
- def images
32
- @images ||= inline_images + stylesheet_images
33
- end
34
36
 
35
- def stylesheets
36
- @stylesheets ||= inline_styles + external_styles
37
+ def self.style_document
38
+ @style_document ||= ::Stylesheet::Document
37
39
  end
38
40
 
39
-
40
- private
41
-
42
- # find all inline styles and build new stylesheet from them
43
- def inline_styles
44
- doc.css("style").map do |style|
45
- Stylesheet.new(text: style.inner_html,
46
- type: "inline",
47
- url: "http://#{host}#{path}")
48
- end
49
- end
50
-
51
- def external_styles
52
- styles = []
53
-
54
- doc.css("link[rel='stylesheet']").each do |style|
55
- next unless href = style["href"]
56
-
57
- asset_url = ColorParser.parse_asset(url, href)
58
- next unless text = ColorParser.request.get(asset_url)
59
-
60
- css = Stylesheet.new(text: text,
61
- type: "external",
62
- url: asset_url)
63
- styles << css
64
- end
65
-
66
- styles
67
- end
68
-
69
- def inline_images
70
- images = []
71
-
72
- doc.css("img").map do |image|
73
- next unless src = image["src"]
74
- next unless src.match(/gif|jpg|jpeg|png|bmp/)
75
-
76
- asset_url = ColorParser.parse_asset(url, src)
77
- images << Image.new(asset_url)
78
- end
79
-
80
- images
81
- end
82
-
83
- def stylesheet_images
84
- [stylesheets.map {|style| style.images }].flatten
41
+ def self.style_document=(style_document)
42
+ @style_document = style_document
85
43
  end
86
44
  end
87
-
88
45
  end
@@ -1,23 +1,9 @@
1
1
  module ColorParser
2
- # a set of css selectors
2
+
3
3
  class Stylesheet
4
- attr_reader :url, :type, :host, :path, :query, :text
5
4
 
6
- def initialize(options)
7
- @type = options[:type]
8
- @text = options[:text]
9
- @url = options[:url]
10
-
11
- @host, @path, @query = ColorParser.parse_url(url)
12
- end
13
-
14
- def name
15
- path.split("/").last
16
- end
17
-
18
- # get imported stylesheets
19
- def stylesheets
20
- @stylesheets ||= imported_stylesheets
5
+ def initialize(style_sheet)
6
+ @style_sheet = style_sheet
21
7
  end
22
8
 
23
9
  # gst list of colors from styles
@@ -28,87 +14,44 @@ module ColorParser
28
14
  def bg_colors
29
15
  @bg_colors ||= parse_colors(bg_properties)
30
16
  end
31
-
17
+
32
18
  def text_colors
33
19
  @text_colors ||= parse_colors(text_properties)
34
20
  end
35
-
21
+
36
22
  def border_colors
37
23
  @border_colors ||= parse_colors(border_properties)
38
24
  end
39
25
 
40
-
41
- def images
42
- images = []
43
-
44
- image_properties.each do |key, value|
45
- if value.include?("url") && match = value.match(/url\(['"]?([^'")]+)/)
46
- asset_url = ColorParser.parse_asset(url, match[1])
47
- images << Image.new(asset_url)
48
- end
49
- end
50
-
51
- images
52
- end
53
-
54
-
55
- # groups of css selectors (including imported styles)
56
- def selectors
57
- selectors = {}
58
-
59
- text.scan(/([^\s\}]+)[\s]*?\{(.*?)\}/m).each do |match|
60
- selector, rule = match
61
- selectors[selector] ||= []
62
- selectors[selector] << rule.strip
63
- end
64
-
65
- # imported styles
66
- stylesheets.each do |style|
67
- style.selectors.each do |selector, rule|
68
- selectors[selector] ||= []
69
- selectors[selector] += rule
26
+ def rules
27
+ rules = {}
28
+
29
+ ([@style_sheet] + style_sheets).each do |css|
30
+ css.style_rules.each do |rule|
31
+ rules[rule.selector_text] ||= {}
32
+ rules[rule.selector_text].merge!(rule.style.declarations)
70
33
  end
71
34
  end
72
35
 
73
- selectors
36
+ rules
74
37
  end
75
38
 
76
39
  # split up selectors into properties, and return property key/value pairs
77
40
  def properties
78
41
  properties = []
79
42
 
80
- selectors.each do |selector, rules|
81
- rules.each do |rule|
82
- rule.split(";").each do |property|
83
- props = property.split(":", 2).map {|v| v.strip }
84
- properties << props if props.size == 2
85
- end
86
- end
43
+ rules.values.each do |declarations|
44
+ declarations.each {|property, value| properties << [property, value] }
87
45
  end
88
-
46
+
89
47
  properties
90
48
  end
91
49
 
92
-
93
50
  private
94
51
 
95
- def imported_stylesheets
96
- return [] unless text.include?("@import")
97
-
98
- styles = []
99
- text.scan(/@import(?:\surl|\s)(.*?)[;\n]+/).each do |style|
100
- style_path = style.first.gsub(/['"\(\);]/, "")
101
-
102
- asset_url = ColorParser.parse_asset(url, style_path)
103
- next unless text = ColorParser.request.get(asset_url)
104
-
105
- css = Stylesheet.new(text: text,
106
- type: "imported",
107
- url: asset_url)
108
- styles << css
109
- end
110
-
111
- styles
52
+ # get imported stylesheets
53
+ def style_sheets
54
+ @style_sheets ||= @style_sheet.import_rules.map {|rule| rule.style_sheet }
112
55
  end
113
56
 
114
57
  # find properties that might have a color
@@ -119,7 +62,7 @@ module ColorParser
119
62
  "border-left-color", "color", "outline-color"].include?(key)
120
63
  end
121
64
  end
122
-
65
+
123
66
  # properties with bg colors
124
67
  def bg_properties
125
68
  color_properties.select {|key, value| key.include?("background") }
@@ -137,54 +80,22 @@ module ColorParser
137
80
  end
138
81
  end
139
82
 
140
- # find properties that might have an image
141
- def image_properties
142
- color_properties.select {|key, value| key.include?("background") }
143
- end
144
-
145
83
  def parse_colors(property_list)
146
84
  colors = {}
147
-
148
- text_colors = ColorParser::Color.text_colors.map {|k,v| k }.join("|")
149
-
150
- property_list.each do |key, value|
151
- # hex
152
- hex = if matches = value.match(/#([0-9a-f]{3,6})/i)
153
- normalize_hex(matches[1])
154
-
155
- # rgb/rgba
156
- elsif matches = value.match(/rgba?\((\d{1,3}[,\s]+\d{1,3}[,\s]+\d{1,3})/)
157
- rgb_to_hex(matches[1])
158
-
159
- # textual
160
- elsif matches = value.match(/(#{text_colors})/)
161
- text_to_hex(matches[1])
85
+ property_list.each do |key, value|
86
+ color = nil
87
+ value.gsub(/\s?,\s?/, ",").split(" ").each do |part|
88
+ color ||= ColorConversion::Color.new(part) rescue nil
162
89
  end
90
+ next unless color
163
91
 
164
- next unless hex
165
-
92
+ hex = color.hex.gsub("#", "")
166
93
  colors[hex] ? colors[hex] += 1 : colors[hex] = 1
167
94
  end
168
95
 
169
96
  # sort by colors with most occurrances
170
97
  colors
171
98
  end
172
-
173
- # convert rgb to hex
174
- def rgb_to_hex(rgb)
175
- r, g, b = rgb.split(",").map {|color| color.strip }
176
- "%02x" % r + "%02x" % g + "%02x" % b
177
- end
178
-
179
- # find hex for textual color
180
- def text_to_hex(color)
181
- ColorParser::Color.text_colors[color.intern]
182
- end
183
-
184
- # convert 3 digit hex to 6
185
- def normalize_hex(hex)
186
- (hex.length == 3 ? hex[0,1]*2 + hex[1,1]*2 + hex[2,1]*2: hex).downcase
187
- end
188
-
99
+
189
100
  end
190
101
  end
@@ -1,3 +1,3 @@
1
1
  module ColorParser
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.5"
3
3
  end
@@ -1,34 +1,34 @@
1
1
  /* color names - 008080 */
2
- div {
2
+ div.one {
3
3
  background-color: teal;
4
4
  }
5
5
 
6
6
  /* hex */
7
- div {
7
+ div.two {
8
8
  color: #386ec0;
9
9
  }
10
10
 
11
11
  /* hex short */
12
- div {
12
+ div.three {
13
13
  color: #c0c;
14
14
  }
15
15
 
16
16
  /* rgb -- 718ad7 */
17
- div {
17
+ div.four {
18
18
  color: rgb(113,138,215);
19
19
  }
20
20
 
21
21
  /* rgb spaces -- 3a5dc4 */
22
- div {
22
+ div.five {
23
23
  color: rgb(58, 93, 196);
24
24
  }
25
25
 
26
26
  /* rgba -- 29469e */
27
- div {
27
+ div.six {
28
28
  color: rgba(41,70,158,0.5);
29
29
  }
30
30
 
31
31
  /* rgba spaces -- 3f6aeb */
32
- div {
32
+ div.seven {
33
33
  color: rgba(63, 106, 235, 0.5);
34
34
  }