httpthumbnailer 0.3.1 → 1.0.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 +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
|
-
|