flickollage 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://farm1.staticflickr.com/758/not_found.jpg
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.9.2
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - "*/*"
16
+ response:
17
+ status:
18
+ code: 404
19
+ message: Not Found
20
+ headers:
21
+ Date:
22
+ - Sun, 05 Mar 2017 12:13:42 GMT
23
+ Content-Type:
24
+ - text/html; charset=utf-8
25
+ Transfer-Encoding:
26
+ - chunked
27
+ Connection:
28
+ - keep-alive
29
+ X-Photo-Farm:
30
+ - '1'
31
+ P3p:
32
+ - policyref="https://policies.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM
33
+ DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND
34
+ PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
35
+ X-Photo-Origin:
36
+ - bf1
37
+ Cache-Control:
38
+ - private, no-cache, must-revalidate
39
+ Expires:
40
+ - Mon, 26 Jul 1997 05:00:00 GMT
41
+ Pragma:
42
+ - no-cache
43
+ Last-Modified:
44
+ - Sat, 04 Mar 2017 18:32:59 GMT
45
+ Age:
46
+ - '0'
47
+ Via:
48
+ - http/1.1 pc-pool122.flickr.bf1.yahoo.com (ApacheTrafficServer [cMsSf ]), http/1.1
49
+ cache112.flickr.ir2.yahoo.com (ApacheTrafficServer [cMsSf ])
50
+ Server:
51
+ - ATS
52
+ X-Photo-Farm-Guess:
53
+ - '1'
54
+ body:
55
+ encoding: ASCII-8BIT
56
+ string: |
57
+ pc-pool122.flickr.bf1 : 404
58
+ http_version:
59
+ recorded_at: Sun, 05 Mar 2017 12:13:42 GMT
60
+ recorded_with: VCR 2.9.2
@@ -0,0 +1,57 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://api.flickr.com/services/rest/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: tags=kjasbdib823&sort=interestingness-desc&per_page=1&method=flickr.photos.search&format=json&nojsoncallback=1
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - FlickRaw/0.9.9
16
+ Content-Type:
17
+ - application/x-www-form-urlencoded
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Date:
24
+ - Sun, 05 Mar 2017 12:02:59 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Content-Length:
28
+ - '80'
29
+ P3p:
30
+ - policyref="https://policies.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM
31
+ DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND
32
+ PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
33
+ X-Content-Type-Options:
34
+ - nosniff
35
+ Cache-Control:
36
+ - private
37
+ X-Served-By:
38
+ - www295.flickr.bf1.yahoo.com
39
+ X-Frame-Options:
40
+ - SAMEORIGIN
41
+ Vary:
42
+ - Accept-Encoding
43
+ Age:
44
+ - '0'
45
+ Via:
46
+ - http/1.1 fts125.flickr.bf1.yahoo.com (ApacheTrafficServer [cMsSf ]), http/1.1
47
+ e20.ycpi.amb.yahoo.com (ApacheTrafficServer [cMsSf ])
48
+ Server:
49
+ - ATS
50
+ Connection:
51
+ - keep-alive
52
+ body:
53
+ encoding: ASCII-8BIT
54
+ string: '{"photos":{"page":1,"pages":0,"perpage":1,"total":"0","photo":[]},"stat":"ok"}'
55
+ http_version:
56
+ recorded_at: Sun, 05 Mar 2017 12:02:59 GMT
57
+ recorded_with: VCR 2.9.2
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe Flickollage::Collage do
4
+ let(:subject) { described_class.new(words, options) }
5
+ let(:words) { %w(annapurna elbrus) }
6
+ let(:options) do
7
+ {
8
+ dict: fixture_file_path('mountains'),
9
+ number: 4,
10
+ width: 100,
11
+ height: 60,
12
+ rows: 2,
13
+ cols: 2
14
+ }
15
+ end
16
+
17
+ let(:mocked_image) { MiniMagick::Image.open(fixture_file_path('rothko.jpg')) }
18
+
19
+ before(:each) do
20
+ # mock downloaded image
21
+ allow_any_instance_of(Flickollage::Image).to receive(:search_on_flickr)
22
+ allow_any_instance_of(Flickollage::Image).to receive(:download)
23
+ allow_any_instance_of(Flickollage::Image).to receive(:image).and_return(mocked_image)
24
+ end
25
+
26
+ describe '#initialize' do
27
+ it 'initializes a dictionary' do
28
+ expect(subject.dictionary.words).not_to be_empty
29
+ end
30
+
31
+ it 'loads images' do
32
+ expect(subject.images.size).to eq 4
33
+ end
34
+
35
+ it 'crops images' do
36
+ allow_any_instance_of(Flickollage::Image).to receive(:crop)
37
+ expect(subject.images).to all have_received(:crop).with(100, 60)
38
+ end
39
+
40
+ context 'when image can not be loaded' do
41
+ before(:each) do
42
+ expect(Flickollage::Image)
43
+ .to receive(:new)
44
+ .and_raise(Flickollage::Image::Error).exactly(described_class::RETRY_LIMIT).times
45
+ end
46
+
47
+ it 'should raise Flickollage::Error after RETRY_LIMIT attempts' do
48
+ expect { subject }.to raise_error(Flickollage::Error)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#generate_collage' do
54
+ let(:output) { Tempfile.new(['collage', '.jpg']).path }
55
+ let(:subject) { super().generate_collage(output) }
56
+ let(:collage) { MiniMagick::Image.new(output) }
57
+
58
+ before(:each) { subject }
59
+
60
+ it 'should compose a collage and save it into a file' do
61
+ expect(collage.dimensions).to eq [200, 120]
62
+ end
63
+
64
+ it 'should be similar to a sample image' do
65
+ expect(output).to be_similar_to fixture_file_path('collage.jpg')
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe Flickollage::Dictionary do
4
+ let(:path) { fixture_file_path('mountains') }
5
+ let(:subject) { described_class.new(path) }
6
+
7
+ describe '#initialize' do
8
+ context 'with file' do
9
+ it 'should load all words' do
10
+ expect(subject.words.size).to be > 20
11
+ end
12
+
13
+ it 'shuffles the dictionary' do
14
+ dictionary2 = described_class.new(path)
15
+ expect(subject.words).not_to eq dictionary2.words
16
+ end
17
+
18
+ context 'huge file' do
19
+ before(:each) { stub_const('Flickollage::Dictionary::MAX_DICT_LENGTH', 5) }
20
+ it 'limits dictionary size' do
21
+ expect(subject.words.size).to eq 5
22
+ end
23
+ end
24
+
25
+ context 'file not found' do
26
+ let(:path) { '/not/a/file' }
27
+
28
+ it 'raise an error' do
29
+ expect { subject }.to raise_error Flickollage::Dictionary::Error
30
+ end
31
+ end
32
+ end
33
+
34
+ context 'with list of words' do
35
+ let(:words) { %w(apples oranges) }
36
+ let(:subject) { described_class.new(words) }
37
+ it 'should load all words' do
38
+ expect(subject.words.size).to eq 2
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '#words' do
44
+ let(:subject) { super().words }
45
+
46
+ it 'returns the list of loaded words' do
47
+ expect(subject).to be_an Array
48
+ end
49
+
50
+ it 'does not contain empty words' do
51
+ expect(subject).not_to include ''
52
+ end
53
+ end
54
+
55
+ describe '#pop' do
56
+ let!(:dictionary) { described_class.new(path) }
57
+ let(:subject) { dictionary.pop }
58
+ it 'should return a random word' do
59
+ expect(subject).not_to be_empty
60
+ end
61
+
62
+ it 'should not be a multi-line string' do
63
+ expect(subject).not_to include "\n"
64
+ end
65
+
66
+ it 'should remove a word from the dictionary' do
67
+ expect { subject }.to change { dictionary.words.size }.by(-1)
68
+ end
69
+ end
70
+
71
+ describe '#append' do
72
+ let!(:dictionary) { described_class.new(path) }
73
+ let(:words) { %w(apple banana) }
74
+ let(:subject) { dictionary.append(words) }
75
+
76
+ it 'should append words to the dictionary' do
77
+ subject
78
+ expect(dictionary.pop).to eq 'apple'
79
+ expect(dictionary.pop).to eq 'banana'
80
+ end
81
+ end
82
+
83
+ describe '#default_dict_path' do
84
+ let(:subject) { described_class.default_dict_path }
85
+ it 'should return one of the common dict paths' do
86
+ expect(described_class::COMMON_DICT_PATHS).to include subject
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Flickollage::Image do
4
+ let(:word) { 'dolomites' }
5
+ let(:subject) { described_class.new(word) }
6
+
7
+ let(:flickr_api_key) { ENV['FLICKR_API_KEY'] || 'key' }
8
+ let(:flickr_shared_key) { ENV['FLICKR_SHARED_SECRET'] || 'secret' }
9
+
10
+ before(:each) do
11
+ Flickollage.configure_flickraw(
12
+ flickr_api_key: flickr_api_key,
13
+ flickr_shared_secret: flickr_shared_key
14
+ )
15
+ end
16
+
17
+ describe '#initialize' do
18
+ it 'should retrieve image url from flickr' do
19
+ VCR.use_cassette('flickr') do
20
+ expect(subject.url).to match(/staticflickr\.com/)
21
+ end
22
+ end
23
+
24
+ context 'file not found' do
25
+ let(:word) { 'kjasbdib823' }
26
+ it 'should raise error' do
27
+ VCR.use_cassette('flickr_not_found') do
28
+ expect { subject }.to raise_error { Flickollage::Image::Error }
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ describe '#download' do
35
+ let(:image) { described_class.new(word) }
36
+ let(:subject) { image.download }
37
+ it 'should return an mini magick object' do
38
+ VCR.use_cassette('flickr_download') do
39
+ expect(subject).to be_a MiniMagick::Image
40
+ end
41
+ end
42
+
43
+ context 'file not found' do
44
+ before(:each) do
45
+ # mock Flickr request
46
+ allow_any_instance_of(Flickollage::Image).to receive(:search_on_flickr)
47
+ allow(image).to receive(:url).and_return('https://farm1.staticflickr.com/758/not_found.jpg')
48
+ end
49
+
50
+ it 'should raise en error' do
51
+ VCR.use_cassette('flickr_download_not_found') do
52
+ expect { subject }.to raise_error { Flickollage::Image::Error }
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#crop' do
59
+ let(:image) { described_class.new(word).tap(&:download) }
60
+ let(:crop_size) { [150, 100] }
61
+ let(:subject) { image.crop(*crop_size) }
62
+ before(:each) do
63
+ VCR.use_cassette('flickr_download') do
64
+ image
65
+ end
66
+ end
67
+ it 'crops the image' do
68
+ expect { subject }.to change { image.image.dimensions }.to crop_size
69
+ end
70
+
71
+ context 'result is bigger that the source' do
72
+ let(:crop_size) { [1500, 1500] }
73
+ it 'makes the image bigger' do
74
+ expect { subject }.to change { image.image.dimensions }.to crop_size
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,24 @@
1
+ require 'bundler/setup'
2
+ require 'flickollage'
3
+
4
+ require 'dotenv'
5
+ Dotenv.load
6
+
7
+ # testing frameworks
8
+ require 'rspec'
9
+ require 'webmock/rspec'
10
+ require 'vcr'
11
+
12
+ Flickollage.init_logger
13
+
14
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
15
+
16
+ VCR.configure do |config|
17
+ config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
18
+ config.hook_into :webmock
19
+
20
+ # Removes private data
21
+ config.before_record do |i|
22
+ i.request.headers.delete('Authorization')
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ module Flickollage
2
+ module SpecHelpers
3
+ def fixture_file_path(file_name)
4
+ File.join(__dir__, '..', 'fixtures', file_name)
5
+ end
6
+ end
7
+ end
8
+
9
+ RSpec.configure do |config|
10
+ config.include Flickollage::SpecHelpers
11
+ end
@@ -0,0 +1,12 @@
1
+ RSpec::Matchers.define :be_similar_to do |expected|
2
+ match do |actual|
3
+ expect do
4
+ $stderr = StringIO.new
5
+ MiniMagick::Tool::Compare.new do |compare|
6
+ compare.merge! %W(-metric RMSE #{actual} #{expected} null:)
7
+ end
8
+ # expect($stderr.string).to eq '0 (0)'
9
+ $stderr = STDERR
10
+ end.not_to raise_error
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flickollage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Aleksandr Zykov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.19'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.19'
27
+ - !ruby/object:Gem::Dependency
28
+ name: flickraw
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.9'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mini_magick
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '4.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: dotenv
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: vcr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.47.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.47.1
125
+ description: Flickollage is a simple command line tool for generating collages
126
+ email: alexandrz@gmail.com
127
+ executables:
128
+ - flickollage
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".rspec"
134
+ - ".rubocop.yml"
135
+ - ".travis.yml"
136
+ - Gemfile
137
+ - README.md
138
+ - bin/flickollage
139
+ - flickollage.gemspec
140
+ - lib/flickollage.rb
141
+ - lib/flickollage/cli.rb
142
+ - lib/flickollage/collage.rb
143
+ - lib/flickollage/dictionary.rb
144
+ - lib/flickollage/image.rb
145
+ - lib/flickollage/logger.rb
146
+ - spec/fixtures/cities.png
147
+ - spec/fixtures/collage.jpg
148
+ - spec/fixtures/mountains
149
+ - spec/fixtures/mountains.png
150
+ - spec/fixtures/rothko.jpg
151
+ - spec/fixtures/vcr_cassettes/flickr.yml
152
+ - spec/fixtures/vcr_cassettes/flickr_download.yml
153
+ - spec/fixtures/vcr_cassettes/flickr_download_not_found.yml
154
+ - spec/fixtures/vcr_cassettes/flickr_not_found.yml
155
+ - spec/lib/collage_spec.rb
156
+ - spec/lib/dictionary_spec.rb
157
+ - spec/lib/image_spec.rb
158
+ - spec/spec_helper.rb
159
+ - spec/support/flickollage_helpers.rb
160
+ - spec/support/similar_image_matcher.rb
161
+ homepage: https://github.com/alexandrz/flickollage
162
+ licenses:
163
+ - MIT
164
+ metadata: {}
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubyforge_project:
181
+ rubygems_version: 2.6.9
182
+ signing_key:
183
+ specification_version: 4
184
+ summary: Flickollage Collage Generator
185
+ test_files:
186
+ - spec/fixtures/cities.png
187
+ - spec/fixtures/collage.jpg
188
+ - spec/fixtures/mountains
189
+ - spec/fixtures/mountains.png
190
+ - spec/fixtures/rothko.jpg
191
+ - spec/fixtures/vcr_cassettes/flickr.yml
192
+ - spec/fixtures/vcr_cassettes/flickr_download.yml
193
+ - spec/fixtures/vcr_cassettes/flickr_download_not_found.yml
194
+ - spec/fixtures/vcr_cassettes/flickr_not_found.yml
195
+ - spec/lib/collage_spec.rb
196
+ - spec/lib/dictionary_spec.rb
197
+ - spec/lib/image_spec.rb
198
+ - spec/spec_helper.rb
199
+ - spec/support/flickollage_helpers.rb
200
+ - spec/support/similar_image_matcher.rb