remote_files 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/remote_files.rb CHANGED
@@ -63,6 +63,13 @@ module RemoteFiles
63
63
  true
64
64
  end
65
65
 
66
+ def self.delete!(file)
67
+ file.stored_in.each do |store_identifier|
68
+ store = lookup_store(store_identifier)
69
+ store.delete!(file.identifier)
70
+ end
71
+ end
72
+
66
73
  def self.synchronize!(file)
67
74
  file.missing_stores.each do |store_identifier|
68
75
  store = lookup_store(store_identifier)
@@ -6,6 +6,14 @@ module RemoteFiles
6
6
  @identifier = identifier
7
7
  end
8
8
 
9
+ def options
10
+ @options ||= {}
11
+ end
12
+
13
+ def []=(name, value)
14
+ options[name] = value
15
+ end
16
+
9
17
  def store!(file)
10
18
  raise "You need to implement #{self.class.name}#store!"
11
19
  end
@@ -14,8 +22,26 @@ module RemoteFiles
14
22
  raise "You need to implement #{self.class.name}#retrieve!"
15
23
  end
16
24
 
25
+ def delete!(identifier)
26
+ raise "You need to implement #{self.class.name}#delete!"
27
+ end
28
+
17
29
  def url(identifier)
18
30
  raise "You need to implement #{self.class.name}#url"
19
31
  end
32
+
33
+ def url_matcher
34
+ raise "You need to implement #{self.class.name}:#url_matcher"
35
+ end
36
+
37
+ def file_from_url(url)
38
+ matched = url_matcher.match(url)
39
+
40
+ return nil unless matched
41
+
42
+ file_identifier = matched[1]
43
+
44
+ RemoteFiles::File.new(file_identifier, :stored_in => [identifier])
45
+ end
20
46
  end
21
47
  end
@@ -10,6 +10,13 @@ module RemoteFiles
10
10
  @options = options
11
11
  end
12
12
 
13
+ def self.from_url(url)
14
+ RemoteFiles.stores.each do |store|
15
+ file = store.file_from_url(url)
16
+ return file if file
17
+ end
18
+ end
19
+
13
20
  def options
14
21
  @options.merge(
15
22
  :identifier => identifier,
@@ -55,5 +62,18 @@ module RemoteFiles
55
62
  def synchronize!
56
63
  RemoteFiles.synchronize!(self)
57
64
  end
65
+
66
+ def delete!
67
+ RemoteFiles.delete!(self)
68
+ end
69
+
70
+ def delete
71
+ begin
72
+ delete!
73
+ true
74
+ rescue RemoteFiles::Error => e
75
+ false
76
+ end
77
+ end
58
78
  end
59
79
  end
@@ -0,0 +1,47 @@
1
+ require 'pathname'
2
+
3
+ # This is good for use in deveopment
4
+
5
+ module RemoteFiles
6
+ class FileStore < AbstractStore
7
+
8
+ def directory
9
+ @directory ||= Pathname.new(options[:directory]).tap do |dir|
10
+ dir.mkdir unless dir.exist?
11
+ raise "#{dir} is not a directory" unless dir.directory?
12
+ end
13
+ end
14
+
15
+ def store!(file)
16
+ ::File.open(directory + file.identifier, 'w') do |f|
17
+ f.write(file.content)
18
+ # what about content-type?
19
+ end
20
+ end
21
+
22
+ def retrieve!(identifier)
23
+ content = File.new(directory + identifier).read
24
+
25
+ ::File.new(identifier,
26
+ :content => content,
27
+ :stored_in => [self.identifier]
28
+ # what about content-type? maybe use the mime-types gem?
29
+ )
30
+ rescue Errno::ENOENT => e
31
+ raise NotFoundError, e.message
32
+ end
33
+
34
+ def delete!(identifier)
35
+ ::File.delete(directory + identifier)
36
+ rescue Errno::ENOENT => e
37
+ end
38
+
39
+ def url(identifier)
40
+ "file://localhost/#{directory + identifier}"
41
+ end
42
+
43
+ def url_matcher
44
+ @url_matcher ||= /file:\/\/localhost\/#{directory}\/(.*)/
45
+ end
46
+ end
47
+ end
@@ -43,12 +43,19 @@ module RemoteFiles
43
43
  end
44
44
  end
45
45
 
46
- def options
47
- @options ||= {}
46
+ def url_matcher
47
+ @url_matcher ||= case options[:provider]
48
+ when 'AWS'
49
+ /https?:\/\/s3[^\.]*.amazonaws.com\/#{options[:directory]}\/(.*)/
50
+ when 'Rackspace'
51
+ /https?:\/\/storage.cloudfiles.com\/#{options[:directory]}\/(.*)/
52
+ else
53
+ raise "#{self.class.name}#url_matcher was not implemented for the #{options[:provider]} provider"
54
+ end
48
55
  end
49
56
 
50
- def []=(name, value)
51
- options[name] = value
57
+ def delete!(identifier)
58
+ connection.delete_object(directory.key, identifier)
52
59
  end
53
60
 
54
61
  def connection
@@ -0,0 +1,46 @@
1
+ # This is good for use in tests.
2
+ # Be sure to call #clear! before each test run.
3
+
4
+ module RemoteFiles
5
+ class MemoryStore < AbstractStore
6
+ def data
7
+ @data ||= {}
8
+ end
9
+
10
+ def clear!
11
+ data.clear
12
+ end
13
+
14
+ def self.clear!
15
+ RemoteFiles.stores.each do |store|
16
+ store.clear! if store.is_a?(RemoteFiles::MemoryStore)
17
+ end
18
+ end
19
+
20
+ def store!(file)
21
+ data[file.identifier] = { :content => file.content, :content_type => file.content_type}
22
+ end
23
+
24
+ def retrieve!(identifier)
25
+ raise NotFoundError, "#{identifier} not found in #{self.identifier} store" unless data.has_key?(identifier)
26
+
27
+ File.new(identifier,
28
+ :content => data[identifier][:content],
29
+ :content_type => data[identifier][:content_type],
30
+ :stored_in => [self.identifier]
31
+ )
32
+ end
33
+
34
+ def delete!(identifier)
35
+ data.delete(identifier)
36
+ end
37
+
38
+ def url(identifier)
39
+ "memory://#{self.identifier}/#{identifier}"
40
+ end
41
+
42
+ def url_matcher
43
+ @url_matcher ||= /memory:\/\/#{identifier}\/(.*)/
44
+ end
45
+ end
46
+ end
@@ -1,25 +1,5 @@
1
- module RemoteFiles
2
- class MockStore < AbstractStore
3
- def data
4
- @data ||= {}
5
- end
6
-
7
- def store!(file)
8
- data[file.identifier] = { :content => file.content, :content_type => file.content_type}
9
- end
10
-
11
- def retrieve!(identifier)
12
- raise NotFoundError, "#{identifier} not found in #{self.identifier} store" unless data.has_key?(identifier)
1
+ require 'remote_files/memory_store'
13
2
 
14
- File.new(identifier,
15
- :content => data[identifier][:content],
16
- :content_type => data[identifier][:content_type],
17
- :stored_in => [self.identifier]
18
- )
19
- end
20
-
21
- def url(identifier)
22
- "mock://#{self.identifier}/#{identifier}"
23
- end
24
- end
3
+ module RemoteFiles
4
+ MockStore = MemoryStore
25
5
  end
@@ -1,3 +1,3 @@
1
1
  module RemoteFiles
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
data/test/file_test.rb CHANGED
@@ -63,7 +63,7 @@ describe RemoteFiles::File do
63
63
  end
64
64
  end
65
65
 
66
- describe 'current_url' do
66
+ describe '#current_url' do
67
67
  it 'should return the url from the first store where the file is currently stored' do
68
68
  @s3.stubs(:url).returns('s3_url')
69
69
  @cf.stubs(:url).returns('cf_url')
@@ -80,5 +80,13 @@ describe RemoteFiles::File do
80
80
  @file.stored_in.replace([])
81
81
  @file.current_url.must_be_nil
82
82
  end
83
+
84
+ describe '::from_url' do
85
+ it 'should return a file from the first store that matches' do
86
+ url = 'http://something'
87
+ @cf.expects(:file_from_url).with(url).returns(@file)
88
+ assert_equal @file, RemoteFiles::File.from_url(url)
89
+ end
90
+ end
83
91
  end
84
92
  end
@@ -105,4 +105,65 @@ describe RemoteFiles::FogStore do
105
105
  end
106
106
  end
107
107
  end
108
+
109
+ describe '#file_from_url' do
110
+ describe 'for an S3 store' do
111
+ before { @store[:provider] = 'AWS' }
112
+
113
+ it 'should create a file if the bucket matches' do
114
+ file = @store.file_from_url('http://s3-eu-west-1.amazonaws.com/directory/key/on/s3.txt')
115
+ assert file
116
+ assert_equal 'key/on/s3.txt', file.identifier
117
+
118
+ file = @store.file_from_url('http://s3-eu-west-1.amazonaws.com/other_bucket/key/on/s3.txt')
119
+ assert !file
120
+
121
+ file = @store.file_from_url('http://storage.cloudfiles.com/directory/key/on/s3.txt')
122
+ assert !file
123
+ end
124
+ end
125
+
126
+ describe 'for a cloudfiles store' do
127
+ before { @store[:provider] = 'Rackspace' }
128
+
129
+ it 'should create a file if the container matches' do
130
+ file = @store.file_from_url('http://storage.cloudfiles.com/directory/key/on/s3.txt')
131
+ assert file
132
+ assert_equal 'key/on/s3.txt', file.identifier
133
+
134
+ file = @store.file_from_url('http://storage.cloudfiles.com/other_container/key/on/s3.txt')
135
+ assert !file
136
+
137
+ file = @store.file_from_url('http://s3-eu-west-1.amazonaws.com/directory/key/on/s3.txt')
138
+ assert !file
139
+ end
140
+ end
141
+
142
+ describe 'for other stores' do
143
+ before { @store[:provider] = 'Google' }
144
+
145
+ it 'should raise a RuntimeError' do
146
+ proc { @store.file_from_url('http://s3-eu-west-1.amazonaws.com/directory/key/on/s3.txt') }.must_raise(RuntimeError)
147
+ end
148
+ end
149
+ end
150
+
151
+ describe '#delete!' do
152
+ before do
153
+ @store.directory.files.create(
154
+ :body => 'content',
155
+ :content_type => 'text/plain',
156
+ :key => 'identifier',
157
+ )
158
+ end
159
+
160
+ it 'should destroy the file' do
161
+ assert @store.directory.files.get('identifier')
162
+
163
+ @store.delete!('identifier')
164
+
165
+ assert !@store.directory.files.get('identifier')
166
+ end
167
+ end
168
+
108
169
  end
@@ -146,6 +146,15 @@ describe RemoteFiles do
146
146
  end
147
147
  end
148
148
 
149
+ describe '::delete!' do
150
+ it 'should delete the file from all the stores' do
151
+ @file.stored_in.replace([:mock1, :mock2])
152
+ @mock_store1.expects(:delete!).with(@file.identifier)
153
+ @mock_store2.expects(:delete!).with(@file.identifier)
154
+ RemoteFiles.delete!(@file)
155
+ end
156
+ end
157
+
149
158
  describe '::synchronize!' do
150
159
  describe 'when the file is not stored anywhere' do
151
160
  before { @file.stored_in.replace([]) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remote_files
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-06 00:00:00.000000000 Z
12
+ date: 2012-09-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog
@@ -117,7 +117,9 @@ extra_rdoc_files: []
117
117
  files:
118
118
  - lib/remote_files/abstract_store.rb
119
119
  - lib/remote_files/file.rb
120
+ - lib/remote_files/file_store.rb
120
121
  - lib/remote_files/fog_store.rb
122
+ - lib/remote_files/memory_store.rb
121
123
  - lib/remote_files/mock_store.rb
122
124
  - lib/remote_files/resque_job.rb
123
125
  - lib/remote_files/version.rb
@@ -142,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
144
  version: '0'
143
145
  segments:
144
146
  - 0
145
- hash: -3554087706226059699
147
+ hash: -3981899794566552461
146
148
  required_rubygems_version: !ruby/object:Gem::Requirement
147
149
  none: false
148
150
  requirements:
@@ -151,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
153
  version: '0'
152
154
  segments:
153
155
  - 0
154
- hash: -3554087706226059699
156
+ hash: -3981899794566552461
155
157
  requirements: []
156
158
  rubyforge_project:
157
159
  rubygems_version: 1.8.24