syncano 4.0.0.alpha4 → 4.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/README.md +1 -13
  4. data/circle.yml +1 -1
  5. data/lib/active_attr/dirty.rb +26 -0
  6. data/lib/active_attr/typecasting/hash_typecaster.rb +34 -0
  7. data/lib/active_attr/typecasting_override.rb +29 -0
  8. data/lib/syncano.rb +9 -55
  9. data/lib/syncano/api.rb +2 -20
  10. data/lib/syncano/connection.rb +47 -48
  11. data/lib/syncano/model/associations.rb +121 -0
  12. data/lib/syncano/model/associations/base.rb +38 -0
  13. data/lib/syncano/model/associations/belongs_to.rb +30 -0
  14. data/lib/syncano/model/associations/has_many.rb +75 -0
  15. data/lib/syncano/model/associations/has_one.rb +22 -0
  16. data/lib/syncano/model/base.rb +257 -0
  17. data/lib/syncano/model/callbacks.rb +49 -0
  18. data/lib/syncano/model/scope_builder.rb +158 -0
  19. data/lib/syncano/query_builder.rb +7 -11
  20. data/lib/syncano/resources/base.rb +66 -91
  21. data/lib/syncano/schema.rb +159 -10
  22. data/lib/syncano/schema/attribute_definition.rb +0 -75
  23. data/lib/syncano/schema/resource_definition.rb +2 -24
  24. data/lib/syncano/version.rb +1 -1
  25. data/spec/integration/syncano_spec.rb +26 -268
  26. data/spec/spec_helper.rb +1 -3
  27. data/spec/unit/connection_spec.rb +74 -34
  28. data/spec/unit/query_builder_spec.rb +2 -2
  29. data/spec/unit/resources_base_spec.rb +64 -125
  30. data/spec/unit/schema/resource_definition_spec.rb +3 -24
  31. data/spec/unit/schema_spec.rb +55 -5
  32. data/spec/unit/syncano_spec.rb +9 -45
  33. data/syncano.gemspec +0 -5
  34. metadata +14 -87
  35. data/lib/syncano/api/endpoints.rb +0 -17
  36. data/lib/syncano/poller.rb +0 -55
  37. data/lib/syncano/resources.rb +0 -158
  38. data/lib/syncano/resources/paths.rb +0 -48
  39. data/lib/syncano/resources/resource_invalid.rb +0 -15
  40. data/lib/syncano/response.rb +0 -55
  41. data/lib/syncano/schema/endpoints_whitelist.rb +0 -40
  42. data/lib/syncano/upload_io.rb +0 -7
  43. data/spec/unit/resources/paths_spec.rb +0 -21
  44. data/spec/unit/response_spec.rb +0 -75
  45. data/spec/unit/schema/attribute_definition_spec.rb +0 -18
@@ -1,16 +1,66 @@
1
1
  require_relative '../spec_helper'
2
2
 
3
+
4
+ require 'rspec/expectations'
5
+ require 'active_attr/matchers/have_attribute_matcher'
6
+ require 'shoulda-matchers'
7
+
3
8
  describe Syncano::Schema do
4
- let(:connection) { double 'connection' }
9
+ include ActiveAttr::Matchers
10
+
11
+ let(:connection) { double("connection") }
12
+
13
+ subject { described_class.new connection }
5
14
 
6
15
  before do
7
- expect(connection).to receive(:request).with(:get, described_class.schema_path) { schema }
16
+ expect(connection).to receive(:request).with(:get, described_class::SCHEMA_PATH) { schema }
17
+
18
+ Syncano::Resources.instance_eval do
19
+ constants.each do |const|
20
+ if ![:Base, :Collection, :Space].include?(const) && const_defined?(const)
21
+ remove_const const
22
+ end
23
+ end
24
+ end
8
25
  end
9
26
 
10
- subject { described_class.new(connection) }
27
+ describe 'process!' do
28
+ it 'defintes classes according to the schema' do
29
+ expect { Syncano::Resources::Class }.to raise_error(NameError)
30
+
31
+ subject.process!
32
+
33
+ expect { Syncano::Resources::Class }.to_not raise_error
34
+
35
+ expect(Syncano::Resources::Class).to have_attribute(:name)
36
+ expect(Syncano::Resources::Class).to have_attribute(:status)
37
+ expect(Syncano::Resources::Class).to have_attribute(:created_at)
38
+ expect(Syncano::Resources::Class).to have_attribute(:description)
39
+ expect(Syncano::Resources::Class).to have_attribute(:updated_at)
40
+ expect(Syncano::Resources::Class).to have_attribute(:objects_count)
41
+ expect(Syncano::Resources::Class).to have_attribute(:metadata)
42
+ expect(Syncano::Resources::Class).to have_attribute(:revision)
43
+
44
+ class_instance = Syncano::Resources::Class.new(connection, {}, { links: {} })
45
+
46
+ expect(class_instance).to validate_presence_of(:name)
47
+ expect(class_instance).to validate_length_of(:name).is_at_most(50)
48
+
49
+ expect(class_instance).to respond_to(:objects)
50
+
51
+ code_box_instance = Syncano::Resources::CodeBox.new(connection, {}, { links: {} })
52
+ expect(code_box_instance).to validate_inclusion_of(:runtime_name).
53
+ in_array(%w(nodejs ruby python))
54
+
55
+ end
56
+
57
+ it 'defines foreign keys attributes when attributes names collide with links' do
58
+ subject.process!
59
+
60
+ schedule_instance = Syncano::Resources::Schedule.new connection, {}, links: {}
11
61
 
12
- specify '#resource_definitions' do
13
- expect(subject.definition).to be_kind_of(Hash)
62
+ expect(schedule_instance).to respond_to(:codebox)
63
+ end
14
64
  end
15
65
 
16
66
  def schema
@@ -5,59 +5,23 @@ describe Syncano do
5
5
  describe '#connect' do
6
6
  let(:email) { 'kiszka@koza.com' }
7
7
  let(:password) { 'kiszonka' }
8
- let(:email_options) { { email: email, password: password } }
8
+ let(:options) { { email: email, password: password } }
9
9
  let(:api_key) { 'kozakoza123' }
10
10
 
11
- context 'with credentials in options' do
12
- context 'email and password' do
13
- before do
14
- stub_auth_request
15
- stub_schema_request
16
- end
17
-
18
- specify do
19
- expect(Syncano.connect(email_options)).to be_kind_of(Syncano::API)
20
- end
21
- end
22
-
23
- context 'api key' do
24
- before do
25
- stub_schema_request
26
- end
27
-
28
- specify do
29
- expect(Syncano.connect(api_key: api_key)).to be_kind_of(Syncano::API)
30
- end
31
- end
32
- end
33
-
34
- context 'with credentials in ENV variables' do
35
- before do
36
- @old_api_key = ENV['SYNCANO_API_KEY']
37
- ENV['SYNCANO_API_KEY'] = api_key
38
-
39
- stub_schema_request
40
- end
41
-
42
- after do
43
- ENV['SYNCANO_API_KEY'] = @old_api_key
44
- end
45
-
46
- specify { expect(Syncano.connect).to be_kind_of(Syncano::API) }
47
- end
11
+ before do
12
+ stub_request(:post, endpoint_uri('account/auth/'))
13
+ .with(body: options)
14
+ .to_return(status: 200,
15
+ body: generate_body(id: 15, email: email, first_name: '', last_name: '', account_key: api_key))
48
16
 
49
- def stub_schema_request
50
17
  stub_request(:get, endpoint_uri('schema/'))
51
18
  .with(headers: { 'X-Api-Key' => api_key })
52
19
  .to_return(status: 200, body: generate_body([]))
53
- end
54
20
 
55
- def stub_auth_request
56
- stub_request(:post, endpoint_uri('account/auth/'))
57
- .with(body: email_options)
58
- .to_return(status: 200,
59
- body: generate_body(id: 15, email: email, first_name: '', last_name: '', account_key: api_key))
21
+ expect_any_instance_of(Syncano::Connection)
22
+ .to receive(:authenticated?)
60
23
  end
61
24
 
25
+ specify { expect(Syncano.connect(options)).to be_kind_of(Syncano::API) }
62
26
  end
63
27
  end
@@ -24,9 +24,4 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency 'faraday', '~> 0.9'
25
25
  spec.add_dependency 'activesupport', '>= 4.0'
26
26
  spec.add_dependency 'active_attr', '~> 0.8'
27
- spec.add_dependency 'dirty_hashy', '~> 0.2'
28
- spec.add_dependency 'celluloid'
29
- spec.add_dependency 'celluloid-io'
30
- spec.add_dependency 'mimetype-fu'
31
- spec.add_dependency 'http', '= 0.7.4' # should work with no version constraint once 0.8.2 is released https://github.com/httprb/http.rb/issues/203#issuecomment-100299898
32
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syncano
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.alpha4
4
+ version: 4.0.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Zadrożny
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-04 00:00:00.000000000 Z
12
+ date: 2015-04-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -81,76 +81,6 @@ dependencies:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0.8'
84
- - !ruby/object:Gem::Dependency
85
- name: dirty_hashy
86
- requirement: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - "~>"
89
- - !ruby/object:Gem::Version
90
- version: '0.2'
91
- type: :runtime
92
- prerelease: false
93
- version_requirements: !ruby/object:Gem::Requirement
94
- requirements:
95
- - - "~>"
96
- - !ruby/object:Gem::Version
97
- version: '0.2'
98
- - !ruby/object:Gem::Dependency
99
- name: celluloid
100
- requirement: !ruby/object:Gem::Requirement
101
- requirements:
102
- - - ">="
103
- - !ruby/object:Gem::Version
104
- version: '0'
105
- type: :runtime
106
- prerelease: false
107
- version_requirements: !ruby/object:Gem::Requirement
108
- requirements:
109
- - - ">="
110
- - !ruby/object:Gem::Version
111
- version: '0'
112
- - !ruby/object:Gem::Dependency
113
- name: celluloid-io
114
- requirement: !ruby/object:Gem::Requirement
115
- requirements:
116
- - - ">="
117
- - !ruby/object:Gem::Version
118
- version: '0'
119
- type: :runtime
120
- prerelease: false
121
- version_requirements: !ruby/object:Gem::Requirement
122
- requirements:
123
- - - ">="
124
- - !ruby/object:Gem::Version
125
- version: '0'
126
- - !ruby/object:Gem::Dependency
127
- name: mimetype-fu
128
- requirement: !ruby/object:Gem::Requirement
129
- requirements:
130
- - - ">="
131
- - !ruby/object:Gem::Version
132
- version: '0'
133
- type: :runtime
134
- prerelease: false
135
- version_requirements: !ruby/object:Gem::Requirement
136
- requirements:
137
- - - ">="
138
- - !ruby/object:Gem::Version
139
- version: '0'
140
- - !ruby/object:Gem::Dependency
141
- name: http
142
- requirement: !ruby/object:Gem::Requirement
143
- requirements:
144
- - - '='
145
- - !ruby/object:Gem::Version
146
- version: 0.7.4
147
- type: :runtime
148
- prerelease: false
149
- version_requirements: !ruby/object:Gem::Requirement
150
- requirements:
151
- - - '='
152
- - !ruby/object:Gem::Version
153
- version: 0.7.4
154
84
  description: A Ruby client that provides convenient interface for the Syncano api.
155
85
  email:
156
86
  - piotr.zadrozny@mindpower.pl
@@ -168,25 +98,28 @@ files:
168
98
  - README.md
169
99
  - Rakefile
170
100
  - circle.yml
101
+ - lib/active_attr/dirty.rb
102
+ - lib/active_attr/typecasting/hash_typecaster.rb
103
+ - lib/active_attr/typecasting_override.rb
171
104
  - lib/syncano.rb
172
105
  - lib/syncano/api.rb
173
- - lib/syncano/api/endpoints.rb
174
106
  - lib/syncano/connection.rb
175
- - lib/syncano/poller.rb
107
+ - lib/syncano/model/associations.rb
108
+ - lib/syncano/model/associations/base.rb
109
+ - lib/syncano/model/associations/belongs_to.rb
110
+ - lib/syncano/model/associations/has_many.rb
111
+ - lib/syncano/model/associations/has_one.rb
112
+ - lib/syncano/model/base.rb
113
+ - lib/syncano/model/callbacks.rb
114
+ - lib/syncano/model/scope_builder.rb
176
115
  - lib/syncano/query_builder.rb
177
- - lib/syncano/resources.rb
178
116
  - lib/syncano/resources/base.rb
179
117
  - lib/syncano/resources/collection.rb
180
- - lib/syncano/resources/paths.rb
181
- - lib/syncano/resources/resource_invalid.rb
182
118
  - lib/syncano/resources/space.rb
183
- - lib/syncano/response.rb
184
119
  - lib/syncano/schema.rb
185
120
  - lib/syncano/schema/attribute_definition.rb
186
- - lib/syncano/schema/endpoints_whitelist.rb
187
121
  - lib/syncano/schema/resource_definition.rb
188
122
  - lib/syncano/scope.rb
189
- - lib/syncano/upload_io.rb
190
123
  - lib/syncano/version.rb
191
124
  - spec/integration/syncano_spec.rb
192
125
  - spec/spec_helper.rb
@@ -194,11 +127,8 @@ files:
194
127
  - spec/unit/connection_spec.rb
195
128
  - spec/unit/query_builder_spec.rb
196
129
  - spec/unit/resources/collection_spec.rb
197
- - spec/unit/resources/paths_spec.rb
198
130
  - spec/unit/resources/space_spec.rb
199
131
  - spec/unit/resources_base_spec.rb
200
- - spec/unit/response_spec.rb
201
- - spec/unit/schema/attribute_definition_spec.rb
202
132
  - spec/unit/schema/resource_definition_spec.rb
203
133
  - spec/unit/schema_spec.rb
204
134
  - spec/unit/syncano_spec.rb
@@ -223,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
153
  version: 1.3.1
224
154
  requirements: []
225
155
  rubyforge_project:
226
- rubygems_version: 2.4.5.1
156
+ rubygems_version: 2.2.2
227
157
  signing_key:
228
158
  specification_version: 4
229
159
  summary: A Ruby client library for Syncano 4.0
@@ -234,11 +164,8 @@ test_files:
234
164
  - spec/unit/connection_spec.rb
235
165
  - spec/unit/query_builder_spec.rb
236
166
  - spec/unit/resources/collection_spec.rb
237
- - spec/unit/resources/paths_spec.rb
238
167
  - spec/unit/resources/space_spec.rb
239
168
  - spec/unit/resources_base_spec.rb
240
- - spec/unit/response_spec.rb
241
- - spec/unit/schema/attribute_definition_spec.rb
242
169
  - spec/unit/schema/resource_definition_spec.rb
243
170
  - spec/unit/schema_spec.rb
244
171
  - spec/unit/syncano_spec.rb
@@ -1,17 +0,0 @@
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
@@ -1,55 +0,0 @@
1
- module Syncano
2
- class Poller
3
- include Celluloid::IO
4
-
5
- attr_accessor :connection, :method_name, :path, :responses
6
-
7
-
8
- def initialize(connection, method_name, path)
9
- self.connection = connection
10
- self.method_name = method_name
11
- self.path = path
12
- self.responses = []
13
- end
14
-
15
- def poll
16
- loop do
17
- responses << http_fetcher.get(path)
18
- end
19
- end
20
-
21
- def last_response
22
- responses.last
23
- end
24
-
25
- private
26
-
27
- def http_fetcher
28
- HttpFetcher.new connection.api_key, connection.user_key
29
- end
30
-
31
- class HttpFetcher
32
- attr_accessor :api_key, :user_key
33
-
34
- def initialize(api_key, user_key)
35
- self.api_key = api_key
36
- self.user_key = user_key
37
- end
38
-
39
- def get(path, params = {})
40
- url = Syncano::Connection.api_root + path
41
-
42
- response = HTTP.
43
- with_headers('X-API-KEY' => api_key,
44
- 'X-USER-KEY' => user_key,
45
- 'User-Agent' => "Syncano Ruby Gem #{Syncano::VERSION}").
46
- get(url,
47
- params: params,
48
- ssl_socket_class: Celluloid::IO::SSLSocket,
49
- socket_class: Celluloid::IO::TCPSocket)
50
-
51
- response
52
- end
53
- end
54
- end
55
- end
@@ -1,158 +0,0 @@
1
- require 'dirty_hashy'
2
-
3
- module Syncano
4
- module Resources
5
- class << self
6
- def build_definitions(schema_definition)
7
- schema_definition.map do |name, raw_resource_definition|
8
- ::Syncano::Schema::ResourceDefinition.new(name, raw_resource_definition)
9
- end
10
- end
11
-
12
- def define_resource_class(resource_definition)
13
- resource_class = new_resource_class(resource_definition)
14
-
15
- const_set resource_definition.name, resource_class
16
-
17
- if resource_definition[:collection]
18
- resources_paths.collections.define resource_definition[:collection][:path], resource_class
19
- end
20
-
21
- if resource_definition[:member]
22
- resources_paths.members.define resource_definition[:member][:path], resource_class
23
- end
24
-
25
- resource_class
26
- end
27
-
28
- def resources_paths
29
- ::Syncano::Resources::Paths.instance
30
- end
31
-
32
- def new_resource_class(definition)
33
- attributes_definitions = definition.attributes
34
-
35
- ::Class.new(::Syncano::Resources::Base) do
36
- self.create_writable_attributes = []
37
- self.update_writable_attributes = []
38
-
39
- attributes_definitions.each do |attribute_definition|
40
-
41
- attribute attribute_definition.name,
42
- type: attribute_definition.type,
43
- default: attribute_definition.default
44
-
45
- # TODO extract to a dynamically defined module
46
- define_method("#{attribute_definition.name}=") do |new_value|
47
- if new_value != read_attribute(attribute_definition.name)
48
- send("#{attribute_definition.name}_will_change!")
49
- end
50
-
51
- super new_value
52
- end
53
-
54
- if attribute_definition.validate?
55
- validates attribute_definition.name, presence: true
56
- end
57
-
58
- validates attribute_definition.name, length: attribute_definition.required_length
59
-
60
- if inclusion = attribute_definition.required_values_inclusion
61
- validates attribute_definition.name, inclusion: inclusion
62
- end
63
-
64
- self.create_writable_attributes << attribute_definition.name.to_sym if attribute_definition.writable?
65
- self.update_writable_attributes << attribute_definition.name.to_sym if attribute_definition.updatable?
66
- end
67
-
68
-
69
- if definition.name == 'Object' #TODO: extract to a separate module + spec
70
- def save(options = {})
71
- options.assert_valid_keys :overwrite
72
- overwrite = options[:overwrite] == true
73
-
74
- if new_record? || !overwrite
75
- super()
76
- else
77
- response = connection.request(:post, member_path, attributes)
78
- initialize! response, true
79
- end
80
- end
81
-
82
- def initialize!(_attributes = {}, _from_database = false)
83
- to_return = super
84
-
85
- custom_attributes.clean_up!
86
-
87
- to_return
88
- end
89
-
90
- def select_changed_attributes
91
- custom_attributes.changes.inject(super) do |changed, (key, (_was, is))|
92
- changed[key] = is
93
- changed
94
- end
95
- end
96
-
97
- def attributes=(new_attributes)
98
- super
99
-
100
- self.custom_attributes = new_attributes.select { |k, v| !self.class.attributes.keys.include?(k) }
101
- end
102
-
103
- def attributes
104
- super.merge custom_attributes
105
- end
106
-
107
- def changed
108
- super + custom_attributes.changes.keys
109
- end
110
-
111
- def custom_attributes
112
- @custom_attributes ||= DirtyHashy.new
113
- end
114
-
115
- def custom_attributes=(value)
116
- @custom_attributes = value.is_a?(DirtyHashy) ?
117
- value : DirtyHashy.new(value)
118
- end
119
-
120
- def method_missing(method_name, *args, &block)
121
- if method_name.to_s =~ /=$/
122
- custom_attributes[method_name.to_s.gsub(/=$/, '')] = args.first
123
- else
124
- if custom_attributes.has_key? method_name.to_s
125
- custom_attributes[method_name.to_s]
126
- else
127
- super
128
- end
129
- end
130
- end
131
- end
132
-
133
- (definition[:associations]['links'] || []).each do |association_schema|
134
- case association_schema['type']
135
- when 'list'
136
- define_method(association_schema['name']) do
137
- has_many_association(association_schema['name'])
138
- end
139
- when 'run'
140
- define_method(association_schema['name']) do |config = nil|
141
- custom_method association_schema['name'], config
142
- end
143
- when 'poll'
144
- define_method(association_schema['name']) do |config = nil|
145
- async_method association_schema['name'], config
146
- end
147
- end
148
- end
149
-
150
- private
151
-
152
- self.resource_definition = definition
153
- end
154
- end
155
-
156
- end
157
- end
158
- end