httpthumbnailer 0.3.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -11
- data/Gemfile.lock +75 -51
- data/README.md +184 -54
- data/VERSION +1 -1
- data/bin/httpthumbnailer +76 -133
- data/features/httpthumbnailer.feature +11 -260
- data/features/step_definitions/httpthumbnailer_steps.rb +89 -44
- data/features/support/env.rb +22 -9
- data/features/support/test-large.jpg +0 -0
- data/features/thumbnail.feature +241 -0
- data/features/thumbnails.feature +142 -0
- data/httpthumbnailer.gemspec +39 -40
- data/lib/httpthumbnailer/error_reporter.rb +38 -0
- data/lib/httpthumbnailer/plugin/thumbnailer.rb +396 -0
- data/lib/httpthumbnailer/thumbnail_specs.rb +50 -47
- data/lib/httpthumbnailer/thumbnailer.rb +52 -229
- data/load_test/load_test-cd9679c.csv +10 -0
- data/load_test/load_test-v0.3.1.csv +10 -0
- data/load_test/load_test.jmx +49 -34
- data/load_test/soak_test-ac0c6bcbe5e-broken-libjpeg-tatoos.csv +11 -0
- data/load_test/soak_test-cd9679c.csv +10 -0
- data/load_test/soak_test-f98334a-tatoos.csv +11 -0
- data/load_test/soak_test.jmx +697 -0
- data/spec/image_processing_spec.rb +148 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/thumbnail_specs_spec.rb +18 -5
- metadata +101 -71
- data/lib/httpthumbnailer/multipart_response.rb +0 -45
- data/spec/multipart_response_spec.rb +0 -95
- data/spec/thumbnailer_spec.rb +0 -33
@@ -0,0 +1,148 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'unicorn-cuba-base'
|
3
|
+
require 'httpthumbnailer/plugin/thumbnailer'
|
4
|
+
|
5
|
+
class TestImage
|
6
|
+
include Plugin::Thumbnailer::ImageProcessing
|
7
|
+
|
8
|
+
@@created = 0
|
9
|
+
@@destroyed = 0
|
10
|
+
|
11
|
+
def self.alive
|
12
|
+
@@created - @@destroyed
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@@created += 1
|
17
|
+
@destroyed = false
|
18
|
+
@final = false
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy!
|
22
|
+
fail "already destroyed: #{self}" if @destroyed
|
23
|
+
@destroyed = true
|
24
|
+
@@destroyed += 1
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def copy
|
29
|
+
TestImage.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroyed?
|
33
|
+
@destroyed
|
34
|
+
end
|
35
|
+
|
36
|
+
def final!
|
37
|
+
@final = true
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def final?
|
42
|
+
@final
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'image processing module' do
|
47
|
+
it '#replace will return new or original image makng sure that all other images are destroyed' do
|
48
|
+
image = TestImage.new.replace do |image|
|
49
|
+
image.copy.replace do |image|
|
50
|
+
image.final!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
image.should be_final
|
54
|
+
image.should_not be_destroyed
|
55
|
+
|
56
|
+
TestImage.alive.should == 1
|
57
|
+
image.destroy!
|
58
|
+
|
59
|
+
image = TestImage.new.replace do |image|
|
60
|
+
image.copy.replace do |image|
|
61
|
+
image.copy.replace do |image|
|
62
|
+
image.copy
|
63
|
+
end.replace do |image|
|
64
|
+
image.final!
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
image.should be_final
|
69
|
+
image.should_not be_destroyed
|
70
|
+
|
71
|
+
TestImage.alive.should == 1
|
72
|
+
image.destroy!
|
73
|
+
|
74
|
+
image = TestImage.new.replace do |image|
|
75
|
+
image.copy.replace do |image|
|
76
|
+
image = image.copy.replace do |image|
|
77
|
+
image.copy
|
78
|
+
end
|
79
|
+
image.replace do |image|
|
80
|
+
image.copy.replace do |image|
|
81
|
+
image.final!
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
image.should be_final
|
87
|
+
image.should_not be_destroyed
|
88
|
+
|
89
|
+
TestImage.alive.should == 1
|
90
|
+
image.destroy!
|
91
|
+
end
|
92
|
+
|
93
|
+
it '#replace will destroy created images on exception' do
|
94
|
+
lambda {
|
95
|
+
image = TestImage.new.replace do |image|
|
96
|
+
image.copy.replace do |image|
|
97
|
+
image.copy.replace do |image|
|
98
|
+
image.copy.replace do |image|
|
99
|
+
fail 'test'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
}.should raise_error(RuntimeError, 'test')
|
105
|
+
|
106
|
+
TestImage.alive.should == 0
|
107
|
+
|
108
|
+
lambda {
|
109
|
+
image = TestImage.new.replace do |image|
|
110
|
+
image.copy.replace do |image|
|
111
|
+
image.copy.replace do |image|
|
112
|
+
image.copy
|
113
|
+
end.replace do |image|
|
114
|
+
fail 'test'
|
115
|
+
image.final!
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
}.should raise_error(RuntimeError, 'test')
|
120
|
+
|
121
|
+
TestImage.alive.should == 0
|
122
|
+
end
|
123
|
+
|
124
|
+
it '#use should return image to be used for multiple processing and destroy it at the end' do
|
125
|
+
image = TestImage.new.use do |image|
|
126
|
+
i1 = image.replace do |image|
|
127
|
+
image.copy.final!
|
128
|
+
end
|
129
|
+
i1.should be_final
|
130
|
+
i1.destroy!
|
131
|
+
|
132
|
+
i2 = image.replace do |image|
|
133
|
+
image.copy.final!
|
134
|
+
end
|
135
|
+
i2.should be_final
|
136
|
+
i2.destroy!
|
137
|
+
|
138
|
+
i3 = image.replace do |image|
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
i3.should_not be_destroyed
|
142
|
+
end
|
143
|
+
image.should be_destroyed
|
144
|
+
|
145
|
+
TestImage.alive.should == 0
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
|
2
3
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
4
|
require 'rspec'
|
4
5
|
|
@@ -6,6 +7,8 @@ require 'rspec'
|
|
6
7
|
# in ./support/ and its subdirectories.
|
7
8
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
8
9
|
|
10
|
+
require 'capybara/rspec'
|
11
|
+
|
9
12
|
RSpec.configure do |config|
|
10
|
-
|
11
13
|
end
|
14
|
+
|
@@ -2,29 +2,42 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
require 'httpthumbnailer/thumbnail_specs'
|
3
3
|
|
4
4
|
describe ThumbnailSpecs do
|
5
|
-
it "can be
|
6
|
-
ts = ThumbnailSpecs.from_uri('test,128,256,
|
5
|
+
it "can be created from URI" do
|
6
|
+
ts = ThumbnailSpecs.from_uri('test,128,256,jpeg,magick:64,number:8/pad,128,128,png,background:0xFF00FF/crop,32,32,gif')
|
7
7
|
|
8
8
|
ts[0].method.should == 'test'
|
9
9
|
ts[0].width.should == 128
|
10
10
|
ts[0].height.should == 256
|
11
11
|
ts[0].format.should == 'JPEG'
|
12
|
-
ts[0].mime.should == 'image/jpeg'
|
13
12
|
ts[0].options.should == { 'magick' => '64', 'number' => '8' }
|
14
13
|
|
15
14
|
ts[1].method.should == 'pad'
|
16
15
|
ts[1].width.should == 128
|
17
16
|
ts[1].height.should == 128
|
18
17
|
ts[1].format.should == 'PNG'
|
19
|
-
ts[1].mime.should == 'image/png'
|
20
18
|
ts[1].options.should == { 'background' => '0xFF00FF' }
|
21
19
|
|
22
20
|
ts[2].method.should == 'crop'
|
23
21
|
ts[2].width.should == 32
|
24
22
|
ts[2].height.should == 32
|
25
23
|
ts[2].format.should == 'GIF'
|
26
|
-
ts[2].mime.should == 'image/gif'
|
27
24
|
ts[2].options.should == {}
|
28
25
|
end
|
26
|
+
|
27
|
+
it 'should provide :input symbol when input is used as width, height or format' do
|
28
|
+
ts = ThumbnailSpecs.from_uri('test,input,256,jpeg,magick:64,number:8/pad,128,input,png,background:0xFF00FF/crop,32,32,input')
|
29
|
+
|
30
|
+
ts[0].width.should == :input
|
31
|
+
ts[0].height.should == 256
|
32
|
+
ts[0].format.should == 'JPEG'
|
33
|
+
|
34
|
+
ts[1].width.should == 128
|
35
|
+
ts[1].height.should == :input
|
36
|
+
ts[1].format.should == 'PNG'
|
37
|
+
|
38
|
+
ts[2].width.should == 32
|
39
|
+
ts[2].height.should == 32
|
40
|
+
ts[2].format.should == :input
|
41
|
+
end
|
29
42
|
end
|
30
43
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpthumbnailer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,33 +9,27 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement:
|
15
|
+
name: unicorn-cuba-base
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
21
|
+
version: '1.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: mongrel
|
27
|
-
requirement: &16908960 !ruby/object:Gem::Requirement
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
25
|
none: false
|
29
26
|
requirements:
|
30
|
-
- -
|
27
|
+
- - ~>
|
31
28
|
- !ruby/object:Gem::Version
|
32
|
-
version: 1.
|
33
|
-
type: :runtime
|
34
|
-
prerelease: false
|
35
|
-
version_requirements: *16908960
|
29
|
+
version: '1.0'
|
36
30
|
- !ruby/object:Gem::Dependency
|
37
31
|
name: rmagick
|
38
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
39
33
|
none: false
|
40
34
|
requirements:
|
41
35
|
- - ~>
|
@@ -43,54 +37,47 @@ dependencies:
|
|
43
37
|
version: '2'
|
44
38
|
type: :runtime
|
45
39
|
prerelease: false
|
46
|
-
version_requirements:
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: haml
|
49
|
-
requirement: &16941920 !ruby/object:Gem::Requirement
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
41
|
none: false
|
51
42
|
requirements:
|
52
43
|
- - ~>
|
53
44
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
55
|
-
type: :runtime
|
56
|
-
prerelease: false
|
57
|
-
version_requirements: *16941920
|
45
|
+
version: '2'
|
58
46
|
- !ruby/object:Gem::Dependency
|
59
|
-
name:
|
60
|
-
requirement:
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
61
49
|
none: false
|
62
50
|
requirements:
|
63
51
|
- - ~>
|
64
52
|
- !ruby/object:Gem::Version
|
65
|
-
version: '
|
66
|
-
type: :
|
53
|
+
version: '2.13'
|
54
|
+
type: :development
|
67
55
|
prerelease: false
|
68
|
-
version_requirements:
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: cli
|
71
|
-
requirement: &16938600 !ruby/object:Gem::Requirement
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
57
|
none: false
|
73
58
|
requirements:
|
74
59
|
- - ~>
|
75
60
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
77
|
-
type: :runtime
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: *16938600
|
61
|
+
version: '2.13'
|
80
62
|
- !ruby/object:Gem::Dependency
|
81
|
-
name: rspec
|
82
|
-
requirement:
|
63
|
+
name: rspec-mocks
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
83
65
|
none: false
|
84
66
|
requirements:
|
85
67
|
- - ~>
|
86
68
|
- !ruby/object:Gem::Version
|
87
|
-
version: 2.
|
69
|
+
version: '2.13'
|
88
70
|
type: :development
|
89
71
|
prerelease: false
|
90
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.13'
|
91
78
|
- !ruby/object:Gem::Dependency
|
92
79
|
name: cucumber
|
93
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
94
81
|
none: false
|
95
82
|
requirements:
|
96
83
|
- - ! '>='
|
@@ -98,73 +85,108 @@ dependencies:
|
|
98
85
|
version: '0'
|
99
86
|
type: :development
|
100
87
|
prerelease: false
|
101
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
102
94
|
- !ruby/object:Gem::Dependency
|
103
|
-
name:
|
104
|
-
requirement:
|
95
|
+
name: capybara
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
105
97
|
none: false
|
106
98
|
requirements:
|
107
99
|
- - ~>
|
108
100
|
- !ruby/object:Gem::Version
|
109
|
-
version: 1.
|
101
|
+
version: '1.1'
|
110
102
|
type: :development
|
111
103
|
prerelease: false
|
112
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '1.1'
|
113
110
|
- !ruby/object:Gem::Dependency
|
114
111
|
name: jeweler
|
115
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
116
113
|
none: false
|
117
114
|
requirements:
|
118
115
|
- - ~>
|
119
116
|
- !ruby/object:Gem::Version
|
120
|
-
version: 1.
|
117
|
+
version: 1.8.4
|
121
118
|
type: :development
|
122
119
|
prerelease: false
|
123
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 1.8.4
|
124
126
|
- !ruby/object:Gem::Dependency
|
125
|
-
name:
|
126
|
-
requirement:
|
127
|
+
name: httpclient
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
127
129
|
none: false
|
128
130
|
requirements:
|
129
|
-
- -
|
131
|
+
- - ~>
|
130
132
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
133
|
+
version: '2.3'
|
132
134
|
type: :development
|
133
135
|
prerelease: false
|
134
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '2.3'
|
135
142
|
- !ruby/object:Gem::Dependency
|
136
|
-
name:
|
137
|
-
requirement:
|
143
|
+
name: rdoc
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
138
145
|
none: false
|
139
146
|
requirements:
|
140
147
|
- - ~>
|
141
148
|
- !ruby/object:Gem::Version
|
142
|
-
version: '
|
149
|
+
version: '3.9'
|
143
150
|
type: :development
|
144
151
|
prerelease: false
|
145
|
-
version_requirements:
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '3.9'
|
146
158
|
- !ruby/object:Gem::Dependency
|
147
|
-
name:
|
148
|
-
requirement:
|
159
|
+
name: multipart-parser
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
149
161
|
none: false
|
150
162
|
requirements:
|
151
163
|
- - ~>
|
152
164
|
- !ruby/object:Gem::Version
|
153
|
-
version:
|
165
|
+
version: 0.1.1
|
154
166
|
type: :development
|
155
167
|
prerelease: false
|
156
|
-
version_requirements:
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.1.1
|
157
174
|
- !ruby/object:Gem::Dependency
|
158
|
-
name:
|
159
|
-
requirement:
|
175
|
+
name: daemon
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
160
177
|
none: false
|
161
178
|
requirements:
|
162
179
|
- - ~>
|
163
180
|
- !ruby/object:Gem::Version
|
164
|
-
version: '
|
181
|
+
version: '1.1'
|
165
182
|
type: :development
|
166
183
|
prerelease: false
|
167
|
-
version_requirements:
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ~>
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '1.1'
|
168
190
|
description: Provides HTTP API for thumbnailing images
|
169
191
|
email: jpastuszek@gmail.com
|
170
192
|
executables:
|
@@ -191,25 +213,33 @@ files:
|
|
191
213
|
- features/support/test.jpg
|
192
214
|
- features/support/test.png
|
193
215
|
- features/support/test.txt
|
216
|
+
- features/thumbnail.feature
|
217
|
+
- features/thumbnails.feature
|
194
218
|
- httpthumbnailer.gemspec
|
195
|
-
- lib/httpthumbnailer/
|
219
|
+
- lib/httpthumbnailer/error_reporter.rb
|
220
|
+
- lib/httpthumbnailer/plugin/thumbnailer.rb
|
196
221
|
- lib/httpthumbnailer/thumbnail_specs.rb
|
197
222
|
- lib/httpthumbnailer/thumbnailer.rb
|
198
223
|
- load_test/extralarge.jpg
|
199
224
|
- load_test/large.jpg
|
200
225
|
- load_test/large.png
|
226
|
+
- load_test/load_test-cd9679c.csv
|
227
|
+
- load_test/load_test-v0.3.1.csv
|
201
228
|
- load_test/load_test.jmx
|
202
229
|
- load_test/medium.jpg
|
203
230
|
- load_test/small.jpg
|
231
|
+
- load_test/soak_test-ac0c6bcbe5e-broken-libjpeg-tatoos.csv
|
232
|
+
- load_test/soak_test-cd9679c.csv
|
233
|
+
- load_test/soak_test-f98334a-tatoos.csv
|
234
|
+
- load_test/soak_test.jmx
|
204
235
|
- load_test/tiny.jpg
|
205
236
|
- load_test/v0.0.13-loading.csv
|
206
237
|
- load_test/v0.0.13.csv
|
207
238
|
- load_test/v0.0.14-no-optimization.csv
|
208
239
|
- load_test/v0.0.14.csv
|
209
|
-
- spec/
|
240
|
+
- spec/image_processing_spec.rb
|
210
241
|
- spec/spec_helper.rb
|
211
242
|
- spec/thumbnail_specs_spec.rb
|
212
|
-
- spec/thumbnailer_spec.rb
|
213
243
|
homepage: http://github.com/jpastuszek/httpthumbnailer
|
214
244
|
licenses:
|
215
245
|
- MIT
|
@@ -225,7 +255,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
225
255
|
version: '0'
|
226
256
|
segments:
|
227
257
|
- 0
|
228
|
-
hash:
|
258
|
+
hash: -1707312696099202820
|
229
259
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
230
260
|
none: false
|
231
261
|
requirements:
|
@@ -234,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
234
264
|
version: '0'
|
235
265
|
requirements: []
|
236
266
|
rubyforge_project:
|
237
|
-
rubygems_version: 1.8.
|
267
|
+
rubygems_version: 1.8.25
|
238
268
|
signing_key:
|
239
269
|
specification_version: 3
|
240
270
|
summary: HTTP thumbnailing server
|
@@ -1,45 +0,0 @@
|
|
1
|
-
class MultipartResponse
|
2
|
-
class NoBoundaryFoundInContentTypeError < ArgumentError
|
3
|
-
def initialize(content_type_header, exception)
|
4
|
-
super("Content-Type header of '#{content_type_header}' has no boundary defined: #{exception.class.name}: #{exception}")
|
5
|
-
end
|
6
|
-
end
|
7
|
-
|
8
|
-
class Part
|
9
|
-
def initialize(data)
|
10
|
-
if data.include?("\r\n\r\n")
|
11
|
-
headers, *body = *data.split("\r\n\r\n")
|
12
|
-
@headers = Hash[headers.split("\r\n").map{|h| h.split(/: ?/)}]
|
13
|
-
@body = body.join("\r\n\r\n")
|
14
|
-
else
|
15
|
-
@headers = {'Content-Type' => 'text/plain'}
|
16
|
-
@body = data
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
attr_reader :headers, :body
|
21
|
-
alias :header :headers
|
22
|
-
end
|
23
|
-
|
24
|
-
def initialize(content_type_header, body)
|
25
|
-
@boundary = begin
|
26
|
-
content_type_header.split(';').map{|e| e.strip}.select{|e| e =~ /^boundary=/}.first.match(/^boundary="(.*)"/)[1]
|
27
|
-
rescue => e
|
28
|
-
raise NoBoundaryFoundInContentTypeError.new(content_type_header, e)
|
29
|
-
end
|
30
|
-
|
31
|
-
body, epilogue = *body.split("--#{@boundary}--")
|
32
|
-
preamble, *parts = *body.split("--#{@boundary}")
|
33
|
-
|
34
|
-
@preamble = preamble.sub(/\r\n$/m, '')
|
35
|
-
@preamble = nil if @preamble.empty?
|
36
|
-
|
37
|
-
@epilogue = epilogue.sub(/^\r\n/m, '') if epilogue
|
38
|
-
|
39
|
-
@parts = parts.map{|p| p.sub(/^\r\n/m, '').sub(/\r\n$/m, '')}.map{|p| Part.new(p)}
|
40
|
-
end
|
41
|
-
|
42
|
-
attr_reader :boundary, :preamble, :parts, :epilogue
|
43
|
-
alias :part :parts
|
44
|
-
end
|
45
|
-
|
@@ -1,95 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
require 'httpthumbnailer/multipart_response'
|
3
|
-
|
4
|
-
describe MultipartResponse do
|
5
|
-
describe "parsing" do
|
6
|
-
it "should privide preamble, parts with headers and epilogue" do
|
7
|
-
content_type_header = 'multipart/mixed; boundary="cut here"'
|
8
|
-
body =
|
9
|
-
"""hello
|
10
|
-
--cut here
|
11
|
-
Content-Type: text/plain
|
12
|
-
|
13
|
-
part 1
|
14
|
-
--cut here
|
15
|
-
Content-Type: text/html
|
16
|
-
Content-Transfer-Encoding: base64
|
17
|
-
|
18
|
-
part 2
|
19
|
-
--cut here
|
20
|
-
part 3
|
21
|
-
--cut here--
|
22
|
-
world""".gsub!("\n", "\r\n")
|
23
|
-
|
24
|
-
mr = MultipartResponse.new(content_type_header, body)
|
25
|
-
mr.preamble.should == "hello"
|
26
|
-
|
27
|
-
mr.parts[0].body.should == "part 1"
|
28
|
-
mr.parts[0].header['Content-Type'].should == "text/plain"
|
29
|
-
|
30
|
-
mr.parts[1].body.should == "part 2"
|
31
|
-
mr.parts[1].header['Content-Type'].should == "text/html"
|
32
|
-
mr.parts[1].header['Content-Transfer-Encoding'].should == "base64"
|
33
|
-
|
34
|
-
mr.parts[2].body.should == "part 3"
|
35
|
-
|
36
|
-
mr.epilogue.should == "world"
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should privide nil preamble if no prologue sent" do
|
40
|
-
content_type_header = 'multipart/mixed; boundary="cut here"'
|
41
|
-
body =
|
42
|
-
"""--cut here
|
43
|
-
part 1
|
44
|
-
--cut here--""".gsub!("\n", "\r\n")
|
45
|
-
|
46
|
-
mr = MultipartResponse.new(content_type_header, body)
|
47
|
-
mr.preamble.should be_nil
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should privide nil epilogue if no epilogue sent" do
|
51
|
-
content_type_header = 'multipart/mixed; boundary="cut here"'
|
52
|
-
body =
|
53
|
-
"""--cut here
|
54
|
-
part 1
|
55
|
-
--cut here--""".gsub!("\n", "\r\n")
|
56
|
-
|
57
|
-
mr = MultipartResponse.new(content_type_header, body)
|
58
|
-
mr.epilogue.should be_nil
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should provide default mime type of text/plain if no Content-Type header specified" do
|
62
|
-
content_type_header = 'multipart/mixed; boundary="cut here"'
|
63
|
-
body =
|
64
|
-
"""--cut here
|
65
|
-
part 1
|
66
|
-
--cut here--""".gsub!("\n", "\r\n")
|
67
|
-
|
68
|
-
mr = MultipartResponse.new(content_type_header, body)
|
69
|
-
mr.part[0].header['Content-Type'].should == 'text/plain'
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should fail with MultipartResponse::NoBoundaryFoundInContentTypeError if no boundary specified in content type header" do
|
73
|
-
lambda {
|
74
|
-
MultipartResponse.new("fas", "")
|
75
|
-
}.should raise_error MultipartResponse::NoBoundaryFoundInContentTypeError
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
it "provides part alias" do
|
80
|
-
content_type_header = 'multipart/mixed; boundary="cut here"'
|
81
|
-
body =
|
82
|
-
"""--cut here
|
83
|
-
part 1
|
84
|
-
--cut here
|
85
|
-
part 2
|
86
|
-
--cut here
|
87
|
-
part 3
|
88
|
-
--cut here--""".gsub!("\n", "\r\n")
|
89
|
-
|
90
|
-
mr = MultipartResponse.new(content_type_header, body)
|
91
|
-
mr.part[0].body.should == "part 1"
|
92
|
-
mr.part[1].body.should == "part 2"
|
93
|
-
mr.part[2].body.should == "part 3"
|
94
|
-
end
|
95
|
-
end
|
data/spec/thumbnailer_spec.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
require 'httpthumbnailer/thumbnailer'
|
3
|
-
|
4
|
-
describe ThumbnailSpec do
|
5
|
-
it "should store thumbanil attributes method, widht, height and options" do
|
6
|
-
t = ThumbnailSpec.new('pad', 128, 256, 'PNG', 'background' => '0x00ffff')
|
7
|
-
t.method.should == 'pad'
|
8
|
-
t.width.should == 128
|
9
|
-
t.height.should == 256
|
10
|
-
t.format.should == 'PNG'
|
11
|
-
t.mime.should == 'image/png'
|
12
|
-
t.options.should == { 'background' => '0x00ffff' }
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should return full jpeg mime time on JPG format" do
|
16
|
-
t = ThumbnailSpec.new('pad', 128, 256, 'JPG')
|
17
|
-
t.format.should == 'JPG'
|
18
|
-
t.mime.should == 'image/jpeg'
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe Thumbnailer do
|
23
|
-
it 'should allow adding new method of thumbnails' do
|
24
|
-
t = Thumbnailer.new
|
25
|
-
|
26
|
-
t.method('test') do |image, spec|
|
27
|
-
image + spec.width + spec.height + spec.format.to_i + spec.options[:magic]
|
28
|
-
end
|
29
|
-
|
30
|
-
t.process_image(256, ThumbnailSpec.new('test', 128, 32, '8', :magic => 64)).should == 256 + 128 + 32 + 8 + 64
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|