fragmenter 1.0.0.rc1 → 1.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/HISTORY.md +9 -0
- data/README.md +11 -6
- data/fragmenter.gemspec +1 -0
- data/lib/fragmenter.rb +1 -0
- data/lib/fragmenter/request.rb +1 -1
- data/lib/fragmenter/services/uploader.rb +8 -4
- data/lib/fragmenter/validators/checksum_validator.rb +4 -0
- data/lib/fragmenter/validators/image_validator.rb +42 -0
- data/lib/fragmenter/version.rb +1 -1
- data/spec/fixtures/micro.gif +0 -0
- data/spec/fragmenter/request_spec.rb +5 -0
- data/spec/fragmenter/services/uploader_spec.rb +29 -4
- data/spec/fragmenter/validators/checksum_validator_spec.rb +9 -7
- data/spec/fragmenter/validators/image_validator_spec.rb +35 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b5931e8212db98c33d0d78dc0b857214a27f8c33
|
4
|
+
data.tar.gz: 9cc17e75a60b88e87f75e561a7f203874e769898
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f48a59ba0829ad7f7366a3e32c3ccb6c9639cabf6cae23fdf54bc6f877e5f184e20bc34e84f83c6cfc9a013923abf3c9deffc1eaf9502e0915fadfdc3bbd6c0
|
7
|
+
data.tar.gz: 6b15e275846e7eb2d3199016f09f3a7e60a766850bdd17e3db49f0bfce624492b9721ea3c17b3dbb6bbd466ab78982fe98d6161cc05dafc4745b9ea525ee759c
|
data/HISTORY.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# 1.0.0.rc2
|
2
|
+
|
3
|
+
* Automatically rewind IO objects between reads. This fixes the issue of
|
4
|
+
multiple validations preventing storage.
|
5
|
+
* Expose storage errors along with validation errors when using the uploader.
|
6
|
+
* Make good on the documented `ImageValidator`. The implemented version has no
|
7
|
+
additional gem dependencies, but does rely on ImageMagick for its `identify`
|
8
|
+
command.
|
9
|
+
|
1
10
|
# 1.0.0.rc1
|
2
11
|
|
3
12
|
* Add modules for easiy integration with Rails controllers and models.
|
data/README.md
CHANGED
@@ -170,10 +170,11 @@ response with an accompanying message and errors:
|
|
170
170
|
]
|
171
171
|
}
|
172
172
|
```
|
173
|
+
|
173
174
|
As images uploads are a common use-case for fragmented uploading an
|
174
|
-
ImageValidator is included, but not one of the
|
175
|
-
|
176
|
-
|
175
|
+
ImageValidator is included, but not as one of the defaults. You can control
|
176
|
+
which validators are used by overriding the `validators` method within the
|
177
|
+
controller:
|
177
178
|
|
178
179
|
```ruby
|
179
180
|
class AvatarUploader < ApplicationController
|
@@ -188,8 +189,12 @@ end
|
|
188
189
|
```
|
189
190
|
|
190
191
|
To add a custom validator you must add it at some point in the validator chain.
|
191
|
-
A validator can be any class that responds to `valid
|
192
|
-
|
193
|
-
|
192
|
+
A validator can be any class that responds to `valid?`, `part?`, and provides a
|
193
|
+
list of errors. See the [ImageValidator][1] for an example validator that only
|
194
|
+
performs validation when all fragments are complete.
|
195
|
+
|
196
|
+
Note that [ImageMagick][2] is required for the ImageValidator to work, but it
|
197
|
+
doesn't require `RMagick` or `MiniMagick`.
|
194
198
|
|
195
199
|
[1]:lib/fragmenter/validators/image
|
200
|
+
[2]:http://www.imagemagick.org/script/identify.php
|
data/fragmenter.gemspec
CHANGED
@@ -9,6 +9,7 @@ Gem::Specification.new do |gem|
|
|
9
9
|
gem.authors = ['Parker Selbert']
|
10
10
|
gem.email = ['parker@sorentwo.com']
|
11
11
|
gem.homepage = 'https://github.com/dscout/fragmenter'
|
12
|
+
gem.license = 'MIT'
|
12
13
|
gem.description = %q{Fragmentize and rebuild data}
|
13
14
|
gem.summary = <<-SUMMARY
|
14
15
|
Multipart upload support backed by Redis. Fragmenter handles storing
|
data/lib/fragmenter.rb
CHANGED
data/lib/fragmenter/request.rb
CHANGED
@@ -16,7 +16,7 @@ module Fragmenter
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def store
|
19
|
-
stored =
|
19
|
+
stored = parts_valid? && storer.store && rebuilt_valid?
|
20
20
|
@complete = fragmenter.complete?
|
21
21
|
|
22
22
|
if stored && complete?
|
@@ -27,15 +27,19 @@ module Fragmenter
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def errors
|
30
|
-
validator_instances.map(&:errors).flatten
|
30
|
+
[validator_instances.map(&:errors), storer.errors].flatten
|
31
31
|
end
|
32
32
|
|
33
33
|
def complete?
|
34
34
|
!!@complete
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
validator_instances.all?(&:valid?)
|
37
|
+
def parts_valid?
|
38
|
+
validator_instances.select(&:part?).all?(&:valid?)
|
39
|
+
end
|
40
|
+
|
41
|
+
def rebuilt_valid?
|
42
|
+
validator_instances.reject(&:part?).all?(&:valid?)
|
39
43
|
end
|
40
44
|
|
41
45
|
private
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Fragmenter
|
2
|
+
module Validators
|
3
|
+
class ImageValidator
|
4
|
+
attr_reader :errors, :request
|
5
|
+
|
6
|
+
def initialize(request)
|
7
|
+
@request = request
|
8
|
+
@errors = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def part?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
return true unless fragmenter.complete?
|
17
|
+
|
18
|
+
identifiable = identifiable?
|
19
|
+
|
20
|
+
unless identifiable
|
21
|
+
errors << 'Rebuilt fragments are not a valid image'
|
22
|
+
end
|
23
|
+
|
24
|
+
identifiable
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def fragmenter
|
30
|
+
request.fragmenter
|
31
|
+
end
|
32
|
+
|
33
|
+
def identifiable?
|
34
|
+
IO.popen('identify -', 'w', err: '/dev/null', out: '/dev/null') do |io|
|
35
|
+
io << fragmenter.rebuild
|
36
|
+
end
|
37
|
+
|
38
|
+
$?.success?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/fragmenter/version.rb
CHANGED
Binary file
|
@@ -7,6 +7,11 @@ describe Fragmenter::Request do
|
|
7
7
|
expect(request.body).to eq('blob')
|
8
8
|
end
|
9
9
|
|
10
|
+
it 'automaticaly rewinds after reading IO' do
|
11
|
+
request = Fragmenter::Request.new(body: StringIO.new('blob'))
|
12
|
+
expect([request.body, request.body]).to eq(%w[blob blob])
|
13
|
+
end
|
14
|
+
|
10
15
|
it 'does not attempt to read the body if it is not IO' do
|
11
16
|
request = Fragmenter::Request.new(body: 'blob')
|
12
17
|
expect(request.body).to eq('blob')
|
@@ -13,8 +13,12 @@ describe Fragmenter::Services::Uploader do
|
|
13
13
|
expect(uploader.store).to be_true
|
14
14
|
end
|
15
15
|
|
16
|
-
it 'does not attempt to store fragments if any validators are invalid' do
|
16
|
+
it 'does not attempt to store fragments if any part validators are invalid' do
|
17
17
|
validator = Struct.new(:request) do
|
18
|
+
def part?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
18
22
|
def valid?
|
19
23
|
false
|
20
24
|
end
|
@@ -42,6 +46,25 @@ describe Fragmenter::Services::Uploader do
|
|
42
46
|
|
43
47
|
uploader.store
|
44
48
|
end
|
49
|
+
|
50
|
+
it 'does not instruct the resource to rebuild if the full content is invalid' do
|
51
|
+
validator = Struct.new(:request) do
|
52
|
+
def part?; false; end
|
53
|
+
def valid?; false; end
|
54
|
+
end
|
55
|
+
|
56
|
+
resource = double(:resource)
|
57
|
+
fragmenter = double(:fragmenter, complete?: true)
|
58
|
+
storer = double(:storer, store: true)
|
59
|
+
request = Fragmenter::Request.new(resource: resource, fragmenter: fragmenter)
|
60
|
+
uploader = Uploader.new(request, [validator])
|
61
|
+
|
62
|
+
uploader.storer = storer
|
63
|
+
|
64
|
+
expect(resource).to_not receive(:rebuild_fragments)
|
65
|
+
|
66
|
+
uploader.store
|
67
|
+
end
|
45
68
|
end
|
46
69
|
|
47
70
|
describe '#complete?' do
|
@@ -53,21 +76,23 @@ describe Fragmenter::Services::Uploader do
|
|
53
76
|
end
|
54
77
|
|
55
78
|
describe '#errors' do
|
56
|
-
it 'merges the errors from all validators' do
|
79
|
+
it 'merges the errors from all validators and the storer' do
|
57
80
|
validator_a = Struct.new(:request) do
|
81
|
+
def part?; true; end
|
58
82
|
def valid?; false; end
|
59
83
|
def errors; ['bad']; end
|
60
84
|
end
|
61
85
|
|
62
86
|
validator_b = Struct.new(:request) do
|
87
|
+
def part?; true; end
|
63
88
|
def valid?; false; end
|
64
89
|
def errors; ['invalid']; end
|
65
90
|
end
|
66
91
|
|
67
92
|
uploader = Uploader.new({}, [validator_a, validator_b])
|
68
|
-
uploader.
|
93
|
+
uploader.storer = double(:storer, errors: ['horrible'])
|
69
94
|
|
70
|
-
expect(uploader.errors).to eq(%w[bad invalid])
|
95
|
+
expect(uploader.errors).to eq(%w[bad invalid horrible])
|
71
96
|
end
|
72
97
|
end
|
73
98
|
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'fragmenter/validators/checksum_validator'
|
2
2
|
|
3
3
|
describe Fragmenter::Validators::ChecksumValidator do
|
4
|
-
|
4
|
+
let(:validator) do
|
5
|
+
Fragmenter::Validators::ChecksumValidator
|
6
|
+
end
|
5
7
|
|
6
8
|
describe '#valid?' do
|
7
9
|
it 'is always valid if no expected checksum was given' do
|
8
|
-
expect(
|
10
|
+
expect(validator.new(double(headers: {}))).to be_valid
|
9
11
|
end
|
10
12
|
|
11
13
|
it 'is valid if the expected checksum matches the body checksum' do
|
@@ -14,7 +16,7 @@ describe Fragmenter::Validators::ChecksumValidator do
|
|
14
16
|
headers: { 'HTTP_CONTENT_MD5' => '4ac8660969d304047daa9c3539f63682' }
|
15
17
|
)
|
16
18
|
|
17
|
-
expect(
|
19
|
+
expect(validator.new(request)).to be_valid
|
18
20
|
end
|
19
21
|
|
20
22
|
it 'is not valid if the expected checksum does not match the body checksum' do
|
@@ -23,7 +25,7 @@ describe Fragmenter::Validators::ChecksumValidator do
|
|
23
25
|
headers: { 'HTTP_CONTENT_MD5' => 'a9c3539f636824ac8660969d304047da' }
|
24
26
|
)
|
25
27
|
|
26
|
-
expect(
|
28
|
+
expect(validator.new(request)).to_not be_valid
|
27
29
|
end
|
28
30
|
|
29
31
|
it 'records an error when the checksums do not match' do
|
@@ -32,10 +34,10 @@ describe Fragmenter::Validators::ChecksumValidator do
|
|
32
34
|
headers: { 'HTTP_CONTENT_MD5' => 'a9c3539f636824ac8660969d304047da' }
|
33
35
|
)
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
+
instance = validator.new(request)
|
38
|
+
instance.valid?
|
37
39
|
|
38
|
-
expect(
|
40
|
+
expect(instance.errors.length).to be_nonzero
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'fragmenter/request'
|
2
|
+
require 'fragmenter/validators/image_validator'
|
3
|
+
|
4
|
+
describe Fragmenter::Validators::ImageValidator do
|
5
|
+
let(:validator) do
|
6
|
+
Fragmenter::Validators::ImageValidator
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#valid?' do
|
10
|
+
it 'bypasses validation checking if the fragmenter is incomplete' do
|
11
|
+
fragmenter = double(:fragmenter, complete?: false)
|
12
|
+
request = Fragmenter::Request.new(fragmenter: fragmenter)
|
13
|
+
|
14
|
+
expect(validator.new(request)).to be_valid
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'is invalid with a body that can not be parsed as an image' do
|
18
|
+
fragmenter = double(:fragmenter, complete?: true, rebuild: '01010101')
|
19
|
+
request = Fragmenter::Request.new(fragmenter: fragmenter)
|
20
|
+
|
21
|
+
instance = validator.new(request)
|
22
|
+
|
23
|
+
expect(instance).to_not be_valid
|
24
|
+
expect(instance.errors.length).to be_nonzero
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'is valid with a body that can be parsed as an image' do
|
28
|
+
image = IO.read('spec/fixtures/micro.gif')
|
29
|
+
fragmenter = double(:fragmenter, complete?: true, rebuild: image)
|
30
|
+
request = Fragmenter::Request.new(fragmenter: fragmenter)
|
31
|
+
|
32
|
+
expect(validator.new(request)).to be_valid
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fragmenter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Parker Selbert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -63,8 +63,10 @@ files:
|
|
63
63
|
- lib/fragmenter/services/storer.rb
|
64
64
|
- lib/fragmenter/services/uploader.rb
|
65
65
|
- lib/fragmenter/validators/checksum_validator.rb
|
66
|
+
- lib/fragmenter/validators/image_validator.rb
|
66
67
|
- lib/fragmenter/version.rb
|
67
68
|
- lib/fragmenter/wrapper.rb
|
69
|
+
- spec/fixtures/micro.gif
|
68
70
|
- spec/fragmenter/fragment_spec.rb
|
69
71
|
- spec/fragmenter/rails/controller_spec.rb
|
70
72
|
- spec/fragmenter/rails/model_spec.rb
|
@@ -73,11 +75,13 @@ files:
|
|
73
75
|
- spec/fragmenter/services/storer_spec.rb
|
74
76
|
- spec/fragmenter/services/uploader_spec.rb
|
75
77
|
- spec/fragmenter/validators/checksum_validator_spec.rb
|
78
|
+
- spec/fragmenter/validators/image_validator_spec.rb
|
76
79
|
- spec/fragmenter/wrapper_spec.rb
|
77
80
|
- spec/fragmenter_spec.rb
|
78
81
|
- spec/spec_helper.rb
|
79
82
|
homepage: https://github.com/dscout/fragmenter
|
80
|
-
licenses:
|
83
|
+
licenses:
|
84
|
+
- MIT
|
81
85
|
metadata: {}
|
82
86
|
post_install_message:
|
83
87
|
rdoc_options: []
|
@@ -102,6 +106,7 @@ summary: Multipart upload support backed by Redis. Fragmenter handles storing mu
|
|
102
106
|
parts of a larger binary and rebuilding it back into the original after all parts
|
103
107
|
have been stored.
|
104
108
|
test_files:
|
109
|
+
- spec/fixtures/micro.gif
|
105
110
|
- spec/fragmenter/fragment_spec.rb
|
106
111
|
- spec/fragmenter/rails/controller_spec.rb
|
107
112
|
- spec/fragmenter/rails/model_spec.rb
|
@@ -110,6 +115,7 @@ test_files:
|
|
110
115
|
- spec/fragmenter/services/storer_spec.rb
|
111
116
|
- spec/fragmenter/services/uploader_spec.rb
|
112
117
|
- spec/fragmenter/validators/checksum_validator_spec.rb
|
118
|
+
- spec/fragmenter/validators/image_validator_spec.rb
|
113
119
|
- spec/fragmenter/wrapper_spec.rb
|
114
120
|
- spec/fragmenter_spec.rb
|
115
121
|
- spec/spec_helper.rb
|