color_parser 0.1.0 → 1.0.5

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