ipfs-api 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f5f308798c9180262f9aa758b6010b910142a0d9
4
+ data.tar.gz: 13fde3fde504683f14df8e5d891d5291ac3624ba
5
+ SHA512:
6
+ metadata.gz: 9932b1d74862af972ded69d873a42b719b3be8dbbd8cc2977106e746b87282d0eb84efa97f9e288b60e13ef04290b1d42eead4cdaf4f88b072b88420e7a264c6
7
+ data.tar.gz: e0ddc8dd3188cdce71cb4f64f738f71fc33f78d92521b03c154d6b861d427bffc77230cfa77f42111bf5154d21a803635321e496a0dbaad12b66f186851bedc9
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (C) 2015 Holger Joest <holger(at)joest.org>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # Overview
2
+
3
+ IPFS4R is a client library to access the [Interplanetary Filesystem (IPFS)](https://ipfs.io) from Ruby.
4
+
5
+ You can find more examples in the
6
+ [examples directory](https://github.com/hjoest/ruby-ipfs-api/tree/master/examples).
7
+
8
+ ## Installation
9
+
10
+ Use ``gem`` to install it
11
+
12
+ ```bash
13
+ gem install ipfs-api
14
+ ```
15
+
16
+ or simply add this line to your ``Gemfile``
17
+
18
+ ```ruby
19
+ gem 'ipfs-api', '~> 0.1.0'
20
+ ```
21
+
22
+ ## Basic examples
23
+
24
+ This example will add a directory to *IPFS*. The directory ``data``
25
+ must exist or otherwise an ``Errno::ENOENT`` error will be raised.
26
+
27
+ ```ruby
28
+ require 'ipfs-api'
29
+
30
+ ipfs = IPFS::Connection.new
31
+ ipfs.add Dir.new('data')
32
+ ```
33
+
34
+ ## Advanced
35
+
36
+ Dynamically add folders and files to *IPFS*, without creating them
37
+ on the local file system:
38
+
39
+ ```ruby
40
+ require 'ipfs-api'
41
+
42
+ ipfs = IPFS::Connection.new
43
+ folder = IPFS::Upload.folder('test') do |test|
44
+ test.add_file('hello.txt') do |fd|
45
+ fd.write 'Hello'
46
+ end
47
+ test.add_file('world.txt') do |fd|
48
+ fd.write 'World'
49
+ end
50
+ end
51
+ ipfs.add folder do |node|
52
+ # display each uploaded node:
53
+ print "#{node.name}: #{node.hash}\n" if node.finished?
54
+ end
55
+ ```
56
+
57
+ ## License
58
+
59
+ This library is distributed under the [MIT License](https://github.com/hjoest/ruby-ipfs-api/tree/master/LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,103 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rdoc/task'
5
+ require 'rubygems/package_task'
6
+
7
+ $:.unshift 'lib'
8
+ require 'ipfs-api/version'
9
+
10
+ PKG_NAME = 'ipfs-api'
11
+ PKG_VERSION = IPFS::VERSION
12
+ AUTHORS = ['Holger Joest']
13
+ EMAIL = 'holger@joest.org'
14
+ HOMEPAGE = 'http://ruby-ipfs-api.github.io'
15
+ SUMMARY = 'Interplanetary File System for Ruby'
16
+ DESCRIPTION = 'This is a client library to access the IPFS from Ruby'
17
+ RDOC_OPTIONS = [ '--title', SUMMARY, '--quiet', '--main', 'lib/ipfs-api.rb' ]
18
+ BUILD_FILES = [ 'Rakefile', 'ipfs-api.gemspec' ].sort
19
+ RDOC_FILES = [ 'README.md', 'LICENSE' ].sort
20
+ PKG_FILES = (BUILD_FILES + RDOC_FILES + Dir['{lib,test,examples}/**/*']).reject { |f| File.directory?(f) }.sort
21
+
22
+ task :default => [:test]
23
+
24
+ Rake::TestTask.new do |t|
25
+ t.libs << 'test'
26
+ t.test_files = ['test/test_*.rb']
27
+ end
28
+
29
+ RDoc::Task.new do |rd|
30
+ rd.rdoc_dir = 'rdoc'
31
+ rd.rdoc_files.include(RDOC_FILES, "lib/**/*.rb")
32
+ rd.options = RDOC_OPTIONS
33
+ end
34
+
35
+ CLEAN.include [ "*.gem*", "pkg", "rdoc" ]
36
+
37
+ spec = Gem::Specification.new do |s|
38
+ s.name = PKG_NAME
39
+ s.version = PKG_VERSION
40
+ s.authors = AUTHORS
41
+ s.email = EMAIL
42
+ s.homepage = HOMEPAGE
43
+ s.rubyforge_project = PKG_NAME
44
+ s.summary = SUMMARY
45
+ s.description = DESCRIPTION
46
+ s.platform = Gem::Platform::RUBY
47
+ s.licenses = ["MIT"]
48
+ s.require_path = 'lib'
49
+ s.executables = []
50
+ s.files = PKG_FILES
51
+ s.test_files = []
52
+ s.has_rdoc = true
53
+ s.extra_rdoc_files = RDOC_FILES
54
+ s.rdoc_options = RDOC_OPTIONS
55
+ s.required_ruby_version = ">= 1.9.3"
56
+ end
57
+
58
+ # also keep the gemspec up to date each time we package a tarball or gem
59
+ task :package => ['gem:update_gemspec']
60
+ task :gem => ['gem:update_gemspec']
61
+
62
+ Gem::PackageTask.new(spec) do |pkg|
63
+ pkg.gem_spec = spec
64
+ pkg.need_tar = true
65
+ pkg.need_zip = true
66
+ end
67
+
68
+ namespace :gem do
69
+
70
+ # thanks to the Merb project for this code.
71
+ desc "Update Github Gemspec"
72
+ task :update_gemspec do
73
+ skip_fields = %w(new_platform original_platform date cache_dir cache_file loaded)
74
+
75
+ result = "# WARNING : RAKE AUTO-GENERATED FILE. DO NOT MANUALLY EDIT!\n"
76
+ result << "# RUN : 'rake gem:update_gemspec'\n\n"
77
+ result << "Gem::Specification.new do |s|\n"
78
+ spec.instance_variables.sort.each do |ivar|
79
+ value = spec.instance_variable_get(ivar)
80
+ name = ivar.to_s.split("@").last
81
+ next if skip_fields.include?(name) || value.nil? || value == "" || (value.respond_to?(:empty?) && value.empty?)
82
+ if name == "dependencies"
83
+ value.each do |d|
84
+ dep, *ver = d.to_s.split(" ")
85
+ result << " s.add_dependency #{dep.inspect}, #{ver.join(" ").inspect.gsub(/[()]/, "")}\n"
86
+ end
87
+ else
88
+ case value
89
+ when Array
90
+ value = name != "files" ? value.inspect : value.sort.uniq.inspect.split(",").join(",\n")
91
+ when String, Fixnum, true, false
92
+ value = value.inspect
93
+ else
94
+ value = value.to_s.inspect
95
+ end
96
+ result << " s.#{name} = #{value}\n"
97
+ end
98
+ end
99
+ result << "end"
100
+ File.open(File.join(File.dirname(__FILE__), "#{spec.name}.gemspec"), "w"){|f| f << result}
101
+ end
102
+
103
+ end
data/examples/basic.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'ipfs-api'
2
+
3
+ ipfs = IPFS::Connection.new
4
+ ipfs.add Dir.new('data')
@@ -0,0 +1 @@
1
+ Hello World!
@@ -0,0 +1,15 @@
1
+ require 'ipfs-api'
2
+
3
+ ipfs = IPFS::Connection.new
4
+ folder = IPFS::Upload.folder('test') do |test|
5
+ test.add_file('hello.txt') do |fd|
6
+ fd.write 'Hello'
7
+ end
8
+ test.add_file('world.txt') do |fd|
9
+ fd.write 'World'
10
+ end
11
+ end
12
+ ipfs.add folder do |node|
13
+ # display each uploaded node:
14
+ print "#{node.name}: #{node.hash}\n" if node.finished?
15
+ end
data/ipfs-api.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ # WARNING : RAKE AUTO-GENERATED FILE. DO NOT MANUALLY EDIT!
2
+ # RUN : 'rake gem:update_gemspec'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.activated = false
6
+ s.authors = ["Holger Joest"]
7
+ s.bindir = "bin"
8
+ s.description = "This is a client library to access the IPFS from Ruby"
9
+ s.email = "holger@joest.org"
10
+ s.extra_rdoc_files = ["LICENSE", "README.md"]
11
+ s.files = ["LICENSE",
12
+ "README.md",
13
+ "Rakefile",
14
+ "examples/basic.rb",
15
+ "examples/data/hello.txt",
16
+ "examples/upload.rb",
17
+ "ipfs-api.gemspec",
18
+ "lib/ipfs-api.rb",
19
+ "lib/ipfs-api/connection.rb",
20
+ "lib/ipfs-api/io.rb",
21
+ "lib/ipfs-api/upload.rb",
22
+ "lib/ipfs-api/version.rb",
23
+ "test/common.rb",
24
+ "test/samples.rb",
25
+ "test/test_cmd_add.rb",
26
+ "test/test_cmd_cat.rb",
27
+ "test/test_cmd_get.rb",
28
+ "test/test_cmd_id.rb",
29
+ "test/test_cmd_ls.rb",
30
+ "test/test_cmd_name.rb",
31
+ "test/test_io.rb",
32
+ "test/test_upload.rb"]
33
+ s.full_name = "ipfs-api-0.1.0"
34
+ s.has_rdoc = true
35
+ s.homepage = "http://ruby-ipfs-api.github.io"
36
+ s.licenses = ["MIT"]
37
+ s.name = "ipfs-api"
38
+ s.platform = "ruby"
39
+ s.rdoc_options = ["--title", "Interplanetary File System for Ruby", "--quiet", "--main", "lib/ipfs-api.rb"]
40
+ s.require_paths = ["lib"]
41
+ s.required_ruby_version = ">= 1.9.3"
42
+ s.required_rubygems_version = ">= 0"
43
+ s.rubyforge_project = "ipfs-api"
44
+ s.rubygems_version = "2.4.8"
45
+ s.specification_version = 4
46
+ s.summary = "Interplanetary File System for Ruby"
47
+ s.version = "0.1.0"
48
+ end
data/lib/ipfs-api.rb ADDED
@@ -0,0 +1,12 @@
1
+ # =IPFS4R - Interplanetary Filesystem Library for Ruby
2
+ # License:: MIT (see the LICENSE file)
3
+ # Website:: https://ruby-ipfs-api.github.io
4
+ #
5
+ # ==Introduction
6
+ #
7
+ # IPFS4R is an IPFS[https://ipfs.io] library for Ruby.
8
+ #
9
+ require 'ipfs-api/version'
10
+ require 'ipfs-api/io'
11
+ require 'ipfs-api/upload'
12
+ require 'ipfs-api/connection'
@@ -0,0 +1,150 @@
1
+ require 'cgi'
2
+ require 'json'
3
+ require 'net/http'
4
+
5
+ module IPFS
6
+
7
+ class Connection
8
+
9
+ def initialize base_url = 'http://127.0.0.1:5001'
10
+ @base_url = base_url
11
+ end
12
+
13
+ def add nodes, &block
14
+ boundaries = [ generate_boundary ]
15
+ headers = {
16
+ 'Content-Disposition' => 'form-data: name="files"',
17
+ 'Content-Type' => "multipart/form-data; boundary=#{boundaries[0]}"
18
+ }
19
+ walker = Upload::TreeWalker.depth_first(nodes)
20
+ node_map = {}
21
+ stream = IO::ReadFromWriterIO.new do |buf|
22
+ next if walker.nil?
23
+ begin
24
+ node, depth = walker.next
25
+ node_map[node.path] = node
26
+ rescue StopIteration
27
+ depth = -1
28
+ walker = nil
29
+ end
30
+ while boundaries.size > depth+1 && boundary = boundaries.shift
31
+ buf << %Q{\
32
+ --#{boundary}--\r\n\
33
+ \r\n\
34
+ \r\n\
35
+ }
36
+ end
37
+ next if walker.nil?
38
+ if node.folder?
39
+ boundaries.unshift generate_boundary
40
+ buf << %Q{\
41
+ --#{boundaries[1]}\r\n\
42
+ Content-Disposition: form-data; name="file"; filename="#{node.path}"\r\n\
43
+ Content-Type: multipart/mixed; boundary=#{boundaries[0]}\r\n\
44
+ \r\n\
45
+ \r\n\
46
+ }
47
+ elsif node.file?
48
+ buf << %Q{\
49
+ --#{boundaries[0]}\r\n\
50
+ Content-Disposition: file; filename="#{node.path}"\r\n\
51
+ Content-Type: application/octet-stream\r\n\
52
+ \r\n\
53
+ #{node.content}\r\n\
54
+ }
55
+ else
56
+ raise "Unknown node type: #{node}"
57
+ end
58
+ end
59
+ nodes = []
60
+ post("add?encoding=json&r=true&progress=true", stream, headers) do |chunk|
61
+ next if chunk.empty?
62
+ upload = JSON.parse(chunk)
63
+ path, bytes, hash = ['Name', 'Bytes', 'Hash'].map { |p| upload[p] }
64
+ node = node_map[path]
65
+ node.bytes = bytes if bytes
66
+ node.hash = hash if hash
67
+ if block_given?
68
+ block.call(node)
69
+ elsif hash
70
+ nodes << node
71
+ end
72
+ end
73
+ block_given? ? nil : nodes
74
+ end
75
+
76
+ def cat path
77
+ result = ''
78
+ post("cat?arg=#{CGI.escape(path)}") do |chunk|
79
+ result << chunk
80
+ end
81
+ result
82
+ end
83
+
84
+ # FIXME: provides only raw response yet
85
+ def get path
86
+ result = ''
87
+ post("get?arg=#{CGI.escape(path)}") do |chunk|
88
+ result << chunk
89
+ end
90
+ result
91
+ end
92
+
93
+ def id
94
+ JSON.parse(post('id').body)['ID']
95
+ end
96
+
97
+ def ls path
98
+ JSON.parse(post("ls?arg=#{CGI.escape(path)}").body)
99
+ end
100
+
101
+ def name
102
+ NameCommand.new(self)
103
+ end
104
+
105
+ private
106
+ def post command, stream = nil, headers = {}, params = {}, &block # :nodoc:
107
+ uri = URI.parse("#{@base_url}/api/v0/#{command}")
108
+ http = Net::HTTP.new(uri.host, uri.port)
109
+ #http.set_debug_output $stderr
110
+ headers['User-Agent'] = "ruby-ipfs-api/#{VERSION}/"
111
+ headers['Transfer-Encoding'] = 'chunked'
112
+ request = Net::HTTP::Post.new(uri.request_uri, headers)
113
+ if stream
114
+ request.body_stream = stream
115
+ else
116
+ params['encoding'] = 'json'
117
+ params['stream-channels'] = 'true'
118
+ request.set_form_data(params)
119
+ end
120
+ http.request(request) do |response|
121
+ raise "Request failed: #{response.body}" if !response.kind_of?(Net::HTTPOK)
122
+ if block
123
+ response.read_body do |chunk|
124
+ block.call chunk
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ def generate_boundary # :nodoc:
131
+ (1..60).map { rand(16).to_s(16) }.join
132
+ end
133
+
134
+ class NameCommand # :nodoc:
135
+
136
+ def initialize connection
137
+ @connection = connection
138
+ end
139
+
140
+ def resolve
141
+ @connection.instance_exec(self) do
142
+ JSON.parse(post('name/resolve').body)['Path']
143
+ end
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+
150
+ end
@@ -0,0 +1,39 @@
1
+ require 'stringio'
2
+
3
+ module IPFS; end
4
+ module IPFS::IO # :nodoc:
5
+
6
+ class ReadFromWriterIO # :nodoc:
7
+
8
+ def initialize &block
9
+ @block = block
10
+ @stream = StringIO.new
11
+ fetch_data
12
+ end
13
+
14
+ def read length = nil, outbuf = ''
15
+ return nil if @stream.size == 0
16
+ outbuf.slice!(length..-1) if !length.nil?
17
+ q = 0
18
+ while @stream.size > 0
19
+ s = @stream.size - @p
20
+ s = [length - q, s].min if !length.nil?
21
+ outbuf[q, s] = @stream.string[@p, s]
22
+ @p += s
23
+ q += s
24
+ break if q == length
25
+ fetch_data if @stream.size == @p
26
+ end
27
+ outbuf
28
+ end
29
+
30
+ private
31
+ def fetch_data
32
+ @p = 0
33
+ @stream.string = ""
34
+ @block.call @stream if not @stream.closed?
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,182 @@
1
+ module IPFS; end
2
+ module IPFS::Upload
3
+
4
+ ##
5
+ # Define a file with the given name.
6
+ # file = IPFS::Upload.file('hello.txt') do |fd|
7
+ # fd.write 'Hello'
8
+ # end
9
+ # ipfs.add file do |node|
10
+ # print "Successfully uploaded #{node.path}\n" if node.finished?
11
+ # end
12
+ def file name, content = nil, &block
13
+ FileNode.new(name, content, &block)
14
+ end
15
+
16
+ ##
17
+ # Define a folder with the given *name*.
18
+ # folder = IPFS::Upload.folder('test') do |test|
19
+ # test.add_file('hello.txt') do |fd|
20
+ # fd.write 'Hello'
21
+ # end
22
+ # end
23
+ # ipfs.add folder do |node|
24
+ # print "Successfully uploaded #{node.path}\n" if node.finished?
25
+ # end
26
+ def folder name, &block
27
+ FolderNode.new(name, &block)
28
+ end
29
+
30
+ module_function :file, :folder
31
+
32
+ private
33
+
34
+ class Node # :nodoc:
35
+
36
+ attr_accessor :name, :parent, :bytes, :hash
37
+
38
+ def initialize name, parent = nil
39
+ raise "Name #{} must be a String" if not name.is_a?(String)
40
+ @name = name
41
+ @parent = parent
42
+ end
43
+
44
+ def path
45
+ @parent.nil? ? "/#{@name}" : "#{@parent.path}/#{@name}"
46
+ end
47
+
48
+ def file?
49
+ false
50
+ end
51
+
52
+ def folder?
53
+ false
54
+ end
55
+
56
+ def to_s
57
+ inspect
58
+ end
59
+
60
+ def finished?
61
+ !@hash.nil?
62
+ end
63
+
64
+ def inspect
65
+ s = "<#{@name}"
66
+ s << ":#{@bytes}" if @bytes
67
+ s << ":#{@hash}" if @hash
68
+ s << '>'
69
+ end
70
+
71
+ end
72
+
73
+ class FileNode < Node # :nodoc:
74
+
75
+ attr_reader :content
76
+
77
+ def initialize name, parent = nil, content = nil
78
+ super(name, parent)
79
+ if block_given?
80
+ @content = ''
81
+ yield self
82
+ else
83
+ @content = content.to_s
84
+ end
85
+ end
86
+
87
+ def write s
88
+ @content << s
89
+ end
90
+
91
+ def file?
92
+ true
93
+ end
94
+
95
+ def inspect
96
+ "file:#{super}"
97
+ end
98
+
99
+ end
100
+
101
+ class FolderNode < Node # :nodoc:
102
+
103
+ attr_accessor :children
104
+
105
+ def initialize name, parent = nil, &block
106
+ super(name, parent)
107
+ @children = []
108
+ block.call(self) if block_given?
109
+ end
110
+
111
+ def folder?
112
+ true
113
+ end
114
+
115
+ def add_node node
116
+ node.parent = self
117
+ (@children << node).last
118
+ end
119
+
120
+ def add_file file, content = nil, &block
121
+ (@children << FileNode.new(file, self, content, &block)).last
122
+ end
123
+
124
+ def add_folder folder, &block
125
+ (@children << FolderNode.new(folder, self, &block)).last
126
+ end
127
+
128
+ def inspect
129
+ "folder:#{super}#{children}"
130
+ end
131
+
132
+ end
133
+
134
+ module TreeWalker # :nodoc:
135
+
136
+ def depth_first nodes
137
+ nodes = [ nodes ] if not nodes.is_a?(Array)
138
+ stack = [ [ nodes.shift, 0 ] ]
139
+ Enumerator.new do |yielder|
140
+ while not stack.empty?
141
+ node, depth = stack.pop
142
+ node = resolve_node(node)
143
+ next if not node
144
+ yielder << [ node, depth ]
145
+ if node.folder?
146
+ stack += node.children.reverse.map { |n| [ n, depth + 1 ] }
147
+ end
148
+ if stack.empty? and not nodes.empty?
149
+ stack << [ nodes.shift, 0 ]
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ def resolve_node node
156
+ if node.is_a?(Node)
157
+ node
158
+ elsif node.is_a?(Dir)
159
+ FolderNode.new(File.basename(node.path)) do |d|
160
+ node.each do |child|
161
+ if child != '.' and child != '..'
162
+ child_path = File.join(node.path, child)
163
+ if File.directory?(child_path)
164
+ d.add_node resolve_node(Dir.new(child_path))
165
+ else
166
+ d.add_node resolve_node(File.new(child_path))
167
+ end
168
+ end
169
+ end
170
+ end
171
+ elsif node.is_a?(File)
172
+ FileNode.new(File.basename(node.path)) do |d|
173
+ d.write File.read(node.path)
174
+ end
175
+ end
176
+ end
177
+
178
+ module_function :depth_first, :resolve_node
179
+
180
+ end
181
+
182
+ end
@@ -0,0 +1,4 @@
1
+ module IPFS
2
+ VERSION = '0.1.0'
3
+ end
4
+
data/test/common.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'minitest/autorun'
2
+ require 'byebug'
3
+
4
+ $:.unshift File.expand_path('../../lib', __FILE__)
data/test/samples.rb ADDED
@@ -0,0 +1,84 @@
1
+ require 'tmpdir'
2
+ require 'test/common'
3
+ require 'ipfs-api/upload'
4
+
5
+ module Samples
6
+
7
+ include IPFS
8
+
9
+ def some_virtual_folders
10
+ fixture = [
11
+ Upload.folder('a1') { |a1|
12
+ a1.add_file('hello.txt') { |io|
13
+ io.write "Hello World!\n"
14
+ }
15
+ a1.add_file('foo.txt') { |io|
16
+ io.write "bar\n"
17
+ }
18
+ },
19
+ Upload.folder('a2') { |a2|
20
+ a2.add_file 'b1.txt', 'B1'
21
+ a2.add_folder('b2') { |b2|
22
+ b2.add_folder('c1') { |c1|
23
+ c1.add_file 'd1.txt', 'D1'
24
+ }
25
+ }
26
+ a2.add_file 'b3.txt', 'B3'
27
+ },
28
+ Upload.folder('a3') { |a3|
29
+ a3.add_folder('b1') { |b1|
30
+ b1.add_folder('c1') { |c1|
31
+ c1.add_folder('d1') { |d1|
32
+ d1.add_folder('e1') { |e1|
33
+ e1.add_file('thanks.txt') { |io|
34
+ io.write 'This is the end.'
35
+ }
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ]
42
+ expectation = {
43
+ '/a1' => 'QmcsmfcY8SQzNxJQYGZMHLXCkeTgxDBhASDPJyVEGi8Wrv',
44
+ '/a1/hello.txt' => 'QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG',
45
+ '/a1/foo.txt' => 'QmTz3oc4gdpRMKP2sdGUPZTAGRngqjsi99BPoztyP53JMM',
46
+ '/a2' => 'QmcfeG6dVvXufGXzxe6cBHP3ZbFx15yRzh7DSg8W67soto',
47
+ '/a2/b1.txt' => 'QmSwyJZAaxRqo8v2itCErP8U4DKa3dkSu7qTpDF1qG64Vw',
48
+ '/a2/b2' => 'QmQZ7ek8ss65DQFbCxXgFBzZeyJA6ZYJ9SfrTWZDSSQ2jj',
49
+ '/a2/b2/c1' => 'QmU2K25J3hBJQeKuUTJeXpeCovev8Bp2m2FzFHU2ANznnE',
50
+ '/a2/b2/c1/d1.txt' => 'QmNPDoyE8HaJWj7Bb7p2h3usA2nmbmUCx2712jXK2nftxz',
51
+ '/a2/b3.txt' => 'QmdoSx7tA3ybphBXDR9TBNteYPHKKb8aySPLVStNkSaTy2',
52
+ '/a3' => 'QmeQ7BYviWZynBhhzMCJVZRv5izgCFBfkGMU8fJJtzUA3f',
53
+ '/a3/b1' => 'QmW7zVapNEqc7Gmhx6ZGkeNzgUMgcRxpjXkXSkWdoyUWd5',
54
+ '/a3/b1/c1' => 'QmfHyLbTMjfUeD95wCmNNf4h5kJo3D65tEERs54zbRbWvv',
55
+ '/a3/b1/c1/d1' => 'QmRMzLcUNFghRE9Cn62wBHThKJoS6ChjpgEmJwApJBPoVo',
56
+ '/a3/b1/c1/d1/e1' => 'QmdJWhD7iU2kW5wTWP2hXoworetabt3n5tEtfEUyBoXCTv',
57
+ '/a3/b1/c1/d1/e1/thanks.txt' => 'QmWu5tSQetrKPxhDff2AF8owzqcMreXdXqeVjr3LL4WyJX'
58
+ }
59
+ yield fixture, expectation
60
+ end
61
+ module_function :some_virtual_folders
62
+
63
+ def some_filesystem_folders
64
+ Dir.mktmpdir('ruby-ipfs-api-unit-test-') do |root|
65
+ a1 = File.join(root, 'a1')
66
+ Dir.mkdir(a1, 0755)
67
+ b1 = File.join(a1, 'b1')
68
+ Dir.mkdir(b1, 0755)
69
+ hello = File.join(b1, 'hello.txt')
70
+ File.open hello, 'w' do |fd|
71
+ fd.write "Hello World!\n"
72
+ end
73
+ fixture = [ Dir.new(a1) ]
74
+ expectation = {
75
+ '/a1'=>'QmedYJNEKn656faSHaMv5UFVkgfSzwYf9u4zsYoXqgvnch',
76
+ '/a1/b1' => 'QmSh4Xjoy16v6XmnREE1yCrPM1dnizZc2h6LfrqXsnbBV7',
77
+ '/a1/b1/hello.txt' => 'QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG'
78
+ }
79
+ yield fixture, expectation
80
+ end
81
+ end
82
+ module_function :some_filesystem_folders
83
+
84
+ end
@@ -0,0 +1,40 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ require 'test/samples'
4
+ require 'ipfs-api'
5
+
6
+ include IPFS
7
+
8
+ class CommandAddTest < Minitest::Test
9
+
10
+ def test_adding_some_filesystem_folders
11
+ ipfs = Connection.new
12
+ Samples.some_filesystem_folders do |fixture, expectation|
13
+ actual = ipfs.add(fixture)
14
+ assert_equal expectation, Hash[actual.map { |n| [ n.path, n.hash ] }]
15
+ end
16
+ end
17
+
18
+ def test_adding_some_filesystem_folders_with_block
19
+ ipfs = Connection.new
20
+ Samples.some_filesystem_folders do |fixture, expectation|
21
+ actual = {}
22
+ ipfs.add fixture do |node|
23
+ actual[node.path] = node.hash
24
+ end
25
+ assert_equal expectation, actual
26
+ end
27
+ end
28
+
29
+ def test_adding_some_virtual_folders
30
+ ipfs = Connection.new
31
+ Samples.some_virtual_folders do |fixture, expectation|
32
+ actual = {}
33
+ ipfs.add fixture do |node|
34
+ actual[node.path] = node.hash
35
+ end
36
+ assert_equal expectation, actual
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,19 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ require 'test/samples'
4
+ require 'ipfs-api'
5
+
6
+ include IPFS
7
+
8
+ class CommandCatTest < Minitest::Test
9
+
10
+ def test_cat
11
+ ipfs = Connection.new
12
+ Samples.some_virtual_folders do |fixture, expectation|
13
+ ipfs.add fixture
14
+ actual = ipfs.cat('QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG')
15
+ assert_equal "Hello World!\n", actual
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,19 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ require 'test/samples'
4
+ require 'ipfs-api'
5
+
6
+ include IPFS
7
+
8
+ class CommandGetTest < Minitest::Test
9
+
10
+ def test_get
11
+ ipfs = Connection.new
12
+ Samples.some_virtual_folders do |fixture, expectation|
13
+ ipfs.add fixture
14
+ # FIXME: provides only raw response yet
15
+ actual = ipfs.get('QmedYJNEKn656faSHaMv5UFVkgfSzwYf9u4zsYoXqgvnch')
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,17 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ require 'test/common'
4
+ require 'ipfs-api'
5
+
6
+ include IPFS
7
+
8
+ class CommandIdTest < Minitest::Test
9
+
10
+ def test_id
11
+ ipfs = Connection.new
12
+ id = ipfs.id
13
+ assert_equal 46, id.size
14
+ assert id.start_with?('Qm')
15
+ end
16
+
17
+ end
@@ -0,0 +1,40 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ require 'test/samples'
4
+ require 'ipfs-api'
5
+
6
+ include IPFS
7
+
8
+ class CommandLsTest < Minitest::Test
9
+
10
+ def test_ls
11
+ ipfs = Connection.new
12
+ Samples.some_virtual_folders do |fixture, expectation|
13
+ ipfs.add fixture
14
+ actual = ipfs.ls('QmcsmfcY8SQzNxJQYGZMHLXCkeTgxDBhASDPJyVEGi8Wrv')
15
+ expectation = {
16
+ 'Objects' => [
17
+ {
18
+ 'Hash' => 'QmcsmfcY8SQzNxJQYGZMHLXCkeTgxDBhASDPJyVEGi8Wrv',
19
+ 'Links' => [
20
+ {
21
+ 'Name' => 'foo.txt',
22
+ 'Hash' => 'QmTz3oc4gdpRMKP2sdGUPZTAGRngqjsi99BPoztyP53JMM',
23
+ 'Size' => 12,
24
+ 'Type' => 2
25
+ },
26
+ {
27
+ 'Name' => 'hello.txt',
28
+ 'Hash' => 'QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG',
29
+ 'Size' => 21,
30
+ 'Type' => 2
31
+ }
32
+ ]
33
+ }
34
+ ]
35
+ }
36
+ assert_equal expectation, actual
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,16 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ require 'test/common'
4
+ require 'ipfs-api'
5
+
6
+ include IPFS
7
+
8
+ class CommandNameTest < Minitest::Test
9
+
10
+ def test_name_resolve
11
+ ipfs = Connection.new
12
+ resolved = ipfs.name.resolve
13
+ assert resolved.start_with?('/ipfs/Qm')
14
+ end
15
+
16
+ end
data/test/test_io.rb ADDED
@@ -0,0 +1,20 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ require 'test/samples'
4
+ require 'ipfs-api/io'
5
+
6
+ include IPFS::IO
7
+
8
+ class ReadFromWriterIOTest < Minitest::Test
9
+
10
+ def test_read_write_io
11
+ msg = ('a'..'z').to_a.join
12
+ reader = ReadFromWriterIO.new do |writer|
13
+ writer << msg
14
+ writer.close
15
+ end
16
+ result = reader.read
17
+ assert_equal msg, result
18
+ end
19
+
20
+ end
@@ -0,0 +1,20 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+
3
+ require 'test/samples'
4
+ require 'ipfs-api/upload'
5
+
6
+ class NodeTest < Minitest::Test
7
+
8
+ include IPFS
9
+
10
+ def test_tree_walker
11
+ Samples.some_virtual_folders do |fixture, expectations|
12
+ walker = Upload::TreeWalker.depth_first(fixture)
13
+ actual = walker.to_a
14
+ assert_equal 15, actual.size
15
+ paths = actual.map { |item| item.first.path }
16
+ assert_equal expectations.map { |item| item.first }, paths
17
+ end
18
+ end
19
+
20
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ipfs-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Holger Joest
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: This is a client library to access the IPFS from Ruby
14
+ email: holger@joest.org
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files:
18
+ - LICENSE
19
+ - README.md
20
+ files:
21
+ - LICENSE
22
+ - README.md
23
+ - Rakefile
24
+ - examples/basic.rb
25
+ - examples/data/hello.txt
26
+ - examples/upload.rb
27
+ - ipfs-api.gemspec
28
+ - lib/ipfs-api.rb
29
+ - lib/ipfs-api/connection.rb
30
+ - lib/ipfs-api/io.rb
31
+ - lib/ipfs-api/upload.rb
32
+ - lib/ipfs-api/version.rb
33
+ - test/common.rb
34
+ - test/samples.rb
35
+ - test/test_cmd_add.rb
36
+ - test/test_cmd_cat.rb
37
+ - test/test_cmd_get.rb
38
+ - test/test_cmd_id.rb
39
+ - test/test_cmd_ls.rb
40
+ - test/test_cmd_name.rb
41
+ - test/test_io.rb
42
+ - test/test_upload.rb
43
+ homepage: http://ruby-ipfs-api.github.io
44
+ licenses:
45
+ - MIT
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options:
49
+ - "--title"
50
+ - Interplanetary File System for Ruby
51
+ - "--quiet"
52
+ - "--main"
53
+ - lib/ipfs-api.rb
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.9.3
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project: ipfs-api
68
+ rubygems_version: 2.4.8
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Interplanetary File System for Ruby
72
+ test_files: []