wrest 0.0.7-java → 0.0.8-java

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.
@@ -13,11 +13,25 @@ module Wrest::Resource #:nodoc:
13
13
  class Base
14
14
  include Wrest::Components::AttributesContainer
15
15
  include Wrest::Components::AttributesContainer::Typecaster
16
-
17
- always_has :id
16
+
17
+ always_has :id
18
18
  typecast :id => as_integer
19
19
  attr_reader :attributes
20
20
 
21
+ def ==(other)
22
+ return true if self.equal?(other)
23
+ return false unless other.class == self.class
24
+ return self.attributes == other.attributes
25
+ end
26
+
27
+ def hash
28
+ id.hash
29
+ end
30
+
31
+ def to_xml(options={})
32
+ attributes.to_xml({:root => self.class.resource_name.gsub('_', '-')}.merge(options))
33
+ end
34
+
21
35
  class << self
22
36
  def inherited(klass)
23
37
  klass.set_resource_name klass.name
@@ -29,7 +43,7 @@ module Wrest::Resource #:nodoc:
29
43
  # we often do while writing tests.
30
44
  # By default, the resource name is set to the name of the class.
31
45
  def set_resource_name(resource_name)
32
- self.class_eval "def self.resource_name; '#{resource_name}';end"
46
+ self.class_eval "def self.resource_name; '#{resource_name.underscore}';end"
33
47
  end
34
48
 
35
49
  # Allows the host url at which the resource is found to be configured
@@ -42,43 +56,44 @@ module Wrest::Resource #:nodoc:
42
56
  def set_host(host)
43
57
  self.class_eval "def self.host; '#{host}';end"
44
58
  end
45
-
59
+
46
60
  def set_default_format(format)
47
61
  self.class_eval "def self.default_format; '#{format.to_s}';end"
48
62
  end
49
-
50
- def set_redirect_handler(method_object)
51
- end
52
63
 
53
- def resource_path
54
- @resource_path ||= "/#{resource_name.underscore.pluralize}"
55
- end
56
-
57
- def resource_collection_url
58
- "#{host}#{resource_path}"
64
+ def set_redirect_handler(method_object)
59
65
  end
60
66
 
61
- def find_all
67
+ def resource_collection_name
68
+ @resource_collection_name ||= "#{resource_name.underscore.pluralize}"
62
69
  end
63
70
 
64
- def find(resource_type = [:one, :collection, :singleton], from = "")
71
+ def find_one_uri_template
72
+ @find_one_template ||= Wrest::UriTemplate.new(':host/:resource_collection_name/:id.:format')
65
73
  end
66
74
 
67
75
  def find(id)
68
- response_hash = "#{resource_collection_url}/#{id}.#{default_format}".to_uri.get.deserialise.mutate_using(
69
- Wrest::Components::Mutators.chain(
70
- :xml_mini_type_caster, :camel_to_snake_case
71
- )
72
- )
73
- resource_type = response_hash.keys.first
74
- if(resource_type.underscore.camelize == self.name)
75
- self.new(response_hash[resource_type])
76
- else
77
- response_hash
78
- end
76
+ response = find_one_uri_template.to_uri(
77
+ :host => host,
78
+ :resource_collection_name => resource_collection_name,
79
+ :id => id,
80
+ :format => default_format
81
+ ).get
82
+ self.new(response.deserialise.mutate_using(
83
+ Wrest::Components::Mutators.chain(:xml_mini_type_caster, :camel_to_snake_case)
84
+ ).shift.last)
79
85
  end
80
86
 
81
- def objectify(hash)
87
+ def create(attributes = {})
88
+ response = Wrest::UriTemplate.new(':host/:resource_collection_name.:format').to_uri(
89
+ :host => host,
90
+ :resource_collection_name => resource_collection_name,
91
+ :format => default_format
92
+ ).post(self.new(attributes).to_xml, 'Content-Type' => "application/#{default_format}")
93
+
94
+ self.new(response.deserialise.mutate_using(
95
+ Wrest::Components::Mutators.chain(:xml_mini_type_caster, :camel_to_snake_case)
96
+ ).shift.last)
82
97
  end
83
98
  end
84
99
  end
data/lib/wrest/uri.rb CHANGED
@@ -11,10 +11,44 @@ module Wrest #:nodoc:
11
11
  # Wrest::Uri provides a simple api for
12
12
  # REST calls. String#to_uri is a convenience
13
13
  # method to build a Wrest::Uri from a string url.
14
+ # Note that a Wrest::Uri is immutable.
15
+ #
16
+ # Basic HTTP Authentication is supported.
17
+ # Example:
18
+ # "http://kaiwren:fupuppies@coathangers.com/portal/1".to_uri
19
+ # "http://coathangers.com/portal/1".to_uri(:username => 'kaiwren', :password => 'fupuppies')
20
+ #
21
+ # The second form is preferred as it can handle passwords with special characters like ^ and @
22
+ #
23
+ # You can find examples that use real APIs (like delicious) under the wrest/examples directory.
14
24
  class Uri
15
- attr_reader :uri
16
- def initialize(uri_string)
25
+ attr_reader :uri, :username, :password
26
+ def initialize(uri_string, options = {})
27
+ @options = options
28
+ @uri_string = uri_string.clone
17
29
  @uri = URI.parse(uri_string)
30
+ @options = options
31
+ @username = (@options[:username] ||= @uri.user)
32
+ @password = (@options[:password] ||= @uri.password)
33
+ end
34
+
35
+ # Build a new Wrest::Uri by appending _path_ to
36
+ # the current uri. If the original Wrest::Uri
37
+ # has a username and password, that will be
38
+ # copied to the new Wrest::Uri as well.
39
+ #
40
+ # Example:
41
+ # uri = "https://localhost:3000/v1".to_uri
42
+ # uri['/oogas/1'].get
43
+ #
44
+ # To change the username and password on the new
45
+ # instance, simply pass them as an options map.
46
+ #
47
+ # Example:
48
+ # uri = "https://localhost:3000/v1".to_uri(:username => 'foo', :password => 'bar')
49
+ # uri['/oogas/1', {:username => 'meh', :password => 'baz'}].get
50
+ def [](path, options = nil)
51
+ Uri.new(@uri_string+path, options || @options)
18
52
  end
19
53
 
20
54
  def eql?(other)
@@ -23,56 +57,74 @@ module Wrest #:nodoc:
23
57
 
24
58
  def ==(other)
25
59
  return false if other.class != self.class
26
- return other.uri == self.uri
60
+ return other.uri == self.uri && self.username == other.username && self.password == other.password
27
61
  end
28
62
 
29
63
  def hash
30
- self.uri.hash + 20090423
64
+ @uri.hash + @username.hash + @password.hash + 20090423
31
65
  end
32
66
 
33
- # Make a HTTP get request to this URI.
34
- # Remember to escape the parameter strings using URI.escape
67
+ # Make a GET request to this URI. This is a convenience API
68
+ # that creates a Wrest::Http::Get, executes it and returns a Wrest::Http::Response.
69
+ #
70
+ # Remember to escape all parameter strings if necessary, using URI.escape
35
71
  def get(parameters = {}, headers = {})
36
- do_request 'get', parameters.empty? ? @uri.request_uri : "#{@uri.request_uri}?#{parameters.to_query}", headers.stringify_keys
72
+ Http::Get.new(self, parameters, headers, @options).invoke
37
73
  end
38
74
 
39
- def put(body = '', headers = {})
40
- do_request 'put', @uri.request_uri, body.to_s, headers.stringify_keys
75
+ # Make a PUT request to this URI. This is a convenience API
76
+ # that creates a Wrest::Http::Put, executes it and returns a Wrest::Http::Response.
77
+ #
78
+ # Remember to escape all parameter strings if necessary, using URI.escape
79
+ def put(body = '', headers = {}, parameters = {})
80
+ Http::Put.new(self, body.to_s, headers, parameters, @options).invoke
41
81
  end
42
82
 
43
- def post(body = '', headers = {})
44
- do_request 'post', @uri.request_uri, body.to_s, headers.stringify_keys
83
+ # Makes a POST request to this URI. This is a convenience API
84
+ # that creates a Wrest::Http::Post, executes it and returns a Wrest::Http::Response.
85
+ #
86
+ # Remember to escape all parameter strings if necessary, using URI.escape
87
+ def post(body = '', headers = {}, parameters = {})
88
+ Http::Post.new(self, body.to_s, headers, parameters, @options).invoke
45
89
  end
46
90
 
91
+ # Makes a DELETE request to this URI. This is a convenience API
92
+ # that creates a Wrest::Http::Delete, executes it and returns a Wrest::Http::Response.
93
+ #
94
+ # Remember to escape all parameter strings if necessary, using URI.escape
47
95
  def delete(parameters = {}, headers = {})
48
- do_request 'delete', parameters.empty? ? @uri.request_uri : "#{@uri.request_uri}?#{parameters.to_query}", headers.stringify_keys
96
+ Http::Delete.new(self, parameters, headers, @options).invoke
49
97
  end
50
98
 
99
+ # Makes an OPTIONS request to this URI. This is a convenience API
100
+ # that creates a Wrest::Http::Options, executes it and returns the Wrest::Http::Response.
51
101
  def options
52
- do_request 'options', @uri.request_uri
102
+ Http::Options.new(self, @options).invoke
53
103
  end
54
-
55
- def do_request(method, url, *args)
56
- response = nil
57
-
58
- Wrest.logger.info "--> (#{method}) #{@uri.scheme}://#{@uri.host}:#{@uri.port}#{url}"
59
- time = Benchmark.realtime { response = Wrest::Response.new(http.send(method, url, *args)) }
60
- Wrest.logger.info "--> %d %s (%d %.2fs)" % [response.code, response.message, response.body ? response.body.length : 0, time]
61
104
 
62
- response
63
- end
64
-
65
105
  def https?
66
106
  @uri.is_a?(URI::HTTPS)
67
107
  end
68
-
69
- def http
70
- http = Net::HTTP.new(@uri.host, @uri.port)
71
- if https?
72
- http.use_ssl = true
73
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
74
- end
75
- http
108
+
109
+ # Provides the full path of a request.
110
+ # For example, for
111
+ # http://localhost:3000/demons/1/chi?sort=true
112
+ # this would return
113
+ # /demons/1/chi?sort=true
114
+ def full_path
115
+ uri.request_uri
116
+ end
117
+
118
+ def protocol
119
+ uri.scheme
120
+ end
121
+
122
+ def host
123
+ uri.host
124
+ end
125
+
126
+ def port
127
+ uri.port
76
128
  end
77
129
  end
78
130
  end
@@ -19,9 +19,26 @@ module Wrest
19
19
  # the corressponding values.
20
20
  #
21
21
  # Example:
22
- # template = UriTemplate.new("http://localhost:3000/:resource/:id.:format")
22
+ # template = UriTemplate.new("http://coathangers.com/:resource/:id.:format")
23
23
  # template.to_uri(:resource => 'shen_coins', :id => 5, :format => :json)
24
24
  # => #<Wrest::Uri:0x1225514 @uri=#<URI::HTTP:0x9127d8 URL:http://localhost:3000/shen_coins/5.json>>
25
+ #
26
+ # This feature can also be used to handle HTTP authentication where the username
27
+ # and password needs changing at runtime. However, this approach _will_ fail if
28
+ # the password contains characters like ^ and @.
29
+ #
30
+ # Note that beacuse because both HTTP Auth and UriTemplate
31
+ # use ':' as a delimiter, the pattern does look slightly weird, but it still works.
32
+ #
33
+ # Example:
34
+ # template = UriTemplate.new("http://:username::password@coathangers.com/:resource/:id.:format")
35
+ # template.to_uri(
36
+ # :user => 'kaiwren',
37
+ # :password => 'fupuppies',
38
+ # :resource => 'portal',
39
+ # :id => '1'
40
+ # )
41
+ # => #<Wrest::Uri:0x18e0bec @uri=#<URI::HTTP:0x18e09a8 URL:http://kaiwren:fupuppies@coathangers.com/portal/1>>
25
42
  def to_uri(options = {})
26
43
  options.inject(uri_pattern.clone) do |uri_string, tuple|
27
44
  key, value = tuple
data/lib/wrest/version.rb CHANGED
@@ -12,7 +12,7 @@ module Wrest
12
12
  unless defined? MAJOR
13
13
  MAJOR = 0
14
14
  MINOR = 0
15
- TINY = 7
15
+ TINY = 8
16
16
 
17
17
  STRING = [MAJOR, MINOR, TINY].join('.')
18
18
 
@@ -179,6 +179,17 @@ module Wrest::Components
179
179
  @li_piao.id = 6
180
180
  @li_piao.id.should == 6
181
181
  end
182
+
183
+ it "should provide getter and query methods to instance which has corresponding attribute" do
184
+ zotoh_zhaan = HumanBeing.new(:species => "Delvian")
185
+ zotoh_zhaan.species.should == "Delvian"
186
+ zotoh_zhaan.species?.should be_true
187
+ zotoh_zhaan.species = "Human"
188
+ lambda{@li_piao.species}.should raise_error(NoMethodError)
189
+ lambda{@li_piao.species?}.should raise_error(NoMethodError)
190
+ @li_piao.should_not respond_to(:species=)
191
+ @li_piao.methods.grep(/:species=/).should be_empty
192
+ end
182
193
  end
183
194
  end
184
195
  end
@@ -13,4 +13,13 @@ describe String, 'conversions' do
13
13
  it "should know how to convert a string to a Wrest::Uri" do
14
14
  'http://localhost:3000'.to_uri.should == Wrest::Uri.new('http://localhost:3000')
15
15
  end
16
+
17
+ it "should accept username and password as options" do
18
+ uri = 'http://localhost:3000'.to_uri(
19
+ :username => 'ooga',
20
+ :password => 'booga'
21
+ )
22
+ uri.username.should == 'ooga'
23
+ uri.password.should == 'booga'
24
+ end
16
25
  end
@@ -0,0 +1,22 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ require File.dirname(__FILE__) + '/../../spec_helper'
11
+
12
+ describe Wrest::Http::Request do
13
+ it "should convert all symbols in header keys to strings" do
14
+ Wrest::Http::Request.new(
15
+ 'http://localhost/foo'.to_uri, Net::HTTP::Get, {},
16
+ nil, 'Content-Type' => 'application/xml', :per_page => '10'
17
+ ).headers.should == {
18
+ 'Content-Type' => 'application/xml',
19
+ 'per_page' => '10'
20
+ }
21
+ end
22
+ end
@@ -1,18 +1,18 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
2
 
3
3
  module Wrest
4
- describe Response do
4
+ describe Http::Response do
5
5
  it "should know how to delegate to a translator" do
6
6
  http_response = mock('response')
7
7
  Components::Translators::Xml.should_receive(:deserialise).with(http_response)
8
- Response.new(http_response).deserialise_using(Components::Translators::Xml)
8
+ Http::Response.new(http_response).deserialise_using(Components::Translators::Xml)
9
9
  end
10
10
 
11
11
  it "should know how to load a translator based on content type" do
12
12
  http_response = mock('response')
13
13
  http_response.should_receive(:content_type).and_return('application/xml')
14
14
 
15
- response = Response.new(http_response)
15
+ response = Http::Response.new(http_response)
16
16
  response.should_receive(:deserialise_using).with(Components::Translators::Xml)
17
17
 
18
18
  response.deserialise
@@ -5,11 +5,12 @@ class Glassware < Wrest::Resource::Base
5
5
  end
6
6
 
7
7
  class BottledUniverse < Glassware
8
- set_host "http://localhost:3001"
8
+ set_host "http://localhost:3001"
9
+ set_default_format :xml
9
10
  end
10
11
 
11
12
  module Wrest
12
- describe Resource::Base do
13
+ describe Wrest::Resource::Base do
13
14
  it "should not affect other classes when setting up its macros" do
14
15
  Class.should_not respond_to(:host=)
15
16
  Object.should_not respond_to(:host=)
@@ -23,21 +24,80 @@ module Wrest
23
24
  before(:each) do
24
25
  @BottledUniverse = Class.new(Resource::Base)
25
26
  @BottledUniverse.class_eval do
26
- set_resource_name 'BottledUniverse'
27
+ set_resource_name 'BottledUniverse'
28
+ end
29
+ end
30
+
31
+ describe 'equality' do
32
+ it "should be equal if it is the same instance" do
33
+ universe = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
34
+ (universe == universe).should be_true
35
+ end
36
+
37
+ it "should be equal if it has the same state" do
38
+ (
39
+ @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1) == @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
40
+ ).should be_true
41
+ end
42
+
43
+ it "should not be equal to nil" do
44
+ (@BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1) == nil).should be_false
45
+ end
46
+
47
+ it "should not be equal if it is not the same class" do
48
+ (
49
+ @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1) == Glassware.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
50
+ ).should be_false
51
+ end
52
+
53
+ it "should not be equal if it is has a different state" do
54
+ (
55
+ @BottledUniverse.new(:universe_id=>3, :name=>"Wooz", :id=>1) == @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
56
+ ).should be_false
57
+ end
58
+
59
+ it "should be symmetric" do
60
+ universe_one = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
61
+ universe_two = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
62
+ (universe_one == universe_one).should be_true
63
+ (universe_two == universe_two).should be_true
64
+ end
65
+
66
+ it "should be transitive" do
67
+ universe_one = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
68
+ universe_two = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
69
+ universe_three = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
70
+ (universe_one == universe_two).should be_true
71
+ (universe_two == universe_three).should be_true
72
+ (universe_one == universe_three).should be_true
73
+ end
74
+
75
+ it "should ensure that the hashcode is a fixnum" do
76
+ @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1).hash.should be_kind_of(Fixnum)
77
+ end
78
+
79
+ it "should ensure that instances with the same ids have the same hashcode" do
80
+ universe_one = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
81
+ universe_two = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
82
+ universe_one.hash.should == universe_two.hash
83
+ end
84
+
85
+ it "should ensure that instances with different ids have the different hashcodes" do
86
+ universe_one = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
87
+ universe_two = @BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>2)
88
+ universe_one.hash.should_not == universe_two.hash
27
89
  end
28
90
  end
29
91
 
30
92
  it "should know its name as a resource by default" do
31
- BottledUniverse.resource_name.should == 'BottledUniverse'
93
+ BottledUniverse.resource_name.should == 'bottled_universe'
32
94
  end
33
95
 
34
96
  it "should allow its name as a resource to be configured for anonymous classes" do
35
- @BottledUniverse.resource_name.should == 'BottledUniverse'
97
+ @BottledUniverse.resource_name.should == 'bottled_universe'
36
98
  end
37
99
 
38
100
  it "should know how to create an instance using deserialised attributes" do
39
- # Json => {"lead_bottle"=>{"name"=>"Wooz", "id"=>1, "universe_id"=>nil}}
40
- # Xml => {"lead-bottle"=>[{"name"=>["Wooz"], "universe-id"=>[{"type"=>"integer", "nil"=>"true"}], "id"=>[{"type"=>"integer", "content"=>"1"}]}]}
41
101
  universe = @BottledUniverse.new "name"=>"Wooz", "id"=>'1', "universe_id"=>nil, 'owner_id'=>nil
42
102
  universe.name.should == "Wooz"
43
103
  universe.owner_id.should be_nil
@@ -69,8 +129,48 @@ module Wrest
69
129
  @BottledUniverse.host.should == "http://localhost:3000"
70
130
  end
71
131
 
72
- it "should know its resource path" do
73
- Glassware.resource_path.should == '/glasswares'
132
+ it "should know its resource collection name" do
133
+ Glassware.resource_collection_name.should == 'glasswares'
134
+ end
135
+
136
+ it "should know its uri template for find one" do
137
+ Glassware.find_one_uri_template.to_uri(
138
+ :host => 'http://localhost:3000',
139
+ :resource_collection_name => 'glasswares',
140
+ :id => 1,
141
+ :format => 'json'
142
+ ).should == 'http://localhost:3000/glasswares/1.json'.to_uri
143
+ end
144
+
145
+ it "should know how to serialise itself to xml" do
146
+ BottledUniverse.new(:name => 'Foo').to_xml.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bottled-universe>\n <name>Foo</name>\n</bottled-universe>\n"
147
+ end
148
+
149
+ describe 'finders' do
150
+ # Json =>
151
+ # body => {"lead_bottle": {"name": "Wooz", "id": 1, "universe_id": null}}
152
+ # hash => {"lead_bottle"=>{"name"=>"Wooz", "id"=>1, "universe_id"=>nil}}
153
+ # Xml =>
154
+ # body =>
155
+ # <?xml version="1.0" encoding="UTF-8"?>
156
+ # <lead-bottle>
157
+ # <id type="integer">1</id>
158
+ # <name>Wooz</name>
159
+ # <universe-id type="integer" nil="true"></universe-id>
160
+ # </lead-bottle>
161
+ # hash =>
162
+ # {"lead-bottle"=>{"name"=>{"__content__"=>"Wooz"}, "universe-id"=>{"type"=>"integer", "nil"=>"true"}, "id"=>{"__content__"=>"1", "type"=>"integer"}}}
163
+ # typecast =>
164
+ # {"lead_bottle"=>{"name"=>"Wooz", "id"=>1, "universe_id"=>nil}}
165
+ it "should know how to find a resource by id" do
166
+ uri = 'http://localhost:3001/bottled_universe/1.xml'.to_uri
167
+ Wrest::Uri.should_receive(:new).with('http://localhost:3001/bottled_universes/1.xml', {}).and_return(uri)
168
+ response = mock(Wrest::Http::Response)
169
+ uri.should_receive(:get).with(no_args).and_return(response)
170
+ response.should_receive(:deserialise).and_return({"bottled-universe"=>{"name"=>{"__content__"=>"Wooz"}, "universe-id"=>{"type"=>"integer", "nil"=>"true"}, "id"=>{"__content__"=>"1", "type"=>"integer"}}})
171
+
172
+ BottledUniverse.find(1).should == BottledUniverse.new(:universe_id=>nil, :name=>"Wooz", :id=>1)
173
+ end
74
174
  end
75
175
  end
76
176
 
@@ -80,8 +180,23 @@ module Wrest
80
180
  BottledUniverse.host.should == "http://localhost:3001"
81
181
  end
82
182
 
83
- it "should know its resource path when it is a subclass of a subclass" do
84
- BottledUniverse.resource_path.should == '/bottled_universes'
183
+ it "should know its resource collection name when it is a subclass of a subclass" do
184
+ BottledUniverse.resource_collection_name.should == 'bottled_universes'
185
+ end
186
+
187
+
188
+ it "should know how to create a new resource" do
189
+ uri = mock(Uri)
190
+ mock_http_response = mock(Net::HTTPResponse)
191
+ mock_http_response.stub!(:content_type).and_return('application/xml')
192
+ mock_http_response.stub!(:body).and_return("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bottled-universe>\n <name>Woot</name>\n <id>1</id>\n </bottled-universe>\n")
193
+
194
+ Uri.should_receive(:new).with("http://localhost:3001/bottled_universes.xml", {}).and_return(uri)
195
+ uri.should_receive(:post).with(
196
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bottled-universe>\n <name>Woot</name>\n</bottled-universe>\n",
197
+ 'Content-Type' => 'application/xml'
198
+ ).and_return(Wrest::Http::Response.new(mock_http_response))
199
+ ware = BottledUniverse.create(:name => 'Woot')
85
200
  end
86
201
  end
87
202