safrano 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/multipart.rb +182 -0
- data/lib/odata/batch.rb +60 -127
- data/lib/odata/collection.rb +0 -2
- data/lib/odata/collection_order.rb +0 -1
- data/lib/odata/entity.rb +0 -1
- data/lib/odata/error.rb +0 -1
- data/lib/odata/relations.rb +0 -1
- data/lib/odata/walker.rb +2 -2
- data/lib/rack_app.rb +9 -3
- data/lib/safrano.rb +1 -0
- data/lib/service.rb +2 -2
- metadata +37 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4af1e3f2a6c005cb7269a3eb1a0f3d9f4de7c46aa76a79323b2b4052599e41ed
|
4
|
+
data.tar.gz: c7293279d1b38862dd8c26e8e98c8f90ca3cf75f0111ef7bf7f5c3994a6d9d44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca004d2c4842f70b6032f0d4d3930d02df98f7d29dc661bba3e8fa4e54fd5b9617dd640fb1333be8af7e8a110f778956f7e62c0c42f64fe7dfdf65804793dc5d
|
7
|
+
data.tar.gz: '09cdef8944addc559a2b7231344dd25b216965e42ed4f0e4e71b7e400bcb6a23a0070a65d250897cf44e8a5b363b72174edb847ecd787204650ed873343f1db2'
|
data/lib/multipart.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Simple multipart support for OData $batch purpose
|
4
|
+
|
5
|
+
module Multi
|
6
|
+
RETNL = "\r\n".freeze
|
7
|
+
HTTP_VERB_URI_REGEXP = /^(POST|GET|PUT|PATCH)\s+(\S*)\s?(\S*)$/.freeze
|
8
|
+
HEADER_REGEXP = %r{^([a-zA-Z\-]+):\s*([0-9a-zA-Z\-\/,\s]+;?\S*)\s*$}.freeze
|
9
|
+
module Parts
|
10
|
+
class Base
|
11
|
+
attr_accessor :parts
|
12
|
+
attr_reader :body
|
13
|
+
attr_reader :headers
|
14
|
+
|
15
|
+
def initialize(boundary)
|
16
|
+
@boundary = boundary
|
17
|
+
@headers = {}
|
18
|
+
@body = ''
|
19
|
+
@parts = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def finalize
|
23
|
+
@parts.each do |part|
|
24
|
+
@body << "--#{@boundary}#{RETNL}"
|
25
|
+
@body << part.message_s
|
26
|
+
@body << RETNL
|
27
|
+
end
|
28
|
+
@body << "--#{@boundary}--#{RETNL}"
|
29
|
+
@headers['Content-Length'] = @body.bytesize.to_s
|
30
|
+
@body
|
31
|
+
end
|
32
|
+
end
|
33
|
+
class Mixed < Base
|
34
|
+
def initialize(boundary)
|
35
|
+
super(boundary)
|
36
|
+
@headers['Content-Type'] = "multipart/mixed;boundary=#{@boundary}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def shadow_copy
|
40
|
+
self.class.new(@boundary)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.parse(inp, boundary)
|
44
|
+
@mmboundary = "--#{boundary}"
|
45
|
+
ret = Multi::Parts::Mixed.new(boundary)
|
46
|
+
inp.split(@mmboundary).each do |p|
|
47
|
+
ret.parts << parse_part(p) unless (p.strip == '--') || p.empty?
|
48
|
+
end
|
49
|
+
ret
|
50
|
+
end
|
51
|
+
|
52
|
+
# Ultrasimplified parser...
|
53
|
+
def self.parse_part(inp)
|
54
|
+
state = :start
|
55
|
+
ct_headers = {}
|
56
|
+
headers = {}
|
57
|
+
body_str = ''
|
58
|
+
http_method = nil
|
59
|
+
uri = nil
|
60
|
+
inp.each_line do |l|
|
61
|
+
next if l.strip.empty?
|
62
|
+
|
63
|
+
case state
|
64
|
+
when :start, :ohd
|
65
|
+
md = l.strip.match(HEADER_REGEXP)
|
66
|
+
|
67
|
+
if md
|
68
|
+
state = :ohd
|
69
|
+
ct_headers[md[1]] = md[2]
|
70
|
+
else
|
71
|
+
md = l.strip.match(HTTP_VERB_URI_REGEXP)
|
72
|
+
if md
|
73
|
+
state = :hd
|
74
|
+
http_method = md[1]
|
75
|
+
uri = md[2]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
when :hd
|
79
|
+
md = l.strip.match(HEADER_REGEXP)
|
80
|
+
if md
|
81
|
+
state = :hd
|
82
|
+
headers[md[1]] = md[2]
|
83
|
+
else
|
84
|
+
body_str << l
|
85
|
+
state = :bd
|
86
|
+
end
|
87
|
+
|
88
|
+
when :bd
|
89
|
+
body_str << l
|
90
|
+
end
|
91
|
+
end
|
92
|
+
if ct_headers['Content-Type'] == 'application/http'
|
93
|
+
|
94
|
+
Multi::Part::HttpReq.new(headers,
|
95
|
+
http_method,
|
96
|
+
uri,
|
97
|
+
body_str)
|
98
|
+
|
99
|
+
else
|
100
|
+
# TODO: should probably be a BadRequestError ?
|
101
|
+
raise RuntimeError
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
module Part
|
108
|
+
class Base
|
109
|
+
attr_accessor :content_type
|
110
|
+
attr_accessor :content_transfer_enc
|
111
|
+
def initialize
|
112
|
+
@content = nil
|
113
|
+
end
|
114
|
+
|
115
|
+
attr_writer :content
|
116
|
+
|
117
|
+
def message_s
|
118
|
+
result = ''
|
119
|
+
result << "Content-Type: #{@content_type}#{RETNL}"
|
120
|
+
result << "Content-Transfer-Encoding: #{@content_transfer_enc}#{RETNL}"
|
121
|
+
result << RETNL
|
122
|
+
result << content.to_s
|
123
|
+
result
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class HttpReq < Base
|
128
|
+
def initialize(headers, method, url, body)
|
129
|
+
super()
|
130
|
+
@content_type = 'application/http'
|
131
|
+
@content_transfer_enc = 'binary'
|
132
|
+
@headers = headers
|
133
|
+
@http_method = method
|
134
|
+
@url = url
|
135
|
+
@body = body
|
136
|
+
end
|
137
|
+
|
138
|
+
def finalize
|
139
|
+
@content = "#{@http_method} #{@url} HTTP/1.1#{RETNL}"
|
140
|
+
@headers.each do |k, v|
|
141
|
+
@content << "#{k}: #{v}#{RETNL}"
|
142
|
+
end
|
143
|
+
if @body != ''
|
144
|
+
@content << RETNL
|
145
|
+
@content << @body
|
146
|
+
end
|
147
|
+
@content
|
148
|
+
end
|
149
|
+
|
150
|
+
def content
|
151
|
+
@content = (@content || finalize)
|
152
|
+
end
|
153
|
+
|
154
|
+
# shamelessely copied from Rack::TEST:Session
|
155
|
+
def headers_for_env
|
156
|
+
converted_headers = {}
|
157
|
+
|
158
|
+
@headers.each do |name, value|
|
159
|
+
env_key = name.upcase.tr('-', '_')
|
160
|
+
env_key = 'HTTP_' + env_key unless env_key == 'CONTENT_TYPE'
|
161
|
+
converted_headers[env_key] = value
|
162
|
+
end
|
163
|
+
|
164
|
+
converted_headers
|
165
|
+
end
|
166
|
+
|
167
|
+
def batch_env
|
168
|
+
@env = ::Rack::MockRequest.env_for(@url,
|
169
|
+
method: @http_method,
|
170
|
+
input: @body_str)
|
171
|
+
@env.merge! headers_for_env
|
172
|
+
@env
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
class HttpGet < HttpReq
|
177
|
+
def initialize(url, app_headers)
|
178
|
+
super(app_headers, 'GET', url, '')
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/lib/odata/batch.rb
CHANGED
@@ -2,66 +2,66 @@
|
|
2
2
|
|
3
3
|
require 'rack_app.rb'
|
4
4
|
require 'safrano_core.rb'
|
5
|
+
require 'webrick/httpstatus'
|
5
6
|
|
6
7
|
module OData
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
RETNEW = "\r\n".freeze
|
9
|
+
class Request
|
10
|
+
def create_batch_app
|
11
|
+
Batch::MyOApp.new(self)
|
12
|
+
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
def parse_multipart_mixed
|
15
|
+
@boundary = media_type_params['boundary']
|
16
|
+
Multi::Parts::Mixed.parse(body.read, @boundary)
|
17
|
+
end
|
18
|
+
end
|
15
19
|
|
16
|
-
|
20
|
+
class Response
|
21
|
+
APPLICATION_HTTP_11 = ['Content-Type: application/http',
|
22
|
+
"Content-Transfer-Encoding: binary#{RETNEW}",
|
23
|
+
'HTTP/1.1 '].join(RETNEW).freeze
|
24
|
+
StatusMessage = WEBrick::HTTPStatus::StatusMessage.freeze
|
25
|
+
def message_s
|
26
|
+
b = String.new(APPLICATION_HTTP_11)
|
27
|
+
b << "#{@status} #{StatusMessage[@status]} #{RETNEW}"
|
28
|
+
headers.each { |k, v| b << k.to_s << ':' << v.to_s << RETNEW }
|
29
|
+
b << RETNEW
|
30
|
+
b << @body[0].to_s
|
31
|
+
b << RETNEW
|
32
|
+
end
|
33
|
+
end
|
17
34
|
|
18
|
-
|
19
|
-
|
35
|
+
module Batch
|
36
|
+
# Mayonaise
|
37
|
+
class MyOApp < OData::ServerApp
|
38
|
+
attr_reader :full_req
|
39
|
+
attr_reader :response
|
20
40
|
|
21
|
-
def
|
22
|
-
|
23
|
-
@response.headers.each { |k, v| b << k.to_s << ':' << v.to_s << "\r\n" }
|
24
|
-
b << "\r\n"
|
25
|
-
b << @response.body[0].to_s
|
26
|
-
b << "\r\n"
|
41
|
+
def initialize(full_req)
|
42
|
+
@full_req = full_req
|
27
43
|
end
|
28
|
-
end
|
29
44
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
attr_accessor :http_method
|
36
|
-
attr_accessor :uri
|
37
|
-
attr_accessor :env
|
38
|
-
def initialize
|
39
|
-
@headers = {}
|
40
|
-
@odata_headers = {}
|
41
|
-
@body_str = ''
|
45
|
+
# redefined for $batch
|
46
|
+
def before
|
47
|
+
headers 'Cache-Control' => 'no-cache'
|
48
|
+
@request.service = @full_req.service
|
49
|
+
headers 'DataServiceVersion' => @request.service.data_service_version
|
42
50
|
end
|
43
51
|
|
44
|
-
|
45
|
-
|
46
|
-
|
52
|
+
def batch_call(part_req)
|
53
|
+
env = part_req.batch_env
|
54
|
+
env['HTTP_HOST'] = @full_req.env['HTTP_HOST']
|
47
55
|
|
48
|
-
@
|
49
|
-
|
50
|
-
env_key = 'HTTP_' + env_key unless env_key == 'CONTENT_TYPE'
|
51
|
-
converted_headers[env_key] = value
|
52
|
-
end
|
53
|
-
|
54
|
-
converted_headers
|
55
|
-
end
|
56
|
+
@request = OData::Request.new(env)
|
57
|
+
@response = OData::Response.new
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
input: @body_str)
|
61
|
-
@env.merge! headers_for_env
|
62
|
-
@env
|
59
|
+
before
|
60
|
+
dispatch
|
61
|
+
@response.finish
|
63
62
|
end
|
64
63
|
end
|
64
|
+
|
65
65
|
# Huile d'olive extra
|
66
66
|
class HandlerBase
|
67
67
|
TREND = Safrano::Transition.new('', trans: 'transition_end')
|
@@ -85,8 +85,6 @@ module OData
|
|
85
85
|
end
|
86
86
|
# battre le tout
|
87
87
|
class EnabledHandler < HandlerBase
|
88
|
-
HTTP_VERB_URI_REGEXP = /^(POST|GET|PUT|PATCH)\s+(\S*)\s?(\S*)$/.freeze
|
89
|
-
HEADER_REGEXP = %r{^([a-zA-Z\-]+):\s*([0-9a-zA-Z\-\/]+;?\S*)\s*$}.freeze
|
90
88
|
attr_accessor :boundary
|
91
89
|
attr_accessor :mmboundary
|
92
90
|
attr_accessor :body_str
|
@@ -97,93 +95,28 @@ module OData
|
|
97
95
|
@parts = []
|
98
96
|
end
|
99
97
|
|
98
|
+
# here we are in the Batch handler object, and this POST should
|
99
|
+
# normally handle a $batch request
|
100
100
|
def odata_post(req)
|
101
|
-
odata_batch(req)
|
102
|
-
end
|
103
|
-
|
104
|
-
def odata_get(_req)
|
105
|
-
[405, {}, 'You cant GET $batch, POST it ']
|
106
|
-
end
|
107
|
-
|
108
|
-
def odata_batch(req)
|
109
101
|
@request = req
|
110
|
-
if @request.media_type == 'multipart/mixed'
|
111
|
-
read
|
112
|
-
parse
|
113
|
-
[202,
|
114
|
-
{ 'Content-Type' => "multipart/mixed;boundary=#{@boundary}" },
|
115
|
-
process_parts]
|
116
|
-
else
|
117
|
-
[415, {}, 'Unsupported Media Type']
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def read
|
122
|
-
@body_str = @request.body.read
|
123
|
-
@boundary = @request.media_type_params['boundary']
|
124
|
-
@mmboundary = '--' << @boundary
|
125
|
-
end
|
126
102
|
|
127
|
-
|
128
|
-
|
129
|
-
@
|
130
|
-
|
131
|
-
end
|
103
|
+
if @request.media_type == 'multipart/mixed'
|
104
|
+
batcha = @request.create_batch_app
|
105
|
+
@mult_request = @request.parse_multipart_mixed
|
106
|
+
@mult_response = @mult_request.shadow_copy
|
132
107
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
part = RequestPartBuilder.new
|
137
|
-
inp.each_line do |l|
|
138
|
-
next if l.strip.empty?
|
139
|
-
|
140
|
-
case state
|
141
|
-
when :start, :ohd
|
142
|
-
md = l.strip.match(HEADER_REGEXP)
|
143
|
-
|
144
|
-
if md
|
145
|
-
state = :ohd
|
146
|
-
part.odata_headers[md[1]] = md[2]
|
147
|
-
else
|
148
|
-
md = l.strip.match(HTTP_VERB_URI_REGEXP)
|
149
|
-
if md
|
150
|
-
state = :hd
|
151
|
-
part.http_method = md[1]
|
152
|
-
part.uri = md[2]
|
153
|
-
end
|
154
|
-
end
|
155
|
-
when :hd
|
156
|
-
md = l.strip.match(HEADER_REGEXP)
|
157
|
-
if md
|
158
|
-
state = :hd
|
159
|
-
part.headers[md[1]] = md[2]
|
160
|
-
else
|
161
|
-
part.body_str << l
|
162
|
-
state = :bd
|
163
|
-
end
|
164
|
-
|
165
|
-
when :bd
|
166
|
-
part.body_str << l
|
108
|
+
@mult_request.parts.each_with_object(@mult_response) do |req_part, mresp|
|
109
|
+
batcha.batch_call(req_part)
|
110
|
+
mresp.parts << batcha.response
|
167
111
|
end
|
112
|
+
[202, @mult_response.headers, @mult_response.finalize]
|
113
|
+
else
|
114
|
+
[415, {}, 'Unsupported Media Type']
|
168
115
|
end
|
169
|
-
part
|
170
116
|
end
|
171
117
|
|
172
|
-
def
|
173
|
-
|
174
|
-
@parts.each do |p|
|
175
|
-
next unless p.uri
|
176
|
-
|
177
|
-
batcha = MyOApp.new
|
178
|
-
|
179
|
-
batcha.full_req = @request
|
180
|
-
|
181
|
-
batcha.batch_call(p.batch_env)
|
182
|
-
|
183
|
-
full_batch_body << @mmboundary << "\r\n"
|
184
|
-
full_batch_body << batcha.batch_body
|
185
|
-
end
|
186
|
-
full_batch_body << @mmboundary << "--\r\n"
|
118
|
+
def odata_get(_req)
|
119
|
+
[405, {}, 'You cant GET $batch, POST it ']
|
187
120
|
end
|
188
121
|
end
|
189
122
|
end
|
data/lib/odata/collection.rb
CHANGED
data/lib/odata/entity.rb
CHANGED
data/lib/odata/error.rb
CHANGED
data/lib/odata/relations.rb
CHANGED
data/lib/odata/walker.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'json'
|
4
|
-
require 'pp'
|
5
4
|
require 'rexml/document'
|
6
5
|
require 'safrano.rb'
|
7
6
|
|
@@ -29,6 +28,8 @@ module OData
|
|
29
28
|
attr_reader :do_links
|
30
29
|
|
31
30
|
def initialize(service, path)
|
31
|
+
raise 'Walker is called with a nil service' unless service
|
32
|
+
|
32
33
|
path = URI.decode_www_form_component(path)
|
33
34
|
@context = service
|
34
35
|
@contexts = [@context]
|
@@ -99,7 +100,6 @@ module OData
|
|
99
100
|
else
|
100
101
|
@context = nil
|
101
102
|
@status = :error
|
102
|
-
# @error = OData::ServerError
|
103
103
|
@error = OData::ErrorNotFound
|
104
104
|
end
|
105
105
|
|
data/lib/rack_app.rb
CHANGED
@@ -4,7 +4,6 @@ require 'rack'
|
|
4
4
|
require_relative 'odata/walker.rb'
|
5
5
|
require_relative 'request.rb'
|
6
6
|
require_relative 'response.rb'
|
7
|
-
require 'pry'
|
8
7
|
|
9
8
|
module OData
|
10
9
|
# handle GET PUT etc
|
@@ -25,7 +24,14 @@ module OData
|
|
25
24
|
|
26
25
|
def odata_error
|
27
26
|
if @walker.error.nil?
|
28
|
-
|
27
|
+
|
28
|
+
# this is too critical; raise a real Exception
|
29
|
+
# begin
|
30
|
+
raise 'Walker construction failed with a unknown Error '
|
31
|
+
# rescue StandardError
|
32
|
+
# binding.pry
|
33
|
+
# end
|
34
|
+
# [500, {}, 'Server Error']
|
29
35
|
else
|
30
36
|
@walker.error.odata_get(@request)
|
31
37
|
end
|
@@ -82,7 +88,7 @@ module OData
|
|
82
88
|
|
83
89
|
neg_error = @request.negotiate_service_version
|
84
90
|
|
85
|
-
raise
|
91
|
+
raise RuntimeError if neg_error
|
86
92
|
|
87
93
|
return false unless @request.service
|
88
94
|
|
data/lib/safrano.rb
CHANGED
data/lib/service.rb
CHANGED
@@ -185,8 +185,8 @@ module OData
|
|
185
185
|
|
186
186
|
def enable_batch
|
187
187
|
@batch_handler = OData::Batch::EnabledHandler.new
|
188
|
-
@v1.batch_handler = @batch_handler
|
189
|
-
@v2.batch_handler = @batch_handler
|
188
|
+
(@v1.batch_handler = @batch_handler) if @v1
|
189
|
+
(@v2.batch_handler = @batch_handler) if @v2
|
190
190
|
end
|
191
191
|
|
192
192
|
def enable_v1_service
|
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- D.M.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rack
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: rack
|
28
|
+
name: rack-cors
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '1.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sequel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.15'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.15'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +66,20 @@ dependencies:
|
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '12.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rack-test
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rubocop
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,6 +100,7 @@ executables: []
|
|
72
100
|
extensions: []
|
73
101
|
extra_rdoc_files: []
|
74
102
|
files:
|
103
|
+
- lib/multipart.rb
|
75
104
|
- lib/odata/attribute.rb
|
76
105
|
- lib/odata/batch.rb
|
77
106
|
- lib/odata/collection.rb
|