file_proxy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in file_proxy.gemspec
4
+ gemspec
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.
@@ -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.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -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
@@ -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,3 @@
1
+ module FileProxy
2
+ OriginalFile = File.dup
3
+ end
@@ -0,0 +1,13 @@
1
+ module FileProxy
2
+ module Proxies
3
+ module FileProxy
4
+ def remote
5
+ @remote ||= SimpleDelegator.new(OriginalFile)
6
+ end
7
+
8
+ def method_missing *args, &blk
9
+ remote.send *args, &blk
10
+ end
11
+ end
12
+ end
13
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module FileProxy
2
+ VERSION = "0.0.1"
3
+ 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: []