rscribd 1.1.0 → 1.2.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.
@@ -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