facehugger 0.0.0 → 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.
data/Gemfile CHANGED
@@ -3,6 +3,10 @@ source "http://rubygems.org"
3
3
  # Example:
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
 
6
+ gem "rest-client"
7
+ gem "yajl-ruby"
8
+ gem "rmagick"
9
+
6
10
  # Add dependencies to develop your gem here.
7
11
  # Include everything needed to run rake, tests, features, etc.
8
12
  group :development do
@@ -12,3 +16,8 @@ group :development do
12
16
  gem "jeweler", "~> 1.8.3"
13
17
  gem "simplecov", ">= 0"
14
18
  end
19
+
20
+ group :test do
21
+ gem "webmock"
22
+ gem "vcr"
23
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.8)
5
+ crack (0.3.1)
6
+ diff-lcs (1.1.3)
7
+ git (1.2.5)
8
+ jeweler (1.8.3)
9
+ bundler (~> 1.0)
10
+ git (>= 1.2.5)
11
+ rake
12
+ rdoc
13
+ json (1.7.3)
14
+ mime-types (1.18)
15
+ multi_json (1.3.5)
16
+ rake (0.9.2.2)
17
+ rdoc (3.12)
18
+ json (~> 1.4)
19
+ rest-client (1.6.7)
20
+ mime-types (>= 1.16)
21
+ rmagick (2.13.1)
22
+ rspec (2.10.0)
23
+ rspec-core (~> 2.10.0)
24
+ rspec-expectations (~> 2.10.0)
25
+ rspec-mocks (~> 2.10.0)
26
+ rspec-core (2.10.1)
27
+ rspec-expectations (2.10.0)
28
+ diff-lcs (~> 1.1.3)
29
+ rspec-mocks (2.10.1)
30
+ simplecov (0.6.4)
31
+ multi_json (~> 1.0)
32
+ simplecov-html (~> 0.5.3)
33
+ simplecov-html (0.5.3)
34
+ vcr (2.1.1)
35
+ webmock (1.8.7)
36
+ addressable (>= 2.2.7)
37
+ crack (>= 0.1.7)
38
+ yajl-ruby (1.1.0)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ bundler (~> 1.1.0)
45
+ jeweler (~> 1.8.3)
46
+ rdoc (~> 3.12)
47
+ rest-client
48
+ rmagick
49
+ rspec (~> 2.10.0)
50
+ simplecov
51
+ vcr
52
+ webmock
53
+ yajl-ruby
data/Rakefile CHANGED
@@ -43,7 +43,7 @@ Rake::RDocTask.new do |rdoc|
43
43
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
44
 
45
45
  rdoc.rdoc_dir = 'rdoc'
46
- rdoc.title = "facehugger #{version}"
46
+ rdoc.title = "face #{version}"
47
47
  rdoc.rdoc_files.include('README*')
48
48
  rdoc.rdoc_files.include('lib/**/*.rb')
49
49
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.1.0
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env /usr/local/bin/ruby-1.9.3-p194@3.2
2
+
3
+ require 'facehugger'
4
+ require 'RMagick'
5
+
6
+ gallery = {
7
+ :urls => "http://2.bp.blogspot.com/-sRejIPLgEaY/Tqe0887jyOI/AAAAAAAAAm4/yEL9k2pxfG4/s1600/man-4+patrickhoelck-4e308eb4e5e102.jpg",
8
+ :file => "data/group-of-people.jpg"
9
+ }
10
+
11
+ fs_image = [
12
+ "data/joe-manganiello.jpg",
13
+ "data/group-of-people.jpg"
14
+ ]
15
+
16
+ gallery.each_with_index do |(key, value), i|
17
+ img = Magick::Image.read(fs_image[i])[0]
18
+ w = img.columns
19
+ h = img.rows
20
+
21
+ new_height = (w * 2.0 / 3).to_i
22
+ photos = facehugger.faces_detect(key => value)
23
+
24
+ photos.each do |photo|
25
+ tag = photo.tags.first
26
+ puts tag.inspect
27
+
28
+ img.crop!(0, (h * tag.center['y'] / 100.0) - new_height / 2, w, new_height)
29
+ img.resize(w, new_height).write("data/cropped-#{i}.jpg")
30
+ end
31
+ end
Binary file
Binary file
@@ -0,0 +1,82 @@
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 = "facehugger"
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 = ["Jimmy Y. Huang"]
12
+ s.date = "2012-05-29"
13
+ s.description = "A RESTful ruby interface for the Face API"
14
+ s.email = "jimmy.huang@duragility.com"
15
+ s.executables = ["reprocess_photo.rb"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE.txt",
18
+ "README",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".rspec",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE.txt",
27
+ "README",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "VERSION",
31
+ "bin/reprocess_photo.rb",
32
+ "data/group-of-people.jpg",
33
+ "data/joe-manganiello.jpg",
34
+ "facehugger.gemspec",
35
+ "lib/face/api.rb",
36
+ "lib/face/base.rb",
37
+ "lib/facehugger.rb",
38
+ "spec/config/face.yml",
39
+ "spec/facehugger_spec.rb",
40
+ "spec/spec_helper.rb",
41
+ "spec/support/custom_matchers.rb"
42
+ ]
43
+ s.homepage = "http://github.com/yhuang/facehugger"
44
+ s.licenses = ["MIT"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = "1.8.24"
47
+ s.summary = "A simple gem to interact with the Face API"
48
+
49
+ if s.respond_to? :specification_version then
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency(%q<rest-client>, [">= 0"])
54
+ s.add_runtime_dependency(%q<yajl-ruby>, [">= 0"])
55
+ s.add_runtime_dependency(%q<rmagick>, [">= 0"])
56
+ s.add_development_dependency(%q<rspec>, ["~> 2.10.0"])
57
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
58
+ s.add_development_dependency(%q<bundler>, ["~> 1.1.0"])
59
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
60
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
61
+ else
62
+ s.add_dependency(%q<rest-client>, [">= 0"])
63
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
64
+ s.add_dependency(%q<rmagick>, [">= 0"])
65
+ s.add_dependency(%q<rspec>, ["~> 2.10.0"])
66
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
67
+ s.add_dependency(%q<bundler>, ["~> 1.1.0"])
68
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
69
+ s.add_dependency(%q<simplecov>, [">= 0"])
70
+ end
71
+ else
72
+ s.add_dependency(%q<rest-client>, [">= 0"])
73
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
74
+ s.add_dependency(%q<rmagick>, [">= 0"])
75
+ s.add_dependency(%q<rspec>, ["~> 2.10.0"])
76
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
77
+ s.add_dependency(%q<bundler>, ["~> 1.1.0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
79
+ s.add_dependency(%q<simplecov>, [">= 0"])
80
+ end
81
+ end
82
+
data/lib/face/api.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'yajl'
2
+
3
+ module Face
4
+ module API
5
+ {
6
+ :faces_detect => 'http://api.face.com/faces/detect.json',
7
+ :account_limits => 'http://api.face.com/account/limits.json',
8
+ }.each do |name, url|
9
+ define_method(name) do |*args|
10
+ full_url = url + "?api_key=#{@api_key}&api_secret=#{@api_secret}"
11
+
12
+ options = args[0] || {}
13
+ file_upload = nil
14
+
15
+ options.each do |key, value|
16
+ case key
17
+ when :file || 'file'
18
+ file_upload = File.new(value, 'rb') if File.exists?(value)
19
+ else
20
+ full_url += "&#{key}=#{value}"
21
+ end
22
+ end
23
+
24
+ begin
25
+ if file_upload
26
+ Yajl::Parser.parse RestClient.post full_url, :file => file_upload
27
+ else
28
+ Yajl::Parser.parse RestClient.get full_url
29
+ end
30
+ rescue => e
31
+ Yajl::Parser.parse e.response
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
data/lib/face/base.rb ADDED
@@ -0,0 +1,21 @@
1
+ module Face
2
+ base_class = Class.new do
3
+ def initialize(hash)
4
+ hash.each do |k, v|
5
+
6
+ # create and initialize an instance variable for this key/value pair
7
+ self.instance_variable_set("@#{k}", v)
8
+
9
+ # create the getter that returns the instance variable
10
+ self.class.send(:define_method, k, proc { self.instance_variable_get("@#{k}") })
11
+
12
+ # create the setter that sets the instance variable
13
+ self.class.send(:define_method, "#{k}=", proc { |v| self.instance_variable_set("@#{k}", v) })
14
+ end
15
+ end
16
+ end
17
+
18
+ ["Photo", "Tag"].each do |const_name|
19
+ const_set(const_name, base_class.clone)
20
+ end
21
+ end
data/lib/facehugger.rb CHANGED
@@ -0,0 +1,54 @@
1
+ require 'face/api'
2
+ require 'face/base'
3
+ require 'json'
4
+ require 'rest_client'
5
+
6
+ class Facehugger
7
+ include Face::API
8
+
9
+ attr_accessor :api_key, :api_secret
10
+
11
+ def initialize(args = {:api_key => "", :api_secret => ""})
12
+ @api_key = args[:api_key]
13
+ @api_secret = args[:api_secret]
14
+ end
15
+
16
+ def valid?
17
+ response = account_limits
18
+ response['status'] == 'success'
19
+ end
20
+
21
+ def self.photos(response = {})
22
+ photos = []
23
+
24
+ if response.has_key? 'photos'
25
+ response['photos'].each do |photo|
26
+ photos << Face::Photo.new(photo)
27
+ end
28
+ end
29
+
30
+ photos
31
+ end
32
+
33
+ def faces_detect(args = {})
34
+ response = super args
35
+ return nil if response['status'] != 'success'
36
+
37
+ photos = Facehugger.photos response
38
+ return nil if photos.nil?
39
+
40
+ photos.each do |photo|
41
+ tags = []
42
+
43
+ photo.tags.sort_by! do |t|
44
+ t['attributes']['face']['confidence']
45
+ end.reverse.each do |tag|
46
+ tags << Face::Tag.new(tag)
47
+ end
48
+
49
+ photo.tags = tags
50
+ end
51
+
52
+ photos
53
+ end
54
+ end
@@ -0,0 +1,2 @@
1
+ api_key: API_KEY
2
+ api_secret: API_SECRET
@@ -1,7 +1,66 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "Facehugger" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
4
+ context "new" do
5
+ before :all do
6
+ VCR.insert_cassette 'new', :record => :new_episodes
7
+ end
8
+
9
+ after :all do
10
+ VCR.eject_cassette
11
+ end
12
+
13
+ let(:facehugger) { Facehugger.new }
14
+
15
+ describe "when valid API key and no API secret" do
16
+ it {
17
+ facehugger.api_key = FACE_ACCOUNT['api_key']
18
+ facehugger.should_not be_valid
19
+ }
20
+ end
21
+
22
+ describe "when no API key and valid API secret" do
23
+ it {
24
+ facehugger.api_secret = FACE_ACCOUNT['api_secret']
25
+ facehugger.should_not be_valid
26
+ }
27
+ end
28
+
29
+ describe "when valid API key and valid API secret" do
30
+ it {
31
+ facehugger.api_key = FACE_ACCOUNT['api_key']
32
+ facehugger.api_secret = FACE_ACCOUNT['api_secret']
33
+ facehugger.should be_valid
34
+ }
35
+ end
36
+ end
37
+
38
+ context "faces_detect" do
39
+ before :all do
40
+ VCR.insert_cassette 'faces_detect', :record => :new_episodes
41
+ end
42
+
43
+ after :all do
44
+ VCR.eject_cassette
45
+ end
46
+
47
+ let(:facehugger) {
48
+ Facehugger.new(:api_key => FACE_ACCOUNT['api_key'],
49
+ :api_secret => FACE_ACCOUNT['api_secret'])
50
+ }
51
+
52
+ describe "valid image" do
53
+ it {
54
+ photos = facehugger.faces_detect(:urls => "http://cdn.bleacherreport.net/images_root/slides/photos/002/097/419/mimi_knoop_original.jpg")
55
+ photos.should_not be_nil
56
+ }
57
+ end
58
+
59
+ describe "valid image upload" do
60
+ it {
61
+ photos = facehugger.faces_detect(:file => "data/group-of-people.jpg")
62
+ photos.should_not be_nil
63
+ }
64
+ end
6
65
  end
7
- end
66
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,25 @@
1
1
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
- require 'rspec'
3
+ require 'RMagick'
4
+
4
5
  require 'facehugger'
6
+ require 'rspec'
7
+ require 'vcr'
8
+ require 'webmock/rspec'
9
+ require 'yaml'
5
10
 
6
11
  # Requires supporting files with custom matchers and macros, etc,
7
12
  # in ./support/ and its subdirectories.
8
13
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
14
 
10
15
  RSpec.configure do |config|
11
-
12
16
  end
17
+
18
+ FACE_ACCOUNT = YAML.load open File.join File.dirname(__FILE__), "config", "face.yml"
19
+
20
+ VCR.configure do |config|
21
+ config.cassette_library_dir = 'spec/fixtures/vcr'
22
+ config.filter_sensitive_data('API_KEY') { FACE_ACCOUNT['api_key'] }
23
+ config.filter_sensitive_data('API_SECRET') { FACE_ACCOUNT['api_secret'] }
24
+ config.hook_into :webmock
25
+ end
@@ -0,0 +1,45 @@
1
+ module CustomMatchers
2
+ #checks that an AR model validates, by testing error messages from .valid?
3
+ #displays any error messages recieved in test failure output
4
+ class BeValid
5
+ #do any setup required - at the very least, set some instance variables.
6
+ #In this case, i don't take any arguments - it simply either passes or fails.
7
+ def initialize
8
+ @expected = []
9
+ end
10
+
11
+ #perform the actual match - 'target' is the thing being tested
12
+ def matches?(target)
13
+ #target.errors.full_messages is an array of error messages produced by the valid? method
14
+ #if valid? is true, it will be empty
15
+ target.valid?
16
+ @errors = target.errors.full_messages
17
+ @errors.eql?(@expected)
18
+ end
19
+
20
+ #displayed when 'should' fails
21
+ def failure_message
22
+ "validation failed with #{@errors.inspect}, expected no validation errors"
23
+ end
24
+
25
+ #displayed when 'should_not' fails
26
+ def negative_failure_message
27
+ "validation succeeded, expected one or more validation errors"
28
+ end
29
+
30
+ #displayed in the spec description if the user doesn't provide one (ie if they just write 'it do' for the spec header)
31
+ def description
32
+ "validate successfully"
33
+ end
34
+
35
+ # Returns string representation of the object being tested
36
+ def to_s(value)
37
+ "#{@errors.inspect}"
38
+ end
39
+ end
40
+
41
+ # the matcher method that the user calls in their specs
42
+ def be_valid
43
+ BeValid.new
44
+ end
45
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facehugger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,56 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-26 00:00:00.000000000 Z
12
+ date: 2012-05-29 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
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: yajl-ruby
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rmagick
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
14
62
  - !ruby/object:Gem::Dependency
15
63
  name: rspec
16
64
  requirement: !ruby/object:Gem::Requirement
@@ -93,7 +141,8 @@ dependencies:
93
141
  version: '0'
94
142
  description: A RESTful ruby interface for the Face API
95
143
  email: jimmy.huang@duragility.com
96
- executables: []
144
+ executables:
145
+ - reprocess_photo.rb
97
146
  extensions: []
98
147
  extra_rdoc_files:
99
148
  - LICENSE.txt
@@ -103,14 +152,23 @@ files:
103
152
  - .document
104
153
  - .rspec
105
154
  - Gemfile
155
+ - Gemfile.lock
106
156
  - LICENSE.txt
107
157
  - README
108
158
  - README.rdoc
109
159
  - Rakefile
110
160
  - VERSION
161
+ - bin/reprocess_photo.rb
162
+ - data/group-of-people.jpg
163
+ - data/joe-manganiello.jpg
164
+ - facehugger.gemspec
165
+ - lib/face/api.rb
166
+ - lib/face/base.rb
111
167
  - lib/facehugger.rb
168
+ - spec/config/face.yml
112
169
  - spec/facehugger_spec.rb
113
170
  - spec/spec_helper.rb
171
+ - spec/support/custom_matchers.rb
114
172
  homepage: http://github.com/yhuang/facehugger
115
173
  licenses:
116
174
  - MIT
@@ -126,7 +184,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
184
  version: '0'
127
185
  segments:
128
186
  - 0
129
- hash: 802059609446032406
187
+ hash: 3426172783520172189
130
188
  required_rubygems_version: !ruby/object:Gem::Requirement
131
189
  none: false
132
190
  requirements: