dm-fasten-the-seat-belt 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
File without changes
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Maxime Guilbot for Ekohe Limited
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/Manifest.txt ADDED
@@ -0,0 +1,22 @@
1
+ History.txt
2
+ LICENSE
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ TODO
7
+ lib/dm-fasten-the-seat-belt.rb
8
+ lib/dm-fasten-the-seat-belt/fasten-the-seat-belt/compression.rb
9
+ lib/dm-fasten-the-seat-belt/fasten-the-seat-belt/version.rb
10
+ spec/classes.rb
11
+ spec/documents/classes.rb
12
+ spec/documents/files/document.pdf
13
+ spec/documents/files/word.doc
14
+ spec/documents/integration_spec.rb
15
+ spec/pictures/classes.rb
16
+ spec/pictures/files/children.jpg
17
+ spec/pictures/files/children.png
18
+ spec/pictures/files/sunshine.jpg
19
+ spec/pictures/integration_spec.rb
20
+ spec/spec.opts
21
+ spec/spec_helper.rb
22
+ tasks/hoe.rb
data/README.txt ADDED
@@ -0,0 +1,2 @@
1
+ dm-fasten-the-seat-belt
2
+ =========================
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'spec'
4
+ require 'spec/rake/spectask'
5
+ require 'pathname'
6
+
7
+ ROOT = Pathname(__FILE__).dirname.expand_path
8
+ require ROOT + 'lib/dm-fasten-the-seat-belt/fasten-the-seat-belt/version'
9
+
10
+ PLUGIN = "dm-fasten-the-seat-belt"
11
+ PROJECT_NAME = NAME = "dm-fasten-the-s"
12
+ AUTHOR = "Maxime Guilbot"
13
+ EMAIL = "maxime [a] ekohe [d] com"
14
+ HOMEPAGE = PROJECT_URL = "http://github.com/maxime/dm-fasten-the-seat-belt"
15
+ SUMMARY = PROJECT_DESCRIPTION = PROJECT_SUMMARY = "A new merb plugin for adding image and file upload storage capabilities"
16
+ GEM_VERSION = DataMapper::FastenTheSeatBelt::VERSION
17
+ GEM_DEPENDENCIES = [["dm-core", GEM_VERSION], ["mini_magick", ">=1.2.3"]]
18
+ GEM_CLEAN = ["log", "pkg"]
19
+ GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.txt LICENSE TODO ] }
20
+
21
+ GEM_NAME = "dm-fasten-the-seat-belt"
22
+
23
+ require 'tasks/hoe'
24
+
25
+ task :default => [ :spec ]
26
+
27
+ WIN32 = (RUBY_PLATFORM =~ /win32|mingw|cygwin/) rescue nil
28
+ SUDO = WIN32 ? '' : ('sudo' unless ENV['SUDOLESS'])
29
+
30
+ desc "Install #{GEM_NAME} #{GEM_VERSION}"
31
+ task :install => [ :package ] do
32
+ sh "#{SUDO} gem install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources", :verbose => false
33
+ end
34
+
35
+ desc "Uninstall #{GEM_NAME} #{GEM_VERSION} (default ruby)"
36
+ task :uninstall => [ :clobber ] do
37
+ sh "#{SUDO} gem uninstall #{GEM_NAME} -v#{GEM_VERSION} -I -x", :verbose => false
38
+ end
39
+
40
+ desc 'Run specifications'
41
+ Spec::Rake::SpecTask.new(:spec) do |t|
42
+ t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
43
+ t.spec_files = Pathname.glob((ROOT + 'spec/**/*_spec.rb').to_s)
44
+
45
+ begin
46
+ t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
47
+ t.rcov_opts << "--exclude 'config,spec,#{Gem::path.join(',')}'"
48
+ t.rcov_opts << '--text-summary'
49
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
50
+ rescue Exception
51
+ # rcov not installed
52
+ end
53
+ end
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ - Add mime type validation (only images, pdfs, etc.)
2
+ - S3 and database blob storage
3
+ - RMagick and ImageScience support
@@ -0,0 +1,199 @@
1
+ require 'rubygems'
2
+ require 'pathname'
3
+
4
+ require 'mini_magick'
5
+
6
+ gem 'dm-core', '~>0.9.8'
7
+ require 'dm-core'
8
+
9
+ require File.join(File.dirname(__FILE__), 'dm-fasten-the-seat-belt', 'fasten-the-seat-belt','compression')
10
+
11
+ module DataMapper
12
+ module FastenTheSeatBelt
13
+ def self.included(base)
14
+ base.send(:extend, ClassMethods)
15
+ base.send(:include, InstanceMethods)
16
+ base.send(:include, Compression)
17
+ base.send(:include, MiniMagick)
18
+ base.class_eval do
19
+ attr_accessor :file
20
+
21
+ class << self; attr_accessor :fasten_the_seat_belt_options end
22
+
23
+ @fasten_the_seat_belt_options
24
+ end
25
+ end
26
+
27
+ module ClassMethods
28
+
29
+ def fasten_the_seat_belt(options={})
30
+ # Properties
31
+ self.property :filename, String
32
+ self.property :size, Integer, :lazy => true
33
+ self.property :content_type, String, :lazy => true
34
+ self.property :created_at, DateTime, :lazy => true
35
+ self.property :updated_at, DateTime, :lazy => true
36
+
37
+ self.property :images_are_compressed, DataMapper::Types::Boolean, :lazy => true
38
+
39
+ # Callbacks to manage the file
40
+ before :save, :save_attributes
41
+ after :save, :save_file
42
+ after :destroy, :delete_directory
43
+
44
+ # Options
45
+ if !defined?(Merb) && !options[:file_system_path]
46
+ raise "If you're running dm-fasten-the-seat-belt outside of Merb, you must specifiy :file_system_path in the options"
47
+ end
48
+
49
+ options[:file_system_path] ||= File.join((defined?(Merb) ? Merb.root : ''), 'public', merb_environment, self.storage_name)
50
+ options[:thumbnails] ||= {}
51
+
52
+ self.fasten_the_seat_belt_options = options
53
+ end
54
+
55
+ def recreate_thumbnails!
56
+ all.each {|object| object.generate_thumbnails! }
57
+ true
58
+ end
59
+
60
+ def merb_environment
61
+ (defined?(Merb) ? Merb.env : '')
62
+ end
63
+ end
64
+
65
+ module InstanceMethods
66
+
67
+ # Get file path
68
+ #
69
+ def path(thumb=nil)
70
+ File.join(web_directory_name, filename_for_thumbnail(thumb))
71
+ end
72
+
73
+ def absolute_path(thumb=nil)
74
+ File.join(complete_directory_name, filename_for_thumbnail(thumb))
75
+ end
76
+
77
+ def filename_for_thumbnail(thumb=nil)
78
+ if thumb != nil
79
+ basename = self.filename.gsub(/\.(.*)$/, '')
80
+ extension = self.filename.gsub(/^(.*)\./, '')
81
+ return basename + '_' + thumb.to_s + '.' + extension
82
+ else
83
+ return self.filename
84
+ end
85
+ end
86
+
87
+ def save_attributes
88
+ return unless @file
89
+ # The following line is solving an IE6 problem. This removes the C:\Documents and Settings\.. shit
90
+ @file[:filename] = File.basename(@file[:filename].gsub(/\\/, '/')) if @file[:filename]
91
+
92
+ # Setup attributes
93
+ [:content_type, :size, :filename].each do |attribute|
94
+ self.send("#{attribute}=", @file[attribute])
95
+ end
96
+ end
97
+
98
+ def save_file
99
+ return unless self.filename and @file
100
+
101
+ create_directory
102
+
103
+ FileUtils.mv @file[:tempfile].path, complete_file_path if File.exists?(@file[:tempfile].path)
104
+
105
+ generate_thumbnails!
106
+
107
+ @file = nil
108
+
109
+ # By default, images are supposed to be compressed
110
+ self.images_are_compressed ||= true
111
+ end
112
+
113
+ def directory_name
114
+ # you can thank Jamis Buck for this: http://www.37signals.com/svn/archives2/id_partitioning.php
115
+ dir = ("%08d" % self.id).scan(/..../)
116
+ File.join(dir[0], dir[1])
117
+ end
118
+
119
+ def web_directory_name
120
+ raise "Can't return web directory name if not running in Merb" unless defined?(Merb)
121
+ unless complete_directory_name.include?(Merb.root)
122
+ raise "Can't return web directory name, the images aren't stored under the Merb application public directory"
123
+ end
124
+
125
+ complete_directory_name.gsub(/^#{Merb.root}\/public/, '')
126
+ end
127
+
128
+ def complete_directory_name
129
+ File.join(self.class.fasten_the_seat_belt_options[:file_system_path], directory_name)
130
+ end
131
+
132
+ def complete_file_path
133
+ File.join(complete_directory_name, (self.filename || ""))
134
+ end
135
+
136
+ def create_directory
137
+ FileUtils.mkdir_p(complete_directory_name) unless FileTest.exists?(complete_directory_name)
138
+ end
139
+
140
+ def delete_directory
141
+ FileUtils.rm_rf(complete_directory_name) if FileTest.exists?(complete_directory_name)
142
+ end
143
+
144
+ def generate_thumbnails!
145
+ self.class.fasten_the_seat_belt_options[:thumbnails].each_pair do |key, value|
146
+ resize_to = value[:size]
147
+ quality = value[:quality].to_i
148
+
149
+ image = MiniMagick::Image.from_file(complete_file_path)
150
+ if value[:crop]
151
+ # tw, th are target width and target height
152
+
153
+ tw = resize_to.gsub(/([0-9]*)x([0-9]*)/, '\1').to_i
154
+ th = resize_to.gsub(/([0-9]*)x([0-9]*)/, '\2').to_i
155
+
156
+ # ow and oh are origin width and origin height
157
+ ow = image[:width]
158
+ oh = image[:height]
159
+
160
+ # iw and ih and the dimensions of the cropped picture before resizing
161
+ # there are 2 cases, iw = ow or ih = oh
162
+ # using iw / ih = tw / th, we can determine the other values
163
+ # we use the minimal values to determine the good case
164
+ iw = [ow, ((oh.to_f*tw.to_f) / th.to_f)].min
165
+ ih = [oh, ((ow.to_f*th.to_f) / tw.to_f)].min
166
+
167
+ # we calculate how much image we must crop
168
+ shave_width = ((ow.to_f - iw.to_f) / 2.0).to_i
169
+ shave_height = ((oh.to_f - ih.to_f) / 2.0).to_i
170
+
171
+
172
+ # specify the width of the region to be removed from both sides of the image and the height of the regions to be removed from top and bottom.
173
+ image.shave "#{shave_width}x#{shave_height}"
174
+
175
+ # resize of the pic
176
+ image.resize resize_to.to_s + "!"
177
+ else
178
+ # no cropping
179
+ image.resize resize_to
180
+ end
181
+ basename = self.filename.gsub(/\.(.*)$/, '')
182
+ extension = self.filename.gsub(/^(.*)\./, '')
183
+
184
+ thumb_filename = File.join(complete_directory_name, (basename + '_' + key.to_s + '.' + extension))
185
+
186
+ # Delete thumbnail if exists
187
+ File.delete(thumb_filename) if File.exists?(thumb_filename)
188
+ image.write thumb_filename
189
+
190
+ next if self.images_are_compressed == false
191
+
192
+ if quality and quality!=0 and quality < 100
193
+ compress_jpeg(thumb_filename, quality)
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end # FastenTheSeatBelt
199
+ end # DataMapper
@@ -0,0 +1,35 @@
1
+ module DataMapper
2
+ module FastenTheSeatBelt
3
+ module Compression
4
+ COMPRESSABLE_MIME_TYPES = ["image/jpeg", "image/jpg", "image/pjpeg"]
5
+
6
+ def compressable?
7
+ COMPRESSABLE_MIME_TYPES.include?(self.content_type)
8
+ end
9
+
10
+ def dont_compress_now!
11
+ self.images_are_compressed = false
12
+ end
13
+
14
+ def compress_jpeg(filename, quality)
15
+ if compressable?
16
+ system("jpegoptim -m#{quality} -q --strip-all \"#{filename}\" &> /dev/null")
17
+ else
18
+ puts "FastenTheSeatBelt says: Quality setting not supported for #{self.content_type} files"
19
+ end
20
+ end
21
+
22
+ def compress_now!
23
+ return false if self.images_are_compressed
24
+ self.class.fasten_the_seat_belt_options[:thumbnails].each_pair do |key, value|
25
+ thumb_filename = absolute_path(key)
26
+
27
+ compress_jpeg(thumb_filename, value[:quality].to_i) if value[:quality] and value[:quality].to_i < 100
28
+ end
29
+
30
+ self.update_attributes(:images_are_compressed => true)
31
+ end
32
+
33
+ end # Compression
34
+ end # FastenTheSeatBelt
35
+ end # DataMapper
@@ -0,0 +1,5 @@
1
+ module DataMapper
2
+ module FastenTheSeatBelt
3
+ VERSION = '0.9.9'
4
+ end
5
+ end
data/spec/classes.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/pictures/classes.rb'
2
+ require File.dirname(__FILE__) + '/documents/classes.rb'
@@ -0,0 +1,10 @@
1
+ class Document
2
+ include DataMapper::Resource
3
+ include DataMapper::FastenTheSeatBelt
4
+
5
+ property :id, Serial
6
+
7
+ fasten_the_seat_belt :file_system_path => File.dirname(__FILE__) + '/storage/documents'
8
+
9
+ validates_present :file, :if => Proc.new{|resource| resource.new_record?}
10
+ end
Binary file
Binary file
@@ -0,0 +1,53 @@
1
+ require 'tempfile'
2
+
3
+ require File.dirname(__FILE__) + '/../spec_helper'
4
+
5
+ describe DataMapper::FastenTheSeatBelt, "outside of Merb" do
6
+ before :all do
7
+ @pdf_original_file_path = File.dirname(__FILE__) + '/files/document.pdf'
8
+ @pdf_tempfile = Tempfile.new('document.pdf')
9
+ FileUtils.copy(@pdf_original_file_path, @pdf_tempfile.path)
10
+
11
+ @pdf = Document.new(:file => {:filename => 'document.pdf',
12
+ :content_type => 'application/pdf',
13
+ :tempfile => @pdf_tempfile})
14
+ # Expected file paths
15
+ @main_file_path = File.join(File.dirname(__FILE__), 'storage', 'documents', '0000', '0001', 'document.pdf')
16
+ end
17
+
18
+ after :all do
19
+ @pdf_tempfile.close!
20
+ end
21
+
22
+ it "should be able to attach pdf documents" do
23
+ @pdf.should be_valid
24
+ @pdf.save.should == true
25
+ end
26
+
27
+ it "should be able to attach a word document" do
28
+ @doc_original_file_path = File.dirname(__FILE__) + '/files/word.doc'
29
+ @doc_tempfile = Tempfile.new('word.doc')
30
+ FileUtils.copy(@doc_original_file_path, @doc_tempfile.path)
31
+
32
+ @doc = Document.new(:file => {:filename => 'word.doc',
33
+ :content_type => 'application/msword',
34
+ :tempfile => @doc_tempfile})
35
+
36
+ @doc.should be_valid
37
+ @doc.save.should == true
38
+ File.exists?(File.join(File.dirname(__FILE__), 'storage', 'documents', '0000', '0002', 'word.doc')).should == true
39
+ end
40
+
41
+ it "should be able to save the document file in the right place" do
42
+ File.exists?(@main_file_path).should == true
43
+ end
44
+
45
+ it "should be able to return the path of a document" do
46
+ File.expand_path(@pdf.absolute_path).should == @main_file_path
47
+ end
48
+
49
+ it "should be able to delete the files if the object is destroyed" do
50
+ @pdf.destroy
51
+ File.exists?(@main_file_path).should == false
52
+ end
53
+ end
@@ -0,0 +1,14 @@
1
+ class Picture
2
+ include DataMapper::Resource
3
+ include DataMapper::FastenTheSeatBelt
4
+
5
+ property :id, Serial
6
+
7
+ fasten_the_seat_belt :thumbnails => {
8
+ :small => {:size => "232x232", :crop => true, :quality => 100},
9
+ :large => {:size => "800x600", :quality => 90},
10
+ },
11
+ :file_system_path => File.dirname(__FILE__) + '/storage/pictures'
12
+
13
+ validates_present :file, :if => Proc.new{|resource| resource.new_record?}
14
+ end
Binary file
Binary file
Binary file
@@ -0,0 +1,194 @@
1
+ require 'tempfile'
2
+ require 'mini_magick'
3
+
4
+ require File.dirname(__FILE__) + '/../spec_helper'
5
+
6
+ describe DataMapper::FastenTheSeatBelt, "outside of Merb" do
7
+ before :all do
8
+ @children_original_file_path = File.dirname(__FILE__) + '/files/children.jpg'
9
+ @children_tempfile = Tempfile.new('children.jpg')
10
+ FileUtils.copy(@children_original_file_path, @children_tempfile.path)
11
+
12
+ @children_picture = Picture.new(:file => {:filename => 'children.jpg',
13
+ :content_type => 'image/jpeg',
14
+ :tempfile => @children_tempfile})
15
+ # Expected file paths
16
+ @main_file_path = File.join(File.dirname(__FILE__), 'storage', 'pictures', '0000', '0001', 'children.jpg')
17
+ @large_thumbnail_file_path = File.join(File.dirname(__FILE__), 'storage', 'pictures', '0000', '0001', 'children_large.jpg')
18
+ @small_thumbnail_file_path = File.join(File.dirname(__FILE__), 'storage', 'pictures', '0000', '0001', 'children_small.jpg')
19
+ end
20
+
21
+ after :all do
22
+ @children_tempfile.close!
23
+ end
24
+
25
+ it "should be able to attach pictures" do
26
+ @children_picture.should be_valid
27
+ @children_picture.save.should == true
28
+ end
29
+
30
+ it "should create the pictures in the file system with the right dimensions and the right path" do
31
+ # original file
32
+ File.exists?(@main_file_path).should == true
33
+ File.size(@main_file_path).should == File.size(@children_original_file_path)
34
+
35
+ # thumbnails
36
+
37
+ # large thumbnail
38
+ File.exists?(@large_thumbnail_file_path).should == true
39
+ large_thumbnail = MiniMagick::Image.from_file(@large_thumbnail_file_path)
40
+ large_thumbnail[:width].should == 800
41
+ large_thumbnail[:height].should == 533
42
+
43
+ # small thumbnail
44
+ File.exists?(@small_thumbnail_file_path).should == true
45
+ small_thumbnail = MiniMagick::Image.from_file(@small_thumbnail_file_path)
46
+ small_thumbnail[:width].should == 232
47
+ small_thumbnail[:height].should == 232
48
+ end
49
+
50
+ it "should be able to recreate the thumbnails of the pictures" do
51
+ File.delete(@large_thumbnail_file_path)
52
+ File.delete(@small_thumbnail_file_path)
53
+
54
+ File.exists?(@large_thumbnail_file_path).should == false
55
+ File.exists?(@small_thumbnail_file_path).should == false
56
+
57
+ Picture.recreate_thumbnails!
58
+
59
+ File.exists?(@large_thumbnail_file_path).should == true
60
+ File.exists?(@small_thumbnail_file_path).should == true
61
+ end
62
+
63
+ it "should be able to get the image and thumbnail absolute paths" do
64
+ File.expand_path(@children_picture.absolute_path).should == @main_file_path
65
+ File.expand_path(@children_picture.absolute_path(:small)).should == @small_thumbnail_file_path
66
+ File.expand_path(@children_picture.absolute_path(:large)).should == @large_thumbnail_file_path
67
+ end
68
+
69
+ it "should support delayed compression" do
70
+ new_picture_tempfile = Tempfile.new('children.jpg')
71
+ FileUtils.copy(@children_original_file_path, new_picture_tempfile.path)
72
+
73
+ new_picture = Picture.new(:file => {:filename => 'children.jpg',
74
+ :content_type => 'image/jpeg',
75
+ :tempfile => new_picture_tempfile})
76
+ new_picture.dont_compress_now!
77
+ new_picture.save
78
+
79
+ new_picture.reload
80
+
81
+ # Image shouldn't be compressed yet
82
+ new_picture.images_are_compressed.should == false
83
+
84
+ size_before_compression = File.size(new_picture.absolute_path(:large))
85
+
86
+ # Compress now
87
+ new_picture.compress_now!
88
+ new_picture.reload
89
+
90
+ size_after_compression = File.size(new_picture.absolute_path(:large))
91
+
92
+ # Compressed image should be smaller in size
93
+ size_before_compression.should > size_after_compression
94
+
95
+ # Image should be marked as compressed
96
+ new_picture.images_are_compressed.should == true
97
+ end
98
+
99
+ it "should be able to delete the files if the object is destroyed" do
100
+ @children_picture.destroy
101
+ File.exists?(@main_file_path).should == false
102
+
103
+ File.exists?(@large_thumbnail_file_path).should == false
104
+
105
+ File.exists?(@small_thumbnail_file_path).should == false
106
+ end
107
+
108
+ it "should raise an error if it's not running in Merb and if the file_system_path isn't present" do
109
+ lambda {
110
+ class BrokenPicture
111
+ include DataMapper::Resource
112
+ include DataMapper::FastenTheSeatBelt
113
+
114
+ property :id, Serial
115
+ fasten_the_seat_belt
116
+ end
117
+ }.should raise_error("If you're running dm-fasten-the-seat-belt outside of Merb, you must specifiy :file_system_path in the options")
118
+
119
+ end
120
+ end
121
+
122
+ describe DataMapper::FastenTheSeatBelt, "inside Merb" do
123
+ before :all do
124
+ module Merb
125
+ def self.root
126
+ File.join(File.dirname(__FILE__), 'merb')
127
+ end
128
+
129
+ def self.env
130
+ "production"
131
+ end
132
+ end
133
+
134
+ class Image
135
+ include DataMapper::Resource
136
+ include DataMapper::FastenTheSeatBelt
137
+
138
+ property :id, Serial
139
+
140
+ fasten_the_seat_belt :thumbnails => {:small => {:size => "320x240", :quality => 99}}
141
+ end
142
+
143
+ Image.auto_migrate!
144
+
145
+ @sunshine_original_file_path = File.dirname(__FILE__) + '/files/sunshine.jpg'
146
+ @sunshine_tempfile = Tempfile.new('sunshine.jpg')
147
+ FileUtils.copy(@sunshine_original_file_path, @sunshine_tempfile.path)
148
+
149
+ @sunshine_image = Image.new(:file => {:filename => 'sunshine.jpg',
150
+ :content_type => 'image/jpeg',
151
+ :tempfile => @sunshine_tempfile})
152
+ # Expected file paths
153
+ @main_file_path = File.join(File.dirname(__FILE__), 'merb', 'public', 'production', 'images', '0000', '0001', 'sunshine.jpg')
154
+ @small_thumbnail_file_path = File.join(File.dirname(__FILE__), 'merb', 'public', 'production', 'images', '0000', '0001', 'sunshine_small.jpg')
155
+ end
156
+
157
+ after :all do
158
+ @sunshine_tempfile.close!
159
+ end
160
+
161
+ it "should be able to attach images" do
162
+ @sunshine_image.save.should == true
163
+ end
164
+
165
+ it "should store the files under the public/production/images directory by default" do
166
+ File.expand_path(@sunshine_image.absolute_path).should == @main_file_path
167
+ File.expand_path(@sunshine_image.absolute_path(:small)).should == @small_thumbnail_file_path
168
+ end
169
+
170
+ it "should be able to return the web path" do
171
+ @sunshine_image.path.should == '/production/images/0000/0001/sunshine.jpg'
172
+ @sunshine_image.path(:small).should == '/production/images/0000/0001/sunshine_small.jpg'
173
+ end
174
+
175
+ it "should raise an error if we try to get a web path and if the pictures aren't in the public directory" do
176
+ class Image
177
+ fasten_the_seat_belt :thumbnails => {:small => {:size => "320x240", :quality => 99}}, :file_system_path => '/'
178
+ end
179
+
180
+ lambda { @sunshine_image.path }.should raise_error("Can't return web directory name, the images aren't stored under the Merb application public directory")
181
+ end
182
+
183
+ it "should output 'Quality not supported' if we try to apply a quality setting on a non-jpeg image" do
184
+ @png_original_file_path = File.dirname(__FILE__) + '/files/children.png'
185
+ @png_tempfile = Tempfile.new('children.png')
186
+ FileUtils.copy(@png_original_file_path, @png_tempfile.path)
187
+
188
+ @png_image = Image.new(:file => {:filename => 'children.png',
189
+ :content_type => 'image/png',
190
+ :tempfile => @png_tempfile})
191
+ @png_image.should_receive(:puts).with("FastenTheSeatBelt says: Quality setting not supported for image/png files")
192
+ @png_image.save
193
+ end
194
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --format=progress
2
+ --colour
@@ -0,0 +1,37 @@
1
+ $TESTING=true
2
+ require 'rubygems'
3
+ gem 'rspec', '>=1.1.3'
4
+ require 'spec'
5
+ require 'pathname'
6
+
7
+ gem 'dm-validations'
8
+ require 'dm-validations'
9
+
10
+ require Pathname(__FILE__).dirname.expand_path.parent + 'lib/dm-fasten-the-seat-belt'
11
+
12
+ def load_driver(name, default_uri)
13
+ return false if ENV['ADAPTER'] != name.to_s
14
+
15
+ lib = "do_#{name}"
16
+
17
+ begin
18
+ gem lib, '>=0.9.10'
19
+ require lib
20
+ DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
21
+ DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
22
+ true
23
+ rescue Gem::LoadError => e
24
+ warn "Could not load #{lib}: #{e}"
25
+ false
26
+ end
27
+ end
28
+
29
+ ENV['ADAPTER'] ||= 'sqlite3'
30
+
31
+ HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
32
+ HAS_MYSQL = load_driver(:mysql, 'mysql://localhost/dm_fasten_the_seat_belt_test')
33
+ HAS_POSTGRES = load_driver(:postgres, 'postgres://postgres@localhost/dm_fasten_the_seat_belt_test')
34
+
35
+ require File.dirname(__FILE__) + '/classes'
36
+
37
+ DataMapper.auto_migrate!
data/tasks/hoe.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'hoe'
2
+
3
+ @config_file = "~/.rubyforge/user-config.yml"
4
+ @config = nil
5
+ RUBYFORGE_USERNAME = "unknown"
6
+ def rubyforge_username
7
+ unless @config
8
+ begin
9
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
10
+ rescue
11
+ puts <<-EOS
12
+ ERROR: No rubyforge config file found: #{@config_file}
13
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
14
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
15
+ EOS
16
+ exit
17
+ end
18
+ end
19
+ RUBYFORGE_USERNAME.replace @config["username"]
20
+ end
21
+
22
+ hoe = Hoe.new(GEM_NAME, GEM_VERSION) do |p|
23
+
24
+ p.developer(AUTHOR, EMAIL)
25
+
26
+ p.description = PROJECT_DESCRIPTION
27
+ p.summary = PROJECT_SUMMARY
28
+ p.url = PROJECT_URL
29
+
30
+ p.rubyforge_name = PROJECT_NAME if PROJECT_NAME
31
+
32
+ p.clean_globs |= GEM_CLEAN
33
+ p.spec_extras = GEM_EXTRAS if GEM_EXTRAS
34
+
35
+ GEM_DEPENDENCIES.each do |dep|
36
+ p.extra_deps << dep
37
+ end
38
+
39
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-fasten-the-seat-belt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.9
5
+ platform: ruby
6
+ authors:
7
+ - Maxime Guilbot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-08 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dm-core
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.9
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: mini_magick
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.3
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.8.2
44
+ version:
45
+ description: A new merb plugin for adding image and file upload storage capabilities
46
+ email:
47
+ - maxime [a] ekohe [d] com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - README.txt
54
+ - LICENSE
55
+ - TODO
56
+ files:
57
+ - History.txt
58
+ - LICENSE
59
+ - Manifest.txt
60
+ - README.txt
61
+ - Rakefile
62
+ - TODO
63
+ - lib/dm-fasten-the-seat-belt.rb
64
+ - lib/dm-fasten-the-seat-belt/fasten-the-seat-belt/compression.rb
65
+ - lib/dm-fasten-the-seat-belt/fasten-the-seat-belt/version.rb
66
+ - spec/classes.rb
67
+ - spec/documents/classes.rb
68
+ - spec/documents/files/document.pdf
69
+ - spec/documents/files/word.doc
70
+ - spec/documents/integration_spec.rb
71
+ - spec/pictures/classes.rb
72
+ - spec/pictures/files/children.jpg
73
+ - spec/pictures/files/children.png
74
+ - spec/pictures/files/sunshine.jpg
75
+ - spec/pictures/integration_spec.rb
76
+ - spec/spec.opts
77
+ - spec/spec_helper.rb
78
+ - tasks/hoe.rb
79
+ has_rdoc: true
80
+ homepage: http://github.com/maxime/dm-fasten-the-seat-belt
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --main
84
+ - README.txt
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ version:
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: "0"
98
+ version:
99
+ requirements: []
100
+
101
+ rubyforge_project: dm-fasten-the-s
102
+ rubygems_version: 1.3.1
103
+ signing_key:
104
+ specification_version: 2
105
+ summary: A new merb plugin for adding image and file upload storage capabilities
106
+ test_files: []
107
+