bulldog 0.1.0 → 0.1.1
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 +7 -0
- data/lib/bulldog.rb +1 -1
- data/lib/bulldog/attachment/base.rb +1 -4
- data/lib/bulldog/attachment/maybe.rb +3 -2
- data/lib/bulldog/has_attachment.rb +134 -127
- data/lib/bulldog/processor/ffmpeg.rb +1 -0
- data/lib/bulldog/version.rb +1 -1
- data/spec/unit/has_attachment_spec.rb +11 -0
- metadata +3 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.1.1 2010-06-30
|
2
|
+
|
3
|
+
* Create output directory when recording frames if necessary.
|
4
|
+
* Only add Bulldog callbacks in classes that need them.
|
5
|
+
* Fix comparison of attachments with non-attachment classes.
|
6
|
+
* Don't create blank file when saving record with a missing file.
|
7
|
+
|
1
8
|
== 0.1.0 2010-06-23
|
2
9
|
|
3
10
|
* Add Bulldog.path_root, for specifying per-environment roots.
|
data/lib/bulldog.rb
CHANGED
@@ -9,7 +9,7 @@ module Bulldog
|
|
9
9
|
@name = name
|
10
10
|
@stream = stream
|
11
11
|
@value = stream && stream.target
|
12
|
-
@saved = value.is_a?(SavedFile)
|
12
|
+
@saved = @value.is_a?(SavedFile) || @value.is_a?(MissingFile)
|
13
13
|
end
|
14
14
|
|
15
15
|
attr_reader :record, :name, :stream, :value
|
@@ -39,7 +39,8 @@ module Bulldog
|
|
39
39
|
# same state as the given Attachment.
|
40
40
|
#
|
41
41
|
def ==(other)
|
42
|
-
|
42
|
+
other.is_a?(Bulldog::Attachment::Maybe) &&
|
43
|
+
record == other.record &&
|
43
44
|
name == other.name &&
|
44
45
|
value == other.value &&
|
45
46
|
saved? == other.saved?
|
@@ -1,160 +1,180 @@
|
|
1
1
|
module Bulldog
|
2
2
|
module HasAttachment
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
#
|
4
|
+
# Declare that this model has an attachment.
|
5
|
+
#
|
6
|
+
# TODO: example that shows all the options.
|
7
|
+
#
|
8
|
+
def has_attachment(name, &block)
|
9
|
+
unless include?(InstanceMethods)
|
10
|
+
extend ClassMethods
|
11
|
+
include InstanceMethods
|
12
|
+
end
|
6
13
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
14
|
+
reflection = attachment_reflections[name] || Reflection.new(self, name)
|
15
|
+
reflection.configure(&block)
|
16
|
+
attachment_reflections[name] = reflection
|
17
|
+
define_attachment_accessors(reflection.name)
|
18
|
+
define_attachment_attribute_methods(reflection.name)
|
19
|
+
end
|
12
20
|
|
13
|
-
|
14
|
-
base
|
21
|
+
module InstanceMethods
|
22
|
+
def self.included(base)
|
23
|
+
base.instance_variable_set(:@attachment_reflections, {})
|
15
24
|
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
# We need to store the attachment changes ourselves, since
|
26
|
+
# they're unavailable in an after_save.
|
27
|
+
base.before_save :store_original_attachments
|
28
|
+
base.after_save :save_attachments
|
29
|
+
base.after_save :clear_original_attachments
|
19
30
|
|
20
|
-
|
21
|
-
base.
|
22
|
-
|
31
|
+
base.before_save :update_attachment_timestamps
|
32
|
+
base.after_destroy :destroy_attachments
|
33
|
+
|
34
|
+
# Force initialization of attachments, as #destroy will freeze
|
35
|
+
# the attributes afterwards.
|
36
|
+
base.before_destroy :initialize_remaining_attachments
|
37
|
+
|
38
|
+
%w[validation save create update].each do |event|
|
39
|
+
base.send("before_#{event}", "process_attachments_for_before_#{event}")
|
40
|
+
base.send("after_#{event}", "process_attachments_for_after_#{event}")
|
41
|
+
end
|
23
42
|
end
|
24
|
-
end
|
25
43
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
44
|
+
def save_attachments
|
45
|
+
attachment_reflections.each do |name, reflection|
|
46
|
+
original_attachment = @original_attachments[name] and
|
47
|
+
original_attachment.destroy
|
48
|
+
_attachment_for(name).save
|
49
|
+
end
|
31
50
|
end
|
32
|
-
end
|
33
51
|
|
34
|
-
|
35
|
-
|
36
|
-
|
52
|
+
def destroy_attachments
|
53
|
+
attachment_reflections.each do |name, reflection|
|
54
|
+
_attachment_for(name).destroy
|
55
|
+
end
|
37
56
|
end
|
38
|
-
end
|
39
57
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
58
|
+
def update_attachment_timestamps
|
59
|
+
attachment_reflections.each do |name, reflection|
|
60
|
+
next unless send("#{name}_changed?")
|
61
|
+
setter = "#{name}_updated_at="
|
62
|
+
if respond_to?(setter)
|
63
|
+
send(setter, Time.now)
|
64
|
+
end
|
46
65
|
end
|
47
66
|
end
|
48
|
-
end
|
49
67
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
68
|
+
def process_attachment(name, event, *args)
|
69
|
+
reflection = attachment_reflections[name] or
|
70
|
+
raise ArgumentError, "no such attachment: #{name}"
|
71
|
+
_attachment_for(name).process(event, *args)
|
72
|
+
end
|
55
73
|
|
56
|
-
|
57
|
-
|
58
|
-
|
74
|
+
def attachment_reflection_for(name)
|
75
|
+
self.class.attachment_reflections[name]
|
76
|
+
end
|
59
77
|
|
60
|
-
|
78
|
+
private # -------------------------------------------------------
|
61
79
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
80
|
+
# Prefixed with '_', as it would collide with paperclip otherwise.
|
81
|
+
def _attachment_for(name)
|
82
|
+
read_attribute(name) or
|
83
|
+
initialize_attachment(name)
|
84
|
+
end
|
67
85
|
|
68
|
-
|
69
|
-
|
70
|
-
value = nil
|
71
|
-
else
|
72
|
-
reflection = attachment_reflection_for(name)
|
73
|
-
file_name_column = reflection.column_name_for_stored_attribute(:file_name)
|
74
|
-
file_name = file_name_column ? send(file_name_column) : nil
|
75
|
-
if file_name_column && file_name.nil?
|
86
|
+
def initialize_attachment(name)
|
87
|
+
if new_record?
|
76
88
|
value = nil
|
77
89
|
else
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
if
|
82
|
-
value =
|
90
|
+
reflection = attachment_reflection_for(name)
|
91
|
+
file_name_column = reflection.column_name_for_stored_attribute(:file_name)
|
92
|
+
file_name = file_name_column ? send(file_name_column) : nil
|
93
|
+
if file_name_column && file_name.nil?
|
94
|
+
value = nil
|
83
95
|
else
|
84
|
-
|
85
|
-
|
96
|
+
template = reflection.path_template
|
97
|
+
style = reflection.styles[:original]
|
98
|
+
original_path = Interpolation.interpolate(template, self, name, style, :basename => file_name)
|
99
|
+
if File.exist?(original_path)
|
100
|
+
value = SavedFile.new(original_path, :file_name => file_name)
|
86
101
|
else
|
87
|
-
|
102
|
+
if file_name_column
|
103
|
+
value = MissingFile.new(:file_name => file_name)
|
104
|
+
else
|
105
|
+
value = nil
|
106
|
+
end
|
88
107
|
end
|
89
108
|
end
|
90
109
|
end
|
110
|
+
|
111
|
+
attachment = make_attachment_for(name, value)
|
112
|
+
write_attribute_without_dirty(name, attachment)
|
113
|
+
attachment.read_storable_attributes
|
114
|
+
attachment
|
91
115
|
end
|
92
116
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
117
|
+
def assign_attachment(name, value)
|
118
|
+
old_attachment = _attachment_for(name)
|
119
|
+
unless old_attachment.value == value
|
120
|
+
old_attachment.unload
|
121
|
+
new_attachment = make_attachment_for(name, value)
|
122
|
+
new_attachment.load
|
123
|
+
write_attribute(name, new_attachment)
|
124
|
+
end
|
125
|
+
end
|
98
126
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
write_attribute(name, new_attachment)
|
127
|
+
def make_attachment_for(name, value)
|
128
|
+
return Attachment.none(self, name) if value.nil?
|
129
|
+
stream = Stream.new(value)
|
130
|
+
reflection = attachment_reflection_for(name)
|
131
|
+
type = reflection.detect_attachment_type(self, stream)
|
132
|
+
Attachment.of_type(type, self, name, stream)
|
106
133
|
end
|
107
|
-
end
|
108
134
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
135
|
+
def store_original_attachments
|
136
|
+
@original_attachments = {}
|
137
|
+
attachment_reflections.each do |name, reflection|
|
138
|
+
if send("#{name}_changed?")
|
139
|
+
@original_attachments[name] = send("#{name}_was")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
116
143
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
if
|
121
|
-
|
144
|
+
def clear_original_attachments
|
145
|
+
# This can be unset if the record is resaved between store and
|
146
|
+
# clear (e.g., in an after_save: store, save, store, clear, clear).
|
147
|
+
if instance_variable_defined?(:@original_attachments)
|
148
|
+
remove_instance_variable :@original_attachments
|
122
149
|
end
|
123
150
|
end
|
124
|
-
end
|
125
151
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
152
|
+
def process_attachments_for_event(event, *args)
|
153
|
+
self.class.attachment_reflections.each do |name, reflection|
|
154
|
+
_attachment_for(reflection.name).process(event, *args)
|
155
|
+
end
|
130
156
|
end
|
131
|
-
end
|
132
157
|
|
133
|
-
|
134
|
-
|
135
|
-
|
158
|
+
def initialize_remaining_attachments
|
159
|
+
self.attachment_reflections.each do |name, reflection|
|
160
|
+
_attachment_for(name) # force initialization
|
161
|
+
end
|
136
162
|
end
|
137
|
-
end
|
138
163
|
|
139
|
-
|
140
|
-
|
141
|
-
|
164
|
+
%w[validation save create update].each do |event|
|
165
|
+
module_eval <<-EOS
|
166
|
+
def process_attachments_for_before_#{event}
|
167
|
+
process_attachments_for_event(:before_#{event})
|
168
|
+
end
|
169
|
+
def process_attachments_for_after_#{event}
|
170
|
+
process_attachments_for_event(:after_#{event})
|
171
|
+
end
|
172
|
+
EOS
|
142
173
|
end
|
143
|
-
end
|
144
174
|
|
145
|
-
|
146
|
-
module_eval <<-EOS
|
147
|
-
def process_attachments_for_before_#{event}
|
148
|
-
process_attachments_for_event(:before_#{event})
|
149
|
-
end
|
150
|
-
def process_attachments_for_after_#{event}
|
151
|
-
process_attachments_for_event(:after_#{event})
|
152
|
-
end
|
153
|
-
EOS
|
175
|
+
delegate :attachment_reflections, :to => 'self.class'
|
154
176
|
end
|
155
177
|
|
156
|
-
delegate :attachment_reflections, :to => 'self.class'
|
157
|
-
|
158
178
|
module ClassMethods
|
159
179
|
def attachment_reflections
|
160
180
|
@attachment_reflections ||=
|
@@ -168,19 +188,6 @@ module Bulldog
|
|
168
188
|
end
|
169
189
|
end
|
170
190
|
|
171
|
-
#
|
172
|
-
# Declare that this model has an attachment.
|
173
|
-
#
|
174
|
-
# TODO: example that shows all the options.
|
175
|
-
#
|
176
|
-
def has_attachment(name, &block)
|
177
|
-
reflection = attachment_reflections[name] || Reflection.new(self, name)
|
178
|
-
reflection.configure(&block)
|
179
|
-
attachment_reflections[name] = reflection
|
180
|
-
define_attachment_accessors(reflection.name)
|
181
|
-
define_attachment_attribute_methods(reflection.name)
|
182
|
-
end
|
183
|
-
|
184
191
|
def define_attachment_accessors(name)
|
185
192
|
module_eval <<-EOS, __FILE__, __LINE__
|
186
193
|
def #{name}
|
data/lib/bulldog/version.rb
CHANGED
@@ -335,6 +335,17 @@ describe HasAttachment do
|
|
335
335
|
@thing.photo_content_type == "image/jpeg"
|
336
336
|
@thing.photo_file_size.should == File.size(test_path('test.jpg'))
|
337
337
|
end
|
338
|
+
|
339
|
+
describe "when the record is saved" do
|
340
|
+
before do
|
341
|
+
instantiate
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should not create any files" do
|
345
|
+
@thing.save
|
346
|
+
File.should_not exist(@thing.photo.path(:original))
|
347
|
+
end
|
348
|
+
end
|
338
349
|
end
|
339
350
|
end
|
340
351
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- George Ogata
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-30 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|