persevere 0.18.0 → 0.21.0

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