commute 0.2.0.rc.2 → 0.3.0.pre
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.
- data/.todo +28 -12
- data/README.md +0 -1
- data/commute.gemspec +4 -5
- data/lib/commute/common/basic_auth.rb +10 -9
- data/lib/commute/common/caching.rb +208 -0
- data/lib/commute/common/chemicals.rb +47 -24
- data/lib/commute/common/eventmachine.rb +68 -0
- data/lib/commute/common/synchrony.rb +42 -0
- data/lib/commute/common/typhoeus.rb +64 -0
- data/lib/commute/core/api.rb +42 -29
- data/lib/commute/core/builder.rb +4 -15
- data/lib/commute/core/context.rb +156 -15
- data/lib/commute/core/http.rb +124 -0
- data/lib/commute/core/layer.rb +187 -0
- data/lib/commute/core/sequence.rb +83 -132
- data/lib/commute/core/stack.rb +63 -72
- data/lib/commute/core/status.rb +45 -0
- data/lib/commute/core/util/event_emitter.rb +58 -0
- data/lib/commute/core/util/path.rb +37 -0
- data/lib/commute/core/util/stream.rb +141 -0
- data/lib/commute/extensions/crud.rb +88 -0
- data/lib/commute/extensions/param.rb +20 -0
- data/lib/commute/extensions/url.rb +53 -0
- data/lib/commute/version.rb +1 -1
- data/spec/commute/common/caching_spec.rb +158 -0
- data/spec/commute/common/eventmachine_spec.rb +74 -0
- data/spec/commute/common/typhoeus_spec.rb +67 -0
- data/spec/commute/core/api_spec.rb +3 -1
- data/spec/commute/core/builder_spec.rb +8 -8
- data/spec/commute/core/http_spec.rb +39 -0
- data/spec/commute/core/layer_spec.rb +81 -0
- data/spec/commute/core/sequence_spec.rb +36 -150
- data/spec/commute/core/stack_spec.rb +33 -83
- data/spec/commute/core/util/event_emitter_spec.rb +35 -0
- data/spec/commute/core/util/path_spec.rb +29 -0
- data/spec/commute/core/util/stream_spec.rb +90 -0
- data/spec/commute/extensions/url_spec.rb +76 -0
- data/spec/spec_helper.rb +3 -1
- metadata +61 -48
- data/examples/gist_api.rb +0 -71
- data/examples/highrise_task_api.rb +0 -59
- data/examples/pastie_api.rb +0 -18
- data/lib/commute/aspects/caching.rb +0 -37
- data/lib/commute/aspects/crud.rb +0 -41
- data/lib/commute/aspects/pagination.rb +0 -16
- data/lib/commute/aspects/url.rb +0 -57
- data/lib/commute/common/cache.rb +0 -43
- data/lib/commute/common/conditional.rb +0 -27
- data/lib/commute/common/em-synchrony_adapter.rb +0 -29
- data/lib/commute/common/em_http_request_adapter.rb +0 -57
- data/lib/commute/common/typhoeus_adapter.rb +0 -40
- data/lib/commute/common/xml.rb +0 -7
- data/lib/commute/core/commuter.rb +0 -116
- data/lib/commute/core/processors/code_status_processor.rb +0 -40
- data/lib/commute/core/processors/hook.rb +0 -14
- data/lib/commute/core/processors/request_builder.rb +0 -26
- data/lib/commute/core/processors/sequencer.rb +0 -46
- data/lib/commute/core/request.rb +0 -58
- data/lib/commute/core/response.rb +0 -18
- data/spec/commute/aspects/caching_spec.rb +0 -12
- data/spec/commute/aspects/url_spec.rb +0 -61
- data/spec/commute/core/commuter_spec.rb +0 -64
- data/spec/commute/core/processors/code_status_processor_spec.rb +0 -5
- data/spec/commute/core/processors/hook_spec.rb +0 -25
- data/spec/commute/core/processors/request_builder_spec.rb +0 -25
- data/spec/commute/core/processors/sequencer_spec.rb +0 -33
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'commute/core/util/event_emitter'
|
2
|
+
|
3
|
+
module Commute
|
4
|
+
|
5
|
+
# Internal: A Simple Evented stream modelled after node.js' stream.
|
6
|
+
# More info: http://nodejs.org/api/stream.html.
|
7
|
+
#
|
8
|
+
# When you create a stream, you can write anything to it. For every
|
9
|
+
# write, an event 'data' is emitted to the listeners (evented reading).
|
10
|
+
#
|
11
|
+
# When a stream is ended, an 'end' event is emitted and the stream is
|
12
|
+
# not writeable anymore.
|
13
|
+
#
|
14
|
+
module Stream
|
15
|
+
include EventEmitter
|
16
|
+
|
17
|
+
class Simple
|
18
|
+
include Stream
|
19
|
+
end
|
20
|
+
|
21
|
+
# Internal: Opens a new writeable stream.
|
22
|
+
def initialize *args
|
23
|
+
super *args
|
24
|
+
@writeable = true
|
25
|
+
end
|
26
|
+
|
27
|
+
# Internal: Writes data to the stream.
|
28
|
+
# Note: Silenty does not write if the stream is not writeable (see #writable?).
|
29
|
+
#
|
30
|
+
# data - A chunk of data to write to the stream.
|
31
|
+
#
|
32
|
+
# Returns the written data (nil if no data was written).
|
33
|
+
def write data
|
34
|
+
if writeable?
|
35
|
+
emit :data, data
|
36
|
+
data
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Internal: Checks if the stream is writeable.
|
41
|
+
#
|
42
|
+
# Returns true if the stream is writeable.
|
43
|
+
def writeable?
|
44
|
+
@writeable
|
45
|
+
end
|
46
|
+
|
47
|
+
# Internal: Ends the stream.
|
48
|
+
# Note: After this, the stream is not writeable anymore.
|
49
|
+
#
|
50
|
+
# data - Last chunk of data to send.
|
51
|
+
#
|
52
|
+
# Returns Nothing
|
53
|
+
def end data = nil
|
54
|
+
emit :data, data if data
|
55
|
+
@writeable = false
|
56
|
+
emit :end
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# Internal: Pipes the stream to another stream.
|
61
|
+
#
|
62
|
+
# Whenever data is written to the source stream,
|
63
|
+
# it gets written to the destination stream.
|
64
|
+
# When the source stream end, the destinations stream
|
65
|
+
# is ended as well.
|
66
|
+
#
|
67
|
+
# destination - The stream to pipe to.
|
68
|
+
# options - For future use.
|
69
|
+
#
|
70
|
+
# Returns Nothing.
|
71
|
+
def pipe destination, options = {}
|
72
|
+
on(:data) { |chunk| destination.write chunk }
|
73
|
+
on(:end) { destination.end }
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
# Buffers data and emits the entire buffer.
|
78
|
+
# Calls << on the initial for every chunk in the stream.
|
79
|
+
#
|
80
|
+
# initial - The initial value of the buffer (default: []).
|
81
|
+
#
|
82
|
+
# Yields if done buffering.
|
83
|
+
# Returns a new buffered stream.
|
84
|
+
def buffer
|
85
|
+
inject [], &:<<
|
86
|
+
end
|
87
|
+
|
88
|
+
def >> sink
|
89
|
+
buffer.on(:data) { |buffer| sink.concat buffer }
|
90
|
+
end
|
91
|
+
|
92
|
+
def map &block
|
93
|
+
Simple.new.tap do |stream|
|
94
|
+
on(:data) { |chunk| stream.write block.call(chunk) }
|
95
|
+
on(:end) { stream.end }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def reject &block
|
100
|
+
Simple.new.tap do |stream|
|
101
|
+
on(:data) { |chunk| stream.write chunk unless block.call(chunk) }
|
102
|
+
on(:end) { stream.end }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def select &block
|
107
|
+
Simple.new.tap do |stream|
|
108
|
+
on(:data) { |chunk| stream.write chunk if block.call(chunk) }
|
109
|
+
on(:end) { stream.end }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def inject initial, &block
|
114
|
+
Simple.new.tap do |stream|
|
115
|
+
triggered = false
|
116
|
+
on(:data) do |chunk|
|
117
|
+
initial = block.call initial, chunk
|
118
|
+
triggered = true
|
119
|
+
end
|
120
|
+
on(:end) do
|
121
|
+
stream.write initial if triggered
|
122
|
+
stream.end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def take amount
|
128
|
+
Simple.new.tap do |stream|
|
129
|
+
count = 0
|
130
|
+
on(:data) do |chunk|
|
131
|
+
if count < amount
|
132
|
+
stream.write chunk
|
133
|
+
count += 1
|
134
|
+
else
|
135
|
+
stream.end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Commute
|
2
|
+
module Extension
|
3
|
+
|
4
|
+
# Public: Defines standard Restful CRUD actions.
|
5
|
+
#
|
6
|
+
# create -> POST
|
7
|
+
# read -> GET
|
8
|
+
# update -> PUT
|
9
|
+
# destroy -> DELETE
|
10
|
+
#
|
11
|
+
# Note: Implement "one" and "list" methods to
|
12
|
+
# hook on different CRUD selectors.
|
13
|
+
#
|
14
|
+
# Examples:
|
15
|
+
#
|
16
|
+
# gist = gists.find(1).run!
|
17
|
+
# gist[:description] = "Testing CRUD"
|
18
|
+
# gists.update(gist).where(id: 1).run
|
19
|
+
# gists.destroy(1).run
|
20
|
+
#
|
21
|
+
# # Making use of contexts.
|
22
|
+
# handle = gists.where(id: 1)
|
23
|
+
# gist = handle.find.run!
|
24
|
+
# gist[:description] = "Testing CRUD"
|
25
|
+
# handle.update(gist).run
|
26
|
+
# handle.destroy
|
27
|
+
#
|
28
|
+
module Crud
|
29
|
+
METHODS = [:all, :find, :update, :create, :destroy].freeze
|
30
|
+
|
31
|
+
# Public: An Extended CRUD extension that uses PATCH for updates.
|
32
|
+
#
|
33
|
+
# create -> POST
|
34
|
+
# read -> GET
|
35
|
+
# update -> PATCH
|
36
|
+
# replace -> PUT
|
37
|
+
# destroy -> DELETE
|
38
|
+
#
|
39
|
+
module Extended
|
40
|
+
include Crud
|
41
|
+
METHODS = [:all, :find, :update, :replace, :create, :destroy].freeze
|
42
|
+
|
43
|
+
# Public: Replaces a resource
|
44
|
+
def replace body = nil
|
45
|
+
put.body(body).try :one
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Updates a resource.
|
49
|
+
def update body = nil
|
50
|
+
patch.body(body).try :one
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Public: Get all resources.
|
55
|
+
def all
|
56
|
+
get.try :list
|
57
|
+
end
|
58
|
+
|
59
|
+
# Public: Find a resource using an id.
|
60
|
+
#
|
61
|
+
# id - The id of the resource (optional).
|
62
|
+
#
|
63
|
+
def find id = nil
|
64
|
+
with id: id
|
65
|
+
get.try :one
|
66
|
+
end
|
67
|
+
|
68
|
+
# Public: Updates a resource.
|
69
|
+
def update body = nil
|
70
|
+
put.body(body).try :one
|
71
|
+
end
|
72
|
+
|
73
|
+
# Public: Creates a resource.
|
74
|
+
def create body = nil
|
75
|
+
post.body(body).try :one
|
76
|
+
end
|
77
|
+
|
78
|
+
# Public: Destroys a resource.
|
79
|
+
#
|
80
|
+
# id - The id of the resource to destroy (optional).
|
81
|
+
#
|
82
|
+
def destroy id = nil
|
83
|
+
with id: id
|
84
|
+
delete.try :one
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Commute
|
2
|
+
module Extension
|
3
|
+
|
4
|
+
module Param
|
5
|
+
METHOD = [:param, :params]
|
6
|
+
|
7
|
+
def param name, param_name = name
|
8
|
+
transform name do |request, value|
|
9
|
+
request.query[param_name] = value
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def params names
|
14
|
+
names.each do |name|
|
15
|
+
self.param name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Commute
|
4
|
+
module Extension
|
5
|
+
|
6
|
+
# The url extensions provides an `url` method that pushes
|
7
|
+
# a transformation on the context that renders the required url
|
8
|
+
# based on a pattern.
|
9
|
+
#
|
10
|
+
# The pattern uses the standard ruby format specification. When
|
11
|
+
# not all variables are present, the url in sanitized in a
|
12
|
+
# way that it is valid again.
|
13
|
+
#
|
14
|
+
# Examples:
|
15
|
+
#
|
16
|
+
# class GistApi < Commute::Api
|
17
|
+
# include Commute::Extension::Url
|
18
|
+
#
|
19
|
+
# url 'https://api.github.com/gists/%{filter}'
|
20
|
+
#
|
21
|
+
# def user user = nil
|
22
|
+
# with(user: user)
|
23
|
+
# url('https://api.github.com/user/%{user}/gists').all
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
module Url
|
28
|
+
METHODS = [:url].freeze
|
29
|
+
|
30
|
+
# Public: Define the url pattern to use.
|
31
|
+
#
|
32
|
+
# pattern - The patter with variables between %{}.
|
33
|
+
#
|
34
|
+
# Returns self.
|
35
|
+
def url pattern
|
36
|
+
# Transform the context, filling in the url.
|
37
|
+
transform do |request, context|
|
38
|
+
# First, render the url pattern.
|
39
|
+
rendered = pattern.gsub(/%{([^}]*)}/) { |m| context[$1.to_sym] }
|
40
|
+
# Parse the rendered url using uri.
|
41
|
+
uri = URI rendered
|
42
|
+
# Substitute multiple / by one /.
|
43
|
+
uri.path.gsub! /\/+/, '/'
|
44
|
+
# Substiture /.format by .format
|
45
|
+
uri.path.sub! /\/\.([^\/]+)$/, '.\1'
|
46
|
+
|
47
|
+
# Assign the uri to the request.
|
48
|
+
request.uri = uri
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/commute/version.rb
CHANGED
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'commute/common/caching'
|
3
|
+
|
4
|
+
describe Commute::Common::Caching do
|
5
|
+
|
6
|
+
let(:cache) { stub }
|
7
|
+
|
8
|
+
let(:response) {
|
9
|
+
Commute::Http::Response.new(nil).tap { |response|
|
10
|
+
response.headers['ETag'] = 'A'
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
let(:body) {
|
15
|
+
{ some: ['complex', 'structure'] }
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:responder) {
|
19
|
+
proc { |router, request|
|
20
|
+
request.respond(response, status).tap { |response|
|
21
|
+
response.write body
|
22
|
+
response.end
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
let(:stack) {
|
28
|
+
Commute::Stack.new do |stack|
|
29
|
+
stack.sequence do |s|
|
30
|
+
s.append Commute::Common::Caching.new
|
31
|
+
s.append responder
|
32
|
+
end
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
let(:base) {
|
37
|
+
Commute::Context.new(stack).with(caching: {
|
38
|
+
cache: cache
|
39
|
+
}).context
|
40
|
+
}
|
41
|
+
|
42
|
+
describe 'a get request' do
|
43
|
+
let(:api) do
|
44
|
+
base.transform do |request|
|
45
|
+
request.method = :get
|
46
|
+
request.uri = URI('http://www.example.com')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'nothing in the cache' do
|
51
|
+
before do
|
52
|
+
cache.stubs(:get).returns nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should fire the request' do
|
56
|
+
responder.expects(:call).once.with do |router, request|
|
57
|
+
request.http.method.must_equal :get
|
58
|
+
end
|
59
|
+
call
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'the response was succesful' do
|
63
|
+
let(:status) { Commute::Http::Status.new(200) }
|
64
|
+
|
65
|
+
it 'should store the response in the cache and return the response' do
|
66
|
+
cache.expects(:set).with('http://www.example.com', {
|
67
|
+
data: body,
|
68
|
+
etag: 'A'
|
69
|
+
})
|
70
|
+
call
|
71
|
+
@body.must_equal body
|
72
|
+
@status.success?.must_equal true
|
73
|
+
@status.cached.must_equal false
|
74
|
+
@status.http.wont_be_nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'the response was not successful' do
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'something in the cache' do
|
83
|
+
before do
|
84
|
+
cache.stubs(:get).with('http://www.example.com').returns \
|
85
|
+
data: body,
|
86
|
+
etag: 'A'
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'without validation' do
|
90
|
+
it 'should return a response with the cached data' do
|
91
|
+
responder.expects(:call).never
|
92
|
+
call
|
93
|
+
@body.must_equal body
|
94
|
+
@status.success?.must_equal true
|
95
|
+
@status.cached.must_equal true
|
96
|
+
@status.updated.must_equal false
|
97
|
+
@status.http.must_be_nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'with validation' do
|
102
|
+
let(:base) {
|
103
|
+
Commute::Context.new(stack).with(caching: {
|
104
|
+
cache: cache,
|
105
|
+
validate: true
|
106
|
+
}).context
|
107
|
+
}
|
108
|
+
|
109
|
+
it 'should verify the etag of the resource' do
|
110
|
+
responder.expects(:call).once.with do |router, request|
|
111
|
+
request.http.headers['If-None-Match'].must_equal 'A'
|
112
|
+
end
|
113
|
+
call
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'the resource was not modified' do
|
117
|
+
let(:status) { Commute::Http::Status.new(304) }
|
118
|
+
|
119
|
+
it 'it should respond without updating the cache' do
|
120
|
+
cache.expects(:set).never
|
121
|
+
call
|
122
|
+
@body.must_equal body
|
123
|
+
@status.success?.must_equal true
|
124
|
+
@status.cached.must_equal true
|
125
|
+
@status.updated.must_equal false
|
126
|
+
@status.http.wont_be_nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe 'the resource was modified' do
|
131
|
+
let(:status) { Commute::Http::Status.new(200) }
|
132
|
+
|
133
|
+
it 'it should respond and update the cache' do
|
134
|
+
cache.expects(:set).with('http://www.example.com', {
|
135
|
+
data: body,
|
136
|
+
etag: 'A'
|
137
|
+
})
|
138
|
+
call
|
139
|
+
@body.must_equal body
|
140
|
+
@status.success?.must_equal true
|
141
|
+
@status.cached.must_equal true
|
142
|
+
@status.updated.must_equal true
|
143
|
+
@status.http.wont_be_nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'the response was not succesful' do
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def call
|
156
|
+
@body, @status = api.run
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'commute/common/eventmachine'
|
3
|
+
|
4
|
+
describe Commute::Common::Eventmachine do
|
5
|
+
|
6
|
+
let(:adapter) { Commute::Common::Eventmachine.new }
|
7
|
+
|
8
|
+
let(:router) { Commute::Stack::Router.new [adapter].each }
|
9
|
+
|
10
|
+
before do
|
11
|
+
@stub = stub_request(:post, "http://www.example.com/").with \
|
12
|
+
headers: {
|
13
|
+
'Accept-Encoding' => 'gzip, deflate'
|
14
|
+
},
|
15
|
+
body: 'Hello World!'
|
16
|
+
|
17
|
+
@done = proc {}
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should be able to make a successful request' do
|
21
|
+
@done.expects(:call).twice
|
22
|
+
EM.run do
|
23
|
+
# Stub the request.
|
24
|
+
@stub.to_return(status: 200, body: 'Hello!', headers: {})
|
25
|
+
|
26
|
+
# Create a Http Request.
|
27
|
+
http_request = Commute::Http::Request.new(nil).tap do |r|
|
28
|
+
r.uri = URI('http://www.example.com')
|
29
|
+
r.method = :post
|
30
|
+
end
|
31
|
+
|
32
|
+
# Execute the request.
|
33
|
+
request = router.call http_request do |response, status|
|
34
|
+
@done.call
|
35
|
+
status.success?.must_equal true
|
36
|
+
response.buffer.on(:data) do |body|
|
37
|
+
@done.call
|
38
|
+
body.join.must_equal 'Hello!'
|
39
|
+
end
|
40
|
+
|
41
|
+
EM.stop
|
42
|
+
end
|
43
|
+
request.write 'Hello'
|
44
|
+
request.write ' World!'
|
45
|
+
request.end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should be able to handle a bad response' do
|
50
|
+
@done.expects(:call).once
|
51
|
+
EM.run do
|
52
|
+
# Stub the request.
|
53
|
+
@stub.to_return(status: 500, headers: {})
|
54
|
+
|
55
|
+
# Create a Http Request.
|
56
|
+
http_request = Commute::Http::Request.new(nil).tap do |r|
|
57
|
+
r.uri = URI('http://www.example.com')
|
58
|
+
r.method = :post
|
59
|
+
end
|
60
|
+
|
61
|
+
# Execute the request.
|
62
|
+
request = router.call http_request do |response, status|
|
63
|
+
@done.call
|
64
|
+
status.fail?.must_equal true
|
65
|
+
response.on(:data) { @done.call }
|
66
|
+
|
67
|
+
EM.stop
|
68
|
+
end
|
69
|
+
request.write 'Hello'
|
70
|
+
request.write ' World!'
|
71
|
+
request.end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'commute/common/typhoeus'
|
3
|
+
|
4
|
+
describe Commute::Common::Typhoeus do
|
5
|
+
|
6
|
+
let(:adapter) { Commute::Common::Typhoeus.new }
|
7
|
+
|
8
|
+
let(:router) { Commute::Stack::Router.new [adapter].each }
|
9
|
+
|
10
|
+
before do
|
11
|
+
@stub = stub_request(:post, "http://www.example.com/").with \
|
12
|
+
headers: {
|
13
|
+
'User-Agent' => 'Typhoeus - https://github.com/typhoeus/typhoeus'
|
14
|
+
},
|
15
|
+
body: 'Hello World!'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be able to make a successful request' do
|
19
|
+
# Stub the request.
|
20
|
+
@stub.to_return(status: 200, body: 'Hello!', headers: {})
|
21
|
+
|
22
|
+
# Create a Http Request.
|
23
|
+
http_request = Commute::Http::Request.new(nil).tap do |r|
|
24
|
+
r.uri = URI('http://www.example.com')
|
25
|
+
r.method = :post
|
26
|
+
end
|
27
|
+
|
28
|
+
# Execute the request.
|
29
|
+
response, body, status = nil, [], nil
|
30
|
+
request = router.call http_request do |_response, _status|
|
31
|
+
_response >> body
|
32
|
+
response, status = _response, _status
|
33
|
+
end
|
34
|
+
request.write 'Hello'
|
35
|
+
request.write ' World!'
|
36
|
+
request.end
|
37
|
+
|
38
|
+
# Do some checks.
|
39
|
+
status.success?.must_equal true
|
40
|
+
body.join.must_equal 'Hello!'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should be able to handle a bad response' do
|
44
|
+
# Stub the request.
|
45
|
+
@stub.to_return(status: 500, headers: {})
|
46
|
+
|
47
|
+
# Create a Http Request.
|
48
|
+
http_request = Commute::Http::Request.new(nil).tap do |r|
|
49
|
+
r.uri = URI('http://www.example.com')
|
50
|
+
r.method = :post
|
51
|
+
end
|
52
|
+
|
53
|
+
# Execute the request.
|
54
|
+
response, body, status = nil, [], nil
|
55
|
+
request = router.call http_request do |_response, _status|
|
56
|
+
_response >> body
|
57
|
+
response, status = _response, _status
|
58
|
+
end
|
59
|
+
request.write 'Hello'
|
60
|
+
request.write ' World!'
|
61
|
+
request.end
|
62
|
+
|
63
|
+
# Do some checks.
|
64
|
+
status.fail?.must_equal true
|
65
|
+
body.must_be_empty
|
66
|
+
end
|
67
|
+
end
|
@@ -48,14 +48,16 @@ describe Commute::Api do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'should create a new Api instance when a method is called on the class' do
|
51
|
+
api_klass.builder[:id].must_equal 1
|
51
52
|
context = api_klass.with(id: 2).all.context
|
52
53
|
context.parameters.must_equal id: 2, text: 'go', help: true
|
54
|
+
api_klass.builder[:id].must_equal 1
|
53
55
|
end
|
54
56
|
|
55
57
|
it 'should deal with inheritance' do
|
56
58
|
context = TestInheritance.new.context
|
57
59
|
context.parameters[:id].must_equal 2
|
58
|
-
context.stack.sequence.
|
60
|
+
context.stack.sequence.size.must_be :>=, 2
|
59
61
|
end
|
60
62
|
|
61
63
|
describe '#new' do
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'commute/core/context'
|
3
|
-
require 'commute/core/
|
3
|
+
require 'commute/core/http'
|
4
4
|
|
5
5
|
describe Commute::Builder do
|
6
6
|
|
7
7
|
let(:parameters) {{}}
|
8
|
-
let(:stack) { Commute::Stack.new {
|
9
|
-
|
8
|
+
let(:stack) { Commute::Stack.new {
|
9
|
+
sequence.append Proc.new {}
|
10
10
|
}}
|
11
11
|
let(:transformations) {[]}
|
12
12
|
let(:disables) {[]}
|
@@ -15,7 +15,7 @@ describe Commute::Builder do
|
|
15
15
|
|
16
16
|
let(:builder) { Commute::Builder.new context }
|
17
17
|
|
18
|
-
let(:request) { Commute::Request.new }
|
18
|
+
let(:request) { Commute::Http::Request.new context }
|
19
19
|
|
20
20
|
describe '#with' do
|
21
21
|
it 'should add parameters to the context' do
|
@@ -82,18 +82,18 @@ describe Commute::Builder do
|
|
82
82
|
|
83
83
|
it 'should be able to add a dynamic transform without dependencies' do
|
84
84
|
context = builder.with(id: 1).transform { |request, context|
|
85
|
-
request.path = "/#{context[:id]}"
|
85
|
+
request.uri.path = "/#{context[:id]}"
|
86
86
|
}.context
|
87
87
|
context.transformations.first.call(request, context)
|
88
|
-
request.path.must_equal '/1'
|
88
|
+
request.uri.path.must_equal '/1'
|
89
89
|
end
|
90
90
|
|
91
91
|
it 'should be able to add a dynamic transform with dependencies' do
|
92
92
|
context = builder.with(id: 1).transform(:id) { |request, id|
|
93
|
-
request.path = "/#{id}"
|
93
|
+
request.uri.path = "/#{id}"
|
94
94
|
}.context
|
95
95
|
context.transformations.first.call(request, context)
|
96
|
-
request.path.must_equal '/1'
|
96
|
+
request.uri.path.must_equal '/1'
|
97
97
|
end
|
98
98
|
|
99
99
|
it 'should never call the transformation when its dependencies are all nil' do
|