rosemary 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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