rosemary 0.2.8 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rosemary/api.rb CHANGED
@@ -12,7 +12,6 @@ module Rosemary
12
12
  # api.save(@node)
13
13
  class Api
14
14
  include HTTParty
15
- include ChangesetCallbacks
16
15
  API_VERSION = "0.6".freeze
17
16
 
18
17
  # the default base URI for the API
@@ -31,10 +30,6 @@ module Rosemary
31
30
  @client = client
32
31
  end
33
32
 
34
- def changeset!
35
- @changeset ||= create_changeset
36
- end
37
-
38
33
  # Get a Node with specified ID from API.
39
34
  #
40
35
  # call-seq: find_node(id) -> Rosemary::Node
@@ -67,6 +62,21 @@ module Rosemary
67
62
  find_element('changeset', id)
68
63
  end
69
64
 
65
+ # Get a Changeset with specified ID from API
66
+ # if that changeset is missing, id is nil, or the changeset is closed
67
+ # create a new one
68
+ #
69
+ # call-seq: find_or_create_open_changeset(id, comment) -> Rosemary::Changeset
70
+ #
71
+ def find_or_create_open_changeset(id, comment = nil)
72
+ find_open_changeset(id) || create_changeset(comment)
73
+ end
74
+
75
+ def find_open_changeset(id)
76
+ cs = find_changeset(id)
77
+ (cs && cs.open?) ? cs : nil
78
+ end
79
+
70
80
  # Get the user which represented by the Rosemary::Client
71
81
  #
72
82
  # call-seq: find_user -> Rosemary::User
@@ -79,8 +89,7 @@ module Rosemary
79
89
  end
80
90
 
81
91
  # Delete an element
82
- def destroy(element)
83
- raise ChangesetMissing unless changeset.open?
92
+ def destroy(element, changeset)
84
93
  element.changeset = changeset.id
85
94
  response = delete("/#{element.type.downcase}/#{element.id}", :body => element.to_xml) unless element.id.nil?
86
95
  response.to_i # New version number
@@ -88,34 +97,32 @@ module Rosemary
88
97
 
89
98
  # Saves an element to the API.
90
99
  # If it has no id yet, the element will be created, otherwise updated.
91
- def save(element)
100
+ def save(element, changeset)
92
101
  response = if element.id.nil?
93
- create(element)
102
+ create(element, changeset)
94
103
  else
95
- update(element)
104
+ update(element, changeset)
96
105
  end
97
106
  end
98
107
 
99
- def create(element)
100
- raise ChangesetMissing unless changeset.open?
108
+ def create(element, changeset)
101
109
  element.changeset = changeset.id
102
110
  put("/#{element.type.downcase}/create", :body => element.to_xml)
103
111
  end
104
112
 
105
- def update(element)
106
- raise ChangesetMissing unless changeset.open?
113
+ def update(element, changeset)
107
114
  element.changeset = changeset.id
108
115
  response = put("/#{element.type.downcase}/#{element.id}", :body => element.to_xml)
109
116
  response.to_i # New Version number
110
117
  end
111
118
 
112
- def create_changeset
113
- changeset = Changeset.new
119
+ def create_changeset(comment = nil)
120
+ changeset = Changeset.new(:tags => { :comment => comment })
114
121
  changeset_id = put("/changeset/create", :body => changeset.to_xml).to_i
115
122
  find_changeset(changeset_id) unless changeset_id == 0
116
123
  end
117
124
 
118
- def close_changeset
125
+ def close_changeset(changeset)
119
126
  put("/changeset/#{changeset.id}/close")
120
127
  end
121
128
 
@@ -131,9 +138,13 @@ module Rosemary
131
138
  #
132
139
  def find_element(type, id)
133
140
  raise ArgumentError.new("type needs to be one of 'node', 'way', and 'relation'") unless type =~ /^(node|way|relation|changeset)$/
134
- raise TypeError.new('id needs to be a positive integer') unless(id.kind_of?(Fixnum) && id > 0)
135
- response = get("/#{type}/#{id}")
136
- response.is_a?(Array ) ? response.first : response
141
+ return nil if id.nil?
142
+ begin
143
+ response = get("/#{type}/#{id}")
144
+ response.is_a?(Array ) ? response.first : response
145
+ rescue NotFound
146
+ nil
147
+ end
137
148
  end
138
149
 
139
150
  private
@@ -197,14 +208,6 @@ module Rosemary
197
208
  end
198
209
  end
199
210
 
200
- def find_open_changeset
201
- find_changesets_for_user(:open => true).first
202
- end
203
-
204
- def find_or_create_open_changeset(options = {})
205
- @changeset = (find_open_changeset || create_changeset)
206
- end
207
-
208
211
  def check_response_codes(response)
209
212
  body = response.body
210
213
  case response.code.to_i
@@ -220,7 +223,7 @@ module Rosemary
220
223
  # when 414 then raise UriTooLarge.new(body)
221
224
  when 500 then raise ServerError
222
225
  when 503 then raise Unavailable.new('Service Unavailable')
223
- else raise Error("Unknown response code: #{response.code}")
226
+ else raise "Unknown response code: #{response.code}"
224
227
  end
225
228
  end
226
229
 
@@ -30,19 +30,20 @@ module Rosemary
30
30
  attr_reader :tags
31
31
 
32
32
  def initialize(attrs = {}) #:nodoc:
33
- attrs.stringify_keys!
34
- @id = attrs['id'].to_i if attrs['id']
35
- @uid = attrs['uid'].to_i
36
- @user = attrs['user']
37
- @created_at = Time.parse(attrs['created_at']) rescue nil
38
- @closed_at = Time.parse(attrs['closed_at']) rescue nil
39
- @open = attrs['open']
40
- @tags = Tags.new
41
- @tags[:created_by] = 'osm for ruby'
42
- @min_lat = attrs['min_lat'].to_f
43
- @min_lon = attrs['min_lon'].to_f
44
- @max_lat = attrs['max_lat'].to_f
45
- @max_lon = attrs['max_lon'].to_f
33
+ attrs = attrs.dup.stringify_keys!
34
+ @id = attrs['id'].to_i if attrs['id']
35
+ @uid = attrs['uid'].to_i
36
+ @user = attrs['user']
37
+ @created_at = Time.parse(attrs['created_at']) rescue nil
38
+ @closed_at = Time.parse(attrs['closed_at']) rescue nil
39
+ @open = attrs['open']
40
+ tags = attrs['tags'] || {}
41
+ @tags = Tags.new.merge(tags.dup.stringify_keys!)
42
+ @tags['created_by'] = 'osm for ruby'
43
+ @min_lat = attrs['min_lat'].to_f
44
+ @min_lon = attrs['min_lon'].to_f
45
+ @max_lat = attrs['max_lat'].to_f
46
+ @max_lon = attrs['max_lon'].to_f
46
47
 
47
48
  end
48
49
 
@@ -12,9 +12,6 @@ module Rosemary
12
12
  # This error occurs when Rosemary is instantiated without a client
13
13
  class CredentialsMissing < StandardError; end
14
14
 
15
- # This error occurs when Rosemary has no changeset.
16
- class ChangesetMissing < StandardError; end
17
-
18
15
  # An object was not found in the database.
19
16
  class NotFound < Error; end
20
17
 
@@ -1,3 +1,3 @@
1
1
  module Rosemary
2
- VERSION = "0.2.8"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/rosemary.rb CHANGED
@@ -2,7 +2,6 @@ require "rosemary/version"
2
2
 
3
3
  require 'hash'
4
4
  require 'active_model'
5
- require 'changeset_callbacks'
6
5
  require 'rosemary/tags'
7
6
  require 'rosemary/element'
8
7
  require 'rosemary/node'
data/rosemary.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.date = "2012-03-22"
12
12
  s.description = "OpenStreetMap API client for ruby"
13
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"]
14
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md"]
15
15
  s.homepage = "https://github.com/sozialhelden/rosemary"
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "OpenStreetMap", "--main", "README.md"]
17
17
  s.require_paths = ["lib"]
@@ -1,13 +1,18 @@
1
1
  require 'spec_helper'
2
+ include Rosemary
2
3
 
3
- describe Rosemary::Changeset do
4
+ describe Changeset do
4
5
 
5
6
  before do
6
7
  WebMock.disable_net_connect!
7
8
  end
8
9
 
9
10
  let :osm do
10
- Rosemary::Api.new
11
+ Api.new
12
+ end
13
+
14
+ let :auth_osm do
15
+ Api.new(BasicAuthClient.new('a_username', 'a_password'))
11
16
  end
12
17
 
13
18
  def valid_fake_user
@@ -61,11 +66,11 @@ describe Rosemary::Changeset do
61
66
 
62
67
  describe '#find:' do
63
68
 
64
- let :request_url do
69
+ def request_url
65
70
  "http://www.openstreetmap.org/api/0.6/changeset/10"
66
71
  end
67
72
 
68
- let :stubbed_request do
73
+ def stubbed_request
69
74
  stub_request(:get, request_url)
70
75
  end
71
76
 
@@ -73,28 +78,63 @@ describe Rosemary::Changeset do
73
78
  stubbed_request.to_return(:status => 200, :body => single_changeset, :headers => {'Content-Type' => 'application/xml'})
74
79
  changeset = osm.find_changeset(10)
75
80
  assert_requested :get, request_url, :times => 1
76
- changeset.class.should eql Rosemary::Changeset
81
+ changeset.class.should eql Changeset
77
82
  end
78
83
 
79
84
  it "should raise an NotFound error, when a changeset cannot be found" do
80
85
  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)
86
+ node = osm.find_changeset(10)
87
+ node.should be_nil
84
88
  end
85
89
  end
86
90
 
87
- describe '#find_for_user' do
91
+ describe '#create' do
92
+
93
+ def request_url
94
+ "http://a_username:a_password@www.openstreetmap.org/api/0.6/changeset/create"
95
+ end
88
96
 
89
- let :osm do
90
- Rosemary::Api.new(Rosemary::BasicAuthClient.new('a_username', 'a_password'))
97
+ def stub_create_request
98
+ stub_request(:put, request_url)
91
99
  end
92
100
 
93
- let :request_url do
101
+ it "should post a new changeset with given comment" do
102
+ body = Changeset.new(:tags => { :comment => 'New changeset' }).to_xml
103
+
104
+ stub_create_request.with(:body => body).to_return(:status => 200, :body => "3", :headers => {'Content-Type' => 'plain/text'})
105
+ auth_osm.should_receive(:find_changeset).with(3).and_return(cs = mock())
106
+ auth_osm.create_changeset('New changeset').should == cs
107
+ end
108
+ end
109
+
110
+ describe "#find_or_create_open_changeset" do
111
+ it "returns an exisiting changeset if that exists and is open" do
112
+ auth_osm.should_receive(:find_changeset).with(3).and_return(cs = mock(:open? => true))
113
+ auth_osm.should_not_receive(:create_changeset)
114
+ auth_osm.find_or_create_open_changeset(3, "some foo comment").should == cs
115
+ end
116
+
117
+ it "returns an new changeset if the requested one exists and is closed" do
118
+ auth_osm.should_receive(:find_changeset).with(3).and_return(mock(:open? => false))
119
+ auth_osm.should_receive(:create_changeset).with("some foo comment").and_return(cs = mock())
120
+ auth_osm.find_or_create_open_changeset(3, "some foo comment").should == cs
121
+ end
122
+
123
+ it "returns an new changeset if the requested one doesn't exist" do
124
+ auth_osm.should_receive(:find_changeset).with(3).and_return(nil)
125
+ auth_osm.should_receive(:create_changeset).with("some foo comment").and_return(cs = mock())
126
+ auth_osm.find_or_create_open_changeset(3, "some foo comment").should == cs
127
+ end
128
+
129
+ end
130
+
131
+ describe '#find_for_user' do
132
+
133
+ def request_url
94
134
  "http://www.openstreetmap.org/api/0.6/changesets?user=1234"
95
135
  end
96
136
 
97
- let :stubbed_request do
137
+ def stubbed_request
98
138
  stub_request(:get, request_url)
99
139
  end
100
140
 
@@ -104,22 +144,22 @@ describe Rosemary::Changeset do
104
144
 
105
145
  it "should not find changeset for user if user has none" do
106
146
  stubbed_request.to_return(:status => 200, :body => missing_changeset, :headers => {'Content-Type' => 'application/xml'})
107
- changesets = osm.find_changesets_for_user
147
+ changesets = auth_osm.find_changesets_for_user
108
148
  changesets.should be_empty
109
149
  end
110
150
 
111
151
  it "should find a single changeset for user" do
112
152
  stubbed_request.to_return(:status => 200, :body => single_changeset, :headers => {'Content-Type' => 'application/xml'})
113
- changesets = osm.find_changesets_for_user
153
+ changesets = auth_osm.find_changesets_for_user
114
154
  changesets.size.should eql 1
115
- changesets.first.class.should eql Rosemary::Changeset
155
+ changesets.first.class.should eql Changeset
116
156
  end
117
157
 
118
158
  it "should find a multiple changesets for a user" do
119
159
  stubbed_request.to_return(:status => 200, :body => multiple_changeset, :headers => {'Content-Type' => 'application/xml'})
120
- changesets = osm.find_changesets_for_user
160
+ changesets = auth_osm.find_changesets_for_user
121
161
  changesets.size.should eql 2
122
- changesets.first.class.should eql Rosemary::Changeset
162
+ changesets.first.class.should eql Changeset
123
163
  end
124
164
  end
125
165
 
@@ -1,20 +1,20 @@
1
1
  require 'spec_helper'
2
-
3
- describe Rosemary::Node do
2
+ include Rosemary
3
+ describe Node do
4
4
 
5
5
  before do
6
6
  WebMock.disable_net_connect!
7
7
  end
8
8
 
9
- let :osm do
10
- Rosemary::Api.new
11
- end
9
+ let(:changeset) { Changeset.new(:id => 1) }
12
10
 
13
- let :stub_changeset_lookup do
11
+ let(:osm) { Api.new }
12
+
13
+ def stub_changeset_lookup
14
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
15
  end
16
16
 
17
- let :stub_node_lookup do
17
+ def stub_node_lookup
18
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
19
  end
20
20
 
@@ -60,11 +60,11 @@ describe Rosemary::Node do
60
60
 
61
61
  describe '#find:' do
62
62
 
63
- let :request_url do
63
+ def request_url
64
64
  "http://www.openstreetmap.org/api/0.6/node/1234"
65
65
  end
66
66
 
67
- let :stubbed_request do
67
+ def stubbed_request
68
68
  stub_request(:get, request_url)
69
69
  end
70
70
 
@@ -72,7 +72,7 @@ describe Rosemary::Node do
72
72
  stubbed_request.to_return(:status => 200, :body => valid_fake_node, :headers => {'Content-Type' => 'application/xml'})
73
73
  node = osm.find_node 1234
74
74
  assert_requested :get, request_url, :times => 1
75
- node.class.should eql Rosemary::Node
75
+ node.class.should eql Node
76
76
  node.tags.size.should eql 3
77
77
  node.tags['name'].should eql 'The rose'
78
78
  node['name'].should eql 'The rose'
@@ -84,84 +84,95 @@ describe Rosemary::Node do
84
84
  stubbed_request.to_timeout
85
85
  lambda {
86
86
  node = osm.find_node(1234)
87
- }.should raise_error(Rosemary::Unavailable)
87
+ }.should raise_error(Unavailable)
88
88
  end
89
89
 
90
90
  it "should raise an Gone error, when a node has been deleted" do
91
91
  stubbed_request.to_return(:status => 410, :body => '', :headers => {'Content-Type' => 'text/plain'})
92
92
  lambda {
93
93
  node = osm.find_node(1234)
94
- }.should raise_error(Rosemary::Gone)
94
+ }.should raise_error(Gone)
95
95
  end
96
96
 
97
97
  it "should raise an NotFound error, when a node cannot be found" do
98
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)
99
+ node = osm.find_node(1234)
100
+ node.should be_nil
102
101
  end
103
102
  end
104
103
 
105
104
  describe 'with BasicAuthClient' do
106
105
 
107
106
  let :osm do
108
- Rosemary::Api.new(Rosemary::BasicAuthClient.new('a_username', 'a_password'))
107
+ Api.new(BasicAuthClient.new('a_username', 'a_password'))
109
108
  end
110
109
 
111
- let :stub_user_lookup do
110
+ def stub_user_lookup
112
111
  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
112
  end
114
113
 
115
114
  describe '#create:' do
116
115
 
117
- let (:node) { Rosemary::Node.new }
118
- let (:request_url) { "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/create" }
119
- let (:stubbed_request) { stub_request(:put, request_url) }
116
+ let (:node) { Node.new }
117
+
118
+ let (:expected_body) {
119
+ expected_node = node.dup
120
+ expected_node.changeset = changeset.id
121
+ expected_node.to_xml
122
+ }
123
+
124
+ def request_url
125
+ "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/create"
126
+ end
127
+
128
+ def stubbed_request
129
+ stub_request(:put, request_url)
130
+ end
120
131
 
121
132
  before do
122
- stub_changeset_lookup
123
133
  stub_user_lookup
124
134
  end
125
135
 
126
136
  it "should create a new Node from given attributes" do
127
- stubbed_request.to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'})
128
- node.id.should be_nil
129
- new_id = osm.save(node)
137
+ stubbed_request.with(:body => expected_body).
138
+ to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'})
139
+
140
+ new_id = osm.create(node, changeset)
130
141
  end
131
142
 
132
143
  it "should raise a Unavailable, when api times out" do
133
144
  stubbed_request.to_timeout
134
145
  lambda {
135
- new_id = osm.save(node)
136
- }.should raise_error(Rosemary::Unavailable)
146
+ new_id = osm.create(node, changeset)
147
+ }.should raise_error(Unavailable)
137
148
  end
138
149
 
139
150
  it "should not create a Node with invalid xml but raise BadRequest" do
140
151
  stubbed_request.to_return(:status => 400, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'})
141
152
  lambda {
142
- new_id = osm.save(node)
143
- }.should raise_error(Rosemary::BadRequest)
153
+ new_id = osm.save(node, changeset)
154
+ }.should raise_error(BadRequest)
144
155
  end
145
156
 
146
157
  it "should not allow to create a node when a changeset has been closed" do
147
158
  stubbed_request.to_return(:status => 409, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'})
148
159
  lambda {
149
- new_id = osm.save(node)
150
- }.should raise_error(Rosemary::Conflict)
160
+ new_id = osm.save(node, changeset)
161
+ }.should raise_error(Conflict)
151
162
  end
152
163
 
153
164
  it "should not allow to create a node when no authentication client is given" do
154
- osm = Rosemary::Api.new
165
+ osm = Api.new
155
166
  lambda {
156
- osm.save(node)
157
- }.should raise_error(Rosemary::CredentialsMissing)
167
+ osm.save(node, changeset)
168
+ }.should raise_error(CredentialsMissing)
158
169
  end
159
170
 
160
171
  it "should set a changeset" do
161
172
  stubbed_request.to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'})
162
173
  node.changeset = nil
163
- osm.save(node)
164
- node.changeset.should == osm.changeset.id
174
+ osm.save(node, changeset)
175
+ node.changeset.should == changeset.id
165
176
  end
166
177
  end
167
178
 
@@ -172,7 +183,6 @@ describe Rosemary::Node do
172
183
  end
173
184
 
174
185
  before do
175
- stub_changeset_lookup
176
186
  stub_user_lookup
177
187
  stub_node_lookup
178
188
  end
@@ -182,15 +192,15 @@ describe Rosemary::Node do
182
192
  node.tags['amenity'] = 'restaurant'
183
193
  node.tags['name'] = 'Il Tramonto'
184
194
  node.should_receive(:changeset=)
185
- new_version = osm.save(node)
195
+ new_version = osm.save(node, changeset)
186
196
  new_version.should eql 43
187
197
  end
188
198
 
189
199
  it "should set a changeset" do
190
200
  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'})
191
201
  node.changeset = nil
192
- osm.save(node)
193
- node.changeset.should == osm.changeset.id
202
+ osm.save(node, changeset)
203
+ node.changeset.should == changeset.id
194
204
  end
195
205
 
196
206
 
@@ -209,62 +219,62 @@ describe Rosemary::Node do
209
219
  end
210
220
 
211
221
  it "should not delete an node with missing id" do
212
- node = Rosemary::Node.new
213
- osm.destroy(node)
222
+ node = Node.new
223
+ osm.destroy(node, changeset)
214
224
  end
215
225
 
216
226
  it "should delete an existing node" do
217
227
  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'})
218
228
  node.should_receive(:changeset=)
219
- new_version = osm.destroy(node)
229
+ new_version = osm.destroy(node, changeset)
220
230
  new_version.should eql 43 # new version number
221
231
  end
222
232
 
223
233
  it "should raise an error if node to be deleted is still part of a way" do
224
234
  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'})
225
235
  lambda {
226
- response = osm.destroy(node)
236
+ response = osm.destroy(node, changeset)
227
237
  response.should eql "Version does not match current database version"
228
- }.should raise_error Rosemary::BadRequest
238
+ }.should raise_error BadRequest
229
239
  end
230
240
 
231
241
  it "should raise an error if node cannot be found" do
232
242
  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'})
233
243
  lambda {
234
- response = osm.destroy(node)
244
+ response = osm.destroy(node, changeset)
235
245
  response.should eql "Node cannot be found"
236
- }.should raise_error Rosemary::NotFound
246
+ }.should raise_error NotFound
237
247
  end
238
248
 
239
249
  it "should raise an error if there is a conflict" do
240
250
  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'})
241
251
  lambda {
242
- response = osm.destroy(node)
252
+ response = osm.destroy(node, changeset)
243
253
  response.should eql "Node has been deleted in this changeset"
244
- }.should raise_error Rosemary::Conflict
254
+ }.should raise_error Conflict
245
255
  end
246
256
 
247
257
  it "should raise an error if the node is already delted" do
248
258
  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'})
249
259
  lambda {
250
- response = osm.destroy(node)
260
+ response = osm.destroy(node, changeset)
251
261
  response.should eql "Node has been deleted"
252
- }.should raise_error Rosemary::Gone
262
+ }.should raise_error Gone
253
263
  end
254
264
 
255
265
  it "should raise an error if the node is part of a way" do
256
266
  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'})
257
267
  lambda {
258
- response = osm.destroy(node)
268
+ response = osm.destroy(node, changeset)
259
269
  response.should eql "Node 123 is still used by way 456"
260
- }.should raise_error Rosemary::Precondition
270
+ }.should raise_error Precondition
261
271
  end
262
272
 
263
273
  it "should set the changeset an existing node" do
264
274
  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'})
265
275
  node.changeset = nil
266
- new_version = osm.destroy(node)
267
- node.changeset.should == osm.changeset.id
276
+ new_version = osm.destroy(node, changeset)
277
+ node.changeset.should == changeset.id
268
278
  end
269
279
  end
270
280
  end
@@ -287,23 +297,23 @@ describe Rosemary::Node do
287
297
  end
288
298
 
289
299
  let :osm do
290
- Rosemary::Api.new(Rosemary::OauthClient.new(access_token))
300
+ Api.new(OauthClient.new(access_token))
291
301
  end
292
302
 
293
- let :stub_user_lookup do
303
+ def stub_user_lookup
294
304
  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'} )
295
305
  end
296
306
 
297
307
  describe '#create:' do
298
308
  let :node do
299
- Rosemary::Node.new
309
+ Node.new
300
310
  end
301
311
 
302
- let :request_url do
312
+ def request_url
303
313
  "http://www.openstreetmap.org/api/0.6/node/create"
304
314
  end
305
315
 
306
- let :stubbed_request do
316
+ def stubbed_request
307
317
  stub_request(:put, request_url)
308
318
  end
309
319
 
@@ -315,36 +325,36 @@ describe Rosemary::Node do
315
325
  it "should create a new Node from given attributes" do
316
326
  stubbed_request.to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'})
317
327
  node.id.should be_nil
318
- new_id = osm.save(node)
328
+ new_id = osm.save(node, changeset)
319
329
  end
320
330
 
321
331
  it "should raise a Unavailable, when api times out" do
322
332
  stubbed_request.to_timeout
323
333
  lambda {
324
- new_id = osm.save(node)
325
- }.should raise_error(Rosemary::Unavailable)
334
+ new_id = osm.save(node, changeset)
335
+ }.should raise_error(Unavailable)
326
336
  end
327
337
 
328
338
 
329
339
  it "should not create a Node with invalid xml but raise BadRequest" do
330
340
  stubbed_request.to_return(:status => 400, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'})
331
341
  lambda {
332
- new_id = osm.save(node)
333
- }.should raise_error(Rosemary::BadRequest)
342
+ new_id = osm.save(node, changeset)
343
+ }.should raise_error(BadRequest)
334
344
  end
335
345
 
336
346
  it "should not allow to create a node when a changeset has been closed" do
337
347
  stubbed_request.to_return(:status => 409, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'})
338
348
  lambda {
339
- new_id = osm.save(node)
340
- }.should raise_error(Rosemary::Conflict)
349
+ new_id = osm.save(node, changeset)
350
+ }.should raise_error(Conflict)
341
351
  end
342
352
 
343
353
  it "should not allow to create a node when no authentication client is given" do
344
- osm = Rosemary::Api.new
354
+ osm = Api.new
345
355
  lambda {
346
- osm.save(node)
347
- }.should raise_error(Rosemary::CredentialsMissing)
356
+ osm.save(node, changeset)
357
+ }.should raise_error(CredentialsMissing)
348
358
  end
349
359
 
350
360
  end
@@ -366,7 +376,7 @@ describe Rosemary::Node do
366
376
  node.tags['amenity'] = 'restaurant'
367
377
  node.tags['name'] = 'Il Tramonto'
368
378
  node.should_receive(:changeset=)
369
- new_version = osm.save(node)
379
+ new_version = osm.save(node, changeset)
370
380
  new_version.should eql 43
371
381
  end
372
382
  end
@@ -388,8 +398,8 @@ describe Rosemary::Node do
388
398
  node.should_receive(:changeset=)
389
399
  lambda {
390
400
  # Delete is not implemented using oauth
391
- new_version = osm.destroy(node)
392
- }.should raise_error(Rosemary::NotImplemented)
401
+ new_version = osm.destroy(node, changeset)
402
+ }.should raise_error(NotImplemented)
393
403
  end
394
404
  end
395
405
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
-
3
- describe Rosemary::User do
2
+ include Rosemary
3
+ describe User do
4
4
 
5
5
  before do
6
6
  WebMock.disable_net_connect!
@@ -22,7 +22,7 @@ describe Rosemary::User do
22
22
  end
23
23
 
24
24
  let :osm do
25
- Rosemary::Api.new(Rosemary::OauthClient.new(access_token))
25
+ Api.new(OauthClient.new(access_token))
26
26
  end
27
27
 
28
28
  def valid_fake_user
@@ -47,14 +47,14 @@ describe Rosemary::User do
47
47
  it "should build a User from API response via find_user" do
48
48
  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'})
49
49
  user = osm.find_user
50
- user.class.should eql Rosemary::User
50
+ user.class.should eql User
51
51
  end
52
52
 
53
53
  it "should raise error from api" do
54
54
  stub_request(:get, "http://www.openstreetmap.org/api/0.6/user/details").to_return(:status => 403, :body => "OAuth token doesn't have that capability.", :headers => {'Content-Type' => 'plain/text'})
55
55
  lambda {
56
56
  osm.find_user
57
- }.should raise_error Rosemary::Forbidden
57
+ }.should raise_error Forbidden
58
58
  end
59
59
  end
60
60
  end
@@ -1,13 +1,13 @@
1
1
  require 'spec_helper'
2
-
3
- describe Rosemary::Way do
2
+ include Rosemary
3
+ describe Way do
4
4
 
5
5
  before do
6
6
  WebMock.disable_net_connect!
7
7
  end
8
8
 
9
9
  let :osm do
10
- Rosemary::Api.new
10
+ Api.new
11
11
  end
12
12
 
13
13
  def valid_fake_way
@@ -36,7 +36,7 @@ describe Rosemary::Way do
36
36
  it "should build a Way from API response via get_way" do
37
37
  stub_request(:get, "http://www.openstreetmap.org/api/0.6/way/1234").to_return(:status => 200, :body => valid_fake_way, :headers => {'Content-Type' => 'application/xml'})
38
38
  way = osm.find_way(1234)
39
- way.class.should eql Rosemary::Way
39
+ way.class.should eql Way
40
40
  way.nodes.should include(15735246)
41
41
  end
42
42
  end
@@ -1,9 +1,9 @@
1
1
  require 'spec_helper'
2
-
3
- describe 'Rosemary::Changeset' do
2
+ include Rosemary
3
+ describe Changeset do
4
4
 
5
5
  let :changeset do
6
- Rosemary::Changeset.new( :id => "123",
6
+ Changeset.new( :id => "123",
7
7
  :user => "fred",
8
8
  :uid => "123",
9
9
  :created_at => "2008-11-08T19:07:39+01:00",
@@ -11,80 +11,98 @@ describe 'Rosemary::Changeset' do
11
11
  :min_lat => "52.2",
12
12
  :max_lat => "52.3",
13
13
  :min_lon => "13.4",
14
- :max_lon => "13.5")
14
+ :max_lon => "13.5",
15
+ :tags => { :comment => 'A bloody comment' })
15
16
  end
16
17
 
17
- it "should have an id attribute set from attributes" do
18
- changeset.id.should eql(123)
19
- end
18
+ context 'attributes' do
20
19
 
21
- it "should have an id attribute within xml representation" do
22
- changeset.to_xml.should match /id=\"123\"/
23
- end
20
+ subject { changeset }
24
21
 
25
- it "should have a user attributes set from attributes" do
26
- changeset.user.should eql("fred")
27
- end
22
+ it "should have an id attribute set from attributes" do
23
+ subject.id.should eql(123)
24
+ end
28
25
 
29
- it "should have a user attribute within xml representation" do
30
- changeset.to_xml.should match /user=\"fred\"/
31
- end
26
+ it "should have a user attributes set from attributes" do
27
+ subject.user.should eql("fred")
28
+ end
32
29
 
33
- it "should have an uid attribute set from attributes" do
34
- changeset.uid.should eql(123)
35
- end
30
+ it "should have an uid attribute set from attributes" do
31
+ subject.uid.should eql(123)
32
+ end
36
33
 
37
- it "should have an uid attribute within xml representation" do
38
- changeset.to_xml.should match /uid=\"123\"/
39
- end
34
+ it "should have a changeset attributes set from attributes" do
35
+ subject.should be_open
36
+ end
40
37
 
41
- it "should have a changeset attributes set from attributes" do
42
- changeset.should be_open
43
- end
38
+ it "should have a min_lat attribute set from attributes" do
39
+ subject.min_lat.should eql(52.2)
40
+ end
44
41
 
45
- it "should have an open attribute within xml representation" do
46
- changeset.to_xml.should match /open=\"true\"/
47
- end
42
+ it "should have a min_lon attribute set from attributes" do
43
+ subject.min_lon.should eql(13.4)
44
+ end
48
45
 
49
- it "should have a min_lat attribute set from attributes" do
50
- changeset.min_lat.should eql(52.2)
51
- end
46
+ it "should have a max_lat attribute set from attributes" do
47
+ subject.max_lat.should eql(52.3)
48
+ end
52
49
 
53
- it "should have a min_lat attribute within xml representation" do
54
- changeset.to_xml.should match /min_lat=\"52.2\"/
55
- end
50
+ it "should have a max_lon attribute set from attributes" do
51
+ subject.max_lon.should eql(13.5)
52
+ end
56
53
 
57
- it "should have a min_lon attribute set from attributes" do
58
- changeset.min_lon.should eql(13.4)
59
- end
54
+ it "should have a created_at attribute set from attributes" do
55
+ subject.created_at.should eql Time.parse('2008-11-08T19:07:39+01:00')
56
+ end
60
57
 
61
- it "should have a min_lon attribute within xml representation" do
62
- changeset.to_xml.should match /min_lon=\"13.4\"/
58
+ it "should have a comment attribute set from attributes" do
59
+ subject.tags['comment'].should eql 'A bloody comment'
60
+ end
63
61
  end
64
62
 
65
- it "should have a max_lat attribute set from attributes" do
66
- changeset.max_lat.should eql(52.3)
67
- end
63
+ context 'xml representation' do
68
64
 
69
- it "should have a max_lat attribute within xml representation" do
70
- changeset.to_xml.should match /max_lat=\"52.3\"/
71
- end
65
+ subject { changeset.to_xml }
72
66
 
73
- it "should have a max_lon attribute set from attributes" do
74
- changeset.max_lon.should eql(13.5)
75
- end
67
+ it "should have an id attribute within xml representation" do
68
+ subject.should have_xml "//changeset[@id='123']"
69
+ end
76
70
 
77
- it "should have a max_lon attribute within xml representation" do
78
- changeset.to_xml.should match /max_lon=\"13.5\"/
79
- end
71
+ it "should have a user attribute within xml representation" do
72
+ subject.should have_xml "//changeset[@user='fred']"
73
+ end
80
74
 
81
- it "should have a created_at attribute set from attributes" do
82
- changeset.created_at.should eql Time.parse('2008-11-08T19:07:39+01:00')
83
- end
75
+ it "should have an uid attribute within xml representation" do
76
+ subject.should have_xml "//changeset[@uid='123']"
77
+ end
84
78
 
85
- it "should have a created_at attribute within xml representation" do
86
- changeset.to_xml.should match /created_at=\"/
87
- end
79
+ it "should have an open attribute within xml representation" do
80
+ subject.should have_xml "//changeset[@open='true']"
81
+ end
88
82
 
83
+ it "should have a min_lat attribute within xml representation" do
84
+ subject.should have_xml "//changeset[@min_lat='52.2']"
85
+ end
89
86
 
87
+ it "should have a min_lon attribute within xml representation" do
88
+ subject.should have_xml "//changeset[@min_lon='13.4']"
89
+ end
90
+
91
+ it "should have a max_lat attribute within xml representation" do
92
+ subject.should have_xml "//changeset[@max_lat='52.3']"
93
+ end
94
+
95
+ it "should have a max_lon attribute within xml representation" do
96
+ subject.should have_xml "//changeset[@max_lon='13.5']"
97
+ end
98
+
99
+ it "should have a created_at attribute within xml representation" do
100
+ subject.should have_xml "//changeset[@created_at='2008-11-08 19:07:39 +0100']"
101
+ end
102
+
103
+ it "should have a comment tag within xml representation" do
104
+ subject.should have_xml "//tag[@k='comment'][@v='A bloody comment']"
105
+ end
106
+
107
+ end
90
108
  end
@@ -1,9 +1,9 @@
1
1
  require 'spec_helper'
2
-
3
- describe 'Rosemary::Node' do
2
+ describe Rosemary
3
+ describe Node do
4
4
 
5
5
  subject do
6
- Rosemary::Node.new(:id => "123",
6
+ Node.new(:id => "123",
7
7
  :lat => "52.2",
8
8
  :lon => "13.4",
9
9
  :changeset => "12",
@@ -1,9 +1,9 @@
1
1
  require 'spec_helper'
2
-
3
- describe 'Rosemary::Relation' do
2
+ include Rosemary
3
+ describe Relation do
4
4
 
5
5
  subject do
6
- Rosemary::Relation.new(:id => "123",
6
+ Relation.new(:id => "123",
7
7
  :lat => "52.2",
8
8
  :lon => "13.4",
9
9
  :changeset => "12",
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
-
3
- describe 'Rosemary::Way' do
2
+ include Rosemary
3
+ describe Way do
4
4
 
5
5
  def valid_fake_way
6
6
  way=<<-EOF
@@ -24,7 +24,7 @@ describe 'Rosemary::Way' do
24
24
  end
25
25
 
26
26
  subject do
27
- @way ||= Rosemary::Way.from_xml(valid_fake_way)
27
+ @way ||= Way.from_xml(valid_fake_way)
28
28
  end
29
29
 
30
30
  it "should have 4 nodes" do
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,31 @@
1
1
  require 'webmock/rspec'
2
2
  require 'rosemary'
3
3
 
4
+ require 'libxml'
5
+
6
+ RSpec::Matchers.define :have_xml do |xpath, text|
7
+ match do |body|
8
+ parser = LibXML::XML::Parser.string body
9
+ doc = parser.parse
10
+ nodes = doc.find(xpath)
11
+ nodes.empty?.should be_false
12
+ if text
13
+ nodes.each do |node|
14
+ node.content.should == text
15
+ end
16
+ end
17
+ true
18
+ end
19
+
20
+ failure_message_for_should do |body|
21
+ "expected to find xml tag #{xpath} in:\n#{body}"
22
+ end
23
+
24
+ failure_message_for_should_not do |response|
25
+ "expected not to find xml tag #{xpath} in:\n#{body}"
26
+ end
27
+
28
+ description do
29
+ "have xml tag #{xpath}"
30
+ end
31
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rosemary
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-03-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
16
- requirement: &70147855734540 !ruby/object:Gem::Requirement
16
+ requirement: &70283461963940 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70147855734540
24
+ version_requirements: *70283461963940
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: libxml-ruby
27
- requirement: &70147855733880 !ruby/object:Gem::Requirement
27
+ requirement: &70283461963320 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70147855733880
35
+ version_requirements: *70283461963320
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: builder
38
- requirement: &70147855733360 !ruby/object:Gem::Requirement
38
+ requirement: &70283461962620 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70147855733360
46
+ version_requirements: *70283461962620
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: oauth
49
- requirement: &70147855732860 !ruby/object:Gem::Requirement
49
+ requirement: &70283461961580 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70147855732860
57
+ version_requirements: *70283461961580
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: activemodel
60
- requirement: &70147855732360 !ruby/object:Gem::Requirement
60
+ requirement: &70283461961100 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70147855732360
68
+ version_requirements: *70283461961100
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &70147855731880 !ruby/object:Gem::Requirement
71
+ requirement: &70283461960400 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70147855731880
79
+ version_requirements: *70283461960400
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: webmock
82
- requirement: &70147855731400 !ruby/object:Gem::Requirement
82
+ requirement: &70283461959920 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70147855731400
90
+ version_requirements: *70283461959920
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rake
93
- requirement: &70147855730900 !ruby/object:Gem::Requirement
93
+ requirement: &70283461959420 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70147855730900
101
+ version_requirements: *70283461959420
102
102
  description: OpenStreetMap API client for ruby
103
103
  email:
104
104
  - info@christophbuente.de
@@ -108,22 +108,6 @@ extra_rdoc_files:
108
108
  - CHANGELOG
109
109
  - LICENSE
110
110
  - README.md
111
- - lib/changeset_callbacks.rb
112
- - lib/hash.rb
113
- - lib/rosemary/api.rb
114
- - lib/rosemary/basic_auth_client.rb
115
- - lib/rosemary/changeset.rb
116
- - lib/rosemary/element.rb
117
- - lib/rosemary/errors.rb
118
- - lib/rosemary/member.rb
119
- - lib/rosemary/node.rb
120
- - lib/rosemary/oauth_client.rb
121
- - lib/rosemary/parser.rb
122
- - lib/rosemary/relation.rb
123
- - lib/rosemary/tags.rb
124
- - lib/rosemary/user.rb
125
- - lib/rosemary/way.rb
126
- - lib/rosemary.rb
127
111
  files:
128
112
  - .gitignore
129
113
  - .rbenv-version
@@ -136,7 +120,6 @@ files:
136
120
  - Manifest
137
121
  - README.md
138
122
  - Rakefile
139
- - lib/changeset_callbacks.rb
140
123
  - lib/hash.rb
141
124
  - lib/rosemary.rb
142
125
  - lib/rosemary/api.rb
@@ -183,7 +166,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
183
166
  version: '0'
184
167
  segments:
185
168
  - 0
186
- hash: -3755060652839665335
169
+ hash: 4264551617807260197
187
170
  required_rubygems_version: !ruby/object:Gem::Requirement
188
171
  none: false
189
172
  requirements:
@@ -1,31 +0,0 @@
1
- # According to the OSM API any changes made to the date need an open changeset which belongs to the user
2
- # executing the changes.
3
- # To keep the code simple the before_save method is included which makes sure and open
4
- module ChangesetCallbacks
5
-
6
- def self.included(into)
7
- into.instance_methods(false).select{|method_name| [:save, :create, :update, :destroy].include?(method_name.to_sym)}.each do |m|
8
- ChangesetCallbacks.before_write(into, m)
9
- end
10
-
11
- def into.method_added(m)
12
- unless @adding
13
- @adding = true
14
- if [:save, :create, :update, :destroy].include?(m.to_sym)
15
- ChangesetCallbacks.before_write(self, m)
16
- end
17
- @adding = false
18
- end
19
- end
20
- end
21
-
22
- def ChangesetCallbacks.before_write(klass, meth)
23
- klass.class_eval do
24
- alias_method "old_#{meth}", "#{meth}"
25
- define_method(meth) do |*args|
26
- find_or_create_open_changeset
27
- self.send("old_#{meth}", *args)
28
- end
29
- end
30
- end
31
- end