defog 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +68 -24
- data/lib/defog/error.rb +3 -0
- data/lib/defog/file.rb +27 -22
- data/lib/defog/handle.rb +2 -2
- data/lib/defog/proxy.rb +77 -7
- data/lib/defog/version.rb +1 -1
- data/spec/proxy_spec.rb +118 -19
- metadata +15 -15
data/README.rdoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
= defog
|
2
2
|
|
3
|
-
Defog wraps the [
|
4
|
-
|
3
|
+
Defog wraps the fog[https://rubygems.org/gems/fog] gem (specifically,
|
4
|
+
{Fog::Storage}[http://fog.io/1.3.1/storage/]), providing access to files
|
5
5
|
stored in the cloud via proxy files on the local file system.
|
6
6
|
A proxy file can be
|
7
7
|
* Read-only: A local cached copy of a cloud file.
|
@@ -10,7 +10,7 @@ A proxy file can be
|
|
10
10
|
|
11
11
|
Defog thus lets you use ordinary programmatic tools to access and
|
12
12
|
manipulate your cloud data. Thanks to the magic of
|
13
|
-
[
|
13
|
+
fog[https://rubygems.org/gems/fog] it works across cloud providers, and
|
14
14
|
it also works with the local file system as a "provider" so that you can,
|
15
15
|
e.g. use the local file system for development and the cloud for
|
16
16
|
production.
|
@@ -100,38 +100,83 @@ In addition, the handle allows you to look up the path where the local proxy fil
|
|
100
100
|
|
101
101
|
=== Persistence
|
102
102
|
|
103
|
-
By default, the local proxy
|
104
|
-
possible to
|
105
|
-
|
106
|
-
|
107
|
-
|
103
|
+
By default, Defog will delete the local proxy when closing a file.
|
104
|
+
However, it is possible to keep the local proxy file so that it if the
|
105
|
+
remote is accessed again the data will not need to be transferred again.
|
106
|
+
(This is true even between executions of the program: a Defog::Proxy
|
107
|
+
instance can start with proxy files already in place, and it will use them.)
|
108
|
+
|
109
|
+
Persistence can be enabled by default for the Defog::Proxy instance via:
|
110
|
+
|
111
|
+
defog = Defog::Proxy.new(:provider => ..., :persist => true)
|
112
|
+
|
113
|
+
And/or persistence can be overridden on a per-file basis at proxy open time:
|
108
114
|
|
109
115
|
file = defog.file("key/of/file", mode, :persist => true)
|
110
116
|
|
111
|
-
or
|
117
|
+
or at proxy close time:
|
112
118
|
|
113
119
|
file.close(:persist => true)
|
114
120
|
|
115
121
|
When opening a file whose local proxy has been persisted, Defog checks to see if
|
116
|
-
the local proxy is out of date and if so replaces it.
|
122
|
+
the local proxy is out of date and if so replaces it (via MD5 digests).
|
123
|
+
|
124
|
+
== Local proxy file cache
|
125
|
+
|
126
|
+
For basic usage, you don't need to worry about the cache, the default
|
127
|
+
settings work fine. But if you will be persisting proxy files you may want to
|
128
|
+
manage the cache more carefully.
|
129
|
+
|
130
|
+
=== Cache location
|
131
|
+
|
132
|
+
The cache for a given Defog::Proxy is rooted at a directory on the local
|
133
|
+
file system. You can set and query the root via
|
134
|
+
|
135
|
+
defog = Defog::Proxy.new(:provider => ..., :proxy_root => "/my/chosen/root")
|
136
|
+
defog.proxy_root # => returns a Pathname
|
117
137
|
|
118
|
-
|
119
|
-
locally persisted file (other than opening and closing it again without
|
120
|
-
:persist => true). But it's fair game to delete it outside of Defog, such
|
121
|
-
as via a cron job that cleans out old files.
|
138
|
+
If you don't specify a root, Defog uses one of two defaults:
|
122
139
|
|
123
|
-
|
140
|
+
{Rails.root}/tmp/defog/{provider}-{location} # if Rails is defined
|
141
|
+
{Dir.tmpdir}/defog/{provider}-{location} # if Rails is not defined
|
124
142
|
|
125
|
-
|
143
|
+
In these, <code>location</code> disambiguates between Defog::Proxy instances.
|
144
|
+
For :AWS it's the bucket name and for :local it's the
|
145
|
+
<code>local_root</code> directory path with slashes replaced with dashes.
|
126
146
|
|
127
|
-
|
147
|
+
[Why cache local files, you ask? Why not bypass this whole cache thing if
|
148
|
+
using :local? Well, the motivation for supporting :local is to use it in
|
149
|
+
development and use :AWS in production. So, to more faithfully mimic
|
150
|
+
production behavior, :local mode goes through the same code path and same
|
151
|
+
caching mechanism.]
|
128
152
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
<code>local_root</code> directory path with slashes replaced with underscores.
|
153
|
+
Within the cache, indvidiual proxy files are located by treating the key as
|
154
|
+
a path relative to the proxy root (with slashes in the key indicating
|
155
|
+
subdirectories in the path).
|
133
156
|
|
134
|
-
|
157
|
+
=== Cache size management
|
158
|
+
|
159
|
+
Defog can perform simple size management of the local proxy file cache. This is
|
160
|
+
of course useful mostly when persisting files.
|
161
|
+
|
162
|
+
You can specify a maximum cache size via:
|
163
|
+
|
164
|
+
defog = Defog::Proxy.new(:provider => ..., :max_cache_size => size-in-bytes)
|
165
|
+
|
166
|
+
If a maximum size is set, then before downloading data to create a proxy,
|
167
|
+
Defog will check the space available and delete persisted proxy files as needed
|
168
|
+
in LRU order. Does not delete files for proxies that are currently open.
|
169
|
+
If this would not free up enough space (because of open proxies or just
|
170
|
+
because the remote is larger than the cache), raises
|
171
|
+
Defog::Error::CacheFull and doesn't actually delete anything.
|
172
|
+
|
173
|
+
You can also manually delete an individual persisted file, such as via:
|
174
|
+
|
175
|
+
defog.file("key").proxy_path.unlink
|
176
|
+
|
177
|
+
And it's fair game to delete proxy files outside of Defog, such as via a
|
178
|
+
cron job. Of course in these cases it's up to you to make sure not to
|
179
|
+
unintentionally delete a proxy file that's currently open.
|
135
180
|
|
136
181
|
== Installation
|
137
182
|
|
@@ -141,9 +186,8 @@ Gemfile:
|
|
141
186
|
== Compatibility
|
142
187
|
|
143
188
|
Defog has (so far) been tested on MRI 1.9.3 using
|
144
|
-
[
|
189
|
+
fog[https://rubygems.org/gems/fog] storage providers :local and :AWS
|
145
190
|
|
146
191
|
== Copyright
|
147
192
|
|
148
193
|
Released under the MIT License. See LICENSE for details.
|
149
|
-
|
data/lib/defog/error.rb
CHANGED
data/lib/defog/file.rb
CHANGED
@@ -31,35 +31,40 @@ module Defog
|
|
31
31
|
# Upon closing the proxy file, in normal use the cloud storage gets synchronized and
|
32
32
|
# the proxy deleted. See File#close for more details.
|
33
33
|
class File < ::File
|
34
|
-
def self.get(opts={}, &block) #:nodoc:
|
35
|
-
opts = opts.keyword_args(:handle => :required, :mode => :required, :persist => :optional)
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
def initialize(opts={}, &block) #:nodoc:
|
36
|
+
opts = opts.keyword_args(:handle => :required, :mode => :required, :persist => :optional)
|
37
|
+
@handle = opts.handle
|
38
|
+
@persist = opts.persist
|
40
39
|
|
40
|
+
key = @handle.key
|
41
|
+
proxy_path = @handle.proxy_path
|
41
42
|
proxy_path.dirname.mkpath
|
42
|
-
|
43
43
|
case opts.mode
|
44
|
-
when "r"
|
45
|
-
|
46
|
-
when "w", "w+"
|
47
|
-
|
48
|
-
when "r+", "a", "a+"
|
49
|
-
|
50
|
-
|
44
|
+
when "r"
|
45
|
+
create_proxy
|
46
|
+
when "w", "w+"
|
47
|
+
@upload = true
|
48
|
+
when "r+", "a", "a+"
|
49
|
+
create_proxy
|
50
|
+
@upload = true
|
51
51
|
else
|
52
52
|
raise ArgumentError, "Invalid mode #{opts.mode.inspect}"
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
super(proxy_path, opts.mode, &block)
|
56
56
|
end
|
57
57
|
|
58
|
-
def
|
59
|
-
@
|
60
|
-
|
58
|
+
def create_proxy
|
59
|
+
@handle.proxy.open_proxy_file(@handle)
|
60
|
+
@handle.proxy.fog_wrapper.get_file(@handle.key, @handle.proxy_path)
|
61
|
+
end
|
62
|
+
|
63
|
+
def upload_proxy
|
64
|
+
@handle.proxy.fog_wrapper.put_file(@handle.key, @handle.proxy_path)
|
61
65
|
end
|
62
66
|
|
67
|
+
|
63
68
|
# Closes the proxy file and synchronizes the cloud storage (if it was
|
64
69
|
# opened as writeable) then deletes the proxy file.
|
65
70
|
#
|
@@ -75,13 +80,13 @@ module Defog
|
|
75
80
|
# (This will override the setting of <code>:persist</code> passed to Proxy#file)
|
76
81
|
#
|
77
82
|
def close(opts={})
|
78
|
-
opts = opts.keyword_args(:persist => @
|
83
|
+
opts = opts.keyword_args(:persist => @persist, :synchronize => true)
|
79
84
|
super()
|
80
|
-
|
81
|
-
|
82
|
-
handle.
|
83
|
-
handle.proxy_path.unlink unless opts.persist
|
85
|
+
if @handle.proxy_path.exist?
|
86
|
+
upload_proxy if @upload and opts.synchronize
|
87
|
+
@handle.proxy_path.unlink unless opts.persist
|
84
88
|
end
|
89
|
+
@handle.proxy.close_proxy_file(@handle)
|
85
90
|
end
|
86
91
|
end
|
87
92
|
end
|
data/lib/defog/handle.rb
CHANGED
@@ -93,8 +93,8 @@ module Defog
|
|
93
93
|
# to suppress deleting the file and so maintain the file after closing. See File#close for more
|
94
94
|
# details.
|
95
95
|
def open(mode, opts={}, &block)
|
96
|
-
opts = opts.keyword_args(:persist)
|
97
|
-
File.
|
96
|
+
opts = opts.keyword_args(:persist => @proxy.persist)
|
97
|
+
File.open(opts.merge(:handle => self, :mode => mode), &block)
|
98
98
|
end
|
99
99
|
|
100
100
|
end
|
data/lib/defog/proxy.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
require "hash_keyword_args"
|
2
|
-
require "tmpdir"
|
3
2
|
require "pathname"
|
3
|
+
require "set"
|
4
|
+
require "tmpdir"
|
4
5
|
|
5
6
|
module Defog
|
6
7
|
class Proxy
|
7
8
|
|
8
|
-
attr_reader :proxy_root
|
9
|
+
attr_reader :proxy_root
|
10
|
+
attr_reader :persist
|
11
|
+
attr_reader :max_cache_size
|
9
12
|
attr_reader :fog_wrapper # :nodoc:
|
10
13
|
|
11
14
|
# Opens a <code>Fog</code> cloud storage connection to map to a corresponding proxy
|
12
15
|
# directory. Use via, e.g.,
|
13
16
|
#
|
14
|
-
# Defog::Proxy.new(:provider => :AWS, :aws_access_key_id => access_key, ...)
|
17
|
+
# defog = Defog::Proxy.new(:provider => :AWS, :aws_access_key_id => access_key, ...)
|
15
18
|
#
|
16
19
|
# The <code>:provider</code> and its corresponding options must be
|
17
20
|
# specified as per <code>Fog::Storage.new</code>. Currently, only
|
@@ -31,10 +34,27 @@ module Defog
|
|
31
34
|
# to worry about it. But if you do care, you can specify the option:
|
32
35
|
# :proxy_root => "/root/for/this/proxy/files"
|
33
36
|
#
|
37
|
+
# You can turn on persistence of local proxy files by specifying
|
38
|
+
# :persist => true
|
39
|
+
# The persistence behavior can be overriden on a per-file basis when
|
40
|
+
# opening a proxy (see Defog::Handle#open)
|
41
|
+
#
|
42
|
+
# You can enable cache management by specifying a max cache size in
|
43
|
+
# bytes, e.g.
|
44
|
+
# :max_cache_size => 3.gigabytes
|
45
|
+
# See the README for discussion. [Number#gigabytes is defined in
|
46
|
+
# Rails' ActiveSupport core extensions]
|
34
47
|
def initialize(opts={})
|
35
|
-
opts = opts.keyword_args(:provider => :required,
|
48
|
+
opts = opts.keyword_args(:provider => :required,
|
49
|
+
:proxy_root => :optional,
|
50
|
+
:persist => :optional,
|
51
|
+
:max_cache_size => :optional,
|
52
|
+
:OTHERS => :optional)
|
36
53
|
|
37
54
|
@proxy_root = Pathname.new(opts.delete(:proxy_root)) if opts.proxy_root
|
55
|
+
@persist = opts.delete(:persist)
|
56
|
+
@max_cache_size = opts.delete(:max_cache_size)
|
57
|
+
@open_proxy_paths = Set.new
|
38
58
|
|
39
59
|
@fog_wrapper = FogWrapper.connect(opts)
|
40
60
|
|
@@ -69,12 +89,13 @@ module Defog
|
|
69
89
|
@fog_wrapper.fog_directory
|
70
90
|
end
|
71
91
|
|
72
|
-
# Proxy a remote cloud file. Returns a Defog::Handle object that
|
92
|
+
# Proxy a remote cloud file. Returns or yields a Defog::Handle object that
|
73
93
|
# represents the file.
|
74
94
|
#
|
75
|
-
# If a <code>mode</code> is
|
95
|
+
# If a <code>mode</code> is given, opens a proxy file via
|
76
96
|
# Defog::Handle#open (passing it the mode and other options and
|
77
|
-
# optional block), returning instead the Defog::File object.
|
97
|
+
# optional block), returning or yielding instead the Defog::File object.
|
98
|
+
#
|
78
99
|
#
|
79
100
|
# Thus
|
80
101
|
# proxy.file("key", mode, options, &block)
|
@@ -90,5 +111,54 @@ module Defog
|
|
90
111
|
end
|
91
112
|
end
|
92
113
|
|
114
|
+
def open_proxy_file(handle) #:nodoc:
|
115
|
+
manage_cache(handle) if max_cache_size
|
116
|
+
@open_proxy_paths << handle.proxy_path
|
117
|
+
end
|
118
|
+
|
119
|
+
def close_proxy_file(handle) #:nodoc:
|
120
|
+
@open_proxy_paths.delete handle.proxy_path
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def manage_cache(handle)
|
126
|
+
remote_size = handle.size
|
127
|
+
proxy_path = handle.proxy_path
|
128
|
+
|
129
|
+
# find available space (not counting current proxy)
|
130
|
+
available = max_cache_size
|
131
|
+
proxy_root.find { |path| available -= path.size if path.file? and path != proxy_path}
|
132
|
+
return if available >= remote_size
|
133
|
+
|
134
|
+
space_needed = remote_size - available
|
135
|
+
|
136
|
+
# find all paths in the cache that aren't currently open (not
|
137
|
+
# counting current proxy)
|
138
|
+
candidates = []
|
139
|
+
proxy_root.find { |path| candidates << path if path.file? and not @open_proxy_paths.include?(path) and path != proxy_path}
|
140
|
+
|
141
|
+
# take candidates in LRU order until that would be enough space
|
142
|
+
would_free = 0
|
143
|
+
candidates = Set.new(candidates.sort_by(&:atime).take_while{|path| (would_free < space_needed).tap{|condition| would_free += path.size}})
|
144
|
+
|
145
|
+
# still not enough...?
|
146
|
+
raise Error::CacheFull, "No room in cache for #{handle.key.inspect}: size=#{remote_size} available=#{available} can_free=#{would_free}, max_cache_size=#{max_cache_size}" if would_free < space_needed
|
147
|
+
|
148
|
+
# LRU order may have taken more than needed, if last file was a big
|
149
|
+
# chunk. So take another pass, eliminating files that aren't needed.
|
150
|
+
# Do this in reverse size order, since we want to keep big files in
|
151
|
+
# the cache if possible since they're most expensive to replace.
|
152
|
+
candidates.sort_by(&:size).reverse.each do |path|
|
153
|
+
if (would_free - path.size) > space_needed
|
154
|
+
candidates.delete path
|
155
|
+
would_free -= path.size
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# free the remaining candidates
|
160
|
+
candidates.each(&:unlink)
|
161
|
+
end
|
162
|
+
|
93
163
|
end
|
94
164
|
end
|
data/lib/defog/version.rb
CHANGED
data/spec/proxy_spec.rb
CHANGED
@@ -2,25 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
shared_examples "a proxy" do |args|
|
4
4
|
|
5
|
-
|
6
|
-
proxy = Defog::Proxy.new(args)
|
7
|
-
proxy.proxy_root.should == Pathname.new(Dir.tmpdir) + "defog" + proxy.provider.to_s + proxy.location
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should default proxy root to Rails.root" do
|
11
|
-
with_rails_defined do
|
12
|
-
proxy = Defog::Proxy.new(args)
|
13
|
-
proxy.proxy_root.should == Rails.root + "tmp/defog" + proxy.provider.to_s + proxy.location
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should accept proxy root parameter" do
|
18
|
-
path = Pathname.new("/a/random/path")
|
19
|
-
proxy = Defog::Proxy.new(args.merge(:proxy_root => path))
|
20
|
-
proxy.proxy_root.should == path
|
21
|
-
end
|
22
|
-
|
23
|
-
context do
|
5
|
+
context "basic features" do
|
24
6
|
before(:each) do
|
25
7
|
@proxy = Defog::Proxy.new(args)
|
26
8
|
end
|
@@ -57,6 +39,123 @@ shared_examples "a proxy" do |args|
|
|
57
39
|
end
|
58
40
|
end
|
59
41
|
|
42
|
+
context "proxy root location" do
|
43
|
+
it "should default proxy root to tmpdir/defog" do
|
44
|
+
proxy = Defog::Proxy.new(args)
|
45
|
+
proxy.proxy_root.should == Pathname.new(Dir.tmpdir) + "defog" + proxy.provider.to_s + proxy.location
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should default proxy root to Rails.root" do
|
49
|
+
with_rails_defined do
|
50
|
+
proxy = Defog::Proxy.new(args)
|
51
|
+
proxy.proxy_root.should == Rails.root + "tmp/defog" + proxy.provider.to_s + proxy.location
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should accept proxy root parameter" do
|
56
|
+
path = Pathname.new("/a/random/path")
|
57
|
+
proxy = Defog::Proxy.new(args.merge(:proxy_root => path))
|
58
|
+
proxy.proxy_root.should == path
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "cache management" do
|
63
|
+
before(:each) do
|
64
|
+
@proxy = Defog::Proxy.new(args.merge(:max_cache_size => 100, :persist => true))
|
65
|
+
@proxy.proxy_root.rmtree
|
66
|
+
@proxy.proxy_root.mkpath
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should raise an error trying to proxy a file larger than the cache" do
|
70
|
+
create_remote("x" * 101)
|
71
|
+
expect { @proxy.file(key, "r") }.should raise_error(Defog::Error::CacheFull)
|
72
|
+
proxy_path.should_not be_exist
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not count existing proxy in total" do
|
76
|
+
create_proxy("y" * 70)
|
77
|
+
create_remote("x" * 70)
|
78
|
+
expect { @proxy.file(key, "r") do end }.should_not raise_error(Defog::Error::CacheFull)
|
79
|
+
proxy_path.should be_exist
|
80
|
+
proxy_path.read.should == remote_body
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should delete proxies to make room" do
|
84
|
+
create_other_proxy("a", 10)
|
85
|
+
create_other_proxy("b", 30)
|
86
|
+
create_other_proxy("c", 40)
|
87
|
+
create_remote("x" * 80)
|
88
|
+
expect { @proxy.file(key, "r") do end }.should_not raise_error(Defog::Error::CacheFull)
|
89
|
+
proxy_path.should be_exist
|
90
|
+
other_proxy_path("a").should be_exist
|
91
|
+
other_proxy_path("b").should_not be_exist
|
92
|
+
other_proxy_path("c").should_not be_exist
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should not delete proxies that are open" do
|
96
|
+
create_other_proxy("a", 20)
|
97
|
+
create_other_proxy("b", 20)
|
98
|
+
create_other_remote("R", 30)
|
99
|
+
create_other_remote("S", 30)
|
100
|
+
create_remote("x" * 30)
|
101
|
+
@proxy.file("R", "r") do
|
102
|
+
@proxy.file("S", "r") do
|
103
|
+
expect { @proxy.file(key, "r") do end }.should_not raise_error(Defog::Error::CacheFull)
|
104
|
+
proxy_path.should be_exist
|
105
|
+
other_proxy_path("a").should_not be_exist
|
106
|
+
other_proxy_path("b").should_not be_exist
|
107
|
+
other_proxy_path("R").should be_exist
|
108
|
+
other_proxy_path("S").should be_exist
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should delete proxies that are no longer open" do
|
114
|
+
create_other_remote("R", 60)
|
115
|
+
create_remote("z" * 60)
|
116
|
+
@proxy.file("R", "r") do end
|
117
|
+
other_proxy_path("R").should be_exist
|
118
|
+
expect { @proxy.file(key, "r") do end }.should_not raise_error(Defog::Error::CacheFull)
|
119
|
+
proxy_path.should be_exist
|
120
|
+
other_proxy_path("R").should_not be_exist
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should not delete proxies if there wouldn't be enough space" do
|
124
|
+
create_other_proxy("a", 20)
|
125
|
+
create_other_proxy("b", 20)
|
126
|
+
create_other_remote("r", 30)
|
127
|
+
create_other_remote("s", 30)
|
128
|
+
create_remote("z" * 50)
|
129
|
+
@proxy.file("r", "r") do
|
130
|
+
@proxy.file("s", "r") do
|
131
|
+
expect { @proxy.file(key, "r") do end }.should raise_error(Defog::Error::CacheFull)
|
132
|
+
proxy_path.should_not be_exist
|
133
|
+
other_proxy_path("a").should be_exist
|
134
|
+
other_proxy_path("b").should be_exist
|
135
|
+
other_proxy_path("r").should be_exist
|
136
|
+
other_proxy_path("s").should be_exist
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def create_other_proxy(otherkey, size)
|
144
|
+
other_proxy_path(otherkey).open("w") do |f|
|
145
|
+
f.write("x" * size)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def other_proxy_path(otherkey)
|
150
|
+
@proxy.file(otherkey).proxy_path
|
151
|
+
end
|
152
|
+
|
153
|
+
def create_other_remote(otherkey, size)
|
154
|
+
@proxy.fog_directory.files.create(:key => otherkey, :body => "x" * size)
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
60
159
|
end
|
61
160
|
|
62
161
|
describe Defog::Proxy do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: defog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-04-27 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog
|
16
|
-
requirement: &
|
16
|
+
requirement: &70234406646360 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70234406646360
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: hash_keyword_args
|
27
|
-
requirement: &
|
27
|
+
requirement: &70234406645920 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70234406645920
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: fastandand
|
38
|
-
requirement: &
|
38
|
+
requirement: &70234406645400 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70234406645400
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake
|
49
|
-
requirement: &
|
49
|
+
requirement: &70234406644900 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70234406644900
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rspec
|
60
|
-
requirement: &
|
60
|
+
requirement: &70234406644280 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70234406644280
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: simplecov
|
71
|
-
requirement: &
|
71
|
+
requirement: &70234406643420 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70234406643420
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: simplecov-gem-adapter
|
82
|
-
requirement: &
|
82
|
+
requirement: &70234406643000 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,7 +87,7 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70234406643000
|
91
91
|
description: Wrapper to fog gem, proxying access to cloud files as local files.
|
92
92
|
email:
|
93
93
|
- ronen@barzel.org
|