flickollage 0.0.3

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,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