bulldog 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.0.6 2009-11-17
2
+
3
+ * Add attachment#reload for when the file changes behind Bulldog's
4
+ back.
5
+
1
6
  == 0.0.5 2009-11-17
2
7
 
3
8
  * Fix @original_attachments not being set in after save.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bulldog}
8
- s.version = "0.0.5"
8
+ s.version = "0.0.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["George Ogata"]
@@ -62,6 +62,7 @@ Flexible file attachments for active record.
62
62
  "spec/data/empty.txt",
63
63
  "spec/data/test.jpg",
64
64
  "spec/data/test.mov",
65
+ "spec/data/test.ogg",
65
66
  "spec/data/test.pdf",
66
67
  "spec/data/test.png",
67
68
  "spec/data/test2.jpg",
@@ -118,6 +118,11 @@ module Bulldog
118
118
  end
119
119
  end
120
120
 
121
+ def unload
122
+ super
123
+ @examination_result = nil
124
+ end
125
+
121
126
  protected # ---------------------------------------------------
122
127
 
123
128
  #
@@ -27,6 +27,11 @@ module Bulldog
27
27
 
28
28
  include HasDimensions
29
29
 
30
+ def unload
31
+ super
32
+ @original_dimensions = nil
33
+ end
34
+
30
35
  protected # ---------------------------------------------------
31
36
 
32
37
  #
@@ -66,9 +66,12 @@ module Bulldog
66
66
  end
67
67
 
68
68
  #
69
- # Set the stored attributes in the record.
69
+ # Load the attachment.
70
70
  #
71
- def set_stored_attributes
71
+ # Called just after initializing the attachment, or after a
72
+ # reload on the new attachment.
73
+ #
74
+ def load
72
75
  storable_attributes.each do |name, storable_attribute|
73
76
  if (column_name = reflection.column_name_for_stored_attribute(name))
74
77
  value = storable_attribute.value_for(self, :original)
@@ -78,16 +81,46 @@ module Bulldog
78
81
  end
79
82
 
80
83
  #
81
- # Clear the stored attributes in the record.
84
+ # Unload the attachment.
85
+ #
86
+ # Called before a reload on the old attachment, or before a
87
+ # destroy.
82
88
  #
83
- def clear_stored_attributes
84
- storable_attributes.each do |name, callback|
89
+ def unload
90
+ storable_attributes.each do |name, storable_attribute|
85
91
  if (column_name = reflection.column_name_for_stored_attribute(name))
86
92
  record.send("#{column_name}=", nil)
87
93
  end
94
+ if storable_attribute.memoize?
95
+ send("memoized_#{name}").clear
96
+ end
88
97
  end
89
98
  end
90
99
 
100
+ #
101
+ # Refresh the attachment. This includes anything read from the
102
+ # file, such as stored attributes, and dimensions.
103
+ #
104
+ # Use this to update the record if the underlying file has been
105
+ # modified outside of Bulldog. Note that the file has to be
106
+ # initialized from a saved file for this to work.
107
+ #
108
+ # Example:
109
+ #
110
+ # article = Article.create(:photo => photo_file)
111
+ # article = Article.find(article.id)
112
+ #
113
+ # # ... file is modified by an outside force ...
114
+ #
115
+ # article.photo.reload
116
+ # article.photo.dimensions # now reflects the new dimensions
117
+ #
118
+ def reload
119
+ unload
120
+ stream.reload
121
+ load
122
+ end
123
+
91
124
  #
92
125
  # Set the stored attributes in the attachment from the values in
93
126
  # the record.
@@ -80,6 +80,13 @@ module Bulldog
80
80
 
81
81
  storable_attribute :duration , :per_style => true, :memoize => true
82
82
 
83
+ def unload
84
+ super
85
+ instance_variables.grep(/@original_/).each do |name|
86
+ instance_variable_set(name, nil)
87
+ end
88
+ end
89
+
83
90
  protected # ---------------------------------------------------
84
91
 
85
92
  #
@@ -99,9 +99,9 @@ module Bulldog
99
99
  def assign_attachment(name, value)
100
100
  old_attachment = _attachment_for(name)
101
101
  unless old_attachment.value == value
102
- old_attachment.clear_stored_attributes
102
+ old_attachment.unload
103
103
  new_attachment = make_attachment_for(name, value)
104
- new_attachment.set_stored_attributes
104
+ new_attachment.load
105
105
  write_attribute(name, new_attachment)
106
106
  end
107
107
  end
@@ -88,6 +88,13 @@ module Bulldog
88
88
  FileUtils.cp src, dst
89
89
  end
90
90
  end
91
+
92
+ #
93
+ # Reload data from the target.
94
+ #
95
+ def reload
96
+ @content_type = nil
97
+ end
91
98
  end
92
99
 
93
100
  class ForTempfile < Base
Binary file
@@ -125,4 +125,40 @@ describe Attachment::Image do
125
125
  end
126
126
  end
127
127
  end
128
+
129
+ describe "#reload" do
130
+ before do
131
+ thing = Thing.create(:photo => test_image_file('test.jpg'))
132
+ @thing = Thing.find(thing.id)
133
+ end
134
+
135
+ it "should update the stored attributes from the file" do
136
+ # Prime the cached values.
137
+ @thing.photo_width.should == 40
138
+ @thing.photo_height.should == 30
139
+ @thing.photo_aspect_ratio.should be_close(4.0/3, 1e-5)
140
+ @thing.photo_dimensions.should == '40x30'
141
+
142
+ FileUtils.cp(test_path('test2.jpg'), @thing.photo.path(:original))
143
+ @thing.photo.reload
144
+ @thing.photo_width.should == 2
145
+ @thing.photo_height.should == 2
146
+ @thing.photo_aspect_ratio.should == 1
147
+ @thing.photo_dimensions.should == '2x2'
148
+ end
149
+
150
+ it "should update the original dimensions from the file" do
151
+ @thing.photo.dimensions(:original).should == [40, 30]
152
+ FileUtils.cp(test_path('test2.jpg'), @thing.photo.path(:original))
153
+ @thing.photo.reload
154
+ @thing.photo.dimensions(:original).should == [2, 2]
155
+ end
156
+
157
+ it "should update the dimensions for each style from the file" do
158
+ @thing.photo.dimensions(:double).should == [80, 60]
159
+ FileUtils.cp(test_path('test2.jpg'), @thing.photo.path(:original))
160
+ @thing.photo.reload
161
+ @thing.photo.dimensions(:double).should == [60, 60]
162
+ end
163
+ end
128
164
  end
@@ -1,7 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Attachment::Maybe do
4
- use_model_class(:Thing, :photo_file_name => :string)
4
+ use_model_class(:Thing,
5
+ :photo_file_name => :string,
6
+ :photo_file_size => :integer,
7
+ :photo_content_type => :string)
5
8
 
6
9
  before do
7
10
  spec = self
@@ -123,4 +126,23 @@ describe Attachment::Maybe do
123
126
  end
124
127
  end
125
128
  end
129
+
130
+ describe "#reload" do
131
+ before do
132
+ thing = Thing.create(:photo => test_file('test.png'))
133
+ @thing = Thing.find(thing.id)
134
+ end
135
+
136
+ it "should update the file size stored attribute from the file" do
137
+ FileUtils.cp(test_path('test2.jpg'), @thing.photo.path(:original))
138
+ @thing.photo.reload
139
+ @thing.photo_file_size.should == File.size(test_path('test2.jpg'))
140
+ end
141
+
142
+ it "should reload the content type stored attribute from the file" do
143
+ FileUtils.cp(test_path('test.png'), @thing.photo.path(:original))
144
+ @thing.photo.reload
145
+ @thing.photo_content_type.should =~ %r'image/png'
146
+ end
147
+ end
126
148
  end
@@ -173,4 +173,40 @@ describe Attachment::Video do
173
173
  end
174
174
  end
175
175
  end
176
+
177
+ describe "#reload" do
178
+ before do
179
+ thing = Thing.create(:video => test_video_file('test.mov'))
180
+ @thing = Thing.find(thing.id)
181
+ end
182
+
183
+ it "should update the stored attributes from the file" do
184
+ # Prime the cached values.
185
+ @thing.video_width.should == 640
186
+ @thing.video_height.should == 480
187
+ @thing.video_aspect_ratio.should be_close(4.0/3, 1e-5)
188
+ @thing.video_dimensions.should == '640x480'
189
+
190
+ FileUtils.cp(test_path('test.ogg'), @thing.video.path(:original))
191
+ @thing.video.reload
192
+ @thing.video_width.should == 176
193
+ @thing.video_height.should == 144
194
+ @thing.video_aspect_ratio.should == 176.0/144
195
+ @thing.video_dimensions.should == '176x144'
196
+ end
197
+
198
+ it "should update the original dimensions from the file" do
199
+ @thing.video.dimensions(:original).should == [640, 480]
200
+ FileUtils.cp(test_path('test.ogg'), @thing.video.path(:original))
201
+ @thing.video.reload
202
+ @thing.video.dimensions(:original).should == [176, 144]
203
+ end
204
+
205
+ it "should update the dimensions for each style from the file" do
206
+ @thing.video.dimensions(:half).should == [320, 240]
207
+ FileUtils.cp(test_path('test.ogg'), @thing.video.path(:original))
208
+ @thing.video.reload
209
+ @thing.video.dimensions(:half).should == [292, 240]
210
+ end
211
+ end
176
212
  end
@@ -82,6 +82,40 @@ describe Stream do
82
82
  end
83
83
  end
84
84
  end
85
+
86
+ describe "#reload" do
87
+ if options[:reloadable]
88
+ it "should make #size return the new size of the file" do
89
+ stream = stream('content')
90
+ update_target(stream, 'new content')
91
+ stream.reload
92
+ stream.size.should == 'new content'.size
93
+ end
94
+
95
+ it "should make #content_type return the new content type of the file" do
96
+ jpg_data = File.read(test_path('test.jpg'))
97
+ png_data = File.read(test_path('test.png'))
98
+ stream = stream(jpg_data)
99
+ stream.content_type.should =~ %r'\Aimage/jpeg'
100
+ update_target(stream, png_data)
101
+ stream.reload
102
+ stream.content_type.should =~ %r'\Aimage/png'
103
+ end
104
+ else
105
+ it "should not change the result of #size" do
106
+ stream = stream('content')
107
+ stream.reload
108
+ stream.size.should == 'content'.size
109
+ end
110
+
111
+ it "should not change the result of #content_type" do
112
+ jpg_data = File.read(test_path('test.jpg'))
113
+ stream = stream(jpg_data)
114
+ stream.reload
115
+ stream.content_type.should =~ %r'\Aimage/jpeg'
116
+ end
117
+ end
118
+ end
85
119
  end
86
120
 
87
121
  describe 'for a small uploaded file' do
@@ -100,28 +134,28 @@ describe Stream do
100
134
  it_should_behave_like_all_streams :file_name => :original_path
101
135
 
102
136
  def object(content)
103
- stringio = StringIO.new(content)
104
- class << stringio
137
+ tempfile = Tempfile.new('bulldog-spec')
138
+ tempfile.print(content)
139
+ class << tempfile
105
140
  attr_accessor :original_path
106
141
  end
107
- stringio
142
+ tempfile
108
143
  end
109
144
  end
110
145
 
111
- describe 'for a StringIO' do
146
+ describe Stream::ForStringIO do
112
147
  it_should_behave_like_all_streams
113
148
 
114
149
  def object(content)
115
- tempfile = Tempfile.new('bulldog-spec')
116
- tempfile.print(content)
117
- class << tempfile
150
+ stringio = StringIO.new(content)
151
+ class << stringio
118
152
  attr_accessor :original_path
119
153
  end
120
- tempfile
154
+ stringio
121
155
  end
122
156
  end
123
157
 
124
- describe 'for a Tempfile' do
158
+ describe Stream::ForTempfile do
125
159
  it_should_behave_like_all_streams
126
160
 
127
161
  def object(content)
@@ -131,7 +165,7 @@ describe Stream do
131
165
  end
132
166
  end
133
167
 
134
- describe 'for a File opened for reading' do
168
+ describe "Stream::ForFile (opened for writing)" do
135
169
  it_should_behave_like_all_streams :file_name => :basename
136
170
 
137
171
  def object(content)
@@ -152,7 +186,7 @@ describe Stream do
152
186
  end
153
187
  end
154
188
 
155
- describe 'for a File opened for writing' do
189
+ describe "Stream::ForFile (opened for writing)" do
156
190
  it_should_behave_like_all_streams :file_name => :basename
157
191
 
158
192
  def object(content)
@@ -162,17 +196,21 @@ describe Stream do
162
196
  end
163
197
  end
164
198
 
165
- describe 'for an SavedFile' do
166
- it_should_behave_like_all_streams :file_name => :file_name
199
+ describe Stream::ForSavedFile do
200
+ it_should_behave_like_all_streams :file_name => :file_name, :reloadable => true
167
201
 
168
202
  def object(content)
169
203
  path = "#{temporary_directory}/file"
170
204
  open(path, 'w'){|f| f.print content}
171
205
  SavedFile.new(path)
172
206
  end
207
+
208
+ def update_target(stream, content)
209
+ open(stream.target.path, 'w'){|f| f.print content}
210
+ end
173
211
  end
174
212
 
175
- describe 'for a MissingFile' do
213
+ describe Stream::ForMissingFile do
176
214
  it_should_behave_like_all_streams :file_name => :file_name
177
215
 
178
216
  def object(content)
@@ -210,12 +248,14 @@ describe Stream do
210
248
  end
211
249
  end
212
250
 
213
- describe 'for an IO' do
251
+ describe Stream::ForIO do
214
252
  it_should_behave_like_all_streams
215
253
 
216
254
  def object(content)
217
- io = IO.popen("echo -n #{content}")
218
- autoclose_stream(io)
255
+ readable, writable = IO.pipe
256
+ writable.print content
257
+ writable.close
258
+ autoclose_stream(readable)
219
259
  end
220
260
 
221
261
  describe "#path" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bulldog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Ogata
@@ -98,6 +98,7 @@ files:
98
98
  - spec/data/empty.txt
99
99
  - spec/data/test.jpg
100
100
  - spec/data/test.mov
101
+ - spec/data/test.ogg
101
102
  - spec/data/test.pdf
102
103
  - spec/data/test.png
103
104
  - spec/data/test2.jpg