persevere 0.18.0 → 0.21.0
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.
- data/README.txt +7 -3
- data/lib/persevere.rb +20 -2
- data/spec/persevere_spec.rb +143 -69
- data/spec/spec_helper.rb +7 -44
- metadata +25 -25
data/README.txt
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
A DataMapper adapter for Persevere (http://www.persvr.org/)
|
4
4
|
|
5
|
-
This requires the persevere gem (http://github.com/irjudson/persevere) which provides a ruby interface to Persevere.
|
6
|
-
|
7
5
|
== Usage
|
8
6
|
|
9
7
|
DM Persevere Adapter is very simple and very similar to the REST
|
@@ -21,6 +19,9 @@ DataMapper.setup(:default, {
|
|
21
19
|
:host => 'localhost',
|
22
20
|
:port => '8080'
|
23
21
|
})
|
22
|
+
|
23
|
+
# Or,
|
24
|
+
# DataMapper.setup(:default, "persevere://localhost:8080")
|
24
25
|
|
25
26
|
class MyUser
|
26
27
|
include DataMapper::Resource
|
@@ -57,6 +58,8 @@ production:
|
|
57
58
|
|
58
59
|
== Code
|
59
60
|
|
61
|
+
MyUser.auto_migrate!
|
62
|
+
|
60
63
|
# Create
|
61
64
|
user = MyUser.new(:username => "dmtest", :uuid => UUID.random_create().to_s,
|
62
65
|
:name => "DataMapper Test", :homedirectory => "/home/dmtest",
|
@@ -81,5 +84,6 @@ puts "Result: #{result}"
|
|
81
84
|
|
82
85
|
== To Do:
|
83
86
|
|
84
|
-
- Make a do-adapter for persevere.
|
85
87
|
- Cleanup Documentation
|
88
|
+
- Add more negative / failure tests
|
89
|
+
|
data/lib/persevere.rb
CHANGED
@@ -13,6 +13,23 @@ require 'uri'
|
|
13
13
|
require 'rubygems'
|
14
14
|
require 'json'
|
15
15
|
|
16
|
+
# Ugly Monkey patching because Persever uses non-standard content-range headers.
|
17
|
+
module Net
|
18
|
+
module HTTPHeader
|
19
|
+
alias old_content_range content_range
|
20
|
+
# Returns a Range object which represents Content-Range: header field.
|
21
|
+
# This indicates, for a partial entity body, where this fragment
|
22
|
+
# fits inside the full entity body, as range of byte offsets.
|
23
|
+
def content_range
|
24
|
+
return nil unless @header['content-range']
|
25
|
+
m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or
|
26
|
+
return nil
|
27
|
+
m[1].to_i .. m[2].to_i + 1
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
16
33
|
class PersevereResult
|
17
34
|
attr_reader :location, :code, :message, :body
|
18
35
|
|
@@ -49,7 +66,7 @@ class Persevere
|
|
49
66
|
|
50
67
|
# Pass in a resource hash
|
51
68
|
def create(path, resource, headers = {})
|
52
|
-
json_blob = resource.to_json
|
69
|
+
json_blob = resource.reject{|key,value| value.nil? }.to_json
|
53
70
|
response = nil
|
54
71
|
while response.nil?
|
55
72
|
begin
|
@@ -69,7 +86,7 @@ class Persevere
|
|
69
86
|
response = @persevere.send_request('GET', path, nil, HEADERS.merge(headers))
|
70
87
|
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
|
71
88
|
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
|
72
|
-
puts "Persevere
|
89
|
+
puts "Persevere Retrieve Failed: #{e}, Trying again."
|
73
90
|
end
|
74
91
|
end
|
75
92
|
return PersevereResult.make(response)
|
@@ -92,6 +109,7 @@ class Persevere
|
|
92
109
|
|
93
110
|
def delete(path, headers = {})
|
94
111
|
response = nil
|
112
|
+
# puts "DELETING #{path}"
|
95
113
|
while response.nil?
|
96
114
|
begin
|
97
115
|
response = @persevere.send_request('DELETE', path, nil, HEADERS.merge(headers))
|
data/spec/persevere_spec.rb
CHANGED
@@ -11,9 +11,9 @@ describe Persevere do
|
|
11
11
|
@blobObj = {
|
12
12
|
'id' => 'Yogo',
|
13
13
|
'properties' => {
|
14
|
-
'cid' => {'type' => 'string' },
|
15
|
-
'parent' => { 'type' => 'string'},
|
16
|
-
'data' => { 'type' => 'string'}
|
14
|
+
'cid' => {'type' => 'string', 'optional' => true },
|
15
|
+
'parent' => { 'type' => 'string', 'optional' => true},
|
16
|
+
'data' => { 'type' => 'string', 'optional' => true}
|
17
17
|
}
|
18
18
|
}
|
19
19
|
|
@@ -29,90 +29,164 @@ describe Persevere do
|
|
29
29
|
@mockObj = {
|
30
30
|
'id' => 'Yogo',
|
31
31
|
'properties' => {
|
32
|
-
'cid' => {'type' => 'string' },
|
33
|
-
'parent' => { 'type' => 'string'},
|
34
|
-
'data' => { 'type' => 'string'}
|
32
|
+
'cid' => {'type' => 'string', 'optional' => true },
|
33
|
+
'parent' => { 'type' => 'string', 'optional' => true},
|
34
|
+
'data' => { 'type' => 'string', 'optional' => true}
|
35
35
|
},
|
36
36
|
'prototype' => {}
|
37
37
|
}
|
38
|
+
|
39
|
+
@object = {
|
40
|
+
'cid' => '123',
|
41
|
+
'parent' => 'none',
|
42
|
+
'data' => 'A Chunk Of Data'
|
43
|
+
}
|
44
|
+
|
38
45
|
end
|
39
46
|
|
40
|
-
|
47
|
+
|
41
48
|
# Test POST to create a new class
|
42
|
-
|
49
|
+
|
43
50
|
describe '#post' do
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
51
|
+
it 'should create a new object in persevere' do
|
52
|
+
result = @p.create('/Class/', @blobObj)
|
53
|
+
result.code.should == "201"
|
54
|
+
JSON.parse(result.body).should == @mockObj
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should not allow posting with a bad object' do
|
58
|
+
result = @p.create('/Class/', @corruptObj)
|
59
|
+
result.code.should == "500"
|
60
|
+
result.body.should == "\"Can not modify queries\""
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should not allow posting to an existing object/id/path' do
|
64
|
+
result = @p.create('/Class/', @blobObj)
|
65
|
+
result.code.should == "201"
|
66
|
+
JSON.parse(result.body).should == @blobObj
|
67
|
+
# This shouldn't be a 201, it should say something mean.
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Test GET to retrieve the list of classes from Persvr
|
73
|
+
#
|
74
|
+
describe '#get' do
|
75
|
+
it 'should retrieve the previously created object from persevere' do
|
76
|
+
result = @p.retrieve('/Class/Yogo')
|
77
|
+
result.code.should == "200"
|
78
|
+
JSON.parse(result.body).should == @blobObj
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should 404 on a non-existent object' do
|
82
|
+
result = @p.retrieve('/Class/GetNotThere')
|
83
|
+
result.code.should == "404"
|
84
|
+
result.message.should == "Not Found"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Test PUT to modify an existing class
|
90
|
+
#
|
91
|
+
describe '#put' do
|
92
|
+
it 'should modify the previously created object in persevere' do
|
93
|
+
@blobObj['properties']['tstAttribute'] = { 'type' => 'string' }
|
94
|
+
result = @p.update('/Class/Yogo', @blobObj)
|
95
|
+
result.code.should == "200"
|
96
|
+
JSON.parse(result.body).should == @blobObj
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should fail to modify a non-existent item' do
|
100
|
+
result = @p.update('/Class/NonExistent', @blobObj)
|
101
|
+
result.code.should == "500"
|
102
|
+
result.body.should == "\"id does not match location\""
|
103
|
+
@p.delete('/Class/NonExistent') # A bug(?) in Persevere makes a broken NonExistent class.
|
104
|
+
# This should be a 404 and not throw a persevere server exception
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Test DELETE to remove the previously created and modified class
|
110
|
+
#
|
111
|
+
describe '#delete' do
|
112
|
+
it 'should remove the previously created and modified object from persevere' do
|
113
|
+
result = @p.delete('/Class/Yogo')
|
114
|
+
result.code.should == "204"
|
115
|
+
@p.retrieve('/Class/Yogo').code.should == "404"
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should fail to delete a non-existent item' do
|
119
|
+
result = @p.delete('/Class/NotThere')
|
120
|
+
result.code.should == "404"
|
121
|
+
result.message.should == "Not Found"
|
122
|
+
result.body.should == "\"Class/NotThere not found\""
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "POSTing objects" do
|
127
|
+
before(:all) do
|
128
|
+
@p.create('/Class/', @blobObj)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should not allow nil fields to be posted" do
|
132
|
+
obj_with_nil = @object.merge({'cid' => nil})
|
133
|
+
result = @p.create('/Yogo', obj_with_nil)
|
134
|
+
result.code.should == "201"
|
135
|
+
JSON.parse(result.body).reject{|key,value| key == 'id' }.should ==
|
136
|
+
obj_with_nil.reject{|key,value| value.nil?}
|
137
|
+
end
|
138
|
+
|
139
|
+
after(:all) do
|
140
|
+
@p.delete('/Class/Yogo')
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "GETting limits and offsets" do
|
145
|
+
before(:all) do
|
146
|
+
@p.create('/Class/', @blobObj)
|
147
|
+
(0..99).each do |i|
|
148
|
+
@p.create('/Yogo/', @object.merge({'cid' => "#{i}"}))
|
149
|
+
end
|
61
150
|
end
|
62
|
-
end
|
63
151
|
|
64
|
-
|
65
|
-
|
66
|
-
#
|
67
|
-
describe '#get' do
|
68
|
-
it 'should retrieve the previously created object from persevere' do
|
69
|
-
result = @p.retrieve('/Class/Yogo')
|
152
|
+
it "should only retrieve all objects" do
|
153
|
+
result = @p.retrieve('/Yogo/')
|
70
154
|
result.code.should == "200"
|
71
|
-
JSON.parse(result.body).should ==
|
155
|
+
JSON.parse(result.body).length.should == 100
|
72
156
|
end
|
73
157
|
|
74
|
-
it
|
75
|
-
result = @p.retrieve('/
|
76
|
-
result.code.should == "404"
|
77
|
-
result.message.should == "Not Found"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
#
|
82
|
-
# Test PUT to modify an existing class
|
83
|
-
#
|
84
|
-
describe '#put' do
|
85
|
-
it 'should modify the previously created object in persevere' do
|
86
|
-
@blobObj['properties']['tstAttribute'] = { 'type' => 'string' }
|
87
|
-
result = @p.update('/Class/Yogo', @blobObj)
|
158
|
+
it "should retrieve the first objects" do
|
159
|
+
result = @p.retrieve('/Yogo/1')
|
88
160
|
result.code.should == "200"
|
89
|
-
JSON.parse(result.body).should ==
|
161
|
+
JSON.parse(result.body)['id'].should == '1'
|
90
162
|
end
|
91
163
|
|
92
|
-
it
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
@p.delete('/Class/NonExistent') # A bug(?) in Persevere makes a broken NonExistent class.
|
97
|
-
# This should be a 404 and not throw a persevere server exception
|
164
|
+
it "should retrieve a 10 of the objects" do
|
165
|
+
result = @p.retrieve('/Yogo/', {'Range' => "items=1-10"})
|
166
|
+
result.code.should == '206'
|
167
|
+
JSON.parse(result.body).length.should == 10
|
98
168
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
169
|
+
|
170
|
+
it "should return the first 2 objects" do
|
171
|
+
result = @p.retrieve('/Yogo/', {'Range' => "items=0-1"})
|
172
|
+
result.code.should == '206'
|
173
|
+
json = JSON.parse(result.body)
|
174
|
+
json.length.should == 2
|
175
|
+
json[0]['id'].should == '1'
|
176
|
+
json[1]['id'].should == '2'
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should return 21 and up objects" do
|
180
|
+
result = @p.retrieve('/Yogo/', {'Range' => 'items=20-'})
|
181
|
+
result.code.should == '206'
|
182
|
+
json = JSON.parse(result.body)
|
183
|
+
json.length.should == 80
|
184
|
+
json[0]['id'].should == '21'
|
185
|
+
json[-1]['id'].should == '100'
|
109
186
|
end
|
110
187
|
|
111
|
-
|
112
|
-
|
113
|
-
result.code.should == "404"
|
114
|
-
result.message.should == "Not Found"
|
115
|
-
result.body.should == "\"Class/NotThere not found\""
|
188
|
+
after(:all) do
|
189
|
+
@p.delete('/Class/Yogo')
|
116
190
|
end
|
117
191
|
end
|
118
192
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,52 +1,15 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
require 'rubygems'
|
3
|
-
|
4
3
|
require 'addressable/uri'
|
5
4
|
require 'spec'
|
6
|
-
|
7
|
-
require 'ruby-debug'
|
8
|
-
|
5
|
+
|
9
6
|
require 'dm-core'
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
ENV['ADAPTERS'] ||= 'all'
|
19
|
-
|
20
|
-
ADAPTERS = []
|
21
|
-
|
22
|
-
PRIMARY = {
|
23
|
-
'persevere' => {:adapter => 'persevere', :host => 'localhost', :port => '8080'}
|
24
|
-
}
|
25
|
-
|
26
|
-
adapters = ENV['ADAPTERS'].split(' ').map { |adapter_name| adapter_name.strip.downcase }.uniq
|
27
|
-
adapters = PRIMARY.keys if adapters.include?('all')
|
28
|
-
|
29
|
-
PRIMARY.only(*adapters).each do |name, default|
|
30
|
-
connection_string = ENV["#{name.upcase}_SPEC_URI"] || default
|
31
|
-
begin
|
32
|
-
adapter = DataMapper.setup(name.to_sym, connection_string)
|
33
|
-
|
34
|
-
# test the connection if possible
|
35
|
-
if adapter.respond_to?(:query)
|
36
|
-
name == 'oracle' ? adapter.select('SELECT 1 FROM dual') : adapter.select('SELECT 1')
|
37
|
-
end
|
38
|
-
|
39
|
-
ADAPTERS << name
|
40
|
-
PRIMARY[name] = connection_string # ensure *_SPEC_URI is saved
|
41
|
-
rescue Exception => exception
|
42
|
-
puts "Could not connect to the database using #{connection_string.inspect} because: #{exception.inspect}"
|
8
|
+
def path_to(gem_name, version=nil)
|
9
|
+
version = version ? Gem::Requirement.create(version) : Gem::Requirement.default
|
10
|
+
specs = Gem.source_index.find_name(gem_name, version)
|
11
|
+
paths = specs.map do |spec|
|
12
|
+
spec_path = spec.loaded_from
|
13
|
+
expanded_path = File.join(File.dirname(spec_path), '..', 'gems', "#{spec.name}-#{spec.version}")
|
43
14
|
end
|
44
|
-
end
|
45
|
-
|
46
|
-
logger = DataMapper::Logger.new(DataMapper.root / 'log' / 'dm.log', :debug)
|
47
|
-
logger.auto_flush = true
|
48
|
-
|
49
|
-
Spec::Runner.configure do |config|
|
50
|
-
config.extend(DataMapper::Spec::AdapterHelpers)
|
51
|
-
# config.include(DataMapper::Spec::PendingHelpers)
|
52
15
|
end
|
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: persevere
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- Ivan R. Judson
|
8
|
-
- The Yogo Data Management Development Team
|
7
|
+
- Ivan R. Judson
|
8
|
+
- The Yogo Data Management Development Team
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2010-01-
|
13
|
+
date: 2010-01-19 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
17
17
|
description: A ruby wrapper for persevere
|
18
18
|
email:
|
19
|
-
- irjudson [a] gmail [d] com
|
19
|
+
- irjudson [a] gmail [d] com
|
20
20
|
executables: []
|
21
21
|
|
22
22
|
extensions: []
|
23
23
|
|
24
24
|
extra_rdoc_files:
|
25
|
-
- LICENSE.txt
|
26
|
-
- README.txt
|
25
|
+
- LICENSE.txt
|
26
|
+
- README.txt
|
27
27
|
files:
|
28
|
-
- LICENSE.txt
|
29
|
-
- Rakefile
|
30
|
-
- lib/persevere.rb
|
31
|
-
- persevere/History.txt
|
32
|
-
- persevere/README.txt
|
33
|
-
- README.txt
|
28
|
+
- LICENSE.txt
|
29
|
+
- Rakefile
|
30
|
+
- lib/persevere.rb
|
31
|
+
- persevere/History.txt
|
32
|
+
- persevere/README.txt
|
33
|
+
- README.txt
|
34
34
|
has_rdoc: true
|
35
35
|
homepage: http://github.com/yogo/persevere
|
36
36
|
licenses: []
|
37
37
|
|
38
38
|
post_install_message:
|
39
39
|
rdoc_options:
|
40
|
-
- --main
|
41
|
-
- persevere/README.txt
|
40
|
+
- --main
|
41
|
+
- persevere/README.txt
|
42
42
|
require_paths:
|
43
|
-
- lib
|
43
|
+
- lib
|
44
44
|
required_ruby_version: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
49
|
version:
|
50
50
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
55
|
version:
|
56
56
|
requirements: []
|
57
57
|
|
@@ -61,6 +61,6 @@ signing_key:
|
|
61
61
|
specification_version: 3
|
62
62
|
summary: A ruby wrapper for persevere
|
63
63
|
test_files:
|
64
|
-
- spec/persevere_spec.rb
|
65
|
-
- spec/spec.opts
|
66
|
-
- spec/spec_helper.rb
|
64
|
+
- spec/persevere_spec.rb
|
65
|
+
- spec/spec.opts
|
66
|
+
- spec/spec_helper.rb
|