remote_files 1.0.0 → 1.1.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/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