leancloud-ruby-client 0.1.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.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +16 -0
  4. data/Gemfile.lock +86 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +1177 -0
  7. data/Rakefile +45 -0
  8. data/VERSION +1 -0
  9. data/example.rb +35 -0
  10. data/features.md +1111 -0
  11. data/fixtures/vcr_cassettes/test_acls_arent_objects.yml +274 -0
  12. data/fixtures/vcr_cassettes/test_array_add.yml +213 -0
  13. data/fixtures/vcr_cassettes/test_array_add_pointerizing.yml +380 -0
  14. data/fixtures/vcr_cassettes/test_array_add_unique.yml +319 -0
  15. data/fixtures/vcr_cassettes/test_batch_create_object.yml +107 -0
  16. data/fixtures/vcr_cassettes/test_batch_delete_object.yml +637 -0
  17. data/fixtures/vcr_cassettes/test_batch_run.yml +109 -0
  18. data/fixtures/vcr_cassettes/test_batch_update_nils_delete_keys.yml +435 -0
  19. data/fixtures/vcr_cassettes/test_batch_update_object.yml +637 -0
  20. data/fixtures/vcr_cassettes/test_contains_all.yml +1143 -0
  21. data/fixtures/vcr_cassettes/test_cql.yml +99 -0
  22. data/fixtures/vcr_cassettes/test_created_at.yml +109 -0
  23. data/fixtures/vcr_cassettes/test_decrement.yml +213 -0
  24. data/fixtures/vcr_cassettes/test_deep_parse.yml +321 -0
  25. data/fixtures/vcr_cassettes/test_destroy.yml +213 -0
  26. data/fixtures/vcr_cassettes/test_empty_response.yml +1026 -0
  27. data/fixtures/vcr_cassettes/test_eq_pointerize.yml +427 -0
  28. data/fixtures/vcr_cassettes/test_equality.yml +321 -0
  29. data/fixtures/vcr_cassettes/test_get.yml +215 -0
  30. data/fixtures/vcr_cassettes/test_get_installation.yml +58 -0
  31. data/fixtures/vcr_cassettes/test_get_missing.yml +160 -0
  32. data/fixtures/vcr_cassettes/test_image_file_associate_with_object.yml +2089 -0
  33. data/fixtures/vcr_cassettes/test_image_file_save.yml +1928 -0
  34. data/fixtures/vcr_cassettes/test_include.yml +321 -0
  35. data/fixtures/vcr_cassettes/test_new_model.yml +109 -0
  36. data/fixtures/vcr_cassettes/test_new_object.yml +109 -0
  37. data/fixtures/vcr_cassettes/test_nils_delete_keys.yml +319 -0
  38. data/fixtures/vcr_cassettes/test_object_id.yml +56 -0
  39. data/fixtures/vcr_cassettes/test_parse_delete.yml +421 -0
  40. data/fixtures/vcr_cassettes/test_pointer.yml +109 -0
  41. data/fixtures/vcr_cassettes/test_request_sms.yml +48 -0
  42. data/fixtures/vcr_cassettes/test_reset_password.yml +109 -0
  43. data/fixtures/vcr_cassettes/test_retries.yml +4173 -0
  44. data/fixtures/vcr_cassettes/test_retries_404.yml +1026 -0
  45. data/fixtures/vcr_cassettes/test_retries_404_correct.yml +1026 -0
  46. data/fixtures/vcr_cassettes/test_retries_json_error.yml +2265 -0
  47. data/fixtures/vcr_cassettes/test_retries_server_error.yml +2265 -0
  48. data/fixtures/vcr_cassettes/test_save_installation.yml +58 -0
  49. data/fixtures/vcr_cassettes/test_save_with_sub_objects.yml +484 -0
  50. data/fixtures/vcr_cassettes/test_saving_boolean_values.yml +215 -0
  51. data/fixtures/vcr_cassettes/test_saving_nested_objects.yml +62 -0
  52. data/fixtures/vcr_cassettes/test_server_update.yml +586 -0
  53. data/fixtures/vcr_cassettes/test_simple_save.yml +109 -0
  54. data/fixtures/vcr_cassettes/test_text_file_save.yml +109 -0
  55. data/fixtures/vcr_cassettes/test_update.yml +213 -0
  56. data/fixtures/vcr_cassettes/test_updated_at.yml +213 -0
  57. data/fixtures/vcr_cassettes/test_user_login.yml +276 -0
  58. data/fixtures/vcr_cassettes/test_user_save.yml +109 -0
  59. data/fixtures/vcr_cassettes/test_xget.yml +603 -0
  60. data/leancloud-ruby-client.gemspec +166 -0
  61. data/lib/faraday/better_retry.rb +94 -0
  62. data/lib/faraday/extended_parse_json.rb +39 -0
  63. data/lib/faraday/get_method_override.rb +32 -0
  64. data/lib/leancloud-ruby-client.rb +34 -0
  65. data/lib/leancloud/application.rb +7 -0
  66. data/lib/leancloud/batch.rb +53 -0
  67. data/lib/leancloud/client.rb +149 -0
  68. data/lib/leancloud/cloud.rb +28 -0
  69. data/lib/leancloud/datatypes.rb +355 -0
  70. data/lib/leancloud/error.rb +42 -0
  71. data/lib/leancloud/installation.rb +57 -0
  72. data/lib/leancloud/model.rb +14 -0
  73. data/lib/leancloud/object.rb +252 -0
  74. data/lib/leancloud/protocol.rb +193 -0
  75. data/lib/leancloud/push.rb +48 -0
  76. data/lib/leancloud/query.rb +194 -0
  77. data/lib/leancloud/user.rb +38 -0
  78. data/lib/leancloud/util.rb +93 -0
  79. data/test/cloud_functions/MyCloudCode/cloud/main.js +4 -0
  80. data/test/config/global.json +14 -0
  81. data/test/helper.rb +108 -0
  82. data/test/middleware/better_retry_test.rb +57 -0
  83. data/test/middleware/extend_parse_json_test.rb +55 -0
  84. data/test/parsers.jpg +0 -0
  85. data/test/test_batch.rb +132 -0
  86. data/test/test_client.rb +183 -0
  87. data/test/test_cloud.rb +31 -0
  88. data/test/test_datatypes.rb +105 -0
  89. data/test/test_file.rb +67 -0
  90. data/test/test_init.rb +23 -0
  91. data/test/test_init_from_cloud_code.rb +8 -0
  92. data/test/test_installation.rb +49 -0
  93. data/test/test_model.rb +22 -0
  94. data/test/test_object.rb +295 -0
  95. data/test/test_push.rb +45 -0
  96. data/test/test_query.rb +198 -0
  97. data/test/test_throttle.rb +5 -0
  98. data/test/test_user.rb +60 -0
  99. metadata +298 -0
@@ -0,0 +1,166 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "leancloud-ruby-client"
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Alan deLevie", "Adam Alpern", "Dennis Zhuang"]
12
+ s.date = "2015-04-10"
13
+ s.description = "A simple Ruby client for the leancloud.cn REST API"
14
+ s.email = "killme2008@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".travis.yml",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "example.rb",
28
+ "features.md",
29
+ "fixtures/vcr_cassettes/test_acls_arent_objects.yml",
30
+ "fixtures/vcr_cassettes/test_array_add.yml",
31
+ "fixtures/vcr_cassettes/test_array_add_pointerizing.yml",
32
+ "fixtures/vcr_cassettes/test_array_add_unique.yml",
33
+ "fixtures/vcr_cassettes/test_batch_create_object.yml",
34
+ "fixtures/vcr_cassettes/test_batch_delete_object.yml",
35
+ "fixtures/vcr_cassettes/test_batch_run.yml",
36
+ "fixtures/vcr_cassettes/test_batch_update_nils_delete_keys.yml",
37
+ "fixtures/vcr_cassettes/test_batch_update_object.yml",
38
+ "fixtures/vcr_cassettes/test_contains_all.yml",
39
+ "fixtures/vcr_cassettes/test_cql.yml",
40
+ "fixtures/vcr_cassettes/test_created_at.yml",
41
+ "fixtures/vcr_cassettes/test_decrement.yml",
42
+ "fixtures/vcr_cassettes/test_deep_parse.yml",
43
+ "fixtures/vcr_cassettes/test_destroy.yml",
44
+ "fixtures/vcr_cassettes/test_empty_response.yml",
45
+ "fixtures/vcr_cassettes/test_eq_pointerize.yml",
46
+ "fixtures/vcr_cassettes/test_equality.yml",
47
+ "fixtures/vcr_cassettes/test_get.yml",
48
+ "fixtures/vcr_cassettes/test_get_installation.yml",
49
+ "fixtures/vcr_cassettes/test_get_missing.yml",
50
+ "fixtures/vcr_cassettes/test_image_file_associate_with_object.yml",
51
+ "fixtures/vcr_cassettes/test_image_file_save.yml",
52
+ "fixtures/vcr_cassettes/test_include.yml",
53
+ "fixtures/vcr_cassettes/test_new_model.yml",
54
+ "fixtures/vcr_cassettes/test_new_object.yml",
55
+ "fixtures/vcr_cassettes/test_nils_delete_keys.yml",
56
+ "fixtures/vcr_cassettes/test_object_id.yml",
57
+ "fixtures/vcr_cassettes/test_parse_delete.yml",
58
+ "fixtures/vcr_cassettes/test_pointer.yml",
59
+ "fixtures/vcr_cassettes/test_request_sms.yml",
60
+ "fixtures/vcr_cassettes/test_reset_password.yml",
61
+ "fixtures/vcr_cassettes/test_retries.yml",
62
+ "fixtures/vcr_cassettes/test_retries_404.yml",
63
+ "fixtures/vcr_cassettes/test_retries_404_correct.yml",
64
+ "fixtures/vcr_cassettes/test_retries_json_error.yml",
65
+ "fixtures/vcr_cassettes/test_retries_server_error.yml",
66
+ "fixtures/vcr_cassettes/test_save_installation.yml",
67
+ "fixtures/vcr_cassettes/test_save_with_sub_objects.yml",
68
+ "fixtures/vcr_cassettes/test_saving_boolean_values.yml",
69
+ "fixtures/vcr_cassettes/test_saving_nested_objects.yml",
70
+ "fixtures/vcr_cassettes/test_server_update.yml",
71
+ "fixtures/vcr_cassettes/test_simple_save.yml",
72
+ "fixtures/vcr_cassettes/test_text_file_save.yml",
73
+ "fixtures/vcr_cassettes/test_update.yml",
74
+ "fixtures/vcr_cassettes/test_updated_at.yml",
75
+ "fixtures/vcr_cassettes/test_user_login.yml",
76
+ "fixtures/vcr_cassettes/test_user_save.yml",
77
+ "fixtures/vcr_cassettes/test_xget.yml",
78
+ "leancloud-ruby-client.gemspec",
79
+ "lib/faraday/better_retry.rb",
80
+ "lib/faraday/extended_parse_json.rb",
81
+ "lib/faraday/get_method_override.rb",
82
+ "lib/leancloud-ruby-client.rb",
83
+ "lib/leancloud/application.rb",
84
+ "lib/leancloud/batch.rb",
85
+ "lib/leancloud/client.rb",
86
+ "lib/leancloud/cloud.rb",
87
+ "lib/leancloud/datatypes.rb",
88
+ "lib/leancloud/error.rb",
89
+ "lib/leancloud/installation.rb",
90
+ "lib/leancloud/model.rb",
91
+ "lib/leancloud/object.rb",
92
+ "lib/leancloud/protocol.rb",
93
+ "lib/leancloud/push.rb",
94
+ "lib/leancloud/query.rb",
95
+ "lib/leancloud/user.rb",
96
+ "lib/leancloud/util.rb",
97
+ "test/cloud_functions/MyCloudCode/cloud/main.js",
98
+ "test/config/global.json",
99
+ "test/helper.rb",
100
+ "test/middleware/better_retry_test.rb",
101
+ "test/middleware/extend_parse_json_test.rb",
102
+ "test/parsers.jpg",
103
+ "test/test_batch.rb",
104
+ "test/test_client.rb",
105
+ "test/test_cloud.rb",
106
+ "test/test_datatypes.rb",
107
+ "test/test_file.rb",
108
+ "test/test_init.rb",
109
+ "test/test_init_from_cloud_code.rb",
110
+ "test/test_installation.rb",
111
+ "test/test_model.rb",
112
+ "test/test_object.rb",
113
+ "test/test_push.rb",
114
+ "test/test_query.rb",
115
+ "test/test_throttle.rb",
116
+ "test/test_user.rb"
117
+ ]
118
+ s.homepage = "http://github.com/killme2008/leancloud-ruby-client"
119
+ s.licenses = ["MIT"]
120
+ s.require_paths = ["lib"]
121
+ s.rubygems_version = "2.0.6"
122
+ s.summary = "A simple Ruby client for the leancloud.cn REST API"
123
+
124
+ if s.respond_to? :specification_version then
125
+ s.specification_version = 4
126
+
127
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
128
+ s.add_runtime_dependency(%q<faraday>, [">= 0"])
129
+ s.add_runtime_dependency(%q<faraday_middleware>, [">= 0"])
130
+ s.add_development_dependency(%q<bundler>, [">= 0"])
131
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
132
+ s.add_development_dependency(%q<test-unit>, ["= 2.5.0"])
133
+ s.add_development_dependency(%q<mocha>, ["= 0.12.0"])
134
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.5"])
135
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
136
+ s.add_development_dependency(%q<webmock>, ["~> 1.9.0"])
137
+ s.add_development_dependency(%q<vcr>, [">= 0"])
138
+ s.add_development_dependency(%q<pry>, [">= 0"])
139
+ else
140
+ s.add_dependency(%q<faraday>, [">= 0"])
141
+ s.add_dependency(%q<faraday_middleware>, [">= 0"])
142
+ s.add_dependency(%q<bundler>, [">= 0"])
143
+ s.add_dependency(%q<shoulda>, [">= 0"])
144
+ s.add_dependency(%q<test-unit>, ["= 2.5.0"])
145
+ s.add_dependency(%q<mocha>, ["= 0.12.0"])
146
+ s.add_dependency(%q<jeweler>, ["~> 1.8.5"])
147
+ s.add_dependency(%q<simplecov>, [">= 0"])
148
+ s.add_dependency(%q<webmock>, ["~> 1.9.0"])
149
+ s.add_dependency(%q<vcr>, [">= 0"])
150
+ s.add_dependency(%q<pry>, [">= 0"])
151
+ end
152
+ else
153
+ s.add_dependency(%q<faraday>, [">= 0"])
154
+ s.add_dependency(%q<faraday_middleware>, [">= 0"])
155
+ s.add_dependency(%q<bundler>, [">= 0"])
156
+ s.add_dependency(%q<shoulda>, [">= 0"])
157
+ s.add_dependency(%q<test-unit>, ["= 2.5.0"])
158
+ s.add_dependency(%q<mocha>, ["= 0.12.0"])
159
+ s.add_dependency(%q<jeweler>, ["~> 1.8.5"])
160
+ s.add_dependency(%q<simplecov>, [">= 0"])
161
+ s.add_dependency(%q<webmock>, ["~> 1.9.0"])
162
+ s.add_dependency(%q<vcr>, [">= 0"])
163
+ s.add_dependency(%q<pry>, [">= 0"])
164
+ end
165
+ end
166
+
@@ -0,0 +1,94 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'ostruct'
3
+ module Faraday
4
+ # Catches exceptions and retries each request a limited number of times.
5
+ #
6
+ # By default, it retries 2 times and handles only timeout exceptions. It can
7
+ # be configured with an arbitrary number of retries, a list of exceptions to
8
+ # handle an a retry interval.
9
+ #
10
+ # Examples
11
+ #
12
+ # Faraday.new do |conn|
13
+ # conn.request :retry, max: 2, interval: 0.05,
14
+ # exceptions: [CustomException, 'Timeout::Error']
15
+ # conn.adapter ...
16
+ # end
17
+ class BetterRetry < Faraday::Middleware
18
+ class Options < OpenStruct
19
+
20
+ def max
21
+ (self[:max] ||= 2).to_i
22
+ end
23
+
24
+ def interval
25
+ (self[:interval] ||= 0).to_f
26
+ end
27
+
28
+ def exceptions
29
+ Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error', Error::TimeoutError])
30
+ end
31
+
32
+ # define for ruby less than 2.0
33
+ def [](name)
34
+ @table[name.to_sym]
35
+ end
36
+
37
+ def []=(name, value)
38
+ modifiable[new_ostruct_member(name)] = value
39
+ end
40
+
41
+ end
42
+
43
+ # Public: Initialize middleware
44
+ #
45
+ # Options:
46
+ # max - Maximum number of retries (default: 2).
47
+ # interval - Pause in seconds between retries (default: 0).
48
+ # exceptions - The list of exceptions to handle. Exceptions can be
49
+ # given as Class, Module, or String. (default:
50
+ # [Errno::ETIMEDOUT, Timeout::Error, Error::TimeoutError])
51
+ def initialize(app, options = {})
52
+ super(app)
53
+ @options = Options.new(options)
54
+ @errmatch = build_exception_matcher(@options.exceptions)
55
+ @logger = options[:logger]
56
+ end
57
+
58
+ def call(env)
59
+ env[:retries] = retries = @options.max
60
+ begin
61
+ @app.call(env)
62
+ rescue @errmatch => e
63
+ if retries > 0
64
+ if @logger
65
+ @logger.warn("Retrying Parse Error #{e.inspect} on request #{env[:url].to_s} #{env[:body].inspect} response #{env[:response].inspect}")
66
+ end
67
+ retries -= 1
68
+ env[:retries] = retries
69
+ sleep @options.interval if @options.interval > 0
70
+ retry
71
+ end
72
+ raise
73
+ end
74
+ end
75
+
76
+ # Private: construct an exception matcher object.
77
+ #
78
+ # An exception matcher for the rescue clause can usually be any object that
79
+ # responds to `===`, but for Ruby 1.8 it has to be a Class or Module.
80
+ def build_exception_matcher(exceptions)
81
+ matcher = Module.new
82
+ (class << matcher; self; end).class_eval do
83
+ define_method(:===) do |error|
84
+ exceptions.any? do |ex|
85
+ if ex.is_a? Module then error.is_a? ex
86
+ else error.class.to_s == ex.to_s
87
+ end
88
+ end
89
+ end
90
+ end
91
+ matcher
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,39 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Faraday
3
+
4
+ class ExtendedParseJson < FaradayMiddleware::ParseJson
5
+
6
+ def process_response(env)
7
+ env[:raw_body] = env[:body] if preserve_raw?(env)
8
+
9
+
10
+ if env[:status] >= 400
11
+ data = parse(env[:body]) || {} rescue {}
12
+
13
+ array_codes = [
14
+ AV::Protocol::ERROR_INTERNAL,
15
+ AV::Protocol::ERROR_TIMEOUT,
16
+ AV::Protocol::ERROR_EXCEEDED_BURST_LIMIT
17
+ ]
18
+ error_hash = { "error" => "HTTP Status #{env[:status]} Body #{env[:body]}", "http_status_code" => env[:status] }.merge(data)
19
+ if data['code'] && array_codes.include?(data['code'])
20
+ sleep 60 if data['code'] == AV::Protocol::ERROR_EXCEEDED_BURST_LIMIT
21
+ raise exception(env).new(error_hash.merge(data))
22
+ elsif env[:status] >= 500
23
+ raise exception(env).new(error_hash.merge(data))
24
+ end
25
+ raise AV::AVProtocolError.new(error_hash)
26
+ else
27
+ data = parse(env[:body]) || {}
28
+
29
+ env[:body] = data
30
+ end
31
+ end
32
+
33
+ def exception env
34
+ # decide to retry or not
35
+ (env[:retries].to_i.zero? ? AV::AVProtocolError : AV::AVProtocolRetry)
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'faraday'
4
+
5
+ module Faraday
6
+ # Public: Writes the original HTTP method to "X-Http-Method-Override" header
7
+ # and sends the request as POST for GET requests that are too long.
8
+ class GetMethodOverride < Faraday::Middleware
9
+
10
+ HEADER = "X-Http-Method-Override".freeze
11
+
12
+ # Public: Initialize the middleware.
13
+ #
14
+ # app - the Faraday app to wrap
15
+ def initialize(app, options = nil)
16
+ super(app)
17
+ end
18
+
19
+ def call(env)
20
+ if env[:method] == :get && env[:url].to_s.size > 2000
21
+ env[:request_headers][HEADER] = 'GET'
22
+ env[:request_headers]['Content-Type'] =
23
+ 'application/x-www-form-urlencoded'
24
+ env[:body] = env[:url].query
25
+ env[:url].query = nil
26
+ env[:method] = :post
27
+ end
28
+
29
+ @app.call(env)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding : utf-8 -*-
2
+ ## ----------------------------------------------------------------------
3
+ ##
4
+ ## Ruby client for parse.com
5
+ ## A quick library for playing with parse.com's REST API for object storage.
6
+ ## See https://parse.com/docs/rest for full documentation on the API.
7
+ ##
8
+ ## ----------------------------------------------------------------------
9
+ require 'rubygems'
10
+ require 'bundler/setup'
11
+
12
+ require 'faraday'
13
+ require 'faraday_middleware'
14
+ require 'faraday/better_retry'
15
+ require 'faraday/extended_parse_json'
16
+ require 'faraday/get_method_override'
17
+ require 'date'
18
+ require 'cgi'
19
+
20
+ cwd = Pathname(__FILE__).dirname
21
+ $:.unshift(cwd.to_s) unless $:.include?(cwd.to_s) || $:.include?(cwd.expand_path.to_s)
22
+
23
+ require 'leancloud/object'
24
+ require 'leancloud/query'
25
+ require 'leancloud/datatypes'
26
+ require 'leancloud/util'
27
+ require 'leancloud/protocol'
28
+ require 'leancloud/user'
29
+ require "leancloud/installation"
30
+ require 'leancloud/push'
31
+ require 'leancloud/cloud'
32
+ require 'leancloud/model'
33
+ require 'leancloud/batch'
34
+ require 'leancloud/application'
@@ -0,0 +1,7 @@
1
+ module AV
2
+ class Application
3
+ def self.config
4
+ AV.client.request(AV::Protocol.config_uri)['params']
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,53 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module AV
3
+ class Batch
4
+ attr_reader :requests
5
+ attr_reader :client
6
+
7
+ def initialize(client = AV.client)
8
+ @client = client
9
+ @requests ||= []
10
+ end
11
+
12
+ def add_request(request)
13
+ @requests << request
14
+ end
15
+
16
+ def create_object(object)
17
+ method = "POST"
18
+ path = AV::Protocol.class_uri(object.class_name)
19
+ body = object.safe_hash
20
+ add_request({
21
+ "method" => method,
22
+ "path" => path,
23
+ "body" => body
24
+ })
25
+ end
26
+
27
+ def update_object(object)
28
+ method = "PUT"
29
+ path = AV::Protocol.class_uri(object.class_name, object.id)
30
+ body = object.safe_hash
31
+ add_request({
32
+ "method" => method,
33
+ "path" => path,
34
+ "body" => body
35
+ })
36
+ end
37
+
38
+ def delete_object(object)
39
+ add_request({
40
+ "method" => "DELETE",
41
+ "path" => AV::Protocol.class_uri(object.class_name, object.id)
42
+ })
43
+ end
44
+
45
+ def run!
46
+ uri = AV::Protocol.batch_request_uri
47
+ body = {:requests => @requests}.to_json
48
+ @client.request(uri, :post, body)
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,149 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'leancloud/protocol'
3
+ require 'leancloud/error'
4
+ require 'leancloud/util'
5
+
6
+ require 'logger'
7
+ module AV
8
+
9
+ # A class which encapsulates the HTTPS communication with the Parse
10
+ # API server.
11
+ class Client
12
+ attr_accessor :host
13
+ attr_accessor :application_id
14
+ attr_accessor :api_key
15
+ attr_accessor :master_key
16
+ attr_accessor :session_token
17
+ attr_accessor :session
18
+ attr_accessor :max_retries
19
+ attr_accessor :logger
20
+ attr_accessor :quiet
21
+
22
+ def initialize(data = {}, &blk)
23
+ @host = data[:host] || Protocol::HOST
24
+ @application_id = data[:application_id]
25
+ @api_key = data[:api_key]
26
+ @master_key = data[:master_key]
27
+ @session_token = data[:session_token]
28
+ @max_retries = data[:max_retries] || 3
29
+ @logger = data[:logger] || Logger.new(STDERR).tap{|l| l.level = Logger::INFO}
30
+ @quiet = data[:quiet] || false
31
+
32
+ options = {:request => {:timeout => 30, :open_timeout => 30}}
33
+
34
+ @session = Faraday.new("https://#{host}", options) do |c|
35
+ c.request :json
36
+
37
+ c.use Faraday::GetMethodOverride
38
+
39
+ c.use Faraday::BetterRetry,
40
+ max: @max_retries,
41
+ logger: @logger,
42
+ interval: 0.5,
43
+ exceptions: ['Faraday::Error::TimeoutError', 'Faraday::Error::ParsingError', 'AV::AVProtocolRetry']
44
+ c.use Faraday::ExtendedParseJson
45
+
46
+ c.response :logger, @logger unless @quiet
47
+ c.adapter Faraday.default_adapter
48
+
49
+ yield(c) if block_given?
50
+ end
51
+ end
52
+
53
+ # Perform an HTTP request for the given uri and method
54
+ # with common basic response handling. Will raise a
55
+ # AVProtocolError if the response has an error status code,
56
+ # and will return the parsed JSON body on success, if there is one.
57
+ def request(uri, method = :get, body = nil, query = nil, content_type = nil)
58
+ headers = {}
59
+
60
+ {
61
+ "Content-Type" => content_type || 'application/json',
62
+ "User-Agent" => 'Parse for Ruby, 0.0',
63
+ Protocol::HEADER_MASTER_KEY => @master_key,
64
+ Protocol::HEADER_APP_ID => @application_id,
65
+ Protocol::HEADER_API_KEY => @api_key,
66
+ Protocol::HEADER_SESSION_TOKEN => @session_token,
67
+ }.each do |key, value|
68
+ headers[key] = value if value
69
+ end
70
+
71
+ @session.send(method, uri, query || body || {}, headers).body
72
+ end
73
+
74
+ def get(uri)
75
+ request(uri)
76
+ end
77
+
78
+ def post(uri, body)
79
+ request(uri, :post, body)
80
+ end
81
+
82
+ def put(uri, body)
83
+ request(uri, :put, body)
84
+ end
85
+
86
+ def delete(uri)
87
+ request(uri, :delete)
88
+ end
89
+
90
+ end
91
+
92
+
93
+ # Module methods
94
+ # ------------------------------------------------------------
95
+ class << self
96
+ # A singleton client for use by methods in Object.
97
+ # Always use AV.client to retrieve the client object.
98
+ @client = nil
99
+
100
+ # Initialize the singleton instance of Client which is used
101
+ # by all API methods. AV.init must be called before saving
102
+ # or retrieving any objects.
103
+ def init(data = {}, &blk)
104
+ defaults = {:application_id => ENV["LC_APPLICATION_ID"], :api_key => ENV["LC_APPLICATION_KEY"]}
105
+ defaults.merge!(data)
106
+
107
+ # use less permissive key if both are specified
108
+ defaults[:master_key] = ENV["PARSE_MASTER_API_KEY"] unless data[:master_key] || defaults[:api_key]
109
+ @@client = Client.new(defaults, &blk)
110
+ end
111
+
112
+ # A convenience method for using global.json
113
+ def init_from_cloud_code(path = "../config/global.json")
114
+ # warning: toplevel constant File referenced by AV::Object::File
115
+ global = JSON.parse(Object::File.open(path).read)
116
+ application_name = global["applications"]["_default"]["link"]
117
+ application_id = global["applications"][application_name]["applicationId"]
118
+ master_key = global["applications"][application_name]["masterKey"]
119
+ self.init(:application_id => application_id, :master_key => master_key)
120
+ end
121
+
122
+ # Used mostly for testing. Lets you delete the api key global vars.
123
+ def destroy
124
+ @@client = nil
125
+ self
126
+ end
127
+
128
+ def client
129
+ raise AVError, "API not initialized" if !@@client
130
+ @@client
131
+ end
132
+
133
+ # Perform a simple retrieval of a simple object, or all objects of a
134
+ # given class. If object_id is supplied, a single object will be
135
+ # retrieved. If object_id is not supplied, then all objects of the
136
+ # given class will be retrieved and returned in an Array.
137
+ def get(class_name, object_id = nil)
138
+ data = self.client.get( Protocol.class_uri(class_name, object_id) )
139
+ self.parse_json class_name, data
140
+ rescue AVProtocolError => e
141
+ if e.code == Protocol::ERROR_OBJECT_NOT_FOUND_FOR_GET
142
+ e.message += ": #{class_name}:#{object_id}"
143
+ end
144
+ raise
145
+ end
146
+ end
147
+
148
+ end
149
+