jeremyboles-graffic 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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