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 +5 -0
- data/VERSION +1 -1
- data/bulldog.gemspec +2 -1
- data/lib/bulldog/attachment/base.rb +5 -0
- data/lib/bulldog/attachment/image.rb +5 -0
- data/lib/bulldog/attachment/maybe.rb +38 -5
- data/lib/bulldog/attachment/video.rb +7 -0
- data/lib/bulldog/has_attachment.rb +2 -2
- data/lib/bulldog/stream.rb +7 -0
- data/spec/data/test.ogg +0 -0
- data/spec/unit/attachment/image_spec.rb +36 -0
- data/spec/unit/attachment/maybe_spec.rb +23 -1
- data/spec/unit/attachment/video_spec.rb +36 -0
- data/spec/unit/stream_spec.rb +57 -17
- metadata +2 -1
data/CHANGELOG
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/bulldog.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{bulldog}
|
8
|
-
s.version = "0.0.
|
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",
|
@@ -66,9 +66,12 @@ module Bulldog
|
|
66
66
|
end
|
67
67
|
|
68
68
|
#
|
69
|
-
#
|
69
|
+
# Load the attachment.
|
70
70
|
#
|
71
|
-
|
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
|
-
#
|
84
|
+
# Unload the attachment.
|
85
|
+
#
|
86
|
+
# Called before a reload on the old attachment, or before a
|
87
|
+
# destroy.
|
82
88
|
#
|
83
|
-
def
|
84
|
-
storable_attributes.each do |name,
|
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.
|
102
|
+
old_attachment.unload
|
103
103
|
new_attachment = make_attachment_for(name, value)
|
104
|
-
new_attachment.
|
104
|
+
new_attachment.load
|
105
105
|
write_attribute(name, new_attachment)
|
106
106
|
end
|
107
107
|
end
|
data/lib/bulldog/stream.rb
CHANGED
data/spec/data/test.ogg
ADDED
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,
|
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
|
data/spec/unit/stream_spec.rb
CHANGED
@@ -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
|
-
|
104
|
-
|
137
|
+
tempfile = Tempfile.new('bulldog-spec')
|
138
|
+
tempfile.print(content)
|
139
|
+
class << tempfile
|
105
140
|
attr_accessor :original_path
|
106
141
|
end
|
107
|
-
|
142
|
+
tempfile
|
108
143
|
end
|
109
144
|
end
|
110
145
|
|
111
|
-
describe
|
146
|
+
describe Stream::ForStringIO do
|
112
147
|
it_should_behave_like_all_streams
|
113
148
|
|
114
149
|
def object(content)
|
115
|
-
|
116
|
-
|
117
|
-
class << tempfile
|
150
|
+
stringio = StringIO.new(content)
|
151
|
+
class << stringio
|
118
152
|
attr_accessor :original_path
|
119
153
|
end
|
120
|
-
|
154
|
+
stringio
|
121
155
|
end
|
122
156
|
end
|
123
157
|
|
124
|
-
describe
|
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
|
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
|
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
|
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
|
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
|
251
|
+
describe Stream::ForIO do
|
214
252
|
it_should_behave_like_all_streams
|
215
253
|
|
216
254
|
def object(content)
|
217
|
-
|
218
|
-
|
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.
|
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
|