bulldog 0.1.1 → 0.2.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 +7 -0
- data/lib/bulldog/attachment/base.rb +3 -6
- data/lib/bulldog/attachment/has_dimensions.rb +43 -34
- data/lib/bulldog/attachment/image.rb +5 -26
- data/lib/bulldog/attachment/pdf.rb +3 -28
- data/lib/bulldog/attachment/video.rb +48 -45
- data/lib/bulldog/style.rb +28 -1
- data/lib/bulldog/version.rb +1 -1
- data/spec/data/3-bytes.txt +1 -0
- data/spec/data/4-bytes.txt +1 -0
- data/spec/data/5-bytes.txt +1 -0
- data/spec/data/6-bytes.txt +1 -0
- data/spec/data/test-20x10.jpg +0 -0
- data/spec/data/test-20x10.pdf +0 -0
- data/spec/data/test-20x10x1.mov +0 -0
- data/spec/data/test-40x30.jpg +0 -0
- data/spec/data/test-40x30.pdf +0 -0
- data/spec/data/test-40x30x1.mov +0 -0
- data/spec/helpers/files.rb +123 -0
- data/spec/integration/lifecycle_hooks_spec.rb +1 -1
- data/spec/integration/processing_image_attachments.rb +1 -13
- data/spec/macros/attachment/has_dimensions_spec.rb +313 -0
- data/spec/spec_helper.rb +3 -4
- data/spec/unit/attachment/base_spec.rb +25 -45
- data/spec/unit/attachment/image_spec.rb +48 -171
- data/spec/unit/attachment/maybe_spec.rb +4 -12
- data/spec/unit/attachment/pdf_spec.rb +18 -136
- data/spec/unit/attachment/video_spec.rb +98 -170
- data/spec/unit/attachment_spec.rb +1 -1
- data/spec/unit/has_attachment_spec.rb +29 -26
- data/spec/unit/interpolation_spec.rb +2 -2
- data/spec/unit/processor/ffmpeg_spec.rb +3 -3
- data/spec/unit/processor/image_magick_spec.rb +1 -1
- data/spec/unit/processor/one_shot_spec.rb +1 -1
- data/spec/unit/stream_spec.rb +3 -3
- data/spec/unit/style_spec.rb +40 -0
- data/spec/unit/validations_spec.rb +33 -33
- metadata +28 -8
- data/spec/helpers/temporary_directory.rb +0 -25
- data/spec/helpers/test_upload_files.rb +0 -108
@@ -129,20 +129,12 @@ describe Attachment::Maybe do
|
|
129
129
|
|
130
130
|
describe "#reload" do
|
131
131
|
before do
|
132
|
-
thing = Thing.create(:photo =>
|
133
|
-
@thing
|
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))
|
132
|
+
@thing = Thing.create!(:photo => uploaded_file('test.png'))
|
133
|
+
FileUtils.cp("#{ROOT}/spec/data/test.jpg", @thing.photo.path(:original))
|
138
134
|
@thing.photo.reload
|
139
|
-
@thing.photo_file_size.should == File.size(test_path('test2.jpg'))
|
140
135
|
end
|
141
136
|
|
142
|
-
it "should
|
143
|
-
|
144
|
-
@thing.photo.reload
|
145
|
-
@thing.photo_content_type.should =~ %r'image/png'
|
146
|
-
end
|
137
|
+
it "should update the file size stored attribute from the file"
|
138
|
+
it "should reload the content type stored attribute from the file"
|
147
139
|
end
|
148
140
|
end
|
@@ -1,150 +1,32 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Attachment::Pdf do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "when file attributes are not stored" do
|
4
|
+
it_should_behave_like_an_attachment_with_dimensions(
|
5
|
+
:type => :pdf,
|
6
|
+
:missing_dimensions => [1, 1],
|
7
|
+
:file_40x30 => 'test-40x30.pdf',
|
8
|
+
:file_20x10 => 'test-20x10.pdf'
|
9
|
+
)
|
10
|
+
|
11
|
+
describe "#process" do
|
15
12
|
use_model_class(:Thing, :attachment_file_name => :string)
|
16
13
|
|
17
|
-
describe "#dimensions" do
|
18
|
-
it "should return 1x1 if the file is missing" do
|
19
|
-
Thing.has_attachment :attachment do
|
20
|
-
type :pdf
|
21
|
-
style :double, :size => '1224x1584'
|
22
|
-
style :filled, :size => '500x500', :filled => true
|
23
|
-
style :unfilled, :size => '1000x1000'
|
24
|
-
default_style :double
|
25
|
-
end
|
26
|
-
@thing = Thing.new(:attachment => test_file)
|
27
|
-
@thing.save.should be_true
|
28
|
-
File.unlink(@thing.attachment.path(:original))
|
29
|
-
@thing = Thing.find(@thing.id)
|
30
|
-
@thing.attachment.is_a?(Attachment::Pdf) # sanity check
|
31
|
-
@thing.attachment.stream.missing? # sanity check
|
32
|
-
@thing.attachment.dimensions(:original).should == [1, 1]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
describe "when file attributes are stored" do
|
38
|
-
use_model_class(:Thing,
|
39
|
-
:attachment_file_name => :string,
|
40
|
-
:attachment_width => :integer,
|
41
|
-
:attachment_height => :integer,
|
42
|
-
:attachment_aspect_ratio => :float,
|
43
|
-
:attachment_dimensions => :string)
|
44
|
-
|
45
14
|
before do
|
46
|
-
Thing.has_attachment :attachment
|
47
|
-
|
48
|
-
style :filled, :size => '500x500', :filled => true
|
49
|
-
style :unfilled, :size => '1000x1000'
|
50
|
-
default_style :double
|
51
|
-
end
|
52
|
-
@thing = Thing.new(:attachment => test_file)
|
15
|
+
Thing.has_attachment :attachment
|
16
|
+
@thing = Thing.new(:attachment => uploaded_file('test.pdf'))
|
53
17
|
end
|
54
18
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
context = self
|
62
|
-
end
|
19
|
+
it "should process with ImageMagick by default" do
|
20
|
+
context = nil
|
21
|
+
Thing.has_attachment :attachment do
|
22
|
+
style :output
|
23
|
+
process :on => :event do
|
24
|
+
context = self
|
63
25
|
end
|
64
|
-
|
65
|
-
@thing.attachment.process(:event)
|
66
|
-
context.should be_a(Processor::ImageMagick)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe "#dimensions" do
|
71
|
-
it "should return the width and height of the default style if no style name is given" do
|
72
|
-
@thing.attachment.dimensions.should == [1224, 1584]
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should return the width and height of the given style" do
|
76
|
-
@thing.attachment.dimensions(:original).should == [612, 792]
|
77
|
-
@thing.attachment.dimensions(:double).should == [1224, 1584]
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should return the calculated width according to style filledness" do
|
81
|
-
@thing.attachment.dimensions(:filled).should == [500, 500]
|
82
|
-
@thing.attachment.dimensions(:unfilled).should == [773, 1000]
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should only invoke identify once"
|
86
|
-
it "should log the result"
|
87
|
-
end
|
88
|
-
|
89
|
-
describe "#width" do
|
90
|
-
it "should return the width of the default style if no style name is given" do
|
91
|
-
@thing.attachment.width.should == 1224
|
92
|
-
end
|
93
|
-
|
94
|
-
it "should return the width of the given style" do
|
95
|
-
@thing.attachment.width(:original).should == 612
|
96
|
-
@thing.attachment.width(:double).should == 1224
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe "#height" do
|
101
|
-
it "should return the height of the default style if no style name is given" do
|
102
|
-
@thing.attachment.height.should == 1584
|
103
|
-
end
|
104
|
-
|
105
|
-
it "should return the height of the given style" do
|
106
|
-
@thing.attachment.height(:original).should == 792
|
107
|
-
@thing.attachment.height(:double).should == 1584
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "#aspect_ratio" do
|
112
|
-
it "should return the aspect ratio of the default style if no style name is given" do
|
113
|
-
@thing.attachment.aspect_ratio.should be_close(612.0/792, 1e-5)
|
114
26
|
end
|
115
27
|
|
116
|
-
|
117
|
-
|
118
|
-
@thing.attachment.aspect_ratio(:filled).should be_close(1, 1e-5)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
describe "storable attributes" do
|
123
|
-
it "should set the stored attributes on assignment" do
|
124
|
-
@thing.attachment_width.should == 612
|
125
|
-
@thing.attachment_height.should == 792
|
126
|
-
@thing.attachment_aspect_ratio.should be_close(612.0/792, 1e-5)
|
127
|
-
@thing.attachment_dimensions.should == '612x792'
|
128
|
-
end
|
129
|
-
|
130
|
-
describe "after roundtripping through the database" do
|
131
|
-
before do
|
132
|
-
@thing.save
|
133
|
-
@thing = Thing.find(@thing.id)
|
134
|
-
end
|
135
|
-
|
136
|
-
it "should restore the stored attributes" do
|
137
|
-
@thing.attachment_width.should == 612
|
138
|
-
@thing.attachment_height.should == 792
|
139
|
-
@thing.attachment_aspect_ratio.should be_close(612.0/792, 1e-5)
|
140
|
-
@thing.attachment_dimensions.should == '612x792'
|
141
|
-
end
|
142
|
-
|
143
|
-
it "should recalculate the dimensions correctly" do
|
144
|
-
@thing.attachment.dimensions(:filled).should == [500, 500]
|
145
|
-
@thing.attachment.dimensions(:unfilled).should == [773, 1000]
|
146
|
-
end
|
147
|
-
end
|
28
|
+
@thing.attachment.process(:event)
|
29
|
+
context.should be_a(Processor::ImageMagick)
|
148
30
|
end
|
149
31
|
end
|
150
32
|
end
|
@@ -1,212 +1,140 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Attachment::Video do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
:video_duration => :string)
|
11
|
-
|
12
|
-
before do
|
13
|
-
Thing.has_attachment :video do
|
14
|
-
# original video is 640x480.
|
15
|
-
style :half, :size => '320x240'
|
16
|
-
style :filled, :size => '60x60', :filled => true
|
17
|
-
style :unfilled, :size => '120x120'
|
18
|
-
default_style :half
|
19
|
-
end
|
20
|
-
@thing = Thing.new(:video => test_file)
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_file
|
24
|
-
path = "#{temporary_directory}/test.mov"
|
25
|
-
FileUtils.cp("#{ROOT}/spec/data/test.mov", path)
|
26
|
-
autoclose open(path)
|
27
|
-
end
|
28
|
-
|
29
|
-
def run(command)
|
30
|
-
`#{command}`
|
31
|
-
$?.success? or
|
32
|
-
raise "command failed: #{command}"
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "#dimensions" do
|
36
|
-
it "should return 2x2 if the style is missing" do
|
37
|
-
Thing.attachment_reflections[:video].configure do
|
38
|
-
detect_type_by{:video}
|
39
|
-
end
|
40
|
-
@thing.save.should be_true
|
41
|
-
File.unlink(@thing.video.path(:original))
|
42
|
-
@thing = Thing.find(@thing.id)
|
43
|
-
@thing.video.is_a?(Attachment::Video) # sanity check
|
44
|
-
@thing.video.stream.missing? # sanity check
|
45
|
-
@thing.video.dimensions(:original).should == [2, 2]
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should return the width and height of the default style if no style name is given" do
|
49
|
-
@thing.video.dimensions.should == [320, 240]
|
50
|
-
end
|
4
|
+
it_should_behave_like_an_attachment_with_dimensions(
|
5
|
+
:type => :video,
|
6
|
+
:missing_dimensions => [2, 2],
|
7
|
+
:file_40x30 => 'test-40x30x1.mov',
|
8
|
+
:file_20x10 => 'test-20x10x1.mov'
|
9
|
+
)
|
51
10
|
|
52
|
-
|
53
|
-
|
54
|
-
@thing.video.dimensions(:half).should == [320, 240]
|
55
|
-
end
|
11
|
+
describe "when instantiated" do
|
12
|
+
use_model_class(:Thing, :attachment_file_name => :string)
|
56
13
|
|
57
|
-
|
58
|
-
|
59
|
-
|
14
|
+
before do
|
15
|
+
Thing.has_attachment :attachment do
|
16
|
+
style :double, :size => '80x60'
|
17
|
+
style :filled, :size => '60x60', :filled => true
|
18
|
+
style :unfilled, :size => '120x120'
|
19
|
+
default_style :double
|
20
|
+
end
|
21
|
+
@thing = Thing.new(:attachment => uploaded_file('test-40x30x1.mov'))
|
60
22
|
end
|
61
23
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
24
|
+
describe "#dimensions" do
|
25
|
+
it "should round calculated dimensions down to the nearest multiple of 2" do
|
26
|
+
Thing.has_attachment :attachment do
|
27
|
+
style :odd, :size => '59x59', :filled => true
|
28
|
+
end
|
29
|
+
@thing.attachment.dimensions(:odd).should == [58, 58]
|
30
|
+
end
|
66
31
|
end
|
67
32
|
|
68
|
-
|
69
|
-
|
70
|
-
|
33
|
+
describe "#duration" do
|
34
|
+
it "should return the duration of the given style" do
|
35
|
+
@thing.attachment.duration(:original).should == 1.second
|
36
|
+
# TODO: Add video slicing, and make duration return the correct duration.
|
37
|
+
@thing.attachment.duration(:double).should == 1.second
|
38
|
+
end
|
71
39
|
|
72
|
-
|
73
|
-
it "should return the width of the default style if no style name is given" do
|
74
|
-
@thing.video.width.should == 320
|
40
|
+
it "should use the default style if no style is given"
|
75
41
|
end
|
76
42
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
43
|
+
describe "#video_tracks" do
|
44
|
+
it "should return the video tracks of the given style" do
|
45
|
+
@thing.attachment.video_tracks(:original).should have(1).video_track
|
46
|
+
@thing.attachment.video_tracks(:original).first.dimensions.should == [40, 30]
|
47
|
+
end
|
82
48
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
49
|
+
it "should take into account filledness of the style" do
|
50
|
+
@thing.attachment.video_tracks(:original).should have(1).video_track
|
51
|
+
@thing.attachment.video_tracks(:original).first.dimensions.should == [40, 30]
|
52
|
+
end
|
87
53
|
|
88
|
-
|
89
|
-
|
90
|
-
|
54
|
+
it "should use the default style if no style is given" do
|
55
|
+
@thing.attachment.video_tracks.should have(1).video_track
|
56
|
+
@thing.attachment.video_tracks.first.dimensions.should == [80, 60]
|
57
|
+
end
|
91
58
|
end
|
92
|
-
end
|
93
59
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
60
|
+
describe "#audio_tracks" do
|
61
|
+
it "should return the audio tracks of the given style" do
|
62
|
+
@thing.attachment.audio_tracks(:original).should have(1).audio_track
|
63
|
+
@thing.attachment.audio_tracks(:original).first.duration.should == 1
|
64
|
+
end
|
98
65
|
|
99
|
-
|
100
|
-
|
101
|
-
|
66
|
+
it "should use the default style if no style is given" do
|
67
|
+
@thing.attachment.audio_tracks.should have(1).audio_track
|
68
|
+
@thing.attachment.audio_tracks.first.duration.should == 1
|
69
|
+
end
|
102
70
|
end
|
103
71
|
end
|
104
72
|
|
105
|
-
describe "
|
106
|
-
|
107
|
-
@thing.video.duration.should == 1.second
|
108
|
-
end
|
73
|
+
describe "when the duration is stored" do
|
74
|
+
use_model_class(:Thing, :attachment_file_name => :string, :attachment_duration => :integer)
|
109
75
|
|
110
|
-
|
111
|
-
|
76
|
+
before do
|
77
|
+
Thing.has_attachment :attachment do
|
78
|
+
type :video
|
79
|
+
style :double, :size => '80x60'
|
80
|
+
end
|
112
81
|
end
|
113
82
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
it "should return the video tracks of the original style if no style name is given" do
|
121
|
-
@thing.video.video_tracks.should have(1).video_track
|
122
|
-
@thing.video.video_tracks.first.dimensions.should == [320, 240]
|
123
|
-
end
|
83
|
+
describe "when the stored values are hacked, and the record reinstantiated" do
|
84
|
+
before do
|
85
|
+
@thing = Thing.create!(:attachment => uploaded_file('test-40x30x1.mov'))
|
86
|
+
Thing.update_all({:attachment_duration => 2}, {:id => @thing.id})
|
87
|
+
@thing = Thing.find(@thing.id)
|
88
|
+
end
|
124
89
|
|
125
|
-
|
126
|
-
|
127
|
-
|
90
|
+
it "should use the stored duration for the original" do
|
91
|
+
@thing.attachment.duration(:original).should == 2
|
92
|
+
end
|
128
93
|
|
129
|
-
|
130
|
-
|
94
|
+
it "should calculate the duration of other styles from that of the original" do
|
95
|
+
@thing.attachment.duration(:double).should == 2
|
96
|
+
end
|
131
97
|
end
|
132
98
|
end
|
133
99
|
|
134
|
-
describe "
|
135
|
-
|
136
|
-
@thing.video.video_tracks.should have(1).video_track
|
137
|
-
@thing.video.video_tracks.first.dimensions.should == [320, 240]
|
138
|
-
end
|
139
|
-
|
140
|
-
it "should return the audio tracks of the target style if a style name is given" do
|
141
|
-
@thing.video.video_tracks(:original).should have(1).video_track
|
142
|
-
@thing.video.video_tracks(:original).first.dimensions.should == [640, 480]
|
143
|
-
|
144
|
-
@thing.video.video_tracks(:filled).should have(1).video_track
|
145
|
-
@thing.video.video_tracks(:filled).first.dimensions.should == [60, 60]
|
146
|
-
end
|
147
|
-
end
|
100
|
+
describe "when the duration is not stored" do
|
101
|
+
use_model_class(:Thing, :attachment_file_name => :string)
|
148
102
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
@thing.video_dimensions.should == '640x480'
|
103
|
+
before do
|
104
|
+
Thing.has_attachment :attachment do
|
105
|
+
type :video
|
106
|
+
style :double, :size => '80x60'
|
107
|
+
end
|
155
108
|
end
|
156
109
|
|
157
|
-
describe "
|
110
|
+
describe "when the file is missing" do
|
158
111
|
before do
|
159
|
-
@thing.
|
112
|
+
@thing = Thing.create!(:attachment => uploaded_file('test-40x30x1.mov'))
|
113
|
+
File.unlink(@thing.attachment.path(:original))
|
160
114
|
@thing = Thing.find(@thing.id)
|
161
115
|
end
|
162
116
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
@thing.video_dimensions.should == '640x480'
|
168
|
-
end
|
117
|
+
describe "#duration" do
|
118
|
+
it "should return 0 for the original style" do
|
119
|
+
@thing.attachment.duration(:original).should == 0
|
120
|
+
end
|
169
121
|
|
170
|
-
|
171
|
-
|
172
|
-
|
122
|
+
it "should calculate the duration of other styles from that of the original" do
|
123
|
+
@thing.attachment.duration(:double).should == 0
|
124
|
+
end
|
173
125
|
end
|
174
|
-
end
|
175
|
-
end
|
176
126
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
127
|
+
describe "#video_tracks" do
|
128
|
+
it "should return no video tracks" do
|
129
|
+
@thing.attachment.video_tracks.should have(0).video_tracks
|
130
|
+
end
|
131
|
+
end
|
204
132
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
133
|
+
describe "#audio_tracks" do
|
134
|
+
it "should return no audio tracks" do
|
135
|
+
@thing.attachment.audio_tracks.should have(0).audio_tracks
|
136
|
+
end
|
137
|
+
end
|
210
138
|
end
|
211
139
|
end
|
212
140
|
end
|