redbooth-ruby 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +0 -1
  4. data/README.md +187 -115
  5. data/lib/redbooth-ruby/client.rb +6 -39
  6. data/lib/redbooth-ruby/client_operations/perform.rb +93 -0
  7. data/lib/redbooth-ruby/file.rb +8 -0
  8. data/lib/redbooth-ruby/helpers.rb +32 -0
  9. data/lib/redbooth-ruby/operations/base.rb +3 -2
  10. data/lib/redbooth-ruby/request/collection.rb +3 -2
  11. data/lib/redbooth-ruby/request/connection.rb +66 -30
  12. data/lib/redbooth-ruby/request/helpers.rb +2 -2
  13. data/lib/redbooth-ruby/request/info.rb +1 -1
  14. data/lib/redbooth-ruby/request/validator.rb +2 -2
  15. data/lib/redbooth-ruby/session.rb +34 -11
  16. data/lib/redbooth-ruby/task_list.rb +28 -0
  17. data/lib/redbooth-ruby/version.rb +2 -2
  18. data/lib/redbooth-ruby.rb +6 -3
  19. data/spec/cassettes/RedboothRuby_File/_download/downloads_a_file.yml +354 -0
  20. data/spec/cassettes/RedboothRuby_Organization/_delete/makes_a_new_DELETE_request_using_the_correct_API_endpoint_to_delete_a_specific_organization.yml +4 -4
  21. data/spec/cassettes/RedboothRuby_Project/_delete/makes_a_new_DELETE_request_using_the_correct_API_endpoint_to_delete_a_specific_project.yml +110 -110
  22. data/spec/cassettes/RedboothRuby_Session/_refresh_access_token_/.yml +55 -0
  23. data/spec/cassettes/RedboothRuby_Session/_refresh_access_token_/call_on_token_refresh_with_the_old_and_new_token.yml +55 -0
  24. data/spec/cassettes/RedboothRuby_Session/_refresh_access_token_/refreshes_the_access_token.yml +55 -0
  25. data/spec/redbooth-ruby/base_spec.rb +5 -5
  26. data/spec/redbooth-ruby/client_operations/metadata_spec.rb +4 -4
  27. data/spec/redbooth-ruby/client_operations/perform_spec.rb +135 -0
  28. data/spec/redbooth-ruby/client_operations/search_spec.rb +4 -4
  29. data/spec/redbooth-ruby/client_spec.rb +2 -43
  30. data/spec/redbooth-ruby/comment_spec.rb +17 -18
  31. data/spec/redbooth-ruby/conversation_spec.rb +16 -16
  32. data/spec/redbooth-ruby/file_spec.rb +29 -22
  33. data/spec/redbooth-ruby/me_spec.rb +2 -2
  34. data/spec/redbooth-ruby/membership_spec.rb +18 -18
  35. data/spec/redbooth-ruby/note_spec.rb +16 -16
  36. data/spec/redbooth-ruby/organization_spec.rb +16 -16
  37. data/spec/redbooth-ruby/person_spec.rb +18 -18
  38. data/spec/redbooth-ruby/project_spec.rb +18 -18
  39. data/spec/redbooth-ruby/request/base_spec.rb +5 -5
  40. data/spec/redbooth-ruby/request/collection_spec.rb +3 -3
  41. data/spec/redbooth-ruby/request/connection_spec.rb +8 -8
  42. data/spec/redbooth-ruby/request/info_spec.rb +13 -13
  43. data/spec/redbooth-ruby/request/response_spec.rb +4 -4
  44. data/spec/redbooth-ruby/request/validator_spec.rb +7 -7
  45. data/spec/redbooth-ruby/session_spec.rb +100 -0
  46. data/spec/redbooth-ruby/subtaks_spec.rb +16 -16
  47. data/spec/redbooth-ruby/task_spec.rb +22 -22
  48. data/spec/redbooth-ruby/user_spec.rb +4 -4
  49. data/spec/redbooth_spec.rb +13 -13
  50. data/spec/spec_helper.rb +2 -3
  51. data/temp/spec/files/test_download.txt +8 -0
  52. metadata +41 -24
@@ -2,10 +2,11 @@ module RedboothRuby
2
2
  class Client
3
3
  include RedboothRuby::ClientOperations::Search
4
4
  include RedboothRuby::ClientOperations::Metadata
5
+ include Helpers
5
6
 
6
7
  RESOURCES = [ :me, :user, :task, :organization, :person, :project,
7
8
  :conversation, :membership, :comment, :note, :subtask,
8
- :file ]
9
+ :file, :task_list ]
9
10
 
10
11
  attr_reader :session, :options
11
12
 
@@ -27,7 +28,7 @@ module RedboothRuby
27
28
  #
28
29
  # @param [String||Symbol] action name of the action to execute over
29
30
  # @param [Hash] options for the execution
30
- # @returns the execution return or nil
31
+ # @return the execution return or nil
31
32
  #
32
33
  # @example
33
34
  # session = RedboothRuby::Session.new(api_key: '_your_api_key_', auth_token: '_aut_token_for_the_user')
@@ -50,43 +51,9 @@ module RedboothRuby
50
51
  # @param [String||Symbol] resource_name name of the resource to execute over
51
52
  # @param [String||Symbol] action name of the action to execute over
52
53
  # @param [Hash] options for the execution
53
- # @returns the execution return or nil
54
+ # @return the execution return or nil
54
55
  def perform!(resource_name, action, options = {})
55
- fail RedboothRuby::AuthenticationError unless session
56
- resource(resource_name).send(action, options_with_session(options))
57
- rescue Processing => processing
58
- delay = processing.response.data["retry_after"] || 10
59
- retry_in(delay, resource_name, action, options)
56
+ ClientOperations::Perform.new(resource_name, action, session, options).perform!
60
57
  end
61
-
62
- # Retryes the request in the given time
63
- # either calls the given proc options[:retry]
64
- # or executes it in this thread
65
- #
66
- def retry_in(delay, *args)
67
- if options[:retry]
68
- options[:retry].call(delay)
69
- else
70
- sleep(delay)
71
- perform!(*args)
72
- end
73
- end
74
-
75
- # Merge the given options with the session for use the api
76
- #
77
- # @param [Hash] options options to merge with session
78
- # @return [Hash]
79
- def options_with_session(options={})
80
- options.merge(session: @session)
81
- end
82
-
83
- # Gest the api resource model class by his name
84
- #
85
- # @param [String||Symbol] name name of the resource
86
- # @return [Copy::Base] resource to use the api
87
- def resource(name)
88
- eval('RedboothRuby::' + name.to_s.capitalize) rescue nil
89
- end
90
-
91
58
  end
92
- end
59
+ end
@@ -0,0 +1,93 @@
1
+ module RedboothRuby
2
+ module ClientOperations
3
+ class Perform
4
+ include RedboothRuby::Helpers
5
+ attr_accessor :resource_name, :action, :session, :options
6
+ attr_accessor :tries, :processing_error, :oauth_token_expired_error
7
+
8
+ def initialize(resource_name, action, session, options = {})
9
+ @resource_name = resource_name
10
+ @action = action
11
+ @session = session
12
+ @options = options
13
+ @tries = 0
14
+ end
15
+
16
+ # Performs the resource action
17
+ #
18
+ # @return the execution return or nil
19
+ def perform!
20
+ @tries += 1
21
+ fail RedboothRuby::AuthenticationError unless session
22
+ resource(resource_name).send(action, options_with_session(options))
23
+ rescue Processing => processing_error
24
+ @processing_error = processing_error
25
+ perform_processing!
26
+ rescue OauthTokenExpired => oauth_token_expired_error
27
+ @oauth_token_expired_error = oauth_token_expired_error
28
+ perform_oauth_token_expired!
29
+ end
30
+
31
+ # Delays the execution of the enqueued processing
32
+ #
33
+ # @return the execution return or nil
34
+ def perform_processing!
35
+ delay = if processing_error && processing_error.response
36
+ processing_error.response.data['retry_after'].to_i
37
+ else
38
+ 10
39
+ end
40
+ retry_in(delay)
41
+ end
42
+
43
+ # Perform refresh on the session access token
44
+ #
45
+ # @return the execution return or raise OauthTokenExpired
46
+ def perform_oauth_token_expired!
47
+ if tries == 1 && refresh_session_access_token!
48
+ perform!
49
+ else
50
+ raise oauth_token_expired_error
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ # Retries the request in the given time either calls the given
57
+ # proc options[:retry] or executes it in this thread
58
+ #
59
+ def retry_in(delay)
60
+ if options[:retry]
61
+ options[:retry].call(delay)
62
+ else
63
+ sleep(delay)
64
+ perform!
65
+ end
66
+ end
67
+
68
+ # Merge the given options with the session for use the api
69
+ #
70
+ # @param [Hash] options options to merge with session
71
+ # @return [Hash]
72
+ def options_with_session(options={})
73
+ options.merge(session: @session)
74
+ end
75
+
76
+ # Get the api resource model class by his name
77
+ #
78
+ # @param [String||Symbol] name name of the resource
79
+ # @return [Copy::Base] resource to use the api
80
+ def resource(name)
81
+ Object.const_get("RedboothRuby::#{camelize(name)}") rescue nil
82
+ end
83
+
84
+ # Refresh the session access token if auto_refresh_token is enabled
85
+ #
86
+ # @return [Boolean]
87
+ def refresh_session_access_token!
88
+ session.auto_refresh_token && session.refresh_access_token!
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -24,6 +24,14 @@ module RedboothRuby
24
24
  :created_at,
25
25
  :updated_at
26
26
 
27
+ # Returns a blop with the file data
28
+ #
29
+ # @return [String] the object metadata
30
+ def download(style='original')
31
+ request = RedboothRuby.request(:download, nil, "files/#{id}/download/#{style}/#{name}", {}, { session: session })
32
+ request.body
33
+ end
34
+
27
35
  class << self
28
36
  # Create operation overwrite to parse file first
29
37
  def create(attrs)
@@ -0,0 +1,32 @@
1
+ module RedboothRuby
2
+ module Helpers
3
+
4
+ # Transform a resource name into a class name.
5
+ # Transform a Symbol|String:
6
+ # capitalize the first letter
7
+ # capitalize the first letter after _'s, removing the _'s
8
+ # Example: camelize(:task_list) # => TaskList
9
+ # Example: camelize('task_list') # => TaskList
10
+ #
11
+ # @param [Symbol|String] name to convert
12
+ # @return [String] string of the class name
13
+ def camelize(name)
14
+ name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
15
+ end
16
+
17
+ # Transform a class name into a resource name.
18
+ # Downcase all the letters, inserting an underscore _ before capitals
19
+ # Example: underscore('TaskList') # => task_list
20
+ #
21
+ # @param [String] camel_case_word to convert
22
+ # @return [String] string of the resource name
23
+ def underscore(camel_case_word)
24
+ camel_case_word.gsub(/::/, '/').
25
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
26
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
27
+ tr("-", "_").
28
+ downcase
29
+ end
30
+
31
+ end
32
+ end
@@ -2,6 +2,7 @@ module RedboothRuby
2
2
  module Operations
3
3
  module Base
4
4
  module ClassMethods
5
+ include RedboothRuby::Helpers
5
6
  # Options for request
6
7
  # overwrite this in the model to set security
7
8
  #
@@ -20,7 +21,7 @@ module RedboothRuby
20
21
  #
21
22
  def api_member_url(id = nil, method = nil)
22
23
  url = api_resource_name(method)
23
- url += "/#{id}" if id
24
+ url += "/#{ id }" if id
24
25
  url
25
26
  end
26
27
 
@@ -35,7 +36,7 @@ module RedboothRuby
35
36
  # overwrite this in the model if the api is not well named
36
37
  #
37
38
  def api_resource_name(method = nil)
38
- "#{name.split('::').last.downcase}s"
39
+ "#{ underscore(name.split('::').last) }s"
39
40
  end
40
41
  end
41
42
 
@@ -1,6 +1,7 @@
1
1
  module RedboothRuby
2
2
  module Request
3
3
  class Collection
4
+ include RedboothRuby::Helpers
4
5
  attr_reader :response, :params, :method, :session, :resource
5
6
 
6
7
  def initialize(attributes={})
@@ -99,12 +100,12 @@ module RedboothRuby
99
100
  klass.new(hash)
100
101
  end
101
102
 
102
- # Gest the api resource model class by his name
103
+ # Get the api resource model class by his name
103
104
  #
104
105
  # @param [String||Symbol] name name of the resource
105
106
  # @return [Copy::Base] resource to use the api
106
107
  def resource_klass(name)
107
- eval('RedboothRuby::' + name.to_s.capitalize) rescue nil
108
+ eval('RedboothRuby::' + camelize(name)) rescue nil
108
109
  end
109
110
 
110
111
  # Whenever the response is paginated or not
@@ -14,34 +14,35 @@ module RedboothRuby
14
14
 
15
15
  def request
16
16
  return unless access_token
17
- if use_body_file?
18
- ::File.open(body_file_attrs[:local_path]) do |file|
19
- req = Net::HTTP::Post::Multipart.new(
20
- api_url,
21
- body_hash.merge(
22
- 'asset' => UploadIO.new(file,
23
- 'application/octet-stream',
24
- body_file_attrs[:name]
25
- )
26
- )
27
- )
28
- req['Authorization'] = "Bearer #{access_token.token}"
29
- # access_token.sign! req
30
- if RedboothRuby.configuration[:use_ssl]
31
- http = Net::HTTP.new(RedboothRuby.configuration[:api_base] , Net::HTTP.https_default_port)
32
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
33
- http.use_ssl = RedboothRuby.configuration[:use_ssl]
34
- else
35
- domain, port = RedboothRuby.configuration[:api_base].split(':')
36
- http = Net::HTTP.new(domain, port || Net::HTTP.http_default_port)
37
- end
17
+ case
18
+ when use_body_file?
19
+ multipart_request
20
+ when download_file?
21
+ download_file_with_redirect
22
+ else
23
+ access_token.send(*request_data)
24
+ end
25
+ end
26
+
27
+ # Downloads the desired file following redirects to
28
+ # amazon s3 without authentication headers
29
+ #
30
+ def download_file_with_redirect
31
+ max_redirects = access_token.options.fetch(:max_redirects, 20)
32
+ response = access_token.send(:get, URI.encode(api_url), { redirect_count: max_redirects + 1 })
33
+ if [302, 301].include? response.status
34
+ url = response.headers['Location']
35
+ uri = URI.parse(url)
36
+ req = Net::HTTP::Get.new(uri)
37
+ http = Net::HTTP.new(uri.host , Net::HTTP.https_default_port)
38
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
39
+ http.use_ssl = RedboothRuby.configuration[:use_ssl]
38
40
  http.start do |inner_http|
39
41
  inner_http.request(req)
40
42
  end
43
+ else
44
+ response
41
45
  end
42
- else
43
- access_token.send(*request_data)
44
- end
45
46
  end
46
47
 
47
48
  def set_request_data
@@ -55,6 +56,36 @@ module RedboothRuby
55
56
 
56
57
  protected
57
58
 
59
+ # Performs a multipart request by containing given files and post data
60
+ #
61
+ # @return [Http::Request]
62
+ def multipart_request
63
+ ::File.open(body_file_attrs[:local_path]) do |file|
64
+ req = Net::HTTP::Post::Multipart.new(
65
+ api_url,
66
+ body_hash.merge(
67
+ 'asset' => UploadIO.new(file,
68
+ 'application/octet-stream',
69
+ body_file_attrs[:name]
70
+ )
71
+ )
72
+ )
73
+ req['Authorization'] = "Bearer #{access_token.token}"
74
+ # access_token.sign! req
75
+ if RedboothRuby.configuration[:use_ssl]
76
+ http = Net::HTTP.new(RedboothRuby.configuration[:api_base] , Net::HTTP.https_default_port)
77
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
78
+ http.use_ssl = RedboothRuby.configuration[:use_ssl]
79
+ else
80
+ domain, port = RedboothRuby.configuration[:api_base].split(':')
81
+ http = Net::HTTP.new(domain, port || Net::HTTP.http_default_port)
82
+ end
83
+ http.start do |inner_http|
84
+ inner_http.request(req)
85
+ end
86
+ end
87
+ end
88
+
58
89
  # Body params hash
59
90
  #
60
91
  # @return [Hash]
@@ -88,6 +119,11 @@ module RedboothRuby
88
119
  body_hash.key?(:asset)
89
120
  end
90
121
 
122
+ def download_file?
123
+ return false unless @info
124
+ @info.http_method == :download
125
+ end
126
+
91
127
  def use_url_params?
92
128
  return false unless @info
93
129
  case @info.http_method
@@ -98,12 +134,12 @@ module RedboothRuby
98
134
  end
99
135
  end
100
136
 
101
- # Returns the api url foir this request or default
137
+ # Returns the api url for this request or default
102
138
  def api_url
103
- url = "#{api_url_method}#{api_url_domain}"
104
- url += "#{RedboothRuby.configuration[:api_base]}"
105
- url += "#{api_url_path}"
106
- url += "#{api_url_version}"
139
+ url = "#{ api_url_method}#{api_url_domain }"
140
+ url += "#{ RedboothRuby.configuration[:api_base] }"
141
+ url += "#{ api_url_path }"
142
+ url += "#{ api_url_version }"
107
143
  if @info
108
144
  url += @info.url
109
145
  if use_url_params? && !body_hash.empty?
@@ -123,7 +159,7 @@ module RedboothRuby
123
159
 
124
160
  def api_url_domain
125
161
  return '' unless domain
126
- "#{domain}."
162
+ "#{ domain }."
127
163
  end
128
164
 
129
165
  def api_url_path
@@ -23,7 +23,7 @@ module RedboothRuby
23
23
  result[name.to_s] = normalize_params(value)
24
24
  when Array
25
25
  value.each_with_index do |item_value, index|
26
- result["#{name.to_s}[#{index}]"] = item_value.to_s
26
+ result["#{ name.to_s }[#{ index }]"] = item_value.to_s
27
27
  end
28
28
  else
29
29
  result[name.to_s] = value.to_s
@@ -33,4 +33,4 @@ module RedboothRuby
33
33
  end
34
34
  end
35
35
  end
36
- end
36
+ end
@@ -25,7 +25,7 @@ module RedboothRuby
25
25
  def path_with_params(path, params)
26
26
  unless params.empty?
27
27
  encoded_params = URI.encode_www_form(params)
28
- [path, encoded_params].join("?")
28
+ [path, encoded_params].join('?')
29
29
  else
30
30
  path
31
31
  end
@@ -47,9 +47,9 @@ module RedboothRuby
47
47
  def verify_authentication_header
48
48
  case raw_response.headers['WWW-Authenticate']
49
49
  when /error\=\"invalid_token\".*expired/
50
- fail OauhtTokenExpired
50
+ fail OauthTokenExpired
51
51
  when /error\=\"invalid_token\".*revoked/
52
- fail OauhtTokenRevoked
52
+ fail OauthTokenRevoked
53
53
  end
54
54
  end
55
55
 
@@ -3,18 +3,23 @@ require 'oauth2'
3
3
  module RedboothRuby
4
4
  class Session
5
5
 
6
- attr_accessor :token, :refresh_token, :access_token
6
+ attr_accessor :token, :access_token
7
+ attr_accessor :refresh_token, :expires_in, :auto_refresh_token, :on_token_refresh
7
8
  attr_accessor :consumer_key, :consumer_secret
8
9
  attr_accessor :oauth_verifier, :oauth_token
9
10
 
10
11
  OAUTH_URLS = {
11
- :site => 'https://redbooth.com/api/3',
12
- :authorize_url => 'https://redbooth.com/oauth2/authorize',
13
- :token_url => 'https://redbooth.com/oauth2/token'
12
+ site: 'https://redbooth.com/api/3',
13
+ authorize_url: 'https://redbooth.com/oauth2/authorize',
14
+ token_url: 'https://redbooth.com/oauth2/token'
14
15
  }
15
16
 
16
17
  def initialize(opts = {})
17
18
  @token = opts[:token]
19
+ @refresh_token = opts[:refresh_token]
20
+ @expires_in = opts[:expires_in]
21
+ @auto_refresh_token = opts[:auto_refresh_token] || true
22
+ @on_token_refresh = opts[:on_token_refresh]
18
23
  @consumer_key = opts[:consumer_key] || RedboothRuby.configuration[:consumer_key]
19
24
  @consumer_secret = opts[:consumer_secret] || RedboothRuby.configuration[:consumer_secret]
20
25
  @oauth_verifier = opts[:oauth_verifier]
@@ -31,16 +36,34 @@ module RedboothRuby
31
36
  end
32
37
 
33
38
  def get_access_token_url
34
- url = OAUTH_URLS[:request_token_url]
35
- url += "?oauth_verifier=#{oauth_verifier}" if oauth_verifier
36
- url += "&oauth_token=#{oauth_token}" if oauth_token
39
+ uri = URI.parse(OAUTH_URLS[:token_url])
40
+ params = URI.decode_www_form(uri.query.to_s)
41
+ params << ['oauth_verifier', oauth_verifier] if oauth_verifier
42
+ params << ['oauth_token', oauth_token] if oauth_token
43
+ uri.query = URI.encode_www_form(params) if params.size > 0
44
+ uri.to_s
37
45
  end
38
46
 
39
47
  def access_token
40
- @access_token ||= OAuth2::AccessToken.new(client, token)
48
+ @access_token ||= OAuth2::AccessToken.new(client, token,
49
+ refresh_token: refresh_token, expires_in: expires_in)
41
50
  end
42
51
 
43
- end
44
- end
45
-
52
+ def refresh_access_token!
53
+ new_access_token = access_token.refresh!
54
+ if new_access_token
55
+ on_token_refresh.call(access_token, new_access_token) if on_token_refresh.is_a?(Proc)
56
+ @access_token = new_access_token
57
+ end
58
+ new_access_token
59
+ end
46
60
 
61
+ def on_token_refresh(&block)
62
+ if block_given?
63
+ @on_token_refresh = block
64
+ else
65
+ @on_token_refresh
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,28 @@
1
+ module RedboothRuby
2
+ class TaskList < Base
3
+ include RedboothRuby::Operations::Index
4
+ include RedboothRuby::Operations::Create
5
+ include RedboothRuby::Operations::Update
6
+ include RedboothRuby::Operations::Show
7
+ include RedboothRuby::Operations::Delete
8
+ include RedboothRuby::Operations::Meta
9
+
10
+ attr_accessor :id,
11
+ :name,
12
+ :project_id,
13
+ :user_id,
14
+ :start_on,
15
+ :finish_on,
16
+ :position,
17
+ :archived,
18
+ :archived_tasks_count,
19
+ :tasks_count,
20
+ :last_comment_id,
21
+ :updated_by_id,
22
+ :metadata,
23
+ :deleted,
24
+ :completed,
25
+ :created_at,
26
+ :updated_at
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module RedboothRuby
2
- VERSION = '0.0.5'
3
- end
2
+ VERSION = '0.1.0'
3
+ end
data/lib/redbooth-ruby.rb CHANGED
@@ -15,6 +15,7 @@ module RedboothRuby
15
15
  autoload :Me, 'redbooth-ruby/me'
16
16
  autoload :User, 'redbooth-ruby/user'
17
17
  autoload :Task, 'redbooth-ruby/task'
18
+ autoload :TaskList, 'redbooth-ruby/task_list'
18
19
  autoload :Organization, 'redbooth-ruby/organization'
19
20
  autoload :Person, 'redbooth-ruby/person'
20
21
  autoload :Project, 'redbooth-ruby/project'
@@ -24,6 +25,7 @@ module RedboothRuby
24
25
  autoload :Note, 'redbooth-ruby/note'
25
26
  autoload :Subtask, 'redbooth-ruby/subtask'
26
27
  autoload :File, 'redbooth-ruby/file'
28
+ autoload :Helpers, 'redbooth-ruby/helpers'
27
29
 
28
30
 
29
31
  module Operations
@@ -47,14 +49,15 @@ module RedboothRuby
47
49
  end
48
50
 
49
51
  module ClientOperations
52
+ autoload :Perform, 'redbooth-ruby/client_operations/perform'
50
53
  autoload :Search, 'redbooth-ruby/client_operations/search'
51
54
  autoload :Metadata, 'redbooth-ruby/client_operations/metadata'
52
55
  end
53
56
 
54
57
  class RedboothError < StandardError; end
55
58
  class AuthenticationError < RedboothError; end
56
- class OauhtTokenExpired < AuthenticationError; end
57
- class OauhtTokenRevoked < AuthenticationError; end
59
+ class OauthTokenExpired < AuthenticationError; end
60
+ class OauthTokenRevoked < AuthenticationError; end
58
61
  class NotFound < RedboothError; end
59
62
  class APIError < RedboothError; end
60
63
  class ObjectNotFound < APIError; end
@@ -120,4 +123,4 @@ module RedboothRuby
120
123
  @@configuration[:api_version] ||= '3'
121
124
  @@configuration[:use_ssl] ||= true
122
125
  end
123
- end
126
+ end