safrano 0.0.8 → 0.0.9
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 +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
|