riakrest 0.0.1

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.
Files changed (42) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +41 -0
  3. data/PostInstall.txt +2 -0
  4. data/README.rdoc +51 -0
  5. data/Rakefile +24 -0
  6. data/examples/auto_update_data.rb +50 -0
  7. data/examples/auto_update_links.rb +48 -0
  8. data/examples/basic_client.rb +33 -0
  9. data/examples/basic_resource.rb +34 -0
  10. data/examples/json_data_resource.rb +32 -0
  11. data/examples/linked_resource.rb +113 -0
  12. data/examples/multiple_resources.rb +43 -0
  13. data/lib/riakrest/core/exceptions.rb +73 -0
  14. data/lib/riakrest/core/jiak_bucket.rb +146 -0
  15. data/lib/riakrest/core/jiak_client.rb +316 -0
  16. data/lib/riakrest/core/jiak_data.rb +265 -0
  17. data/lib/riakrest/core/jiak_link.rb +131 -0
  18. data/lib/riakrest/core/jiak_object.rb +233 -0
  19. data/lib/riakrest/core/jiak_schema.rb +242 -0
  20. data/lib/riakrest/core/query_link.rb +156 -0
  21. data/lib/riakrest/data/jiak_data_hash.rb +182 -0
  22. data/lib/riakrest/resource/jiak_resource.rb +628 -0
  23. data/lib/riakrest/version.rb +7 -0
  24. data/lib/riakrest.rb +164 -0
  25. data/riakrest.gemspec +38 -0
  26. data/script/console +10 -0
  27. data/script/destroy +14 -0
  28. data/script/generate +14 -0
  29. data/spec/core/exceptions_spec.rb +18 -0
  30. data/spec/core/jiak_bucket_spec.rb +103 -0
  31. data/spec/core/jiak_client_spec.rb +358 -0
  32. data/spec/core/jiak_link_spec.rb +77 -0
  33. data/spec/core/jiak_object_spec.rb +210 -0
  34. data/spec/core/jiak_schema_spec.rb +184 -0
  35. data/spec/core/query_link_spec.rb +128 -0
  36. data/spec/data/jiak_data_hash_spec.rb +14 -0
  37. data/spec/resource/jiak_resource_spec.rb +128 -0
  38. data/spec/riakrest_spec.rb +17 -0
  39. data/spec/spec.opts +5 -0
  40. data/spec/spec_helper.rb +12 -0
  41. data/tasks/rspec.rake +21 -0
  42. metadata +113 -0
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2009-10-20
2
+
3
+ * Initial release:
4
+ * Still pre-alpha
data/Manifest.txt ADDED
@@ -0,0 +1,41 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ examples/auto_update_data.rb
7
+ examples/auto_update_links.rb
8
+ examples/basic_client.rb
9
+ examples/basic_resource.rb
10
+ examples/json_data_resource.rb
11
+ examples/linked_resource.rb
12
+ examples/multiple_resources.rb
13
+ lib/riakrest.rb
14
+ lib/riakrest/core/exceptions.rb
15
+ lib/riakrest/core/jiak_bucket.rb
16
+ lib/riakrest/core/jiak_client.rb
17
+ lib/riakrest/core/jiak_data.rb
18
+ lib/riakrest/core/jiak_link.rb
19
+ lib/riakrest/core/jiak_object.rb
20
+ lib/riakrest/core/jiak_schema.rb
21
+ lib/riakrest/core/query_link.rb
22
+ lib/riakrest/data/jiak_data_hash.rb
23
+ lib/riakrest/resource/jiak_resource.rb
24
+ lib/riakrest/version.rb
25
+ riakrest.gemspec
26
+ script/console
27
+ script/destroy
28
+ script/generate
29
+ spec/core/exceptions_spec.rb
30
+ spec/core/jiak_bucket_spec.rb
31
+ spec/core/jiak_client_spec.rb
32
+ spec/core/jiak_link_spec.rb
33
+ spec/core/jiak_object_spec.rb
34
+ spec/core/jiak_schema_spec.rb
35
+ spec/core/query_link_spec.rb
36
+ spec/data/jiak_data_hash_spec.rb
37
+ spec/resource/jiak_resource_spec.rb
38
+ spec/riakrest_spec.rb
39
+ spec/spec.opts
40
+ spec/spec_helper.rb
41
+ tasks/rspec.rake
data/PostInstall.txt ADDED
@@ -0,0 +1,2 @@
1
+
2
+ For more information on riakrest, see http://gemcutter.org/dingosky/riakrest
data/README.rdoc ADDED
@@ -0,0 +1,51 @@
1
+ = riakrest
2
+
3
+ http://github.com/wcpr/riakrest
4
+
5
+ == DESCRIPTION:
6
+
7
+ RiakRest provides structured, RESTful interaction with a Riak document
8
+ store. In Riak parlance, this JSON data exchange is called Jiak. RiakRest
9
+ provides two levels of interaction: Core Client and Resource. Core Client
10
+ interaction works down at the Jiak level and exposes Jiak internals. Resource
11
+ interaction is an abstraction built on top of the Core Client.
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+
16
+ == SYNOPSIS:
17
+
18
+
19
+ == REQUIREMENTS:
20
+
21
+ RestClient is used for REST server interaction.
22
+ JSON is used for data exchange.
23
+
24
+ == INSTALL:
25
+
26
+ sudo gem install riakrest
27
+
28
+ == LICENSE:
29
+
30
+ (The MIT License)
31
+
32
+ Copyright (c) 2009 Paul Rogers, DingoSky LLC
33
+
34
+ Permission is hereby granted, free of charge, to any person obtaining
35
+ a copy of this software and associated documentation files (the
36
+ 'Software'), to deal in the Software without restriction, including
37
+ without limitation the rights to use, copy, modify, merge, publish,
38
+ distribute, sublicense, and/or sell copies of the Software, and to
39
+ permit persons to whom the Software is furnished to do so, subject to
40
+ the following conditions:
41
+
42
+ The above copyright notice and this permission notice shall be
43
+ included in all copies or substantial portions of the Software.
44
+
45
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
46
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
48
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
49
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
50
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
51
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/riakrest'
6
+
7
+ Hoe.plugin :newgem
8
+
9
+ # Generate all the Rake tasks
10
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
11
+ $hoe = Hoe.spec 'riakrest' do
12
+ self.developer 'Paul Rogers', 'paul@dingosky.com'
13
+ self.post_install_message = 'PostInstall.txt'
14
+ self.rubyforge_name = self.name # TODO this is default value
15
+ # self.extra_deps = [['activesupport','>= 2.0.2']]
16
+
17
+ end
18
+
19
+ require 'newgem/tasks'
20
+ Dir['tasks/**/*.rake'].each { |t| load t }
21
+
22
+ # TODO - want other tests/tasks run by default? Add them to the list
23
+ # remove_task :default
24
+ # task :default => [:spec, :features]
@@ -0,0 +1,50 @@
1
+ require 'lib/riakrest'
2
+ include RiakRest
3
+
4
+ PersonData = JiakDataHash.create(:name,:age)
5
+ PersonData.keygen :name
6
+
7
+ class Person
8
+ include JiakResource
9
+
10
+ server 'http://localhost:8002/jiak'
11
+ group 'people'
12
+ data_class PersonData
13
+ auto_post true
14
+ end
15
+
16
+ remy = Person.new(:name => 'remy', :age => 10)
17
+ puts Person.get('remy').name # => "remy"
18
+
19
+ remy.name = "Remy"
20
+ puts Person.get('remy').name # => "remy"
21
+ remy.update
22
+ puts Person.get('remy').name # => "Remy"
23
+
24
+ Person.auto_update true
25
+
26
+ puts Person.get('remy').age # => 10
27
+ remy.age = 12
28
+ puts Person.get('remy').age # => 12
29
+
30
+ Person.auto_update false
31
+ remy.auto_update = true
32
+ puts Person.get('remy').age # => 12
33
+ remy.age = 10
34
+ puts Person.get('remy').age # => 10
35
+
36
+ Person.auto_update true
37
+ remy.auto_update = false
38
+ remy.age = 12
39
+ puts Person.get('remy').age # => 10
40
+ remy.update
41
+ puts Person.get('remy').age # => 12
42
+
43
+ remy.auto_update = nil
44
+ remy.age = 10
45
+ puts Person.get('remy').age # => 10
46
+
47
+ remy.delete
48
+ callie.delete
49
+
50
+
@@ -0,0 +1,48 @@
1
+ require 'lib/riakrest'
2
+ include RiakRest
3
+
4
+ PersonData = JiakDataHash.create(:name,:age)
5
+ PersonData.keygen :name
6
+
7
+ class Person
8
+ include JiakResource
9
+
10
+ server 'http://localhost:8002/jiak'
11
+ group 'people'
12
+ data_class PersonData
13
+ auto_post true
14
+ end
15
+
16
+ remy = Person.new(:name => 'remy', :age => 10)
17
+ callie = Person.new(:name => 'Callie', :age => 12)
18
+
19
+ remy.link(callie,'sister')
20
+ puts remy.walk(Person,'sister').size # => 0
21
+ remy.update
22
+ puts remy.walk(Person,'sister').size # => 1
23
+ remy.remove_link(callie,'sister')
24
+
25
+ Person.auto_update true
26
+ remy.link(callie,'sibling')
27
+ puts remy.walk(Person,'sibling').size # => 1
28
+ remy.remove_link(callie,'sibling')
29
+
30
+ callie.auto_update = false
31
+ callie.link(remy,'sibling')
32
+ puts callie.walk(Person,'sibling').size # => 0
33
+ callie.update
34
+ puts callie.walk(Person,'sibling').size # => 1
35
+ callie.remove_link(remy,'sibling')
36
+
37
+ Person.auto_update false
38
+ remy.auto_update = true
39
+ callie.auto_update = nil
40
+ remy.bi_link(callie,'sisters')
41
+ puts remy.walk(Person,'sisters').size # => 1
42
+ puts callie.walk(Person,'sisters').size # => 0
43
+ callie.update
44
+ puts callie.walk(Person,'sisters').size # => 1
45
+
46
+ remy.delete
47
+ callie.delete
48
+
@@ -0,0 +1,33 @@
1
+ require 'lib/riakrest'
2
+ include RiakRest
3
+
4
+ Person = JiakDataHash.create(:name,:age)
5
+
6
+ client = JiakClient.new("http://localhost:8002/jiak")
7
+ bucket = JiakBucket.new('people',Person)
8
+ client.set_schema(bucket)
9
+
10
+ remy = client.store(JiakObject.new(:bucket => bucket,
11
+ :data => Person.new(:name => "remy",
12
+ :age => 10)),
13
+ :object => true)
14
+ puts client.get(bucket,remy.key).data.name # => "remy"
15
+
16
+ remy.data.name # => "remy"
17
+ remy.data.name = "Remy"
18
+ client.store(remy)
19
+ puts client.get(bucket,remy.key).data.name # => "Remy"
20
+
21
+
22
+ callie = client.store(JiakObject.new(:bucket => bucket,
23
+ :data => Person.new(:name => "Callie",
24
+ :age => 12)),
25
+ :object => true)
26
+ remy << JiakLink.new(bucket,callie.key,'sister')
27
+ client.store(remy)
28
+
29
+ sisters = client.walk(bucket,remy.key,QueryLink.new(bucket,'sister'),Person)
30
+ sisters[0].eql?(callie) # => true
31
+
32
+ client.delete(bucket,remy.key)
33
+ client.delete(bucket,callie.key)
@@ -0,0 +1,34 @@
1
+ require 'lib/riakrest'
2
+ include RiakRest
3
+
4
+ PersonData = JiakDataHash.create(:name,:age)
5
+ PersonData.keygen :name
6
+
7
+ class Person
8
+ include JiakResource
9
+
10
+ server 'http://localhost:8002/jiak'
11
+ group 'people'
12
+ data_class PersonData
13
+ auto_post true
14
+ end
15
+
16
+ remy = Person.new(:name => 'remy', :age => 10)
17
+ puts Person.get('remy').name # => "remy"
18
+
19
+ remy.name = "Remy"
20
+ remy.update
21
+ puts remy.name # => "Remy"
22
+ puts Person.get('remy').name # => "Remy"
23
+
24
+ callie = Person.new(:name => 'Callie', :age => 12)
25
+ remy.bi_link(callie,'sister').update
26
+ callie.update
27
+
28
+ sisters = remy.walk(Person,'sister')
29
+ puts sisters[0].eql?(callie) # => true
30
+
31
+ remy.delete
32
+ callie.delete
33
+
34
+
@@ -0,0 +1,32 @@
1
+ require 'date'
2
+ class DogData # :nodoc:
3
+ include JiakData
4
+
5
+ allowed :name, :birthdate, :weight, :breed
6
+ readwrite :name, :birthdate, :weight
7
+
8
+ def initialize(hsh)
9
+ hsh.each {|key,val| send("#{key}=",val)}
10
+ end
11
+
12
+ def self.create(hsh)
13
+ new(hsh)
14
+ end
15
+
16
+ def self.jiak_create(jiak)
17
+ jiak['birthdate'] = Date.parse(jiak['birthdate']) if jiak['birthdate']
18
+ new(jiak)
19
+ end
20
+
21
+ def for_jiak
22
+ self.class.write_mask.inject({}) do |build,field|
23
+ val = send("#{field}")
24
+ build[field] = val unless val.nil?
25
+ build
26
+ end
27
+ end
28
+
29
+ def keygen
30
+ @name
31
+ end
32
+ end
@@ -0,0 +1,113 @@
1
+ require 'lib/riakrest'
2
+ include RiakRest
3
+
4
+ PersonData = JiakDataHash.create(:name)
5
+ PersonData.keygen :name
6
+
7
+ class Parent
8
+ include JiakResource
9
+
10
+ server 'http://localhost:8002/jiak'
11
+ group 'parents'
12
+ data_class PersonData
13
+ end
14
+
15
+ Child = Parent.copy(:group => 'children')
16
+
17
+ # relationships
18
+ parent_children = {
19
+ 'p0' => ['c0'],
20
+ 'p1' => ['c0','c1','c2'],
21
+ 'p2' => ['c2','c3'],
22
+ 'p3' => ['c3']
23
+ }
24
+
25
+ # invert relationships
26
+ child_parents = parent_children.inject({}) do |build, (p,cs)|
27
+ cs.each do |c|
28
+ build[c] ? build[c] << p : build[c] = [p]
29
+ end
30
+ build
31
+ end
32
+
33
+ # store data and relationships
34
+ parent_children.each do |pname,cnames|
35
+ p = Parent.new(:name => pname)
36
+ cnames.each do |cname|
37
+ begin
38
+ c = Child.get(cname)
39
+ rescue
40
+ c = Child.new(:name => cname)
41
+ end
42
+ c.link(p,'parent')
43
+ c.put
44
+ p.link(c,'child')
45
+ end
46
+ p.post
47
+ end
48
+
49
+ # retrieve parents
50
+ parents = parent_children.keys.map {|p| Parent.get(p)}
51
+ p0,p1,p2,p3 = parents
52
+ p1.name # => 'p1'
53
+
54
+ # retrieve children
55
+ children = child_parents.keys.map {|c| Child.get(c)}
56
+ c0,c1,c2,c3 = children
57
+ c1.name # => 'c1'
58
+
59
+ # retrieve parent children
60
+ p0c,p1c,p2c,p3c = parents.map {|p| p.walk(Child,'child')}
61
+ p2c[0].name # => 'c2' (not sorted, so could be 'c3')
62
+
63
+ # retrieve children parents
64
+ c0p,c1p,c2p,c3p = children.map {|c| c.walk(Parent,'parent')}
65
+ c3p[0].name # => 'p3'
66
+
67
+ # retrieve children siblings
68
+ c0s,c1s,c2s,c3s = children.map do |c|
69
+ c.walk(Parent,'parent',Child,'child').delete_if{|s| s.eql?(c)}
70
+ end
71
+ c3s[0].name # => 'c2'
72
+
73
+ # who is c3's step-sibling's other parent?
74
+ c3sp = c3.walk(Parent,'parent',Child,'child',Parent,'parent')
75
+ c3p.each {|p| c3sp.delete_if{|sp| p.eql?(sp)}}
76
+ c3sp[0].name # => "p1"
77
+
78
+ # add sibling links
79
+ children.each do |c|
80
+ siblings = c.walk(Parent,'parent',Child,'child').delete_if{|s| s.eql?(c)}
81
+ siblings.each {|s| c.link(s,'sibling')}
82
+ c.update
83
+ end
84
+ c1.walk(Child,'sibling').size # => 2
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+ # some folks are odd, and others are normal
94
+ parent_children.keys.each do |p|
95
+ parent = Parent.get(p)
96
+ p_children = parent.walk(Child,'child')
97
+ p_children.each do |child|
98
+ child.link(parent, p[1].to_i.odd? ? 'odd' : 'normal')
99
+ child.update
100
+ parent.link(child, child.name[1].to_i.odd? ? 'odd' : 'normal')
101
+ end
102
+ parent.update
103
+ end
104
+ # refresh parents and children variables
105
+ parents.each {|p| p.get}
106
+ children.each {|c| c.get}
107
+
108
+ # do any odd parents have normal children?
109
+ op = parents.inject([]) do |build,parent|
110
+ build << parent.walk(Child,'normal',Parent,'odd')
111
+ build.flatten.uniq
112
+ end
113
+ op[0].name # => 'p1'
@@ -0,0 +1,43 @@
1
+ require 'lib/riakrest'
2
+ include RiakRest
3
+
4
+ DogData = JiakDataHash.create(:name,:weight,:breed)
5
+ DogData.keygen :name
6
+ class Dog
7
+ include JiakResource
8
+ server 'http://localhost:8002/jiak'
9
+ group 'dogs'
10
+ data_class DogData
11
+ end
12
+
13
+ DogBreedData = JiakDataHash.create(DogData.schema)
14
+ DogBreedData.readwrite :name, :breed
15
+ DogBreed = Dog.copy(:data_class => DogBreedData)
16
+
17
+ DogWeightData = JiakDataHash.create(DogData.schema)
18
+ DogWeightData.readwrite :name, :weight
19
+ DogWeight = Dog.copy(:data_class => DogWeightData)
20
+
21
+ Dog.pov
22
+ addie = Dog.new(:name => 'adelaide', :weight => 45, :breed => 'heeler')
23
+ addie.post
24
+ puts addie.name # => "adelaide"
25
+ puts addie.breed # => "heeler"
26
+ puts addie.weight # => 45
27
+
28
+ DogBreed.pov
29
+ addie = DogBreed.get('adelaide')
30
+ addie.breed = "Heeler"
31
+ addie.put
32
+
33
+ DogWeight.pov
34
+ addie = DogWeight.get('adelaide')
35
+ addie.weight = 47
36
+ addie.put
37
+
38
+ Dog.pov
39
+ addie = Dog.get('adelaide')
40
+ puts addie.name # => "adelaide"
41
+ puts addie.breed # => "Heeler"
42
+ puts addie.weight # => 47
43
+
@@ -0,0 +1,73 @@
1
+ module RiakRest
2
+
3
+ # Top-level RiakRest exception. All RiakRest exceptions are subclass of this
4
+ # class.
5
+ class Exception < StandardError
6
+ end
7
+
8
+ # Client exception in accessing a resource on the Jiak server.
9
+ class JiakResourceException < RiakRest::Exception
10
+ attr_accessor :params
11
+
12
+ # call-seq:
13
+ # raise JiakClientException, message="", params={}
14
+ #
15
+ # The message is handled using normal Ruby exception handling. The params
16
+ # field is a hash containing:
17
+ # <code>action</code>:: The client resource access action.
18
+ # <code>args</code>:: The arguments to the action.
19
+ # <code>uri</code>:: The URI used to access the resource.
20
+ def initialize(msg="", params={})
21
+ super(msg)
22
+ @params = params
23
+ end
24
+
25
+ # call-seq:
26
+ # err.description -> string
27
+ #
28
+ # A string description of a client error when accessing a Jiak resource.
29
+ def description
30
+ unless(@params.empty?)
31
+ action = @params[:action] || ""
32
+ args = @params[:args] || "()"
33
+ uri = @params[:uri] || ""
34
+ "#{self.class}: #{action}#{args} #{message} using uri='#{uri}'"
35
+ else
36
+ "#{self.class}: #{message}"
37
+ end
38
+ end
39
+ end
40
+
41
+ # Exceptions pertaining to JiakClient usage.
42
+ class JiakClientException < RiakRest::Exception
43
+ end
44
+
45
+ # Resource not found on the Jiak server.
46
+ class JiakResourceNotFound < RiakRest::JiakResourceException
47
+ end
48
+
49
+ # Exceptions pertaining to JiakBucket usage.
50
+ class JiakBucketException < RiakRest::Exception
51
+ end
52
+
53
+ # Exceptions pertaining to JiakObject usage.
54
+ class JiakObjectException < RiakRest::Exception
55
+ end
56
+
57
+ # Exceptions pertaining to JiakData usage.
58
+ class JiakDataException < RiakRest::Exception
59
+ end
60
+
61
+ # Exceptions pertaining to JiakLink usage.
62
+ class JiakLinkException < RiakRest::Exception
63
+ end
64
+
65
+ # Exceptions pertaining to JiakSchema usage.
66
+ class JiakSchemaException < RiakRest::Exception
67
+ end
68
+
69
+ # Exceptions pertaining to QueryLink usage.
70
+ class QueryLinkException < RiakRest::Exception
71
+ end
72
+
73
+ end