fragmenter 1.0.0.rc2 → 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.
- checksums.yaml +4 -4
- data/{HISTORY.md → CHANGELOG.md} +5 -0
- data/README.md +12 -0
- data/fragmenter.gemspec +4 -2
- data/lib/fragmenter.rb +1 -0
- data/lib/fragmenter/dummy_io.rb +13 -0
- data/lib/fragmenter/rails/controller.rb +5 -5
- data/lib/fragmenter/version.rb +1 -1
- data/lib/fragmenter/wrapper.rb +6 -0
- data/spec/fragmenter/dummy_io_spec.rb +39 -0
- data/spec/fragmenter/rails/controller_spec.rb +5 -4
- data/spec/fragmenter/wrapper_spec.rb +25 -10
- data/spec/requests/uploading_fragments_spec.rb +105 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/resource.rb +9 -0
- data/spec/support/uploads_app.rb +30 -0
- data/spec/upload_server.rb +11 -0
- metadata +44 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 492790d602b011f85a9c59b2e7730e897b50b4c2
|
4
|
+
data.tar.gz: 15ce8668a07766801e7d1fbfa946e0a51f8481f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c5961781e29d00c847b1683e87f50daf5bff5998db3eb92c0acc61065c9a8a657c4a178b695f2002ae3fcc99a81db81e8047f5679403d058554ebb3d9e213f3
|
7
|
+
data.tar.gz: afe3e60454e3b2e304cd351562befcad35168fddc5d0624c4ca4c4284b174a0c318323bdecf09c6e631fb9d6f92b483ba77322bffd6e9099baea8073a3d8eb4e
|
data/{HISTORY.md → CHANGELOG.md}
RENAMED
data/README.md
CHANGED
@@ -143,6 +143,18 @@ curl -i
|
|
143
143
|
#=> { "content_type": "image/jpeg", "fragments": [1,2], "total": 2 }
|
144
144
|
```
|
145
145
|
|
146
|
+
If you need to customize the status codes for partial or complete `PUT`
|
147
|
+
requests you can override the `update_status` method within the controller:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
private
|
151
|
+
|
152
|
+
# Return 201 Created instead of 202 Accepted
|
153
|
+
def update_status
|
154
|
+
uploader.complete? ? 201 : 200
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
146
158
|
### Validation
|
147
159
|
|
148
160
|
Often you will want to be sure that all of the data is being stored without any
|
data/fragmenter.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
|
|
10
10
|
gem.email = ['parker@sorentwo.com']
|
11
11
|
gem.homepage = 'https://github.com/dscout/fragmenter'
|
12
12
|
gem.license = 'MIT'
|
13
|
-
gem.description =
|
13
|
+
gem.description = 'Fragmentize and rebuild data'
|
14
14
|
gem.summary = <<-SUMMARY
|
15
15
|
Multipart upload support backed by Redis. Fragmenter handles storing
|
16
16
|
multiple parts of a larger binary and rebuilding it back into the original
|
@@ -22,5 +22,7 @@ Gem::Specification.new do |gem|
|
|
22
22
|
gem.require_paths = ['lib']
|
23
23
|
|
24
24
|
gem.add_dependency 'redis', '~> 3.0.0'
|
25
|
-
gem.add_development_dependency 'rspec',
|
25
|
+
gem.add_development_dependency 'rspec', '~> 2.14.0'
|
26
|
+
gem.add_development_dependency 'rack-test', '~> 0.6.2'
|
27
|
+
gem.add_development_dependency 'sinatra', '~> 1.4.3'
|
26
28
|
end
|
data/lib/fragmenter.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Fragmenter
|
2
|
+
class DummyIO < StringIO
|
3
|
+
attr_writer :content_type, :original_filename
|
4
|
+
|
5
|
+
def original_filename
|
6
|
+
@original_filename || ['dummy', content_type.split('/').last].join('.')
|
7
|
+
end
|
8
|
+
|
9
|
+
def content_type
|
10
|
+
@content_type || 'application/octet-stream'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -2,7 +2,7 @@ module Fragmenter
|
|
2
2
|
module Rails
|
3
3
|
module Controller
|
4
4
|
def show
|
5
|
-
render json: fragmenter.as_json
|
5
|
+
render json: fragmenter.as_json, status: 200
|
6
6
|
end
|
7
7
|
|
8
8
|
def update
|
@@ -11,14 +11,14 @@ module Fragmenter
|
|
11
11
|
else
|
12
12
|
render json: {
|
13
13
|
message: 'Upload of part failed.', errors: uploader.errors
|
14
|
-
}, status:
|
14
|
+
}, status: 422
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
def destroy
|
19
19
|
fragmenter.clean!
|
20
20
|
|
21
|
-
render nothing: true, status:
|
21
|
+
render nothing: true, status: 204
|
22
22
|
end
|
23
23
|
|
24
24
|
private
|
@@ -37,13 +37,13 @@ module Fragmenter
|
|
37
37
|
resource: resource,
|
38
38
|
fragmenter: fragmenter,
|
39
39
|
body: request.body,
|
40
|
-
headers: request.
|
40
|
+
headers: request.env
|
41
41
|
), validators
|
42
42
|
)
|
43
43
|
end
|
44
44
|
|
45
45
|
def update_status
|
46
|
-
uploader.complete? ?
|
46
|
+
uploader.complete? ? 202 : 200
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
data/lib/fragmenter/version.rb
CHANGED
data/lib/fragmenter/wrapper.rb
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'fragmenter/dummy_io'
|
2
|
+
|
3
|
+
describe Fragmenter::DummyIO do
|
4
|
+
it 'provies IO like access' do
|
5
|
+
io = Fragmenter::DummyIO.new
|
6
|
+
|
7
|
+
expect(io).to respond_to(:read)
|
8
|
+
expect(io).to respond_to(:length)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#content_type' do
|
12
|
+
it 'defaults to application/octet-stream' do
|
13
|
+
expect(Fragmenter::DummyIO.new.content_type).to eq('application/octet-stream')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'can be overridden' do
|
17
|
+
io = Fragmenter::DummyIO.new
|
18
|
+
io.content_type = 'image/png'
|
19
|
+
|
20
|
+
expect(io.content_type).to eq('image/png')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#original_filename' do
|
25
|
+
it 'defaults to a fake mime comprised of dummy and the content type' do
|
26
|
+
io = Fragmenter::DummyIO.new
|
27
|
+
io.content_type = 'image/png'
|
28
|
+
|
29
|
+
expect(io.original_filename).to eq('dummy.png')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'can be overriden' do
|
33
|
+
io = Fragmenter::DummyIO.new
|
34
|
+
io.original_filename = 'wonderful.png'
|
35
|
+
|
36
|
+
expect(io.original_filename).to eq('wonderful.png')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -22,7 +22,8 @@ describe Fragmenter::Rails::Controller do
|
|
22
22
|
controller.show
|
23
23
|
|
24
24
|
expect(controller).to have_received(:render).with(
|
25
|
-
json: { 'fragments' => [] }
|
25
|
+
json: { 'fragments' => [] },
|
26
|
+
status: 200
|
26
27
|
)
|
27
28
|
end
|
28
29
|
end
|
@@ -40,7 +41,7 @@ describe Fragmenter::Rails::Controller do
|
|
40
41
|
expect(resource.fragmenter).to have_received(:clean!)
|
41
42
|
expect(controller).to have_received(:render).with(
|
42
43
|
nothing: true,
|
43
|
-
status:
|
44
|
+
status: 204
|
44
45
|
)
|
45
46
|
end
|
46
47
|
end
|
@@ -59,7 +60,7 @@ describe Fragmenter::Rails::Controller do
|
|
59
60
|
expect(uploader).to have_received(:store)
|
60
61
|
expect(controller).to have_received(:render).with(
|
61
62
|
json: { 'fragments' => [] },
|
62
|
-
status:
|
63
|
+
status: 200
|
63
64
|
)
|
64
65
|
end
|
65
66
|
|
@@ -78,7 +79,7 @@ describe Fragmenter::Rails::Controller do
|
|
78
79
|
message: 'Upload of part failed.',
|
79
80
|
errors: []
|
80
81
|
},
|
81
|
-
status:
|
82
|
+
status: 422
|
82
83
|
)
|
83
84
|
end
|
84
85
|
end
|
@@ -1,15 +1,17 @@
|
|
1
|
-
require 'fragmenter
|
1
|
+
require 'fragmenter'
|
2
2
|
|
3
3
|
describe Fragmenter::Wrapper do
|
4
4
|
let(:object) { double(:object, id: 1001) }
|
5
5
|
let(:engine_class) { double(:engine_class, new: engine) }
|
6
6
|
let(:engine) { double(:engine) }
|
7
7
|
|
8
|
-
subject(:
|
8
|
+
subject(:wrapper) do
|
9
|
+
Fragmenter::Wrapper.new(object, engine_class)
|
10
|
+
end
|
9
11
|
|
10
12
|
describe '#key' do
|
11
13
|
it 'composes a key from the object class and id value' do
|
12
|
-
|
14
|
+
expect(wrapper.key).to match(/[a-z]+-\d+/)
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -18,14 +20,14 @@ describe Fragmenter::Wrapper do
|
|
18
20
|
let(:headers) { {} }
|
19
21
|
|
20
22
|
it 'delegates #store to the storage engine' do
|
21
|
-
engine.
|
23
|
+
expect(engine).to receive(:store).with(blob, headers)
|
22
24
|
|
23
|
-
|
25
|
+
wrapper.store(blob, headers)
|
24
26
|
end
|
25
27
|
|
26
28
|
it 'delegates #fragments to the storage engine' do
|
27
|
-
engine.
|
28
|
-
|
29
|
+
expect(engine).to receive(:fragments)
|
30
|
+
wrapper.fragments
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
@@ -34,9 +36,22 @@ describe Fragmenter::Wrapper do
|
|
34
36
|
engine.stub('meta' => { 'content_type' => 'application/octet-stream' },
|
35
37
|
'fragments' => ['1', '2'])
|
36
38
|
|
37
|
-
|
38
|
-
json.
|
39
|
-
json.
|
39
|
+
wrapper.as_json.tap do |json|
|
40
|
+
expect(json).to have_key('content_type')
|
41
|
+
expect(json).to have_key('fragments')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#to_io' do
|
47
|
+
it 'wraps the rebuilt data in a Rack::Multipart::UploadedFile compatible IO object' do
|
48
|
+
engine.stub(meta: { 'content_type' => 'image/png' }, rebuild: '0101010')
|
49
|
+
|
50
|
+
wrapper.to_io.tap do |io|
|
51
|
+
expect(io).to be_instance_of(Fragmenter::DummyIO)
|
52
|
+
expect(io.read).to eq('0101010')
|
53
|
+
expect(io.content_type).to eq('image/png')
|
54
|
+
expect(io.original_filename).to eq('dummy.png')
|
40
55
|
end
|
41
56
|
end
|
42
57
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json'
|
3
|
+
require 'rack/test'
|
4
|
+
require 'support/resource'
|
5
|
+
require 'support/uploads_app'
|
6
|
+
|
7
|
+
describe 'Uploading Fragments' do
|
8
|
+
include Rack::Test::Methods
|
9
|
+
|
10
|
+
let(:app) { UploadsApp }
|
11
|
+
let(:resource) { Resource.new(200) }
|
12
|
+
|
13
|
+
around do |example|
|
14
|
+
UploadsApp.resource = resource
|
15
|
+
Fragmenter.logger = Logger.new('/dev/null')
|
16
|
+
|
17
|
+
example.run
|
18
|
+
|
19
|
+
Fragmenter.logger = nil
|
20
|
+
UploadsApp.resource = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'Lists uploaded fragments' do
|
24
|
+
get '/'
|
25
|
+
|
26
|
+
expect(last_response.status).to eq(200)
|
27
|
+
expect(decoded_response).to eq('fragments' => [])
|
28
|
+
|
29
|
+
store_fragment(number: 1, total: 2)
|
30
|
+
|
31
|
+
get '/'
|
32
|
+
|
33
|
+
expect(last_response.status).to eq(200)
|
34
|
+
expect(decoded_response).to eq(
|
35
|
+
'content_type' => 'application/octet-stream',
|
36
|
+
'fragments' => %w[1],
|
37
|
+
'total' => '2'
|
38
|
+
)
|
39
|
+
|
40
|
+
clean_fragments!
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'Stores uploaded fragments' do
|
44
|
+
header 'Content-Type', 'image/gif'
|
45
|
+
header 'X-Fragment-Number', '1'
|
46
|
+
header 'X-Fragment-Total', '2'
|
47
|
+
|
48
|
+
put '/', file_data('micro.gif')
|
49
|
+
|
50
|
+
expect(last_response.status).to eq(200)
|
51
|
+
expect(decoded_response).to eq(
|
52
|
+
'content_type' => 'image/gif',
|
53
|
+
'fragments' => %w[1],
|
54
|
+
'total' => '2'
|
55
|
+
)
|
56
|
+
|
57
|
+
header 'X-Fragment-Number', '2'
|
58
|
+
header 'X-Fragment-Total', '2'
|
59
|
+
|
60
|
+
put '/', file_data('micro.gif')
|
61
|
+
|
62
|
+
expect(last_response.status).to eq(202)
|
63
|
+
expect(decoded_response).to eq('fragments' => [])
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'Destroys uploaded fragments' do
|
67
|
+
store_fragment(number: 1, total: 2)
|
68
|
+
|
69
|
+
delete '/'
|
70
|
+
|
71
|
+
expect(last_response.status).to eq(204)
|
72
|
+
expect(last_response.body).to eq('')
|
73
|
+
expect(fragmenter.fragments.length).to be_zero
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def file_data(file)
|
79
|
+
IO.read("spec/fixtures/#{file}")
|
80
|
+
end
|
81
|
+
|
82
|
+
def decoded_response
|
83
|
+
JSON.parse(last_response.body)
|
84
|
+
end
|
85
|
+
|
86
|
+
def fragmenter
|
87
|
+
resource.fragmenter
|
88
|
+
end
|
89
|
+
|
90
|
+
def store_fragment(options = {})
|
91
|
+
number = options[:number]
|
92
|
+
total = options[:total]
|
93
|
+
|
94
|
+
fragmenter.store(
|
95
|
+
'0101',
|
96
|
+
content_type: 'application/octet-stream',
|
97
|
+
number: number,
|
98
|
+
total: total
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
def clean_fragments!
|
103
|
+
resource.fragmenter.clean!
|
104
|
+
end
|
105
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'fragmenter/rails/controller'
|
2
|
+
require 'sinatra/base'
|
3
|
+
|
4
|
+
class UploadsApp < Sinatra::Base
|
5
|
+
include Fragmenter::Rails::Controller
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :resource
|
9
|
+
end
|
10
|
+
|
11
|
+
get('/') { show }
|
12
|
+
put('/') { update }
|
13
|
+
delete('/') { destroy }
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def resource
|
18
|
+
self.class.resource
|
19
|
+
end
|
20
|
+
|
21
|
+
def render(options)
|
22
|
+
body = if options[:json]
|
23
|
+
JSON.dump(options[:json])
|
24
|
+
else
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
[options[:status], body]
|
29
|
+
end
|
30
|
+
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
|
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-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.14.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rack-test
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.6.2
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.6.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sinatra
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.4.3
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.4.3
|
41
69
|
description: Fragmentize and rebuild data
|
42
70
|
email:
|
43
71
|
- parker@sorentwo.com
|
@@ -48,13 +76,14 @@ files:
|
|
48
76
|
- .gitignore
|
49
77
|
- .rspec
|
50
78
|
- .travis.yml
|
79
|
+
- CHANGELOG.md
|
51
80
|
- Gemfile
|
52
|
-
- HISTORY.md
|
53
81
|
- LICENSE.txt
|
54
82
|
- README.md
|
55
83
|
- Rakefile
|
56
84
|
- fragmenter.gemspec
|
57
85
|
- lib/fragmenter.rb
|
86
|
+
- lib/fragmenter/dummy_io.rb
|
58
87
|
- lib/fragmenter/fragment.rb
|
59
88
|
- lib/fragmenter/rails/controller.rb
|
60
89
|
- lib/fragmenter/rails/model.rb
|
@@ -67,6 +96,7 @@ files:
|
|
67
96
|
- lib/fragmenter/version.rb
|
68
97
|
- lib/fragmenter/wrapper.rb
|
69
98
|
- spec/fixtures/micro.gif
|
99
|
+
- spec/fragmenter/dummy_io_spec.rb
|
70
100
|
- spec/fragmenter/fragment_spec.rb
|
71
101
|
- spec/fragmenter/rails/controller_spec.rb
|
72
102
|
- spec/fragmenter/rails/model_spec.rb
|
@@ -78,7 +108,11 @@ files:
|
|
78
108
|
- spec/fragmenter/validators/image_validator_spec.rb
|
79
109
|
- spec/fragmenter/wrapper_spec.rb
|
80
110
|
- spec/fragmenter_spec.rb
|
111
|
+
- spec/requests/uploading_fragments_spec.rb
|
81
112
|
- spec/spec_helper.rb
|
113
|
+
- spec/support/resource.rb
|
114
|
+
- spec/support/uploads_app.rb
|
115
|
+
- spec/upload_server.rb
|
82
116
|
homepage: https://github.com/dscout/fragmenter
|
83
117
|
licenses:
|
84
118
|
- MIT
|
@@ -94,9 +128,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
128
|
version: '0'
|
95
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
130
|
requirements:
|
97
|
-
- - '
|
131
|
+
- - '>='
|
98
132
|
- !ruby/object:Gem::Version
|
99
|
-
version:
|
133
|
+
version: '0'
|
100
134
|
requirements: []
|
101
135
|
rubyforge_project:
|
102
136
|
rubygems_version: 2.0.0
|
@@ -107,6 +141,7 @@ summary: Multipart upload support backed by Redis. Fragmenter handles storing mu
|
|
107
141
|
have been stored.
|
108
142
|
test_files:
|
109
143
|
- spec/fixtures/micro.gif
|
144
|
+
- spec/fragmenter/dummy_io_spec.rb
|
110
145
|
- spec/fragmenter/fragment_spec.rb
|
111
146
|
- spec/fragmenter/rails/controller_spec.rb
|
112
147
|
- spec/fragmenter/rails/model_spec.rb
|
@@ -118,4 +153,8 @@ test_files:
|
|
118
153
|
- spec/fragmenter/validators/image_validator_spec.rb
|
119
154
|
- spec/fragmenter/wrapper_spec.rb
|
120
155
|
- spec/fragmenter_spec.rb
|
156
|
+
- spec/requests/uploading_fragments_spec.rb
|
121
157
|
- spec/spec_helper.rb
|
158
|
+
- spec/support/resource.rb
|
159
|
+
- spec/support/uploads_app.rb
|
160
|
+
- spec/upload_server.rb
|