syncano 4.0.0.alpha4 → 4.0.0.pre

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 (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