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 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 Create Failed: #{e}, Trying again."
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))
@@ -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
- it 'should create a new object in persevere' do
45
- result = @p.create('/Class/', @blobObj)
46
- result.code.should == "201"
47
- JSON.parse(result.body).should == @mockObj
48
- end
49
-
50
- it 'should not allow posting with a bad object' do
51
- result = @p.create('/Class/', @corruptObj)
52
- result.code.should == "500"
53
- result.body.should == "\"Can not modify queries\""
54
- end
55
-
56
- it 'should not allow posting to an existing object/id/path' do
57
- result = @p.create('/Class/', @blobObj)
58
- result.code.should == "201"
59
- JSON.parse(result.body).should == @blobObj
60
- # This shouldn't be a 201, it should say something mean.
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
- # Test GET to retrieve the list of classes from Persvr
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 == @blobObj
155
+ JSON.parse(result.body).length.should == 100
72
156
  end
73
157
 
74
- it 'should 404 on a non-existent object' do
75
- result = @p.retrieve('/Class/GetNotThere')
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 == @blobObj
161
+ JSON.parse(result.body)['id'].should == '1'
90
162
  end
91
163
 
92
- it 'should fail to modify a non-existent item' do
93
- result = @p.update('/Class/NonExistent', @blobObj)
94
- result.code.should == "500"
95
- result.body.should == "\"id does not match location\""
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
- end
100
-
101
- #
102
- # Test DELETE to remove the previously created and modified class
103
- #
104
- describe '#delete' do
105
- it 'should remove the previously created and modified object from persevere' do
106
- result = @p.delete('/Class/Yogo')
107
- result.code.should == "204"
108
- @p.retrieve('/Class/Yogo').code.should == "404"
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
- it 'should fail to delete a non-existent item' do
112
- result = @p.delete('/Class/NotThere')
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
- require 'adapter_shared_spec'
12
-
13
- SPEC_ROOT = Pathname(__FILE__).dirname.expand_path
14
- # $LOAD_PATH.unshift(SPEC_ROOT.parent + 'lib')
15
-
16
- Pathname.glob((SPEC_ROOT + '{lib,*/shared}/**/*.rb').to_s).each { |file| require file }
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.18.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 00:00:00 -07:00
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
- - !ruby/object:Gem::Version
48
- version: "0"
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
- - !ruby/object:Gem::Version
54
- version: "0"
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