couchmodel 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -1
- data/Rakefile +5 -5
- data/lib/core_extension/string.rb +10 -7
- data/lib/couch_model/base.rb +9 -9
- data/lib/couch_model/base/accessor.rb +2 -0
- data/lib/couch_model/collection.rb +3 -3
- data/lib/couch_model/database.rb +4 -4
- data/lib/couch_model/design.rb +11 -11
- data/lib/couch_model/server.rb +5 -5
- data/lib/transport/base.rb +65 -0
- data/lib/transport/json.rb +69 -0
- data/lib/transport/request/builder.rb +59 -0
- data/lib/transport/request/parameter/serializer.rb +60 -0
- data/spec/fake_transport_helper.rb +7 -2
- data/spec/lib/couch_model/active_model_spec.rb +6 -1
- data/spec/lib/couch_model/{core → base}/accessor_spec.rb +21 -9
- data/spec/lib/couch_model/{core → base}/association_spec.rb +0 -0
- data/spec/lib/couch_model/{core → base}/finder_spec.rb +0 -0
- data/spec/lib/couch_model/{core → base}/setup_spec.rb +0 -0
- data/spec/lib/couch_model/base_spec.rb +4 -4
- data/spec/lib/couch_model/collection_spec.rb +2 -2
- data/spec/lib/couch_model/database_spec.rb +4 -4
- data/spec/lib/transport/base_spec.rb +49 -0
- data/spec/lib/transport/json_spec.rb +56 -0
- data/spec/lib/transport/request/builder_spec.rb +51 -0
- data/spec/lib/transport/request/parameter/serializer_spec.rb +16 -0
- metadata +26 -15
- data/lib/couch_model/transport.rb +0 -178
- data/spec/lib/couch_model/transport_spec.rb +0 -114
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Transport
|
4
|
+
|
5
|
+
module Request
|
6
|
+
|
7
|
+
module Parameter
|
8
|
+
|
9
|
+
# Serializer for transport http parameters
|
10
|
+
class Serializer
|
11
|
+
|
12
|
+
def initialize(parameters = nil)
|
13
|
+
@parameters = parameters || { }
|
14
|
+
end
|
15
|
+
|
16
|
+
def query
|
17
|
+
return @serialized_parameters if @serialized_parameters
|
18
|
+
|
19
|
+
serialize_parameters
|
20
|
+
@serialized_parameters
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def serialize_parameters
|
26
|
+
quote_parameters
|
27
|
+
@serialized_parameters = if @parameters.nil? || @parameters.empty?
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
@quoted_parameters.collect do |key, value|
|
31
|
+
self.class.pair key, value
|
32
|
+
end.join("&")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def quote_parameters
|
37
|
+
@quoted_parameters = { }
|
38
|
+
@parameters.each do |key, value|
|
39
|
+
encoded_key = CGI.escape(key.to_s)
|
40
|
+
@quoted_parameters[encoded_key] = self.class.escape value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.pair(key, value)
|
45
|
+
value.is_a?(Array) ?
|
46
|
+
value.map{ |element| "#{key}=#{element}" }.join("&") :
|
47
|
+
"#{key}=#{value}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.escape(value)
|
51
|
+
value.is_a?(Array) ? value.map{ |element| CGI.escape element } : CGI.escape(value)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "transport", "json"))
|
1
2
|
require 'yaml'
|
2
3
|
|
3
4
|
module FakeTransport
|
@@ -11,7 +12,11 @@ module FakeTransport
|
|
11
12
|
end
|
12
13
|
|
13
14
|
def self.transport_class
|
14
|
-
|
15
|
+
Transport::JSON
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.unexpected_status_code_error_class
|
19
|
+
Transport::UnexpectedStatusCodeError
|
15
20
|
end
|
16
21
|
|
17
22
|
def self.fake!
|
@@ -30,7 +35,7 @@ module FakeTransport
|
|
30
35
|
hash[:headers] == headers
|
31
36
|
end
|
32
37
|
raise StandardError, "no fake request found for [#{http_method} #{url} #{parameters.inspect} #{headers.inspect}]" unless request
|
33
|
-
raise
|
38
|
+
raise unexpected_status_code_error_class.new(request[:response][:code].to_i, request[:response][:body]) if expected_status_code && expected_status_code.to_s != request[:response][:code]
|
34
39
|
request[:response][:body].dup
|
35
40
|
end
|
36
41
|
end
|
@@ -254,7 +254,12 @@ describe ActiveTestModel do
|
|
254
254
|
end
|
255
255
|
|
256
256
|
it "should return all attributes as xml" do
|
257
|
-
@model.to_xml
|
257
|
+
xml = @model.to_xml
|
258
|
+
xml.should =~ /^<\?xml version=.+1\.0.+ encoding=.+UTF-8.+\?>/
|
259
|
+
xml.should =~ /<model-class>ActiveTestModel<\/model-class>/
|
260
|
+
xml.should =~ /<-id>test_model_1<\/-id>/
|
261
|
+
xml.should =~ /<name>test<\/name>/
|
262
|
+
xml.should =~ /<email>test<\/email>/
|
258
263
|
end
|
259
264
|
|
260
265
|
end
|
@@ -5,6 +5,9 @@ class AccessorTestModel < CouchModel::Base
|
|
5
5
|
|
6
6
|
setup_database :url => "http://localhost:5984/test"
|
7
7
|
|
8
|
+
key_reader :test_one, :default => "test default"
|
9
|
+
key_writer :test_two, :default => "test default"
|
10
|
+
key_accessor :test_three, :default => "test default"
|
8
11
|
end
|
9
12
|
|
10
13
|
describe AccessorTestModel do
|
@@ -16,16 +19,21 @@ describe AccessorTestModel do
|
|
16
19
|
describe "key_reader" do
|
17
20
|
|
18
21
|
before :each do
|
19
|
-
AccessorTestModel.key_reader :test, :default => "test default"
|
20
22
|
@model = AccessorTestModel.new
|
21
23
|
end
|
22
24
|
|
23
25
|
it "should define a reader method" do
|
24
|
-
@model.should respond_to(:
|
26
|
+
@model.should respond_to(:test_one)
|
25
27
|
end
|
26
28
|
|
27
29
|
it "should set a default value" do
|
28
|
-
@model.
|
30
|
+
@model.test_one.should == "test default"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should raise an exception if the reader method is already defined" do
|
34
|
+
lambda do
|
35
|
+
AccessorTestModel.key_reader :test_one
|
36
|
+
end.should raise_error(ArgumentError)
|
29
37
|
end
|
30
38
|
|
31
39
|
end
|
@@ -33,16 +41,21 @@ describe AccessorTestModel do
|
|
33
41
|
describe "key_writer" do
|
34
42
|
|
35
43
|
before :each do
|
36
|
-
AccessorTestModel.key_writer :test, :default => "test default"
|
37
44
|
@model = AccessorTestModel.new
|
38
45
|
end
|
39
46
|
|
40
47
|
it "should define a writer method" do
|
41
|
-
@model.should respond_to(:
|
48
|
+
@model.should respond_to(:test_two=)
|
42
49
|
end
|
43
50
|
|
44
51
|
it "should set a default value" do
|
45
|
-
|
52
|
+
AccessorTestModel.defaults["test_two"].should == "test default"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should raise an exception if the writer method is already defined" do
|
56
|
+
lambda do
|
57
|
+
AccessorTestModel.key_writer :test_two
|
58
|
+
end.should raise_error(ArgumentError)
|
46
59
|
end
|
47
60
|
|
48
61
|
end
|
@@ -50,16 +63,15 @@ describe AccessorTestModel do
|
|
50
63
|
describe "key_accessor" do
|
51
64
|
|
52
65
|
before :each do
|
53
|
-
AccessorTestModel.key_accessor(:test, :default => "test default")
|
54
66
|
@model = AccessorTestModel.new
|
55
67
|
end
|
56
68
|
|
57
69
|
it "should define a reader method" do
|
58
|
-
@model.should respond_to(:
|
70
|
+
@model.should respond_to(:test_three)
|
59
71
|
end
|
60
72
|
|
61
73
|
it "should define a writer method" do
|
62
|
-
@model.should respond_to(:
|
74
|
+
@model.should respond_to(:test_three=)
|
63
75
|
end
|
64
76
|
|
65
77
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -93,7 +93,7 @@ describe BaseTestModel do
|
|
93
93
|
end
|
94
94
|
|
95
95
|
it "should return false on wrong status code" do
|
96
|
-
|
96
|
+
Transport::JSON.stub!(:request).and_raise(Transport::UnexpectedStatusCodeError.new(404))
|
97
97
|
do_save.should be_false
|
98
98
|
end
|
99
99
|
|
@@ -110,7 +110,7 @@ describe BaseTestModel do
|
|
110
110
|
end
|
111
111
|
|
112
112
|
it "should return false on wrong status code" do
|
113
|
-
|
113
|
+
Transport::JSON.stub!(:request).and_raise(Transport::UnexpectedStatusCodeError.new(404))
|
114
114
|
do_save.should be_false
|
115
115
|
end
|
116
116
|
|
@@ -143,7 +143,7 @@ describe BaseTestModel do
|
|
143
143
|
end
|
144
144
|
|
145
145
|
it "should raise NotFoundError on wrong status code" do
|
146
|
-
|
146
|
+
Transport::JSON.stub!(:request).and_raise(Transport::UnexpectedStatusCodeError.new(404))
|
147
147
|
lambda do
|
148
148
|
do_destroy
|
149
149
|
end.should raise_error(CouchModel::Base::NotFoundError)
|
@@ -175,7 +175,7 @@ describe BaseTestModel do
|
|
175
175
|
end
|
176
176
|
|
177
177
|
it "should return nil on error" do
|
178
|
-
|
178
|
+
Transport::JSON.stub!(:request).and_raise(Transport::UnexpectedStatusCodeError.new(500))
|
179
179
|
model = BaseTestModel.create :id => "test_model_1"
|
180
180
|
model.should be_nil
|
181
181
|
end
|
@@ -41,7 +41,7 @@ describe CouchModel::Collection do
|
|
41
41
|
describe "without a previously performed fetch" do
|
42
42
|
|
43
43
|
it "should perform a meta fetch (with a limit of zero)" do
|
44
|
-
|
44
|
+
Transport::JSON.should_receive(:request).with(anything, anything,
|
45
45
|
hash_including(:parameters => { :include_docs => true, :limit => 0 }))
|
46
46
|
@collection.total_count
|
47
47
|
end
|
@@ -59,7 +59,7 @@ describe CouchModel::Collection do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should not perform another fetch" do
|
62
|
-
|
62
|
+
Transport::JSON.should_not_receive(:request)
|
63
63
|
@collection.total_count
|
64
64
|
end
|
65
65
|
|
@@ -49,11 +49,11 @@ describe CouchModel::Database do
|
|
49
49
|
|
50
50
|
before :each do
|
51
51
|
@response = { :code => "201" }
|
52
|
-
|
52
|
+
Transport::JSON.stub!(:request).and_return(@response)
|
53
53
|
end
|
54
54
|
|
55
55
|
it "should create the database" do
|
56
|
-
|
56
|
+
Transport::JSON.should_receive(:request).with(:put, /test$/, anything).and_return(@response)
|
57
57
|
@database.create!
|
58
58
|
end
|
59
59
|
|
@@ -83,11 +83,11 @@ describe CouchModel::Database do
|
|
83
83
|
|
84
84
|
before :each do
|
85
85
|
@response = { :code => "200" }
|
86
|
-
|
86
|
+
Transport::JSON.stub!(:request).and_return(@response)
|
87
87
|
end
|
88
88
|
|
89
89
|
it "should delete the database" do
|
90
|
-
|
90
|
+
Transport::JSON.should_receive(:request).with(:delete, /test$/, anything).and_return(@response)
|
91
91
|
@database.delete!
|
92
92
|
end
|
93
93
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "transport", "base"))
|
3
|
+
|
4
|
+
describe Transport::Base do
|
5
|
+
|
6
|
+
use_real_transport!
|
7
|
+
|
8
|
+
describe "request" do
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
@http_method = :get
|
12
|
+
@url = "http://localhost:5984/"
|
13
|
+
@options = { }
|
14
|
+
|
15
|
+
@request_builder = Transport::Request::Builder.new @http_method, @url, @options
|
16
|
+
|
17
|
+
@response = Object.new
|
18
|
+
@response.stub!(:code).and_return("200")
|
19
|
+
@response.stub!(:body).and_return("test")
|
20
|
+
Net::HTTP.stub!(:start).and_return(@response)
|
21
|
+
end
|
22
|
+
|
23
|
+
def do_request(options = { })
|
24
|
+
Transport::Base.request @http_method, @url, @options.merge(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should initialize the correct request builder" do
|
28
|
+
Transport::Request::Builder.should_receive(:new).with(@http_method, @url, @options).and_return(@request_builder)
|
29
|
+
do_request
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should perform the request" do
|
33
|
+
Net::HTTP.should_receive(:start).and_return(@response)
|
34
|
+
do_request
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return the response" do
|
38
|
+
do_request.body.should == "test"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should raise UnexpectedStatusCodeError if responded status code is wrong" do
|
42
|
+
lambda do
|
43
|
+
do_request :expected_status_code => 201
|
44
|
+
end.should raise_error(Transport::UnexpectedStatusCodeError)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "transport", "json"))
|
3
|
+
|
4
|
+
describe Transport::JSON do
|
5
|
+
|
6
|
+
use_real_transport!
|
7
|
+
|
8
|
+
describe "request" do
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
@http_method = :get
|
12
|
+
@url = "http://localhost:5984/"
|
13
|
+
@options = {
|
14
|
+
:auth_type => :basic,
|
15
|
+
:username => "test",
|
16
|
+
:password => "test",
|
17
|
+
:body => "test"
|
18
|
+
}
|
19
|
+
|
20
|
+
@request_builder = Transport::Request::Builder.new @http_method, @url, @options
|
21
|
+
|
22
|
+
@response = Object.new
|
23
|
+
@response.stub!(:code).and_return("200")
|
24
|
+
@response.stub!(:body).and_return("{\"test\":\"test\"}")
|
25
|
+
Net::HTTP.stub!(:start).and_return(@response)
|
26
|
+
end
|
27
|
+
|
28
|
+
def do_request(options = { })
|
29
|
+
Transport::JSON.request @http_method, @url, @options.merge(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should initialize the correct request object" do
|
33
|
+
Transport::Request::Builder.should_receive(:new).with(
|
34
|
+
@http_method, @url, hash_including(:headers => { "Accept" => "application/json", "Content-Type" => "application/json" })
|
35
|
+
).and_return(@request_builder)
|
36
|
+
do_request
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should perform the request" do
|
40
|
+
Net::HTTP.should_receive(:start).and_return(@response)
|
41
|
+
do_request
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return the parsed response" do
|
45
|
+
do_request.should == { "test" => "test" }
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should raise NotImplementedError if the given auth_type is wrong" do
|
49
|
+
lambda do
|
50
|
+
do_request :auth_type => :invalid
|
51
|
+
end.should raise_error(NotImplementedError)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "lib", "transport", "request", "builder"))
|
3
|
+
|
4
|
+
describe Transport::Request::Builder do
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
@builder = Transport::Request::Builder.new :get,
|
8
|
+
"http://localhost:5984/test",
|
9
|
+
:headers => { "Test-Header" => "test" },
|
10
|
+
:parameters => { "test_parameter" => "test" }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "uri" do
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
@uri = @builder.uri
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should build an uri with the correct host, port and path" do
|
20
|
+
@uri.host.should == "localhost"
|
21
|
+
@uri.port.should == 5984
|
22
|
+
@uri.path.should == "/test"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "request" do
|
28
|
+
|
29
|
+
before :each do
|
30
|
+
@request = @builder.request
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have the correct class" do
|
34
|
+
@request.should be_instance_of(Net::HTTP::Get)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have the correct headers" do
|
38
|
+
@request["Test-Header"].should == "test"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should point to the correct path" do
|
42
|
+
@request.path.should == "/test?test_parameter=test"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should have the correct body" do
|
46
|
+
@request.body.should be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "spec_helper"))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "..", "lib", "transport", "request", "parameter", "serializer"))
|
3
|
+
|
4
|
+
describe Transport::Request::Parameter::Serializer do
|
5
|
+
|
6
|
+
it "should return nil on an empty parameter hash" do
|
7
|
+
serializer = Transport::Request::Parameter::Serializer.new
|
8
|
+
serializer.query.should be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return a correctly encoded query string" do
|
12
|
+
serializer = Transport::Request::Parameter::Serializer.new :foo => "bar", :test => [ "value1", "value2" ]
|
13
|
+
serializer.query.should == "foo=bar&test=value1&test=value2"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|