tylerhunt-relax 0.0.5 → 0.1.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.
- data/LICENSE +1 -1
- data/README.rdoc +194 -0
- data/Rakefile +54 -0
- data/VERSION.yml +4 -0
- data/lib/relax.rb +15 -10
- data/lib/relax/action.rb +49 -0
- data/lib/relax/context.rb +41 -0
- data/lib/relax/contextable.rb +15 -0
- data/lib/relax/endpoint.rb +21 -0
- data/lib/relax/instance.rb +23 -0
- data/lib/relax/parameter.rb +19 -0
- data/lib/relax/performer.rb +47 -0
- data/lib/relax/service.rb +20 -87
- data/spec/relax/context_spec.rb +10 -0
- data/spec/relax/endpoint_spec.rb +99 -0
- data/spec/relax/integration_spec.rb +63 -0
- data/spec/relax/service_spec.rb +32 -0
- data/spec/services/flickr.rb +78 -0
- data/spec/services/service_with_custom_parser.rb +28 -0
- data/spec/spec_helper.rb +13 -0
- metadata +77 -38
- data/README +0 -171
- data/lib/relax/parsers.rb +0 -13
- data/lib/relax/parsers/base.rb +0 -34
- data/lib/relax/parsers/factory.rb +0 -43
- data/lib/relax/parsers/hpricot.rb +0 -145
- data/lib/relax/parsers/rexml.rb +0 -158
- data/lib/relax/query.rb +0 -46
- data/lib/relax/request.rb +0 -95
- data/lib/relax/response.rb +0 -78
- data/lib/relax/symbolic_hash.rb +0 -79
- data/spec/parsers/factory_spec.rb +0 -29
- data/spec/parsers/hpricot_spec.rb +0 -35
- data/spec/parsers/rexml_spec.rb +0 -40
- data/spec/query_spec.rb +0 -60
- data/spec/request_spec.rb +0 -108
- data/spec/response_spec.rb +0 -98
- data/spec/symbolic_hash_spec.rb +0 -67
data/lib/relax/symbolic_hash.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
module Relax
|
2
|
-
# SymbolicHash provides an extension of Hash, but one that only supports keys
|
3
|
-
# that are symbols. This has been done in an effort to prevent the case where
|
4
|
-
# both a string key and a symbol key are set on the same hash, and espcially
|
5
|
-
# for dealing with this particular case when convert the hash to a string.
|
6
|
-
#
|
7
|
-
# === Example
|
8
|
-
#
|
9
|
-
# hash = Relax::SymbolicHash.new
|
10
|
-
# hash[:one] = 1
|
11
|
-
# hash['one'] = 2
|
12
|
-
# puts hash[:one] # => 2
|
13
|
-
#
|
14
|
-
# === Credits
|
15
|
-
#
|
16
|
-
# Some of the inspiration (and code) for this class comes from the
|
17
|
-
# HashWithIndifferentAccess that ships with Rails.
|
18
|
-
class SymbolicHash < Hash
|
19
|
-
def initialize(constructor = {})
|
20
|
-
if constructor.is_a?(Hash)
|
21
|
-
super()
|
22
|
-
update(constructor)
|
23
|
-
else
|
24
|
-
super(constructor)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def [](key)
|
29
|
-
super(convert_key(key))
|
30
|
-
end
|
31
|
-
|
32
|
-
def []=(key, value)
|
33
|
-
super(convert_key(key), convert_value(value))
|
34
|
-
end
|
35
|
-
|
36
|
-
def update(other_hash)
|
37
|
-
other_hash.each_pair { |key, value| store(convert_key(key), convert_value(value)) }
|
38
|
-
self
|
39
|
-
end
|
40
|
-
alias :merge! :update
|
41
|
-
|
42
|
-
def fetch(key, *extras)
|
43
|
-
super(convert_key(key), *extras)
|
44
|
-
end
|
45
|
-
|
46
|
-
def values_at(*indices)
|
47
|
-
indices.collect { |key| self[convert_key(key)] }
|
48
|
-
end
|
49
|
-
|
50
|
-
def dup
|
51
|
-
SymbolicHash.new(self)
|
52
|
-
end
|
53
|
-
|
54
|
-
def merge(hash)
|
55
|
-
self.dup.update(hash)
|
56
|
-
end
|
57
|
-
|
58
|
-
def delete(key)
|
59
|
-
super(convert_key(key))
|
60
|
-
end
|
61
|
-
|
62
|
-
def key?(key)
|
63
|
-
super(convert_key(key))
|
64
|
-
end
|
65
|
-
alias :include? :key?
|
66
|
-
alias :has_key? :key?
|
67
|
-
alias :member? :key?
|
68
|
-
|
69
|
-
protected
|
70
|
-
|
71
|
-
def convert_key(key)
|
72
|
-
!key.kind_of?(Symbol) ? key.to_sym : key
|
73
|
-
end
|
74
|
-
|
75
|
-
def convert_value(value)
|
76
|
-
value
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
-
|
3
|
-
require 'relax'
|
4
|
-
require 'relax/parsers/factory'
|
5
|
-
|
6
|
-
class TestParser ; end
|
7
|
-
|
8
|
-
describe 'a parser factory' do
|
9
|
-
|
10
|
-
before(:each) do
|
11
|
-
@factory = Relax::Parsers::Factory
|
12
|
-
Relax::Parsers::Factory.register(:test, TestParser)
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'should raise UnrecognizedParser for un-registered names' do
|
16
|
-
lambda {
|
17
|
-
@factory.get(:bad_name)
|
18
|
-
}.should raise_error(Relax::UnrecognizedParser)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'should return a registered parser class' do
|
22
|
-
@factory.get(:test).should ==TestParser
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should register the first registered parser as the default' do
|
26
|
-
@factory.get(:default).should ==Relax::Parsers::Hpricot
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
-
require File.dirname(__FILE__) + '/../parser_helper'
|
3
|
-
|
4
|
-
|
5
|
-
class HpricotTestResponse < Relax::Response
|
6
|
-
class Token < Relax::Response
|
7
|
-
parser :hpricot
|
8
|
-
parameter :token_id, :element => :tokenid
|
9
|
-
parameter :status
|
10
|
-
end
|
11
|
-
|
12
|
-
class Error < Relax::Response
|
13
|
-
parser :hpricot
|
14
|
-
parameter :code, :type => :integer
|
15
|
-
parameter :message
|
16
|
-
end
|
17
|
-
|
18
|
-
parser :hpricot
|
19
|
-
parameter :status, :required => true
|
20
|
-
parameter :request_id, :element => :requestid, :type => :integer
|
21
|
-
parameter :valid_request, :element => :requestid, :attribute => :valid
|
22
|
-
parameter :tokens, :collection => Token
|
23
|
-
parameter :error, :type => Error
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
describe 'an Hpricot parser' do
|
28
|
-
|
29
|
-
before(:each) do
|
30
|
-
@response = HpricotTestResponse.new(XML)
|
31
|
-
end
|
32
|
-
|
33
|
-
it_should_behave_like 'a successfully parsed response'
|
34
|
-
|
35
|
-
end
|
data/spec/parsers/rexml_spec.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
-
require File.dirname(__FILE__) + '/../parser_helper'
|
3
|
-
|
4
|
-
|
5
|
-
class RexmlTestResponse < Relax::Response
|
6
|
-
class Token < Relax::Response
|
7
|
-
parser :rexml
|
8
|
-
parameter :token_id, :element => 'TokenId'
|
9
|
-
parameter :status, :element => 'Status'
|
10
|
-
end
|
11
|
-
|
12
|
-
class Error < Relax::Response
|
13
|
-
parser :rexml
|
14
|
-
parameter :code, :element => 'Code', :type => :integer
|
15
|
-
parameter :message, :element => 'Message'
|
16
|
-
end
|
17
|
-
|
18
|
-
parser :rexml
|
19
|
-
parameter :status, :element => 'Status', :required => true
|
20
|
-
parameter :request_id, :element => 'RequestId', :type => :integer
|
21
|
-
parameter :valid_request, :element => 'RequestId', :attribute => :valid
|
22
|
-
parameter :namespace, :element => 'Namespace', :namespace => 'ns1'
|
23
|
-
parameter :tokens, :element => 'Tokens', :collection => Token
|
24
|
-
parameter :error, :element => 'Error', :type => Error
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
describe 'a REXML parser' do
|
29
|
-
|
30
|
-
before(:each) do
|
31
|
-
@response = RexmlTestResponse.new(XML)
|
32
|
-
end
|
33
|
-
|
34
|
-
it_should_behave_like 'a successfully parsed response'
|
35
|
-
|
36
|
-
it 'should parse namespaced parameters' do
|
37
|
-
@response.namespace.should eql('Passed')
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
data/spec/query_spec.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
-
|
3
|
-
require 'relax/query'
|
4
|
-
|
5
|
-
describe 'a query' do
|
6
|
-
before(:each) do
|
7
|
-
@uri = URI::parse('http://example.com/?action=search&query=keyword')
|
8
|
-
@query = Relax::Query.new
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'should convert to a query string' do
|
12
|
-
@query[:action] = 'Search'
|
13
|
-
@query[:query] = 'strings'
|
14
|
-
@query.to_s.should eql('action=Search&query=strings')
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'should convert its values to strings' do
|
18
|
-
date = Date.today
|
19
|
-
@query[:date] = date
|
20
|
-
@query.to_s.should eql("date=#{date.to_s}")
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'should escape its values using "+" instead of "%20"' do
|
24
|
-
Relax::Query.send(:escape_value, 'two words').should == 'two+words'
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'should sort its parameters' do
|
28
|
-
@query[:charlie] = 3
|
29
|
-
@query[:alpha] = 1
|
30
|
-
@query[:bravo] = 2
|
31
|
-
@query.to_s.should eql('alpha=1&bravo=2&charlie=3')
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'should encode its parameter values' do
|
35
|
-
@query[:spaces] = 'two words'
|
36
|
-
@query[:url] = 'http://example.com/'
|
37
|
-
@query.to_s.should eql('spaces=two+words&url=http%3A%2F%2Fexample.com%2F')
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should be able to parse query strings' do
|
41
|
-
parsed_query = Relax::Query.parse(@uri)
|
42
|
-
parsed_query[:action].should eql('search')
|
43
|
-
parsed_query[:query].should eql('keyword')
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'should parse key value pairs into only two parts' do
|
47
|
-
parsed_query = Relax::Query.parse(URI.parse("http://example.com/?action=test=&foo=bar"))
|
48
|
-
parsed_query[:action].should eql('test=')
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'should unescape query string key-value pair keys' do
|
52
|
-
parsed_query = Relax::Query.parse(URI.parse("http://example.com/?action%20helper=test"))
|
53
|
-
parsed_query[:"action helper"].should eql('test')
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'should unescape query string key-value pair values' do
|
57
|
-
parsed_query = Relax::Query.parse(URI.parse("http://example.com/?action=test%20action"))
|
58
|
-
parsed_query[:action].should eql('test action')
|
59
|
-
end
|
60
|
-
end
|
data/spec/request_spec.rb
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
-
|
3
|
-
require 'relax/request'
|
4
|
-
|
5
|
-
class Amount < Relax::Request
|
6
|
-
parameter :amount
|
7
|
-
parameter :currency
|
8
|
-
end
|
9
|
-
|
10
|
-
class TestRequest < Relax::Request
|
11
|
-
parameter :action
|
12
|
-
parameter :token_id
|
13
|
-
parameter :user_id
|
14
|
-
parameter :amount, :type => Amount
|
15
|
-
end
|
16
|
-
|
17
|
-
class ChildRequest < TestRequest
|
18
|
-
parameter :child_id
|
19
|
-
end
|
20
|
-
|
21
|
-
describe 'an option initialized request', :shared => true do
|
22
|
-
it 'should have its values set by the options hash' do
|
23
|
-
request = TestRequest.new(:action => 'FetchAll', :token_id => 123)
|
24
|
-
request.action.should eql('FetchAll')
|
25
|
-
request.token_id.should eql(123)
|
26
|
-
request.user_id.should be_nil
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe 'a request that converts to a query', :shared => true do
|
31
|
-
before(:each) do
|
32
|
-
@query = TestRequest.new(:action => 'Search', :token_id => 123).to_query
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'should include its parameters in the query' do
|
36
|
-
@query[:action].should eql('Search')
|
37
|
-
@query[:token_id].should eql('123')
|
38
|
-
@query[:user_id].should be_nil
|
39
|
-
@query[:amount].should be_nil
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'should only include parameters in the query if they are set' do
|
43
|
-
@query.key?(:action).should be_true
|
44
|
-
@query.key?(:token_id).should be_true
|
45
|
-
@query.key?(:user_id).should be_false
|
46
|
-
@query.key?(:amount).should be_false
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe 'a normal request' do
|
51
|
-
it_should_behave_like 'a request that converts to a query'
|
52
|
-
it_should_behave_like 'an option initialized request'
|
53
|
-
end
|
54
|
-
|
55
|
-
describe 'a template request' do
|
56
|
-
it_should_behave_like 'a request that converts to a query'
|
57
|
-
it_should_behave_like 'an option initialized request'
|
58
|
-
|
59
|
-
before(:each) do
|
60
|
-
# this syntax may need to go away unless we can find a way to make it work
|
61
|
-
TestRequest[:api_key] = '123456'
|
62
|
-
TestRequest[:secret] = 'shhh!'
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'should always have the template values in its query' do
|
66
|
-
request = TestRequest.new
|
67
|
-
request.api_key.should eql('123456')
|
68
|
-
request.secret.should eql('shhh!')
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'should allow its template variables to be overridden' do
|
72
|
-
request = TestRequest.new(:secret => 'abracadabra')
|
73
|
-
request.api_key.should eql('123456')
|
74
|
-
request.secret.should eql('abracadabra')
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'should pass its template on to its children' do
|
78
|
-
request = ChildRequest.new
|
79
|
-
request.api_key.should eql('123456')
|
80
|
-
request.secret.should eql('shhh!')
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'should allow template parameters on its children that are additive' do
|
84
|
-
ChildRequest[:query] = '1a2b3c'
|
85
|
-
child = ChildRequest.new
|
86
|
-
child.api_key.should eql('123456')
|
87
|
-
child.secret.should eql('shhh!')
|
88
|
-
child.query.should eql('1a2b3c')
|
89
|
-
|
90
|
-
parent = TestRequest.new
|
91
|
-
parent.api_key.should eql('123456')
|
92
|
-
parent.secret.should eql('shhh!')
|
93
|
-
parent.respond_to?(:query).should be_false
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
describe 'a request with a custom type' do
|
98
|
-
before(:each) do
|
99
|
-
request = TestRequest.new(:action => 'Pay', :token_id => 123)
|
100
|
-
request.amount = Amount.new(:amount => 3.50, :currency => 'USD')
|
101
|
-
@query = request.to_query
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'should add the type parameters to the query' do
|
105
|
-
@query.key?(:"amount.amount").should be_true
|
106
|
-
@query.key?(:"amount.currency").should be_true
|
107
|
-
end
|
108
|
-
end
|
data/spec/response_spec.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
-
|
3
|
-
|
4
|
-
class BaseResponse < Relax::Response
|
5
|
-
parameter :status, :required => true
|
6
|
-
parameter :request_id, :element => :requestid, :type => :integer
|
7
|
-
end
|
8
|
-
|
9
|
-
class TestResponse < BaseResponse
|
10
|
-
class Token < Relax::Response
|
11
|
-
parameter :token_id, :element => :tokenid
|
12
|
-
parameter :status
|
13
|
-
end
|
14
|
-
|
15
|
-
class Error < Relax::Response
|
16
|
-
parser :hpricot
|
17
|
-
parameter :code, :type => :integer
|
18
|
-
parameter :message
|
19
|
-
end
|
20
|
-
|
21
|
-
parameter :valid_request, :element => :requestid, :attribute => :valid
|
22
|
-
parameter :tokens, :collection => Token
|
23
|
-
parameter :error, :type => Error
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
describe 'a response' do
|
28
|
-
before(:each) do
|
29
|
-
@response = Relax::Response.new(XML)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should allow access to the root' do
|
33
|
-
root = @response.root
|
34
|
-
root.should be_an_instance_of(Hpricot::Elem)
|
35
|
-
root.name.should eql('RESTResponse')
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'should be checkable by the name of its root' do
|
39
|
-
@response.is?(:RESTResponse).should be_true
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'should allow access to an element by its name' do
|
43
|
-
@response.element(:RequestId).should be_an_instance_of(Hpricot::Elem)
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'should allow access to an element\'s elements by its name' do
|
47
|
-
tokens = @response.elements(:Tokens)
|
48
|
-
tokens.should be_an_instance_of(Hpricot::Elements)
|
49
|
-
tokens.should_not be_empty
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'should allow access to an element\'s value by its name' do
|
53
|
-
token = Relax::Response.new(@response.elements(:Tokens).first)
|
54
|
-
token.element(:TokenId).inner_text.should eql('JPMQARDVJK')
|
55
|
-
token.element(:Status).inner_text.should eql('Active')
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'should have a means of checking for the existence of a node' do
|
59
|
-
@response.has?(:Status).should_not be_nil
|
60
|
-
@response.has?(:Errors).should be_nil
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'should be able to define children of Response without modifying parent' do
|
64
|
-
Relax::Response.new(XML).respond_to?(:status).should be_false
|
65
|
-
TestResponse.new(XML).respond_to?(:status).should be_true
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'should automatically pull parameters from the XML' do
|
69
|
-
response = TestResponse.new(XML)
|
70
|
-
response.valid_request.should eql('true')
|
71
|
-
response.tokens.length.should eql(2)
|
72
|
-
response.tokens.first.status.should eql('Active')
|
73
|
-
response.error.code.should eql(1)
|
74
|
-
response.error.message.should eql('Failed')
|
75
|
-
end
|
76
|
-
|
77
|
-
it "should automatically pull its parent's parameters from the XML" do
|
78
|
-
response = TestResponse.new(XML)
|
79
|
-
response.status.should eql('Success')
|
80
|
-
response.request_id.should eql(44287)
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'should be relationally equivalent to its children' do
|
84
|
-
(Relax::Response === TestResponse).should be_true
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'should raise MissingParameter if required parameters are missing' do
|
88
|
-
proc { TestResponse.new('') }.should raise_error(Relax::MissingParameter)
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'should use the default parser when undefined' do
|
92
|
-
TestResponse::Token.new('').parser_name.should ==:default
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'should use the defined parser when given' do
|
96
|
-
TestResponse::Error.new('').parser_name.should ==:hpricot
|
97
|
-
end
|
98
|
-
end
|