jeremyboles-graffic 0.2.7 → 0.3.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.
@@ -11,21 +11,26 @@ require 'graffic/view_helpers'
11
11
  # A Graffic record progresses through four states: received, moved, uploaded and processed.
12
12
  # Graffic is designed in a way to let slow operating states out of the request cycle, if desired.
13
13
  #
14
+ # TODO: Figure out how to make this read-only
15
+ #
14
16
  class Graffic < ActiveRecord::Base
17
+ after_create :move
15
18
  after_destroy :delete_s3_file
16
19
 
17
- attr_writer :file, :processor
18
-
19
20
  before_validation_on_create :set_initial_state
20
21
 
21
22
  belongs_to :resource, :polymorphic => true
22
23
 
23
- class_inheritable_accessor :bucket_name, :processor
24
+ class_inheritable_accessor :bucket_name
24
25
  class_inheritable_accessor :format, :default => 'png'
25
26
  class_inheritable_accessor :process_queue_name, :default => 'graffic_process'
26
27
  class_inheritable_accessor :upload_queue_name, :default => 'graffic_upload'
28
+ class_inheritable_accessor :should_process_versions, :use_queue, :default => true
27
29
  class_inheritable_accessor :tmp_dir, :default => RAILS_ROOT + '/tmp/graffics'
28
- class_inheritable_hash :versions
30
+ class_inheritable_accessor :processors, :default => []
31
+ class_inheritable_accessor :versions, :default => {}
32
+
33
+ attr_writer :file, :processors
29
34
 
30
35
  validate_on_create :file_was_given
31
36
 
@@ -35,6 +40,7 @@ class Graffic < ActiveRecord::Base
35
40
  @bucket ||= Graffic::Aws.s3.bucket(bucket_name, true, 'public-read')
36
41
  end
37
42
 
43
+ # Create the tmp dir to store files until we upload them
38
44
  def create_tmp_dir
39
45
  FileUtils.mkdir(tmp_dir) unless File.exists?(tmp_dir)
40
46
  end
@@ -45,7 +51,7 @@ class Graffic < ActiveRecord::Base
45
51
  data = YAML.load(message.to_s)
46
52
  begin
47
53
  record = find(data[:id])
48
- record.process!
54
+ record.process
49
55
  rescue ActiveRecord::RecordNotFound
50
56
  return 'Not found'
51
57
  ensure
@@ -55,13 +61,14 @@ class Graffic < ActiveRecord::Base
55
61
  end
56
62
 
57
63
  # Handles the first message in the upload queue
64
+ # TODO: Figure out a better way to handle messages when records aren't there
58
65
  def handle_top_in_upload_queue!
59
66
  if message = upload_queue.receive
60
67
  data = YAML.load(message.to_s)
61
68
  return if data[:hostname] != `hostname`.strip
62
69
  begin
63
70
  record = find(data[:id])
64
- record.upload!
71
+ record.upload
65
72
  rescue ActiveRecord::RecordNotFound
66
73
  return 'Not found'
67
74
  ensure
@@ -70,10 +77,13 @@ class Graffic < ActiveRecord::Base
70
77
  end
71
78
  end
72
79
 
80
+ # DSL method for processing images
73
81
  def process(&block)
74
- self.processor = block if block_given?
82
+ self.processors ||= []
83
+ self.processors << block if block_given?
75
84
  end
76
85
 
86
+ # When we create a new type of Graffic, make sure we save the original
77
87
  def inherited(subclass)
78
88
  subclass.has_one(:original, :class_name => 'Graffic', :as => :resource, :dependent => :destroy, :conditions => { :name => 'original' })
79
89
  super
@@ -84,12 +94,10 @@ class Graffic < ActiveRecord::Base
84
94
  @process_queue ||= Graffic::Aws.sqs.queue(process_queue_name, true)
85
95
  end
86
96
 
97
+ # DSL method for making thumbnails
87
98
  def size(name, size = {})
88
99
  size.assert_valid_keys(:width, :height)
89
- version(name) do |img|
90
- img = img.first if img.respond_to?(:first)
91
- img.crop_resized(size[:width], size[:height])
92
- end
100
+ version(name) { |img| img.crop_resized(size[:width], size[:height]) }
93
101
  end
94
102
 
95
103
  # The queue for uploading images
@@ -97,12 +105,11 @@ class Graffic < ActiveRecord::Base
97
105
  @upload_queue ||= Graffic::Aws.sqs.queue(upload_queue_name, true)
98
106
  end
99
107
 
108
+ # DSL method for declaring a version of an image
100
109
  def version(name, &block)
101
- self.versions ||= {}
102
- if block_given?
103
- self.versions[name] = block || nil
104
- has_one(name, :class_name => 'Graffic', :as => :resource, :dependent => :destroy, :conditions => { :name => name.to_s })
105
- end
110
+ self.versions[name] ||= []
111
+ self.versions[name] << block if block_given?
112
+ has_one(name, :class_name => 'Graffic', :as => :resource, :dependent => :destroy, :conditions => { :name => name.to_s })
106
113
  end
107
114
  end
108
115
 
@@ -111,6 +118,7 @@ class Graffic < ActiveRecord::Base
111
118
  attributes['format'] || self.class.format
112
119
  end
113
120
 
121
+ # Return an RMagick image, based on the state of image
114
122
  def image
115
123
  @image ||= case self.state
116
124
  when 'moved': Magick::Image.read(tmp_file_path).first
@@ -119,70 +127,51 @@ class Graffic < ActiveRecord::Base
119
127
  end
120
128
 
121
129
  # Move the file to the temporary directory
122
- def move!
123
- move_without_queue!
124
- queue_for_upload
125
- end
126
-
127
- # Move the file to the temporary directory
128
- def move_without_queue!
130
+ def move
131
+ logger.debug("***** Moving? #{self.state}")
132
+ return unless self.state == 'received'
129
133
  logger.debug("***** Graffic[#{self.id}](#{self.name})#move!")
130
- if @file.is_a?(Tempfile)
131
- @file.write(tmp_file_path)
132
- change_state('moved')
133
- elsif @file.is_a?(String)
134
- FileUtils.cp(@file, tmp_file_path)
135
- change_state('moved')
136
- elsif @file.is_a?(Magick::Image)
134
+ logger.debug("***** File type: #{@file.class.name}")
135
+ if @file.is_a?(Tempfile) # Uploaded File
136
+ FileUtils.cp(@file.path, tmp_file_path)
137
+ logger.debug("***** Moving file: #{@file.path}, #{tmp_file_path}")
138
+ elsif @file.is_a?(String) # String representing a file's location
139
+ FileUtils.cp(@file.strip, tmp_file_path)
140
+ logger.debug("***** Moving file: #{@file.strip}, #{tmp_file_path}")
141
+ elsif @file.is_a?(Magick::Image) # An actually RMagick file
137
142
  @image = @file
138
- upload_without_queue!
143
+ self.use_queue = false
139
144
  change_state('uploaded')
145
+ process
146
+ return
147
+ else
148
+ raise "Don't know how to handle file type #{@file.class.name}"
140
149
  end
150
+
151
+ change_state('moved')
152
+ use_queue? ? queue_for_upload : upload
141
153
  end
142
154
 
143
- # Process the image
144
- def process!
145
- process_without_verions!
146
- process_versions
155
+ attr_accessor :should_process_versions
156
+ def should_process_versions?
157
+ should_process_versions.nil? ? self.class.should_process_versions : should_process_versions
147
158
  end
148
159
 
149
- # Process the image without the versions
150
- def process_without_verions!
160
+ # Process the image
161
+ def process
162
+ return unless self.state == 'uploaded'
151
163
  logger.debug("***** Graffic[#{self.id}](#{self.name})#process!")
152
164
  run_processors
153
165
  record_image_dimensions_and_format
154
166
  upload_image
155
167
  change_state('processed')
168
+
169
+ process_versions if should_process_versions?
156
170
  end
157
-
171
+
158
172
  # Returns the processor for the instance
159
- def processor
160
- @processor || self.class.processor
161
- end
162
-
163
- # Move the file if it saved successfully
164
- def save_and_move
165
- move! if status = save
166
- status
167
- end
168
-
169
- # Save the file and process it immediately. Does to use queues.
170
- def save_and_process
171
- if status = save
172
- move_without_queue!
173
- upload_without_queue!
174
- process!
175
- end
176
- status
177
- end
178
-
179
- def save_and_process_without_versions
180
- if status = save
181
- move_without_queue!
182
- upload_without_queue!
183
- process_without_verions!
184
- end
185
- status
173
+ def processors
174
+ @processors || self.class.processors
186
175
  end
187
176
 
188
177
  # Returns a size string. Good for RMagick and image_tag :size
@@ -191,18 +180,15 @@ class Graffic < ActiveRecord::Base
191
180
  end
192
181
 
193
182
  # Upload the file
194
- def upload!
195
- upload_without_queue!
196
- queue_for_processing
197
- end
198
-
199
- # Upload the file
200
- def upload_without_queue!
183
+ def upload
184
+ return unless self.state == 'moved'
201
185
  logger.debug("***** Graffic[#{self.id}](#{self.name})#upload!")
202
186
  upload_image
203
187
  save_original
204
188
  remove_tmp_file
189
+
205
190
  change_state('uploaded')
191
+ use_queue? ? queue_for_processing : process
206
192
  end
207
193
 
208
194
  # Return the url for displaying the image
@@ -210,6 +196,11 @@ class Graffic < ActiveRecord::Base
210
196
  self.s3_key.public_link
211
197
  end
212
198
 
199
+ attr_accessor :use_queue
200
+ def use_queue?
201
+ use_queue.nil? ? self.class.use_queue : use_queue
202
+ end
203
+
213
204
  protected
214
205
 
215
206
  # Connivence method for getting the bucket
@@ -243,15 +234,12 @@ protected
243
234
  end
244
235
 
245
236
  def process_versions
246
- unless self.versions.blank?
247
- self.versions.each do |version, processor|
248
- logger.debug("***** Graffic[#{self.id}](#{self.name}): Processing version: #{version}")
249
- g = Graffic.create(:file => self.image, :name => version.to_s)
250
- g.processor = processor unless processor.nil?
251
- g.save_and_process
252
- self.update_attribute(version, g)
253
- end
254
- end
237
+ self.versions.each do |version, processors|
238
+ logger.debug("***** Graffic[#{self.id}](#{self.name}): Processing version: #{version} (#{processors.size} processors)")
239
+ g = Graffic.new(:file => self.image, :name => version.to_s, :use_queue => false)
240
+ g.processors += processors unless processors.nil?
241
+ self.update_attribute(version, g)
242
+ end unless self.versions.blank?
255
243
  end
256
244
 
257
245
  def queue_for_upload
@@ -281,11 +269,17 @@ protected
281
269
  end
282
270
 
283
271
  def run_processors
284
- logger.debug("***** Graffic[#{self.id}](#{self.name}): Running processor")
285
- unless self.processor.blank?
286
- @image = processor.call(image, self)
272
+ logger.debug("***** Graffic[#{self.id}](#{self.name}): Running processor (#{self.processors.try(:size)} processors)")
273
+ self.processors.each do |processor|
274
+ img = self.image
275
+ img = img.first if img.respond_to?(:first)
276
+ @image = case processor.arity # Pass in the record itself, if the block wants it
277
+ when 1: processor.call(img)
278
+ when 2: processor.call(img, self)
279
+ end
287
280
  raise 'You need to return an image' unless @image.is_a?(Magick::Image)
288
- end
281
+ logger.debug("Returned Image Size: #{@image.columns}x#{@image.rows}")
282
+ end unless self.processors.blank?
289
283
  end
290
284
 
291
285
  def s3_key
@@ -295,8 +289,7 @@ protected
295
289
  def save_original
296
290
  if respond_to?(:original)
297
291
  logger.debug("***** Graffic[#{self.id}](#{self.name}): Saving Original")
298
- g = Graffic.new(:file => tmp_file_path, :name => 'original')
299
- g.save_and_process
292
+ g = Graffic.new(:file => tmp_file_path, :name => 'original', :use_queue => false)
300
293
  self.update_attribute(:original, g)
301
294
  end
302
295
  end
@@ -1,6 +1,6 @@
1
1
  module Graffic::ViewHelpers
2
2
  def graffic_tag(graffic, version_or_opts = {}, opts = {})
3
- if graffic
3
+ if graffic && graffic.state.eql?('processed')
4
4
  if version_or_opts.is_a?(Symbol)
5
5
  graffic_tag(graffic.try(version_or_opts), opts)
6
6
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeremyboles-graffic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Boles