color_parser 0.0.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +0 -2
  4. data/Guardfile +9 -0
  5. data/README.md +17 -26
  6. data/Rakefile +18 -6
  7. data/color_parser.gemspec +10 -2
  8. data/lib/color_parser.rb +3 -134
  9. data/lib/color_parser/errors.rb +3 -0
  10. data/lib/color_parser/page.rb +14 -57
  11. data/lib/color_parser/stylesheet.rb +27 -123
  12. data/lib/color_parser/version.rb +1 -1
  13. data/{test → spec}/fixtures/css_color/frequency.html +0 -0
  14. data/{test → spec}/fixtures/css_color/stylesheets/color_styles.css +7 -7
  15. data/{test → spec}/fixtures/css_color/stylesheets/css_elements.css +0 -0
  16. data/{test → spec}/fixtures/css_color/stylesheets/frequency.css +9 -9
  17. data/{test → spec}/fixtures/css_color/stylesheets/imported_selectors.css +0 -0
  18. data/{test → spec}/fixtures/css_color/stylesheets/properties.css +0 -0
  19. data/spec/page_spec.rb +39 -0
  20. data/spec/spec_helper.rb +10 -0
  21. data/{test/test_request.rb → spec/stubs/fake_request.rb} +2 -2
  22. data/spec/stylesheet_spec.rb +125 -0
  23. data/spec/version_spec.rb +9 -0
  24. metadata +114 -123
  25. data/lib/color_parser/image.rb +0 -20
  26. data/test/color_parser_test.rb +0 -83
  27. data/test/fixtures/css/absolute.html +0 -15
  28. data/test/fixtures/css/inline.html +0 -34
  29. data/test/fixtures/css/inline_import.html +0 -16
  30. data/test/fixtures/css/invalid.html +0 -15
  31. data/test/fixtures/css/relative.html +0 -15
  32. data/test/fixtures/css/relative_root.html +0 -15
  33. data/test/fixtures/css/stylesheets/colors.css +0 -0
  34. data/test/fixtures/css/stylesheets/fonts.css +0 -0
  35. data/test/fixtures/css/stylesheets/print.css +0 -3
  36. data/test/fixtures/css/stylesheets/screen.css +0 -16
  37. data/test/fixtures/css_images/images/apple.png +0 -0
  38. data/test/fixtures/css_images/images/cantaloupe.png +0 -0
  39. data/test/fixtures/css_images/images/kiwi.jpg +0 -0
  40. data/test/fixtures/css_images/images/mango.png +0 -0
  41. data/test/fixtures/css_images/images/pineapple.png +0 -0
  42. data/test/fixtures/css_images/paths.html +0 -14
  43. data/test/fixtures/css_images/stylesheets/import_paths.css +0 -4
  44. data/test/fixtures/css_images/stylesheets/paths.css +0 -17
  45. data/test/fixtures/css_images/stylesheets/quotes.css +0 -14
  46. data/test/fixtures/css_import/index.html +0 -15
  47. data/test/fixtures/css_import/stylesheets/borders.css +0 -0
  48. data/test/fixtures/css_import/stylesheets/colors.css +0 -0
  49. data/test/fixtures/css_import/stylesheets/fonts.css +0 -3
  50. data/test/fixtures/css_import/stylesheets/ie.css +0 -3
  51. data/test/fixtures/css_import/stylesheets/images.css +0 -0
  52. data/test/fixtures/css_import/stylesheets/master.css +0 -12
  53. data/test/fixtures/css_import/stylesheets/print.css +0 -3
  54. data/test/fixtures/css_import/stylesheets/screen.css +0 -12
  55. data/test/fixtures/inline_images/absolute.html +0 -14
  56. data/test/fixtures/inline_images/images/apple.png +0 -0
  57. data/test/fixtures/inline_images/images/kiwi.jpg +0 -0
  58. data/test/fixtures/inline_images/relative.html +0 -14
  59. data/test/fixtures/inline_images/relative_root.html +0 -14
  60. data/test/image_test.rb +0 -27
  61. data/test/page_test.rb +0 -194
  62. data/test/stylesheet_test.rb +0 -257
  63. data/test/test_helper.rb +0 -6
  64. data/test/version_test.rb +0 -7
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 87fb5246ee611764195e313bb830a0b6a857e843248edb939a9eb88bc4864942
4
+ data.tar.gz: 06747e256d940da5ecc6c33dd7ec2b8be38737a14bc7addf3b560fe4401a0f59
5
+ SHA512:
6
+ metadata.gz: 2ff0fbc960fde8b9d9e31e8a0cc65c0b106af820d27aaf41199301129a17683cbd7baebfe85dd492f8fda91029a3d84111f83f8977aa3416fde2081f12406ebf
7
+ data.tar.gz: 1abfe0694f4121e473501ac9ad8da90362a6b350c8b50e24af464f8733bdc6c63a0acbd988566362a35c5f2abf6a1a6a08a9255fb6aba59b7e02bbbf32bdb093
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  .bundle
5
5
  .config
6
6
  .yardoc
7
+ .rspec
7
8
  Gemfile.lock
8
9
  InstalledFiles
9
10
  _yardoc
@@ -16,3 +17,4 @@ spec/reports
16
17
  test/tmp
17
18
  test/version_tmp
18
19
  tmp
20
+ bin
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
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/color_parser/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/README.md CHANGED
@@ -1,43 +1,34 @@
1
1
  ## ColorParser
2
2
 
3
- The ColorParser gem provides a simple way to parse the colors from an html page or CSS file. It works with both local and remote resources.
3
+ The ColorParser gem provides a simple way to parse the colors from an HTML page.
4
+ It scans both the HTML and CSS to find all colors and sort them by frequency
5
+ used.
4
6
 
5
7
  ## Example
6
8
 
9
+ Get colors on a given webpage
10
+
7
11
  ```ruby
8
- page = ColorParser::Page.new("http://sportspyder.com/")
12
+ page = ColorParser::Page.new("http://google.com/")
9
13
  colors = page.colors
14
+ => {"ffffff"=>5, "c9d7f1"=>1, "0000cc"=>2, "dd8e27"=>1, "990000"=>1,
15
+ "3366cc"=>3, "000000"=>2, "1111cc"=>5, "cccccc"=>2, "551a8b"=>1}
16
+
17
+ colors = page.colors_by_frequency
18
+ => ["ffffff", "1111cc", "3366cc", "000000", "cccccc",
19
+ "0000cc", "dd8e27", "c9d7f1", "990000", "551a8b"]
10
20
  ```
11
21
 
12
22
  ## Installation
13
23
 
14
- ```
15
- gem install color_parser
16
- ```
17
- ```
24
+ To install ColorParser, add the gem to your Gemfile:
25
+
26
+ ```ruby
18
27
  gem "color_parser"
19
28
  ```
20
29
 
21
30
  ## LICENSE
22
31
 
23
- (The MIT License)
24
-
25
- Copyright © 2012 [Derek DeVries](https://github.com/devrieda/)
26
-
27
- Permission is hereby granted, free of charge, to any person obtaining a
28
- copy of this software and associated documentation files (the "Software"),
29
- to deal in the Software without restriction, including without
30
- limitation the rights to use, copy, modify, merge, publish, distribute,
31
- sublicense, and/or sell copies of the Software, and to permit persons
32
- to whom the Software is furnished to do so, subject to the following conditions:
33
-
34
- The above copyright notice and this permission notice shall be included
35
- in all copies or substantial portions of the Software.
32
+ Copyright (c) 2013 Derek DeVries
36
33
 
37
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
40
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
41
- OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
42
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
43
- OTHER DEALINGS IN THE SOFTWARE.
34
+ Released under the [MIT License](http://www.opensource.org/licenses/MIT)
data/Rakefile CHANGED
@@ -1,10 +1,22 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
- require 'rake/testtask'
4
3
 
5
- Rake::TestTask.new do |t|
6
- t.libs << 'lib/color_parser'
7
- t.test_files = FileList['test/**/*_test.rb']
8
- t.verbose = true
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new
7
+
8
+ namespace :spec do
9
+ desc 'Run unit specs only'
10
+ RSpec::Core::RakeTask.new(:unit) do |task|
11
+ task.pattern = 'spec'
12
+ task.rspec_opts = '--tag "~live"'
13
+ end
14
+
15
+ desc 'Run acceptance specs only'
16
+ RSpec::Core::RakeTask.new(:acceptance) do |task|
17
+ task.pattern = 'spec'
18
+ task.rspec_opts = '--tag "live"'
19
+ end
9
20
  end
10
- task :default => :test
21
+
22
+ task :default => :spec
@@ -6,7 +6,7 @@ require 'color_parser/version'
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "color_parser"
8
8
  gem.version = ColorParser::VERSION
9
- gem.summary = %q{Color Parser finds the colors on a given webpage}
9
+ gem.summary = %q{Finds colors on a given webpage}
10
10
  gem.description = gem.summary
11
11
 
12
12
  gem.required_ruby_version = '>= 1.9.3'
@@ -20,7 +20,15 @@ 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("stylesheet", "~> 0.1.7")
25
+ gem.add_runtime_dependency("color_conversion", "~> 0.1.0")
23
26
 
24
- gem.add_runtime_dependency("nokogiri", "~> 1.5")
25
27
  gem.add_development_dependency("rake")
28
+ gem.add_development_dependency("rspec", "~> 2.9")
29
+
30
+ # guard
31
+ gem.add_development_dependency("guard", "~> 1.7")
32
+ gem.add_development_dependency("guard-rspec", "~> 2.5")
33
+ gem.add_development_dependency("rb-fsevent", "~> 0.9")
26
34
  end
@@ -1,142 +1,11 @@
1
- require 'net/http'
2
1
  require 'uri'
3
- require 'nokogiri'
2
+ require 'stylesheet'
3
+ require 'color_conversion'
4
4
 
5
+ require 'color_parser/errors'
5
6
  require 'color_parser/version'
6
7
  require 'color_parser/page'
7
8
  require 'color_parser/stylesheet'
8
- require 'color_parser/image'
9
9
 
10
10
  module ColorParser
11
-
12
- # Build url of an asset based on the relative/absolute url
13
- def self.parse_asset(doc_url, asset_url)
14
- doc_host, doc_path, doc_query = self.parse_url(doc_url)
15
- asset_host, asset_path, asset_query = self.parse_url(asset_url)
16
-
17
- # absolute path
18
- host, path, query = if asset_url.include?("http")
19
- [asset_host, asset_path, asset_query]
20
-
21
- # root relative
22
- elsif asset_url[0,1] == "/"
23
- [doc_host, asset_path, asset_query]
24
-
25
- # relative
26
- else
27
- path = File.expand_path("#{doc_path.gsub(/[^\/]*$/, "")}#{asset_path}", "/")
28
- [doc_host, path, asset_query]
29
- end
30
-
31
- "http://#{host}#{path}#{"?"+query if query}"
32
- end
33
-
34
- # parse url parts
35
- def self.parse_url(url)
36
- begin
37
- uri = URI.parse(url.strip)
38
- rescue URI::InvalidURIError
39
- uri = URI.parse(URI.escape(url.strip))
40
- end
41
-
42
- [uri.host, (uri.path != "" ? uri.path : "/"), uri.query]
43
- end
44
-
45
-
46
- # Request
47
-
48
- def self.request=(request)
49
- @request = request
50
- end
51
-
52
- def self.request
53
- @request ||= Request.new
54
- end
55
-
56
- # Request an asset
57
- #
58
- class Request
59
- @@last_request = Time.now
60
-
61
- # default throttle requests 1 per sec
62
- def initialize(params={})
63
- @throttle = params[:throttle] || 1
64
- end
65
-
66
- def get(url)
67
- throttle
68
-
69
- begin
70
- uri = URI.parse(url.strip)
71
- rescue URI::InvalidURIError
72
- uri = URI.parse(URI.escape(url.strip))
73
- end
74
-
75
- response = get_response(uri)
76
-
77
- # redirect
78
- @prev_redirect ||= ""
79
- if response.header['location']
80
- # make sure we're not in an infinite loop
81
- if response.header['location'] == @prev_redirect
82
- raise HTTPError, "Recursive redirect: #{@prev_redirect}"
83
- end
84
- @prev_redirect = response.header['location']
85
-
86
- return get(response.header['location'])
87
- end
88
-
89
- # bad req
90
- if response.to_s.index 'Bad Request' || response.nil?
91
- raise HTTPError, "invalid HTTP request #{url}"
92
- end
93
-
94
- response = fix_encoding(response)
95
- response.body
96
- end
97
-
98
- def user_agent
99
- "ColorParser Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7"
100
- end
101
-
102
-
103
- private
104
-
105
- # Use charset in content-type, default to UTF-8 if absent
106
- #
107
- # text/html; charset=UTF-8
108
- # - or -
109
- # text/html; charset=iso-8859-1
110
- # - or -
111
- # text/html
112
- def fix_encoding(response)
113
- charset = if response.header["Content-Type"].to_s.include?("charset")
114
- response.header["Content-Type"].split(";")[1].split("=")[1]
115
- else
116
- "UTF-8"
117
- end
118
-
119
- response.body.force_encoding(charset.upcase).encode("UTF-8")
120
- response
121
- end
122
-
123
- # build http request object
124
- def get_response(uri)
125
- http = Net::HTTP.new(uri.host, uri.port)
126
- http.open_timeout = 15
127
- http.read_timeout = 30
128
-
129
- request = Net::HTTP::Get.new(uri.request_uri)
130
- request["User-Agent"] = user_agent
131
-
132
- http.request(request)
133
- end
134
-
135
- # throttle requests to 1 per sec
136
- def throttle
137
- sleep @throttle if @@last_request + @throttle > Time.now
138
- @@last_request = Time.now
139
- end
140
- end
141
-
142
11
  end
@@ -0,0 +1,3 @@
1
+ module ColorParser
2
+ class Error < StandardError; end
3
+ 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,32 +1,9 @@
1
1
  module ColorParser
2
- # a set of css selectors
3
- class Stylesheet
4
- TEXT_COLORS = {
5
- aqua: "00ffff", black: "000000", blue: "0000ff",
6
- fuchsia: "ff00ff", gray: "808080", green: "008000",
7
- lime: "00ff00", maroon: "800000", navy: "000080",
8
- olive: "808000", purple: "800080", red: "ff0000",
9
- silver: "c0c0c0", teal: "008080", white: "ffffff",
10
- yellow: "ffff00"
11
- }
12
2
 
13
- attr_reader :url, :type, :host, :path, :query, :text
3
+ class Stylesheet
14
4
 
15
- def initialize(options)
16
- @type = options[:type]
17
- @text = options[:text]
18
- @url = options[:url]
19
-
20
- @host, @path, @query = ColorParser.parse_url(url)
21
- end
22
-
23
- def name
24
- path.split("/").last
25
- end
26
-
27
- # get imported stylesheets
28
- def stylesheets
29
- @stylesheets ||= imported_stylesheets
5
+ def initialize(style_sheet)
6
+ @style_sheet = style_sheet
30
7
  end
31
8
 
32
9
  # gst list of colors from styles
@@ -37,87 +14,44 @@ module ColorParser
37
14
  def bg_colors
38
15
  @bg_colors ||= parse_colors(bg_properties)
39
16
  end
40
-
17
+
41
18
  def text_colors
42
19
  @text_colors ||= parse_colors(text_properties)
43
20
  end
44
-
21
+
45
22
  def border_colors
46
23
  @border_colors ||= parse_colors(border_properties)
47
24
  end
48
25
 
49
-
50
- def images
51
- images = []
52
-
53
- image_properties.each do |key, value|
54
- if value.include?("url") && match = value.match(/url\(['"]?([^'")]+)/)
55
- asset_url = ColorParser.parse_asset(url, match[1])
56
- images << Image.new(asset_url)
57
- end
58
- end
59
-
60
- images
61
- end
62
-
63
-
64
- # groups of css selectors (including imported styles)
65
- def selectors
66
- selectors = {}
67
-
68
- text.scan(/([^\s\}]+)[\s]*?\{(.*?)\}/m).each do |match|
69
- selector, rule = match
70
- selectors[selector] ||= []
71
- selectors[selector] << rule.strip
72
- end
73
-
74
- # imported styles
75
- stylesheets.each do |style|
76
- style.selectors.each do |selector, rule|
77
- selectors[selector] ||= []
78
- 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)
79
33
  end
80
34
  end
81
35
 
82
- selectors
36
+ rules
83
37
  end
84
38
 
85
39
  # split up selectors into properties, and return property key/value pairs
86
40
  def properties
87
41
  properties = []
88
42
 
89
- selectors.each do |selector, rules|
90
- rules.each do |rule|
91
- rule.split(";").each do |property|
92
- props = property.split(":", 2).map {|v| v.strip }
93
- properties << props if props.size == 2
94
- end
95
- end
43
+ rules.values.each do |declarations|
44
+ declarations.each {|property, value| properties << [property, value] }
96
45
  end
97
-
46
+
98
47
  properties
99
48
  end
100
49
 
101
-
102
50
  private
103
51
 
104
- def imported_stylesheets
105
- return [] unless text.include?("@import")
106
-
107
- styles = []
108
- text.scan(/@import(?:\surl|\s)(.*?)[;\n]+/).each do |style|
109
- style_path = style.first.gsub(/['"\(\);]/, "")
110
-
111
- asset_url = ColorParser.parse_asset(url, style_path)
112
- next unless text = ColorParser.request.get(asset_url)
113
-
114
- css = Stylesheet.new(text: text,
115
- type: "imported",
116
- url: asset_url)
117
- styles << css
118
- end
119
-
120
- styles
52
+ # get imported stylesheets
53
+ def style_sheets
54
+ @style_sheets ||= @style_sheet.import_rules.map {|rule| rule.style_sheet }
121
55
  end
122
56
 
123
57
  # find properties that might have a color
@@ -128,7 +62,7 @@ module ColorParser
128
62
  "border-left-color", "color", "outline-color"].include?(key)
129
63
  end
130
64
  end
131
-
65
+
132
66
  # properties with bg colors
133
67
  def bg_properties
134
68
  color_properties.select {|key, value| key.include?("background") }
@@ -146,52 +80,22 @@ module ColorParser
146
80
  end
147
81
  end
148
82
 
149
- # find properties that might have an image
150
- def image_properties
151
- color_properties.select {|key, value| key.include?("background") }
152
- end
153
-
154
83
  def parse_colors(property_list)
155
84
  colors = {}
156
-
157
- property_list.each do |key, value|
158
- # hex
159
- hex = if matches = value.match(/#([0-9a-f]{3,6})/i)
160
- normalize_hex(matches[1])
161
-
162
- # rgb/rgba
163
- elsif matches = value.match(/rgba?\((\d{1,3}[,\s]+\d{1,3}[,\s]+\d{1,3})/)
164
- rgb_to_hex(matches[1])
165
-
166
- # textual
167
- elsif matches = value.match(/(#{TEXT_COLORS.map {|k,v| k }.join("|")})/)
168
- 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
169
89
  end
90
+ next unless color
170
91
 
171
- next unless hex
172
-
92
+ hex = color.hex.gsub("#", "")
173
93
  colors[hex] ? colors[hex] += 1 : colors[hex] = 1
174
94
  end
175
95
 
176
96
  # sort by colors with most occurrances
177
97
  colors
178
98
  end
179
-
180
- # convert rgb to hex
181
- def rgb_to_hex(rgb)
182
- r, g, b = rgb.split(",").map {|color| color.strip }
183
- "%02x" % r + "%02x" % g + "%02x" % b
184
- end
185
-
186
- # find hex for textual color
187
- def text_to_hex(color)
188
- TEXT_COLORS[color.intern]
189
- end
190
-
191
- # convert 3 digit hex to 6
192
- def normalize_hex(hex)
193
- (hex.length == 3 ? hex[0,1]*2 + hex[1,1]*2 + hex[2,1]*2: hex).downcase
194
- end
195
-
99
+
196
100
  end
197
101
  end