file_proxy 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENCE +7 -0
- data/README.md +86 -0
- data/Rakefile +1 -0
- data/file_proxy.gemspec +24 -0
- data/lib/file_proxy.rb +10 -0
- data/lib/file_proxy/original_file.rb +3 -0
- data/lib/file_proxy/proxies/file_proxy.rb +13 -0
- data/lib/file_proxy/proxies/http_proxy.rb +15 -0
- data/lib/file_proxy/proxy.rb +16 -0
- data/lib/file_proxy/shim.rb +14 -0
- data/lib/file_proxy/version.rb +3 -0
- metadata +59 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENCE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2011 Craig R Webster <craig@barkingiguana.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# File Proxy
|
2
|
+
|
3
|
+
A toy project to see if I can make a library with no knowledge of an external
|
4
|
+
storage service read files from and write files to that service.
|
5
|
+
|
6
|
+
Why would you want to do this? Well, here's an example of reading a CSV:
|
7
|
+
|
8
|
+
require 'csv'
|
9
|
+
CSV.foreach("./employees.csv",
|
10
|
+
:headers => :first_row) do |row|
|
11
|
+
puts row.to_hash.inspect
|
12
|
+
end
|
13
|
+
|
14
|
+
This causes the CSV library to read the file `employees.csv` from the local
|
15
|
+
filesystem. What if I have access to that file from a central resource, maybe
|
16
|
+
an HR database, and it's exposed over something like HTTP? Do I really want to
|
17
|
+
deal with downloading that file before I read it? Why can't I just tell `CSV`
|
18
|
+
where the file lives?
|
19
|
+
|
20
|
+
CSV.foreach("http://hr.local/data/employees.csv",
|
21
|
+
:headers => :first_row) do |row|
|
22
|
+
puts row.to_hash.inspect
|
23
|
+
end
|
24
|
+
|
25
|
+
I could pass an `IO` to the `CSV` library which correctly wrapped the HTTP
|
26
|
+
resource, and that would be perfectly valid and in this case arguable better,
|
27
|
+
but there are plenty of other libraries that don't provide the same degree of
|
28
|
+
flexibility and I want to see if I can support those too. I'd also like to not
|
29
|
+
worry about providing IO wrappers around common things like reading from or
|
30
|
+
writing to objects stored in s3 or on some FTP server.
|
31
|
+
|
32
|
+
|
33
|
+
## A word of warning
|
34
|
+
|
35
|
+
This is a toy project and I'm not sure I'd use it for anything serious unless
|
36
|
+
there was absolutely no better way. "Better" is, of course, rather subjective,
|
37
|
+
so I'll leave that up to you do decide.
|
38
|
+
|
39
|
+
Here are some alternatives that were suggested to me as more sane solutions
|
40
|
+
when talking about this project:
|
41
|
+
|
42
|
+
* Use `open-uri` to read files
|
43
|
+
* Mount the remote service via FUSE
|
44
|
+
|
45
|
+
I'm sure there are others - feel free to add your suggestions here.
|
46
|
+
|
47
|
+
|
48
|
+
## How is it used and how does it work?
|
49
|
+
|
50
|
+
Include the shim into the `File` class:
|
51
|
+
|
52
|
+
require 'file_proxy'
|
53
|
+
File.class_eval { include FileProxy::Shim }
|
54
|
+
|
55
|
+
That little piece of code totally screws with the `File` class as provided by
|
56
|
+
stdlib. I'd encourage you to read the code to find out exactly the sort of
|
57
|
+
crazy things I'm doing.
|
58
|
+
|
59
|
+
From now on, any file access (via `File` at least) will try to parse the path
|
60
|
+
as an `URI`. If there's no scheme part to the URI, as will be the case with
|
61
|
+
normal filesystem paths, then proxy back to the original `File` class ie
|
62
|
+
behaviour should not be changed.
|
63
|
+
|
64
|
+
If there *is* a scheme in the URI then attempt to load the appropriate Proxy
|
65
|
+
behaviour from `FileProxy::Proxies::<Scheme>Proxy` and call the method which
|
66
|
+
was origianlly called on `File` from that, passing the same arguments
|
67
|
+
(including blocks, if any) to that method.
|
68
|
+
|
69
|
+
|
70
|
+
## Who made this crazy thing?
|
71
|
+
|
72
|
+
[Craig R Webster][0] wrote most of the madness.
|
73
|
+
|
74
|
+
Jon Wood helped work out how to delegate back to the original File class.
|
75
|
+
|
76
|
+
Tom Stuart and James Adam tried to talk me into doing something sane (sorry
|
77
|
+
guys) and talked about how to capture the original File class before futzing
|
78
|
+
with it.
|
79
|
+
|
80
|
+
[0]: mailto:craig@barkingiguana.com
|
81
|
+
|
82
|
+
|
83
|
+
## Licence
|
84
|
+
|
85
|
+
Since nothing is complete without a licence, this is released under the terms
|
86
|
+
of the MIT licence, a copy of which is included in the LICENCE file.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/file_proxy.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "file_proxy/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "file_proxy"
|
7
|
+
s.version = FileProxy::VERSION
|
8
|
+
s.authors = ["Craig R Webster"]
|
9
|
+
s.email = ["craig@barkingiguana.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Proxy the File class to places that aren't on the local filesystem}
|
12
|
+
s.description = %q{A toy project to see if I can make a library with no knowledge of an external storage service read files from and write files to that service.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "file_proxy"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
data/lib/file_proxy.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'delegate'
|
4
|
+
|
5
|
+
require 'file_proxy/version'
|
6
|
+
require 'file_proxy/original_file'
|
7
|
+
require 'file_proxy/proxies/file_proxy'
|
8
|
+
require 'file_proxy/proxies/http_proxy'
|
9
|
+
require 'file_proxy/proxy'
|
10
|
+
require 'file_proxy/shim'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module FileProxy
|
2
|
+
module Proxies
|
3
|
+
module HttpProxy
|
4
|
+
def open url, *args, &blk
|
5
|
+
uri = URI.parse url
|
6
|
+
data = Net::HTTP.get uri
|
7
|
+
buffer = '/tmp/' + Time.now.to_s + rand(1_000_000_000_000).to_s
|
8
|
+
::FileProxy::OriginalFile.open buffer, 'w+' do |f|
|
9
|
+
f.print data
|
10
|
+
end
|
11
|
+
::FileProxy::OriginalFile.open buffer, *args, &blk
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module FileProxy
|
2
|
+
class Proxy
|
3
|
+
def initialize scheme
|
4
|
+
self.class.instance_eval do
|
5
|
+
include proxy_for scheme
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.proxy_for scheme
|
10
|
+
return Proxies::FileProxy if scheme.nil?
|
11
|
+
proxy = scheme.dup
|
12
|
+
proxy[0] = proxy[0].upcase
|
13
|
+
Proxies.const_get "#{proxy}Proxy"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FileProxy
|
2
|
+
module Shim
|
3
|
+
def self.included into
|
4
|
+
class << into
|
5
|
+
def open file_name, *args, &blk
|
6
|
+
uri = URI.parse file_name
|
7
|
+
puts uri.scheme.inspect
|
8
|
+
proxy = Proxy.new uri.scheme
|
9
|
+
proxy.open file_name, *args, &blk
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: file_proxy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Craig R Webster
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-22 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: A toy project to see if I can make a library with no knowledge of an
|
15
|
+
external storage service read files from and write files to that service.
|
16
|
+
email:
|
17
|
+
- craig@barkingiguana.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- Gemfile
|
24
|
+
- LICENCE
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- file_proxy.gemspec
|
28
|
+
- lib/file_proxy.rb
|
29
|
+
- lib/file_proxy/original_file.rb
|
30
|
+
- lib/file_proxy/proxies/file_proxy.rb
|
31
|
+
- lib/file_proxy/proxies/http_proxy.rb
|
32
|
+
- lib/file_proxy/proxy.rb
|
33
|
+
- lib/file_proxy/shim.rb
|
34
|
+
- lib/file_proxy/version.rb
|
35
|
+
homepage: ''
|
36
|
+
licenses: []
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project: file_proxy
|
55
|
+
rubygems_version: 1.8.10
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: Proxy the File class to places that aren't on the local filesystem
|
59
|
+
test_files: []
|