syncano 4.0.0.alpha1 → 4.0.0.alpha2
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.
- checksums.yaml +4 -4
- data/README.md +8 -157
- data/circle.yml +1 -1
- data/lib/syncano.rb +38 -11
- data/lib/syncano/api.rb +20 -2
- data/lib/syncano/api/endpoints.rb +17 -0
- data/lib/syncano/connection.rb +46 -54
- data/lib/syncano/poller.rb +55 -0
- data/lib/syncano/resources.rb +48 -16
- data/lib/syncano/resources/base.rb +46 -56
- data/lib/syncano/resources/paths.rb +48 -0
- data/lib/syncano/resources/resource_invalid.rb +15 -0
- data/lib/syncano/response.rb +55 -0
- data/lib/syncano/schema.rb +10 -29
- data/lib/syncano/schema/attribute_definition.rb +2 -2
- data/lib/syncano/schema/endpoints_whitelist.rb +40 -0
- data/lib/syncano/schema/resource_definition.rb +5 -0
- data/lib/syncano/upload_io.rb +7 -0
- data/lib/syncano/version.rb +1 -1
- data/spec/integration/syncano_spec.rb +220 -15
- data/spec/spec_helper.rb +3 -1
- data/spec/unit/connection_spec.rb +34 -97
- data/spec/unit/resources/paths_spec.rb +21 -0
- data/spec/unit/resources_base_spec.rb +77 -16
- data/spec/unit/response_spec.rb +75 -0
- data/spec/unit/schema/resource_definition_spec.rb +10 -0
- data/spec/unit/schema_spec.rb +5 -55
- data/syncano.gemspec +4 -0
- metadata +69 -13
- data/lib/active_attr/dirty.rb +0 -26
- data/lib/active_attr/typecasting/hash_typecaster.rb +0 -34
- data/lib/active_attr/typecasting_override.rb +0 -29
- data/lib/syncano/model/associations.rb +0 -121
- data/lib/syncano/model/associations/base.rb +0 -38
- data/lib/syncano/model/associations/belongs_to.rb +0 -30
- data/lib/syncano/model/associations/has_many.rb +0 -75
- data/lib/syncano/model/associations/has_one.rb +0 -22
- data/lib/syncano/model/base.rb +0 -257
- data/lib/syncano/model/callbacks.rb +0 -49
- data/lib/syncano/model/scope_builder.rb +0 -158
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd053f463d602ab8927be7cd6f1da7080cd50e03
|
4
|
+
data.tar.gz: 672affd48e958f2387e1e01a3b74e5a8324a95d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35fc5c588f6b5d90a0b8cd318bf9be218a432985cd7703fe0ab98d1f4c9d01838685e2b137f5e39e3bbd6424f72de3f611e654f01c95d31b3b6c86e0f569f8d9
|
7
|
+
data.tar.gz: 7b4373ec897884764c0a70c0ea1a03504eb72d8841dad4f64653b01a47c4c2b1186a9bf16b74b16d3ca067ffbb679d3602b12321a22fdff84a6c8a0f3033f3ba
|
data/README.md
CHANGED
@@ -1,167 +1,18 @@
|
|
1
|
-
# Syncano 4.0
|
1
|
+
# Syncano 4.0 Ruby Gem
|
2
2
|
|
3
|
+
## Ruby QuickStart Guide
|
4
|
+
---
|
3
5
|
|
4
|
-
|
6
|
+
Syncano ruby gem provides communication with Syncano platform - ([www.syncano.io](http://www.syncano.io/?utm_source=github&utm_medium=readme&utm_campaign=syncano-ruby))
|
5
7
|
|
6
|
-
|
8
|
+
You can find quick start on installing and using Syncano's Ruby library in our [documentation](http://docs.syncano.io/docs/ruby/?utm_source=github&utm_medium=readme&utm_campaign=syncano-js).
|
7
9
|
|
8
|
-
|
9
|
-
$ gem install syncano --pre
|
10
|
-
```
|
10
|
+
For more detailed information on how to use Syncano and its features - our [Developer Manual](http://docs.syncano.io/docs/getting-started-with-syncano/?utm_source=github&utm_medium=readme&utm_campaign=syncano-js) should be very helpful.
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
After installation, you have to set a path for api root for syncano.
|
15
|
-
|
16
|
-
If you want to use staging, export:
|
17
|
-
|
18
|
-
```bash
|
19
|
-
$ export API_ROOT=https://api.syncano.rocks
|
20
|
-
```
|
21
|
-
|
22
|
-
If you're less adventurous, use our production api servers:
|
23
|
-
|
24
|
-
```bash
|
25
|
-
$ export=API_ROOT=https://api.syncano.io
|
26
|
-
```
|
27
|
-
|
28
|
-
Ok, now we can start coding!
|
29
|
-
|
30
|
-
```ruby
|
31
|
-
require 'syncano'
|
32
|
-
|
33
|
-
syncano = Syncano.connect(api_key: 'your-api-key')
|
34
|
-
|
35
|
-
syncano.instances.all.each { |instance| puts instance }
|
36
|
-
```
|
37
|
-
|
38
|
-
You can either pass your API key to the connect method as above or set
|
39
|
-
`ENV['SYNCANO_API_KEY']` and call just `Syncano.connect`.
|
40
|
-
|
41
|
-
## API basics
|
42
|
-
|
43
|
-
Syncano API is a nested API - all the endpointes are scoped by an instances, ex.
|
44
|
-
codeboxes path is `/instance/your_instance_name/codeboxes/`. Syncano instances
|
45
|
-
is more less a schema is in relation databases. **Your instance name must be
|
46
|
-
unique across all existing Syncano instnaces, not only limitted to your account.**
|
47
|
-
|
48
|
-
|
49
|
-
# Instances
|
50
|
-
|
51
|
-
In order to do anything with Syncano, you have to create an instances. Choose a
|
52
|
-
globally unique name and call:
|
53
|
-
|
54
|
-
```ruby
|
55
|
-
instances = syncano.instances.create name: 'my_instances_name'
|
56
|
-
instance.first
|
57
|
-
|
58
|
-
#=> #<Syncano::Resources::Instance created_at: Sun, 26 Apr 2015 18:09:46 +0000, description: "", metadata: {}, name: "my_instance_name", owner: nil, role: "full", updated_at: Sun, 26 Apr 2015 18:09:46 +0000>
|
59
|
-
```
|
60
|
-
|
61
|
-
# Classes and objects
|
62
|
-
|
63
|
-
In order to save objects in Syncano, first you need to create a class. A class
|
64
|
-
defines objects' attributes in the class' schema. The attribute definition has two
|
65
|
-
mandatory (`name`, `type`) and two optional fields (`filter_index`, `order_index`).
|
66
|
-
What these fields are for is rather obvious - `name` defines objects' attribute
|
67
|
-
name, and `type` defines type (you can read more about available types in the
|
68
|
-
[API docs](http://docs.syncano.com/v0.1/docs/instancesinstanceclasses-2)). `*_index`
|
69
|
-
fields are indexing. `order_index` allows you order returned collections,
|
70
|
-
`filter_index` allows filtering in a various ways. There will be a few examples
|
71
|
-
in this README, but you can read in the
|
72
|
-
[API docs](http://docs.syncano.com/v0.1/docs/filtering-data-objects).
|
73
|
-
|
74
|
-
```ruby
|
75
|
-
stock = instance.classes.create name: 'stock_items',
|
76
|
-
schema: [{ name: 'name', type: 'string',
|
77
|
-
filter_index: true },
|
78
|
-
{ name: 'amount', type: 'integer',
|
79
|
-
filter_index: true,
|
80
|
-
order_index: true }]
|
81
|
-
```
|
82
|
-
|
83
|
-
Once we have a class, we can start creating objects.
|
84
|
-
|
85
|
-
```ruby
|
86
|
-
chorizo = stock.objects.create name: 'Chorizo', amount: 100
|
87
|
-
black_pudding = stock.objects.create name: 'Black pudding', amount: 200
|
88
|
-
curry_wurts = stock.objects.create name: 'Curry wurst', amount: 150
|
89
|
-
kabanos = stock.objects.create name: 'Kabanos'
|
90
|
-
something = stock.objects.create amount: 3
|
91
|
-
```
|
92
|
-
|
93
|
-
Now we have a few items in stock, let's try filtering.
|
94
|
-
|
95
|
-
```ruby
|
96
|
-
stock.objects.all(order_by: '-amount', query: { amount: { _lte: 150 }, name: { _exists: true } })
|
97
|
-
#=> #<Syncano::Resources::Collection:0x007fc18b9c7698 @next=false, @prev=false, @collection=[#<Syncano::Resources::Object amount: 150, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:21:31 +0000, group: nil, group_permissions: "none", id: 12, name: "Curry wurst", other_permissions: "none", owner: nil, owner_permissions: "none", revision: 1, updated_at: Mon, 27 Apr 2015 05:21:31 +0000>, #<Syncano::Resources::Object amount: 100, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:21:30 +0000, group: nil, group_permissions: "none", id: 10, name: "Chorizo", other_permissions: "none", owner: nil, owner_permissions: "none", revision: 1, updated_at: Mon, 27 Apr 2015 05:21:30 +0000>]>
|
98
|
-
```
|
99
|
-
|
100
|
-
Let's give `something` a name and try again.
|
101
|
-
|
102
|
-
```ruby
|
103
|
-
something.name = 'Unidentified sausage'
|
104
|
-
something.save
|
105
|
-
|
106
|
-
stock.objects.all(order_by: '-amount', query: { amount: { _lte: 150 }, name: { _exists: true } })
|
107
|
-
#=> #<Syncano::Resources::Collection:0x007fc18d58a628 @next=false, @prev=false, @collection=[#<Syncano::Resources::Object amount: 150, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:21:31 +0000, group: nil, group_permissions: \"none\", id: 12, name: \"Curry wurst\", other_permissions: \"none\", owner: nil, owner_permissions: \"none\", revision: 1, updated_at: Mon, 27 Apr 2015 05:21:31 +0000>, #<Syncano::Resources::Object amount: 100, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:21:30 +0000, group: nil, group_permissions: \"none\", id: 10, name: \"Chorizo\", other_permissions: \"none\", owner: nil, owner_permissions: \"none\", revision: 1, updated_at: Mon, 27 Apr 2015 05:21:30 +0000>, #<Syncano::Resources::Object amount: 3, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:30:18 +0000, group: nil, group_permissions: \"none\", id: 15, name: \"Unidentified sausage\", other_permissions: \"none\", owner: nil, owner_permissions: \"none\", revision: 2, updated_at: Mon, 27 Apr 2015 05:30:48 +0000>]>
|
108
|
-
```
|
109
|
-
|
110
|
-
Now it matches the query and appears in the result.
|
111
|
-
|
112
|
-
# Codeboxes
|
113
|
-
|
114
|
-
Codeboxes are small pieces of code that run on Syncano servers. You can run them
|
115
|
-
manually using the API, you can create a schedule to run them periodically, you
|
116
|
-
can create a Webhook (and optionally make it public) to run them from the web,
|
117
|
-
you can create a trigger to run one after a class' object is created, updated or
|
118
|
-
deleted. There are three runtimes available: Ruby, Python and Node. This gem is
|
119
|
-
available in Ruby runtime (just needs to be required). Let's create a simple
|
120
|
-
codebox and run it.
|
121
|
-
|
122
|
-
```ruby
|
123
|
-
clock = instance.codeboxes.create(name: 'clock', source: 'puts Time.now', runtime_name: 'ruby')
|
124
|
-
#=> #<Syncano::Resources::CodeBox config: {}, created_at: Thu, 30 Apr 2015 05:50:09 +0000, description: "", id: 1, name: "clock", runtime_name: "ruby", source: "puts Time.now", updated_at: Thu, 30 Apr 2015 05:50:09 +0000>
|
125
|
-
clock.run
|
126
|
-
#=> {"status"=>"pending", "links"=>{"self"=>"gv1/instances/a523b7e842dea927d8c306ec0a9a7a4ac30191c2cd034b11d/codeboxes/1/traces/1/"}, "executed_at"=>nil, "result"=>"", "duration"=>nil, "id"=>1}
|
127
|
-
```
|
128
|
-
|
129
|
-
When you schedule a codebox run, it returns the trace. Immediately after the
|
130
|
-
call it's status is pending, so you need to check the trace.
|
131
|
-
|
132
|
-
```ruby
|
133
|
-
clock.traces.first
|
134
|
-
=> #<Syncano::Resources::CodeBoxTrace duration: 526, executed_at: Thu, 30 Apr 2015 05:25:14 +0000, id: 1, result: "2015-04-30 05:25:14 +0000", status: "success">
|
135
|
-
```
|
136
|
-
|
137
|
-
The run method is asynchronous and returns immediately. You should use this to
|
138
|
-
run codeboxes when you don't care about results at this very moment. If you
|
139
|
-
want to run the codebox and get results in one call, you should use webhooks.
|
140
|
-
|
141
|
-
# Webhooks
|
142
|
-
|
143
|
-
You can use webhooks to run codeboxes synchronously. Webhooks can be either
|
144
|
-
public or private. You have to provide your API key when calling private ones,
|
145
|
-
public are public, you can call them with curl, connect with third party
|
146
|
-
services, etc. Ruby:
|
147
|
-
|
148
|
-
|
149
|
-
```ruby
|
150
|
-
webhook = @instance.webhooks.create slug: 'clock-webhook', codebox: clock.primary_key, public: true
|
151
|
-
#=> #<Syncano::Resources::Webhook codebox: 1, public: true, public_link: "a20b0ae122b53b2f2c445f6a7a202b274c3631ad", slug: "clock-webhook">
|
152
|
-
|
153
|
-
webhook.run['result']
|
154
|
-
#=> "2015-04-30 05:51:45 +0000"
|
155
|
-
```
|
156
|
-
|
157
|
-
and curl
|
158
|
-
|
159
|
-
```bash
|
160
|
-
$ curl "https://api.syncano.rocks/v1/instances//af248d3e8b92e6e7aaa42dfc41de80c66c90d620cbe3fcd19/webhooks/p/a20b0ae122b53b2f2c445f6a7a202b274c3631ad/"
|
161
|
-
{"status": "success", "duration": 270, "result": "2015-04-30 06:11:08 +0000", "executed_at": "2015-04-30T06:11:08.607389Z"}
|
162
|
-
```
|
12
|
+
In case you need help working with the library - email us at libraries@syncano.com - we will be happy to help!
|
163
13
|
|
164
14
|
## Contributing
|
15
|
+
---
|
165
16
|
|
166
17
|
1. Fork it
|
167
18
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
data/circle.yml
CHANGED
data/lib/syncano.rb
CHANGED
@@ -1,30 +1,42 @@
|
|
1
1
|
$: << Dir.pwd
|
2
2
|
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require 'active_attr/typecasting_override'
|
7
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
3
|
+
require 'active_attr'
|
4
|
+
require 'active_model'
|
5
|
+
require 'active_support/concern'
|
8
6
|
require 'active_support/core_ext/class/attribute.rb'
|
7
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
9
8
|
require 'active_support/inflector'
|
9
|
+
require 'celluloid/future'
|
10
|
+
require 'celluloid/io'
|
11
|
+
require 'faraday'
|
12
|
+
require 'http'
|
13
|
+
require 'yaml'
|
14
|
+
require 'mimetype_fu'
|
15
|
+
|
16
|
+
require 'syncano/query_builder'
|
10
17
|
require 'syncano/version'
|
11
18
|
require 'syncano/api'
|
19
|
+
require 'syncano/api/endpoints'
|
12
20
|
require 'syncano/connection'
|
13
21
|
require 'syncano/schema'
|
14
22
|
require 'syncano/scope'
|
23
|
+
require 'syncano/poller'
|
15
24
|
require 'syncano/resources'
|
16
25
|
require 'syncano/resources/base'
|
17
26
|
require 'syncano/resources/collection'
|
27
|
+
require 'syncano/resources/paths'
|
28
|
+
require 'syncano/resources/resource_invalid'
|
18
29
|
require 'syncano/resources/space'
|
30
|
+
require 'syncano/response'
|
31
|
+
require 'syncano/upload_io'
|
19
32
|
require 'syncano/query_builder'
|
20
|
-
require 'syncano/model/base'
|
21
33
|
|
22
34
|
module Syncano
|
23
35
|
class << self
|
24
36
|
def connect(options = {})
|
25
37
|
connection = Connection.new(
|
26
38
|
options.reverse_merge(api_key: ENV['SYNCANO_API_KEY']))
|
27
|
-
connection.authenticate
|
39
|
+
connection.authenticate unless connection.authenticated?
|
28
40
|
|
29
41
|
API.new connection
|
30
42
|
end
|
@@ -35,6 +47,23 @@ module Syncano
|
|
35
47
|
class RuntimeError < StandardError; end
|
36
48
|
|
37
49
|
class HTTPError < StandardError
|
50
|
+
end
|
51
|
+
|
52
|
+
class NotFound < HTTPError
|
53
|
+
attr_accessor :path, :method_name
|
54
|
+
|
55
|
+
def initialize(path, method_name)
|
56
|
+
self.path = path
|
57
|
+
self.method_name = method_name
|
58
|
+
end
|
59
|
+
|
60
|
+
def inspect
|
61
|
+
%{#{self.class.name} path: "#{path}" method: "#{method_name}"}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class HTTPErrorWithBody < HTTPError
|
66
|
+
|
38
67
|
attr_accessor :body, :original_response
|
39
68
|
|
40
69
|
def initialize(body, original_response)
|
@@ -49,8 +78,8 @@ module Syncano
|
|
49
78
|
alias :to_s :inspect
|
50
79
|
end
|
51
80
|
|
52
|
-
class ClientError <
|
53
|
-
class ServerError <
|
81
|
+
class ClientError < HTTPErrorWithBody; end
|
82
|
+
class ServerError < HTTPErrorWithBody; end
|
54
83
|
|
55
84
|
class UnsupportedStatusError < StandardError
|
56
85
|
attr_accessor :original_response
|
@@ -62,7 +91,5 @@ module Syncano
|
|
62
91
|
def inspect
|
63
92
|
"The server returned unsupported status code #{original_response.status}"
|
64
93
|
end
|
65
|
-
|
66
|
-
alias :to_s :inspect
|
67
94
|
end
|
68
95
|
end
|
data/lib/syncano/api.rb
CHANGED
@@ -1,13 +1,31 @@
|
|
1
1
|
module Syncano
|
2
2
|
class API
|
3
|
+
|
3
4
|
def initialize(connection)
|
4
5
|
self.connection = connection
|
5
|
-
|
6
|
-
|
6
|
+
|
7
|
+
self.class.initialize(connection) unless self.class.initialized?
|
8
|
+
end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def initialize(connection)
|
12
|
+
endpoints = Schema::EndpointsWhitelist.new(Schema.new(connection))
|
13
|
+
|
14
|
+
resources_definitions = Resources.build_definitions(endpoints)
|
15
|
+
|
16
|
+
include Syncano::API::Endpoints.definition(resources_definitions)
|
17
|
+
|
18
|
+
self.initialized = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialized?
|
22
|
+
initialized
|
23
|
+
end
|
7
24
|
end
|
8
25
|
|
9
26
|
private
|
10
27
|
|
11
28
|
attr_accessor :connection
|
29
|
+
cattr_accessor :initialized
|
12
30
|
end
|
13
31
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Syncano
|
2
|
+
class API
|
3
|
+
module Endpoints
|
4
|
+
def self.definition(resources_definition)
|
5
|
+
Module.new do
|
6
|
+
resources_definition.each do |resource_definition|
|
7
|
+
resource_class = ::Syncano::Resources.define_resource_class(resource_definition)
|
8
|
+
|
9
|
+
define_method(resource_definition.name.tableize) do
|
10
|
+
::Syncano::QueryBuilder.new(connection, resource_class)
|
11
|
+
end if resource_definition.top_level?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/syncano/connection.rb
CHANGED
@@ -6,89 +6,81 @@ module Syncano
|
|
6
6
|
AUTH_PATH = 'account/auth/'
|
7
7
|
METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options]
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
attr_accessor :api_key
|
10
|
+
attr_accessor :user_key
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def api_root
|
14
|
+
ENV['API_ROOT']
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def http_fetcher
|
19
|
+
HttpFetcher.new api_key, user_key
|
11
20
|
end
|
12
21
|
|
13
22
|
def initialize(options = {})
|
14
23
|
self.api_key = options[:api_key]
|
15
24
|
self.email = options[:email]
|
16
25
|
self.password = options[:password]
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
26
|
+
self.user_key = options[:user_key]
|
27
|
+
self.conn = Faraday.new(self.class.api_root) do |faraday|
|
28
|
+
faraday.path_prefix = API_VERSION
|
29
|
+
faraday.request :multipart
|
30
|
+
faraday.request :url_encoded
|
31
|
+
faraday.adapter Faraday.default_adapter
|
32
|
+
end
|
22
33
|
end
|
23
34
|
|
24
35
|
def authenticated?
|
25
36
|
!api_key.nil?
|
26
37
|
end
|
27
38
|
|
28
|
-
def authenticate
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def authenticate!
|
35
|
-
response = conn.post(AUTH_PATH, email: email, password: password)
|
36
|
-
body = parse_response(response)
|
37
|
-
|
38
|
-
case response
|
39
|
-
when Status.successful
|
40
|
-
self.api_key = body['account_key']
|
41
|
-
when Status.client_error
|
42
|
-
raise ClientError.new(body, response)
|
43
|
-
end
|
39
|
+
def authenticate
|
40
|
+
api_key = request(:post, AUTH_PATH,
|
41
|
+
email: email,
|
42
|
+
password: password)['account_key']
|
43
|
+
self.api_key = api_key
|
44
44
|
end
|
45
45
|
|
46
46
|
def request(method, path, params = {})
|
47
47
|
raise %{Unsupported method "#{method}"} unless METHODS.include? method
|
48
|
-
|
48
|
+
|
49
|
+
conn.headers['X-API-KEY'] = api_key if api_key
|
50
|
+
conn.headers['X-USER-KEY'] = user_key if user_key
|
49
51
|
conn.headers['User-Agent'] = "Syncano Ruby Gem #{Syncano::VERSION}"
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
when Status.successful
|
55
|
-
parse_response response
|
56
|
-
when Status.client_error # TODO figure out if we want to raise an exception on not found or not
|
57
|
-
raise ClientError.new(response.body, response)
|
58
|
-
when Status.server_error
|
59
|
-
raise ServerError.new(response.body, response)
|
60
|
-
else
|
61
|
-
raise UnsupportedStatusError.new(response)
|
62
|
-
end
|
52
|
+
|
53
|
+
raw_response = conn.send(method, path, params)
|
54
|
+
|
55
|
+
Syncano::Response.handle ResponseWrapper.new(raw_response)
|
63
56
|
end
|
64
57
|
|
65
58
|
private
|
66
59
|
|
67
|
-
|
68
|
-
|
69
|
-
|
60
|
+
class ResponseWrapper < BasicObject
|
61
|
+
def initialize(response)
|
62
|
+
@response = response
|
63
|
+
end
|
70
64
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
->(response) { (200...300).include? response.status }
|
75
|
-
end
|
65
|
+
def method_missing(name, *args, &block)
|
66
|
+
@response.__send__(name, *args, &block)
|
67
|
+
end
|
76
68
|
|
77
|
-
|
78
|
-
|
79
|
-
|
69
|
+
def status
|
70
|
+
Status.new @response.status
|
71
|
+
end
|
80
72
|
|
81
|
-
|
82
|
-
|
83
|
-
|
73
|
+
private
|
74
|
+
|
75
|
+
class Status
|
76
|
+
attr_accessor :code
|
84
77
|
|
85
|
-
def
|
86
|
-
|
78
|
+
def initialize(code)
|
79
|
+
self.code = code
|
87
80
|
end
|
88
81
|
end
|
89
82
|
end
|
90
83
|
|
91
|
-
attr_accessor :api_key
|
92
84
|
attr_accessor :api_root
|
93
85
|
attr_accessor :email
|
94
86
|
attr_accessor :password
|