rester 0.0.1
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 +7 -0
- data/lib/rester.rb +23 -0
- data/lib/rester/client.rb +61 -0
- data/lib/rester/client/adapters.rb +8 -0
- data/lib/rester/client/adapters/adapter.rb +114 -0
- data/lib/rester/client/adapters/http_adapter.rb +31 -0
- data/lib/rester/client/adapters/http_adapter/connection.rb +58 -0
- data/lib/rester/errors.rb +52 -0
- data/lib/rester/middleware.rb +6 -0
- data/lib/rester/middleware/base.rb +44 -0
- data/lib/rester/middleware/error_handling.rb +49 -0
- data/lib/rester/railtie.rb +12 -0
- data/lib/rester/service.rb +137 -0
- data/lib/rester/utils.rb +49 -0
- data/lib/rester/version.rb +3 -0
- metadata +136 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 891fe3d740381cb54c48e89ad69fca06e1fc06d6
|
4
|
+
data.tar.gz: db402da2918dc425d879b3719fc41e976b1de4bf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1a4992cf642165b17d1e77e854ac9fdaadef82ccc45337548d0a902048bb372dc9574713ff5109f5baba43e3f0c730b1c299c005932314d1ff5bc803ca6d087b
|
7
|
+
data.tar.gz: 4b9ef3355867f57f67632b24dffd84b9d39027d94544d8681058b27e01fe204418dc04b3a9b843ad48fdcf9b412460dda07707bdfbc74ed77bac057b38a347e2
|
data/lib/rester.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rester/version'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
module Rester
|
5
|
+
require 'rester/railtie' if defined?(Rails)
|
6
|
+
autoload(:Service, 'rester/service')
|
7
|
+
autoload(:Errors, 'rester/errors')
|
8
|
+
autoload(:Client, 'rester/client')
|
9
|
+
autoload(:Utils, 'rester/utils')
|
10
|
+
autoload(:Middleware, 'rester/middleware')
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def load_tasks
|
14
|
+
Dir[
|
15
|
+
File.expand_path("../../tasks", __FILE__) + '/**.rake'
|
16
|
+
].each { |rake_file| load rake_file }
|
17
|
+
end
|
18
|
+
|
19
|
+
def connect(*args)
|
20
|
+
Client.new(*args)
|
21
|
+
end
|
22
|
+
end # Class Methods
|
23
|
+
end # Rester
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Rester
|
4
|
+
class Client
|
5
|
+
autoload(:Adapters, 'rester/client/adapters')
|
6
|
+
|
7
|
+
attr_reader :adapter
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
case args.first
|
11
|
+
when Adapters::Adapter
|
12
|
+
self.adapter = args.first
|
13
|
+
else
|
14
|
+
self.adapter = Adapters::HttpAdapter.new(*args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def connect(*args)
|
19
|
+
adapter.connect(*args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def connected?
|
23
|
+
adapter.connected? && adapter.get(:test_connection).first == 200
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def adapter=(adapter)
|
29
|
+
@adapter = adapter
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
##
|
35
|
+
# Submits the method to the adapter.
|
36
|
+
def method_missing(meth, *args, &block)
|
37
|
+
verb, meth = Utils.extract_method_verb(meth)
|
38
|
+
_process_response(meth, *adapter.request(verb, meth, *args, &block))
|
39
|
+
end
|
40
|
+
|
41
|
+
def _process_response(meth, status, body)
|
42
|
+
if status.between?(200, 299)
|
43
|
+
_parse_json(body)
|
44
|
+
elsif status == 400
|
45
|
+
raise Errors::RequestError, _parse_json(body)[:message]
|
46
|
+
elsif status == 404
|
47
|
+
raise Errors::InvalidMethodError, meth.to_s
|
48
|
+
else
|
49
|
+
raise Errors::ServerError, _parse_json(body)[:message]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def _parse_json(data)
|
54
|
+
if data.is_a?(String) && !data.empty?
|
55
|
+
JSON.parse(data, symbolize_names: true)
|
56
|
+
else
|
57
|
+
{}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end # Client
|
61
|
+
end # Rester
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Rester
|
2
|
+
module Client::Adapters
|
3
|
+
class Adapter
|
4
|
+
def initialize(*args)
|
5
|
+
connect(*args) unless args.empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
##
|
9
|
+
# Returns the headers defined for this Adapter. Optionally, you may also
|
10
|
+
# define additional headers you'd like to add/override.
|
11
|
+
def headers(new_headers={})
|
12
|
+
(@headers ||= {}).merge!(new_headers)
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Connect to a service. The specific arguments depend on the Adapter
|
17
|
+
# subclass.
|
18
|
+
def connect(*args)
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Returns whether or not the Adapter is connected to a service.
|
24
|
+
def connected?
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
def request(verb, method, *args, &block)
|
29
|
+
_validate_verb(verb)
|
30
|
+
params = _validate_params(args.pop) if args.last.is_a?(Hash)
|
31
|
+
_validate_args(args)
|
32
|
+
|
33
|
+
public_send(
|
34
|
+
"#{verb}!",
|
35
|
+
"/#{method}/#{args.map(&:to_s).join('/')}",
|
36
|
+
params
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def get(method, *args, &block)
|
41
|
+
request(:get, method, *args, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def post(method, *args, &block)
|
45
|
+
request(:post, method, *args, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get!(path, params={})
|
49
|
+
raise NotImplementedError
|
50
|
+
end
|
51
|
+
|
52
|
+
def post!(path, params={})
|
53
|
+
raise NotImplementedError
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def headers=(h)
|
59
|
+
@headers = h
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
VALID_VERBS = {
|
65
|
+
get: true,
|
66
|
+
post: true
|
67
|
+
}.freeze
|
68
|
+
|
69
|
+
VALID_ARG_TYPES = {
|
70
|
+
String => true,
|
71
|
+
Symbol => true,
|
72
|
+
Fixnum => true,
|
73
|
+
Integer => true,
|
74
|
+
Float => true
|
75
|
+
}.freeze
|
76
|
+
|
77
|
+
VALID_PARAM_KEY_TYPES = {
|
78
|
+
String => true,
|
79
|
+
Symbol => true
|
80
|
+
}.freeze
|
81
|
+
|
82
|
+
VALID_PARAM_VALUE_TYPES = {
|
83
|
+
String => true,
|
84
|
+
Symbol => true,
|
85
|
+
Fixnum => true,
|
86
|
+
Integer => true,
|
87
|
+
Float => true,
|
88
|
+
DateTime => true
|
89
|
+
}.freeze
|
90
|
+
|
91
|
+
def _validate_verb(verb)
|
92
|
+
VALID_VERBS[verb] or
|
93
|
+
raise ArgumentError, "Invalid verb: #{verb.inspect}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def _validate_args(args)
|
97
|
+
args.each { |arg|
|
98
|
+
VALID_ARG_TYPES[arg.class] or
|
99
|
+
raise ArgumentError, "Invalid argument type: #{arg.inspect}"
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def _validate_params(params)
|
104
|
+
params.each { |key, value|
|
105
|
+
VALID_PARAM_KEY_TYPES[key.class] or
|
106
|
+
raise ArgumentError, "Invalid param key type: #{key.inspect}"
|
107
|
+
|
108
|
+
VALID_PARAM_VALUE_TYPES[value.class] or
|
109
|
+
raise ArgumentError, "Invalid param value type: #{value.inspect}"
|
110
|
+
}
|
111
|
+
end
|
112
|
+
end # Adapter
|
113
|
+
end # Client::Adapters
|
114
|
+
end # Rester
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rester
|
2
|
+
module Client::Adapters
|
3
|
+
class HttpAdapter < Adapter
|
4
|
+
autoload(:Connection, 'rester/client/adapters/http_adapter/connection')
|
5
|
+
|
6
|
+
attr_reader :connection
|
7
|
+
|
8
|
+
def connect(*args)
|
9
|
+
nil.tap { @connection = Connection.new(*args) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def connected?
|
13
|
+
!!connection
|
14
|
+
end
|
15
|
+
|
16
|
+
def get!(path, params={})
|
17
|
+
_prepare_response(connection.get(path, headers: headers, query: params))
|
18
|
+
end
|
19
|
+
|
20
|
+
def post!(path, params={})
|
21
|
+
_prepare_response(connection.post(path, headers: headers, data: params))
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def _prepare_response(response)
|
27
|
+
[response.code.to_i, response.body]
|
28
|
+
end
|
29
|
+
end # HttpAdapter
|
30
|
+
end # Client::Adapters
|
31
|
+
end # Rester
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'openssl'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Rester
|
6
|
+
module Client::Adapters
|
7
|
+
class HttpAdapter::Connection
|
8
|
+
DEFAULT_POST_HEADERS = {
|
9
|
+
"Content-Type".freeze => "application/x-www-form-urlencoded".freeze
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
attr_reader :url
|
13
|
+
|
14
|
+
def initialize(url)
|
15
|
+
@url = url.is_a?(String) ? URI(url) : url
|
16
|
+
@url.path = @url.path[0..-2] if @url.path[-1] == '/'
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(path, params={})
|
20
|
+
_http.get(
|
21
|
+
_path(path, params[:query]),
|
22
|
+
_prepare_headers(params[:headers])
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def post(path, params={})
|
27
|
+
headers = DEFAULT_POST_HEADERS.merge(_prepare_headers(params[:headers]))
|
28
|
+
encoded_data = URI.encode_www_form(params[:data] || {})
|
29
|
+
_http.post(_path(path), encoded_data, headers)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def _path(path, query=nil)
|
35
|
+
u = url.dup
|
36
|
+
u.path += path
|
37
|
+
u.query = URI.encode_www_form(query) if query && !query.empty?
|
38
|
+
u.request_uri
|
39
|
+
end
|
40
|
+
|
41
|
+
def _http
|
42
|
+
Net::HTTP.new(url.hostname, url.port).tap { |http|
|
43
|
+
if (http.use_ssl=url.is_a?(URI::HTTPS))
|
44
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
45
|
+
|
46
|
+
http.cert_store = OpenSSL::X509::Store.new.tap { |s|
|
47
|
+
s.set_default_paths
|
48
|
+
}
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def _prepare_headers(headers)
|
54
|
+
Hash[(headers || {}).map { |k, v| [k.to_s, v.to_s] }]
|
55
|
+
end
|
56
|
+
end # HttpAdapter::Connection
|
57
|
+
end # Client::Adapters
|
58
|
+
end # Rester
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rester
|
2
|
+
module Errors
|
3
|
+
class << self
|
4
|
+
##
|
5
|
+
# Throws an error instead of raising it, which is more performant. Must
|
6
|
+
# be caught by an appropriate error handling wrapper.
|
7
|
+
def throw_error!(klass, message=nil)
|
8
|
+
error = message ? klass.new(message) : klass.new
|
9
|
+
throw :error, error
|
10
|
+
end
|
11
|
+
end # Class Methods
|
12
|
+
|
13
|
+
class Error < StandardError; end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Packet errors
|
17
|
+
class PacketError < Error; end
|
18
|
+
class InvalidEncodingError < PacketError; end
|
19
|
+
|
20
|
+
#############
|
21
|
+
# Http Errors
|
22
|
+
class HttpError < Error; end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Request Errors
|
26
|
+
|
27
|
+
# 400 Error
|
28
|
+
class RequestError < HttpError; end
|
29
|
+
|
30
|
+
# 401 Error
|
31
|
+
class AuthenticationError < RequestError; end
|
32
|
+
|
33
|
+
# 403 Error
|
34
|
+
class ForbiddenError < RequestError; end
|
35
|
+
|
36
|
+
# 404 Not Found
|
37
|
+
class NotFoundError < RequestError; end
|
38
|
+
class InvalidMethodError < NotFoundError; end
|
39
|
+
|
40
|
+
# 500 ServerError
|
41
|
+
class ServerError < RequestError; end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Server Errors
|
45
|
+
|
46
|
+
# General Errors
|
47
|
+
class InvalidValueError < Error; end
|
48
|
+
|
49
|
+
# Rester Errors
|
50
|
+
class ServiceNotDefinedError < Error; end
|
51
|
+
end # Errors
|
52
|
+
end # Rester
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Rester
|
2
|
+
module Middleware
|
3
|
+
class Base
|
4
|
+
attr_reader :app
|
5
|
+
attr_reader :options
|
6
|
+
|
7
|
+
def initialize(app, options = {})
|
8
|
+
@app = app
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
app.call(env)
|
14
|
+
end
|
15
|
+
|
16
|
+
def service
|
17
|
+
@__service ||= _find_service
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def _find_service
|
23
|
+
service = app
|
24
|
+
|
25
|
+
loop {
|
26
|
+
break if service.is_a?(Service)
|
27
|
+
|
28
|
+
[:app, :target].each { |meth|
|
29
|
+
if service.respond_to?(meth)
|
30
|
+
service = service.public_send(meth)
|
31
|
+
break
|
32
|
+
end
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
service.is_a?(Service) && service
|
37
|
+
end
|
38
|
+
|
39
|
+
def _error!(klass, message=nil)
|
40
|
+
Errors.throw_error!(klass, message)
|
41
|
+
end
|
42
|
+
end # Base
|
43
|
+
end # Middleware
|
44
|
+
end # Rester
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Rester
|
4
|
+
module Middleware
|
5
|
+
##
|
6
|
+
# Provides error handling for Rester. Should be mounted above all other
|
7
|
+
# Rester middleware.
|
8
|
+
class ErrorHandling < Base
|
9
|
+
def call(env)
|
10
|
+
error = catch(:error) {
|
11
|
+
begin
|
12
|
+
return super
|
13
|
+
rescue Exception => error
|
14
|
+
throw :error, error
|
15
|
+
end
|
16
|
+
}
|
17
|
+
|
18
|
+
_error_to_response(error).finish
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def _error_to_response(error)
|
24
|
+
Rack::Response.new(
|
25
|
+
[JSON.dump(message: error.message)],
|
26
|
+
_error_to_http_code(error),
|
27
|
+
{ "Content-Type" => "application/json"}
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def _error_to_http_code(error)
|
32
|
+
case error
|
33
|
+
when Errors::NotFoundError
|
34
|
+
404
|
35
|
+
when Errors::ForbiddenError
|
36
|
+
403
|
37
|
+
when Errors::AuthenticationError
|
38
|
+
401
|
39
|
+
when Errors::RequestError
|
40
|
+
400
|
41
|
+
when Errors::ServerError
|
42
|
+
500
|
43
|
+
else
|
44
|
+
500
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end # ErrorHandling
|
48
|
+
end # Middleware
|
49
|
+
end # Rester
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
module Rester
|
5
|
+
class Service
|
6
|
+
##
|
7
|
+
# The base set of middleware to use for every service.
|
8
|
+
# Middleware will be executed in the order specified.
|
9
|
+
BASE_MIDDLEWARE = [
|
10
|
+
Rack::Head,
|
11
|
+
Middleware::ErrorHandling
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
# Used to signify an empty body
|
15
|
+
class EmptyResponse; end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def instance
|
19
|
+
@instance ||= new
|
20
|
+
end
|
21
|
+
|
22
|
+
# The call method needs to call the rack_call method, which adds additional
|
23
|
+
# rack middleware.
|
24
|
+
def call(env)
|
25
|
+
instance.rack_call(env)
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(meth, *args, &block)
|
29
|
+
instance.public_send(meth, *args, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
###
|
33
|
+
# Middleware DSL
|
34
|
+
###
|
35
|
+
|
36
|
+
def use(klass, *args)
|
37
|
+
_middleware << [klass, *args]
|
38
|
+
end
|
39
|
+
|
40
|
+
def _middleware
|
41
|
+
@__middleware ||= BASE_MIDDLEWARE.dup
|
42
|
+
end
|
43
|
+
end # Class methods
|
44
|
+
|
45
|
+
attr_reader :request
|
46
|
+
|
47
|
+
def initialize(opts={})
|
48
|
+
@_opts = opts.dup
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# To be called by Rack. Wraps the app in middleware.
|
53
|
+
def rack_call(env)
|
54
|
+
_rack_app.call(env)
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Call the service app directly.
|
59
|
+
#
|
60
|
+
# Duplicates the instance before processing the request so individual requests
|
61
|
+
# can't impact each other.
|
62
|
+
def call(env)
|
63
|
+
dup.call!(env)
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Actually process the request.
|
68
|
+
#
|
69
|
+
# Calls methods that may modify instance variables, so the instance should
|
70
|
+
# be dup'd beforehand.
|
71
|
+
def call!(env)
|
72
|
+
@request = Rack::Request.new(env)
|
73
|
+
_process_request
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Built in service method called by Client#connected?
|
78
|
+
def test_connection(params={})
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def _rack_app
|
84
|
+
@__rack_app ||= _build_rack_app
|
85
|
+
end
|
86
|
+
|
87
|
+
def _build_rack_app
|
88
|
+
Rack::Builder.new.tap { |app|
|
89
|
+
self.class._middleware.each { |m| app.use(*m) }
|
90
|
+
app.run self
|
91
|
+
}.to_app
|
92
|
+
end
|
93
|
+
|
94
|
+
def _process_request
|
95
|
+
error!(Errors::NotFoundError) unless request.get? || request.post?
|
96
|
+
method, *args = _parse_path
|
97
|
+
params = _parse_params
|
98
|
+
method = "#{method}!" if request.post?
|
99
|
+
retval = public_send(method, *args, params)
|
100
|
+
_response(request.post? ? 201 : 200, _prepare_response(retval))
|
101
|
+
end
|
102
|
+
|
103
|
+
def _prepare_response(retval)
|
104
|
+
retval ||= {}
|
105
|
+
|
106
|
+
unless retval.is_a?(Hash)
|
107
|
+
error!(Errors::ServerError, "Invalid response: #{retval.inspect}")
|
108
|
+
end
|
109
|
+
|
110
|
+
JSON.dump(retval)
|
111
|
+
end
|
112
|
+
|
113
|
+
def _parse_path
|
114
|
+
path = request.path
|
115
|
+
uri = URI(path)
|
116
|
+
uri.path.split('/')[1..-1]
|
117
|
+
end
|
118
|
+
|
119
|
+
def _parse_params
|
120
|
+
if request.get?
|
121
|
+
request.GET
|
122
|
+
elsif request.post?
|
123
|
+
request.POST
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def _response(status, body=EmptyResponse, headers={})
|
128
|
+
body = body == EmptyResponse ? [] : [body]
|
129
|
+
headers = headers.merge("Content-Type" => "application/json")
|
130
|
+
Rack::Response.new(body, status, headers).finish
|
131
|
+
end
|
132
|
+
|
133
|
+
def _error!(klass, message=nil)
|
134
|
+
Errors.throw_error!(klass, message)
|
135
|
+
end
|
136
|
+
end # Service
|
137
|
+
end # Rester
|
data/lib/rester/utils.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Rester
|
4
|
+
module Utils
|
5
|
+
class << self
|
6
|
+
##
|
7
|
+
# Determines the HTTP method/verb based on the method name.
|
8
|
+
# Defaults to GET but if the method ends with "!" it uses POST.
|
9
|
+
def extract_method_verb(meth)
|
10
|
+
meth = meth.to_s
|
11
|
+
|
12
|
+
if meth[-1] == '!'
|
13
|
+
[:post, meth[0..-2]]
|
14
|
+
else
|
15
|
+
[:get, meth]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def walk(object, context=nil, &block)
|
20
|
+
case object
|
21
|
+
when Hash
|
22
|
+
Hash[
|
23
|
+
object.map { |key, val|
|
24
|
+
[walk(key, :hash_key, &block), walk(val, :hash_value, &block)]
|
25
|
+
}
|
26
|
+
]
|
27
|
+
when Array
|
28
|
+
object.map { |obj| walk(obj, :array_elem, &block) }
|
29
|
+
when Range
|
30
|
+
Range.new(
|
31
|
+
walk(object.begin, :range_begin, &block),
|
32
|
+
walk(object.end, :range_end, &block),
|
33
|
+
object.exclude_end?
|
34
|
+
)
|
35
|
+
else
|
36
|
+
yield object, context
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def symbolize_keys(hash)
|
41
|
+
hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
42
|
+
end
|
43
|
+
|
44
|
+
def classify(str)
|
45
|
+
str.to_s.split("_").map(&:capitalize).join
|
46
|
+
end
|
47
|
+
end # Class methods
|
48
|
+
end # Utils
|
49
|
+
end # Rester
|
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rester
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert Honer
|
8
|
+
- Kayvon Ghaffari
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-09-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rack
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.5'
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.5.2
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '1.5'
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.5.2
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
type: :development
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rspec-rails
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sqlite3
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
type: :development
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: rails
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.0.0
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 4.0.0
|
90
|
+
description: A framework for creating simple RESTful interfaces between services.
|
91
|
+
email:
|
92
|
+
- robert@ribbonpayments.com
|
93
|
+
- kayvon@ribbon.co
|
94
|
+
executables: []
|
95
|
+
extensions: []
|
96
|
+
extra_rdoc_files: []
|
97
|
+
files:
|
98
|
+
- lib/rester.rb
|
99
|
+
- lib/rester/client.rb
|
100
|
+
- lib/rester/client/adapters.rb
|
101
|
+
- lib/rester/client/adapters/adapter.rb
|
102
|
+
- lib/rester/client/adapters/http_adapter.rb
|
103
|
+
- lib/rester/client/adapters/http_adapter/connection.rb
|
104
|
+
- lib/rester/errors.rb
|
105
|
+
- lib/rester/middleware.rb
|
106
|
+
- lib/rester/middleware/base.rb
|
107
|
+
- lib/rester/middleware/error_handling.rb
|
108
|
+
- lib/rester/railtie.rb
|
109
|
+
- lib/rester/service.rb
|
110
|
+
- lib/rester/utils.rb
|
111
|
+
- lib/rester/version.rb
|
112
|
+
homepage: http://github.com/ribbon/rester
|
113
|
+
licenses:
|
114
|
+
- BSD
|
115
|
+
metadata: {}
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 2.4.8
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: A framework for creating simple RESTful interfaces between services.
|
136
|
+
test_files: []
|