rscribd 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,9 +11,9 @@ module Scribd
11
11
  # Raised when trying to perform an action that isn't allowed for the current
12
12
  # active user. Note that this exception is thrown only if the error originates
13
13
  # locally. If the request must go out to the Scribd server before the
14
- # privilege error occurs, a Scribd::ResponseError will be thrown. Unless a
14
+ # privilege error occurs, a {Scribd::ResponseError} will be thrown. Unless a
15
15
  # method's documentation indicates otherwise, assume that the error will
16
- # originate remotely and a Scribd::ResponseError will be thrown.
16
+ # originate remotely and a {Scribd::ResponseError} will be thrown.
17
17
 
18
18
  class PrivilegeError < StandardError; end
19
19
 
@@ -22,11 +22,10 @@ module Scribd
22
22
  # their descriptions for each API method.
23
23
 
24
24
  class ResponseError < RuntimeError
25
- # The error code.
25
+ # @return [Fixnum, String] The error code.
26
26
  attr_reader :code
27
27
 
28
- # Initializes the error with a given code.
29
-
28
+ # @private
30
29
  def initialize(code)
31
30
  @code = code
32
31
  end
@@ -1,36 +1,44 @@
1
1
  module Scribd
2
2
 
3
3
  # Describes a remote object that the Scribd API lets you interact with. All
4
- # such objects are modeled after the <tt>ActiveRecord</tt> ORM approach.
4
+ # such objects are modeled after the Active Record ORM approach.
5
5
  #
6
- # The Resource superclass is never directly used; you will interact with
7
- # actual Scribd entities like Document and User, which inherit functionality
8
- # from this superclass.
6
+ # The @Resource@ superclass is never directly used; you will interact with
7
+ # actual Scribd entities like {Document} and {User}, which inherit
8
+ # functionality from this superclass.
9
9
  #
10
10
  # Objects have one or more attributes (also called fields) that can be
11
11
  # accessed directly through synonymous methods. For instance, if your resource
12
- # has an attribute +title+, you can get and set the title like so:
12
+ # has an attribute @title@, you can get and set the title like so:
13
13
  #
14
- # obj.title #=> "Title"
15
- # obj.title = "New Title"
14
+ # <pre><code>
15
+ # obj.title #=> "Title"
16
+ # obj.title = "New Title"
17
+ # </code></pre>
16
18
  #
17
- # The specific attributes that a Document or a User or any other resource has
18
- # are not stored locally. They are downloaded remotely whenever a resource is
19
- # loaded from the remote server. Thus, you can modify any attribute you want,
20
- # though it may or may not have any effect:
19
+ # The specific attributes that a {Document} or a {User} or any other resource
20
+ # has are not saved locally. They are downloaded remotely whenever a resource
21
+ # is loaded from the remote server. Thus, you can modify any attribute you
22
+ # want, though it may or may not have any effect:
21
23
  #
22
- # doc = Scribd::Document.find(:text => 'foo').first
23
- # doc.self_destruct_in = 5.seconds #=> Does not produce error
24
- # doc.save #=> Has no effect, since that attribute doesn't exist. Your document does not explode.
24
+ # <pre><code>
25
+ # doc = Scribd::Document.find(:text => 'foo').first
26
+ # doc.self_destruct_in = 5.seconds #=> Does not produce error
27
+ # doc.save #=> Has no effect, since that attribute doesn't exist. Your document does not explode.
28
+ # </code></pre>
25
29
  #
26
30
  # As shown above, when you make changes to an attribute, these changes are not
27
31
  # immediately reflected remotely. They are only stored locally until such time
28
32
  # as save is called. When you call save, the remote object is updated to
29
33
  # reflect the changes you made in its API instance.
34
+ #
35
+ # @abstract
30
36
 
31
37
  class Resource
32
38
 
33
39
  # Initializes instance variables.
40
+ #
41
+ # @param [Hash] options Initial attributes for the new object.
34
42
 
35
43
  def initialize(options={})
36
44
  @saved = false
@@ -39,8 +47,11 @@ module Scribd
39
47
  end
40
48
 
41
49
  # Creates a new instance with the given attributes, saves it immediately,
42
- # and returns it. You should call its created? method if you need to verify
43
- # that the object was saved successfully.
50
+ # and returns it. You should call its {#created?} method if you need to
51
+ # verify that the object was saved successfully.
52
+ #
53
+ # @param [Hash] options Initial attributes for the new object.
54
+ # @return [Scribd::Resource] The new object.
44
55
 
45
56
  def self.create(options={})
46
57
  obj = new(options)
@@ -48,49 +59,56 @@ module Scribd
48
59
  obj
49
60
  end
50
61
 
51
- # Throws NotImplementedError by default.
52
-
62
+ # @abstract This method is implemented by subclasses.
63
+
53
64
  def save
54
65
  raise NotImplementedError, "Cannot save #{self.class.to_s} objects"
55
66
  end
56
67
 
57
- # Throws NotImplementedError by default.
58
-
68
+ # @abstract This method is implemented by subclasses.
69
+
59
70
  def self.find(options)
60
71
  raise NotImplementedError, "Cannot find #{self.class.to_s} objects"
61
72
  end
62
73
 
63
- # Throws NotImplementedError by default.
74
+ # @abstract This method is implemented by subclasses.
64
75
 
65
76
  def destroy
66
77
  raise NotImplementedError, "Cannot destroy #{self.class.to_s} objects"
67
78
  end
68
79
 
69
- # Returns true if this document's attributes have been updated remotely, and
70
- # thus their local values reflect the remote values.
80
+ # @return [true, false] Whether this resource's attributes have been updated
81
+ # remotely, and thus their local values reflect the remote values.
71
82
 
72
83
  def saved?
73
84
  @saved
74
85
  end
75
86
 
76
- # Returns true if this document has been created remotely, and corresponds
77
- # to a document on the Scribd website.
87
+ # @return [true, false] Whether this resource has been created remotely, and
88
+ # corresponds to something on the Scribd website.
78
89
 
79
90
  def created?
80
91
  @created
81
92
  end
82
93
 
83
- # Returns the value of an attribute, referenced by string or symbol, or nil
84
- # if the attribute cannot be read.
94
+ # Returns the value of an attribute.
95
+ #
96
+ # @param [#to_sym] attribute The attribute to read.
97
+ # @return [String] The value of the attribute.
98
+ # @return [nil] If the attribute could not be read.
99
+ # @raise [ArgumentError] If an invalid value for @attribute@ is given.
85
100
 
86
101
  def read_attribute(attribute)
87
102
  raise ArgumentError, "Attribute must respond to to_sym" unless attribute.respond_to? :to_sym
88
103
  @attributes[attribute.to_sym]
89
104
  end
90
105
 
91
- # Returns a map of attributes to their values, given an array of attributes,
92
- # referenced by string or symbol. Attributes that cannot be read are
93
- # ignored.
106
+ # Returns a map of attributes to their values, given an array of attributes.
107
+ # Attributes that cannot be read are ignored.
108
+ #
109
+ # @param [Enumerable<String, Symbol>] attributes The attributes to read.
110
+ # @return [Hash<Symbol -> String] The attribute values.
111
+ # @raise [ArgumentError] If an invalid value for @attributes@ is provided.
94
112
 
95
113
  def read_attributes(attributes)
96
114
  raise ArgumentError, "Attributes must be listed in an Enumeration" unless attributes.kind_of?(Enumerable)
@@ -101,8 +119,12 @@ module Scribd
101
119
  end
102
120
 
103
121
  # Assigns values to attributes. Takes a hash that specifies the
104
- # attribute-value pairs to update. Does not perform a save. Non-writeable
122
+ # attribute-value pairs to update. Does not perform a save. Non-writable
105
123
  # attributes are ignored.
124
+ #
125
+ # @param [Hash<#to_sym -> #to_s>] values The values to update and their new
126
+ # values.
127
+ # @raise [ArgumentError] If an invalid value for @values@ is provided.
106
128
 
107
129
  def write_attributes(values)
108
130
  raise ArgumentError, "Values must be specified through a hash of attributes" unless values.kind_of? Hash
@@ -114,15 +136,17 @@ module Scribd
114
136
  # retrieved for changed through a method call, even if it doesn't exist.
115
137
  # Such attributes will be ignored and purged when the document is saved:
116
138
  #
117
- # doc = Scribd::Document.new
118
- # doc.foobar #=> Returns nil
119
- # doc.foobar = 12
120
- # doc.foobar #=> Returns 12
121
- # doc.save
122
- # doc.foobar #=> Returns nil
139
+ # <pre><code>
140
+ # doc = Scribd::Document.new
141
+ # doc.foobar #=> Returns nil
142
+ # doc.foobar = 12
143
+ # doc.foobar #=> Returns 12
144
+ # doc.save
145
+ # doc.foobar #=> Returns nil
146
+ # </code></pre>
123
147
  #
124
- # Because of this, no Scribd resource will ever raise NoMethodError.
125
-
148
+ # Because of this, no Scribd resource will ever raise @NoMethodError@.
149
+
126
150
  def method_missing(meth, *args)
127
151
  if meth.to_s =~ /(\w+)=/ then
128
152
  raise ArgumentError, "Only one parameter can be passed to attribute=" unless args.size == 1
@@ -132,9 +156,8 @@ module Scribd
132
156
  end
133
157
  end
134
158
 
135
- # Pretty-print for debugging output of Scribd resources.
136
-
137
- def inspect #:nodoc:
159
+ # @private
160
+ def inspect
138
161
  "#<#{self.class.to_s} #{@attributes.select { |k, v| not v.nil? }.collect { |k,v| k.to_s + '=' + v.to_s }.join(', ')}>"
139
162
  end
140
163
 
@@ -0,0 +1,102 @@
1
+ module Scribd
2
+
3
+ # Contains methods for working with iPaper Secure. For more information about
4
+ # iPaper Secure, see the online API documentation.
5
+
6
+ module Security
7
+
8
+ # Grants a user access to a {Document}. The user is referenced by his
9
+ # identifier (as used in the iPaper Secure embed code). If no document is
10
+ # provided, globally grants this user access to all documents.
11
+ #
12
+ # @param [String] user_identifier The user identifier as used in your embed
13
+ # code. (See the online iPaper Secure documentation.)
14
+ # @param [Scribd::Document, #to_i, nil] document If @nil@, globally grants
15
+ # this user access to all documents. Otherwise, grants this user access
16
+ # to one document specified by ID or {Document} instance.
17
+ # @raise [ArgumentError] If an invalid value for @document@ is provided.
18
+ # @see Scribd::Document#grant_access
19
+
20
+ def self.grant_access(user_identifier, document=nil)
21
+ set_access user_identifier, true, document
22
+ end
23
+
24
+ # Revokes from a user access to a {Document}. The user is referenced by his
25
+ # identifier (as used in the iPaper Secure embed code). If no document is
26
+ # provided, globally revokes access to all documents from this user.
27
+ #
28
+ # @param [String] user_identifier The user identifier as used in your embed
29
+ # code. (See the online iPaper Secure documentation.)
30
+ # @param [Scribd::Document, #to_i, nil] document If @nil@, globally revokes
31
+ # access to all documents from this user. Otherwise, revokes access to one
32
+ # document specified by ID or {Document} instance.
33
+ # @raise [ArgumentError] If an invalid value for @document@ is provided.
34
+ # @see Scribd::Document#revoke_access
35
+
36
+ def self.revoke_access(user_identifier, document=nil)
37
+ set_access user_identifier, false, document
38
+ end
39
+
40
+ # Sets whether a user has access to a {Document}. The user is referenced by
41
+ # his identifier (as used in the iPaper Secure embed code). If no document
42
+ # is provided, globally sets access to all documents for this user.
43
+ #
44
+ # @param [String] user_identifier The user identifier as used in your embed
45
+ # code. (See the online iPaper Secure documentation.)
46
+ # @param [true, false] access_allowed If @true@, grants access; if @false@,
47
+ # revokes access.
48
+ # @param [Scribd::Document, #to_i, nil] document If @nil@, globally sets
49
+ # access to all documents for this user. Otherwise, sets access to one
50
+ # document specified by ID or {Document} instance.
51
+ # @raise [ArgumentError] If an invalid value for @document@ is provided.
52
+
53
+ def self.set_access(user_identifier, access_allowed, document=nil)
54
+ allow_value = (access_allowed ? 1 : 0)
55
+
56
+ if document.nil? then
57
+ API.instance.send_request('security.setAccess', :user_identifier => user_identifier, :allowed => allow_value)
58
+ return
59
+ end
60
+
61
+ API.instance.send_request('security.setAccess', :user_identifier => user_identifier, :allowed => allow_value, :doc_id => (
62
+ if document.kind_of?(Scribd::Document) then
63
+ document.id
64
+ elsif document.respond_to?(:to_i) then
65
+ document.to_i
66
+ else
67
+ raise ArgumentError, "document must be a Scribd::Document, a document ID, or nil"
68
+ end
69
+ ))
70
+ end
71
+
72
+ # Returns a list of user identifiers that are allowed to access a given
73
+ # document. See the iPaper Secure online documentation for more information.
74
+ #
75
+ # @param [Scribd::Document, Fixnum] document Either a document instance or
76
+ # document ID.
77
+ # @return [Array<String>] An array of user identifiers.
78
+ # @see Scribd::Document#access_list
79
+
80
+ def self.document_access_list(document)
81
+ response = API.instance.send_request('security.getDocumentAccessList', :doc_id => (document.kind_of?(Scribd::Document) ? document.id : document))
82
+ acl = Array.new
83
+ response.get_elements('/rsp/resultset/result/user_identifier').each { |tag| acl << tag.text }
84
+ return acl
85
+ end
86
+
87
+ # Returns a list of documents that a user can view. The user is identified
88
+ # by his user identifier. See the iPaper Secure online documentation for
89
+ # more information.
90
+ #
91
+ # @param [String] user_identifier The user identifier.
92
+ # @return [Array<Scribd::Document>] An array of documents the user can
93
+ # access.
94
+
95
+ def self.user_access_list(user_identifier)
96
+ response = API.instance.send_request('security.getUserAccessList', :user_identifier => user_identifier)
97
+ acl = Array.new
98
+ response.get_elements('/rsp/resultset/result').each { |tag| acl << Scribd::Document.new(:xml => tag) }
99
+ return acl
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,193 @@
1
+ module Scribd
2
+
3
+ # A user of the Scribd website. API programs can use this class to log in as a
4
+ # Scribd user, create new user accounts, and get information about the current
5
+ # user.
6
+ #
7
+ # An API program begins by logging into Scribd:
8
+ #
9
+ # <pre><code>user = Scribd::User.login 'login', 'pass'</code></pre>
10
+ #
11
+ # You can now access information about this user through direct method calls:
12
+ #
13
+ # <pre><code>user.name #=> 'Real Name'</code></pre>
14
+ #
15
+ # If, at any time, you would like to retrieve the {User} instance for the
16
+ # currently logged-in user, simply call:
17
+ #
18
+ # <pre><code>user = Scribd::API.instance.user</code></pre>
19
+ #
20
+ # For information on a user's attributes, please consult the online API
21
+ # documentation.
22
+ #
23
+ # You can create a new account with the {.signup} (a.k.a. {.create}) method:
24
+ #
25
+ # <pre><code>user = Scribd::User.signup :username => 'testuser', :password => 'testpassword', :email => your@email.com</code></pre>
26
+
27
+ class User < Resource
28
+
29
+ # Creates a new, unsaved user with the given attributes. You can eventually
30
+ # use this record to create a new Scribd account.
31
+ #
32
+ # @param [Hash] options The initial attributes for the user.
33
+
34
+ def initialize(options={})
35
+ super
36
+ if options[:xml] then
37
+ load_attributes(options[:xml])
38
+ @saved = true
39
+ @created = true
40
+ else
41
+ @attributes = options
42
+ end
43
+ end
44
+
45
+ # For new, unsaved records, creates a new Scribd user with the provided
46
+ # attributes, then logs in as that user. Currently modification of existing
47
+ # Scribd users is not supported.
48
+ #
49
+ # @raise [Scribd::ResponseError] If a remote error occurs.
50
+
51
+ def save
52
+ if not created? then
53
+ response = API.instance.send_request('user.signup', @attributes)
54
+ xml = response.get_elements('/rsp')[0]
55
+ load_attributes(xml)
56
+ API.instance.user = self
57
+ else
58
+ raise NotImplementedError, "Cannot update a user once that user's been saved"
59
+ end
60
+ end
61
+
62
+ # Returns a list of documents owned by this user. By default, the size of
63
+ # the returned list is capped at 1,000. Use the @:limit@ and @:offset@
64
+ # parameters to page through this user's documents; however, @:limit@ cannot
65
+ # be greater than 1,000. This list is _not_ backed by the server, so if you
66
+ # add or remove items from it, it will not make those changes server-side.
67
+ # This also has some tricky consequences when modifying a list of documents
68
+ # while iterating over it:
69
+ #
70
+ # <pre><code>
71
+ # docs = user.documents
72
+ # docs.each(&:destroy)
73
+ # docs #=> Still populated, because it hasn't been updated
74
+ # docs = user.documents #=> Now it's empty
75
+ # </code></pre>
76
+ #
77
+ # {Scribd::Document} instances returned through this method have more
78
+ # attributes than those returned by the {Scribd::Document.find} method. The
79
+ # additional attributes are documented online.
80
+ #
81
+ # @param [Hash] options Options to provide to the API find method.
82
+ # @return [Array<Scribd::Document>] The found documents.
83
+ # @see #find_documents
84
+
85
+ def documents(options = {})
86
+ response = API.instance.send_request('docs.getList', options.merge(:session_key => @attributes[:session_key]))
87
+ documents = Array.new
88
+ response.elements['/rsp/resultset'].elements.each do |doc|
89
+ documents << Document.new(:xml => doc, :owner => self)
90
+ end
91
+ return documents
92
+ end
93
+
94
+ # Finds documents owned by this user matching a given query. The parameters
95
+ # provided to this method are identical to those provided to {.find}.
96
+ #
97
+ # @param [Hash] options Options to pass to the API find method.
98
+ # @see #documents
99
+
100
+ def find_documents(options={})
101
+ return nil unless @attributes[:session_key]
102
+ Document.find options.merge(:scope => 'user', :session_key => @attributes[:session_key])
103
+ end
104
+
105
+ # Loads a {Document} by ID. You can only load such documents if they belong
106
+ # to this user.
107
+ #
108
+ # @param [Fixnum] document_id The Scribd document ID.
109
+ # @return [Scribd::Document] The found document.
110
+ # @return [nil] If nothing was found.
111
+
112
+ def find_document(document_id)
113
+ return nil unless @attributes[:session_key]
114
+ response = API.instance.send_request('docs.getSettings', { :doc_id => document_id, :session_key => @attributes[:session_key] })
115
+ Document.new :xml => response.elements['/rsp'], :owner => self
116
+ end
117
+
118
+ # Uploads a document to a user's document list. See the
119
+ # {Scribd::Document#save} method for more information on the options hash.
120
+ #
121
+ # @param [Hash] options Options to pass to the API upload method.
122
+ # @raise [Scribd::NotReadyError] If the user is unsaved.
123
+
124
+ def upload(options)
125
+ raise NotReadyError, "User hasn't been created yet" unless created?
126
+ Document.create options.merge(:owner => self)
127
+ end
128
+
129
+ # Returns the collections this user has created. For information about
130
+ # search options, see the online API documentation. The list of collections
131
+ # is not memoized or cached locally.
132
+ #
133
+ # @param [Hash] options Options to pass to the API collections search
134
+ # method.
135
+ # @return [Array<Scribd::Collection>] The collections created by this user.
136
+ # @raise [Scribd::NotReadyError] If the user is unsaved
137
+
138
+ def collections(options={})
139
+ raise NotReadyError, "User hasn't been created yet" unless created?
140
+ response = API.instance.send_request('docs.getCollections', options.merge(:session_key => @attributes[:session_key]))
141
+ collections = Array.new
142
+ response.elements['/rsp/resultset'].elements.each do |coll|
143
+ collections << Collection.new(:xml => coll, :owner => self)
144
+ end
145
+ return collections
146
+ end
147
+
148
+ # Returns a URL that, when visited, will automatically sign in this user and
149
+ # then redirect to the provided URL.
150
+ #
151
+ # @param [String] next_url The URL to redirect to after signing in. By
152
+ # default the user is redirected to the home page.
153
+ # @return [String] An auto-sign-in URL.
154
+ # @raise [Scribd::NotReadyError] If the receiver is not an existing user.
155
+
156
+ def auto_sign_in_url(next_url="")
157
+ raise NotReadyError, "User hasn't been created yet" unless created?
158
+ response = API.instance.send_request('user.getAutoSignInUrl', :session_key => @attributes[:session_key], :next_url => next_url)
159
+ return response.get_elements('/rsp/url').first.cdatas.first.to_s
160
+ end
161
+
162
+ class << self
163
+ alias_method :signup, :create
164
+ end
165
+
166
+ # Logs into Scribd using the given username and password. This user will be
167
+ # used for all subsequent Scribd API calls. You must log in before you can
168
+ # use protected API functions.
169
+ #
170
+ # @param [String] username The Scribd user's login.
171
+ # @param [String] password The Scribd user's password.
172
+ # @return [Scribd::User] The logged-in user.
173
+
174
+ def self.login(username, password)
175
+ response = API.instance.send_request('user.login', { :username => username, :password => password })
176
+ xml = response.get_elements('/rsp').first
177
+ user = User.new(:xml => xml)
178
+ API.instance.user = user
179
+ return user
180
+ end
181
+
182
+ # @return [String] The @user_id@ attribute.
183
+
184
+ def id
185
+ self.user_id
186
+ end
187
+
188
+ # @private
189
+ def to_s
190
+ @attributes[:username]
191
+ end
192
+ end
193
+ end