rb1drv 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: feafbb64ce01c80b2c8f55c4d62dbed44aa6bca0d908965d94700a01def35f8a
4
+ data.tar.gz: 1b31de1595f55f7ecc4f40da51979a87fc72cb0ee6602768af2a6f7a08319661
5
+ SHA512:
6
+ metadata.gz: 9a09646c4cbb6c1afc6e65f7bf2332865a5eae3afe32028b053908c21bacbeec8338e6b31f47176632c6939502971e9962627602528fd6f9eb68765ab9ebeaa2
7
+ data.tar.gz: 37cf356d74830003591bf77c5d3328d354cdfdd46f112b31fddf7baaf029f9ca23318cf782a1a228fd2c4e9842971fcef7f38d39bea5151fb4afb38f64321b31
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3
4
+ - 2.4
5
+ - 2.5
6
+ script: bundle exec ruby -I lib lib/rb1drv.rb
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rb1drv (0.1.1)
5
+ excon (~> 0.62)
6
+ oauth2 (~> 1.4)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ excon (0.62.0)
12
+ faraday (0.12.2)
13
+ multipart-post (>= 1.2, < 3)
14
+ jwt (1.5.6)
15
+ multi_json (1.13.1)
16
+ multi_xml (0.6.0)
17
+ multipart-post (2.0.0)
18
+ oauth2 (1.4.0)
19
+ faraday (>= 0.8, < 0.13)
20
+ jwt (~> 1.0)
21
+ multi_json (~> 1.3)
22
+ multi_xml (~> 0.5)
23
+ rack (>= 1.2, < 3)
24
+ rack (2.0.5)
25
+ rake (10.5.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ bundler (~> 1.16)
32
+ rake (~> 10.0)
33
+ rb1drv!
34
+
35
+ BUNDLED WITH
36
+ 1.16.1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Xinyue Lu
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,78 @@
1
+ # Rb1drv
2
+
3
+ [![Build Status](https://travis-ci.org/msg7086/rb1drv.svg?branch=master)](https://travis-ci.org/msg7086/rb1drv)
4
+
5
+ Rb1drv is a Ruby SDK for Microsoft OneDrive service, providing a simple interface to access files inside OneDrive.
6
+
7
+ Rb1drv allows you to list directories, upload or download files, etc.
8
+
9
+ To use the command line application, install [`rb1drv-tools`](https://github.com/msg7086/rb1drv-tools) gem instead.
10
+
11
+ Further functionalities can be added to the library upon requests.
12
+
13
+ Rb1drv uses the latest Microsoft OAuth2 + Graph API at the time it is written, while there are not many other libraries available for reference (e.g. official OneDrive SDK still uses old OAuth2 API instead of new OAuth2 v2.0 API). Feel free to take this as an unoffical reference implementation and write your own SDK.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'rb1drv'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install rb1drv
30
+
31
+ ## Usage
32
+
33
+ You will have to register a new application on Microsoft Application Registration Portal before using the API.
34
+ Read more at [OneDrive API Docs](https://github.com/OneDrive/onedrive-api-docs/blob/live/docs/rest-api/getting-started/graph-oauth.md).
35
+
36
+ od = OneDrive.new('a2b3c4d5-your-app-id', 'C8V3{your-app-secret(', 'https://your-callback/url')
37
+
38
+ To start using `OneDrive` library, instanciate the class with your application information.
39
+
40
+ ---
41
+
42
+ od.root
43
+ od.get('/Folder1')
44
+ od.get('/File1.avi')
45
+
46
+ Use `OneDrive#root` or `OneDrive#get` to get a drive item.
47
+
48
+ ---
49
+
50
+ od.root.children
51
+ od.root.children.grep(OneDriveDir)
52
+
53
+ Use `OneDriveDir#children` to get contents of a directory.
54
+
55
+ ---
56
+
57
+ od.get('/File1.avi').save_as('/tmp/test.avi', overwrite: true) do |event, stat|
58
+ puts "Downloaded #{stat[:progress]} of #{stat[:total]}" if event == :progress
59
+ end
60
+
61
+ Use `OneDriveFile#save_as` to download a file.
62
+
63
+ ---
64
+
65
+ od.get('/Folder1').upload('/tmp/test.avi', overwrite: true, target_name: 'party.avi') do |event, stat|
66
+ puts "Uploading #{stat[:progress]} of #{stat[:total]} for segment #{stat[:from]}-#{stat[:to]}" if event == :progress
67
+ puts "Uploaded segment #{stat[:from]}-#{stat[:to]}" if event == :finish_segment
68
+ end
69
+
70
+ Use `OneDriveDir#upload` to upload a file to target directory.
71
+
72
+ ## Contributing
73
+
74
+ Bug reports and pull requests are welcome on GitHub at https://github.com/msg7086/rb1drv.
75
+
76
+ ## License
77
+
78
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,29 @@
1
+ module Rb1drv
2
+ class OneDrive
3
+ # Gets authorize URL to start authentication process
4
+ #
5
+ # @return [String] the authorize URL
6
+ def auth_url
7
+ @oauth2_client.auth_code.authorize_url(
8
+ redirect_uri: @callback_url,
9
+ scope: 'openid offline_access https://graph.microsoft.com/Files.ReadWrite.All'
10
+ )
11
+ end
12
+
13
+ # Gets access token from authorize code
14
+ #
15
+ # @return [OAuth2::AccessToken] the access token
16
+ def auth_access(auth_code)
17
+ @access_token = @oauth2_client.auth_code.get_token(auth_code, redirect_uri: @callback_url)
18
+ end
19
+
20
+ # Loads previously retrieved access token from Hash
21
+ #
22
+ # @return [OAuth2::AccessToken] the access token
23
+ def auth_load(access_token)
24
+ @access_token = OAuth2::AccessToken.from_hash(@oauth2_client, access_token)
25
+ @access_token = @access_token.refresh! if @access_token.expired?
26
+ @access_token
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ module Rb1drv
2
+ class OneDrive
3
+ # Get root directory object.
4
+ #
5
+ # @return [OneDriveDir] your root
6
+ def root
7
+ @_root_dir ||= OneDriveDir.new(self, request('drive/root'))
8
+ end
9
+
10
+ # Get an object by an arbitary path.
11
+ #
12
+ # @return [OneDriveDir,OneDriveFile] the drive item you asked
13
+ def get(path)
14
+ path = "/#{path}" unless path[0] == '/'
15
+ OneDriveItem.smart_new(self, request("drive/root:#{path}"))
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,136 @@
1
+ require 'rb1drv/sliced_io'
2
+
3
+ module Rb1drv
4
+ class OneDriveDir < OneDriveItem
5
+ attr_reader :child_count
6
+ def initialize(od, api_hash)
7
+ super
8
+ @child_count = api_hash.dig('folder', 'childCount')
9
+ end
10
+
11
+ # Lists contents of current directory.
12
+ #
13
+ # @return [Array<OneDriveDir,OneDriveFile>] directories and files whose parent is current directory
14
+ def children
15
+ return [] if child_count <= 0
16
+ @od.request("drive/items/#{@id}/children")['value'].map do |child|
17
+ OneDriveItem.smart_new(@od, child)
18
+ end
19
+ end
20
+
21
+ # Get an object by an arbitary path related to current directory.
22
+ #
23
+ # To get an absolute path, make use of OneDrive#get and not this.
24
+ #
25
+ # @param path [String] path relative to current directory
26
+ #
27
+ # @return [OneDriveDir,OneDriveFile] the drive item you asked
28
+ def get(path)
29
+ path = "/#{path}" unless path[0] == '/'
30
+ OneDriveItem.smart_new(self, @od.request("drive/items/#{@id}:#{path}"))
31
+ end
32
+
33
+ # Yes
34
+ def dir?
35
+ true
36
+ end
37
+
38
+ # No
39
+ def file?
40
+ false
41
+ end
42
+
43
+ # @return [String] absolute path of current item
44
+ def absolute_path
45
+ if @parent_path
46
+ File.join(@parent_path, @name)
47
+ else
48
+ '/'
49
+ end
50
+ end
51
+
52
+ # Recursively creates empty directories.
53
+ #
54
+ # @param name [String] directories you'd like to create
55
+ # @return [OneDriveDir] the directory you created
56
+ def mkdir(name)
57
+ newdir, *remainder = name.split('/')
58
+ subdir = @od.request("drive/items/#{@id}:/#{newdir}") rescue nil
59
+ unless subdir
60
+ subdir = @od.request("drive/items/#{@id}/children",
61
+ name: newdir,
62
+ folder: {},
63
+ '@microsoft.graph.conflictBehavior': 'rename'
64
+ )
65
+ end
66
+ subdir = OneDriveDir.new(@od, subdir)
67
+ remainder.any? ? subdir.mkdir(remainder.join('/')) : subdir
68
+ end
69
+
70
+ # Uploads a local file into current remote directory using large file uploading mode.
71
+ #
72
+ # Unfinished download is stored as +target_name.incomplete+ and renamed upon completion.
73
+ #
74
+ # @param filename [String] local filename you'd like to upload
75
+ # @param overwrite [Boolean] whether to overwrite remote file, or rename this
76
+ # @param fragment_size [Integer] fragment size for each upload session, recommended to be multiple of 320KiB
77
+ # @param chunk_size [Integer] IO size for each disk read request and progress notification
78
+ # @param target_name [String] desired remote filename, a relative path to current directory
79
+ #
80
+ # @yield [event, status] for receive progress notification
81
+ # @yieldparam event [Symbol] event of this notification
82
+ # @yieldparam status [{Symbol => String,Integer}] details
83
+ def upload(filename, overwrite: false, fragment_size: 41_943_040, chunk_size: 1_048_576, target_name: nil, &block)
84
+ raise ArgumentError.new('File not found') unless File.exist?(filename)
85
+ file_size = File.size(filename)
86
+ resume_file = "#{filename}.1drv_upload"
87
+ resume_session = JSON.parse(File.read(resume_file)) rescue nil if File.exist?(resume_file)
88
+
89
+ if resume_session && resume_session['session_url']
90
+ conn = Excon.new(resume_session['session_url'])
91
+ result = JSON.parse(conn.get.body)
92
+ resume_position = result.dig('nextExpectedRanges', 0)&.split('-')&.first&.to_i or resume_session = nil
93
+ end
94
+
95
+ resume_position ||= 0
96
+
97
+ if resume_session
98
+ file_size == resume_session['source_size'] or resume_session = nil
99
+ end
100
+
101
+ unless resume_session
102
+ target_name ||= File.basename(filename)
103
+ result = @od.request("drive/items/#{@id}:/#{target_name}:/createUploadSession", item: {'@microsoft.graph.conflictBehavior': overwrite ? 'replace' : 'rename'})
104
+ resume_session = {
105
+ 'session_url' => result['uploadUrl'],
106
+ 'source_size' => File.size(filename),
107
+ 'fragment_size' => fragment_size
108
+ }
109
+ File.write(resume_file, JSON.pretty_generate(resume_session))
110
+ end
111
+
112
+ new_file = nil
113
+ File.open(filename, mode: 'rb', external_encoding: Encoding::BINARY) do |f|
114
+ resume_position.step(file_size, resume_session['fragment_size']) do |from|
115
+ to = [from + resume_session['fragment_size'], file_size].min - 1
116
+ len = to - from + 1
117
+ headers = {
118
+ 'Content-Length': len.to_s,
119
+ 'Content-Range': "bytes #{from}-#{to}/#{file_size}"
120
+ }
121
+ @od.logger.info "Uploading #{from}-#{to}/#{file_size}"
122
+ yield :new_segment, file: filename, from: from, to: to if block_given?
123
+ sliced_io = SlicedIO.new(f, from, to) do |progress, total|
124
+ yield :progress, file: filename, from: from, to: to, progress: progress, total: total if block_given?
125
+ end
126
+ result = conn.put headers: headers, chunk_size: chunk_size, body: sliced_io
127
+ yield :finish_segment, file: filename, from: from, to: to if block_given?
128
+ result = JSON.parse(result.body)
129
+ new_file = OneDriveFile.new(@od, result) if result.dig('file')
130
+ end
131
+ File.unlink(resume_file)
132
+ end
133
+ new_file
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,61 @@
1
+ module Rb1drv
2
+ class OneDriveFile < OneDriveItem
3
+ attr_reader :download_url
4
+ def initialize(od, api_hash)
5
+ super
6
+ @download_url = api_hash.dig('@microsoft.graph.downloadUrl')
7
+ end
8
+
9
+ # No
10
+ def dir?
11
+ false
12
+ end
13
+
14
+ # Yes
15
+ def file?
16
+ true
17
+ end
18
+
19
+ # Saves current remote file as local file.
20
+ #
21
+ # Unfinished download is stored as +target_name.incomplete+ and renamed upon completion.
22
+ #
23
+ # @param target_name [String] desired local filename, a relative path to current directory or an absolute path
24
+ # @param overwrite [Boolean] whether to overwrite local file, or skip this
25
+ # @param resume [Boolean] whether to resume an unfinished download, or start over anyway
26
+ #
27
+ # @yield [event, status] for receive progress notification
28
+ # @yieldparam event [Symbol] event of this notification
29
+ # @yieldparam status [{Symbol => String,Integer}] details
30
+ def save_as(target_name=nil, overwrite: false, resume: true, &block)
31
+ target_name ||= @name
32
+ tmpfile = "#{target_name}.incomplete"
33
+
34
+ return if !overwrite && File.exist?(target_name)
35
+
36
+ if resume && File.size(tmpfile) > 0
37
+ from = File.size(tmpfile)
38
+ len = @size - from
39
+ fmode = 'ab'
40
+ headers = {
41
+ 'Range': "bytes=#{from}-"
42
+ }
43
+ else
44
+ from = 0
45
+ len = @size
46
+ fmode = 'wb'
47
+ headers = {}
48
+ end
49
+
50
+ yield :new_segment, file: target_name, from: from if block_given?
51
+ File.open(tmpfile, mode: fmode, external_encoding: Encoding::BINARY) do |f|
52
+ Excon.get download_url, headers: headers, response_block: ->(chunk, remaining_bytes, total_bytes) do
53
+ f.write(chunk)
54
+ yield :progress, file: target_name, from: from, progress: total_bytes - remaining_bytes, total: total_bytes if block_given?
55
+ end
56
+ end
57
+ yield :finish_segment, file: target_name if block_given?
58
+ FileUtils.mv(tmpfile, filename)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,33 @@
1
+ module Rb1drv
2
+ class OneDriveItem
3
+ attr_reader :id, :name, :eTag, :size, :mtime, :ctime, :muser, :cuser, :parent_path
4
+ protected
5
+ def initialize(od, api_hash)
6
+ @od = od
7
+ %w(id name eTag size).each do |key|
8
+ instance_variable_set("@#{key}", api_hash[key])
9
+ end
10
+ @mtime = Time.iso8601(api_hash.dig('lastModifiedDateTime'))
11
+ @ctime = Time.iso8601(api_hash.dig('createdDateTime'))
12
+ @muser = api_hash.dig('lastModifiedBy', 'user', 'displayName') || 'N/A'
13
+ @cuser = api_hash.dig('createdBy', 'user', 'displayName') || 'N/A'
14
+ @parent_path = api_hash.dig('parentReference', 'path')
15
+ end
16
+
17
+ # Create subclass instance by checking the item type
18
+ #
19
+ # @return [OneDriveFile, OneDriveDir] instanciated drive item
20
+ def self.smart_new(od, item_hash)
21
+ item_hash['file'] ? OneDriveFile.new(od, item_hash) : OneDriveDir.new(od, item_hash)
22
+ end
23
+
24
+ # @return [String] absolute path of current item
25
+ def absolute_path
26
+ if @parent_path
27
+ File.join(@parent_path, @name)
28
+ else
29
+ @name
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ # SlicedIO slices a large File into a small portion.
2
+ class SlicedIO
3
+ def initialize(io, from, to, &block)
4
+ @io = io
5
+ @from = from
6
+ @to = to
7
+ @block = block
8
+ @current = 0
9
+ end
10
+
11
+ def rewind
12
+ io.seek(from)
13
+ @current = 0
14
+ end
15
+
16
+ def size
17
+ @size ||= @to - @from + 1
18
+ end
19
+
20
+ def read(len)
21
+ return nil if @current >= size
22
+ len = [len, @to - @current + 1].min
23
+ # Notify before we read
24
+ @block.call(@current, size)
25
+ @io.read(len)
26
+ ensure
27
+ @current += len
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Rb1drv
2
+ VERSION = "0.1.2"
3
+ end
data/lib/rb1drv.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'excon'
2
+ require 'oauth2'
3
+ require "rb1drv/version"
4
+
5
+ module Rb1drv
6
+ # Base class to support oauth2 authentication and sending simple API requests.
7
+ #
8
+ # Call +#root+ or +#get+ to get an +OneDriveDir+ or +OneDriveFile+ to wotk with.
9
+ class OneDrive
10
+ attr_reader :oauth2_client, :logger, :access_token
11
+ # Instanciates with app id and secret.
12
+ def initialize(client_id, client_secret, callback_url, logger=Logger.new(STDERR))
13
+ @client_id = client_id
14
+ @client_secret = client_secret
15
+ @callback_url = callback_url
16
+ @logger = logger
17
+ @oauth2_client = OAuth2::Client.new client_id, client_secret,
18
+ authorize_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
19
+ token_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
20
+ @conn = Excon.new('https://graph.microsoft.com/', persistent: true)
21
+ @conn.logger = @logger
22
+ end
23
+
24
+ # Issues requests to API endpoint.
25
+ #
26
+ # @param uri [String] relative path of the API
27
+ # @param data [Hash] JSON data to be post
28
+ # @param verb [Symbol] HTTP request verb if data is given
29
+ #
30
+ # @return [Hash] response from API.
31
+ def request(uri, data=nil, verb=:post)
32
+ @logger.info(uri)
33
+ query = {
34
+ path: File.join('v1.0/me/', uri),
35
+ headers: {
36
+ 'Authorization': "Bearer #{@access_token.token}"
37
+ }
38
+ }
39
+ if data
40
+ query[:body] = JSON.generate(data)
41
+ query[:headers]['Content-Type'] = 'application/json'
42
+ @logger.info(query[:body])
43
+ verb = :post unless [:post, :put, :delete].include?(verb)
44
+ response = @conn.send(verb, query)
45
+ else
46
+ response = @conn.get(query)
47
+ end
48
+ JSON.parse(response.body)
49
+ end
50
+ end
51
+ end
52
+
53
+ require 'rb1drv/auth'
54
+ require 'rb1drv/onedrive'
55
+ require 'rb1drv/onedrive_item'
56
+ require 'rb1drv/onedrive_dir'
57
+ require 'rb1drv/onedrive_file'
data/rb1drv.gemspec ADDED
@@ -0,0 +1,28 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "rb1drv/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rb1drv"
8
+ spec.version = Rb1drv::VERSION
9
+ spec.authors = ["Xinyue Lu"]
10
+ spec.email = ["i@7086.in"]
11
+
12
+ spec.summary = "Ruby OneDrive Library"
13
+ spec.homepage = "https://github.com/msg7086/rb1drv"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+ spec.required_ruby_version = '>= 2.3'
23
+
24
+ spec.add_dependency "oauth2", "~> 1.4"
25
+ spec.add_dependency "excon", "~> 0.62"
26
+ spec.add_development_dependency "bundler", "~> 1.16"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rb1drv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Xinyue Lu
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-05-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: oauth2
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: excon
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.62'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.62'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ description:
70
+ email:
71
+ - i@7086.in
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - LICENSE.txt
81
+ - README.md
82
+ - lib/rb1drv.rb
83
+ - lib/rb1drv/auth.rb
84
+ - lib/rb1drv/onedrive.rb
85
+ - lib/rb1drv/onedrive_dir.rb
86
+ - lib/rb1drv/onedrive_file.rb
87
+ - lib/rb1drv/onedrive_item.rb
88
+ - lib/rb1drv/sliced_io.rb
89
+ - lib/rb1drv/version.rb
90
+ - rb1drv.gemspec
91
+ homepage: https://github.com/msg7086/rb1drv
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '2.3'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.7.6
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Ruby OneDrive Library
115
+ test_files: []