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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d849a0a1482e71d93c6c90ea5a9336e2ced2be6
4
- data.tar.gz: 1d87cae0a38cc7dddce3d76a08a5181a7d11587b
3
+ metadata.gz: b5931e8212db98c33d0d78dc0b857214a27f8c33
4
+ data.tar.gz: 9cc17e75a60b88e87f75e561a7f203874e769898
5
5
  SHA512:
6
- metadata.gz: 14a4a61707cf76f83ceff137473dd8343b2ec7a1a0f5c645900c78dbb472516a943075cdae551be02efdf2e7e527e87e7a01afe62e21299738d23f04914382e0
7
- data.tar.gz: 3720a5b353199f1be826f663b758873d0311d0fa4a032a9ebdb99bcfeedcad5059bf4e9b180fea48e2b359dd5726551e6093a89bd718a3bb9b9c6c1b0ebaa47d
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 default validators. You can
175
- control with validators are used by overriding the `validators` method within
176
- the controller:
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?` with a boolean value and
192
- provides a list of errors. See the [ImageValidator][1] for an example validator
193
- that only performs validation when all fragments are complete.
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
@@ -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
@@ -8,6 +8,7 @@ require 'fragmenter/rails/model'
8
8
  require 'fragmenter/services/uploader'
9
9
  require 'fragmenter/services/storer'
10
10
  require 'fragmenter/validators/checksum_validator'
11
+ require 'fragmenter/validators/image_validator'
11
12
 
12
13
  module Fragmenter
13
14
  class << self
@@ -11,7 +11,7 @@ module Fragmenter
11
11
 
12
12
  def body
13
13
  if @body.respond_to?(:read)
14
- @body.read
14
+ @body.read.tap { |_| @body.rewind }
15
15
  else
16
16
  @body
17
17
  end
@@ -16,7 +16,7 @@ module Fragmenter
16
16
  end
17
17
 
18
18
  def store
19
- stored = valid? && storer.store
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 valid?
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
@@ -10,6 +10,10 @@ module Fragmenter
10
10
  @errors = []
11
11
  end
12
12
 
13
+ def part?
14
+ true
15
+ end
16
+
13
17
  def valid?
14
18
  matches = expected.nil? || expected == calculated
15
19
 
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Fragmenter
2
- VERSION = '1.0.0.rc1'
2
+ VERSION = '1.0.0.rc2'
3
3
  end
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.valid?
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
- Validator = Fragmenter::Validators::ChecksumValidator
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(Validator.new(double(headers: {}))).to be_valid
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(Validator.new(request)).to be_valid
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(Validator.new(request)).to_not be_valid
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
- validator = Validator.new(request)
36
- validator.valid?
37
+ instance = validator.new(request)
38
+ instance.valid?
37
39
 
38
- expect(validator.errors.length).to be_nonzero
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.rc1
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-18 00:00:00.000000000 Z
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