grendel-ruby 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ module Grendel
2
+ class Document
3
+ attr_accessor :user, :name, :uri, :data, :content_type
4
+
5
+ def initialize(user, params)
6
+ params.symbolize_keys!
7
+ @user = user
8
+ @client = user.client
9
+ @name = params[:name]
10
+ @data = params[:data]
11
+ @content_type = params[:content_type]
12
+ @uri = params[:uri] ?
13
+ URI.parse(params[:uri]).path :
14
+ "/documents/" + @name # escape this?
15
+ end
16
+
17
+ # delete this document from Grendel
18
+ def delete
19
+ @user.delete(@uri)
20
+ end
21
+
22
+ # send link operations to the Link class
23
+ def links
24
+ LinkManager.new(self)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,47 @@
1
+ module Grendel
2
+ class DocumentManager
3
+
4
+ def initialize(user)
5
+ @user = user
6
+ @base_uri = "/documents"
7
+ end
8
+
9
+ # list all documents
10
+ def list
11
+ response = @user.get(@base_uri)
12
+ response["documents"].map {|d| Document.new(@user, d) }
13
+ end
14
+
15
+ # retreive a document
16
+ def find(name)
17
+ response = @user.get(@base_uri + "/" + name)
18
+ params = {
19
+ :name => name,
20
+ :data => response.body,
21
+ :content_type => response.headers['content-type'].first
22
+ }
23
+ Document.new(@user, params)
24
+ end
25
+
26
+ # store a document, creating a new one if it doesn't exist, or replacing the existing one if it does
27
+ def store(name, data, content_type = nil)
28
+ # if the content type isn't provided, guess it or set it to a default
29
+ unless content_type
30
+ if mime_type = MIME::Types.type_for(name).first
31
+ content_type = mime_type.content_type
32
+ else
33
+ content_type = 'application/octet-stream'
34
+ end
35
+ end
36
+
37
+ response = @user.put(@base_uri + "/" + name, data, :raw_data => true, :headers => {'Content-Type' => content_type})
38
+ Document.new(@user, :name => name, :data => data, :content_type => content_type)
39
+ end
40
+
41
+ # delete the specified document from Grendel
42
+ def delete(name)
43
+ @user.delete(@base_uri + "/" + name)
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ module Grendel
2
+ class Link
3
+ attr_accessor :document, :user, :uri
4
+
5
+ def initialize(document, user, params = {})
6
+ params.symbolize_keys!
7
+ @document = document
8
+ @user = user
9
+ @uri = params[:uri] ?
10
+ URI.parse(params[:uri]).path :
11
+ "/links/" + @user.id # escape this?
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ module Grendel
2
+ class LinkManager
3
+
4
+ def initialize(document)
5
+ @document = document
6
+ @base_uri = @document.uri + "/links"
7
+ end
8
+
9
+ # return links to this document
10
+ def list
11
+ response = @document.user.get(@base_uri)
12
+ response["links"].map do |link|
13
+ Link.new(@document, User.new(@document.user.client, link["user"]), :uri => link["uri"])
14
+ end
15
+ end
16
+
17
+ # add a link to a user and return a Link object
18
+ def add(user_id)
19
+ # REVIEW: 2010-02-23 <brad@wesabe.com> -- what does Grendel return if the link already exists?
20
+ @document.user.put(@base_uri + "/" + user_id)
21
+ Link.new(@document, User.new(@document.user.client, :id => user_id))
22
+ end
23
+
24
+ # remove a link to a user
25
+ def remove(user_id)
26
+ # REVIEW: 2010-02-23 <brad@wesabe.com> -- what does Grendel return if the link didn't exist?
27
+ @document.user.delete(@base_uri + "/" + user_id)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module Grendel
2
+ class LinkedDocument < Document
3
+ attr_accessor :linked_user, :owner
4
+
5
+ # create a new linked document
6
+ # user - linked user
7
+ # params:
8
+ # :name => document name
9
+ # :uri => linked document uri
10
+ # :owner => {
11
+ # :id => owner id
12
+ # :uri => owner uri
13
+ # }
14
+ def initialize(linked_user, params)
15
+ params.symbolize_keys!
16
+ @owner = User.new(linked_user.client, params[:owner])
17
+ super(@owner, params)
18
+ @linked_user = linked_user
19
+ @name = params[:name]
20
+ @uri = params[:uri] ?
21
+ URI.parse(params[:uri]).path :
22
+ ["/linked-documents", @owner.id, name].join("/")
23
+ end
24
+
25
+ # delete this linked document
26
+ def delete
27
+ @linked_user.delete(@uri)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module Grendel
2
+ class LinkedDocumentManager
3
+ def initialize(user)
4
+ @user = user
5
+ @base_uri = "/linked-documents"
6
+ end
7
+
8
+ # list this user's linked documents. Returns an array of LinkedDocument objects
9
+ def list
10
+ response = @user.get(@base_uri)
11
+ response["linked-documents"].map {|ld| LinkedDocument.new(@user, ld) }
12
+ end
13
+
14
+ # retreive a linked document
15
+ def find(owner_id, name)
16
+ response = @user.get([@base_uri, owner_id, name].join("/"))
17
+ params = {
18
+ :name => name,
19
+ :data => response.body,
20
+ :content_type => response.headers['content-type'].first,
21
+ :owner => { :id => owner_id }
22
+ }
23
+ LinkedDocument.new(@user, params)
24
+ end
25
+
26
+ # delete the linked document
27
+ def delete(owner_id, name)
28
+ @user.delete([@base_uri, owner_id, name].join("/"))
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,68 @@
1
+ module Grendel
2
+ class User
3
+ attr_accessor :id, :password, :uri
4
+ attr_reader :client, :modified_at, :created_at, :keys
5
+
6
+ # create a new Grendel::User object
7
+ # params:
8
+ # id
9
+ # uri
10
+ # password
11
+ def initialize(client, params)
12
+ params.symbolize_keys!
13
+ @client = client
14
+ @id = params[:id]
15
+ @uri = params[:uri] ?
16
+ URI.parse(params[:uri]).path :
17
+ "/users/" + @id # escape this?
18
+ @password = params[:password]
19
+ @modified_at = DateTime.parse(params[:"modified-at"]) if params[:"modified-at"]
20
+ @created_at = DateTime.parse(params[:"created-at"]) if params[:"created-at"]
21
+ @keys = params[:keys]
22
+ end
23
+
24
+ # return user's creds in the form required by HTTParty
25
+ def auth
26
+ {:basic_auth => {:username => id, :password => password}}
27
+ end
28
+
29
+ #
30
+ # methods to do authenticated client calls with the user's base_uri
31
+ #
32
+ def get(uri = "", options = {})
33
+ options.merge!(auth)
34
+ @client.get(@uri + uri, options)
35
+ end
36
+
37
+ def post(uri = "", data = {}, options = {})
38
+ options.merge!(auth)
39
+ @client.post(@uri + uri, data, options)
40
+ end
41
+
42
+ def put(uri = "", data = {}, options = {})
43
+ options.merge!(auth)
44
+ @client.put(@uri + uri, data, options)
45
+ end
46
+
47
+ def delete(uri = "", options = {})
48
+ options.merge!(auth)
49
+ @client.delete(@uri + uri, options)
50
+ end
51
+
52
+ # change the user's password
53
+ def change_password(new_password)
54
+ put("", {:password => new_password})
55
+ @password = new_password
56
+ end
57
+
58
+ # send documents calls to the DocumentManager
59
+ def documents
60
+ DocumentManager.new(self)
61
+ end
62
+
63
+ # send linked documents calls to the LinkedDocumentManager
64
+ def linked_documents
65
+ LinkedDocumentManager.new(self)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,31 @@
1
+ module Grendel
2
+ class UserManager
3
+
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+
8
+ # return all Grendel users as Grendel::User objects
9
+ def list
10
+ response = @client.get("/users")
11
+ response["users"].map {|u| User.new(@client, u) }
12
+ end
13
+
14
+ # retrieve a user, optionally setting the password
15
+ def find(id, password = nil)
16
+ response = @client.get("/users/#{id}") # need to escape this
17
+ user = User.new(@client, response)
18
+ user.password = password
19
+ return user
20
+ end
21
+
22
+ # create a new user
23
+ def create(id, password)
24
+ params = {:id => id, :password => password}
25
+ response = @client.post("/users", params)
26
+ # TODO: strip protocol and host from uri
27
+ User.new(@client, params.merge(:uri => response.headers['location'].first))
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Grendel::Client" do
4
+ before do
5
+ @client = Grendel::Client.new("http://example.com")
6
+ end
7
+
8
+ describe "new method" do
9
+ it "should set the base_uri" do
10
+ @client.base_uri.should == "http://example.com"
11
+ end
12
+ end
13
+
14
+ describe "users method" do
15
+ it "should return a Grendel::UserManager" do
16
+ @client.users.class.should be(Grendel::UserManager)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,104 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Grendel::DocumentManager" do
4
+ before do
5
+ @client = Grendel::Client.new("http://grendel")
6
+ @user_id = "alice"
7
+ @password = "s3kret"
8
+ @user = Grendel::User.new(@client, :id => @user_id, :password => @password)
9
+ @base_uri = "#{@user_id}:#{@password}@grendel/users/#{@user_id}/documents"
10
+ end
11
+
12
+ describe "list" do
13
+ before do
14
+ stub_json_request(:get, @base_uri, %{{
15
+ "documents":[
16
+ {"name":"document1.txt",
17
+ "uri":"http://grendel/users/#{@user_id}/documents/document1.txt"},
18
+ {"name":"document2.txt",
19
+ "uri":"http://grendel/users/#{@user_id}/documents/document2.txt"}
20
+ ]}})
21
+ end
22
+
23
+ it "should return an array of all documents" do
24
+ docs = @user.documents.list
25
+ docs.length.should == 2
26
+ docs[0].name.should == "document1.txt"
27
+ docs[0].uri.should == "/users/#{@user_id}/documents/document1.txt"
28
+ docs[1].name.should == "document2.txt"
29
+ docs[1].uri.should == "/users/#{@user_id}/documents/document2.txt"
30
+ end
31
+ end
32
+
33
+ describe "find" do
34
+ before do
35
+ stub_json_request(:get, @base_uri + "/document1.txt", "yay for me", :content_type => "text/plain")
36
+ stub_json_request(:get, @base_uri + "/notfound.txt", "", :status => "404 Not Found")
37
+ end
38
+
39
+ it "should return the document" do
40
+ doc = @user.documents.find("document1.txt")
41
+ doc.name.should == "document1.txt"
42
+ doc.content_type.should == "text/plain"
43
+ doc.data.should == "yay for me"
44
+ end
45
+
46
+ it "should raise an exception if the document is not found" do
47
+ lambda {
48
+ @user.documents.find("notfound.txt")
49
+ }.should raise_error(Grendel::Client::HTTPException) {|error| error.message.should match("404")} # change to should == "404 Not Found" once WebMock supports status messages
50
+ end
51
+ end
52
+
53
+ describe "store" do
54
+ describe "a successful request" do
55
+ before do
56
+ stub_json_request(:put, @base_uri + "/new_document.txt", "", :status => "204 No Content")
57
+ end
58
+
59
+ it "should send a properly-formatted request" do
60
+ @user.documents.store("new_document.txt", "top secret stuff", "text/plain")
61
+ params = { "id" => @user_id, "password" => @password }
62
+ request(:put, @base_uri + "/new_document.txt").
63
+ with(:body => "top secret stuff", :headers => {"Content-Type" => "text/plain"}).
64
+ should have_been_made.once
65
+ end
66
+
67
+ it "should guess the content type if not provided" do
68
+ @user.documents.store("new_document.txt", "top secret stuff")
69
+ params = { "id" => @user_id, "password" => @password }
70
+ request(:put, @base_uri + "/new_document.txt").
71
+ with(:body => "top secret stuff", :headers => {"Content-Type" => "text/plain"}).
72
+ should have_been_made.once
73
+ end
74
+
75
+ it "should default the content type to 'application/octet-stream' if unknown" do
76
+ stub_json_request(:put, @base_uri + "/new_document.-wtf-", "", :status => "204 No Content")
77
+ @user.documents.store("new_document.-wtf-", "top secret stuff")
78
+ params = { "id" => @user_id, "password" => @password }
79
+ request(:put, @base_uri + "/new_document.-wtf-").
80
+ with(:body => "top secret stuff", :headers => {"Content-Type" => "application/octet-stream"}).
81
+ should have_been_made.once
82
+ end
83
+
84
+ it "should return a document" do
85
+ doc = @user.documents.store("new_document.txt", "top secret stuff")
86
+ doc.name.should == "new_document.txt"
87
+ doc.data.should == "top secret stuff"
88
+ doc.content_type.should == "text/plain"
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "delete" do
94
+ before do
95
+ stub_json_request(:delete, @base_uri + "/document.txt", "", :status => "204 No Content")
96
+ @document = Grendel::Document.new(@user, :name => "document.txt")
97
+ end
98
+
99
+ it "should send a properly-formatted request" do
100
+ @user.documents.delete("document.txt")
101
+ request(:delete, @base_uri + "/document.txt").should have_been_made.once
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Grendel::Document" do
4
+ before do
5
+ @client = Grendel::Client.new("http://grendel")
6
+ @user_id = "alice"
7
+ @password = "s3kret"
8
+ @user = Grendel::User.new(@client, :id => @user_id, :password => @password)
9
+ @base_uri = "#{@user_id}:#{@password}@grendel/users/#{@user_id}/documents"
10
+ end
11
+
12
+ describe "delete" do
13
+ before do
14
+ stub_json_request(:delete, @base_uri + "/document.txt", "", :status => "204 No Content")
15
+ @document = Grendel::Document.new(@user, :name => "document.txt")
16
+ end
17
+
18
+ it "should send a properly-formatted request" do
19
+ @document.delete
20
+ request(:delete, @base_uri + "/document.txt").should have_been_made.once
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,80 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ # - get a list of documents a user has linked to them
4
+ # docs = user.linked_documents.list
5
+ # - retrieve a linked document
6
+ # doc = user.linked_documents.find("owner_user_id", "document.txt")
7
+ # - delete a linked document
8
+ # user.linked_documents.delete("owner_user_id", "document.txt")
9
+
10
+ describe "Grendel::LinkManager" do
11
+ before do
12
+ @client = Grendel::Client.new("http://grendel")
13
+ @user_id = "alice"
14
+ @password = "s3kret"
15
+ @user = Grendel::User.new(@client, :id => @user_id, :password => @password)
16
+ @document = Grendel::Document.new(@user, :name => "document1.txt")
17
+ @uri = "#{@user_id}:#{@password}@grendel/users/#{@user_id}/documents/#{@document.name}/links"
18
+ end
19
+
20
+ describe "list" do
21
+ before do
22
+ stub_json_request(:get, @uri, %{{
23
+ "links":[
24
+ {
25
+ "user":{
26
+ "id":"bob",
27
+ "uri":"http://grendel/users/bob"
28
+ },
29
+ "uri":"http://grendel/users/alice/documents/document1.txt/links/bob"
30
+ },
31
+ {
32
+ "user":{
33
+ "id":"carol",
34
+ "uri":"http://grendel/users/carol"
35
+ },
36
+ "uri":"http://grendel/users/alice/documents/document1.txt/links/carol"
37
+ }]
38
+ }})
39
+ end
40
+
41
+ it "should list users with links to this document" do
42
+ links = @document.links.list
43
+ links.length.should == 2
44
+ links[0].user.id.should == "bob"
45
+ links[0].uri.should == "/users/alice/documents/document1.txt/links/bob"
46
+ links[1].user.id.should == "carol"
47
+ links[1].uri.should == "/users/alice/documents/document1.txt/links/carol"
48
+ end
49
+ end
50
+
51
+ describe "add" do
52
+ before do
53
+ @other_user_id = "bob"
54
+ stub_json_request(:put, @uri + "/" + @other_user_id, "")
55
+ end
56
+
57
+ it "should send a properly-formatted request" do
58
+ @document.links.add(@other_user_id)
59
+ request(:put, @uri + "/" + @other_user_id).should have_been_made.once
60
+ end
61
+
62
+ it "should return a Link object" do
63
+ link = @document.links.add(@other_user_id)
64
+ link.document.should == @document
65
+ link.user.id.should == @other_user_id
66
+ end
67
+ end
68
+
69
+ describe "remove" do
70
+ before do
71
+ @other_user_id = "bob"
72
+ stub_json_request(:delete, @uri + "/" + @other_user_id, "")
73
+ end
74
+
75
+ it "should send a properly-formatted request" do
76
+ @document.links.remove(@other_user_id)
77
+ request(:delete, @uri + "/" + @other_user_id).should have_been_made.once
78
+ end
79
+ end
80
+ end