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 CHANGED
@@ -1,7 +1,7 @@
1
1
  = defog
2
2
 
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
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
- [fog](https://rubygems.org/gems/fog) it works across cloud providers, and
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 files are deleted when closed. However, it is
104
- possible to persist the local proxy, so that it if the remote is accessed
105
- again-- whether in the same program execution or at a later time or by a
106
- different program--the data will not need to be transferred again. Do so
107
- via
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
- Currently, Defog does not natively support a way to explictly delete the
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
- === Local Proxy File Location
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
- Local proxy files are stored by default in
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
- #{tmproot}/defog/#{provider}/#{location}/#{key}
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
- where <code>tmproot</code> is <code>Rails.root+"tmp"</code> if Rails is
130
- defined, otherwise <code>Dir.tmpdir()</code>. For :AWS,
131
- <code>location</code> is the bucket name, and for :local it's the
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
- See the documentation for configuring other locations.
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
- [fog](https://rubygems.org/gems/fog) storage providers :local and :AWS
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
@@ -3,6 +3,9 @@ module Defog
3
3
 
4
4
  class NoCloudFile < Error
5
5
  end
6
+
7
+ class CacheFull < Error
8
+ end
6
9
  end
7
10
 
8
11
  end
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
- handle = opts.handle
38
- key = handle.key
39
- proxy_path = handle.proxy_path
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" then
45
- handle.proxy.fog_wrapper.get_file(key, proxy_path)
46
- when "w", "w+" then
47
- opts[:upload] = true
48
- when "r+", "a", "a+" then
49
- handle.proxy.fog_wrapper.get_file(key, proxy_path)
50
- opts[:upload] = true
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
- self.open(opts, &block)
55
+ super(proxy_path, opts.mode, &block)
56
56
  end
57
57
 
58
- def initialize(opts={}, &block) #:nodoc:
59
- @defog = opts.keyword_args(:handle => :required, :mode => :required, :upload => :optional, :persist => :optional)
60
- super(@defog.handle.proxy_path, @defog.mode, &block)
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 => @defog.persist, :synchronize => true)
83
+ opts = opts.keyword_args(:persist => @persist, :synchronize => true)
79
84
  super()
80
- handle = @defog.handle
81
- if handle.proxy_path.exist?
82
- handle.proxy.fog_wrapper.put_file(handle.key, handle.proxy_path) if @defog.upload and opts.synchronize
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.get(opts.merge(:handle => self, :mode => mode), &block)
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, :proxy_root => :optional, :OTHERS => :optional)
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 specified given opens a proxy file via
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
@@ -1,3 +1,3 @@
1
1
  module Defog
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
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
- it "should default proxy root to tmpdir/defog" do
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.1.1
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: &70159750978980 !ruby/object:Gem::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: *70159750978980
24
+ version_requirements: *70234406646360
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: hash_keyword_args
27
- requirement: &70159750978560 !ruby/object:Gem::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: *70159750978560
35
+ version_requirements: *70234406645920
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: fastandand
38
- requirement: &70159750978140 !ruby/object:Gem::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: *70159750978140
46
+ version_requirements: *70234406645400
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
- requirement: &70159750977700 !ruby/object:Gem::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: *70159750977700
57
+ version_requirements: *70234406644900
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rspec
60
- requirement: &70159750977280 !ruby/object:Gem::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: *70159750977280
68
+ version_requirements: *70234406644280
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
- requirement: &70159750976820 !ruby/object:Gem::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: *70159750976820
79
+ version_requirements: *70234406643420
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: simplecov-gem-adapter
82
- requirement: &70159750976360 !ruby/object:Gem::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: *70159750976360
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