rosemary 0.2.2

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.
@@ -0,0 +1,84 @@
1
+ module Rosemary
2
+ # OpenStreetMap Way.
3
+ #
4
+ # To create a new Rosemary::Way object:
5
+ # way = Rosemary::Way.new()
6
+ #
7
+ # To get a way from the API:
8
+ # way = Rosemary::Way.find_way(17)
9
+ #
10
+ class Way < Element
11
+ # Array of node IDs in this way.
12
+ attr_reader :nodes
13
+
14
+ # Create new Way object.
15
+ #
16
+ # id:: ID of this way. If +nil+ a new unique negative ID will be allocated.
17
+ # user:: Username
18
+ # timestamp:: Timestamp of last change
19
+ # nodes:: Array of Node objects and/or node IDs
20
+ def initialize(attrs = {})
21
+ attrs.stringify_keys!
22
+ @nodes = []
23
+ super(attrs)
24
+ end
25
+
26
+ def type
27
+ 'Way'
28
+ end
29
+
30
+ # Add one or more tags or nodes to this way.
31
+ #
32
+ # The argument can be one of the following:
33
+ #
34
+ # * If the argument is a Hash or an OSM::Tags object, those tags are added.
35
+ # * If the argument is an OSM::Node object, its ID is added to the list of node IDs.
36
+ # * If the argument is an Integer or String containing an Integer, this ID is added to the list of node IDs.
37
+ # * If the argument is an Array the function is called recursively, i.e. all items in the Array are added.
38
+ #
39
+ # Returns the way to allow chaining.
40
+ #
41
+ # call-seq: way << something -> Way
42
+ #
43
+ def <<(stuff)
44
+ case stuff
45
+ when Array # call this method recursively
46
+ stuff.each do |item|
47
+ self << item
48
+ end
49
+ when Rosemary::Node
50
+ nodes << stuff.id
51
+ when String
52
+ nodes << stuff.to_i
53
+ when Integer
54
+ nodes << stuff
55
+ else
56
+ tags.merge!(stuff)
57
+ end
58
+ self # return self to allow chaining
59
+ end
60
+
61
+
62
+ # The list of attributes for this Way
63
+ def attribute_list # :nodoc:
64
+ [:id, :version, :uid, :user, :timestamp, :changeset]
65
+ end
66
+
67
+ def self.from_xml(xml_string)
68
+ Parser.call(xml_string, :xml)
69
+ end
70
+
71
+ def to_xml(options = {})
72
+ xml = options[:builder] ||= Builder::XmlMarkup.new
73
+ xml.instruct! unless options[:skip_instruct]
74
+ xml.osm do
75
+ xml.way(attributes) do
76
+ nodes.each do |node_id|
77
+ xml.nd(:ref => node_id)
78
+ end unless nodes.empty?
79
+ tags.to_xml(:builder => xml, :skip_instruct => true)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
data/lib/rosemary.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "rosemary/version"
2
+
3
+ require 'hash'
4
+ require 'active_model'
5
+ require 'changeset_callbacks'
6
+ require 'rosemary/tags'
7
+ require 'rosemary/element'
8
+ require 'rosemary/node'
9
+ require 'rosemary/way'
10
+ require 'rosemary/changeset'
11
+ require 'rosemary/relation'
12
+ require 'rosemary/member'
13
+ require 'rosemary/user'
14
+ require 'rosemary/errors'
15
+ require 'rosemary/basic_auth_client'
16
+ require 'rosemary/oauth_client'
17
+ require 'rosemary/parser'
18
+ require 'rosemary/api'
19
+ require 'oauth'
20
+
21
+ # The Rosemary class handles all calls to the OpenStreetMap API.
22
+ #
23
+ # Usage:
24
+ # require 'osm'
25
+ # auth_client = Rosemary::BasicAuthClient.new(:user_name => 'user', :password => 'a_password')
26
+ # osm = Rosemary.new(auth_client)
27
+ # @node = osm.find_node(1234)
28
+ # @node.tags << {:wheelchair => 'no'}
29
+ # osm.save(@node)
30
+ #
31
+ module Rosemary
32
+
33
+ end
data/rosemary.gemspec ADDED
@@ -0,0 +1,58 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rosemary/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rosemary"
7
+ s.version = Rosemary::VERSION
8
+
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
10
+ s.authors = ["Christoph B\u{fc}nte, Enno Brehm"]
11
+ s.date = "2012-03-22"
12
+ s.description = "OpenStreetMap API client for ruby"
13
+ s.email = ["info@christophbuente.de"]
14
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md", "lib/changeset_callbacks.rb", "lib/hash.rb", "lib/rosemary/api.rb", "lib/rosemary/basic_auth_client.rb", "lib/rosemary/changeset.rb", "lib/rosemary/element.rb", "lib/rosemary/errors.rb", "lib/rosemary/member.rb", "lib/rosemary/node.rb", "lib/rosemary/oauth_client.rb", "lib/rosemary/parser.rb", "lib/rosemary/relation.rb", "lib/rosemary/tags.rb", "lib/rosemary/user.rb", "lib/rosemary/way.rb", "lib/rosemary.rb"]
15
+ s.homepage = "https://github.com/sozialhelden/openstreetmap"
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "OpenStreetMap", "--main", "README.md"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = "rosemary"
19
+ s.rubygems_version = "1.8.10"
20
+
21
+ s.summary = "OpenStreetMap API client for ruby"
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+
28
+ if s.respond_to? :specification_version then
29
+ s.specification_version = 3
30
+
31
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
32
+ s.add_runtime_dependency(%q<httparty>, [">= 0"])
33
+ s.add_runtime_dependency(%q<libxml-ruby>, [">= 0"])
34
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
35
+ s.add_runtime_dependency(%q<oauth>, [">= 0"])
36
+ s.add_runtime_dependency(%q<activemodel>, [">= 0"])
37
+ s.add_development_dependency(%q<rspec>, [">= 0"])
38
+ s.add_development_dependency(%q<webmock>, [">= 0"])
39
+ s.add_development_dependency(%q<rake>, [">= 0"])
40
+ else
41
+ s.add_dependency(%q<httparty>, [">= 0"])
42
+ s.add_dependency(%q<libxml-ruby>, [">= 0"])
43
+ s.add_dependency(%q<builder>, [">= 0"])
44
+ s.add_dependency(%q<oauth>, [">= 0"])
45
+ s.add_dependency(%q<activemodel>, [">= 0"])
46
+ s.add_dependency(%q<rspec>, [">= 0"])
47
+ s.add_dependency(%q<webmock>, [">= 0"])
48
+ end
49
+ else
50
+ s.add_dependency(%q<httparty>, [">= 0"])
51
+ s.add_dependency(%q<libxml-ruby>, [">= 0"])
52
+ s.add_dependency(%q<builder>, [">= 0"])
53
+ s.add_dependency(%q<oauth>, [">= 0"])
54
+ s.add_dependency(%q<activemodel>, [">= 0"])
55
+ s.add_dependency(%q<rspec>, [">= 0"])
56
+ s.add_dependency(%q<webmock>, [">= 0"])
57
+ end
58
+ end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rosemary::Changeset do
4
+
5
+ before do
6
+ WebMock.disable_net_connect!
7
+ end
8
+
9
+ let :osm do
10
+ Rosemary::Api.new
11
+ end
12
+
13
+ def valid_fake_user
14
+ user=<<-EOF
15
+ <osm version="0.6" generator="OpenStreetMap server">
16
+ <user display_name="Max Muster" account_created="2006-07-21T19:28:26Z" id="1234">
17
+ <home lat="49.4733718952806" lon="8.89285988577866" zoom="3"/>
18
+ <description>The description of your profile</description>
19
+ <languages>
20
+ <lang>de-DE</lang>
21
+ <lang>de</lang>
22
+ <lang>en-US</lang>
23
+ <lang>en</lang>
24
+ </languages>
25
+ </user>
26
+ </osm>
27
+ EOF
28
+ end
29
+
30
+ def missing_changeset
31
+ changeset=<<-EOF
32
+ <osm version="0.6" generator="OpenStreetMap server"/>
33
+ EOF
34
+ end
35
+
36
+ def single_changeset
37
+ changeset=<<-EOF
38
+ <osm version="0.6" generator="OpenStreetMap server">
39
+ <changeset id="10" user="fred" uid="123" created_at="2008-11-08T19:07:39+01:00" open="true" min_lon="7.0191821" min_lat="49.2785426" max_lon="7.0197485" max_lat="49.2793101">
40
+ <tag k="created_by" v="JOSM 1.61"/>
41
+ <tag k="comment" v="Just adding some streetnames"/>
42
+ </changeset>
43
+ </osm>
44
+ EOF
45
+ end
46
+
47
+ def multiple_changeset
48
+ changeset=<<-EOF
49
+ <osm version="0.6" generator="OpenStreetMap server">
50
+ <changeset id="10" user="fred" uid="123" created_at="2008-11-08T19:07:39+01:00" open="true" min_lon="7.0191821" min_lat="49.2785426" max_lon="7.0197485" max_lat="49.2793101">
51
+ <tag k="created_by" v="JOSM 1.61"/>
52
+ <tag k="comment" v="Just adding some streetnames"/>
53
+ </changeset>
54
+ <changeset id="11" user="fred" uid="123" created_at="2008-11-08T19:07:39+01:00" open="true" min_lon="7.0191821" min_lat="49.2785426" max_lon="7.0197485" max_lat="49.2793101">
55
+ <tag k="created_by" v="JOSM 1.61"/>
56
+ <tag k="comment" v="Just adding some streetnames"/>
57
+ </changeset>
58
+ </osm>
59
+ EOF
60
+ end
61
+
62
+ describe '#find:' do
63
+
64
+ let :request_url do
65
+ "http://www.openstreetmap.org/api/0.6/changeset/10"
66
+ end
67
+
68
+ let :stubbed_request do
69
+ stub_request(:get, request_url)
70
+ end
71
+
72
+ it "should build a Change from API response via find_changeset_object" do
73
+ stubbed_request.to_return(:status => 200, :body => single_changeset, :headers => {'Content-Type' => 'application/xml'})
74
+ changeset = osm.find_changeset(10)
75
+ assert_requested :get, request_url, :times => 1
76
+ changeset.class.should eql Rosemary::Changeset
77
+ end
78
+
79
+ it "should raise an NotFound error, when a changeset cannot be found" do
80
+ stubbed_request.to_return(:status => 404, :body => '', :headers => {'Content-Type' => 'text/plain'})
81
+ lambda {
82
+ node = osm.find_changeset(10)
83
+ }.should raise_error(Rosemary::NotFound)
84
+ end
85
+ end
86
+
87
+ describe '#find_for_user' do
88
+
89
+ let :osm do
90
+ Rosemary::Api.new(Rosemary::BasicAuthClient.new('a_username', 'a_password'))
91
+ end
92
+
93
+ let :request_url do
94
+ "http://www.openstreetmap.org/api/0.6/changesets?user=1234"
95
+ end
96
+
97
+ let :stubbed_request do
98
+ stub_request(:get, request_url)
99
+ end
100
+
101
+ let! :stub_user_lookup do
102
+ stub_request(:get, "http://a_username:a_password@www.openstreetmap.org/api/0.6/user/details").to_return(:status => 200, :body => valid_fake_user, :headers => {'Content-Type' => 'application/xml'} )
103
+ end
104
+
105
+ it "should not find changeset for user if user has none" do
106
+ stubbed_request.to_return(:status => 200, :body => missing_changeset, :headers => {'Content-Type' => 'application/xml'})
107
+ changesets = osm.find_changesets_for_user
108
+ changesets.should be_empty
109
+ end
110
+
111
+ it "should find a single changeset for user" do
112
+ stubbed_request.to_return(:status => 200, :body => single_changeset, :headers => {'Content-Type' => 'application/xml'})
113
+ changesets = osm.find_changesets_for_user
114
+ changesets.size.should eql 1
115
+ changesets.first.class.should eql Rosemary::Changeset
116
+ end
117
+
118
+ it "should find a multiple changesets for a user" do
119
+ stubbed_request.to_return(:status => 200, :body => multiple_changeset, :headers => {'Content-Type' => 'application/xml'})
120
+ changesets = osm.find_changesets_for_user
121
+ changesets.size.should eql 2
122
+ changesets.first.class.should eql Rosemary::Changeset
123
+ end
124
+ end
125
+
126
+ describe '#update:' do
127
+ end
128
+
129
+ describe '#close' do
130
+ end
131
+ end
132
+
@@ -0,0 +1,384 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rosemary::Node do
4
+
5
+ before do
6
+ WebMock.disable_net_connect!
7
+ end
8
+
9
+ let :osm do
10
+ Rosemary::Api.new
11
+ end
12
+
13
+ let :stub_changeset_lookup do
14
+ stub_request(:get, "http://www.openstreetmap.org/api/0.6/changesets?open=true&user=1234").to_return(:status => 200, :body => valid_fake_changeset, :headers => {'Content-Type' => 'application/xml'} )
15
+ end
16
+
17
+ let :stub_node_lookup do
18
+ stub_request(:get, "http://www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => valid_fake_node, :headers => {'Content-Type' => 'application/xml'})
19
+ end
20
+
21
+ def valid_fake_node
22
+ node=<<-EOF
23
+ <osm>
24
+ <node id="123" lat="51.2" lon="13.4" version="42" changeset="12" user="fred" uid="123" visible="true" timestamp="2005-07-30T14:27:12+01:00">
25
+ <tag k="note" v="Just a node"/>
26
+ <tag k="amenity" v="bar" />
27
+ <tag k="name" v="The rose" />
28
+ </node>
29
+ </osm>
30
+ EOF
31
+ end
32
+
33
+ def valid_fake_user
34
+ user=<<-EOF
35
+ <osm version="0.6" generator="OpenStreetMap server">
36
+ <user display_name="Max Muster" account_created="2006-07-21T19:28:26Z" id="1234">
37
+ <home lat="49.4733718952806" lon="8.89285988577866" zoom="3"/>
38
+ <description>The description of your profile</description>
39
+ <languages>
40
+ <lang>de-DE</lang>
41
+ <lang>de</lang>
42
+ <lang>en-US</lang>
43
+ <lang>en</lang>
44
+ </languages>
45
+ </user>
46
+ </osm>
47
+ EOF
48
+ end
49
+
50
+ def valid_fake_changeset
51
+ changeset=<<-EOF
52
+ <osm>
53
+ <changeset id="10" user="fred" uid="123" created_at="2008-11-08T19:07:39+01:00" open="true" min_lon="7.0191821" min_lat="49.2785426" max_lon="7.0197485" max_lat="49.2793101">
54
+ <tag k="created_by" v="JOSM 1.61"/>
55
+ <tag k="comment" v="Just adding some streetnames"/>
56
+ </changeset>
57
+ </osm>
58
+ EOF
59
+ end
60
+
61
+ describe '#find:' do
62
+
63
+ let :request_url do
64
+ "http://www.openstreetmap.org/api/0.6/node/1234"
65
+ end
66
+
67
+ let :stubbed_request do
68
+ stub_request(:get, request_url)
69
+ end
70
+
71
+ it "should build a Node from API response via get_object" do
72
+ stubbed_request.to_return(:status => 200, :body => valid_fake_node, :headers => {'Content-Type' => 'application/xml'})
73
+ node = osm.find_node 1234
74
+ assert_requested :get, request_url, :times => 1
75
+ node.class.should eql Rosemary::Node
76
+ node.tags.size.should eql 3
77
+ node.tags['name'].should eql 'The rose'
78
+ node['name'].should eql 'The rose'
79
+ node.add_tags('wheelchair' => 'yes')
80
+ node['wheelchair'].should eql 'yes'
81
+ end
82
+
83
+ it "should raise a Unavailable, when api times out" do
84
+ stubbed_request.to_timeout
85
+ lambda {
86
+ node = osm.find_node(1234)
87
+ }.should raise_error(Rosemary::Unavailable)
88
+ end
89
+
90
+ it "should raise an Gone error, when a node has been deleted" do
91
+ stubbed_request.to_return(:status => 410, :body => '', :headers => {'Content-Type' => 'text/plain'})
92
+ lambda {
93
+ node = osm.find_node(1234)
94
+ }.should raise_error(Rosemary::Gone)
95
+ end
96
+
97
+ it "should raise an NotFound error, when a node cannot be found" do
98
+ stubbed_request.to_return(:status => 404, :body => '', :headers => {'Content-Type' => 'text/plain'})
99
+ lambda {
100
+ node = osm.find_node(1234)
101
+ }.should raise_error(Rosemary::NotFound)
102
+ end
103
+ end
104
+
105
+ describe 'with BasicAuthClient' do
106
+
107
+ let :osm do
108
+ Rosemary::Api.new(Rosemary::BasicAuthClient.new('a_username', 'a_password'))
109
+ end
110
+
111
+ let :stub_user_lookup do
112
+ stub_request(:get, "http://a_username:a_password@www.openstreetmap.org/api/0.6/user/details").to_return(:status => 200, :body => valid_fake_user, :headers => {'Content-Type' => 'application/xml'} )
113
+ end
114
+
115
+ describe '#create:' do
116
+
117
+ let :node do
118
+ Rosemary::Node.new
119
+ end
120
+
121
+ let :request_url do
122
+ "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/create"
123
+ end
124
+
125
+ let :stubbed_request do
126
+ stub_request(:put, request_url)
127
+ end
128
+
129
+ before do
130
+ stub_changeset_lookup
131
+ stub_user_lookup
132
+ end
133
+
134
+ it "should create a new Node from given attributes" do
135
+ stubbed_request.to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'})
136
+ node.id.should be_nil
137
+ new_id = osm.save(node)
138
+ end
139
+
140
+ it "should raise a Unavailable, when api times out" do
141
+ stubbed_request.to_timeout
142
+ lambda {
143
+ new_id = osm.save(node)
144
+ }.should raise_error(Rosemary::Unavailable)
145
+ end
146
+
147
+ it "should not create a Node with invalid xml but raise BadRequest" do
148
+ stubbed_request.to_return(:status => 400, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'})
149
+ lambda {
150
+ new_id = osm.save(node)
151
+ }.should raise_error(Rosemary::BadRequest)
152
+ end
153
+
154
+ it "should not allow to create a node when a changeset has been closed" do
155
+ stubbed_request.to_return(:status => 409, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'})
156
+ lambda {
157
+ new_id = osm.save(node)
158
+ }.should raise_error(Rosemary::Conflict)
159
+ end
160
+
161
+ it "should not allow to create a node when no authentication client is given" do
162
+ osm = Rosemary::Api.new
163
+ lambda {
164
+ osm.save(node)
165
+ }.should raise_error(Rosemary::CredentialsMissing)
166
+ end
167
+
168
+ end
169
+
170
+ describe '#update:' do
171
+
172
+ let :node do
173
+ osm.find_node 123
174
+ end
175
+
176
+ before do
177
+ stub_changeset_lookup
178
+ stub_user_lookup
179
+ stub_node_lookup
180
+ end
181
+
182
+ it "should save a edited node" do
183
+ stub_request(:put, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => '43', :headers => {'Content-Type' => 'text/plain'})
184
+ node.tags['amenity'] = 'restaurant'
185
+ node.tags['name'] = 'Il Tramonto'
186
+ node.should_receive(:changeset=)
187
+ new_version = osm.save(node)
188
+ new_version.should eql 43
189
+ end
190
+
191
+ end
192
+
193
+ describe '#delete:' do
194
+
195
+ let :node do
196
+ osm.find_node 123
197
+ end
198
+
199
+ before do
200
+ stub_changeset_lookup
201
+ stub_user_lookup
202
+ stub_node_lookup
203
+ end
204
+
205
+ it "should not delete an node with missing id" do
206
+ node = Rosemary::Node.new
207
+ osm.destroy(node)
208
+ end
209
+
210
+ it "should delete an existing node" do
211
+ stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => '43', :headers => {'Content-Type' => 'text/plain'})
212
+ node.should_receive(:changeset=)
213
+ new_version = osm.destroy(node)
214
+ new_version.should eql 43 # new version number
215
+ end
216
+
217
+ it "should raise an error if node to be deleted is still part of a way" do
218
+ stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 400, :body => 'Version does not match current database version', :headers => {'Content-Type' => 'text/plain'})
219
+ lambda {
220
+ response = osm.destroy(node)
221
+ response.should eql "Version does not match current database version"
222
+ }.should raise_error Rosemary::BadRequest
223
+ end
224
+
225
+ it "should raise an error if node cannot be found" do
226
+ stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 404, :body => 'Node cannot be found', :headers => {'Content-Type' => 'text/plain'})
227
+ lambda {
228
+ response = osm.destroy(node)
229
+ response.should eql "Node cannot be found"
230
+ }.should raise_error Rosemary::NotFound
231
+ end
232
+
233
+ it "should raise an error if there is a conflict" do
234
+ stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 409, :body => 'Node has been deleted in this changeset', :headers => {'Content-Type' => 'text/plain'})
235
+ lambda {
236
+ response = osm.destroy(node)
237
+ response.should eql "Node has been deleted in this changeset"
238
+ }.should raise_error Rosemary::Conflict
239
+ end
240
+
241
+ it "should raise an error if the node is already delted" do
242
+ stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 410, :body => 'Node has been deleted', :headers => {'Content-Type' => 'text/plain'})
243
+ lambda {
244
+ response = osm.destroy(node)
245
+ response.should eql "Node has been deleted"
246
+ }.should raise_error Rosemary::Gone
247
+ end
248
+
249
+ it "should raise an error if the node is part of a way" do
250
+ stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 412, :body => 'Node 123 is still used by way 456', :headers => {'Content-Type' => 'text/plain'})
251
+ lambda {
252
+ response = osm.destroy(node)
253
+ response.should eql "Node 123 is still used by way 456"
254
+ }.should raise_error Rosemary::Precondition
255
+ end
256
+
257
+ end
258
+ end
259
+
260
+ describe 'with OauthClient' do
261
+
262
+ let :consumer do
263
+ OAuth::Consumer.new( 'a_key', 'a_secret',
264
+ {
265
+ :site => 'http://www.openstreetmap.org',
266
+ :request_token_path => '/oauth/request_token',
267
+ :access_token_path => '/oauth/access_token',
268
+ :authorize_path => '/oauth/authorize'
269
+ }
270
+ )
271
+ end
272
+
273
+ let :access_token do
274
+ OAuth::AccessToken.new(consumer, 'a_token', 'a_secret')
275
+ end
276
+
277
+ let :osm do
278
+ Rosemary::Api.new(Rosemary::OauthClient.new(access_token))
279
+ end
280
+
281
+ let :stub_user_lookup do
282
+ stub_request(:get, "http://www.openstreetmap.org/api/0.6/user/details").to_return(:status => 200, :body => valid_fake_user, :headers => {'Content-Type' => 'application/xml'} )
283
+ end
284
+
285
+ describe '#create:' do
286
+ let :node do
287
+ Rosemary::Node.new
288
+ end
289
+
290
+ let :request_url do
291
+ "http://www.openstreetmap.org/api/0.6/node/create"
292
+ end
293
+
294
+ let :stubbed_request do
295
+ stub_request(:put, request_url)
296
+ end
297
+
298
+ before do
299
+ stub_changeset_lookup
300
+ stub_user_lookup
301
+ end
302
+
303
+ it "should create a new Node from given attributes" do
304
+ stubbed_request.to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'})
305
+ node.id.should be_nil
306
+ new_id = osm.save(node)
307
+ end
308
+
309
+ it "should raise a Unavailable, when api times out" do
310
+ stubbed_request.to_timeout
311
+ lambda {
312
+ new_id = osm.save(node)
313
+ }.should raise_error(Rosemary::Unavailable)
314
+ end
315
+
316
+
317
+ it "should not create a Node with invalid xml but raise BadRequest" do
318
+ stubbed_request.to_return(:status => 400, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'})
319
+ lambda {
320
+ new_id = osm.save(node)
321
+ }.should raise_error(Rosemary::BadRequest)
322
+ end
323
+
324
+ it "should not allow to create a node when a changeset has been closed" do
325
+ stubbed_request.to_return(:status => 409, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'})
326
+ lambda {
327
+ new_id = osm.save(node)
328
+ }.should raise_error(Rosemary::Conflict)
329
+ end
330
+
331
+ it "should not allow to create a node when no authentication client is given" do
332
+ osm = Rosemary::Api.new
333
+ lambda {
334
+ osm.save(node)
335
+ }.should raise_error(Rosemary::CredentialsMissing)
336
+ end
337
+
338
+ end
339
+
340
+ describe '#update:' do
341
+
342
+ let :node do
343
+ osm.find_node 123
344
+ end
345
+
346
+ before do
347
+ stub_changeset_lookup
348
+ stub_user_lookup
349
+ stub_node_lookup
350
+ end
351
+
352
+ it "should save a edited node" do
353
+ stub_request(:put, "http://www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => '43', :headers => {'Content-Type' => 'text/plain'})
354
+ node.tags['amenity'] = 'restaurant'
355
+ node.tags['name'] = 'Il Tramonto'
356
+ node.should_receive(:changeset=)
357
+ new_version = osm.save(node)
358
+ new_version.should eql 43
359
+ end
360
+ end
361
+
362
+ describe '#delete:' do
363
+
364
+ let :node do
365
+ osm.find_node 123
366
+ end
367
+
368
+ before do
369
+ stub_changeset_lookup
370
+ stub_user_lookup
371
+ stub_node_lookup
372
+ end
373
+
374
+ it "should delete an existing node" do
375
+ stub_request(:delete, "http://www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => '43', :headers => {'Content-Type' => 'text/plain'})
376
+ node.should_receive(:changeset=)
377
+ lambda {
378
+ # Delete is not implemented using oauth
379
+ new_version = osm.destroy(node)
380
+ }.should raise_error(Rosemary::NotImplemented)
381
+ end
382
+ end
383
+ end
384
+ end