chico 0.1.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.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "gogetter"
4
+ gem "nokogiri", "~> 1.5.0"
5
+ gem "chunky_png"
6
+
7
+ group :development, :test do
8
+ gem "rspec", "~> 2.6.0"
9
+ gem "yard", "~> 0.7.2"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.4"
12
+ gem "fakeweb", "~> 1.3.0"
13
+ end
@@ -0,0 +1,36 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ chunky_png (1.2.1)
5
+ diff-lcs (1.1.2)
6
+ fakeweb (1.3.0)
7
+ git (1.2.5)
8
+ gogetter (0.1.0)
9
+ jeweler (1.6.4)
10
+ bundler (~> 1.0)
11
+ git (>= 1.2.5)
12
+ rake
13
+ nokogiri (1.5.0)
14
+ rake (0.9.2)
15
+ rspec (2.6.0)
16
+ rspec-core (~> 2.6.0)
17
+ rspec-expectations (~> 2.6.0)
18
+ rspec-mocks (~> 2.6.0)
19
+ rspec-core (2.6.4)
20
+ rspec-expectations (2.6.0)
21
+ diff-lcs (~> 1.1.2)
22
+ rspec-mocks (2.6.0)
23
+ yard (0.7.2)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 1.0.0)
30
+ chunky_png
31
+ fakeweb (~> 1.3.0)
32
+ gogetter
33
+ jeweler (~> 1.6.4)
34
+ nokogiri (~> 1.5.0)
35
+ rspec (~> 2.6.0)
36
+ yard (~> 0.7.2)
@@ -0,0 +1,13 @@
1
+ Copyright [2011] [Conduit Ltd.]
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,13 @@
1
+ = Chico
2
+
3
+ Chico fetches favicons from web pages and extracts PNG images from the ICO
4
+ format, all in native Ruby.
5
+
6
+ == Usage
7
+ icon_dir = Chico::Extractor.new(IO.read('google.ico'))
8
+
9
+ icons = image.entries
10
+ == Copyright
11
+
12
+ Copyright (c) 2011 Conduit Ltd.
13
+
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ gem.name = "chico"
17
+ gem.homepage = "http://github.com/ConduitTeam/chico"
18
+ gem.license = "Apache2"
19
+ gem.summary = %Q{Fetch favicons}
20
+ gem.email = "elad.kehat@conduit.com"
21
+ gem.authors = ["Elad Kehat", 'Ben Aviram']
22
+ ["gogetter",["nokogiri", "~> 1.5.0"], "chunky_png"].each do |dep|
23
+ gem.add_dependency *dep
24
+ end
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ task :default => :spec
35
+
36
+ require 'yard'
37
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,94 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "chico"
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Elad Kehat", "Ben Aviram"]
12
+ s.date = "2011-08-31"
13
+ s.email = "elad.kehat@conduit.com"
14
+ s.extra_rdoc_files = [
15
+ "LICENSE.txt",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".document",
20
+ ".rspec",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "chico.gemspec",
28
+ "lib/chico.rb",
29
+ "lib/chico/bitmapper.rb",
30
+ "lib/chico/extractor.rb",
31
+ "lib/chico/fetcher.rb",
32
+ "spec/chico/bitmapper_spec.rb",
33
+ "spec/chico/extractor_spec.rb",
34
+ "spec/chico/fetcher_spec.rb",
35
+ "spec/chico_spec.rb",
36
+ "spec/res/foxnews.ico",
37
+ "spec/res/google.ico",
38
+ "spec/res/microsoft.ico",
39
+ "spec/res/msn.ico",
40
+ "spec/res/nhl.ico",
41
+ "spec/res/sports.ico",
42
+ "spec/res/wikipedia.ico",
43
+ "spec/res/yahoo.ico",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+ s.homepage = "http://github.com/ConduitTeam/chico"
47
+ s.licenses = ["Apache2"]
48
+ s.require_paths = ["lib"]
49
+ s.rubygems_version = "1.8.10"
50
+ s.summary = "Fetch favicons"
51
+
52
+ if s.respond_to? :specification_version then
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<gogetter>, [">= 0"])
57
+ s.add_runtime_dependency(%q<nokogiri>, ["~> 1.5.0"])
58
+ s.add_runtime_dependency(%q<chunky_png>, [">= 0"])
59
+ s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
60
+ s.add_development_dependency(%q<yard>, ["~> 0.7.2"])
61
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
62
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
63
+ s.add_development_dependency(%q<fakeweb>, ["~> 1.3.0"])
64
+ s.add_runtime_dependency(%q<gogetter>, [">= 0"])
65
+ s.add_runtime_dependency(%q<nokogiri>, ["~> 1.5.0"])
66
+ s.add_runtime_dependency(%q<chunky_png>, [">= 0"])
67
+ else
68
+ s.add_dependency(%q<gogetter>, [">= 0"])
69
+ s.add_dependency(%q<nokogiri>, ["~> 1.5.0"])
70
+ s.add_dependency(%q<chunky_png>, [">= 0"])
71
+ s.add_dependency(%q<rspec>, ["~> 2.6.0"])
72
+ s.add_dependency(%q<yard>, ["~> 0.7.2"])
73
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
74
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
75
+ s.add_dependency(%q<fakeweb>, ["~> 1.3.0"])
76
+ s.add_dependency(%q<gogetter>, [">= 0"])
77
+ s.add_dependency(%q<nokogiri>, ["~> 1.5.0"])
78
+ s.add_dependency(%q<chunky_png>, [">= 0"])
79
+ end
80
+ else
81
+ s.add_dependency(%q<gogetter>, [">= 0"])
82
+ s.add_dependency(%q<nokogiri>, ["~> 1.5.0"])
83
+ s.add_dependency(%q<chunky_png>, [">= 0"])
84
+ s.add_dependency(%q<rspec>, ["~> 2.6.0"])
85
+ s.add_dependency(%q<yard>, ["~> 0.7.2"])
86
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
87
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
88
+ s.add_dependency(%q<fakeweb>, ["~> 1.3.0"])
89
+ s.add_dependency(%q<gogetter>, [">= 0"])
90
+ s.add_dependency(%q<nokogiri>, ["~> 1.5.0"])
91
+ s.add_dependency(%q<chunky_png>, [">= 0"])
92
+ end
93
+ end
94
+
@@ -0,0 +1,36 @@
1
+ require 'chico/extractor'
2
+ require 'chico/bitmapper'
3
+ require 'chico/fetcher'
4
+ require 'uri'
5
+
6
+ module Chico
7
+
8
+ def self.extract_from_file(filepath, dest_dir, options={})
9
+ ex = Extractor.new(IO.read(filepath))
10
+ basename = File.basename(filepath, File.extname(filepath))
11
+ ex.entries.each do |entry|
12
+ ext = "#{entry[:width]}x#{entry[:height]}"
13
+ content = ex.image_for(entry)
14
+ File.open(File.join(dest_dir, "#{basename}.#{ext}.png"), 'wb') do |f|
15
+ f.write content
16
+ end
17
+ end
18
+ end
19
+
20
+ def self.extract_from_url(url, dest_dir, options={})
21
+ fetcher = Fetecher.new(url)
22
+ ex = Extractor.new(fetcher.fetch)
23
+ write_to_files(ex, dest_dir, URI.parse(url).host)
24
+ end
25
+
26
+ private
27
+ def self.write_to_files(extractor, dest_dir, basename)
28
+ extractor.entries.each do |entry|
29
+ ext = "#{entry[:width]}x#{entry[:height]}"
30
+ content = extractor.image_for(entry)
31
+ File.open(File.join(dest_dir, "#{basename}.#{ext}.png"), 'wb') do |f|
32
+ f.write content
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,96 @@
1
+ # Unpack an ico bitmap
2
+ module Chico
3
+ class Bitmapper
4
+ attr_reader :pixels
5
+
6
+ def initialize(data, ico_direntry=nil)
7
+ @data = data
8
+ @ico_direntry = ico_direntry
9
+ end
10
+
11
+ def bitmap
12
+ parse_dib
13
+ @pixels = case @bits_per_pixel
14
+ when 0..8 then bitmap8
15
+ when 24 then bitmap24
16
+ when 32 then bitmap32
17
+ else raise "Unable to handle #{@bits_per_pixel} bits per pixel"
18
+ end
19
+ end
20
+
21
+ # Returns a String with the pixels,
22
+ # rgba, one byte per channel
23
+ def to_stream
24
+ sio = StringIO.new
25
+ @pixels.each {|p| sio.putc(p) }
26
+ sio.pos = 0
27
+ sio
28
+ end
29
+
30
+ def parse_dib
31
+ @offset = @data[0, 4].unpack('V').first
32
+ unless @offset == 40
33
+ raise "Unknown BMP format" # can't handle an ICO where the dib isn't 40 bytes
34
+ end
35
+
36
+ @width = @ico_direntry[:width] || @data[4, 4].unpack('V').first
37
+ @height = @ico_direntry[:height] || @data[8, 4].unpack('V').first
38
+ @bits_per_pixel = @data[14, 2].unpack('v').first
39
+ @image_size = @data[24, 4].unpack('V').first
40
+ if @image_size == 0
41
+ @image_size = @width * @height * @bits_per_pixel / 8
42
+ end
43
+ end
44
+
45
+ def bitmap8
46
+ # assemble the color palette
47
+ color_count = 2 ** @bits_per_pixel
48
+ raw_colors = (0...color_count).map {|i| @data[@offset + 4 * i, 4].unpack('CCCC') }
49
+ #puts "raw colors: " + raw_colors.inspect
50
+ # the RGBQUAD for each palette color is (blue, green, red, reserved)
51
+ palette = raw_colors.map {|raw| raw.values_at(2, 1, 0) }
52
+ # get the XorMap bits
53
+ xor_data_bits = (0...@image_size).map {|i|
54
+ @data[@offset + 4 * color_count + i].unpack('B8').first.split('').map(&:to_i)
55
+ }.flatten
56
+ # get the AndMap bits
57
+ and_row_size = ((@width + 31) >> 5) << 2
58
+ and_data_bits = (0...(and_row_size * @height)).map {|i|
59
+ @data[@offset + 4 * color_count + @image_size].unpack('B8').first.split('').map(&:to_i)
60
+ }.flatten
61
+ get_pixel = ->(x, y) {
62
+ if and_data_bits[(@height - y - 1) * and_row_size * 8 + x] == '1'
63
+ [0, 0, 0, 0] # transparent
64
+ else
65
+ # use the xor value, made solid
66
+ bits = xor_data_bits[@bits_per_pixel * ((@height - y - 1) * @width + x), @bits_per_pixel]
67
+ palette[bits.reduce(0) {|acc, bit| 2 * acc + bit }] + [255]
68
+ end
69
+ }
70
+ (0...@height).map { |y|
71
+ (0...@width).map { |x|
72
+ get_pixel.call(x, y)
73
+ }
74
+ }.flatten
75
+ end
76
+
77
+ def bitmap32
78
+ (0...@height).to_a.reverse.map { |y|
79
+ (0...@width).map { |x|
80
+ pos = @offset + 4 * (y * @width + x)
81
+ #puts "data[#{pos}] = #{@data[pos]}"
82
+ @data[@offset + 4 * (y * @width + x), 4].unpack('CCCC').values_at(2, 1, 0, 3)
83
+ }
84
+ }.flatten
85
+ end
86
+
87
+ def bitmap24
88
+ (0...@height-1).to_a.reverse.map { |y|
89
+ (0...@width).map { |x|
90
+ @data[@offset + 3 * (y * @width + x), 3].unpack('CCC').values_at(2, 1, 0) + [255]
91
+ }
92
+ }.flatten
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,102 @@
1
+ require 'chunky_png'
2
+ module Chico
3
+ # Extracts icons images (bmp / png) from an .ico file
4
+ class Extractor
5
+ attr_reader :entries
6
+
7
+ def initialize(bin)
8
+ @sio = StringIO.new(bin, 'rb')
9
+ @entries = []
10
+ parse_icondir
11
+ end
12
+
13
+ def num_images
14
+ @entries.size
15
+ end
16
+
17
+ # Returns the sizes of the images packed in this icon, as width, height pairs,
18
+ # sorted from smallest to largest width
19
+ def image_sizes
20
+ @entries.map {|e| [e[:width], e[:height]] }.sort
21
+ end
22
+
23
+ # Add support for retrieving images by their size, e.g. 32x32, 16x16, etc.
24
+ def method_missing(sym, *args, &block)
25
+ if sym.to_s =~ /^(\d+)x(\d+)$/
26
+ image_by_size $1, $2
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ def largest
33
+ w, h = image_sizes.last
34
+ self.send "#{w}x#{h}".to_sym
35
+ end
36
+
37
+ def smallest
38
+ w, h = image_sizes.first
39
+ self.send "#{w}x#{h}".to_sym
40
+ end
41
+
42
+ def image_for(entry)
43
+ extract_image(entry)
44
+ end
45
+
46
+ private
47
+
48
+ def parse_icondir
49
+ unless [read(2), read(2)] == [0, 1]
50
+ raise "Not a valid icon"
51
+ end
52
+ count = read 2 # number of icons in this file
53
+ count.times { parse_icondirentry }
54
+ end
55
+
56
+ ICONDIRENTRY_KEYS = [:width, 1, :height, 1, :colors, 1, :reserved, 1, :planes, 2, :bit_count, 2, :size, 4, :offset, 4].freeze
57
+
58
+ def parse_icondirentry
59
+ entry = {}
60
+ ICONDIRENTRY_KEYS.each_slice(2) {|pair| entry[pair[0]] = read(pair[1]) }
61
+ [:width, :height, :colors].each {|key| entry[key] = 256 if entry[key] == 0 }
62
+ @entries << entry
63
+ end
64
+
65
+ # Extract the first image of the given size, or returns nil if no such image is found
66
+ def image_by_size(width, height)
67
+ if entry = @entries.find {|e| e[:width] == width && e[:height] == height }
68
+ extract_image entry
69
+ end
70
+ end
71
+
72
+ # Extract the image file that corresponds to the given icondirentry
73
+ def extract_image(entry)
74
+ @sio.pos = entry[:offset]
75
+ raw = @sio.read(entry[:size])
76
+ if png?(raw)
77
+ raw
78
+ else
79
+ bmp = Bitmapper.new(raw, entry)
80
+ bmp.bitmap
81
+ ChunkyPNG::Image.from_rgba_stream(entry[:width], entry[:height], bmp.to_stream)
82
+ end
83
+ end
84
+
85
+ # detect a png header
86
+ def png?(raw)
87
+ raw.slice(0, 8).unpack('H*').first == "89504e470d0a1a0a"
88
+ end
89
+
90
+ # Read len bytes from @sio and unpack them
91
+ def read(len)
92
+ format = case len
93
+ when 1 then 'C'
94
+ when 2 then 'S'
95
+ when 4 then 'L'
96
+ end
97
+
98
+ @sio.read(len).unpack(format).first
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,81 @@
1
+ require 'gogetter'
2
+ require 'nokogiri'
3
+ module Chico
4
+
5
+ # How it works:
6
+ # When given a domain w/o a path, try to find /favicon.ico
7
+ # If not found (or given a path), load the home page and search for one of:
8
+ # * <link rel="shortcut icon" href="http://example.com/myicon.ico" />
9
+ # * <link rel="icon" type="image/vnd.microsoft.icon" href="http://example.com/image.ico" />
10
+ # * <link rel="icon" type="image/png" href="http://example.com/image.png" />
11
+ # * <link rel="icon" type="image/gif" href="http://example.com/image.gif" />
12
+ # If given a path, and the above didn't work, retry on the domain's index page
13
+ class Fetcher
14
+ attr_reader :url, :searched_icon
15
+
16
+ def initialize(url)
17
+ @url = url
18
+ @uri = GoGetter.parse_url @url
19
+ end
20
+
21
+ def fetch(uri=@uri)
22
+ if @uri.path == '/'
23
+ fetch_default || fetch_link_on_page(@url)
24
+ else
25
+ # try to find a favicon for the specific path first
26
+ if path = fetch_link_on_page(@url)
27
+ fetch_icon path
28
+ else
29
+ # if failed, try again with the root path
30
+
31
+ end
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def fetch_default
38
+ fetch_icon '/favicon.ico'
39
+ end
40
+
41
+ def fetch_icon(path)
42
+ uri = @uri.clone
43
+ uri.path = path
44
+ res = GoGetter.get uri
45
+ if res.is_a? Net::HTTPOK
46
+ @searched_icon = uri.path
47
+ @raw = res.body
48
+ end
49
+ end
50
+
51
+ ICON_XPATHS = [
52
+ "link[@rel='shortcut icon']",
53
+ "link[@rel='icon']"
54
+ ]
55
+ def fetch_link_on_page(url)
56
+ icon_url = find_link_on_page url
57
+ icon_url = Fetcher.make_relative(icon_url)
58
+ if !icon_url.to_s.empty?
59
+ fetch_icon icon_url
60
+ end
61
+ end
62
+
63
+ def find_link_on_page(url)
64
+ res = GoGetter.get url
65
+ if res.is_a? Net::HTTPOK
66
+ doc = Nokogiri res.body
67
+ ICON_XPATHS.each do |xpath|
68
+ if link = doc.at(xpath)
69
+ return link[:href]
70
+ end
71
+ end
72
+ return ""
73
+ end
74
+ end
75
+
76
+ def self.make_relative(url)
77
+ URI.parse(url).path
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Chico" do
4
+ describe "Bitmapper" do
5
+
6
+ describe "#parse_dib" do
7
+ before(:all) do
8
+ class Chico::Bitmapper
9
+ attr_reader :offset, :width, :height, :bits_per_pixel, :image_size
10
+ end
11
+ raw16 = load_res_file('microsoft.16x16.raw')
12
+ @bitmapper16 = Chico::Bitmapper.new(raw16)
13
+ @bitmapper16.parse_dib
14
+ raw32 = load_res_file('microsoft.32x32.raw')
15
+ @bitmapper32 = Chico::Bitmapper.new(raw32)
16
+ @bitmapper32.parse_dib
17
+ end
18
+
19
+ it "reads the correct dib offset" do
20
+ @bitmapper16.offset.should == 40
21
+ @bitmapper32.offset.should == 40
22
+ end
23
+
24
+ it "extracts the correct width" do
25
+ @bitmapper16.width.should == 16
26
+ @bitmapper32.width.should == 32
27
+ end
28
+
29
+ it "extracts the correct height" do
30
+ @bitmapper16.height.should == 16
31
+ @bitmapper32.height.should == 32
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Chico" do
4
+ describe "Extractor" do
5
+
6
+ describe "#initialize" do
7
+ it "parses the icondir entries" do
8
+ ex = Chico::Extractor.new(load_icon_file('microsoft'))
9
+ ex.should have_exactly(2).entries
10
+ ex.entries[0][:width].should == 32
11
+ ex.entries[1][:width].should == 16
12
+ end
13
+ end
14
+
15
+ describe "#num_images" do
16
+ it "returns the number of images contained in the ico file" do
17
+ ex = Chico::Extractor.new(load_icon_file('microsoft'))
18
+ ex.num_images.should == 2
19
+ end
20
+ end
21
+
22
+ describe "#image_sizes" do
23
+ it "returns a sorted list of contained image width,height pairs" do
24
+ ex = Chico::Extractor.new(load_icon_file('microsoft'))
25
+ ex.image_sizes.should eql([[16,16],[32,32]])
26
+ end
27
+ end
28
+
29
+
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Chico" do
4
+ describe "Fetcher" do
5
+ describe "#fetch" do
6
+ it "founds website with default favicon" do
7
+ fetcher = Chico::Fetcher.new('http://microsoft.com/')
8
+ fetcher.fetch().length.should > 0
9
+ fetcher.searched_icon.should == "/favicon.ico"
10
+ end
11
+ it "founds favicon for website without default favicon" do
12
+ fetcher = Chico::Fetcher.new('http://video.foxnews.com')
13
+ fetcher.fetch().length.should > 0
14
+ fetcher.searched_icon.should == '/images/foxnews/favicon.ico'
15
+ end
16
+ end
17
+ describe "#make_relative" do
18
+ it "returns the relative part from full url" do
19
+ Chico::Fetcher.make_relative('http://video.foxnews.com/icon.ico').should == '/icon.ico'
20
+ end
21
+ it "returns the param from relative url" do
22
+ Chico::Fetcher.make_relative('/icon.ico').should == '/icon.ico'
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Chico" do
4
+ path = File.expand_path("res/temp", File.dirname(__FILE__))
5
+ it "Extracts ico bmps as pngs" do
6
+ filepath = File.join(File.dirname(__FILE__), 'res', "msn.ico")
7
+ ex = Chico::Extractor.new(IO.read(filepath))
8
+ basename = File.basename(filepath, File.extname(filepath))
9
+ ex.entries.each do |entry|
10
+ ext = "#{entry[:width]}x#{entry[:height]}"
11
+ content = ex.image_for(entry)
12
+ if !File.directory? path
13
+ Dir.mkdir(path)
14
+ end
15
+ File.open(File.join(File.dirname(__FILE__), 'res/temp', "#{basename}.#{ext}.png"), 'wb') do |f|
16
+ f.write content
17
+ end
18
+ end
19
+ end
20
+
21
+ it "Extracts icon from website markup" do
22
+ imageDir = Chico::extract_from_url('http://video.foxnews.com', path)
23
+ imageDir.length.should == 1
24
+ end
25
+ it "Extracts icon from website default favicon" do
26
+ imageDir = Chico::extract_from_url('http://microsoft.com', path)
27
+ imageDir.length.should == 2
28
+ end
29
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,22 @@
1
+ require 'bundler'
2
+ Bundler.require(:default, :test)
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ require 'rspec'
6
+ require 'chico'
7
+
8
+ # Requires supporting files with custom matchers and macros, etc,
9
+ # in ./support/ and its subdirectories.
10
+ #Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
+
12
+ def load_icon_file(name)
13
+ IO.read(File.join(File.dirname(__FILE__), 'res', "#{name}.ico"))
14
+ end
15
+
16
+ def load_res_file(name)
17
+ IO.read(File.join(File.dirname(__FILE__), 'res', name))
18
+ end
19
+
20
+ RSpec.configure do |config|
21
+
22
+ end
metadata ADDED
@@ -0,0 +1,198 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chico
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Elad Kehat
9
+ - Ben Aviram
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-08-31 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: gogetter
17
+ requirement: &75086960 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *75086960
26
+ - !ruby/object:Gem::Dependency
27
+ name: nokogiri
28
+ requirement: &75086720 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.5.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *75086720
37
+ - !ruby/object:Gem::Dependency
38
+ name: chunky_png
39
+ requirement: &75086480 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *75086480
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ requirement: &75086240 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 2.6.0
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *75086240
59
+ - !ruby/object:Gem::Dependency
60
+ name: yard
61
+ requirement: &75086000 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 0.7.2
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *75086000
70
+ - !ruby/object:Gem::Dependency
71
+ name: bundler
72
+ requirement: &75085760 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.0.0
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *75085760
81
+ - !ruby/object:Gem::Dependency
82
+ name: jeweler
83
+ requirement: &75085520 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: 1.6.4
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: *75085520
92
+ - !ruby/object:Gem::Dependency
93
+ name: fakeweb
94
+ requirement: &75085280 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ~>
98
+ - !ruby/object:Gem::Version
99
+ version: 1.3.0
100
+ type: :development
101
+ prerelease: false
102
+ version_requirements: *75085280
103
+ - !ruby/object:Gem::Dependency
104
+ name: gogetter
105
+ requirement: &75105850 !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ type: :runtime
112
+ prerelease: false
113
+ version_requirements: *75105850
114
+ - !ruby/object:Gem::Dependency
115
+ name: nokogiri
116
+ requirement: &75105610 !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ~>
120
+ - !ruby/object:Gem::Version
121
+ version: 1.5.0
122
+ type: :runtime
123
+ prerelease: false
124
+ version_requirements: *75105610
125
+ - !ruby/object:Gem::Dependency
126
+ name: chunky_png
127
+ requirement: &75105370 !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :runtime
134
+ prerelease: false
135
+ version_requirements: *75105370
136
+ description:
137
+ email: elad.kehat@conduit.com
138
+ executables: []
139
+ extensions: []
140
+ extra_rdoc_files:
141
+ - LICENSE.txt
142
+ - README.rdoc
143
+ files:
144
+ - .document
145
+ - .rspec
146
+ - Gemfile
147
+ - Gemfile.lock
148
+ - LICENSE.txt
149
+ - README.rdoc
150
+ - Rakefile
151
+ - VERSION
152
+ - chico.gemspec
153
+ - lib/chico.rb
154
+ - lib/chico/bitmapper.rb
155
+ - lib/chico/extractor.rb
156
+ - lib/chico/fetcher.rb
157
+ - spec/chico/bitmapper_spec.rb
158
+ - spec/chico/extractor_spec.rb
159
+ - spec/chico/fetcher_spec.rb
160
+ - spec/chico_spec.rb
161
+ - spec/res/foxnews.ico
162
+ - spec/res/google.ico
163
+ - spec/res/microsoft.ico
164
+ - spec/res/msn.ico
165
+ - spec/res/nhl.ico
166
+ - spec/res/sports.ico
167
+ - spec/res/wikipedia.ico
168
+ - spec/res/yahoo.ico
169
+ - spec/spec_helper.rb
170
+ homepage: http://github.com/ConduitTeam/chico
171
+ licenses:
172
+ - Apache2
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ! '>='
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ segments:
184
+ - 0
185
+ hash: -726080447
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ none: false
188
+ requirements:
189
+ - - ! '>='
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubyforge_project:
194
+ rubygems_version: 1.8.10
195
+ signing_key:
196
+ specification_version: 3
197
+ summary: Fetch favicons
198
+ test_files: []