fspsocket 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", "~> 2.3.0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 mokit
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,21 @@
1
+ = fspsocket
2
+
3
+ * FSPSocket is a library for socket-based communication between client/server programs
4
+ over a file synchronization service.
5
+ * It is an acronym for "File Synchronization-based Pseudo Socket."
6
+
7
+ == Contributing to fspsocket
8
+
9
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
10
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
11
+ * Fork the project
12
+ * Start a feature/bugfix branch
13
+ * Commit and push until you are happy with your contribution
14
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
15
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
16
+
17
+ == Copyright
18
+
19
+ Copyright (c) 2011 mokit. See LICENSE.txt for
20
+ further details.
21
+
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "fspsocket"
16
+ gem.homepage = "http://github.com/mokitma/fspsocket"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{A pseudo socket library over a file synchronization service}
19
+ gem.description = %Q{FSPSocket is a module to enable socket-like communication over a file synchronization service, namely Dropbox}
20
+ gem.email = "mokitma@gmail.com"
21
+ gem.authors = ["mokit"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ gem.add_runtime_dependency 'filemonitor', '> 0.0.4'
26
+ gem.add_runtime_dependency 'json', '> 1.5.1'
27
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
28
+ end
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ require 'rspec/core'
32
+ require 'rspec/core/rake_task'
33
+ RSpec::Core::RakeTask.new(:spec) do |spec|
34
+ spec.pattern = FileList['spec/**/*_spec.rb']
35
+ end
36
+
37
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
38
+ spec.pattern = 'spec/**/*_spec.rb'
39
+ spec.rcov = true
40
+ end
41
+
42
+ task :default => :spec
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "fspsocket #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
data/fspsocket.gemspec ADDED
@@ -0,0 +1,72 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{fspsocket}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["mokit"]
12
+ s.date = %q{2011-03-10}
13
+ s.description = %q{FSPSocket is a module to enable socket-like communication over a file synchronization service, namely Dropbox}
14
+ s.email = %q{mokitma@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "LICENSE.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "fspsocket.gemspec",
28
+ "lib/fspsocket.rb",
29
+ "sample/echocli.rb",
30
+ "sample/echoserv.rb",
31
+ "spec/fspsocket_spec.rb",
32
+ "spec/spec_helper.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/mokitma/fspsocket}
35
+ s.licenses = ["MIT"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.7}
38
+ s.summary = %q{A pseudo socket library over a file synchronization service}
39
+ s.test_files = [
40
+ "spec/fspsocket_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
50
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
51
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
52
+ s.add_development_dependency(%q<rcov>, [">= 0"])
53
+ s.add_runtime_dependency(%q<filemonitor>, ["> 0.0.4"])
54
+ s.add_runtime_dependency(%q<json>, ["> 1.5.1"])
55
+ else
56
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
57
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
58
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
59
+ s.add_dependency(%q<rcov>, [">= 0"])
60
+ s.add_dependency(%q<filemonitor>, ["> 0.0.4"])
61
+ s.add_dependency(%q<json>, ["> 1.5.1"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
65
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
66
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
67
+ s.add_dependency(%q<rcov>, [">= 0"])
68
+ s.add_dependency(%q<filemonitor>, ["> 0.0.4"])
69
+ s.add_dependency(%q<json>, ["> 1.5.1"])
70
+ end
71
+ end
72
+
data/lib/fspsocket.rb ADDED
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # = FSPSocket module
4
+ # Author:: mokitma@gmail.com
5
+ # Copyright:: Copyright 2011 mokitma
6
+ #
7
+ # Supports lazy socket communication over file synchronization services,
8
+ # namely Dropbox
9
+ #
10
+ require 'rubygems'
11
+ require 'fileutils'
12
+ require 'socket'
13
+ require 'singleton'
14
+ require 'observer'
15
+ require 'filemonitor'
16
+ require 'uri'
17
+ require 'json'
18
+ require 'drb/drb'
19
+ require 'logger'
20
+
21
+ module FSPSocket
22
+ @@log = Logger.new(STDOUT)
23
+ @@log.level = Logger::WARN
24
+ @@base = [ENV['HOME'], "Dropbox", "socks"].join(File::SEPARATOR)
25
+
26
+ def FSPSocket.new
27
+ return PSocket.new
28
+ end
29
+
30
+ def FSPSocket.open(dst_id, &block)
31
+ return PSocket.open(dst_id, block)
32
+ end
33
+
34
+ class PSocket
35
+ include FSPSocket
36
+ @@id_count = 0
37
+ attr_reader :id
38
+
39
+ def initialize(*args)
40
+ @host = Socket.gethostname
41
+ @pid = Process.pid
42
+ @id = [@host, @pid, @@id_count].join('_')
43
+ @@id_count += 1
44
+ if args.length == 1
45
+ @block = args[0]
46
+ end
47
+ @sock_buf = []
48
+ Manager.instance.add_observer self
49
+ init_channel
50
+ end
51
+
52
+ def init_channel
53
+ unless FileTest.exist? @@base
54
+ Dir::mkdir(@@base, 0777)
55
+ end
56
+
57
+ @path = [@@base, @id].join(File::SEPARATOR)
58
+ @cpath = [@path, :controls].join(File::SEPARATOR)
59
+ @dpath = [@path, :data].join(File::SEPARATOR)
60
+ @connected = [] # for cleanup
61
+ unless FileTest.exist? @path
62
+ Dir::mkdir(@path, 0777)
63
+ Dir::mkdir(@cpath, 0777)
64
+ FileUtils.touch(@dpath)
65
+ end
66
+ Manager.instance.add_dir(@cpath)
67
+ end
68
+ private :init_channel
69
+
70
+ # msg[0] => path, msg[1] => data in JSON delimited with '\n'
71
+ def update(msg)
72
+ @@log.info "--- update #{msg}"
73
+ # msg[1]:data part can contain more than one line
74
+ msg[1].each_line do |item|
75
+ h = JSON.parse(item)
76
+ d = h.fetch(:data.to_s)
77
+ ud = URI.unescape(d)
78
+ ar = ud.split
79
+ if ar[0] == "HELLO"
80
+ @@log.info "---got HELLO: #{ar[1]}"
81
+ Manager.instance.add_file([@@base, ar[1], :data].join(File::SEPARATOR))
82
+ # XXX
83
+ mycpath = [@@base, ar[1], :controls, @id].join(File::SEPARATOR)
84
+ FileUtils.touch(mycpath)
85
+ sleep 1 # XXX for timing purpose
86
+ PSocket.write_to(mycpath, "OK #{@id}")
87
+ elsif ar[0] == "OK"
88
+ @@log.info "---got OK: #{ar[1]}"
89
+ Manager.instance.add_file([@@base, ar[1], :data].join(File::SEPARATOR))
90
+ @block.call(method(:received))
91
+ elsif ar[0] == "BYE"
92
+ @@log.info "---got BYE: #{ar[1]}"
93
+ Manager.instance.remove_file([@@base, ar[1], :data].join(File::SEPARATOR))
94
+ else
95
+ @recv_block.call(msg[0], ud)
96
+ end
97
+ end # each
98
+ end
99
+
100
+ def connect_channel(dst_fullpath)
101
+ # 1. create my controls channel in the other's controls dir
102
+ # /socks/dstid/controls/myid
103
+ mycpath = [dst_fullpath, :controls, @id].join(File::SEPARATOR)
104
+ @connected << mycpath
105
+ FileUtils.touch(mycpath)
106
+ sleep 1 # XXX for timing purpose
107
+ # 2. let the other know my path
108
+ PSocket.write_to(mycpath, "HELLO #{@id}")
109
+ end
110
+
111
+ def delete_channel
112
+ @connected.each do |path|
113
+ if FileTest.exist? path
114
+ File::delete path
115
+ end
116
+ end
117
+
118
+ path = [@@base, @id].join(File::SEPARATOR)
119
+ if FileTest.exist? path
120
+ File::delete [path, :data].join(File::SEPARATOR)
121
+ FileUtils.rm_rf path
122
+ end
123
+ end
124
+
125
+ def PSocket.open(dst_id, block)
126
+ sock = PSocket.new(block)
127
+ if (dst_id.kind_of?(Enumerable))
128
+ dst_id.each do |item|
129
+ sock.connect_channel([@@base, item].join(File::SEPARATOR))
130
+ end
131
+ else
132
+ sock.connect_channel([@@base, dst_id].join(File::SEPARATOR))
133
+ end
134
+ return sock
135
+ end
136
+
137
+ # used to connect to multiple destinations
138
+ def connect(dst_id)
139
+ if (dst_id.kind_of?(Enumerable))
140
+ dst_id.each do |item|
141
+ connect_channel([@@base, item].join(File::SEPARATOR))
142
+ end
143
+ else
144
+ connect_channel([@@base, dst_id].join(File::SEPARATOR))
145
+ end
146
+ end
147
+
148
+ def close
149
+ delete_channel
150
+ PSocket.write_to(@dst_cpath, "BYE #{@id}")
151
+ end
152
+
153
+ def received(&block)
154
+ @recv_block = block
155
+ end
156
+
157
+ def puts(data)
158
+ #@@log.debug "XXX puts: #{@dpath} #{data}"
159
+ PSocket.write_to(@dpath, data)
160
+ end
161
+
162
+ def PSocket.write_to(path, data)
163
+ @@log.info "write_to #{path} #{data}"
164
+ File::open(path, "a+") do |f|
165
+ h = {:time=>Time.now, :data=>URI.encode(data)}
166
+ f.puts(h.to_json)
167
+ end
168
+ end
169
+
170
+ alias_method :_puts, :puts
171
+ private :_puts
172
+ end # class
173
+
174
+ class Manager
175
+ include FSPSocket
176
+ include Singleton
177
+ include Observable
178
+ attr_reader :m
179
+
180
+ def initialize
181
+ @paths = {}
182
+ @m = FileMonitor.new do |f|
183
+ @@log.info "Modified: #{f.path}"
184
+ file_modified(f.path)
185
+ end
186
+ end
187
+
188
+ def add_dir(path)
189
+ @@log.info "add_dir: #{path}"
190
+ @m.add(path) do |f|
191
+ @@log.info "dir modified #{f.path}"
192
+ @paths.store(f.path, [0, 0]) # dummy data
193
+ file_modified(f.path)
194
+ end
195
+ end
196
+
197
+ def add_file(path)
198
+ @@log.info "add_file: #{path}"
199
+ st = File::stat(path)
200
+ @paths.store(path, [st.mtime, st.size])
201
+ @m << path
202
+ end
203
+
204
+ def remove_file(path)
205
+ @paths.delete(path)
206
+ end
207
+
208
+ def get_file
209
+ @paths.each_key
210
+ end
211
+
212
+ def file_modified(path)
213
+ @@log.info "file_modifled: #{path}"
214
+ prev = @paths.fetch(path)
215
+ st = File::stat(path)
216
+ open(path, "r") do |f|
217
+ f.seek(prev[1], IO::SEEK_SET)
218
+ data = f.read(st.size - prev[1])
219
+ @@log.info "data: #{data}"
220
+ begin
221
+ changed
222
+ idpart = path.sub(@@base, "").split(File::Separator)[1]
223
+ notify_observers [idpart, data] # XXX May contain multiple json entries
224
+ rescue
225
+ STDERR.puts $!
226
+ end
227
+ end # open
228
+ @paths.store(path, [st.mtime, st.size])
229
+ end
230
+
231
+ def file_deleted(path)
232
+ @@log.info "file_deleted: #{path}"
233
+ @paths.delete(path)
234
+ end
235
+ end # class
236
+
237
+ Thread.new do # called when the module is loaded
238
+ Manager.instance.m.monitor
239
+ end
240
+ end # module
241
+
242
+
243
+ if __FILE__ == $0
244
+ # FSPSocket.new
245
+ end
data/sample/echocli.rb ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Simple echo client
4
+ #
5
+ require 'rubygems'
6
+ require 'fspsocket'
7
+
8
+ trap('INT') {
9
+ $sock.close
10
+ exit
11
+ }
12
+
13
+ def send_line
14
+ print "> "
15
+ STDOUT.flush
16
+ line = STDIN.gets
17
+ $sock.puts(line)
18
+ end
19
+
20
+ if ARGV.length == 0
21
+ puts "Usage: #{$0} server_id"
22
+ exit 1
23
+ end
24
+
25
+ $sock = FSPSocket.open(ARGV[0]){|rh|
26
+ puts "sock: #{$sock.id}"
27
+ rh.call {|*data|
28
+ puts "#{data[1]}"
29
+ send_line
30
+ }
31
+ send_line
32
+ }
33
+
34
+ loop do
35
+ Thread.pass
36
+ end
37
+ $sock.close
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Simple echo server
4
+ #
5
+ require 'rubygems'
6
+ require 'fspsocket'
7
+
8
+ trap('INT') {
9
+ $sock.close
10
+ exit
11
+ }
12
+
13
+ $sock = FSPSocket.new
14
+ puts $sock.id
15
+ $sock.received {|*data|
16
+ puts "\"#{data[1].strip!}\" from a client<#{data[0]}>"
17
+ $sock.puts("#{data[1]} from a server<#{$sock.id}>")
18
+ }
19
+
20
+ STDIN.gets
21
+ $sock.close
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Fspsocket" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'fspsocket'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fspsocket
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 0
10
+ version: 0.0.0
11
+ platform: ruby
12
+ authors:
13
+ - mokit
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-10 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 2
30
+ - 3
31
+ - 0
32
+ version: 2.3.0
33
+ type: :development
34
+ name: rspec
35
+ prerelease: false
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 23
44
+ segments:
45
+ - 1
46
+ - 0
47
+ - 0
48
+ version: 1.0.0
49
+ type: :development
50
+ name: bundler
51
+ prerelease: false
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 7
60
+ segments:
61
+ - 1
62
+ - 5
63
+ - 2
64
+ version: 1.5.2
65
+ type: :development
66
+ name: jeweler
67
+ prerelease: false
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :development
80
+ name: rcov
81
+ prerelease: false
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">"
88
+ - !ruby/object:Gem::Version
89
+ hash: 23
90
+ segments:
91
+ - 0
92
+ - 0
93
+ - 4
94
+ version: 0.0.4
95
+ type: :runtime
96
+ name: filemonitor
97
+ prerelease: false
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ requirement: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">"
104
+ - !ruby/object:Gem::Version
105
+ hash: 1
106
+ segments:
107
+ - 1
108
+ - 5
109
+ - 1
110
+ version: 1.5.1
111
+ type: :runtime
112
+ name: json
113
+ prerelease: false
114
+ version_requirements: *id006
115
+ description: FSPSocket is a module to enable socket-like communication over a file synchronization service, namely Dropbox
116
+ email: mokitma@gmail.com
117
+ executables: []
118
+
119
+ extensions: []
120
+
121
+ extra_rdoc_files:
122
+ - LICENSE.txt
123
+ - README.rdoc
124
+ files:
125
+ - .document
126
+ - .rspec
127
+ - Gemfile
128
+ - LICENSE.txt
129
+ - README.rdoc
130
+ - Rakefile
131
+ - VERSION
132
+ - fspsocket.gemspec
133
+ - lib/fspsocket.rb
134
+ - sample/echocli.rb
135
+ - sample/echoserv.rb
136
+ - spec/fspsocket_spec.rb
137
+ - spec/spec_helper.rb
138
+ has_rdoc: true
139
+ homepage: http://github.com/mokitma/fspsocket
140
+ licenses:
141
+ - MIT
142
+ post_install_message:
143
+ rdoc_options: []
144
+
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ hash: 3
153
+ segments:
154
+ - 0
155
+ version: "0"
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ none: false
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ hash: 3
162
+ segments:
163
+ - 0
164
+ version: "0"
165
+ requirements: []
166
+
167
+ rubyforge_project:
168
+ rubygems_version: 1.3.7
169
+ signing_key:
170
+ specification_version: 3
171
+ summary: A pseudo socket library over a file synchronization service
172
+ test_files:
173
+ - spec/fspsocket_spec.rb
174
+ - spec/spec_helper.rb