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,28 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module AV
3
+ module Cloud
4
+
5
+ class Function
6
+ attr_accessor :function_name
7
+
8
+ def initialize(function_name)
9
+ @function_name = function_name
10
+ end
11
+
12
+ def uri
13
+ Protocol.cloud_function_uri(@function_name)
14
+ end
15
+
16
+ def call(params={})
17
+ response = AV.client.post(self.uri, params.to_json)
18
+ result = response["result"]
19
+ result
20
+ end
21
+ end
22
+
23
+ def self.request_sms(params)
24
+ response = AV.client.post("/#{Protocol::VERSION}/requestSmsCode", params.to_json)
25
+ return response == {}
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,355 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'time'
3
+ require 'date'
4
+ require 'base64'
5
+
6
+ module AV
7
+
8
+ # Pointer
9
+ # ------------------------------------------------------------
10
+
11
+ class Pointer
12
+ attr_accessor :parse_object_id
13
+ attr_accessor :class_name
14
+ alias :id :parse_object_id
15
+
16
+ def self.make(class_name, object_id)
17
+ Pointer.new(
18
+ Protocol::KEY_CLASS_NAME => class_name,
19
+ Protocol::KEY_OBJECT_ID => object_id
20
+ )
21
+ end
22
+
23
+ def initialize(data)
24
+ @class_name = data[Protocol::KEY_CLASS_NAME]
25
+ @parse_object_id = data[Protocol::KEY_OBJECT_ID]
26
+ end
27
+
28
+ # make it easier to deal with the ambiguity of whether you're passed a pointer or object
29
+ def pointer
30
+ self
31
+ end
32
+
33
+ def eql?(other)
34
+ AV.object_pointer_equality?(self, other)
35
+ end
36
+
37
+ alias == eql?
38
+
39
+ def hash
40
+ AV.object_pointer_hash(self)
41
+ end
42
+
43
+ def new?
44
+ false
45
+ end
46
+
47
+ def to_h(*a)
48
+ {
49
+ Protocol::KEY_TYPE => Protocol::TYPE_POINTER,
50
+ Protocol::KEY_CLASS_NAME => @class_name,
51
+ Protocol::KEY_OBJECT_ID => @parse_object_id
52
+ }
53
+ end
54
+ alias :as_json :to_h
55
+
56
+ def to_json(*a)
57
+ to_h.to_json(*a)
58
+ end
59
+
60
+ # Retrieve the Parse object referenced by this pointer.
61
+ def get
62
+ AV.get @class_name, @parse_object_id if @parse_object_id
63
+ end
64
+
65
+ def to_s
66
+ "#{@class_name}:#{@parse_object_id}"
67
+ end
68
+ end
69
+
70
+ # Date
71
+ # ------------------------------------------------------------
72
+
73
+ class Date
74
+ attr_accessor :value
75
+
76
+ def initialize(data)
77
+ if data.respond_to?(:iso8601)
78
+ @value = data
79
+ elsif data.is_a? Hash
80
+ @value = DateTime.parse data["iso"]
81
+ elsif data.is_a? String
82
+ @value = DateTime.parse data
83
+ else
84
+ raise "data doesn't act like time #{data.inspect}"
85
+ end
86
+ end
87
+
88
+ def eql?(other)
89
+ self.class.equal?(other.class) &&
90
+ value == other.value
91
+ end
92
+
93
+ alias == eql?
94
+
95
+ def hash
96
+ value.hash
97
+ end
98
+
99
+ def <=>(other)
100
+ value <=> other.value
101
+ end
102
+
103
+ def method_missing(method, *args, &block)
104
+ if value.respond_to?(method)
105
+ value.send(method, *args, &block)
106
+ else
107
+ super(method)
108
+ end
109
+ end
110
+
111
+ def respond_to?(method, include_private = false)
112
+ super || value.respond_to?(method, include_private)
113
+ end
114
+
115
+ def to_h(*a)
116
+ {
117
+ Protocol::KEY_TYPE => Protocol::TYPE_DATE,
118
+ "iso" => value.to_time.utc.iso8601(3)
119
+ }
120
+ end
121
+ alias :as_json :to_h
122
+
123
+ def to_json(*a)
124
+ to_h.to_json(*a)
125
+ end
126
+ end
127
+
128
+ # Bytes
129
+ # ------------------------------------------------------------
130
+
131
+ class Bytes
132
+ attr_accessor :value
133
+
134
+ def initialize(data)
135
+ bytes = data["base64"]
136
+ @value = Base64.decode64(bytes)
137
+ end
138
+
139
+ def eql?(other)
140
+ self.class.equal?(other.class) &&
141
+ value == other.value
142
+ end
143
+
144
+ alias == eql?
145
+
146
+ def hash
147
+ value.hash
148
+ end
149
+
150
+ def <=>(other)
151
+ value <=> other.value
152
+ end
153
+
154
+ def method_missing(method, *args, &block)
155
+ if value.respond_to?(method)
156
+ value.send(method, *args, &block)
157
+ else
158
+ super(method)
159
+ end
160
+ end
161
+
162
+ def respond_to?(method, include_private = false)
163
+ super || value.respond_to?(method, include_private)
164
+ end
165
+
166
+ def to_h(*a)
167
+ {
168
+ Protocol::KEY_TYPE => Protocol::TYPE_BYTES,
169
+ "base64" => Base64.encode64(@value)
170
+ }
171
+ end
172
+ alias :as_json :to_h
173
+
174
+ def to_json(*a)
175
+ to_h.to_json(*a)
176
+ end
177
+ end
178
+
179
+ # Increment and Decrement
180
+ # ------------------------------------------------------------
181
+
182
+ class Increment
183
+ # '{"score": {"__op": "Increment", "amount": 1 } }'
184
+ attr_accessor :amount
185
+
186
+ def initialize(amount)
187
+ @amount = amount
188
+ end
189
+
190
+ def eql?(other)
191
+ self.class.equal?(other.class) &&
192
+ amount == other.amount
193
+ end
194
+
195
+ alias == eql?
196
+
197
+ def hash
198
+ amount.hash
199
+ end
200
+
201
+ def to_h(*a)
202
+ {
203
+ Protocol::KEY_OP => Protocol::KEY_INCREMENT,
204
+ Protocol::KEY_AMOUNT => @amount
205
+ }
206
+ end
207
+ alias :as_json :to_h
208
+
209
+ def to_json(*a)
210
+ to_h.to_json(*a)
211
+ end
212
+ end
213
+
214
+ class ArrayOp
215
+ # '{"myArray": {"__op": "Add", "objects": ["something", "something else"] } }'
216
+ attr_accessor :operation
217
+ attr_accessor :objects
218
+
219
+ def initialize(operation, objects)
220
+ @operation = operation
221
+ @objects = objects
222
+ end
223
+
224
+ def eql?(other)
225
+ self.class.equal?(other.class) &&
226
+ operation == other.operation &&
227
+ objects == other.objects
228
+ end
229
+
230
+ alias == eql?
231
+
232
+ def hash
233
+ operation.hash ^ objects.hash
234
+ end
235
+
236
+ def to_h(*a)
237
+ {
238
+ Protocol::KEY_OP => operation,
239
+ Protocol::KEY_OBJECTS => @objects
240
+ }
241
+ end
242
+ alias :as_json :to_h
243
+
244
+ def to_json(*a)
245
+ to_h.to_json(*a)
246
+ end
247
+ end
248
+
249
+ # GeoPoint
250
+ # ------------------------------------------------------------
251
+
252
+ class GeoPoint
253
+ # '{"location": {"__type":"GeoPoint", "latitude":40.0, "longitude":-30.0}}'
254
+ attr_accessor :longitude, :latitude
255
+
256
+ def initialize(data)
257
+ @longitude = data["longitude"]
258
+ @latitude = data["latitude"]
259
+
260
+ if !@longitude && !@latitude
261
+ @longitude = data[:longitude]
262
+ @latitude = data[:latitude]
263
+ end
264
+ end
265
+
266
+ def eql?(other)
267
+ self.class.equal?(other.class) &&
268
+ longitude == other.longitude &&
269
+ latitude == other.latitude
270
+ end
271
+
272
+ alias == eql?
273
+
274
+ def hash
275
+ longitude.hash ^ latitude.hash
276
+ end
277
+
278
+ def to_h(*a)
279
+ {
280
+ Protocol::KEY_TYPE => Protocol::TYPE_GEOPOINT,
281
+ "latitude" => @latitude,
282
+ "longitude" => @longitude
283
+ }
284
+ end
285
+ alias :as_json :to_h
286
+
287
+ def to_json(*a)
288
+ to_h.to_json(*a)
289
+ end
290
+
291
+ def to_s
292
+ "(#{latitude}, #{longitude})"
293
+ end
294
+ end
295
+
296
+ # File
297
+ # ------------------------------------------------------------
298
+ # tf = AV::File.new(:body => "Hello World!", :local_filename => "hello.txt")
299
+ # tf.save
300
+ class File
301
+ # '{"avatar": {"__type":"File", "name":"profile.png", "url"=>"http://files.parse.com/blah/profile.png"}}'
302
+ attr_accessor :local_filename # eg "hello.txt"
303
+ attr_accessor :parse_filename # eg "12-4-532d-d-g3-3-hello.text"
304
+ attr_accessor :content_type
305
+ attr_accessor :body
306
+ attr_accessor :url
307
+ attr_accessor :id
308
+
309
+ def initialize(data)
310
+ data = Hash[data.map{ |k, v| [k.to_s, v] }] # convert hash keys to strings
311
+ @local_filename = data["local_filename"] if data["local_filename"]
312
+ @parse_filename = data["name"] if data["name"]
313
+ @parse_filename = data["parse_filename"] if data["parse_filename"]
314
+ @content_type = data["content_type"] if data["content_type"]
315
+ @url = data["url"] if data["url"]
316
+ @body = data["body"] if data["body"]
317
+ @id = data["id"] if data["id"]
318
+ end
319
+
320
+ def eql?(other)
321
+ self.class.equal?(other.class) &&
322
+ url == other.url
323
+ end
324
+
325
+ alias == eql?
326
+
327
+ def hash
328
+ url.hash
329
+ end
330
+
331
+ def save
332
+ uri = AV::Protocol.file_uri(@local_filename)
333
+ resp = AV.client.request(uri, :post, @body, nil, @content_type)
334
+ @parse_filename = resp["name"]
335
+ @url = resp["url"]
336
+ @id = resp["id"]
337
+ resp
338
+ end
339
+
340
+ def to_h(*a)
341
+ {
342
+ Protocol::KEY_TYPE => Protocol::TYPE_FILE,
343
+ "name" => @parse_filename,
344
+ "url" => @url,
345
+ "id" => @id
346
+ }
347
+ end
348
+ alias :as_json :to_h
349
+
350
+ def to_json(*a)
351
+ to_h.to_json(*a)
352
+ end
353
+ end
354
+
355
+ end
@@ -0,0 +1,42 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module AV
3
+
4
+ # Base exception class for errors thrown by the Parse
5
+ # client library. AVError will be raised by any
6
+ # network operation if AV.init() has not been called.
7
+ class AVError < StandardError #Exception ... why? A:http://www.skorks.com/2009/09/ruby-exceptions-and-exception-handling/
8
+ end
9
+
10
+ # An exception class raised when the REST API returns an error.
11
+ # The error code and message will be parsed out of the HTTP response,
12
+ # which is also included in the response attribute.
13
+ class AVProtocolError < AVError
14
+ attr_accessor :code
15
+ attr_accessor :error
16
+ attr_accessor :response
17
+ attr_accessor :http_status_code
18
+
19
+ def initialize(response)
20
+ @response = response
21
+ if response
22
+ @code = response["code"]
23
+ @error = response["error"]
24
+ @http_status_code = response["http_status_code"]
25
+ end
26
+
27
+ super("#{@code}: #{@error}")
28
+ end
29
+
30
+ def to_s
31
+ @message || super
32
+ end
33
+
34
+ def message=(msg)
35
+ @message = msg
36
+ end
37
+ end
38
+
39
+ class AVProtocolRetry < AVProtocolError
40
+ end
41
+
42
+ end
@@ -0,0 +1,57 @@
1
+ require 'leancloud/protocol'
2
+ require 'leancloud/client'
3
+ require 'leancloud/error'
4
+ require 'leancloud/object'
5
+
6
+ module AV
7
+ class Installation < AV::Object
8
+ UPDATABLE_FIELDS = {
9
+ badge: 'badge',
10
+ channels: 'channels',
11
+ time_zone: 'timeZone',
12
+ device_token: 'deviceToken',
13
+ channel_uris: 'channelUris',
14
+ app_name: 'appName',
15
+ app_version: 'appVersion',
16
+ parse_version: 'parseVersion',
17
+ app_identifier: 'appIdentifier'
18
+ }
19
+
20
+ def initialize(parse_object_id)
21
+ @parse_object_id = parse_object_id
22
+ end
23
+
24
+ def self.get(parse_object_id)
25
+ new(parse_object_id).get
26
+ end
27
+
28
+ def get
29
+ if response = AV.client.request(uri, :get, nil, nil)
30
+ parse AV.parse_json(nil, response)
31
+ end
32
+ end
33
+
34
+ UPDATABLE_FIELDS.each do |method_name, key|
35
+ define_method "#{method_name}=" do |value|
36
+ self[key] = value
37
+ end
38
+ end
39
+
40
+ def uri
41
+ Protocol.installation_uri @parse_object_id
42
+ end
43
+
44
+ def save
45
+ AV.client.request uri, method, self.to_json, nil
46
+ end
47
+
48
+ def rest_api_hash
49
+ self
50
+ end
51
+
52
+ def method
53
+ @parse_object_id ? :put : :post
54
+ end
55
+
56
+ end
57
+ end