asset_cloud 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +13 -0
- data/Rakefile +24 -0
- data/asset_cloud.gemspec +24 -0
- data/lib/asset_cloud.rb +54 -0
- data/lib/asset_cloud/asset.rb +187 -0
- data/lib/asset_cloud/asset_extension.rb +42 -0
- data/lib/asset_cloud/base.rb +247 -0
- data/lib/asset_cloud/bucket.rb +39 -0
- data/lib/asset_cloud/buckets/active_record_bucket.rb +57 -0
- data/lib/asset_cloud/buckets/blackhole_bucket.rb +23 -0
- data/lib/asset_cloud/buckets/bucket_chain.rb +84 -0
- data/lib/asset_cloud/buckets/file_system_bucket.rb +79 -0
- data/lib/asset_cloud/buckets/invalid_bucket.rb +28 -0
- data/lib/asset_cloud/buckets/memory_bucket.rb +42 -0
- data/lib/asset_cloud/buckets/versioned_memory_bucket.rb +33 -0
- data/lib/asset_cloud/callbacks.rb +63 -0
- data/lib/asset_cloud/free_key_locator.rb +28 -0
- data/lib/asset_cloud/metadata.rb +29 -0
- data/lib/asset_cloud/validations.rb +52 -0
- data/spec/active_record_bucket_spec.rb +95 -0
- data/spec/asset_extension_spec.rb +103 -0
- data/spec/asset_spec.rb +177 -0
- data/spec/base_spec.rb +114 -0
- data/spec/blackhole_bucket_spec.rb +41 -0
- data/spec/bucket_chain_spec.rb +158 -0
- data/spec/callbacks_spec.rb +125 -0
- data/spec/file_system_spec.rb +74 -0
- data/spec/files/products/key.txt +1 -0
- data/spec/files/versioned_stuff/foo +1 -0
- data/spec/find_free_key_spec.rb +39 -0
- data/spec/memory_bucket_spec.rb +52 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/validations_spec.rb +53 -0
- data/spec/versioned_memory_bucket_spec.rb +36 -0
- metadata +151 -0
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class SpecialAsset < AssetCloud::Asset
|
4
|
+
end
|
5
|
+
|
6
|
+
class BasicCloud < AssetCloud::Base
|
7
|
+
bucket :special, AssetCloud::MemoryBucket, :asset_class => SpecialAsset
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
describe BasicCloud do
|
12
|
+
directory = File.dirname(__FILE__) + '/files'
|
13
|
+
|
14
|
+
before do
|
15
|
+
@fs = BasicCloud.new(directory , 'http://assets/files' )
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should raise invalid bucket if none is given" do
|
19
|
+
@fs['image.jpg'].exist?.should == false
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
it "should be backed by a file system bucket" do
|
24
|
+
@fs['products/key.txt'].exist?.should == true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should raise when listing non existing buckets" do
|
28
|
+
@fs.ls('products').should == [AssetCloud::Asset.new(@fs, 'products/key.txt')]
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
it "should allow you to create new assets" do
|
33
|
+
obj = @fs.build('new_file.test')
|
34
|
+
obj.should be_an_instance_of(AssetCloud::Asset)
|
35
|
+
obj.cloud.should be_an_instance_of(BasicCloud)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should raise error when using with minus relative or absolute paths" do
|
39
|
+
lambda { @fs['../test'] }.should raise_error(AssetCloud::IllegalPath)
|
40
|
+
lambda { @fs['/test'] }.should raise_error(AssetCloud::IllegalPath)
|
41
|
+
lambda { @fs['.../test'] }.should raise_error(AssetCloud::IllegalPath)
|
42
|
+
lambda { @fs['./test'] }.should raise_error(AssetCloud::IllegalPath)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should allow sensible relative filenames" do
|
46
|
+
@fs['assets/rails_logo.gif']
|
47
|
+
@fs['assets/rails-2.gif']
|
48
|
+
@fs['assets/223434.gif']
|
49
|
+
@fs['files/1.JPG']
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should compute complete urls to assets" do
|
53
|
+
@fs.url_for('products/key with spaces.txt').should == 'http://assets/files/products/key%20with%20spaces.txt'
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#find" do
|
57
|
+
it "should return the appropriate asset when one exists" do
|
58
|
+
asset = @fs.find('products/key.txt')
|
59
|
+
asset.key.should == 'products/key.txt'
|
60
|
+
asset.value.should == 'value'
|
61
|
+
end
|
62
|
+
it "should raise AssetNotFoundError when the asset doesn't exist" do
|
63
|
+
lambda { @fs.find('products/not-there.txt') }.should raise_error(AssetCloud::AssetNotFoundError)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#[]" do
|
68
|
+
it "should return the appropriate asset when one exists" do
|
69
|
+
asset = @fs['products/key.txt']
|
70
|
+
asset.key.should == 'products/key.txt'
|
71
|
+
asset.value.should == 'value'
|
72
|
+
end
|
73
|
+
it "should not raise any errors when the asset doesn't exist" do
|
74
|
+
lambda { @fs['products/not-there.txt'] }.should_not raise_error
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#[]=" do
|
79
|
+
it "should write through the Asset object (and thus run any callbacks on the asset)" do
|
80
|
+
special_asset = double(:special_asset)
|
81
|
+
special_asset.should_receive(:value=).with('fancy fancy!')
|
82
|
+
special_asset.should_receive(:store)
|
83
|
+
SpecialAsset.should_receive(:at).and_return(special_asset)
|
84
|
+
@fs['special/fancy.txt'] = 'fancy fancy!'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "#bucket" do
|
89
|
+
it "should allow specifying a class to use for assets in this bucket" do
|
90
|
+
@fs['assets/rails_logo.gif'].should be_instance_of(AssetCloud::Asset)
|
91
|
+
@fs['special/fancy.txt'].should be_instance_of(SpecialAsset)
|
92
|
+
|
93
|
+
@fs.build('assets/foo').should be_instance_of(AssetCloud::Asset)
|
94
|
+
@fs.build('special/foo').should be_instance_of(SpecialAsset)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "MATCH_BUCKET" do
|
99
|
+
it "should match following stuff " do
|
100
|
+
|
101
|
+
'products/key.txt' =~ AssetCloud::Base::MATCH_BUCKET
|
102
|
+
$1.should == 'products'
|
103
|
+
|
104
|
+
'products/subpath/key.txt' =~ AssetCloud::Base::MATCH_BUCKET
|
105
|
+
$1.should == 'products'
|
106
|
+
|
107
|
+
'key.txt' =~ AssetCloud::Base::MATCH_BUCKET
|
108
|
+
$1.should == nil
|
109
|
+
|
110
|
+
'products' =~ AssetCloud::Base::MATCH_BUCKET
|
111
|
+
$1.should == 'products'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class BlackholeCloud < AssetCloud::Base
|
4
|
+
bucket AssetCloud::BlackholeBucket
|
5
|
+
end
|
6
|
+
|
7
|
+
describe BlackholeCloud do
|
8
|
+
directory = File.dirname(__FILE__) + '/files'
|
9
|
+
|
10
|
+
before do
|
11
|
+
@fs = BlackholeCloud.new(directory , 'http://assets/files' )
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should allow access to files using the [] operator" do
|
15
|
+
@fs['tmp/image.jpg']
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return nil for non existent files" do
|
19
|
+
@fs['tmp/image.jpg'].exist?.should == false
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should still return nil, even if you wrote something there" do
|
23
|
+
@fs['tmp/image.jpg'] = 'test'
|
24
|
+
@fs['tmp/image.jpg'].exist?.should == false
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "when using a sub path" do
|
28
|
+
it "should allow access to files using the [] operator" do
|
29
|
+
@fs['tmp/image.jpg']
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return nil for non existent files" do
|
33
|
+
@fs['tmp/image.jpg'].exist?.should == false
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should still return nil, even if you wrote something there" do
|
37
|
+
@fs['tmp/image.jpg'] = 'test'
|
38
|
+
@fs['tmp/image.jpg'].exist?.should == false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class ChainedCloud < AssetCloud::Base
|
4
|
+
bucket :stuff, AssetCloud::BucketChain.chain( AssetCloud::MemoryBucket,
|
5
|
+
AssetCloud::MemoryBucket,
|
6
|
+
AssetCloud::FileSystemBucket )
|
7
|
+
|
8
|
+
bucket :versioned_stuff, AssetCloud::BucketChain.chain( AssetCloud::FileSystemBucket,
|
9
|
+
AssetCloud::VersionedMemoryBucket,
|
10
|
+
AssetCloud::MemoryBucket )
|
11
|
+
end
|
12
|
+
|
13
|
+
describe AssetCloud::BucketChain do
|
14
|
+
directory = File.dirname(__FILE__) + '/files'
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
@cloud = ChainedCloud.new(directory , 'http://assets/files' )
|
18
|
+
@bucket_chain = @cloud.buckets[:stuff]
|
19
|
+
@chained_buckets = @bucket_chain.chained_buckets
|
20
|
+
@chained_buckets.each {|b| b.ls('stuff').each {|asset| asset.delete}}
|
21
|
+
|
22
|
+
@versioned_stuff = @cloud.buckets[:versioned_stuff]
|
23
|
+
end
|
24
|
+
|
25
|
+
describe ".chain" do
|
26
|
+
it 'should take multiple Bucket classes and return a new Bucket class' do
|
27
|
+
@bucket_chain.should be_a_kind_of(AssetCloud::BucketChain)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#write" do
|
32
|
+
it 'should write to each sub-bucket when everything is kosher and return the result of the first write' do
|
33
|
+
@chained_buckets.each do |bucket|
|
34
|
+
bucket.should_receive(:write).with('stuff/foo', 'successful creation').and_return('successful creation')
|
35
|
+
end
|
36
|
+
|
37
|
+
@bucket_chain.write('stuff/foo', 'successful creation').should == 'successful creation'
|
38
|
+
end
|
39
|
+
it 'should roll back creation-writes and re-raise an error when a bucket raises one' do
|
40
|
+
@chained_buckets.last.should_receive(:write).with('stuff/foo', 'unsuccessful creation').and_raise('hell')
|
41
|
+
@chained_buckets[0..-2].each do |bucket|
|
42
|
+
bucket.should_receive(:write).with('stuff/foo', 'unsuccessful creation').and_return(true)
|
43
|
+
bucket.should_receive(:delete).with('stuff/foo').and_return(true)
|
44
|
+
end
|
45
|
+
|
46
|
+
lambda { @bucket_chain.write('stuff/foo', 'unsuccessful creation') }.should raise_error(RuntimeError)
|
47
|
+
end
|
48
|
+
it 'should roll back update-writes and re-raise an error when a bucket raises one' do
|
49
|
+
@bucket_chain.write('stuff/foo', "original value")
|
50
|
+
|
51
|
+
@chained_buckets.last.should_receive(:write).with('stuff/foo', 'new value').and_raise('hell')
|
52
|
+
|
53
|
+
lambda { @bucket_chain.write('stuff/foo', 'new value') }.should raise_error(RuntimeError)
|
54
|
+
@chained_buckets.each do |bucket|
|
55
|
+
bucket.read('stuff/foo').should == 'original value'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#delete" do
|
61
|
+
it 'should delete from each sub-bucket when everything is kosher' do
|
62
|
+
@bucket_chain.write('stuff/foo', "successful deletion comin' up")
|
63
|
+
|
64
|
+
@chained_buckets.each do |bucket|
|
65
|
+
bucket.should_receive(:delete).with('stuff/foo').and_return(true)
|
66
|
+
end
|
67
|
+
|
68
|
+
@bucket_chain.delete('stuff/foo')
|
69
|
+
end
|
70
|
+
it 'should roll back deletions and re-raise an error when a bucket raises one' do
|
71
|
+
@bucket_chain.write('stuff/foo', "this deletion will fail")
|
72
|
+
|
73
|
+
@chained_buckets.last.should_receive(:delete).with('stuff/foo').and_raise('hell')
|
74
|
+
@chained_buckets[0..-2].each do |bucket|
|
75
|
+
bucket.should_receive(:delete).with('stuff/foo').and_return(true)
|
76
|
+
bucket.should_receive(:write).with('stuff/foo', 'this deletion will fail').and_return(true)
|
77
|
+
end
|
78
|
+
|
79
|
+
lambda { @bucket_chain.delete('stuff/foo') }.should raise_error(RuntimeError)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#read" do
|
84
|
+
it 'should read from only the first available sub-bucket' do
|
85
|
+
@chained_buckets[0].should_receive(:read).with('stuff/foo').and_raise(NotImplementedError)
|
86
|
+
@chained_buckets[0].should_receive(:ls).with(nil).and_raise(NoMethodError)
|
87
|
+
@chained_buckets[0].should_receive(:stat).and_return(:metadata)
|
88
|
+
|
89
|
+
@chained_buckets[1].should_receive(:read).with('stuff/foo').and_return('bar')
|
90
|
+
@chained_buckets[1].should_receive(:ls).with(nil).and_return(:some_assets)
|
91
|
+
@chained_buckets[1].should_not_receive(:stat)
|
92
|
+
|
93
|
+
@chained_buckets[2..-1].each do |bucket|
|
94
|
+
bucket.should_not_receive(:read)
|
95
|
+
bucket.should_not_receive(:ls)
|
96
|
+
bucket.should_not_receive(:stat)
|
97
|
+
end
|
98
|
+
|
99
|
+
@bucket_chain.read('stuff/foo').should == 'bar'
|
100
|
+
@bucket_chain.ls.should == :some_assets
|
101
|
+
@bucket_chain.stat.should == :metadata
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
describe "#read_version" do
|
107
|
+
it 'should read from only the first available sub-bucket' do
|
108
|
+
buckets = @versioned_stuff.chained_buckets
|
109
|
+
|
110
|
+
buckets[1].should_receive(:read_version).with('stuff/foo',3).and_return('bar')
|
111
|
+
buckets.last.should_not_receive(:read_version)
|
112
|
+
|
113
|
+
@versioned_stuff.read_version('stuff/foo', 3).should == 'bar'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "#versions" do
|
118
|
+
it 'should read from only the first available sub-bucket' do
|
119
|
+
buckets = @versioned_stuff.chained_buckets
|
120
|
+
|
121
|
+
buckets[1].should_receive(:versions).with('versioned_stuff/foo').and_return([1,2,3])
|
122
|
+
buckets.last.should_not_receive(:versions)
|
123
|
+
|
124
|
+
@versioned_stuff.versions('versioned_stuff/foo').should == [1,2,3]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "with versioned buckets" do
|
129
|
+
it 'should store and retrieve versions seamlessly' do
|
130
|
+
%w{one two three}.each do |content|
|
131
|
+
@cloud['versioned_stuff/foo'] = content
|
132
|
+
end
|
133
|
+
asset = @cloud['versioned_stuff/foo']
|
134
|
+
asset.value.should == 'three'
|
135
|
+
asset.rollback(1).value.should == 'one'
|
136
|
+
asset.versions.should == [1,2,3]
|
137
|
+
asset.value = 'four'
|
138
|
+
asset.store
|
139
|
+
asset.versions.should == [1,2,3,4]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '#respond_to?' do
|
144
|
+
it 'should return true if any chained buckets respond to the given method' do
|
145
|
+
@bucket_chain.respond_to?(:foo).should == false
|
146
|
+
@chained_buckets[1].should_receive(:respond_to?).with(:bar).and_return(true)
|
147
|
+
@bucket_chain.respond_to?(:bar).should == true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#method_missing' do
|
152
|
+
it 'should try each bucket' do
|
153
|
+
@chained_buckets[1].should_receive(:buzz).and_return(true)
|
154
|
+
@chained_buckets[2].should_not_receive(:buzz)
|
155
|
+
@bucket_chain.buzz.should == true
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class CallbackAsset < AssetCloud::Asset
|
4
|
+
before_store :callback_before_store
|
5
|
+
after_delete :callback_after_delete
|
6
|
+
before_validate :make_value_valid
|
7
|
+
after_validate :add_spice
|
8
|
+
validate :valid_value
|
9
|
+
|
10
|
+
private
|
11
|
+
def make_value_valid
|
12
|
+
self.value = 'valid'
|
13
|
+
end
|
14
|
+
def add_spice
|
15
|
+
self.value += ' spice'
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid_value
|
19
|
+
add_error 'value is not "valid"' unless value == 'valid'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class BasicCloud < AssetCloud::Base
|
24
|
+
bucket :callback_assets, AssetCloud::MemoryBucket, :asset_class => CallbackAsset
|
25
|
+
end
|
26
|
+
|
27
|
+
class CallbackCloud < AssetCloud::Base
|
28
|
+
bucket :tmp, AssetCloud::MemoryBucket
|
29
|
+
|
30
|
+
after_delete :callback_after_delete
|
31
|
+
before_delete :callback_before_delete
|
32
|
+
|
33
|
+
after_write :callback_after_write
|
34
|
+
before_write :callback_before_write
|
35
|
+
end
|
36
|
+
|
37
|
+
class MethodRecordingCloud < AssetCloud::Base
|
38
|
+
attr_accessor :run_callbacks
|
39
|
+
|
40
|
+
bucket :tmp, AssetCloud::MemoryBucket
|
41
|
+
|
42
|
+
before_write :callback_before_write
|
43
|
+
after_write :callback_before_write
|
44
|
+
|
45
|
+
|
46
|
+
def method_missing(method, *args)
|
47
|
+
@run_callbacks << method.to_sym
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe CallbackCloud do
|
52
|
+
before { @fs = CallbackCloud.new(File.dirname(__FILE__) + '/files', 'http://assets/') }
|
53
|
+
|
54
|
+
it "should invoke callbacks after store" do
|
55
|
+
|
56
|
+
@fs.should_receive(:callback_before_write).with('tmp/file.txt', 'text').and_return(true)
|
57
|
+
@fs.should_receive(:callback_after_write).with('tmp/file.txt', 'text').and_return(true)
|
58
|
+
|
59
|
+
|
60
|
+
@fs.write 'tmp/file.txt', 'text'
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should invoke callbacks after delete" do
|
65
|
+
|
66
|
+
@fs.should_receive(:callback_before_delete).with('tmp/file.txt').and_return(true)
|
67
|
+
@fs.should_receive(:callback_after_delete).with('tmp/file.txt').and_return(true)
|
68
|
+
|
69
|
+
|
70
|
+
@fs.delete 'tmp/file.txt'
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should invoke callbacks even when constructing a new asset" do
|
74
|
+
@fs.should_receive(:callback_before_write).with('tmp/file.txt', 'hello').and_return(true)
|
75
|
+
@fs.should_receive(:callback_after_write).with('tmp/file.txt', 'hello').and_return(true)
|
76
|
+
|
77
|
+
|
78
|
+
asset = @fs.build('tmp/file.txt')
|
79
|
+
asset.value = 'hello'
|
80
|
+
asset.store
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
describe MethodRecordingCloud do
|
87
|
+
before do
|
88
|
+
@fs = MethodRecordingCloud.new(File.dirname(__FILE__) + '/files', 'http://assets/')
|
89
|
+
@fs.run_callbacks = []
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should record event when invoked' do
|
93
|
+
@fs.write('tmp/file.txt', 'random data')
|
94
|
+
@fs.run_callbacks.should == [:callback_before_write, :callback_before_write]
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should record event when assignment operator is used' do
|
98
|
+
@fs['tmp/file.txt'] = 'random data'
|
99
|
+
@fs.run_callbacks.should == [:callback_before_write, :callback_before_write]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe CallbackAsset do
|
104
|
+
before(:each) do
|
105
|
+
@fs = BasicCloud.new(File.dirname(__FILE__) + '/files', 'http://assets/')
|
106
|
+
@fs.write('callback_assets/foo', 'bar')
|
107
|
+
@asset = @fs.asset_at('callback_assets/foo')
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should run before_validate, then validate, then after validate, then before_store, then store" do
|
111
|
+
@asset.should_receive(:callback_before_store).and_return(true)
|
112
|
+
@asset.should_not_receive(:callback_after_delete)
|
113
|
+
|
114
|
+
@asset.value = 'foo'
|
115
|
+
@asset.store.should == true
|
116
|
+
@asset.value.should == 'valid spice'
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should run its after_delete callback after delete is called" do
|
120
|
+
@asset.should_not_receive(:callback_before_store)
|
121
|
+
@asset.should_receive(:callback_after_delete).and_return(true)
|
122
|
+
|
123
|
+
@asset.delete
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class FileSystemCloud < AssetCloud::Base
|
5
|
+
bucket AssetCloud::InvalidBucket
|
6
|
+
bucket :products, AssetCloud::FileSystemBucket
|
7
|
+
bucket :tmp, AssetCloud::FileSystemBucket
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
describe FileSystemCloud do
|
12
|
+
directory = File.dirname(__FILE__) + '/files'
|
13
|
+
|
14
|
+
before do
|
15
|
+
@fs = FileSystemCloud.new(directory , 'http://assets/files' )
|
16
|
+
FileUtils.mkdir_p(directory + '/tmp')
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
FileUtils.rm_rf(directory + '/tmp')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should use invalid bucket for random directories" do
|
24
|
+
@fs.bucket_for('does-not-exist/file.txt').should be_an_instance_of(AssetCloud::InvalidBucket)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should use filesystem bucekt for products/ and tmp/ directories" do
|
28
|
+
@fs.bucket_for('products/file.txt').should be_an_instance_of(AssetCloud::FileSystemBucket)
|
29
|
+
@fs.bucket_for('tmp/file.txt').should be_an_instance_of(AssetCloud::FileSystemBucket)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return Asset for existing files" do
|
33
|
+
@fs['products/key.txt'].exist?.should == true
|
34
|
+
@fs['products/key.txt'].should be_an_instance_of(AssetCloud::Asset)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should be able to test if a file exists or not" do
|
38
|
+
@fs.stat('products/key.txt').exist?.should == true
|
39
|
+
@fs.stat('products/key2.txt').exist?.should == false
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should be able to list files" do
|
43
|
+
@fs.ls('products').collect(&:key).should == ['products/key.txt']
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'when modifying file system' do
|
47
|
+
|
48
|
+
it "should call write after storing an asset" do
|
49
|
+
@fs.buckets[:tmp].should_receive(:write).with('tmp/new_file.test', 'hello world').and_return(true)
|
50
|
+
|
51
|
+
@fs.build('tmp/new_file.test', 'hello world').store
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should be able to create new files" do
|
55
|
+
@fs.build('tmp/new_file.test', 'hello world').store
|
56
|
+
|
57
|
+
@fs.stat('tmp/new_file.test').exist.should == true
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should be able to create new files with simple assignment" do
|
61
|
+
@fs['tmp/new_file.test'] = 'hello world'
|
62
|
+
|
63
|
+
@fs.stat('tmp/new_file.test').exist.should == true
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should create directories as needed" do
|
67
|
+
@fs.build('tmp/new_file.test', 'hello world').store
|
68
|
+
|
69
|
+
@fs['tmp/new_file.test'].exist?.should == true
|
70
|
+
@fs['tmp/new_file.test'].value.should == 'hello world'
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|