picture_handler 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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = PictureHandler
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'PictureHandler'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rake/testtask'
23
+
24
+ Rake::TestTask.new(:test) do |t|
25
+ t.libs << 'lib'
26
+ t.libs << 'test'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
30
+
31
+
32
+ task default: :test
@@ -0,0 +1,11 @@
1
+ module PictureHandler
2
+ class Configuration
3
+
4
+ attr_accessor :file_sys, :s3_bucket, :region
5
+
6
+ def initialize
7
+ @file_sys = :file
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,61 @@
1
+ module PictureHandler
2
+ module Exceptions
3
+
4
+ class CustomMessage < StandardError
5
+ alias :orig_to_s :to_s
6
+ def to_s
7
+ @data
8
+ end
9
+
10
+ def message
11
+ @data
12
+ end
13
+
14
+ end
15
+
16
+ class CustomError < CustomMessage
17
+ def initialize(error_description)
18
+ @data = "#{error_description}"
19
+ end
20
+ end
21
+
22
+ class VersionError < CustomMessage
23
+ def initialize(version_name)
24
+ @data = "The Version: \"#{version_name}\" is use as a FROM but doesn't exist."
25
+ end
26
+ end
27
+
28
+ class InitError < CustomMessage
29
+ def initialize(uploader_name)
30
+ @data = "The Uploader: \"#{uploader_name}\" have not been initialized."
31
+ end
32
+ end
33
+
34
+ class WrongArgument < CustomMessage
35
+ def initialize(method)
36
+ @data = "The argument(s) you provided for the method: \"#{method}\" are incomplete or wrong."
37
+ end
38
+ end
39
+
40
+ class NoMethodError < CustomMessage
41
+ def initialize(method)
42
+ @data = "The minimagick method: \"#{method}\" is not a minimagick supported method."
43
+ end
44
+ end
45
+
46
+ class OpenError < CustomMessage
47
+ def initialize(source)
48
+ @data = "The image at source: \"#{source}\" could not be open."
49
+ end
50
+ end
51
+
52
+ class WriteError < CustomMessage
53
+ def initialize(path)
54
+ @data = "The image could not be write at \"#{path}\" path."
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+
61
+
@@ -0,0 +1,124 @@
1
+ module PictureHandler
2
+
3
+ module Mounter
4
+
5
+ def self.included(base)
6
+
7
+ base.extend ClassMethods
8
+ base.class_eval do
9
+ cattr_accessor :column
10
+ cattr_reader :uploaders
11
+
12
+ attr_accessor :remote_path
13
+ attr_reader :model_filename, :uploader, :old_record, :populated
14
+ end
15
+ base.class_variable_set('@@uploaders', {})
16
+
17
+ end
18
+
19
+
20
+ module ClassMethods
21
+
22
+ # Choose the field to action the image with
23
+ def storage_field(column, picture_handler)
24
+
25
+ before_save :picture_store
26
+ before_destroy :picture_delete
27
+
28
+ # Save the COLUMN !
29
+ self.column = column
30
+
31
+ # Put this uploader in the uploader list
32
+ self.uploaders[column] = picture_handler
33
+
34
+ # Inside this class_eval, we are in the instance so you can access Model.picture
35
+ class_eval <<-RUBY
36
+
37
+ # Overwrite the field 'storage field' so you can return a formated object instead
38
+ def #{column}
39
+ get_object_or_string(self[__method__.to_sym], __method__)
40
+ end
41
+
42
+ RUBY
43
+
44
+ end
45
+
46
+ end # ClassMethod
47
+
48
+ private # -------- #
49
+
50
+ # Every time model.picture is called
51
+ def get_object_or_string(attribute, column)
52
+
53
+ build_picture_handler_object(attribute, column) if !@uploader
54
+ @uploader
55
+
56
+ end
57
+
58
+ # CREATE an instance of PictureUploader::Base if the Object has not been created yet
59
+ def build_picture_handler_object(attribute, column)
60
+
61
+ @populated = false
62
+ @column = self.class.column.to_s
63
+ attribute = self.class.uploaders[column].new(self)
64
+ @uploader = attribute
65
+ @model_filename = ""
66
+
67
+ @old_record = !self.id.blank?
68
+ # If the record already exist, populate the name
69
+ if @old_record
70
+ # Active Record, write as attribute for Model.#{column}
71
+ @model_filename = read_attribute(@column)
72
+ end
73
+
74
+ end
75
+
76
+
77
+ def register_active_record_attribute
78
+
79
+ # If there is no image, it means it is an old record that haven't changed yet (not populated yet)
80
+ raise PictureHandler::Exceptions::CustomError.new(
81
+ "Trying to save ActiveRecord attribute, but there is no image populated yet.") if !@populated || @uploader.image.nil?
82
+
83
+ # This return either the filename chosen by the dev or the default filename of PictureUploader::Base class method filename
84
+ @model_filename = @uploader.real_filename + "." + @uploader.image.type.downcase
85
+
86
+ # Active Record, write as attribute for Model.#{column}
87
+ write_attribute(@column, @model_filename)
88
+ @model_filename
89
+
90
+ end
91
+
92
+ # Trigger when ActiveRecord Model.destroy
93
+ def picture_delete
94
+
95
+ # Call Model.column field
96
+ column = self.class.column.to_s
97
+ self.send(column) if @uploader.nil?
98
+
99
+ @uploader.delete_all
100
+
101
+ end
102
+
103
+ # Trigger when ActiveRecord Model.save
104
+ def picture_store
105
+
106
+ # Call Model.column field
107
+ column = self.class.column.to_s
108
+ self.send(column) if @uploader.nil?
109
+
110
+ # If we are in an already existing record a no remote_path have been given prior to save
111
+ return if @old_record && self.remote_path.blank?
112
+
113
+ # STORE IT
114
+ @uploader.store
115
+ @populated = true
116
+
117
+ # Ask for a write inside the ActiveRecord Attribute field
118
+ register_active_record_attribute
119
+
120
+ end
121
+
122
+ end
123
+
124
+ end
@@ -0,0 +1,162 @@
1
+ module PictureHandler
2
+ module Uploader
3
+
4
+ class Base
5
+
6
+ include PictureHandler::Uploader::MiniMagick
7
+ include PictureHandler::Uploader::ImgVersion
8
+ include ('PictureHandler::Uploader::FileSystem::' + PictureHandler.configuration.file_sys.to_s.camelize).constantize
9
+
10
+ attr_accessor :image, :model, :versions
11
+ attr_reader :real_filename
12
+
13
+ def initialize(model=nil)
14
+ # Set once
15
+ @image = nil
16
+ @model = model
17
+ @versions = {}
18
+ register_versions
19
+
20
+ # Changing runtime
21
+ @current_version = nil
22
+ @info_built = false
23
+ @infos = {}
24
+ @real_filename
25
+ end
26
+
27
+ def filename
28
+ "unamed"
29
+ end
30
+
31
+ def store_dir
32
+ "public/ph_pictures/"
33
+ end
34
+
35
+ def remote_path
36
+ nil
37
+ end
38
+
39
+ def register_versions
40
+ # Create different versions of your uploaded files:
41
+ version :thumbnail do
42
+ process resize_to_fill: [200, 200], quality: 80
43
+ end
44
+ end
45
+
46
+ # ----------------------------- #
47
+ # ------ Public Method -------- #
48
+ # ----------------------------- #
49
+
50
+ def info
51
+ build_infos unless @info_built
52
+ @infos
53
+ end
54
+
55
+ # When a Model.save is done
56
+ def store
57
+
58
+ # Get the filename once and will use the same for all futur save
59
+ @real_filename = filename
60
+ # Is the model new ? delete old record if true
61
+ delete_all if @model.old_record
62
+
63
+ process_original_image
64
+ apply_versions
65
+
66
+ end
67
+
68
+ def delete_all
69
+ delete_all_with_file_system
70
+ end
71
+
72
+ private
73
+
74
+ # -------------------------- #
75
+ # ------ INFOS ------ #
76
+ # -------------------------- #
77
+
78
+ # At creation or called once before .info ?
79
+ def build_infos
80
+ model_filename = @model.model_filename
81
+ infos = @infos
82
+
83
+ infos[:filename] = model_filename
84
+ infos[:position] = model_filename.split('_').first.to_i
85
+ infos[:store_dir] = store_dir
86
+ infos[:original_path] = store_dir + model_filename
87
+ infos[:versions] = []
88
+ infos[:paths] = []
89
+ infos[:paths] << { key: infos[:original_path] }
90
+ # Get infos for each version
91
+ @versions.each_key do |version|
92
+ infos[:versions] << version
93
+ version_path = store_dir + version.to_s + '_' + model_filename
94
+ infos[:paths] << { key: version_path }
95
+ infos[version] = version_path
96
+ end
97
+
98
+ @info_built = true
99
+ end
100
+
101
+
102
+ # -------------------------- #
103
+ # ------ CREATE ------ #
104
+ # -------------------------- #
105
+
106
+
107
+ def process_original_image
108
+
109
+ # Call the "SpecialUploader" remote_path method or the Uploader::Base one as default
110
+ source_path = remote_path
111
+ @image = self.class.open_source(source_path)
112
+
113
+ path_to_original = store_dir + @real_filename + "." + @image.type.downcase
114
+ write_file(@image, path_to_original)
115
+
116
+ end
117
+
118
+ def apply_versions
119
+
120
+ # Get the different wanted versions
121
+ @versions.each do |key, value|
122
+ @current_version = key
123
+ create_image_and_process( &(value[:block]) )
124
+ end
125
+
126
+ end
127
+
128
+ # Create a new image for each versions or inherit it from the "from" if specified
129
+ def create_image_and_process
130
+
131
+ # Get if there is a from_version for this version
132
+ from = @versions[@current_version][:from_version]
133
+
134
+ # create a new image from original OR from another to be used for this version
135
+ if from
136
+ raise PictureHandler::Exceptions::VersionError.new(from) if @versions[from].blank? || @versions[from][:image].blank?
137
+ # Put the version_image to our version also so both reference the same one
138
+ image = @versions[from][:image]
139
+ @versions[@current_version].merge!( {image: image} )
140
+
141
+ else # Else create a new instance for this version
142
+ # Open a new image from the local tmp location
143
+ local_path = @image.path
144
+ image = self.class.open_source(local_path)
145
+ # Add the Image to this @versions[:version_name][:image]
146
+ @versions[@current_version].merge!( {image: image} )
147
+ end
148
+
149
+ # Apply the options through the 'process' method
150
+ yield if block_given?
151
+
152
+ # Save the current version
153
+ version_path = store_dir + @current_version.to_s + "_" + @real_filename + "." + image.type.downcase
154
+ # Write this file new version
155
+ write_file(image, version_path)
156
+ end
157
+
158
+ end
159
+
160
+ end
161
+
162
+ end
@@ -0,0 +1,52 @@
1
+ module PictureHandler
2
+ module Uploader
3
+ module FileSystem
4
+ module File
5
+
6
+ # -------------------------- #
7
+ # ------ WRITE ------ #
8
+ # -------------------------- #
9
+
10
+ def write_file(image, path_to_write)
11
+
12
+ # Create path if it doesn't exist
13
+ self.class.create_directories_for_path( self.class.split_dirname_path(path_to_write) )
14
+
15
+ image.write(path_to_write)
16
+
17
+ # Raise an exception if the image is not written at the expected location
18
+ unless ::File.exist?(path_to_write)
19
+ raise PictureHandler::Exceptions::WriteError.new(path_to_write)
20
+ end
21
+ end
22
+
23
+ # -------------------------- #
24
+ # ------ DELETE ------ #
25
+ # -------------------------- #
26
+
27
+ def delete_all_with_file_system
28
+
29
+ infos = info
30
+
31
+ #Delete files and directory
32
+ infos[:paths].each { |hash| delete_from_path(hash[:key]) }
33
+ # Delete directory
34
+ Dir.rmdir(infos[:store_dir])
35
+
36
+ end
37
+
38
+ private
39
+
40
+ def delete_from_path(path)
41
+ path = (Rails.root + path).to_s
42
+ if ::File.exist?(path)
43
+ ::File.delete(path)
44
+ else
45
+ puts "ErrorDeletingFile: The file at path: '#{path}' could not be found."
46
+ end
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,39 @@
1
+ module PictureHandler
2
+ module Uploader
3
+ module FileSystem
4
+ module S3
5
+
6
+ require 'aws-sdk'
7
+
8
+ # -------------------------- #
9
+ # ------ WRITE ------ #
10
+ # -------------------------- #
11
+
12
+ def write_file(image, path_to_write)
13
+
14
+ s3_client = Aws::S3::Client.new
15
+ s3_resource = Aws::S3::Resource.new( client: s3_client )
16
+
17
+ s3_resource.bucket(PictureHandler.configuration.s3_bucket).object(path_to_write).upload_file(image.path)
18
+
19
+ end
20
+
21
+ # -------------------------- #
22
+ # ------ DELETE ------ #
23
+ # -------------------------- #
24
+
25
+ def delete_all_with_file_system
26
+
27
+ infos = info
28
+ s3_client = Aws::S3::Client.new
29
+
30
+ # Get all the objects to delete and delete then in ONE http request
31
+ paths_to_delete = infos[:paths]
32
+ s3_client.delete_objects( bucket: PictureHandler.configuration.s3_bucket, delete: { objects: paths_to_delete } )
33
+
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,78 @@
1
+ module PictureHandler
2
+ module Uploader
3
+ module ImgVersion
4
+ extend ActiveSupport::Concern
5
+
6
+ def version(sym, options={}, &block)
7
+ # If the version already exist, the new one will overwrite the old one
8
+ p "You already have a version named \"#{sym.to_s}\". Old one is being replaced" if @versions[sym] && @versions[sym][:block]
9
+
10
+ # Fill the versions[:version_name][:block] with the block to be executed later
11
+ @versions[sym] = { block: block } if block_given?
12
+
13
+ # Fill the versions[:version_name][:from_version] with the symbol of the version from witch it should inherit
14
+ @versions[sym].merge!( {from_version: options[:from_version]} )
15
+ end
16
+
17
+ # The process is the function called inside the versions declared by the user
18
+ def process(args)
19
+ image = @versions[@current_version][:image]
20
+
21
+ args.each do |key, value|
22
+ case key
23
+ when :resize_to_fill
24
+ self.class.resize_to_fill(image, value)
25
+ when :quality
26
+ self.class.quality(image, value)
27
+ # when :rounded
28
+ # self.class.rounded(image, value)
29
+ else
30
+ raise PictureHandler::Exceptions::NoMethodError.new(key)
31
+ end
32
+ end
33
+ end
34
+
35
+ module ClassMethods
36
+
37
+ # -------------------------------------------------------------- #
38
+ # ------------- Method accepted into a version ---------------- #
39
+ # -------------------------------------------------------------- #
40
+
41
+ def resize_to_fill(image, value)
42
+ width = value.first
43
+ height = value.last
44
+ gravity = 'Center'
45
+ raise PictureHandler::Exceptions::WrongArgument.new(key),
46
+ "You need to specify a width and height as argument of 'resize_to_fill' method." if width.blank? || height.blank?
47
+
48
+ cols, rows = image[:dimensions]
49
+ image.combine_options do |cmd|
50
+ if width != cols || height != rows
51
+ scale_x = width/cols.to_f
52
+ scale_y = height/rows.to_f
53
+ if scale_x >= scale_y
54
+ cols = (scale_x * (cols + 0.5)).round
55
+ rows = (scale_x * (rows + 0.5)).round
56
+ cmd.resize "#{cols}"
57
+ else
58
+ cols = (scale_y * (cols + 0.5)).round
59
+ rows = (scale_y * (rows + 0.5)).round
60
+ cmd.resize "x#{rows}"
61
+ end
62
+ end
63
+ cmd.gravity gravity
64
+ cmd.background "rgba(255,255,255,0.0)"
65
+ cmd.extent "#{width}x#{height}" if cols != width || rows != height
66
+ end
67
+ # image = yield(image) if block_given?
68
+ end
69
+
70
+ def quality(image, value)
71
+ image.quality(value)
72
+ end
73
+
74
+ end # ClassMethod
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,51 @@
1
+ module PictureHandler
2
+ module Uploader
3
+ module MiniMagick
4
+ extend ActiveSupport::Concern
5
+
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ base.class_eval do
9
+ begin
10
+ require "mini_magick"
11
+ rescue LoadError => e
12
+ e.message << " (You may need to install the mini_magick gem)"
13
+ raise e
14
+ end
15
+ end
16
+ end
17
+
18
+ # Common method for all file_system
19
+ module ClassMethods
20
+
21
+ # Open the source File/path/ or URL, raise an error if blank
22
+ def open_source(source_path)
23
+ raise PictureHandler::Exceptions::OpenError.new("nil") if source_path.blank?
24
+
25
+ image = ::MiniMagick::Image.open(source_path)
26
+ if image.blank?
27
+ raise PictureHandler::Exceptions::OpenError.new(source_path)
28
+ end
29
+ image
30
+ end
31
+
32
+ def create_directories_for_path(dir_tokens)
33
+ 1.upto(dir_tokens.size) do |n|
34
+ dir = dir_tokens[0...n]
35
+ dir_str = dir.join("/")
36
+ Dir.mkdir(dir_str) unless Dir.exist?(dir_str)
37
+ end
38
+ end
39
+
40
+ # Works for Windows C:\Files\etc or Linux /usr/app/etc
41
+ def split_dirname_path(some_path)
42
+ dirname = File.dirname(some_path)
43
+ tokens = dirname.split(/[\/\\]/)
44
+ tokens
45
+ end
46
+
47
+ end # ClassMethods
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,3 @@
1
+ module PictureHandler
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,31 @@
1
+ require 'picture_handler/version'
2
+
3
+ module PictureHandler
4
+ autoload :Exceptions, 'picture_handler/exceptions'
5
+ autoload :Configuration, 'picture_handler/configuration'
6
+ autoload :Mounter, 'picture_handler/mounter'
7
+ module Uploader
8
+ autoload :Base, 'picture_handler/uploader/base'
9
+ autoload :MiniMagick, 'picture_handler/uploader/mini_magick'
10
+ autoload :ImgVersion, 'picture_handler/uploader/img_version'
11
+ module FileSystem
12
+ autoload :File, 'picture_handler/uploader/file_system/file'
13
+ autoload :S3, 'picture_handler/uploader/file_system/s3'
14
+ end
15
+ end
16
+
17
+ class << self
18
+
19
+ attr_writer :configuration
20
+
21
+ def configuration
22
+ @configuration ||= Configuration.new
23
+ end
24
+
25
+ def configure
26
+ yield configuration
27
+ end
28
+
29
+ end
30
+
31
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: picture_handler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Flavien Hello
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-04-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mini_magick
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: aws-sdk
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: This module will push it to a S3 bucket, crop, resize and keep track
79
+ of all the different version available for a single image.
80
+ email:
81
+ - flavien@prettyfuntherapy.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - lib/picture_handler/configuration.rb
87
+ - lib/picture_handler/exceptions.rb
88
+ - lib/picture_handler/mounter.rb
89
+ - lib/picture_handler/uploader/base.rb
90
+ - lib/picture_handler/uploader/file_system/file.rb
91
+ - lib/picture_handler/uploader/file_system/s3.rb
92
+ - lib/picture_handler/uploader/img_version.rb
93
+ - lib/picture_handler/uploader/mini_magick.rb
94
+ - lib/picture_handler/version.rb
95
+ - lib/picture_handler.rb
96
+ - MIT-LICENSE
97
+ - Rakefile
98
+ - README.rdoc
99
+ homepage: http://prettyfuntherapy.com
100
+ licenses:
101
+ - MIT
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 1.8.23
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: Handle the upload and retrieving of your pictures for you.
124
+ test_files: []
125
+ has_rdoc: