unimatrix 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 419fc23c152348a645ce538df4c42e539761aca5
4
+ data.tar.gz: faa1871bb56b866c0f8d0fd3d78a4a70a868c4c1
5
+ SHA512:
6
+ metadata.gz: f8d3a342aa86af8e387401e9a3a841de8ce40631245fecb7eee4108480d2b668644d1ba5845f2bfe2c2d6370b671b96cb55ddc2d41b16b46c1335215f131d8ab
7
+ data.tar.gz: 7645ea8566f554c0ba966cf97ae03486f843b059272a08cd8629bfa5ed416a2ce45e3b72adfab7f26531c1c4d9ffca85a805f9defd1f922f722357f3fdc7990d
data/lib/unimatrix.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'active_support'
2
+ require 'active_support/all'
3
+ require 'fnv'
4
+
5
+ require 'unimatrix/version'
6
+
7
+ require 'unimatrix/configuration'
8
+ require 'unimatrix/operation'
9
+ require 'unimatrix/parser'
10
+ require 'unimatrix/request'
11
+ require 'unimatrix/response'
12
+ require 'unimatrix/serializer'
13
+
14
+ require 'unimatrix/resource'
15
+ require 'unimatrix/dynamic_resource'
16
+ require 'unimatrix/realm'
17
+
18
+ require 'unimatrix/error'
19
+ require 'unimatrix/attribute_error'
20
+ require 'unimatrix/bad_request_error'
21
+
22
+ # errors
23
+ require 'unimatrix/error'
24
+ require 'unimatrix/attribute_error'
25
+ require 'unimatrix/bad_request_error'
26
+
27
+ # activist
28
+ require 'unimatrix/activist/task'
29
+ require 'unimatrix/activist/activity'
30
+
31
+ # archivist
32
+ require 'unimatrix/archivist/artifact'
33
+ require 'unimatrix/archivist/artifact_locator'
34
+ require 'unimatrix/archivist/artifact_relationship'
35
+ require 'unimatrix/archivist/blueprint'
36
+ require 'unimatrix/archivist/blueprint_attribute'
37
+ require 'unimatrix/archivist/component'
38
+
39
+ # distributor
40
+ require 'unimatrix/distributor/destination'
41
+ require 'unimatrix/distributor/distribution'
42
+
@@ -0,0 +1,27 @@
1
+ module Unimatrix::Activist
2
+
3
+ class Activity < Unimatrix::DynamicResource
4
+
5
+ field :id
6
+ field :type_name
7
+ field :artifact_uuid
8
+ field :subject_uuid
9
+ field :subject_type
10
+ field :state
11
+ field :uuid
12
+ field :message
13
+ field :properties
14
+ field :completed_at
15
+ field :destroyed_at
16
+ field :created_at
17
+ field :updated_at
18
+ field :execute_at
19
+ field :expire_at
20
+ field :activities_schedule_id
21
+
22
+ has_many :tasks
23
+ has_one :realm
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,23 @@
1
+ module Unimatrix::Activist
2
+
3
+ class Task < Unimatrix::DynamicResource
4
+
5
+ field :id
6
+ field :type_name
7
+ field :subject_uuid
8
+ field :activity_uuid
9
+ field :subject_type
10
+ field :state
11
+ field :message
12
+ field :properties
13
+ field :execute_at
14
+ field :started_at
15
+ field :ended_at
16
+ field :created_at
17
+ field :updated_at
18
+
19
+ has_one :activity
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,34 @@
1
+ module Unimatrix::Archivist
2
+
3
+ class Artifact < Unimatrix::DynamicResource
4
+
5
+ field :id
6
+ field :creator_uuid
7
+ field :picture_uuid
8
+ field :provider
9
+ field :provider_uid
10
+ field :provider_url
11
+ field :description
12
+ field :short_description
13
+ field :short_name
14
+ field :originated_at
15
+ field :destroyed_at
16
+ field :slug
17
+ field :note
18
+ field :type_name
19
+ field :language
20
+ field :uuid
21
+ field :realm_uuid
22
+ field :component_uuids
23
+ field relationships: [ :category ]
24
+ field :name
25
+ field :created_at
26
+ field :updated_at
27
+
28
+ has_many :artifact_locators
29
+ has_many :artifact_relationships
30
+ has_many :errors
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,22 @@
1
+ module Unimatrix::Archivist
2
+
3
+ class ArtifactLocator < Unimatrix::DynamicResource
4
+
5
+ field :id
6
+ field :uuid
7
+ field :provider
8
+ field :type_name
9
+ field :realm_uuid
10
+ field :created_at
11
+ field :updated_at
12
+ field :artifact_uuid
13
+ field :provider_url
14
+ field :provider_uid
15
+ field :destroyed_at
16
+
17
+ has_one :artifact
18
+ has_many :errors
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,17 @@
1
+ module Unimatrix::Archivist
2
+
3
+ class ArtifactRelationship < Unimatrix::DynamicResource
4
+
5
+ field :id
6
+ field :uuid
7
+ field :realm_uuid
8
+ field :name
9
+ field :type_name
10
+ field :artifact_uuid
11
+
12
+ has_one :artifact
13
+ has_many :errors
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,20 @@
1
+ module Unimatrix::Archivist
2
+
3
+ class Blueprint < Unimatrix::DynamicResource
4
+
5
+ field :id
6
+ field :uuid
7
+ field :realm_uuid
8
+ field :type_name
9
+ field :name
10
+ field :resource_class_name
11
+ field :resource_type_name
12
+ field :created_at
13
+ field :updated_at
14
+
15
+ has_many :blueprint_attributes
16
+ has_many :errors
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,34 @@
1
+ module Unimatrix::Archivist
2
+
3
+ class Blueprint < Unimatrix::DynamicResource
4
+
5
+ field :id
6
+ field :uuid
7
+ field :realm_uuid
8
+ field :blueprint_uuid
9
+ field :name
10
+ field :readable
11
+ field :writable
12
+ field :type
13
+ field :validates_uniqueness
14
+ field :validates_uniqueness_scope
15
+ field :validates_presence
16
+ field :validates_absence
17
+ field :validates_format_with
18
+ field :validates_format_without
19
+ field :validates_length_minimum
20
+ field :validates_length_maximum
21
+ field :validates_in
22
+ field :validates_not_in
23
+ field :validates_numeric
24
+ field :validates_numeric_integer
25
+ field :validates_numeric_minimum
26
+ field :validates_numeric_maximum
27
+ field :validates_type
28
+ field :created_at
29
+ field :updated_at
30
+
31
+ has_many :errors
32
+
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ module Unimatrix::Archivist
2
+
3
+ class Component < Unimatrix::DynamicResource
4
+
5
+ field :id
6
+ field :uuid
7
+ field :realm_uuid
8
+ field :type_name
9
+ field :created_at
10
+ field :updated_at
11
+
12
+ has_one :artifact
13
+ has_many :errors
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,7 @@
1
+ module Unimatrix
2
+
3
+ class AttributeError < Error
4
+ field :attribute
5
+ end
6
+
7
+ end
@@ -0,0 +1,6 @@
1
+ module Unimatrix
2
+
3
+ class BadRequestError < Error
4
+ end
5
+
6
+ end
@@ -0,0 +1,32 @@
1
+ require 'singleton'
2
+
3
+ module Unimatrix
4
+
5
+ def self.configuration( &block )
6
+ Configuration.instance().instance_eval( &block ) unless block.nil?
7
+ Configuration.instance()
8
+ end
9
+
10
+ class Configuration
11
+ include Singleton
12
+
13
+ def self.field( field_name, options={} )
14
+ class_eval(
15
+ "def #{ field_name }( *arguments ); " +
16
+ "@#{ field_name } = arguments.first unless arguments.empty?; " +
17
+ "@#{ field_name } || " +
18
+ ( options[ :default ].nil? ?
19
+ "nil" :
20
+ ( options[ :default ].is_a?( String ) ?
21
+ "'#{ options[ :default ] }'" :
22
+ "#{ options[ :default ] }" ) ) + ";" +
23
+ "end",
24
+ __FILE__,
25
+ __LINE__
26
+ )
27
+ end
28
+
29
+ field :url, default: ENV[ 'UNIMATRIX_API_URL' ]
30
+ end
31
+
32
+ end
@@ -0,0 +1,21 @@
1
+ module Unimatrix::Distributor
2
+
3
+ class ActivityReference < Unimatrix::DynamicResource
4
+ field :id
5
+ field :type_name
6
+ field :subject_uuid
7
+ field :subject_type
8
+ field :state
9
+ field :message
10
+ field :properties
11
+ field :distribution_uuid
12
+ field :completed_at
13
+ field :destroyed_at
14
+ field :created_at
15
+ field :updated_at
16
+ field :execute_at
17
+
18
+ has_one :realm
19
+ end
20
+
21
+ end
@@ -0,0 +1,15 @@
1
+ module Unimatrix::Distributor
2
+
3
+ class Destination < Unimatrix::DynamicResource
4
+ field :id
5
+ field :uuid
6
+ field :realm_uuid
7
+ field :type_name
8
+ field :created_at
9
+ field :updated_at
10
+ field :destroyed_at
11
+
12
+ has_one :realm
13
+ end
14
+
15
+ end
@@ -0,0 +1,23 @@
1
+ module Unimatrix::Distributor
2
+
3
+ class Distribution < Unimatrix::DynamicResource
4
+ field :id
5
+ field :uuid
6
+ field :realm_uuid
7
+ field :type_name
8
+ field :state
9
+ field :message
10
+ field :properties
11
+ field :artifact_uuid
12
+ field :add_at
13
+ field :added_at
14
+ field :change_at
15
+ field :changed_at
16
+ field :remove_at
17
+ field :removed_at
18
+
19
+ has_many :activities
20
+ has_one :realm
21
+ end
22
+
23
+ end
@@ -0,0 +1,40 @@
1
+ module Unimatrix
2
+
3
+ class DynamicResource < Resource
4
+
5
+ class << self
6
+
7
+ alias old_new new
8
+
9
+ def new( attributes = {}, associations = {} )
10
+ Class.new( self ).old_new(
11
+ { type_name: self.name.split( '::' ).last.underscore }.
12
+ merge( attributes ),
13
+ associations
14
+ )
15
+ end
16
+
17
+ end
18
+
19
+ def initialize( attributes = {}, associations = {} )
20
+
21
+ unsupported_attributes_names = []
22
+ attributes.each do | key, value |
23
+ unsupported_attributes_names << key.to_sym \
24
+ unless self.respond_to?( key.to_sym )
25
+ end
26
+
27
+ self.class_eval do
28
+ unsupported_attributes_names.each do | name |
29
+ field name
30
+ end
31
+ end
32
+
33
+ super( attributes, associations )
34
+ yield self if block_given?
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,8 @@
1
+ module Unimatrix
2
+
3
+ class Error < Resource
4
+ field :code
5
+ field :message
6
+ end
7
+
8
+ end
@@ -0,0 +1,143 @@
1
+ module Unimatrix
2
+
3
+ class Operation
4
+
5
+ def initialize( path, parameters = {} )
6
+ @path = path
7
+ @parameters = ( parameters || {} ).deep_dup
8
+ @key = nil
9
+ end
10
+
11
+ def key
12
+ return @key ||= begin
13
+ result = 0
14
+ query = @parameters.to_param
15
+ if ( @path.present? || @query.present? )
16
+ query = query.split( '&' ).sort.join( '&' )
17
+ addressable = Addressable::URI.new
18
+ addressable.path = @path
19
+ addressable.query = query unless query.blank?
20
+ result = FNV.new.fnv1a_32( addressable.to_s )
21
+ end
22
+ result
23
+ end
24
+ end
25
+
26
+ def where( parameters )
27
+ self.spawn( parameters )
28
+ end
29
+
30
+ def destroy
31
+ result = nil
32
+ Request.new.tap do | request |
33
+ response = request.destroy( @path, @parameters )
34
+ if response.present?
35
+ result = response.resources
36
+ end
37
+ end
38
+ result
39
+ end
40
+
41
+ def limit( _limit )
42
+ self.spawn( count: _limit )
43
+ end
44
+
45
+ def offset( _offset )
46
+ self.spawn( offset: _offset )
47
+ end
48
+
49
+ def include( *arguments )
50
+ self.spawn( :include => self.normalize_include( *arguments ) )
51
+ end
52
+
53
+ def query( &block )
54
+ result = nil
55
+ Request.new.tap do | request |
56
+ request.get( @path, @parameters ).tap do | response |
57
+ result = response.resources
58
+ if block_given?
59
+ case block.arity
60
+ when 0; yield
61
+ when 1; yield result
62
+ when 2; yield result, response
63
+ end
64
+ end
65
+ end
66
+ end
67
+ result
68
+ end
69
+
70
+ def read( &block )
71
+ response = nil
72
+ result = nil
73
+ self.query do | _result, _response |
74
+ result = _result
75
+ response = _response
76
+ end
77
+ if response.success?
78
+ result = result if result.present? && result.is_a?( Array )
79
+ if block_given?
80
+ case block.arity
81
+ when 0; yield
82
+ when 1; yield result
83
+ when 2; yield result, response
84
+ end
85
+ end
86
+ end
87
+ result
88
+ end
89
+
90
+ def write( node, objects, &block )
91
+ result = nil
92
+ Request.new.tap do | request |
93
+ serializer = Unimatrix::Serializer.new( objects )
94
+ response = request.post( @path, @parameters, serializer.serialize( node ) )
95
+ if response.present?
96
+ result = response.resources
97
+ if block_given?
98
+ case block.arity
99
+ when 0; yield
100
+ when 1; yield result
101
+ when 2; yield result, response
102
+ end
103
+ end
104
+ end
105
+ end
106
+ result
107
+ end
108
+
109
+ protected; def spawn( parameters )
110
+ Operation.new(
111
+ @path,
112
+ @parameters.deep_merge( parameters || {} )
113
+ )
114
+ end
115
+
116
+ protected; def normalize_include( *arguments )
117
+
118
+ includes = {}
119
+ arguments.each do | argument |
120
+ case argument
121
+ when Array
122
+ argument.each do | value |
123
+ includes.deep_merge!( self.normalize_include( value ) )
124
+ end
125
+ when Hash
126
+ argument.each do | key, value |
127
+ if !includes.include?( key ) || includes[ key ] === true
128
+ includes[ key ] = self.normalize_include( value )
129
+ else
130
+ includes[ key ].deep_merge!( self.normalize_include( value ) )
131
+ end
132
+ end
133
+ else
134
+ includes[ argument ] = true
135
+ end
136
+ end
137
+ includes
138
+
139
+ end
140
+
141
+ end
142
+
143
+ end
@@ -0,0 +1,203 @@
1
+ module Unimatrix
2
+
3
+ class Parser
4
+
5
+ def initialize( content = {} )
6
+ @content = content
7
+ yield self if block_given?
8
+ end
9
+
10
+ def name
11
+ @content.include?( '$this' ) ?
12
+ @content[ '$this' ][ 'name' ] :
13
+ nil
14
+ end
15
+
16
+ def type_name
17
+ @content.include?( '$this' ) ?
18
+ @content[ '$this' ][ 'type_name' ] :
19
+ nil
20
+ end
21
+
22
+ def key
23
+ 'id'
24
+ end
25
+
26
+ def keys
27
+ @content.include?( '$this' ) ?
28
+ @content[ '$this' ][ 'ids' ] :
29
+ nil
30
+ end
31
+
32
+ def associations
33
+ @content.include?( '$associations' ) ?
34
+ @content[ '$associations' ] :
35
+ nil
36
+ end
37
+
38
+ def resources
39
+ result = nil
40
+
41
+ unless self.name.blank?
42
+ result = self.keys.map do | key |
43
+ self.resource_by( name, key, { 'type_name' => self.type_name } )
44
+ end
45
+ end
46
+ result
47
+ end
48
+
49
+ def parse_resource( name, attributes )
50
+
51
+ @resources_mutex ||= Hash.new { | hash, key | hash[ key ] = [] }
52
+ resource_key = attributes[ key ]
53
+
54
+ # Lock the resource index for this name/key combination
55
+ # This prevents objects that are associated with
56
+ # themselves from causing a stack overflow
57
+ return nil if @resources_mutex[ name ].include?( resource_key )
58
+ @resources_mutex[ name ].push( resource_key )
59
+
60
+ resource = nil
61
+
62
+ if attributes.present?
63
+
64
+ resource_type_name = attributes[ :type_name ] || self.type_name
65
+ resource_class =
66
+ Resource.find_by_type_name( resource_type_name ) ||
67
+ Resource.find_by_type_name( self.type_name )
68
+
69
+ if resource_class.present?
70
+ relations = name == self.name ?
71
+ self.parse_associations( attributes ) : []
72
+ resource = resource_class.new( attributes, relations )
73
+ end
74
+
75
+ end
76
+
77
+ @resources_mutex[ name ].delete( object_key )
78
+
79
+ resource
80
+
81
+ end
82
+
83
+ def resource_by( name, key, options = {} )
84
+
85
+ @resources_index ||= Hash.new { | hash, key | hash[ key ] = {} }
86
+ @resource_index_mutex ||= Hash.new { | hash, key | hash[ key ] = [] }
87
+
88
+ @resources_index[ name ][ key ] ||= begin
89
+
90
+ # lock the resource index for this name/key combination
91
+ # note: this prevents Unimatrix objects that are associated with
92
+ # themselves from causing a stack overflow
93
+ return nil if @resource_index_mutex[ name ].include?( key )
94
+ @resource_index_mutex[ name ].push( key )
95
+
96
+ result = nil
97
+ resource_attributes = resource_attribute_index[ name ][ key ]
98
+
99
+ if resource_attributes.present?
100
+ parse_nested_attributes( resource_attributes )
101
+
102
+ resource_type_name = options[ 'type_name' ] ||
103
+ resource_attributes[ 'type_name' ]
104
+
105
+ resource_class = Resource.find_by_type_name( resource_type_name )
106
+ if resource_class.present?
107
+ result = resource_class.new(
108
+ resource_attributes,
109
+ self.resource_associations_by( name, key )
110
+ )
111
+ end
112
+ end
113
+
114
+ # unlock the resource index for this name/key combination
115
+ @resource_index_mutex[ name ].delete( key )
116
+
117
+ result
118
+
119
+ end
120
+
121
+ end
122
+
123
+ def resource_associations_by( name, key )
124
+ result = Hash.new { | hash, key | hash[ key ] = [] }
125
+ associations = self.associations
126
+ if associations && associations.include?( name )
127
+ association = associations[ name ].detect do | association |
128
+ association[ 'id' ] == key
129
+ end
130
+ if association.present?
131
+ association.each do | key, value |
132
+ unless key == 'id'
133
+ type_name = value[ 'type_name' ]
134
+ result[ key ] = ( value[ 'ids' ] || [] ).map do | associated_id |
135
+ self.resource_by(
136
+ key,
137
+ associated_id,
138
+ { 'type_name' => type_name }
139
+ )
140
+ end
141
+ result[ key ].compact!
142
+ end
143
+ end
144
+ end
145
+ end
146
+ result
147
+ end
148
+
149
+ def resource_attribute_index
150
+ @resource_attribute_index ||= begin
151
+ index = Hash.new { | hash, key | hash[ key ] = {} }
152
+ @content.each do | key, resources_attributes |
153
+ unless key[0] == '$'
154
+ resources_attributes.each do | resource_attributes |
155
+ index[ key ][ resource_attributes[ 'id' ] ] = resource_attributes
156
+ end
157
+ end
158
+ end
159
+ index
160
+ end
161
+ end
162
+
163
+ private; def parse_nested_attributes( attributes )
164
+
165
+ nested_attributes = {}
166
+
167
+ attributes.delete_if do | key, value |
168
+
169
+ if key.include?( '.' )
170
+
171
+ key, nested_key = key.split( '.' )
172
+
173
+ if nested_attributes[ key ].present?
174
+ nested_attributes[ key ][ nested_key.to_sym ] = value
175
+ else
176
+ nested_attributes[ key ] = { nested_key.to_sym => value }
177
+ end
178
+
179
+ true
180
+
181
+ else
182
+ false
183
+ end
184
+
185
+ end
186
+
187
+ if nested_attributes.present?
188
+
189
+ nested_attributes.each do | key, value |
190
+
191
+ attributes[ key ] = Struct.new( *value.keys ).new
192
+
193
+ value.each do | nested_key, nested_value |
194
+ attributes[ key ][ nested_key ] = nested_value
195
+ end
196
+
197
+ end
198
+
199
+ end
200
+
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,7 @@
1
+ module Unimatrix
2
+
3
+ class Realm < Resource
4
+ field :uuid
5
+ end
6
+
7
+ end
@@ -0,0 +1,77 @@
1
+ require 'net/http'
2
+ require 'addressable/uri'
3
+
4
+ module Unimatrix
5
+
6
+ class Request
7
+
8
+ def initialize( default_parameters = {} )
9
+ uri = URI( Unimatrix.configuration.url )
10
+ @http = Net::HTTP.new( uri.host, uri.port )
11
+
12
+ @http.use_ssl = ( uri.scheme == 'https' )
13
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
14
+
15
+ @default_parameters = default_parameters.stringify_keys
16
+ end
17
+
18
+ def destroy( path, parameters = {} )
19
+
20
+ begin
21
+ request = Net::HTTP::Delete.new(
22
+ compose_request_path( path, parameters ),
23
+ { 'Content-Type' =>'application/json' }
24
+ )
25
+ response = Response.new( @http.request( request ) )
26
+ rescue Timeout::Error
27
+ response = nil
28
+ end
29
+
30
+ response
31
+ end
32
+
33
+ def get( path, parameters = {} )
34
+ response = nil
35
+
36
+ begin
37
+ response = Response.new(
38
+ @http.get( compose_request_path( path, parameters ) )
39
+ )
40
+ rescue Timeout::Error
41
+ response = nil
42
+ end
43
+
44
+ response
45
+ end
46
+
47
+ def post( path, parameters = {}, body = {} )
48
+ response = nil
49
+
50
+ begin
51
+ request = Net::HTTP::Post.new(
52
+ compose_request_path( path, parameters ),
53
+ { 'Content-Type' =>'application/json' }
54
+ )
55
+ request.body = body.to_json
56
+
57
+ response = Response.new( @http.request( request ) )
58
+ rescue Timeout::Error
59
+ response = nil
60
+ end
61
+
62
+ response
63
+ end
64
+
65
+ protected; def compose_request_path( path, parameters = {} )
66
+ parameters = @default_parameters.merge( parameters.stringify_keys )
67
+ addressable = Addressable::URI.new
68
+
69
+ addressable.path = path
70
+ addressable.query = parameters.to_param unless parameters.blank?
71
+
72
+ addressable.to_s
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,102 @@
1
+ module Unimatrix
2
+
3
+ class Resource
4
+
5
+ class << self
6
+
7
+ def inherited( subclass )
8
+ subclass.nested_fields = {}.merge( self.nested_fields )
9
+ subclass.fields = {}.merge( self.fields )
10
+ end
11
+
12
+ def type_name
13
+ name.present? ? name.split( '::' ).last.underscore : nil
14
+ end
15
+
16
+ def find_by_type_name( type_name )
17
+ @descendants_by_type_name = begin
18
+ result = {}
19
+ descendants.each do | descendant |
20
+ descendant_type_name = descendant.type_name
21
+ result[ descendant_type_name ] = descendant \
22
+ unless descendant_type_name.blank?
23
+ end
24
+ result
25
+ end
26
+ @descendants_by_type_name[ type_name ]
27
+ end
28
+
29
+ def field( name, options = {} )
30
+ if name.is_a?( Hash )
31
+ nested_field_key = name.keys.first
32
+ self.nested_fields[ nested_field_key ] = name[ nested_field_key ]
33
+ name = nested_field_key
34
+ end
35
+
36
+ self.fields[ name.to_sym ] = options.merge( name: name )
37
+
38
+ class_eval(
39
+ "def #{ name }(); " +
40
+ "@#{ name }.is_a?( FalseClass ) ? @#{ name } : (" +
41
+ "@#{ name } || " +
42
+ ( options[ :default ].nil? ?
43
+ "nil" :
44
+ ( options[ :default ].is_a?( String ) ?
45
+ "'#{ options[ :default ] }'" :
46
+ "#{ options[ :default ] }" ) ) + ");" +
47
+ "end;" +
48
+ " " +
49
+ "attr_writer :#{ name };",
50
+ __FILE__,
51
+ __LINE__
52
+ )
53
+ end
54
+
55
+ def has_one( name, options = {} )
56
+ define_method name do
57
+ associations = self.instance_variable_get( "@_#{ name.to_s.pluralize }" )
58
+ associations.present? ? associations.first : options[ :default ]
59
+ end
60
+ end
61
+
62
+ def has_many( name, options = {} )
63
+ define_method name do
64
+ self.instance_variable_get( "@_#{ name }" ) ||
65
+ options[ :default ] || []
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ class_attribute :fields, instance_writer: false
72
+ class_attribute :nested_fields, instance_writer: false
73
+
74
+ self.fields = {}
75
+ self.nested_fields = {}
76
+
77
+ field :type_name
78
+ has_many :errors
79
+
80
+ def initialize( attributes={}, associations={} )
81
+
82
+ self.nested_fields.each do | key, value |
83
+ self.send( "#{ key }=", Struct.new( *value ).new )
84
+ end
85
+
86
+ self.type_name = self.class.name.split( '::' ).last.underscore rescue nil
87
+
88
+ attributes.each do | key, value |
89
+ send( "#{ key }=", value ) if self.respond_to?( "#{ key }=" )
90
+ end
91
+
92
+ associations.each do | key, value |
93
+ self.instance_variable_set( "@_#{ key }", value )
94
+ end
95
+
96
+ yield self if block_given?
97
+
98
+ end
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,44 @@
1
+ module Unimatrix
2
+
3
+ class Response
4
+
5
+ attr_reader :code
6
+ attr_reader :body
7
+ attr_reader :resources
8
+
9
+ def initialize( http_response )
10
+ @success = http_response.is_a?( Net::HTTPOK )
11
+ @code = http_response.code
12
+ @resources = []
13
+ @body = decode_response_body( http_response )
14
+
15
+ if ( @body && @body.respond_to?( :keys ) )
16
+ Parser.new( @body ) do | parser |
17
+ @resources = parser.resources
18
+ @success = !( parser.type_name == 'error' )
19
+ end
20
+ else
21
+ @success = false
22
+ @resources << Error.new(
23
+ message: "#{ @code }: #{ http_response.message }."
24
+ )
25
+ end
26
+ end
27
+
28
+ def success?
29
+ @success
30
+ end
31
+
32
+ protected; def decode_response_body( http_response )
33
+ body = http_response.body
34
+
35
+ if body.present?
36
+ JSON.parse( body ) rescue nil
37
+ else
38
+ nil
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,40 @@
1
+ module Unimatrix
2
+
3
+ class Serializer
4
+
5
+ def initialize( payload = [], options = {} )
6
+ @payload = [ payload ].flatten
7
+ @options = options
8
+ end
9
+
10
+ def serialize( node, options = {} )
11
+ result = {}
12
+ result[ node ] = @payload.map do | object |
13
+ node_object = {}
14
+ node_object[ :type_name ] = (
15
+ object.respond_to?( :type_name ) ?
16
+ object.type_name :
17
+ object.class.name.split( '::' ).last.underscore
18
+ )
19
+ if object.respond_to?( :fields )
20
+ object.fields.each do | name, options |
21
+ value = object.send( name ) if object.respond_to?( name )
22
+ if value.is_a?( Struct )
23
+ nested_attributes = value.members
24
+ nested_attributes.each do | nested_attribute |
25
+ key = "#{ name }.#{ nested_attribute }"
26
+ node_object[ key.to_sym ] = value.send( nested_attribute )
27
+ end
28
+ else
29
+ node_object[ name.to_sym ] = value
30
+ end
31
+ end
32
+ end
33
+ node_object
34
+ end
35
+ result
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,3 @@
1
+ module Unimatrix
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unimatrix
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jackson Souza
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-01-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: addressable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fnv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.10.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.10.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-nav
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: The unimatrix gem facilitates making requests to Unimatrix APIs.
84
+ email:
85
+ - jackson@sportsrocket.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - lib/unimatrix.rb
91
+ - lib/unimatrix/activist/activity.rb
92
+ - lib/unimatrix/activist/task.rb
93
+ - lib/unimatrix/archivist/artifact.rb
94
+ - lib/unimatrix/archivist/artifact_locator.rb
95
+ - lib/unimatrix/archivist/artifact_relationship.rb
96
+ - lib/unimatrix/archivist/blueprint.rb
97
+ - lib/unimatrix/archivist/blueprint_attribute.rb
98
+ - lib/unimatrix/archivist/component.rb
99
+ - lib/unimatrix/attribute_error.rb
100
+ - lib/unimatrix/bad_request_error.rb
101
+ - lib/unimatrix/configuration.rb
102
+ - lib/unimatrix/distributor/activity_reference.rb
103
+ - lib/unimatrix/distributor/destination.rb
104
+ - lib/unimatrix/distributor/distribution.rb
105
+ - lib/unimatrix/dynamic_resource.rb
106
+ - lib/unimatrix/error.rb
107
+ - lib/unimatrix/operation.rb
108
+ - lib/unimatrix/parser.rb
109
+ - lib/unimatrix/realm.rb
110
+ - lib/unimatrix/request.rb
111
+ - lib/unimatrix/resource.rb
112
+ - lib/unimatrix/response.rb
113
+ - lib/unimatrix/serializer.rb
114
+ - lib/unimatrix/version.rb
115
+ homepage: http://sportsrocket.com
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.6.12
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: Unimatrix is used to communicate with Unimatrix APIs.
139
+ test_files: []