unimatrix 1.0.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.
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: []