saviour 0.2.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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +491 -0
  7. data/Rakefile +6 -0
  8. data/lib/saviour.rb +170 -0
  9. data/lib/saviour/base_uploader.rb +81 -0
  10. data/lib/saviour/config.rb +13 -0
  11. data/lib/saviour/file.rb +124 -0
  12. data/lib/saviour/local_storage.rb +72 -0
  13. data/lib/saviour/processors/digest.rb +16 -0
  14. data/lib/saviour/s3_storage.rb +77 -0
  15. data/lib/saviour/string_source.rb +15 -0
  16. data/lib/saviour/uploader/element.rb +19 -0
  17. data/lib/saviour/uploader/processors_runner.rb +88 -0
  18. data/lib/saviour/uploader/store_dir_extractor.rb +41 -0
  19. data/lib/saviour/url_source.rb +55 -0
  20. data/lib/saviour/version.rb +3 -0
  21. data/saviour.gemspec +26 -0
  22. data/spec/feature/access_to_model_and_mounted_as.rb +30 -0
  23. data/spec/feature/crud_workflows_spec.rb +138 -0
  24. data/spec/feature/persisted_path_spec.rb +35 -0
  25. data/spec/feature/reload_model_spec.rb +25 -0
  26. data/spec/feature/validations_spec.rb +172 -0
  27. data/spec/feature/versions_spec.rb +186 -0
  28. data/spec/models/base_uploader_spec.rb +396 -0
  29. data/spec/models/config_spec.rb +16 -0
  30. data/spec/models/file_spec.rb +210 -0
  31. data/spec/models/local_storage_spec.rb +154 -0
  32. data/spec/models/processors/digest_spec.rb +22 -0
  33. data/spec/models/s3_storage_spec.rb +170 -0
  34. data/spec/models/saviour_spec.rb +80 -0
  35. data/spec/models/url_source_spec.rb +76 -0
  36. data/spec/spec_helper.rb +93 -0
  37. data/spec/support/data/camaloon.jpg +0 -0
  38. data/spec/support/data/example.xml +21 -0
  39. data/spec/support/data/text.txt +1 -0
  40. data/spec/support/models.rb +3 -0
  41. data/spec/support/schema.rb +9 -0
  42. metadata +196 -0
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Saviour do
4
+ it "raises error if included in a non active record class" do
5
+ expect {
6
+ Class.new do
7
+ include Saviour
8
+ end
9
+ }.to raise_error(Saviour::NoActiveRecordDetected)
10
+ end
11
+
12
+ it "error if column not present" do
13
+ expect {
14
+ Class.new(Test) do
15
+ include Saviour
16
+
17
+ attach_file :not_present, Saviour::BaseUploader
18
+ end
19
+ }.to raise_error(RuntimeError)
20
+ end
21
+
22
+ context do
23
+ it "error if column not present on version" do
24
+ uploader = Class.new(Saviour::BaseUploader) do
25
+ store_dir { "/store/dir" }
26
+
27
+ version(:thumb) do
28
+ store_dir { "/versions/store/dir" }
29
+ end
30
+
31
+ version(:not_present)
32
+ end
33
+
34
+ expect {
35
+ Class.new(Test) do
36
+ include Saviour
37
+
38
+ attach_file :file, uploader
39
+ end
40
+ }.to raise_error(RuntimeError)
41
+ end
42
+ end
43
+
44
+ it "does not raise error if table is not present" do
45
+ allow(Test).to receive(:table_exists?).and_return(false)
46
+
47
+ expect {
48
+ Class.new(Test) do
49
+ include Saviour
50
+
51
+ attach_file :not_present, Saviour::BaseUploader
52
+ end
53
+ }.to_not raise_error
54
+ end
55
+
56
+ describe ".attached_files" do
57
+ it "includes a mapping of the currently attached files and their versions" do
58
+ uploader = Class.new(Saviour::BaseUploader) do
59
+ store_dir { "/store/dir" }
60
+
61
+ version(:thumb)
62
+ version(:thumb_2)
63
+ end
64
+
65
+ klass = Class.new(Test) do
66
+ include Saviour
67
+ attach_file :file, uploader
68
+ end
69
+
70
+ expect(klass.attached_files).to eq({file: [:thumb, :thumb_2]})
71
+
72
+ klass2 = Class.new(Test) do
73
+ include Saviour
74
+ attach_file :file, Saviour::BaseUploader
75
+ end
76
+
77
+ expect(klass2.attached_files).to eq({file: []})
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe Saviour::UrlSource do
4
+ describe "initialization" do
5
+ it "fails if no valid uri" do
6
+ expect { Saviour::UrlSource.new("%^7QQ#%%@#@@") }.to raise_error(ArgumentError).with_message(/is not a valid URI/)
7
+ end
8
+
9
+ it "does not fail if provided a valid uri" do
10
+ expect(Saviour::UrlSource.new("http://domain.com/file.jpg")).to be_truthy
11
+ end
12
+ end
13
+
14
+ describe "#original_filename" do
15
+ it "is extracted from the passed uri" do
16
+ a = Saviour::UrlSource.new("http://domain.com/file.jpg")
17
+ expect(a.original_filename).to eq "file.jpg"
18
+ end
19
+ end
20
+
21
+ describe "#path" do
22
+ it "is extracted from te passed uri" do
23
+ a = Saviour::UrlSource.new("http://domain.com/path/file.jpg")
24
+ expect(a.path).to eq "/path/file.jpg"
25
+ end
26
+ end
27
+
28
+ describe "#read" do
29
+ it "fails if the uri cannot be accessed" do
30
+ allow(Net::HTTP).to receive(:get_response).and_return(Net::HTTPNotFound)
31
+
32
+ a = Saviour::UrlSource.new("http://aboubaosdubioaubosdubaou.com/path/file.jpg")
33
+ expect { a.read }.to raise_error(RuntimeError).with_message(/failed after 3 attempts/)
34
+ end
35
+
36
+ it "retries the request 3 times on error" do
37
+ expect(Net::HTTP).to receive(:get_response).and_return(Net::HTTPNotFound, Net::HTTPNotFound)
38
+ expect(Net::HTTP).to receive(:get_response).and_call_original
39
+ a = Saviour::UrlSource.new("http://example.com/")
40
+ expect(a.read.length).to be > 100
41
+ end
42
+
43
+ it "succeds if the uri is valid" do
44
+ a = Saviour::UrlSource.new("http://example.com/")
45
+ expect(a.read.length).to be > 100
46
+ end
47
+
48
+ it "follows redirects" do
49
+ response = Net::HTTPRedirection.new "1.1", "301", "Redirect"
50
+ expect(response).to receive(:[]).with("location").and_return("http://example.com")
51
+
52
+ expect(Net::HTTP).to receive(:get_response).and_return(response)
53
+ expect(Net::HTTP).to receive(:get_response).and_call_original
54
+
55
+ a = Saviour::UrlSource.new("http://faked.blabla")
56
+ expect(a.read.length).to be > 100
57
+ end
58
+
59
+ it "does not follow more than 10 redirects" do
60
+ response = Net::HTTPRedirection.new "1.1", "301", "Redirect"
61
+ expect(response).to receive(:[]).with("location").exactly(10).times.and_return("http://example.com")
62
+ expect(Net::HTTP).to receive(:get_response).exactly(10).times.and_return(response)
63
+
64
+ expect { Saviour::UrlSource.new("http://faked.blabla").read }.to raise_error(RuntimeError).with_message(/Max number of allowed redirects reached \(10\) when resolving/)
65
+ end
66
+
67
+ it "fails if the redirected location is not a valid URI" do
68
+ response = Net::HTTPRedirection.new "1.1", "301", "Redirect"
69
+ expect(response).to receive(:[]).with("location").and_return("http://example.com/%@(&#<<<<")
70
+
71
+ expect(Net::HTTP).to receive(:get_response).and_return(response)
72
+
73
+ expect { Saviour::UrlSource.new("http://faked.blabla").read }.to raise_error(ArgumentError).with_message(/is not a valid URI/)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,93 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
4
+ require 'bundler/setup'
5
+ require 'rspec'
6
+ require 'active_record'
7
+ require 'sqlite3'
8
+ require 'logger'
9
+
10
+ require File.expand_path("../../lib/saviour", __FILE__)
11
+
12
+ connection_opts = case ENV.fetch('DB', "sqlite")
13
+ when "sqlite"
14
+ {adapter: "sqlite3", database: ":memory:"}
15
+ when "mysql"
16
+ {adapter: "mysql2", database: "saviour", username: "root", encoding: "utf8"}
17
+ when "postgres"
18
+ {adapter: "postgresql", database: "saviour", username: "postgres"}
19
+ end
20
+
21
+ ActiveRecord::Base.establish_connection(connection_opts)
22
+
23
+ ActiveRecord::Base.logger = Logger.new(STDOUT) if ENV['DEBUG']
24
+ silence_stream(STDOUT) { require 'support/schema' }
25
+ require 'support/models'
26
+
27
+ RSpec.configure do |config|
28
+ config.around do |example|
29
+ Fog.mock!
30
+
31
+ Dir.mktmpdir { |dir|
32
+ @tmpdir = dir
33
+ example.run
34
+ }
35
+ end
36
+ end
37
+
38
+ def with_tempfile(ext = ".jpg")
39
+ Tempfile.open(["random", ext], @tmpdir) do |temp|
40
+ yield(temp)
41
+ end
42
+ end
43
+
44
+ def with_test_file(name)
45
+ file_path = File.join(File.expand_path("spec/support/data"), name)
46
+
47
+ basename = File.basename file_path, ".*"
48
+ Tempfile.open([basename, File.extname(file_path)], @tmpdir) do |temp|
49
+ temp.write File.read(file_path)
50
+ temp.flush
51
+ temp.rewind
52
+
53
+ yield(temp, File.basename(temp.path))
54
+ end
55
+ end
56
+
57
+ class MockedS3Helper
58
+ attr_reader :directory
59
+
60
+ def start!(bucket_name: nil)
61
+ @directory = connection.directories.create(key: bucket_name)
62
+ end
63
+
64
+ def write(contents, path)
65
+ directory.files.create(
66
+ key: path,
67
+ body: contents,
68
+ public: true
69
+ )
70
+ end
71
+
72
+ def read(path)
73
+ directory.files.get(path).body
74
+ end
75
+
76
+ def delete(path)
77
+ directory.files.get(path).destroy
78
+ end
79
+
80
+ def exists?(path)
81
+ !!directory.files.head(path)
82
+ end
83
+
84
+ def public_url(path)
85
+ directory.files.get(path).public_url
86
+ end
87
+
88
+ private
89
+
90
+ def connection
91
+ @connection ||= Fog::Storage.new(provider: 'AWS', aws_access_key_id: "stub", aws_secret_access_key: "stub")
92
+ end
93
+ end
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0"?>
2
+ <Order>
3
+ <Date>2003/07/04</Date>
4
+ <CustomerId>123</CustomerId>
5
+ <CustomerName>Acme Alpha</CustomerName>
6
+ <Item>
7
+ <ItemId> 987</ItemId>
8
+ <ItemName>Coupler</ItemName>
9
+ <Quantity>5</Quantity>
10
+ </Item>
11
+ <Item>
12
+ <ItemId>654</ItemId>
13
+ <ItemName>Connector</ItemName>
14
+ <Quantity unit="12">3</Quantity>
15
+ </Item>
16
+ <Item>
17
+ <ItemId>579</ItemId>
18
+ <ItemName>Clasp</ItemName>
19
+ <Quantity>1</Quantity>
20
+ </Item>
21
+ </Order>
@@ -0,0 +1 @@
1
+ Hello world
@@ -0,0 +1,3 @@
1
+ class Test < ActiveRecord::Base
2
+
3
+ end
@@ -0,0 +1,9 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :tests do |t|
3
+ t.string :file
4
+ t.string :file_thumb
5
+ t.string :file_thumb_2
6
+ t.string :name
7
+ t.timestamps null: false
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: saviour
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Roger Campos
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fog-aws
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mime-types
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sqlite3
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: File storage handler following active record model lifecycle
126
+ email:
127
+ - roger@rogercampos.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".travis.yml"
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - lib/saviour.rb
139
+ - lib/saviour/base_uploader.rb
140
+ - lib/saviour/config.rb
141
+ - lib/saviour/file.rb
142
+ - lib/saviour/local_storage.rb
143
+ - lib/saviour/processors/digest.rb
144
+ - lib/saviour/s3_storage.rb
145
+ - lib/saviour/string_source.rb
146
+ - lib/saviour/uploader/element.rb
147
+ - lib/saviour/uploader/processors_runner.rb
148
+ - lib/saviour/uploader/store_dir_extractor.rb
149
+ - lib/saviour/url_source.rb
150
+ - lib/saviour/version.rb
151
+ - saviour.gemspec
152
+ - spec/feature/access_to_model_and_mounted_as.rb
153
+ - spec/feature/crud_workflows_spec.rb
154
+ - spec/feature/persisted_path_spec.rb
155
+ - spec/feature/reload_model_spec.rb
156
+ - spec/feature/validations_spec.rb
157
+ - spec/feature/versions_spec.rb
158
+ - spec/models/base_uploader_spec.rb
159
+ - spec/models/config_spec.rb
160
+ - spec/models/file_spec.rb
161
+ - spec/models/local_storage_spec.rb
162
+ - spec/models/processors/digest_spec.rb
163
+ - spec/models/s3_storage_spec.rb
164
+ - spec/models/saviour_spec.rb
165
+ - spec/models/url_source_spec.rb
166
+ - spec/spec_helper.rb
167
+ - spec/support/data/camaloon.jpg
168
+ - spec/support/data/example.xml
169
+ - spec/support/data/text.txt
170
+ - spec/support/models.rb
171
+ - spec/support/schema.rb
172
+ homepage: https://github.com/rogercampos/saviour
173
+ licenses:
174
+ - MIT
175
+ metadata: {}
176
+ post_install_message:
177
+ rdoc_options: []
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: 2.0.0
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ requirements: []
191
+ rubyforge_project:
192
+ rubygems_version: 2.5.1
193
+ signing_key:
194
+ specification_version: 4
195
+ summary: File storage handler following active record model lifecycle
196
+ test_files: []