commute 0.2.0.rc.2 → 0.3.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/.todo +28 -12
  2. data/README.md +0 -1
  3. data/commute.gemspec +4 -5
  4. data/lib/commute/common/basic_auth.rb +10 -9
  5. data/lib/commute/common/caching.rb +208 -0
  6. data/lib/commute/common/chemicals.rb +47 -24
  7. data/lib/commute/common/eventmachine.rb +68 -0
  8. data/lib/commute/common/synchrony.rb +42 -0
  9. data/lib/commute/common/typhoeus.rb +64 -0
  10. data/lib/commute/core/api.rb +42 -29
  11. data/lib/commute/core/builder.rb +4 -15
  12. data/lib/commute/core/context.rb +156 -15
  13. data/lib/commute/core/http.rb +124 -0
  14. data/lib/commute/core/layer.rb +187 -0
  15. data/lib/commute/core/sequence.rb +83 -132
  16. data/lib/commute/core/stack.rb +63 -72
  17. data/lib/commute/core/status.rb +45 -0
  18. data/lib/commute/core/util/event_emitter.rb +58 -0
  19. data/lib/commute/core/util/path.rb +37 -0
  20. data/lib/commute/core/util/stream.rb +141 -0
  21. data/lib/commute/extensions/crud.rb +88 -0
  22. data/lib/commute/extensions/param.rb +20 -0
  23. data/lib/commute/extensions/url.rb +53 -0
  24. data/lib/commute/version.rb +1 -1
  25. data/spec/commute/common/caching_spec.rb +158 -0
  26. data/spec/commute/common/eventmachine_spec.rb +74 -0
  27. data/spec/commute/common/typhoeus_spec.rb +67 -0
  28. data/spec/commute/core/api_spec.rb +3 -1
  29. data/spec/commute/core/builder_spec.rb +8 -8
  30. data/spec/commute/core/http_spec.rb +39 -0
  31. data/spec/commute/core/layer_spec.rb +81 -0
  32. data/spec/commute/core/sequence_spec.rb +36 -150
  33. data/spec/commute/core/stack_spec.rb +33 -83
  34. data/spec/commute/core/util/event_emitter_spec.rb +35 -0
  35. data/spec/commute/core/util/path_spec.rb +29 -0
  36. data/spec/commute/core/util/stream_spec.rb +90 -0
  37. data/spec/commute/extensions/url_spec.rb +76 -0
  38. data/spec/spec_helper.rb +3 -1
  39. metadata +61 -48
  40. data/examples/gist_api.rb +0 -71
  41. data/examples/highrise_task_api.rb +0 -59
  42. data/examples/pastie_api.rb +0 -18
  43. data/lib/commute/aspects/caching.rb +0 -37
  44. data/lib/commute/aspects/crud.rb +0 -41
  45. data/lib/commute/aspects/pagination.rb +0 -16
  46. data/lib/commute/aspects/url.rb +0 -57
  47. data/lib/commute/common/cache.rb +0 -43
  48. data/lib/commute/common/conditional.rb +0 -27
  49. data/lib/commute/common/em-synchrony_adapter.rb +0 -29
  50. data/lib/commute/common/em_http_request_adapter.rb +0 -57
  51. data/lib/commute/common/typhoeus_adapter.rb +0 -40
  52. data/lib/commute/common/xml.rb +0 -7
  53. data/lib/commute/core/commuter.rb +0 -116
  54. data/lib/commute/core/processors/code_status_processor.rb +0 -40
  55. data/lib/commute/core/processors/hook.rb +0 -14
  56. data/lib/commute/core/processors/request_builder.rb +0 -26
  57. data/lib/commute/core/processors/sequencer.rb +0 -46
  58. data/lib/commute/core/request.rb +0 -58
  59. data/lib/commute/core/response.rb +0 -18
  60. data/spec/commute/aspects/caching_spec.rb +0 -12
  61. data/spec/commute/aspects/url_spec.rb +0 -61
  62. data/spec/commute/core/commuter_spec.rb +0 -64
  63. data/spec/commute/core/processors/code_status_processor_spec.rb +0 -5
  64. data/spec/commute/core/processors/hook_spec.rb +0 -25
  65. data/spec/commute/core/processors/request_builder_spec.rb +0 -25
  66. data/spec/commute/core/processors/sequencer_spec.rb +0 -33
@@ -1,29 +0,0 @@
1
- require "em-synchrony"
2
- require "em-synchrony/em-http"
3
-
4
- require 'commute/common/em_http_request_adapter'
5
-
6
- module Commute
7
- module Common
8
-
9
- # Public: Adapter that uses em-synchrony (with em-http-request).
10
- #
11
- # Requires use of em-synchrony and thus Eventmachine.
12
- #
13
- class EmSynchronyAdapter < EmHttpRequestAdapter
14
- @id = :adapter
15
-
16
- # Internal: Make a request through em-synchrony.
17
- def call commuter, options = {}
18
- # Create a native em-http request.
19
- em_request = to_request commuter.get
20
-
21
- # Create a Commute response.
22
- response = to_response em_request.response_header, em_request.response
23
- response.request = commuter.get
24
- # Set it on the commuter.
25
- commuter.set response
26
- end
27
- end
28
- end
29
- end
@@ -1,57 +0,0 @@
1
- require 'em-http-request'
2
-
3
- require 'commute/core/response'
4
-
5
- module Commute
6
- module Common
7
-
8
- # Public: Adapter that uses em-http-request, an Eventmachine based
9
- # HTTP client, as a underlaying commute engine.
10
- #
11
- # This requires all the commute requests to be made within the
12
- # Eventmachine loop.
13
- #
14
- class EmHttpRequestAdapter
15
- @id = :adapter
16
-
17
- # Internal: Make a request through Eventmachine.
18
- def call commuter, options = {}
19
- # Commuter delay for async processing.
20
- commuter.delay do |&done|
21
- # Create a native em-http request.
22
- em_request = to_request commuter.get
23
-
24
- # Set the callback.
25
- em_request.callback do
26
- # Create a Commute response.
27
- response = to_response em_request.response_header, em_request.response
28
- response.request = request
29
- # Set it on the commuter.
30
- commuter.set response
31
- # Async call finished.
32
- done.call
33
- end
34
- end
35
- end
36
-
37
- protected
38
-
39
- # Internal: Converts a Commute requests into an em-http request.
40
- def to_request request
41
- EventMachine::HttpRequest.new(request.url).send request.method, \
42
- query: request.query,
43
- head: request.headers,
44
- body: request.body
45
- end
46
-
47
- # Internal: Converts an em-http response into a Commute response.
48
- # Note: trims whitespace bodies.
49
- def to_response em_response_header, em_response
50
- Commute::Response.new.tap do |response|
51
- response.code = em_response_header.status
52
- response.body = em_response unless em_response.strip.empty?
53
- end
54
- end
55
- end
56
- end
57
- end
@@ -1,40 +0,0 @@
1
- require 'typhoeus'
2
-
3
- require 'commute/core/response'
4
-
5
- module Commute
6
- module Common
7
-
8
- # Internal: Adapter that uses Typhoeus to make requests.
9
- #
10
- # Compatibility:
11
- #
12
- # TODO
13
- #
14
- class TyphoeusAdapter
15
- @id = :adapter
16
-
17
- def call commuter, options = {}
18
- commuter.change do |request|
19
- # puts request.inspect
20
- # Build a Typhoeus request from this request.
21
- typhoeus_request = Typhoeus::Request.new request.url, \
22
- method: request.method,
23
- body: request.body.to_s,
24
- params: request.query || {},
25
- headers: request.headers
26
- # Run the request.
27
- hydra = Typhoeus::Hydra.new
28
- hydra.queue typhoeus_request
29
- hydra.run
30
- typhoeus_response = typhoeus_request.response
31
- # Build a Commute response.
32
- Response.new(request).tap do |response|
33
- response.code = typhoeus_response.code
34
- response.body = typhoeus_response.body
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,7 +0,0 @@
1
- module Commute
2
- module Common
3
-
4
- class Xml
5
- end
6
- end
7
- end
@@ -1,116 +0,0 @@
1
- require 'commute/core/context'
2
-
3
- module Commute
4
-
5
- # Public: A Commuter is a package that holds a value
6
- # associated to a context.
7
- #
8
- # A commuter can be tagged to make conditional
9
- # processing possible.
10
- #
11
- class Commuter
12
- attr_reader :context
13
-
14
- # Public: Creates a new commuter
15
- def initialize context, value = nil
16
- @context = context
17
- @value = value
18
- @tags = []
19
- end
20
-
21
- # Public: Returns the inner value of the commuter.
22
- def get
23
- @value
24
- end
25
-
26
- # Public: Sets the inner value of the commuter.
27
- #
28
- # value - The new value.
29
- def set value
30
- @value = value
31
- end
32
-
33
- # Public: Changes the value of a commuter using a block.
34
- # ONLY calls the block if the commuter value is not nil.
35
- #
36
- # Yields the value of the commuter.
37
- #
38
- # Returns nothing
39
- def change
40
- @value = yield @value unless @value.nil?
41
- return nil
42
- end
43
-
44
- # Public: Get some parameters on how the commuter
45
- # should be processed within a certain processor.
46
- #
47
- # processor_id - The id of the processor
48
- #
49
- # Returns whatever set in the context for this processor.
50
- def parameters processor_id
51
- self.context[processor_id]
52
- end
53
-
54
- # TODO
55
- def disabled? processor_id
56
- false
57
- end
58
-
59
- # TODO
60
- def enabled? processor_id
61
- !disabled?(processor_id)
62
- end
63
-
64
- # Public: Tags the commuter.
65
- #
66
- # tag - The tag to tag with (can be any object).
67
- #
68
- # Returns nothing.
69
- def tag tag
70
- @tags << tag
71
- return nil
72
- end
73
-
74
- # Public: Checks if a commuter has a certain tag.
75
- #
76
- # tag - The tag to check presence of (can be any object).
77
- #
78
- # Returns true if the commuter is tagged with the given tag.
79
- def tagged? tag
80
- @tags.include? tag
81
- end
82
-
83
- # Public: Delays a commuter by giving it a block that
84
- # must definitely be executed before the commute can continue.
85
- #
86
- # delay - The delay that must be executed.
87
- #
88
- # Returns nothing.
89
- def delay &delay
90
- @delay = delay
91
- nil
92
- end
93
-
94
- def return
95
- delay {}
96
- end
97
-
98
- # Public: check if a commuter is delayed.
99
- def delayed?
100
- !!@delay
101
- end
102
-
103
- # Public: Wait for a delay to be executed.
104
- # And the do something when done.
105
- #
106
- # Yields when the delay has been executed.
107
- #
108
- # Returns nothing.
109
- def wait &done
110
- delay = @delay
111
- @delay = nil
112
- delay.call &done
113
- return nil
114
- end
115
- end
116
- end
@@ -1,40 +0,0 @@
1
- require 'commute/core/commuter'
2
-
3
- module Commute
4
-
5
- # Internal: Looks at a response and decides if it was
6
- # successful or not. This is the most basic one of
7
- # those checkers. It simply checks if the response
8
- # code is a 2xx code, when it is, the request was
9
- # a success.
10
- #
11
- # This processor replaces the commuter's Response
12
- #
13
- class CodeStatusProcessor
14
-
15
- class CodeStatus
16
- @id = :status
17
-
18
- attr_reader :code
19
-
20
- def initialize code
21
- @code = code
22
- @success = (200..299).include? code
23
- end
24
-
25
- def success?
26
- @success
27
- end
28
-
29
- def fail?
30
- !@success
31
- end
32
- end
33
-
34
- def call commuter
35
- commuter.change do |response|
36
- [response.body, CodeStatus.new(response.code)]
37
- end
38
- end
39
- end
40
- end
@@ -1,14 +0,0 @@
1
- require 'commute/core/commuter'
2
-
3
- module Commute
4
-
5
- # Public: A Hook is a processor that yields the commuter value to a handler.
6
- # The handler is given via the options for the processor (via its name).
7
- #
8
- class Hook
9
-
10
- def call commuter, handler = nil
11
- handler.call *commuter.get if handler
12
- end
13
- end
14
- end
@@ -1,26 +0,0 @@
1
- require 'commute/core/commuter'
2
- require 'commute/core/request'
3
-
4
- module Commute
5
-
6
- # Internal: A RequestBuilder builds a request given a context.
7
- #
8
- # It basically call all transformations defined on the context,
9
- # resulting in a request. The request is then passed as the new
10
- # value of the commuter (still with a reference to the context).
11
- #
12
- class RequestBuilder
13
- @id = :builder
14
-
15
- def call commuter
16
- # Create a new request.
17
- request = Request.new
18
- # Build the request using context transformations.
19
- commuter.context.transformations.each do |t|
20
- t.call request, commuter.context
21
- end
22
- # Set the request on the commuter.
23
- commuter.set request
24
- end
25
- end
26
- end
@@ -1,46 +0,0 @@
1
- require 'commute/core/commuter'
2
-
3
- module Commute
4
-
5
- # Public: A sequencer is a processor that lazily fetches a sequence
6
- # from the stack and executes it with the given commuter.
7
- #
8
- # This has the advantage that an either not ye existent sequence or
9
- # a sequence that could be modified later, can be referenced from
10
- # another sequence.
11
- #
12
- # Examples:
13
- #
14
- # Stack.new do |stack, main|
15
- # # Defining a new sequence.
16
- # response = stack.sequence(:response) do
17
- # ...
18
- # end
19
- #
20
- # # This would work but if we alter the response
21
- # # sequence later on, it would still use this one.
22
- # main.append response
23
- #
24
- # # Instead we do
25
- # main.append Sequencer.new(:response)
26
- # end
27
- #
28
- class Sequencer
29
-
30
- # Public: Creates a new sequencer.
31
- #
32
- # name - The name of the sequence that needs to be called (lazily).
33
- def initialize name
34
- @name = name
35
- end
36
-
37
- def call commuter
38
- # Get the stack from the processing context.
39
- stack = commuter.context.stack
40
- # Get the sequence we need to call.
41
- sequence = stack.get(@name)
42
- # Call the sequence if one was found.
43
- sequence.call commuter if sequence
44
- end
45
- end
46
- end
@@ -1,58 +0,0 @@
1
- require 'uri'
2
-
3
- module Commute
4
-
5
- class Request
6
-
7
- # Scheme (http(s))
8
- attr_accessor :scheme
9
-
10
- # Host to connect to (String).
11
- attr_accessor :host
12
-
13
- # Port to connect to (Integer).
14
- attr_accessor :port
15
-
16
- # Path to request (String).
17
- attr_accessor :path
18
-
19
- # Url parameters (Hash).
20
- attr_accessor :query
21
- alias :params :query
22
- alias :params= :query=
23
-
24
- # The HTTP Method of the request (Symbol).
25
- # Mostly :get, :post, :put, :patch, :delete
26
- attr_accessor :method
27
-
28
- # Request headers.
29
- attr_accessor :headers
30
-
31
- # The headers (Hash).
32
-
33
- # The Body.
34
- attr_accessor :body
35
-
36
- def initialize
37
- @headers = {}
38
- @query = {}
39
- end
40
-
41
- def url= url
42
- uri = URI url
43
- @scheme = uri.scheme
44
- @host = uri.host
45
- @port = uri.port
46
- @path = uri.path
47
- @query = Hash[uri.query.split('&').map { |p| p.split('=') }] if uri.query
48
- end
49
-
50
- # SCHEME! TODO
51
- def url
52
- query = @query.map { |k,v| "#{k}=#{v}" }.join '&'
53
- url = "#{@scheme}://#{@host}:#{@port}#{@path}"
54
- url << "?#{query}" unless query.nil? || query.empty?
55
- url
56
- end
57
- end
58
- end
@@ -1,18 +0,0 @@
1
- module Commute
2
-
3
- class Response
4
-
5
- # The request responsible for this response.
6
- attr_accessor :request
7
-
8
- # Response code.
9
- attr_accessor :code
10
-
11
- # The Body.
12
- attr_accessor :body
13
-
14
- def initialize request = nil
15
- @request = request
16
- end
17
- end
18
- end
@@ -1,12 +0,0 @@
1
- require 'spec_helper'
2
- require 'commute/aspects/caching'
3
-
4
- describe Commute::Aspect::Caching do
5
-
6
- class TestApi < Commute::Api
7
- include Commute::Aspect::Caching
8
- end
9
-
10
- it '' do
11
- end
12
- end
@@ -1,61 +0,0 @@
1
- require 'spec_helper'
2
- require 'commute/core/context'
3
- require 'commute/core/request'
4
- require 'commute/aspects/url'
5
-
6
- describe Commute::Aspect::Url do
7
-
8
- Klass = Class.new(Commute::Builder) do |klass|
9
- include Commute::Aspect::Url::ClassMethods
10
- end
11
-
12
- let(:request) { Commute::Request.new }
13
-
14
- it 'should create an url transformation without parameters' do
15
- transformation = example('http://api.example.com')
16
- # Hash that acts as a context.
17
- context = {}
18
- transformation.call(request, context)
19
- # Checks.
20
- request.scheme.must_equal 'http'
21
- request.host.must_equal 'api.example.com'
22
- request.path.must_be_empty
23
- end
24
-
25
- it 'should create an url transformation with parameters in the host and path' do
26
- transformation = example('https://api.$root.com:3000/1/$scope/$id.xml')
27
- # Hash that acts as a context.
28
- context = {
29
- root: 'example',
30
- scope: 'people',
31
- id: '3'
32
- }
33
- transformation.call(request, context)
34
- # Checks.
35
- request.scheme.must_equal 'https'
36
- request.host.must_equal 'api.example.com'
37
- request.path.must_equal '/1/people/3.xml'
38
- request.port.must_equal '3000'
39
- end
40
-
41
- it 'should create an url transformation with parameters in the host and path when only some of the values are present' do
42
- transformation = example('https://api.$root.com:3000/1/$scope/$id.xml')
43
- # Hash that acts as a context.
44
- context = {
45
- root: 'example',
46
- scope: 'people'
47
- }
48
- transformation.call(request, context)
49
- # Checks.
50
- request.scheme.must_equal 'https'
51
- request.host.must_equal 'api.example.com'
52
- request.path.must_equal '/1/people.xml'
53
- request.port.must_equal '3000'
54
- end
55
-
56
- private
57
-
58
- def example pattern
59
- Klass.new(Commute::Context.new).url(pattern).transformations.first
60
- end
61
- end
@@ -1,64 +0,0 @@
1
- require 'spec_helper'
2
- require 'commute/core/commuter'
3
-
4
- describe Commute::Commuter do
5
-
6
- let(:context) { mock }
7
-
8
- let(:commuter) { Commute::Commuter.new(context, 1) }
9
-
10
- describe '#change' do
11
- it 'should take a block that processes the value' do
12
- commuter.change { |number| number + 1 }
13
- commuter.get.must_equal 2
14
- end
15
-
16
- describe 'when there is no value' do
17
- let(:commuter) { Commute::Commuter.new(context, nil) }
18
-
19
- it 'should not call the block' do
20
- block = Proc.new { |n| n+1 }
21
- block.expects(:call).never
22
- commuter.change &block
23
- end
24
- end
25
- end
26
-
27
- describe '#tag' do
28
- it 'should tag the commuter' do
29
- commuter.tag :cool
30
- commuter.tagged?(:cool).must_equal true
31
- end
32
- end
33
-
34
- describe '#context' do
35
- it 'should return the associated context' do
36
- commuter.context.must_equal context
37
- end
38
- end
39
-
40
- describe '#parameters' do
41
- it 'should return parameters needed for a processor to process the commuter' do
42
- context.expects(:[]).with(:processor).returns operation: :multiply
43
- commuter.parameters(:processor).must_equal operation: :multiply
44
- end
45
- end
46
-
47
- describe '#wait' do
48
- it 'waits for a delay and does something when done waiting' do
49
- done = lambda { @done = true }
50
- delay = Proc.new { |&done| done.call }
51
- commuter.delay &delay
52
- commuter.delayed?.must_equal true
53
- commuter.wait &done
54
- @done.must_equal true
55
-
56
- done = lambda { @done = false }
57
- delay = Proc.new { }
58
- commuter.delay &delay
59
- done.expects(:call).never
60
- commuter.wait &done
61
- @done.must_equal true
62
- end
63
- end
64
- end
@@ -1,5 +0,0 @@
1
- require 'spec_helper'
2
- require 'commute/core/processors/code_status_processor'
3
-
4
- describe Commute::CodeStatusProcessor do
5
- end
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
- require 'commute/core/processors/hook'
3
-
4
- describe Commute::Hook do
5
-
6
- let(:hook) { Commute::Hook.new }
7
-
8
- let(:value) { mock }
9
-
10
- let(:commuter) { Commute::Commuter.new mock, value }
11
-
12
- describe 'when no handler is specified' do
13
- it 'should do nothing' do
14
- hook.call commuter
15
- end
16
- end
17
-
18
- describe 'when a handler is specified' do
19
- it 'should call the handler with the commuter value' do
20
- handler = mock
21
- handler.expects(:call).with(value)
22
- hook.call commuter, handler
23
- end
24
- end
25
- end
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
- require 'commute/core/processors/request_builder'
3
-
4
- describe Commute::RequestBuilder do
5
-
6
- let(:context) { Commute::Context.new }
7
-
8
- let(:builder) { Commute::RequestBuilder.new }
9
-
10
- it 'should transform the context' do
11
- c = context.get.
12
- transform(:id) { |request, id| request.url = "http://pastie.org/pastes/#{id}/text" }.
13
- with(id: 1)
14
-
15
- commuter = Commute::Commuter.new(c, nil)
16
-
17
- builder.call commuter
18
-
19
- commuter.get.tap { |request|
20
- request.host.must_equal 'pastie.org'
21
- request.path.must_equal '/pastes/1/text'
22
- request.method.must_equal :get
23
- }
24
- end
25
- end
@@ -1,33 +0,0 @@
1
- require 'spec_helper'
2
- require 'commute/core/processors/sequencer'
3
-
4
- describe Commute::Sequencer do
5
-
6
- let(:stack) { Commute::Stack.new {} }
7
-
8
- let(:context) { Commute::Context.new stack }
9
-
10
- let(:commuter) { Commute::Commuter.new context, mock }
11
-
12
- let(:sequencer) { Commute::Sequencer.new(:response) }
13
-
14
- describe 'The sequence is not defined in the stack' do
15
- it 'should do nothing' do
16
- sequencer.call commuter
17
- end
18
- end
19
-
20
- describe 'The sequence is defined in the stack' do
21
- let(:sequence) { mock }
22
- let(:commuter) do
23
- Commute::Commuter.new context.using { |stack, main|
24
- stack.add sequence, :response
25
- }.context, mock
26
- end
27
-
28
- it 'should call the sequence' do
29
- sequence.expects(:call).once
30
- sequencer.call commuter
31
- end
32
- end
33
- end