nestful 1.0.0.pre → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +40 -26
- data/examples/resource.rb +24 -3
- data/lib/nestful/connection.rb +11 -40
- data/lib/nestful/exceptions.rb +1 -0
- data/lib/nestful/formats/json_format.rb +1 -1
- data/lib/nestful/helpers.rb +12 -28
- data/lib/nestful/request.rb +6 -12
- data/lib/nestful/resource.rb +52 -48
- data/lib/nestful/version.rb +1 -1
- data/lib/nestful.rb +3 -3
- metadata +2 -4
- data/VERSION +0 -1
- data/lib/nestful/formats/multipart_format.rb +0 -80
data/README.markdown
CHANGED
@@ -7,56 +7,70 @@ Nestful is a simple Ruby HTTP/REST client with a sane API.
|
|
7
7
|
## Features
|
8
8
|
|
9
9
|
* Simple API
|
10
|
-
* File buffering
|
11
|
-
* Before/Progress/After Callbacks
|
12
10
|
* JSON requests
|
13
|
-
* Multipart requests (file uploading)
|
14
11
|
* Resource API
|
15
12
|
* Proxy support
|
16
13
|
* SSL support
|
17
14
|
|
18
|
-
##
|
15
|
+
## API
|
16
|
+
|
17
|
+
### GET request
|
18
|
+
|
19
|
+
Nestful.get 'http://example.com' #=> "body"
|
20
|
+
|
21
|
+
### POST request
|
22
|
+
|
23
|
+
Nestful.post 'http://example.com', :foo => 'bar'
|
24
|
+
Nestful.post 'http://example.com', {:foo => 'bar'}, :format => :json
|
25
|
+
|
26
|
+
### Parameters
|
27
|
+
|
28
|
+
Nestful.get 'http://example.com', :nestled => {:vars => 1}
|
29
|
+
|
30
|
+
## Request
|
31
|
+
|
32
|
+
`Request` is the base class for making HTTP requests - everthing else is just an abstraction upon it.
|
33
|
+
|
34
|
+
Request.new(url, options = {})
|
19
35
|
|
20
|
-
Request options:
|
36
|
+
Valid `Request` options are:
|
21
37
|
|
22
38
|
* headers (hash)
|
23
39
|
* params (hash)
|
24
40
|
* method (:get/:post/:put/:delete/:head)
|
25
|
-
|
26
|
-
Connection options:
|
27
|
-
|
28
41
|
* proxy
|
29
42
|
* user
|
30
43
|
* password
|
31
|
-
* auth_type
|
44
|
+
* auth_type (:basic/:bearer)
|
32
45
|
* timeout
|
33
46
|
* ssl_options
|
34
47
|
|
35
|
-
##
|
36
|
-
|
37
|
-
### GET request
|
38
|
-
|
39
|
-
Nestful.get 'http://example.com' #=> "body"
|
40
|
-
|
41
|
-
### POST request
|
48
|
+
## Endpoint
|
42
49
|
|
43
|
-
|
44
|
-
Nestful.post 'http://example.com', :params => {:foo => 'bar'}, :format => :json
|
50
|
+
The `Endpoint` class provides a single object to work with restful services. The following example does a GET request to the URL; http://example.com/assets/1/
|
45
51
|
|
46
|
-
|
52
|
+
Nestful::Endpoint.new('http://example.com')['assets'][1].get
|
47
53
|
|
48
|
-
|
54
|
+
## Resource
|
49
55
|
|
50
|
-
|
56
|
+
If you're building a binding for a REST API, then you should consider using the `Resource` class.
|
51
57
|
|
52
|
-
|
58
|
+
class Charge < Nestful::Resource
|
59
|
+
url 'https://api.stripe.com/v1/charges'
|
53
60
|
|
54
|
-
|
61
|
+
def self.all
|
62
|
+
self.new(get)
|
63
|
+
end
|
55
64
|
|
56
|
-
|
65
|
+
def self.find(id)
|
66
|
+
self.new(get(id))
|
67
|
+
end
|
57
68
|
|
58
|
-
|
69
|
+
def refund
|
70
|
+
post(:refund)
|
71
|
+
end
|
72
|
+
end
|
59
73
|
|
60
74
|
## Credits
|
61
75
|
|
62
|
-
|
76
|
+
Parts of the connection code were taken from ActiveResource
|
data/examples/resource.rb
CHANGED
@@ -1,6 +1,27 @@
|
|
1
1
|
require 'nestful'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# Example of using Stripe's API
|
4
|
+
|
5
|
+
class Base < Nestful::Resource
|
6
|
+
endpoint 'https://api.stripe.com'
|
7
|
+
options :auth_type => :bearer, :password => ENV['SECRET_KEY']
|
8
|
+
|
9
|
+
def self.all(*args)
|
10
|
+
# We have to delve into the response,
|
11
|
+
# as Stripe doesn't return arrays for
|
12
|
+
# list responses.
|
13
|
+
self.new(Base.new(get('', *args)).data)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(id)
|
17
|
+
self.new(get(id))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Charge < Base
|
22
|
+
path '/v1/charges'
|
23
|
+
|
24
|
+
def refund
|
25
|
+
post(:refund)
|
26
|
+
end
|
6
27
|
end
|
data/lib/nestful/connection.rb
CHANGED
@@ -5,12 +5,12 @@ module Nestful
|
|
5
5
|
class Connection
|
6
6
|
UriParser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
|
7
7
|
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :endpoint, :auth_type, :timeout, :proxy, :ssl_options
|
9
9
|
|
10
|
-
# The +
|
10
|
+
# The +endpoint+ parameter is required and will set the +endpoint+
|
11
11
|
# attribute to the URI for the remote resource service.
|
12
|
-
def initialize(
|
13
|
-
self.
|
12
|
+
def initialize(endpoint, options = {})
|
13
|
+
self.endpoint = endpoint
|
14
14
|
|
15
15
|
options.each do |key, value|
|
16
16
|
self.send("#{key}=", value) unless value.nil?
|
@@ -18,8 +18,8 @@ module Nestful
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# Set URI for remote service.
|
21
|
-
def
|
22
|
-
@
|
21
|
+
def endpoint=(endpoint)
|
22
|
+
@endpoint = endpoint.is_a?(URI) ? endpoint : UriParser.parse(endpoint)
|
23
23
|
end
|
24
24
|
|
25
25
|
# Set the proxy for remote service.
|
@@ -51,37 +51,8 @@ module Nestful
|
|
51
51
|
|
52
52
|
# Makes a request to the remote service.
|
53
53
|
def request(method, path, *arguments)
|
54
|
-
|
55
|
-
|
56
|
-
headers = arguments.shift || {}
|
57
|
-
|
58
|
-
method = Net::HTTP.const_get(method.to_s.capitalize)
|
59
|
-
method = method.new(path)
|
60
|
-
|
61
|
-
if body
|
62
|
-
if body.respond_to?(:read)
|
63
|
-
method.body_stream = body
|
64
|
-
else
|
65
|
-
method.body = body
|
66
|
-
end
|
67
|
-
|
68
|
-
if body.respond_to?(:size)
|
69
|
-
headers['Content-Length'] ||= body.size
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
headers.each do |name, value|
|
74
|
-
next unless value
|
75
|
-
method.add_field(name, value)
|
76
|
-
end
|
77
|
-
|
78
|
-
http.start do |stream|
|
79
|
-
stream.request(method) do |rsp|
|
80
|
-
handle_response(rsp)
|
81
|
-
yield(rsp) if block_given?
|
82
|
-
rsp
|
83
|
-
end
|
84
|
-
end
|
54
|
+
response = http.send(method, path, *arguments)
|
55
|
+
handle_response(response)
|
85
56
|
|
86
57
|
rescue Timeout::Error => e
|
87
58
|
raise TimeoutError.new(e.message)
|
@@ -131,11 +102,11 @@ module Nestful
|
|
131
102
|
|
132
103
|
def new_http
|
133
104
|
if proxy
|
134
|
-
Net::HTTP.new(
|
105
|
+
Net::HTTP.new(endpoint.host, endpoint.port,
|
135
106
|
proxy.host, proxy.port,
|
136
107
|
proxy.user, proxy.password)
|
137
108
|
else
|
138
|
-
Net::HTTP.new(
|
109
|
+
Net::HTTP.new(endpoint.host, endpoint.port)
|
139
110
|
end
|
140
111
|
end
|
141
112
|
|
@@ -152,7 +123,7 @@ module Nestful
|
|
152
123
|
end
|
153
124
|
|
154
125
|
def apply_ssl_options(http)
|
155
|
-
return http unless
|
126
|
+
return http unless endpoint.is_a?(URI::HTTPS)
|
156
127
|
|
157
128
|
http.use_ssl = true
|
158
129
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
data/lib/nestful/exceptions.rb
CHANGED
@@ -11,6 +11,7 @@ module Nestful
|
|
11
11
|
message = "Failed."
|
12
12
|
message << " Response code = #{response.code}." if response.respond_to?(:code)
|
13
13
|
message << " Response message = #{response.message}." if response.respond_to?(:message)
|
14
|
+
message << " Response Body = #{response.body}." if response.respond_to?(:body)
|
14
15
|
message
|
15
16
|
end
|
16
17
|
end
|
data/lib/nestful/helpers.rb
CHANGED
@@ -2,40 +2,24 @@ require 'cgi'
|
|
2
2
|
|
3
3
|
module Nestful
|
4
4
|
module Helpers extend self
|
5
|
-
def
|
6
|
-
case
|
7
|
-
when Hash
|
8
|
-
|
9
|
-
|
10
|
-
when Array
|
11
|
-
prefix = "#{key}[]"
|
12
|
-
value.collect { |v| to_query(prefix, v) }.join('&')
|
13
|
-
|
5
|
+
def to_param(value, key = nil)
|
6
|
+
case value
|
7
|
+
when Hash then value.map { |k,v| to_param(v, append_key(key,k)) }.join('&')
|
8
|
+
when Array then value.map { |v| to_param(v, "#{key}[]") }.join('&')
|
9
|
+
when nil then ''
|
14
10
|
else
|
15
|
-
value
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def to_param(object, namespace = nil)
|
20
|
-
case object
|
21
|
-
when Hash
|
22
|
-
object.map do |key, value|
|
23
|
-
key = "#{namespace}[#{key}]" if namespace
|
24
|
-
to_query(key, value)
|
25
|
-
end.join('&')
|
26
|
-
|
27
|
-
when Array
|
28
|
-
object.each do |value|
|
29
|
-
to_param(value)
|
30
|
-
end.join('/')
|
31
|
-
|
32
|
-
else
|
33
|
-
value
|
11
|
+
"#{key}=#{CGI.escape(value.to_s)}"
|
34
12
|
end
|
35
13
|
end
|
36
14
|
|
37
15
|
def camelize(value)
|
38
16
|
value.to_s.split('_').map {|w| w.capitalize }.join
|
39
17
|
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def append_key(root_key, key)
|
22
|
+
root_key.nil? ? key : "#{root_key}[#{key.to_s}]"
|
23
|
+
end
|
40
24
|
end
|
41
25
|
end
|
data/lib/nestful/request.rb
CHANGED
@@ -35,13 +35,13 @@ module Nestful
|
|
35
35
|
def uri
|
36
36
|
return @uri if @uri
|
37
37
|
|
38
|
-
url = @url.match(
|
38
|
+
url = @url.match(/\Ahttps?:\/\//) ? @url : "http://#{@url}"
|
39
39
|
|
40
40
|
@uri = URI.parse(url)
|
41
|
-
@uri.path =
|
41
|
+
@uri.path = '/' if @uri.path.empty?
|
42
42
|
|
43
|
-
@uri.query.split(
|
44
|
-
key, value = res.split(
|
43
|
+
@uri.query.split('&').each do |res|
|
44
|
+
key, value = res.split('=')
|
45
45
|
@params[key] = value
|
46
46
|
end if @uri.query
|
47
47
|
|
@@ -53,16 +53,10 @@ module Nestful
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def execute
|
56
|
-
result = nil
|
57
|
-
|
58
56
|
if encoded?
|
59
|
-
connection.send(method, path, encoded, build_headers)
|
60
|
-
result = res
|
61
|
-
end
|
57
|
+
result = connection.send(method, path, encoded, build_headers)
|
62
58
|
else
|
63
|
-
connection.send(method, query_path, build_headers)
|
64
|
-
result = res
|
65
|
-
end
|
59
|
+
result = connection.send(method, query_path, build_headers)
|
66
60
|
end
|
67
61
|
|
68
62
|
Response.new(result)
|
data/lib/nestful/resource.rb
CHANGED
@@ -4,82 +4,93 @@ module Nestful
|
|
4
4
|
class Resource
|
5
5
|
def self.endpoint(value = nil)
|
6
6
|
@endpoint = value if value
|
7
|
-
@endpoint
|
7
|
+
return @endpoint if @endpoint
|
8
|
+
superclass.respond_to?(:endpoint) ? superclass.endpoint : nil
|
8
9
|
end
|
9
10
|
|
10
|
-
def self.
|
11
|
-
@
|
12
|
-
@
|
11
|
+
def self.path(value = nil)
|
12
|
+
@path = value if value
|
13
|
+
return @path if @path
|
14
|
+
superclass.respond_to?(:path) ? superclass.path : nil
|
13
15
|
end
|
14
16
|
|
15
17
|
def self.options(value = nil)
|
16
18
|
@options = value if value
|
17
|
-
@options
|
19
|
+
return @options if @options
|
20
|
+
superclass.respond_to?(:options) ? superclass.options : nil
|
18
21
|
end
|
19
22
|
|
20
|
-
def self.
|
21
|
-
|
23
|
+
def self.url
|
24
|
+
URI.join(endpoint.to_s, path.to_s).to_s
|
22
25
|
end
|
23
26
|
|
24
|
-
def self.
|
25
|
-
|
27
|
+
def self.uri(*parts)
|
28
|
+
parts.unshift(path)
|
29
|
+
parts.unshift(endpoint)
|
30
|
+
URI.join(*parts.compact.map(&:to_s))
|
26
31
|
end
|
27
32
|
|
28
|
-
def self.
|
29
|
-
request(
|
33
|
+
def self.get(action = '', params = {}, options = {})
|
34
|
+
request(uri(action), options.merge(:method => :get, :params => params))
|
30
35
|
end
|
31
36
|
|
32
|
-
def self.
|
33
|
-
request(
|
37
|
+
def self.put(action = '', params = {}, options = {})
|
38
|
+
request(uri(action), options.merge(:method => :put, :params => params))
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.post(action = '', params = {}, options = {})
|
42
|
+
request(uri(action), options.merge(:method => :post, :params => params))
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.delete(action = '', params = {}, options = {})
|
46
|
+
request(uri(action), options.merge(:method => :delete, :params => params))
|
34
47
|
end
|
35
48
|
|
36
49
|
def self.request(url, options = {})
|
37
50
|
Request.new(url, self.options.merge(options)).execute
|
38
51
|
end
|
39
52
|
|
40
|
-
def self.all
|
41
|
-
self.new(get(
|
53
|
+
def self.all(*args)
|
54
|
+
self.new(get('', *args))
|
42
55
|
end
|
43
56
|
|
44
57
|
def self.find(id)
|
45
|
-
self.new(get(
|
58
|
+
self.new(get(id))
|
46
59
|
end
|
47
60
|
|
48
|
-
def self.new(attributes = {}
|
61
|
+
def self.new(attributes = {})
|
49
62
|
if attributes.is_a?(Array)
|
50
|
-
attributes.map {|set| super(set
|
63
|
+
attributes.map {|set| super(set) }
|
51
64
|
else
|
52
65
|
super
|
53
66
|
end
|
54
67
|
end
|
55
68
|
|
56
|
-
attr_reader :attributes
|
69
|
+
attr_reader :attributes
|
57
70
|
|
58
|
-
def initialize(attributes = {}
|
59
|
-
@attributes =
|
60
|
-
|
71
|
+
def initialize(attributes = {})
|
72
|
+
@attributes = {}
|
73
|
+
load(attributes)
|
61
74
|
end
|
62
75
|
|
63
|
-
def get(*args)
|
64
|
-
self.class.get(
|
76
|
+
def get(action = '', *args)
|
77
|
+
self.class.get(uri(action), *args)
|
65
78
|
end
|
66
79
|
|
67
|
-
def put(*args)
|
68
|
-
self.class.put(
|
80
|
+
def put(action = '', *args)
|
81
|
+
self.class.put(uri(action), *args)
|
69
82
|
end
|
70
83
|
|
71
|
-
def post(*args)
|
72
|
-
self.class.post(
|
84
|
+
def post(action = '', *args)
|
85
|
+
self.class.post(uri(action), *args)
|
73
86
|
end
|
74
87
|
|
75
|
-
def delete(*args)
|
76
|
-
self.class.delete(
|
88
|
+
def delete(action = '', *args)
|
89
|
+
self.class.delete(uri(action), *args)
|
77
90
|
end
|
78
91
|
|
79
|
-
|
80
|
-
|
81
|
-
def url
|
82
|
-
URI.join(self.class.url, self.id.to_s)
|
92
|
+
def uri(*parts)
|
93
|
+
self.class.uri(self.id, *parts)
|
83
94
|
end
|
84
95
|
|
85
96
|
def id #:nodoc:
|
@@ -99,7 +110,7 @@ module Nestful
|
|
99
110
|
end
|
100
111
|
|
101
112
|
def to_hash
|
102
|
-
|
113
|
+
attributes.dup
|
103
114
|
end
|
104
115
|
|
105
116
|
alias_method :as_json, :to_hash
|
@@ -108,6 +119,12 @@ module Nestful
|
|
108
119
|
as_json.to_json
|
109
120
|
end
|
110
121
|
|
122
|
+
def load(attributes = {})
|
123
|
+
attributes.to_hash.each do |key, value|
|
124
|
+
send("#{key}=", value)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
111
128
|
alias_method :respond_to_without_attributes?, :respond_to?
|
112
129
|
|
113
130
|
def respond_to?(method, include_priv = false)
|
@@ -123,19 +140,6 @@ module Nestful
|
|
123
140
|
|
124
141
|
protected
|
125
142
|
|
126
|
-
def indifferent_attributes(attributes)
|
127
|
-
attributes = indifferent_hash.merge(attributes)
|
128
|
-
attributes.each do |key, value|
|
129
|
-
next unless value.is_a?(Hash)
|
130
|
-
attributes[key] = indifferent_attributes(value)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Creates a Hash with indifferent access.
|
135
|
-
def indifferent_hash
|
136
|
-
Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
|
137
|
-
end
|
138
|
-
|
139
143
|
def method_missing(method_symbol, *arguments) #:nodoc:
|
140
144
|
method_name = method_symbol.to_s
|
141
145
|
|
data/lib/nestful/version.rb
CHANGED
data/lib/nestful.rb
CHANGED
@@ -16,15 +16,15 @@ module Nestful
|
|
16
16
|
Endpoint[url].get(*args)
|
17
17
|
end
|
18
18
|
|
19
|
-
def post(url,
|
19
|
+
def post(url, *args)
|
20
20
|
Endpoint[url].post(*args)
|
21
21
|
end
|
22
22
|
|
23
|
-
def put(url,
|
23
|
+
def put(url, *args)
|
24
24
|
Endpoint[url].put(*args)
|
25
25
|
end
|
26
26
|
|
27
|
-
def delete(url,
|
27
|
+
def delete(url, *args)
|
28
28
|
Endpoint[url].delete(*args)
|
29
29
|
end
|
30
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nestful
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-05 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email:
|
@@ -23,7 +23,6 @@ files:
|
|
23
23
|
- MIT-LICENSE
|
24
24
|
- README.markdown
|
25
25
|
- Rakefile
|
26
|
-
- VERSION
|
27
26
|
- examples/resource.rb
|
28
27
|
- lib/nestful.rb
|
29
28
|
- lib/nestful/.DS_Store
|
@@ -33,7 +32,6 @@ files:
|
|
33
32
|
- lib/nestful/formats.rb
|
34
33
|
- lib/nestful/formats/form_format.rb
|
35
34
|
- lib/nestful/formats/json_format.rb
|
36
|
-
- lib/nestful/formats/multipart_format.rb
|
37
35
|
- lib/nestful/helpers.rb
|
38
36
|
- lib/nestful/request.rb
|
39
37
|
- lib/nestful/resource.rb
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.0.8
|
@@ -1,80 +0,0 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
require 'tempfile'
|
3
|
-
|
4
|
-
module Nestful
|
5
|
-
module Formats
|
6
|
-
class MultipartFormat < Format
|
7
|
-
EOL = "\r\n"
|
8
|
-
|
9
|
-
attr_reader :boundary, :stream
|
10
|
-
|
11
|
-
def initialize(*args)
|
12
|
-
super
|
13
|
-
@boundary = SecureRandom.hex(10)
|
14
|
-
@stream = Tempfile.new("nf.#{rand(1000)}")
|
15
|
-
@stream.binmode
|
16
|
-
end
|
17
|
-
|
18
|
-
def mime_type
|
19
|
-
%Q{multipart/form-data; boundary=#{boundary}}
|
20
|
-
end
|
21
|
-
|
22
|
-
def encode(params, options = nil)
|
23
|
-
to_multipart(params)
|
24
|
-
stream.write("--" + boundary + "--" + EOL)
|
25
|
-
stream.flush
|
26
|
-
stream.rewind
|
27
|
-
stream
|
28
|
-
end
|
29
|
-
|
30
|
-
def decode(body)
|
31
|
-
body
|
32
|
-
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
def to_multipart(params, namespace = nil)
|
36
|
-
params.each do |key, value|
|
37
|
-
key = namespace ? "#{namespace}[#{key}]" : key
|
38
|
-
|
39
|
-
# Support nestled params
|
40
|
-
if value.is_a?(Hash)
|
41
|
-
to_multipart(value, key)
|
42
|
-
next
|
43
|
-
end
|
44
|
-
|
45
|
-
stream.write("--" + boundary + EOL)
|
46
|
-
|
47
|
-
if value.respond_to?(:read)
|
48
|
-
create_file_field(key, value)
|
49
|
-
else
|
50
|
-
create_field(key, value)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def create_file_field(key, value)
|
56
|
-
stream.write(%Q{Content-Disposition: form-data; name="#{key}"; filename="#{filename(value)}"} + EOL)
|
57
|
-
stream.write(%Q{Content-Type: application/octet-stream} + EOL)
|
58
|
-
stream.write(%Q{Content-Transfer-Encoding: binary} + EOL)
|
59
|
-
stream.write(EOL)
|
60
|
-
while data = value.read(8124)
|
61
|
-
stream.write(data)
|
62
|
-
end
|
63
|
-
stream.write(EOL)
|
64
|
-
end
|
65
|
-
|
66
|
-
def create_field(key, value)
|
67
|
-
stream.write(%Q{Content-Disposition: form-data; name="#{key}"} + EOL)
|
68
|
-
stream.write(EOL)
|
69
|
-
stream.write(value)
|
70
|
-
stream.write(EOL)
|
71
|
-
end
|
72
|
-
|
73
|
-
def filename(body)
|
74
|
-
return body.original_filename if body.respond_to?(:original_filename)
|
75
|
-
return File.basename(body.path) if body.respond_to?(:path)
|
76
|
-
'Unknown'
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|