jeremyboles-graffic 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ == 0.1.0, released 2009-03-16
2
+
3
+ * Initial release
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
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,28 @@
1
+ Graffic
2
+ ======
3
+
4
+ Graffic is an ActiveRecord class that helps you work with and attach images to other ActiveRecord records.
5
+
6
+
7
+ Example
8
+ ======
9
+
10
+ # models/profile_photo.rb
11
+ class ProfilePhoto < Graffic
12
+ size :medium, :width => 48, :height => 48, :format => :jpg
13
+ end
14
+
15
+ # models/user.rb
16
+ class User < ActiveRecord
17
+ has_one :profile_photo
18
+ end
19
+
20
+ # views/users/_edit.html.erb
21
+ <% form_for @user do |f| %>
22
+ <% f.fields_for :profile_photo do |p| %>
23
+ <%= p.label :file, 'Profile Photo' %>
24
+ <%= p.field_field :file %>
25
+ <% end %>
26
+ <% end %>
27
+
28
+ Copyright (c) 2009 Jeremy Boles, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Generate RDoc documentation for the Graffic plugin.'
10
+ Rake::RDocTask.new(:rdoc) do |rdoc|
11
+ rdoc.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'CHANGELOG.rdoc').include('lib/**/*.rb')
12
+
13
+ rdoc.main = "README.rdoc" # page to start on
14
+ rdoc.title = "Graffic documentation"
15
+
16
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
17
+ rdoc.options << '--inline-source' << '--charset=UTF-8'
18
+ rdoc.options << '--webcvs=http://github.com/jeremyboles/graffic/tree/master/'
19
+ end
20
+
21
+ desc %{Update ".manifest" with the latest list of project filenames.}
22
+ task :manifest do
23
+ list = `git ls-files --full-name --exclude=*.gemspec --exclude=.*`.chomp.split("\n")
24
+
25
+ if spec_file = Dir['*.gemspec'].first
26
+ spec = File.read spec_file
27
+ spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do
28
+ assignment = $1
29
+ bunch = $2 ? list.grep(/^test\//) : list
30
+ '%s%%w(%s)' % [assignment, bunch.join(' ')]
31
+ end
32
+
33
+ File.open(spec_file, 'w') { |f| f << spec }
34
+ end
35
+ File.open('.manifest', 'w') { |f| f << list.join("\n") }
36
+ end
37
+
38
+ desc 'Test the graffic plugin.'
39
+ Rake::TestTask.new(:test) do |t|
40
+ t.libs << 'lib'
41
+ t.libs << 'test'
42
+ t.pattern = 'test/**/*_test.rb'
43
+ t.verbose = true
44
+ end
45
+
46
+ desc 'Generate documentation for the graffic plugin.'
47
+ Rake::RDocTask.new(:rdoc) do |rdoc|
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = 'Graffic'
50
+ rdoc.options << '--line-numbers' << '--inline-source'
51
+ rdoc.rdoc_files.include('README.rdoc')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'rmagick'
2
+ require 'state_machine'
3
+
4
+ require 'graffic'
5
+ require 'graffic/aws'
data/lib/graffic.rb ADDED
@@ -0,0 +1,276 @@
1
+ # Graffic
2
+ class Graffic < ActiveRecord::Base
3
+ attr_writer :file
4
+ attr_writer :image
5
+ cattr_writer :bucket_name
6
+ cattr_writer :queue_name
7
+
8
+ belongs_to :resource, :polymorphic => true
9
+
10
+ after_create :move
11
+ after_destroy :delete_s3_file
12
+
13
+ # We're using the state machine to keep track of what stage of photo
14
+ # processing we're at. Here are the states:
15
+ #
16
+ # received -> moved -> uploaded -> processed
17
+ #
18
+ state_machine :state, :initial => :received do
19
+ before_transition :to => :moved, :do => :move!
20
+ before_transition :to => :uploaded, :do => :save_original!
21
+ before_transition :from => :moved, :do => :upload!
22
+ before_transition :to => :processed, :do => :process!
23
+
24
+ after_transition :from => :moved, :do => :remove_moved_file!
25
+ after_transition :to => :uploaded, :do => :queue_job!
26
+ after_transition :to => :processed, :from => :uploaded, :do => :create_sizes!
27
+ after_transition :to => :processed, :do => :record_dimensions!
28
+
29
+ event :move do
30
+ transition :to => :moved, :from => :received
31
+ end
32
+
33
+ event :upload do
34
+ transition :to => :uploaded, :from => :moved
35
+ end
36
+
37
+ event :upload_unprocessed do
38
+ transition :to => :processed, :from => :moved
39
+ end
40
+
41
+ event :process do
42
+ transition :to => :processed, :from => :uploaded
43
+ end
44
+
45
+ # Based on which state we're at, we'll need to pull the image from a different are
46
+ state :moved do
47
+ # If it hasn't been moved, we'll need to pull it from the local file system
48
+ def image
49
+ @image ||= Magick::Image.read(tmp_file_path).first
50
+ end
51
+ end
52
+
53
+ state :uploaded, :processed do
54
+ # If it's been uploaded and procesed, grab it from S3
55
+ def image
56
+ @image ||= Magick::Image.from_blob(bucket.get(uploaded_file_path)).first
57
+ end
58
+ end
59
+ end
60
+
61
+ class << self
62
+ # Returns the bucket for the model
63
+ def bucket
64
+ @bucket ||= Graffic::Aws.s3.bucket(bucket_name, true, 'public-read')
65
+ end
66
+
67
+ # Change the bucket name from the default
68
+ def bucket_name(name = nil)
69
+ @@bucket_name = name unless name == nil
70
+ @@bucket_name
71
+ end
72
+
73
+ # Upload all of the files that have been moved. This will only work on
74
+ # local files.
75
+ # TODO: Make this work only on file system that the file was used on
76
+ def handle_moved!
77
+ image = first(:conditions => { :state => 'moved' })
78
+ return if image.nil?
79
+ image.upload
80
+ end
81
+
82
+ # Process all of the the uploaded files that are in the queue
83
+ def handle_uploaded!
84
+ message = queue.pop
85
+ return if message.nil?
86
+ image = find(message.body)
87
+ image.process
88
+ message.body
89
+ rescue
90
+ true
91
+ end
92
+
93
+ def inherited(child)
94
+ child.has_one(:original, :class_name => 'Graffic', :as => :resource, :dependent => :destroy, :conditions => { :name => 'original' })
95
+ super
96
+ end
97
+
98
+ def process(&block)
99
+ if block_given?
100
+ @process = block
101
+ else
102
+ return @process
103
+ end
104
+ end
105
+
106
+ # Change the queue name from the default
107
+ def queue_name(name = nil)
108
+ @@queue_name = name unless name == nil
109
+ @@queue_name || 'graffic'
110
+ end
111
+
112
+ # Return the model's queue
113
+ def queue
114
+ @queue ||= Graffic::Aws.sqs.queue(queue_name, true)
115
+ end
116
+
117
+ # Create a size of the graphic.
118
+ def size(name, size={})
119
+ size[:format] ||= :png
120
+ size.assert_valid_keys(:width, :height, :format)
121
+
122
+ @sizes ||= {}
123
+ @sizes[name] = size
124
+
125
+ has_one(name, :class_name => 'Graffic', :as => :resource, :dependent => :destroy, :conditions => { :name => name.to_s })
126
+ end
127
+
128
+ # Returns all of the version names for the mode
129
+ def sizes
130
+ @sizes ||= {}
131
+ end
132
+
133
+ # Set the image format
134
+ def format(format = nil)
135
+ @format = format unless format.nil?
136
+ @format ||= :png
137
+ end
138
+ end
139
+
140
+ # Returns a size string
141
+ def size
142
+ "#{width}x#{height}"
143
+ end
144
+
145
+ # Return the url for displaying the image
146
+ def url
147
+ key.public_link
148
+ end
149
+
150
+ private
151
+ # Connivence method for getting the bucket
152
+ def bucket
153
+ self.class.bucket
154
+ end
155
+
156
+ def create_sizes!
157
+ self.class.sizes.each do |name, size|
158
+ logger.debug("***** Sizing: #{name}")
159
+ file_name = "#{tmp_file_path}.#{name}.#{image_extension(size[:format])}"
160
+
161
+ img = image.crop_resized(size[:width], size[:height])
162
+ img.write(file_name)
163
+
164
+ i = Graffic.create(:file => file_name, :format => size[:format].to_s, :name => name.to_s)
165
+ update_attribute(name, i)
166
+ i.upload_unprocessed
167
+
168
+ FileUtils.rm(file_name)
169
+ end
170
+ end
171
+
172
+ # Deletes the file from S3
173
+ def delete_s3_file
174
+ key.delete
175
+ end
176
+
177
+ # The formate of the image
178
+ def format
179
+ attributes['format'] || self.class.format
180
+ end
181
+
182
+ # Returns true if the file has versions
183
+ def has_sizes?
184
+ !self.class.sizes.empty?
185
+ end
186
+
187
+ def image_extension(atype = nil)
188
+ (atype || format).to_s
189
+ end
190
+
191
+ # Return the S3 key for the record
192
+ def key
193
+ @s3_key ||= bucket.key(uploaded_file_path)
194
+ end
195
+
196
+ # If the file is a Tempfile, we'll need to move to the app's tmp directory so
197
+ # we can insure that it is retrained until we can upload it
198
+ # If its a S3 Key, we'll write that file's date to our tmp directory
199
+ def move!
200
+ if @file.is_a?(Tempfile)
201
+ FileUtils.mv(@file.path, tmp_file_path)
202
+ elsif @file.is_a?(String)
203
+ FileUtils.cp(@file, tmp_file_path)
204
+ end
205
+ end
206
+
207
+ # Process the image
208
+ def process!
209
+ unless self.class.process.nil?
210
+ @image = self.class.process.call(image)
211
+ raise 'You need to return an image' unless @image.is_a?(Magick::Image)
212
+ upload!
213
+ end
214
+ end
215
+
216
+ # Connivence method for getting the queue
217
+ def queue
218
+ self.class.queue
219
+ end
220
+
221
+ # Add a job to the queue
222
+ def queue_job!
223
+ logger.debug("***** Graffic(#{self.id})#queue_job!")
224
+ queue.push(self.id)
225
+ end
226
+
227
+ # Save the image's width and height to the database
228
+ def record_dimensions!
229
+ logger.debug("***** Graffic(#{self.id})#record_dimensions!")
230
+ self.update_attributes(:height => image.rows, :width => image.columns)
231
+ end
232
+
233
+ # Remove the temp file in the app's temp director
234
+ def remove_moved_file!
235
+ logger.debug("***** Graffic(#{self.id})#remove_moved_file!")
236
+ FileUtils.rm(tmp_file_path) if File.exists?(tmp_file_path)
237
+ end
238
+
239
+ # Returns a RMagick constant for the type of image
240
+ def rmagick_type(atype = nil)
241
+ return case (atype || format).to_sym
242
+ when :gif then Magick::LZWCompression
243
+ when :jpg then Magick::JPEGCompression
244
+ when :png then Magick::ZipCompression
245
+ end
246
+ end
247
+
248
+ # Uploads an untouched original
249
+ def save_original!
250
+ logger.debug("***** Graffic(#{self.id})#save_original!")
251
+ if respond_to?(:original)
252
+ i = Graffic.new(:file => tmp_file_path, :name => 'original')
253
+ update_attribute(:original, i)
254
+ i.upload_unprocessed
255
+ end
256
+ end
257
+
258
+ # Returns the path to the file in the app's tmp directory
259
+ def tmp_file_path
260
+ RAILS_ROOT + "/tmp/images/#{id}.tmp"
261
+ end
262
+
263
+ # Upload the file to S3
264
+ def upload!
265
+ logger.debug("***** Graffic(#{self.id})#upload!")
266
+ t = rmagick_type
267
+ data = image.to_blob { |i| i.compression = t }
268
+ bucket.put(uploaded_file_path, data, {}, 'public-read')
269
+ end
270
+
271
+ # Return the path on S3 for the file (the key name, essentially)
272
+ def uploaded_file_path
273
+ "#{self.class.name.tableize}/#{id}.#{image_extension}"
274
+ end
275
+
276
+ end # Graffic
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :graffic do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class GrafficTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_support/test_case'
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jeremyboles-graffic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Boles
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: state_machine
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.6.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: right_aws
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.10.0
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rmagick
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.9.1
44
+ version:
45
+ description: Graffic is an ActiveRecord class that helps you work with and attach images to other ActiveRecord records.
46
+ email: jeremy@jeremyboles.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - README.rdoc
53
+ - LICENSE
54
+ - CHANGELOG.rdoc
55
+ files:
56
+ - MIT-LICENSE
57
+ - README
58
+ - Rakefile
59
+ - init.rb
60
+ - install.rb
61
+ - lib/graffic.rb
62
+ - tasks/graffic_tasks.rake
63
+ - test/graffic_test.rb
64
+ - test/test_helper.rb
65
+ - uninstall.rb
66
+ - README.rdoc
67
+ - LICENSE
68
+ - CHANGELOG.rdoc
69
+ has_rdoc: true
70
+ homepage: http://github.com/jeremyboles/graffic/wikis
71
+ post_install_message:
72
+ rdoc_options:
73
+ - --main
74
+ - README.rdoc
75
+ - --inline-source
76
+ - --charset=UTF-8
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ version:
91
+ requirements: []
92
+
93
+ rubyforge_project:
94
+ rubygems_version: 1.2.0
95
+ signing_key:
96
+ specification_version: 2
97
+ summary: Image asset handing for ActiveRecord and Rails
98
+ test_files:
99
+ - test/graffic_test.rb
100
+ - test/test_helper.rb