neutrino 0.0.1
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 +7 -0
- data/.env.sample +3 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +183 -0
- data/Rakefile +1 -0
- data/lib/neutrino.rb +33 -0
- data/lib/neutrino/processing/nano.rb +41 -0
- data/lib/neutrino/storage/aws.rb +62 -0
- data/lib/neutrino/storage/null.rb +15 -0
- data/lib/neutrino/uploader.rb +31 -0
- data/lib/neutrino/version.rb +3 -0
- data/neutrino.gemspec +30 -0
- data/spec/features/deleting_files_spec.rb +29 -0
- data/spec/features/processing_files_spec.rb +26 -0
- data/spec/features/storing_files_spec.rb +28 -0
- data/spec/fixtures/image.png +0 -0
- data/spec/fixtures/text_file.txt +1 -0
- data/spec/neutrino/processing/nano_spec.rb +40 -0
- data/spec/neutrino/uploader_spec.rb +34 -0
- data/spec/neutrino_spec.rb +25 -0
- data/spec/spec_helper.rb +58 -0
- metadata +136 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 700370ce37aa38dfdc9d9868a86fb7ad8de577de
|
|
4
|
+
data.tar.gz: 9363cc836ecbd7b1c83f297b7e5c25fb241e1963
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 409091534ed84f578e427ec66fe31083fd49d732fac50d30738729b097643a2abaef5d453a2f1c0dd2fb0f0118261b44e480deaaa22ad5d9a274581c058fbf27
|
|
7
|
+
data.tar.gz: afb8ac3876e407def5e7aadeb63e98d1cbb3a0ffbb804bbd6fde2138248e15dd9ca9650b5a65712916d24ad17b63fa0ad2eff2bcbc8e6cff1d5ff4668a8dbf3f
|
data/.env.sample
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
language: ruby
|
|
3
|
+
rvm:
|
|
4
|
+
- 1.9.3
|
|
5
|
+
- 2.0.0
|
|
6
|
+
script: bundle exec rspec spec
|
|
7
|
+
env:
|
|
8
|
+
global:
|
|
9
|
+
- secure: |-
|
|
10
|
+
PpbHqVauGo2B31JKgZ7YTBfwflDuHYOr88QuROMJO7VdBaJidB5+51jjUIrI
|
|
11
|
+
2Z8edxKvwL6Wj4Y9JttY3Q2Rmv//2QE74PxCHv4ofds6SPsYLmgZvIi1C156
|
|
12
|
+
143j05sNhGZaBgHhNe/jVz+VWx39jP6hfhX/UzqdKS1O/GcU0Hc=
|
|
13
|
+
- secure: |-
|
|
14
|
+
Ip+U3IefxnOkZXGDl5iVatTCV3JTeopnPZbs+eG/o9jCu2OTF//ttG5F5PIF
|
|
15
|
+
yn9ffVXLw7Sw1CxR5/G436AKCr/EjZgC3mhnKtW+grOofbig1p3lAMQf1nGB
|
|
16
|
+
qqZtBJ/WL1AZpasr4ab8Gj5wGlpVsVIhpzic3WylhQbH+157+zg=
|
|
17
|
+
- secure: |-
|
|
18
|
+
KuVQfT2Zp/QNXhB7rT4YS0irpZjpd6okDtg0PgqXebwruc+nnSWvuxYTi4Tf
|
|
19
|
+
OfoUs4p4ObFJo0tHGtPfKd1S1fMMQq8bEnMdAd9an4LT+eWoAKc5X6DP0MaO
|
|
20
|
+
UWcTtriA66sQBOkWwNdnkPcPq4UFHzU75mn6dD0tAGUDR8HitF4=
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Parker Selbert
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Neutrino
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/sorentwo/neutrino)
|
|
4
|
+
[](https://codeclimate.com/github/sorentwo/neutrino)
|
|
5
|
+
|
|
6
|
+
Neutrino is a ruby uploader library that embraces the spirit of CarrierWave,
|
|
7
|
+
but rejects many of the implementation details and magic. Neutrino's aim is to
|
|
8
|
+
work regardless of framework and with any persistence, storage, or processor.
|
|
9
|
+
|
|
10
|
+
## Disclaimer
|
|
11
|
+
|
|
12
|
+
Neutrino is under active development and is by no means stable. Classes and
|
|
13
|
+
methods documented in this README are not necessarily implemented yet. When a
|
|
14
|
+
gem is distributed and/or the version is at least `0.1.0` the gem can be
|
|
15
|
+
considered in beta.
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
Neutrino must be configured to handle persistence, storage, or processing.
|
|
20
|
+
Engine configuration uses classes rather than symbols so that any component may
|
|
21
|
+
be substituted for a custom library without the need to modify or extend any of
|
|
22
|
+
Neutrino's internal classes.
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
# Note that neutrino does not load any engines without an explicit require, you
|
|
26
|
+
# must include any engine you need for configuration.
|
|
27
|
+
|
|
28
|
+
require 'neutrino/storage/aws'
|
|
29
|
+
|
|
30
|
+
Neutrino.configure do |config|
|
|
31
|
+
config.storage = Neutrino::Storage::AWS
|
|
32
|
+
|
|
33
|
+
config.storage.configure do |storage|
|
|
34
|
+
storage.bucket = 'bucket.name'
|
|
35
|
+
storage.acl = :public_read
|
|
36
|
+
storage.access_key_id = 'access key id'
|
|
37
|
+
storage.secret_access_key = 'secret access key'
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
# Mounting
|
|
43
|
+
|
|
44
|
+
An uploader can be mounted on any ruby object automatically, or it can be
|
|
45
|
+
handled manually.
|
|
46
|
+
|
|
47
|
+
Automatic mounting, identical to CarrierWave syntax. Mounting will only define
|
|
48
|
+
a reader and writer, it does not automatically eval in callbacks, validation,
|
|
49
|
+
or any additional methods.
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
class User
|
|
53
|
+
include Neutrino::Mixins::Mountable
|
|
54
|
+
|
|
55
|
+
mount_uploader :avatar, AvatarUploader
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Uploaders can also be mounted 'manually' simply by composing them into a class.
|
|
60
|
+
This is all that the automatic mounter is doing, but allows you to add custom
|
|
61
|
+
behavior to the method.
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
class User
|
|
65
|
+
def avatar
|
|
66
|
+
avatar_uploader.stored
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def avatar=(new_avatar)
|
|
70
|
+
avatar_uploader.stored=(new_avatar)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def avatar_uploader
|
|
74
|
+
AvatarUploader.new(self, mounted_on: :avatar)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
# Persistence
|
|
80
|
+
|
|
81
|
+
Having a mounted uploader is nice and all, but you need persistence to retreive
|
|
82
|
+
the asset later. As with mounting there are a couple of ways that you can
|
|
83
|
+
implement persistence.
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
Neutrino.configure do |config|
|
|
87
|
+
config.auto_persist = true
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The built in ActiveRecord engine will define lifecylce callbacks to handle
|
|
92
|
+
storing, tempfile cleanup, and destruction. You would manually define the
|
|
93
|
+
callbacks like this:
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
class User < ActiveRecord::Base
|
|
97
|
+
before_validation -> user { user.avatar_uploader.validate }
|
|
98
|
+
before_save -> user { user.avatar_uploader.store }
|
|
99
|
+
after_save -> user { user.avatar_uploader.cleanup }
|
|
100
|
+
before_destroy -> user { user.avatar_uploader.destroy }
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Processing
|
|
105
|
+
|
|
106
|
+
More often than not processing refers to image processing, though it can be any
|
|
107
|
+
post upload asset processing. Asset processing requires defining a processor
|
|
108
|
+
pipeline, and is performed by a set of `process` directives, each applied in
|
|
109
|
+
sequence.
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
class AvatarUploader
|
|
113
|
+
include Neutrino::Uploader, Neutrino::Processors::Nano
|
|
114
|
+
|
|
115
|
+
def process!
|
|
116
|
+
resize! '120x120'
|
|
117
|
+
convert! 'jpg'
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Versions
|
|
123
|
+
|
|
124
|
+
Defining multiple versions of an asset is simple and modeled directly off of
|
|
125
|
+
CarrierWave's style.
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
class AvatarUploader
|
|
129
|
+
include Neutrino::Uploader, Neutrino::Processors::Nano
|
|
130
|
+
|
|
131
|
+
def process!
|
|
132
|
+
resize! '100x100'
|
|
133
|
+
convert! 'jpg'
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
version(:thumb) do |thumb|
|
|
137
|
+
resize! '100x100'
|
|
138
|
+
convert! 'jpg'
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Testing
|
|
144
|
+
|
|
145
|
+
Performing asset processing during testing is unnecessary and slow. It is
|
|
146
|
+
recommended that you disable global processing in your testing config.
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
Neutrino.configure do |config|
|
|
150
|
+
config.processing = false
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Installation
|
|
155
|
+
|
|
156
|
+
Add this line to your application's Gemfile:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
gem 'neutrino', '~> 0.1.0'
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Contributing
|
|
163
|
+
|
|
164
|
+
Feature specs are dependent on at least one external service (AWS) and the
|
|
165
|
+
specs won't run unless some environment variables are configured. Please copy
|
|
166
|
+
the `.env.sample` file and fill in real credentials to ensure integration specs
|
|
167
|
+
are working properly.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
cp .env.sample .env
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Travis builds are configured to use secure environment variables so that AWS
|
|
174
|
+
integration specs will operate. Those variables are *not* available for pull
|
|
175
|
+
requests, so all pull requests will fail to pass CI. If and when I get any real
|
|
176
|
+
pull requests I'll implement some feature detection to prevent blanekt CI
|
|
177
|
+
failures.
|
|
178
|
+
|
|
179
|
+
1. Fork it
|
|
180
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
181
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
182
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
183
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/lib/neutrino.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'neutrino/storage/null'
|
|
2
|
+
require 'neutrino/uploader'
|
|
3
|
+
require 'neutrino/version'
|
|
4
|
+
|
|
5
|
+
module Neutrino
|
|
6
|
+
class << self
|
|
7
|
+
attr_writer :persistence, :processor, :storage
|
|
8
|
+
|
|
9
|
+
def configure(&block)
|
|
10
|
+
yield self
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def reset!
|
|
14
|
+
configure do |config|
|
|
15
|
+
config.persistence = nil
|
|
16
|
+
config.processor = nil
|
|
17
|
+
config.storage = nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def persistence
|
|
22
|
+
@persistence
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def processor
|
|
26
|
+
@processor
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def storage
|
|
30
|
+
@storage ||= Neutrino::Storage::Null
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'shellwords'
|
|
2
|
+
|
|
3
|
+
module Neutrino
|
|
4
|
+
module Processing
|
|
5
|
+
module Nano
|
|
6
|
+
attr_accessor :cached
|
|
7
|
+
|
|
8
|
+
def convert!(format)
|
|
9
|
+
pathname = converted_pathname(format)
|
|
10
|
+
|
|
11
|
+
manipulate!('-format', format)
|
|
12
|
+
|
|
13
|
+
if pathname != File.expand_path(cached.path)
|
|
14
|
+
File.delete(cached)
|
|
15
|
+
|
|
16
|
+
self.cached = File.open(pathname)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def resize!(dimensions)
|
|
21
|
+
manipulate!('-resize', dimensions)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def manipulate!(*arguments)
|
|
25
|
+
pid = Kernel.spawn(build_command(arguments))
|
|
26
|
+
|
|
27
|
+
Process.wait(pid)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def build_command(arguments)
|
|
33
|
+
Shellwords.join(['mogrify'] + arguments + [cached.path])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def converted_pathname(format)
|
|
37
|
+
File.expand_path(cached.path.sub(/(\.\w*)?$/, ".#{format}"))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'aws/s3'
|
|
2
|
+
|
|
3
|
+
module Neutrino
|
|
4
|
+
module Storage
|
|
5
|
+
class AWS
|
|
6
|
+
class << self
|
|
7
|
+
attr_accessor :acl, :bucket, :access_key_id, :secret_access_key
|
|
8
|
+
|
|
9
|
+
def configure(&block)
|
|
10
|
+
yield self
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
attr_reader :uploader
|
|
15
|
+
|
|
16
|
+
def initialize(uploader)
|
|
17
|
+
@uploader = uploader
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def store(new_file)
|
|
21
|
+
file.write(
|
|
22
|
+
acl: self.class.acl,
|
|
23
|
+
content_type: 'application/octet-stream',
|
|
24
|
+
file: new_file.path
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def delete
|
|
31
|
+
file.delete
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def exists?
|
|
35
|
+
file.exists?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def url
|
|
39
|
+
file.public_url.to_s
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def bucket
|
|
45
|
+
@bucket ||= connection.buckets[self.class.bucket]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def connection
|
|
49
|
+
@connection ||= ::AWS::S3.new(credentials)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def credentials
|
|
53
|
+
{ access_key_id: self.class.access_key_id,
|
|
54
|
+
secret_access_key: self.class.secret_access_key }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def file
|
|
58
|
+
@file ||= bucket.objects[uploader.store_path]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'neutrino'
|
|
2
|
+
require 'forwardable'
|
|
3
|
+
|
|
4
|
+
module Neutrino
|
|
5
|
+
module Uploader
|
|
6
|
+
extend Forwardable
|
|
7
|
+
|
|
8
|
+
attr_writer :storage
|
|
9
|
+
attr_reader :cached
|
|
10
|
+
|
|
11
|
+
delegate [:delete, :exists?, :store, :url] => :storage
|
|
12
|
+
|
|
13
|
+
def storage
|
|
14
|
+
@storage ||= Neutrino.storage.new(self)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def store_dir
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def filename
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def store_path(for_file = filename)
|
|
24
|
+
File.join([store_dir, for_file].compact)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def cache(file)
|
|
28
|
+
@cached = file
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/neutrino.gemspec
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'neutrino/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'neutrino'
|
|
8
|
+
spec.version = Neutrino::VERSION
|
|
9
|
+
spec.authors = ['Parker Selbert']
|
|
10
|
+
spec.email = ['parker@sorentwo.com']
|
|
11
|
+
spec.homepage = 'https://github.com/sorentwo/neutrino'
|
|
12
|
+
spec.license = 'MIT'
|
|
13
|
+
spec.description = %(An uploader library that embraces modularity and rejects magick)
|
|
14
|
+
spec.summary = %(
|
|
15
|
+
Neutrino is a ruby uploader library that embraces the spirit of
|
|
16
|
+
CarrierWave, but rejects many of the implementation details and magic.
|
|
17
|
+
Neutrino's aim is to work regardless of framework and with any persistence,
|
|
18
|
+
storage, or processor.
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
spec.files = `git ls-files`.split($/)
|
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
23
|
+
spec.test_files = spec.files.grep(%r{^spec/})
|
|
24
|
+
spec.require_paths = ['lib']
|
|
25
|
+
|
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.0.2'
|
|
28
|
+
spec.add_development_dependency 'rspec', '~> 2.13.0'
|
|
29
|
+
spec.add_development_dependency 'aws-sdk', '~> 1.8.5'
|
|
30
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
class BasicUploader
|
|
4
|
+
include Neutrino::Uploader
|
|
5
|
+
|
|
6
|
+
def store_dir; 'uploads'; end
|
|
7
|
+
def filename; 'text_file.txt'; end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe 'Deleting Files' do
|
|
11
|
+
let(:text_file) { File.open('spec/fixtures/text_file.txt', 'r') }
|
|
12
|
+
|
|
13
|
+
subject(:uploader) { BasicUploader.new }
|
|
14
|
+
|
|
15
|
+
context 'Using null storage', storage: :null do
|
|
16
|
+
it 'does not delete a file' do
|
|
17
|
+
expect(uploader.delete).to be_nil
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'Using AWS storage', storage: :aws do
|
|
22
|
+
it 'deletes the file from the stored location' do
|
|
23
|
+
uploader.store(text_file)
|
|
24
|
+
uploader.delete
|
|
25
|
+
|
|
26
|
+
expect(uploader.exists?).to be_false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'neutrino/processing/nano'
|
|
3
|
+
|
|
4
|
+
class BasicUploader
|
|
5
|
+
include Neutrino::Uploader, Neutrino::Processing::Nano
|
|
6
|
+
|
|
7
|
+
def store_dir; 'uploads'; end
|
|
8
|
+
def filename; 'image.png'; end
|
|
9
|
+
|
|
10
|
+
def process!
|
|
11
|
+
resize! '100x100'
|
|
12
|
+
convert! 'jpg'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe 'Processing Files', processing: :image do
|
|
17
|
+
it 'applies processing directives to the file before storage' do
|
|
18
|
+
uploader = BasicUploader.new
|
|
19
|
+
image = File.open('spec/fixtures/image.png')
|
|
20
|
+
|
|
21
|
+
uploader.cache(image)
|
|
22
|
+
uploader.process!
|
|
23
|
+
|
|
24
|
+
expect(File.extname(uploader.cached)).to eq('.jpg')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
class BasicUploader
|
|
4
|
+
include Neutrino::Uploader
|
|
5
|
+
|
|
6
|
+
def store_dir; 'uploads'; end
|
|
7
|
+
def filename; 'text_file.txt'; end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe 'Storing Files' do
|
|
11
|
+
let(:text_file) { File.open('spec/fixtures/text_file.txt', 'r') }
|
|
12
|
+
|
|
13
|
+
subject(:uploader) { BasicUploader.new }
|
|
14
|
+
|
|
15
|
+
context 'Using null storage', storage: :null do
|
|
16
|
+
it 'does not store a file' do
|
|
17
|
+
expect(uploader.store(text_file)).to be_true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'Using AWS storage', storage: :aws do
|
|
22
|
+
it 'uploads the file to the configured s3 bucket' do
|
|
23
|
+
expect(uploader.store(text_file)).to be_true
|
|
24
|
+
|
|
25
|
+
expect(uploader.url).to eq("https://#{ENV.fetch('AWS_BUCKET_NAME')}.s3.amazonaws.com/uploads/text_file.txt")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Text File
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'neutrino/processing/nano'
|
|
2
|
+
|
|
3
|
+
describe Neutrino::Processing::Nano, processing: :image do
|
|
4
|
+
let(:file) { File.open('spec/fixtures/image.png') }
|
|
5
|
+
|
|
6
|
+
subject(:processor) do
|
|
7
|
+
Object.new.tap do |object|
|
|
8
|
+
object.extend(Neutrino::Processing::Nano)
|
|
9
|
+
object.cached = file
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#convert!' do
|
|
14
|
+
it 'converts the file to the new format' do
|
|
15
|
+
processor.convert!('jpg')
|
|
16
|
+
|
|
17
|
+
expect(File.extname(processor.cached)).to eq('.jpg')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'cleans up the original file' do
|
|
21
|
+
processor.convert!('jpg')
|
|
22
|
+
|
|
23
|
+
expect(File.exists?(file.path)).to be_false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'does not delete the original file if the format has not changed' do
|
|
27
|
+
processor.convert!('png')
|
|
28
|
+
|
|
29
|
+
expect(File.exists?(file.path)).to be_true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe '#resize!' do
|
|
34
|
+
it 'resizes the image using the exact dimensions' do
|
|
35
|
+
processor.resize!('100x100')
|
|
36
|
+
|
|
37
|
+
expect(`identify #{file.path}`.split(' ')[2]).to eq('100x100')
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'neutrino'
|
|
2
|
+
require 'neutrino/uploader'
|
|
3
|
+
|
|
4
|
+
describe Neutrino::Uploader do
|
|
5
|
+
let(:uploader) do
|
|
6
|
+
Object.new.tap do |object|
|
|
7
|
+
object.extend(Neutrino::Uploader)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#storage' do
|
|
12
|
+
it 'defaults to the null storage engine' do
|
|
13
|
+
expect(uploader.storage).to be_instance_of(Neutrino.storage)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#storage=' do
|
|
18
|
+
it 'overrides the configured storage engine' do
|
|
19
|
+
engine = double(:storage)
|
|
20
|
+
uploader.storage = engine
|
|
21
|
+
|
|
22
|
+
expect(uploader.storage).to eq(engine)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '#cache' do
|
|
27
|
+
it 'holds a reference to the provided file' do
|
|
28
|
+
file = double(:file)
|
|
29
|
+
|
|
30
|
+
uploader.cache(file)
|
|
31
|
+
expect(uploader.cached).to eq(file)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'neutrino'
|
|
2
|
+
|
|
3
|
+
describe Neutrino do
|
|
4
|
+
describe '.configure' do
|
|
5
|
+
let(:custom_module) { double(:custom_module) }
|
|
6
|
+
|
|
7
|
+
it 'overrides the default engines' do
|
|
8
|
+
Neutrino.configure do |config|
|
|
9
|
+
config.persistence = custom_module
|
|
10
|
+
config.processor = custom_module
|
|
11
|
+
config.storage = custom_module
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
expect(Neutrino.persistence).to be(custom_module)
|
|
15
|
+
expect(Neutrino.processor).to be(custom_module)
|
|
16
|
+
expect(Neutrino.storage).to be(custom_module)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '.storage' do
|
|
21
|
+
it 'defaults to the null storage engine' do
|
|
22
|
+
expect(Neutrino.storage).to be(Neutrino::Storage::Null)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'neutrino'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
def source_environment_file!
|
|
5
|
+
return unless File.exists?('.env')
|
|
6
|
+
|
|
7
|
+
File.readlines('.env').each do |line|
|
|
8
|
+
values = line.split('=')
|
|
9
|
+
ENV[values.first] = values.last.chomp
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
RSpec.configure do |config|
|
|
14
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
15
|
+
config.filter_run :focus
|
|
16
|
+
config.order = 'random'
|
|
17
|
+
config.run_all_when_everything_filtered = true
|
|
18
|
+
|
|
19
|
+
config.before do
|
|
20
|
+
Neutrino.reset!
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
config.before(storage: :null) do
|
|
24
|
+
require 'neutrino/storage/null'
|
|
25
|
+
|
|
26
|
+
Neutrino.configure do |config|
|
|
27
|
+
config.storage = Neutrino::Storage::Null
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
config.before(storage: :aws) do
|
|
32
|
+
require 'neutrino/storage/aws'
|
|
33
|
+
|
|
34
|
+
Neutrino.configure do |config|
|
|
35
|
+
config.storage = Neutrino::Storage::AWS
|
|
36
|
+
|
|
37
|
+
config.storage.configure do |storage|
|
|
38
|
+
storage.acl = :public_read
|
|
39
|
+
storage.bucket = ENV.fetch('AWS_BUCKET_NAME')
|
|
40
|
+
storage.access_key_id = ENV.fetch('AWS_ACCESS_KEY_ID')
|
|
41
|
+
storage.secret_access_key = ENV.fetch('AWS_SECRET_ACCESS_KEY')
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
config.before(processing: :image) do
|
|
47
|
+
FileUtils.cp('spec/fixtures/image.png', 'spec/fixtures/backup.png')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
config.after(processing: :image) do
|
|
51
|
+
jpeg_path = 'spec/fixtures/image.jpg'
|
|
52
|
+
|
|
53
|
+
FileUtils.rm(jpeg_path) if File.exists?(jpeg_path)
|
|
54
|
+
FileUtils.mv('spec/fixtures/backup.png', 'spec/fixtures/image.png')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
source_environment_file!
|
|
58
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: neutrino
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Parker Selbert
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.3'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.3'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ~>
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 10.0.2
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ~>
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 10.0.2
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rspec
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ~>
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 2.13.0
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ~>
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 2.13.0
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: aws-sdk
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ~>
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 1.8.5
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ~>
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 1.8.5
|
|
69
|
+
description: An uploader library that embraces modularity and rejects magick
|
|
70
|
+
email:
|
|
71
|
+
- parker@sorentwo.com
|
|
72
|
+
executables: []
|
|
73
|
+
extensions: []
|
|
74
|
+
extra_rdoc_files: []
|
|
75
|
+
files:
|
|
76
|
+
- .env.sample
|
|
77
|
+
- .gitignore
|
|
78
|
+
- .rspec
|
|
79
|
+
- .travis.yml
|
|
80
|
+
- CHANGELOG.md
|
|
81
|
+
- Gemfile
|
|
82
|
+
- LICENSE.txt
|
|
83
|
+
- README.md
|
|
84
|
+
- Rakefile
|
|
85
|
+
- lib/neutrino.rb
|
|
86
|
+
- lib/neutrino/processing/nano.rb
|
|
87
|
+
- lib/neutrino/storage/aws.rb
|
|
88
|
+
- lib/neutrino/storage/null.rb
|
|
89
|
+
- lib/neutrino/uploader.rb
|
|
90
|
+
- lib/neutrino/version.rb
|
|
91
|
+
- neutrino.gemspec
|
|
92
|
+
- spec/features/deleting_files_spec.rb
|
|
93
|
+
- spec/features/processing_files_spec.rb
|
|
94
|
+
- spec/features/storing_files_spec.rb
|
|
95
|
+
- spec/fixtures/image.png
|
|
96
|
+
- spec/fixtures/text_file.txt
|
|
97
|
+
- spec/neutrino/processing/nano_spec.rb
|
|
98
|
+
- spec/neutrino/uploader_spec.rb
|
|
99
|
+
- spec/neutrino_spec.rb
|
|
100
|
+
- spec/spec_helper.rb
|
|
101
|
+
homepage: https://github.com/sorentwo/neutrino
|
|
102
|
+
licenses:
|
|
103
|
+
- MIT
|
|
104
|
+
metadata: {}
|
|
105
|
+
post_install_message:
|
|
106
|
+
rdoc_options: []
|
|
107
|
+
require_paths:
|
|
108
|
+
- lib
|
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - '>='
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '0'
|
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - '>='
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: '0'
|
|
119
|
+
requirements: []
|
|
120
|
+
rubyforge_project:
|
|
121
|
+
rubygems_version: 2.0.0
|
|
122
|
+
signing_key:
|
|
123
|
+
specification_version: 4
|
|
124
|
+
summary: Neutrino is a ruby uploader library that embraces the spirit of CarrierWave,
|
|
125
|
+
but rejects many of the implementation details and magic. Neutrino's aim is to work
|
|
126
|
+
regardless of framework and with any persistence, storage, or processor.
|
|
127
|
+
test_files:
|
|
128
|
+
- spec/features/deleting_files_spec.rb
|
|
129
|
+
- spec/features/processing_files_spec.rb
|
|
130
|
+
- spec/features/storing_files_spec.rb
|
|
131
|
+
- spec/fixtures/image.png
|
|
132
|
+
- spec/fixtures/text_file.txt
|
|
133
|
+
- spec/neutrino/processing/nano_spec.rb
|
|
134
|
+
- spec/neutrino/uploader_spec.rb
|
|
135
|
+
- spec/neutrino_spec.rb
|
|
136
|
+
- spec/spec_helper.rb
|