occi-core 4.1.3 → 4.2.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.
- data/.gitignore +1 -0
- data/Gemfile +8 -0
- data/README.md +49 -17
- data/lib/occi/collection.rb +37 -21
- data/lib/occi/core/action.rb +5 -5
- data/lib/occi/core/action_instance.rb +45 -3
- data/lib/occi/core/actions.rb +2 -1
- data/lib/occi/core/attributes.rb +253 -73
- data/lib/occi/core/categories.rb +1 -0
- data/lib/occi/core/category.rb +25 -8
- data/lib/occi/core/entities.rb +1 -0
- data/lib/occi/core/entity.rb +51 -74
- data/lib/occi/core/kind.rb +15 -11
- data/lib/occi/core/kinds.rb +1 -1
- data/lib/occi/core/link.rb +14 -15
- data/lib/occi/core/links.rb +1 -1
- data/lib/occi/core/mixin.rb +5 -5
- data/lib/occi/core/mixins.rb +2 -2
- data/lib/occi/core/properties.rb +90 -12
- data/lib/occi/core/resource.rb +7 -3
- data/lib/occi/core/resources.rb +2 -2
- data/lib/occi/errors/attribute_definitions_converted_error.rb +5 -0
- data/lib/occi/errors/attribute_missing_error.rb +5 -0
- data/lib/occi/errors/attribute_name_invalid_error.rb +5 -0
- data/lib/occi/errors/attribute_not_defined_error.rb +5 -0
- data/lib/occi/errors/attribute_property_type_error.rb +5 -0
- data/lib/occi/errors/attribute_type_error.rb +5 -0
- data/lib/occi/errors/kind_not_defined_error.rb +5 -0
- data/lib/occi/errors/parser_input_error.rb +5 -0
- data/lib/occi/errors/parser_type_error.rb +5 -0
- data/lib/occi/errors.rb +1 -0
- data/lib/occi/extensions/hashie.rb +25 -0
- data/lib/occi/helpers/comparators/action_instance.rb +22 -0
- data/lib/occi/helpers/comparators/attributes.rb +22 -0
- data/lib/occi/helpers/comparators/categories.rb +22 -0
- data/lib/occi/helpers/comparators/category.rb +22 -0
- data/lib/occi/helpers/comparators/collection.rb +40 -0
- data/lib/occi/helpers/comparators/entities.rb +22 -0
- data/lib/occi/helpers/comparators/entity.rb +22 -0
- data/lib/occi/helpers/comparators/properties.rb +26 -0
- data/lib/occi/helpers/comparators.rb +1 -0
- data/lib/occi/infrastructure/compute.rb +11 -9
- data/lib/occi/infrastructure/network.rb +27 -27
- data/lib/occi/infrastructure/networkinterface.rb +22 -23
- data/lib/occi/infrastructure/os_tpl.rb +1 -1
- data/lib/occi/infrastructure/resource_tpl.rb +1 -1
- data/lib/occi/infrastructure/storage.rb +7 -6
- data/lib/occi/infrastructure/storagelink.rb +4 -4
- data/lib/occi/log.rb +13 -10
- data/lib/occi/model.rb +9 -8
- data/lib/occi/parser/json.rb +11 -9
- data/lib/occi/parser/ova.rb +12 -6
- data/lib/occi/parser/ovf.rb +173 -116
- data/lib/occi/parser/text/constants.rb +87 -0
- data/lib/occi/parser/text.rb +161 -200
- data/lib/occi/parser/xml.rb +10 -8
- data/lib/occi/parser.rb +100 -50
- data/lib/occi/settings.rb +2 -1
- data/lib/occi/version.rb +1 -1
- data/lib/occi-core.rb +6 -4
- data/occi-core.gemspec +0 -7
- data/spec/occi/collection_samples/collection1.json +1 -0
- data/spec/occi/collection_samples/directory2/collection2.json +1 -0
- data/spec/occi/collection_spec.rb +961 -31
- data/spec/occi/core/action_instance_spec.rb +317 -0
- data/spec/occi/core/action_spec.rb +71 -0
- data/spec/occi/core/attributes_spec.rb +582 -27
- data/spec/occi/core/category_spec.rb +194 -18
- data/spec/occi/core/entities_spec.rb +96 -0
- data/spec/occi/core/entity_spec.rb +317 -28
- data/spec/occi/core/kind_spec.rb +127 -16
- data/spec/occi/core/link_spec.rb +35 -0
- data/spec/occi/core/links_spec.rb +130 -0
- data/spec/occi/core/mixins_spec.rb +107 -0
- data/spec/occi/core/properties_spec.rb +167 -0
- data/spec/occi/core/resource_spec.rb +23 -9
- data/spec/occi/core_spec.rb +12 -0
- data/spec/occi/infrastructure/compute_spec.rb +218 -18
- data/spec/occi/infrastructure/network_spec.rb +96 -0
- data/spec/occi/infrastructure/networkinterface_spec.rb +96 -0
- data/spec/occi/infrastructure/storage_spec.rb +33 -0
- data/spec/occi/infrastructure/storagelink_spec.rb +45 -0
- data/spec/occi/log_spec.rb +104 -1
- data/spec/occi/model_spec.rb +251 -39
- data/spec/occi/{test.json → parser/json_samples/test.json} +0 -0
- data/spec/occi/parser/ova_samples/test.dump +0 -0
- data/spec/occi/{test.ova → parser/ova_samples/test.ova} +0 -0
- data/spec/occi/parser/ovf_samples/test.dump +0 -0
- data/spec/occi/{test.ovf → parser/ovf_samples/test.ovf} +0 -0
- data/spec/occi/parser/text_samples/occi_categories.dump +0 -0
- data/spec/occi/parser/text_samples/occi_categories.text +2 -0
- data/spec/occi/parser/text_samples/occi_compute_rocci_server.dump +0 -0
- data/spec/occi/parser/text_samples/occi_compute_rocci_server.resource.dump +0 -0
- data/spec/occi/parser/text_samples/occi_compute_rocci_server.text +10 -0
- data/spec/occi/parser/text_samples/occi_link_resource_instance.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_resource_instance.text +7 -0
- data/spec/occi/parser/text_samples/occi_link_simple.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_simple.link_string.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_simple.text +1 -0
- data/spec/occi/parser/text_samples/occi_link_w_attributes.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_w_attributes.text +7 -0
- data/spec/occi/parser/text_samples/occi_link_w_category.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_w_category.text +3 -0
- data/spec/occi/parser/text_samples/occi_model_rocci_server.dump +0 -0
- data/spec/occi/parser/text_samples/occi_model_rocci_server.text +51 -0
- data/spec/occi/parser/text_samples/occi_network_rocci_server.dump +0 -0
- data/spec/occi/parser/text_samples/occi_network_rocci_server.resource.dump +0 -0
- data/spec/occi/parser/text_samples/occi_network_rocci_server.text +11 -0
- data/spec/occi/parser/text_samples/occi_resource_w_attributes.dump +0 -0
- data/spec/occi/parser/text_samples/occi_resource_w_attributes.text +11 -0
- data/spec/occi/parser/text_samples/occi_resource_w_inline_links.dump +0 -0
- data/spec/occi/parser/text_samples/occi_resource_w_inline_links.text +16 -0
- data/spec/occi/parser/text_samples/occi_resource_w_inline_links_only.dump +0 -0
- data/spec/occi/parser/text_samples/occi_resource_w_inline_links_only.text +13 -0
- data/spec/occi/parser/text_samples/occi_storage_rocci_server.dump +0 -0
- data/spec/occi/parser/text_samples/occi_storage_rocci_server.resource.dump +0 -0
- data/spec/occi/parser/text_samples/occi_storage_rocci_server.text +9 -0
- data/spec/occi/parser/text_spec.rb +274 -78
- data/spec/occi/parser/xml_samples/test.xml +352 -0
- data/spec/occi/parser_spec.rb +255 -104
- data/spec/occi-core_spec.rb +31 -0
- data/spec/spec_helper.rb +6 -2
- metadata +110 -111
- checksums.yaml +0 -7
- data/spec/occi/core/attribute_spec.rb +0 -0
data/lib/occi/core/entity.rb
CHANGED
|
@@ -3,8 +3,10 @@ module Occi
|
|
|
3
3
|
class Entity
|
|
4
4
|
|
|
5
5
|
include Occi::Helpers::Inspect
|
|
6
|
+
include Occi::Helpers::Comparators::Entity
|
|
6
7
|
|
|
7
|
-
attr_accessor :mixins, :attributes, :actions, :id, :model, :
|
|
8
|
+
attr_accessor :mixins, :attributes, :actions, :id, :model, :location
|
|
9
|
+
attr_reader :kind
|
|
8
10
|
|
|
9
11
|
class_attribute :kind, :mixins, :attributes, :actions
|
|
10
12
|
|
|
@@ -64,27 +66,25 @@ module Occi
|
|
|
64
66
|
@kind = self.class.kind.clone
|
|
65
67
|
@mixins = Occi::Core::Mixins.new mixins
|
|
66
68
|
@mixins.entity = self
|
|
69
|
+
|
|
67
70
|
attributes = self.class.attribute_properties if attributes.blank?
|
|
68
71
|
if attributes.kind_of? Occi::Core::Attributes
|
|
69
72
|
@attributes = attributes.convert
|
|
70
73
|
else
|
|
71
74
|
@attributes = Occi::Core::Attributes.new attributes
|
|
72
75
|
end
|
|
76
|
+
@attributes['occi.core.id'] ||= UUIDTools::UUID.random_create.to_s
|
|
77
|
+
|
|
73
78
|
@actions = Occi::Core::Actions.new actions
|
|
74
79
|
@location = location
|
|
75
80
|
end
|
|
76
81
|
|
|
77
|
-
# @return [Occi::Core::Kind]
|
|
78
|
-
def kind
|
|
79
|
-
@kind
|
|
80
|
-
end
|
|
81
|
-
|
|
82
82
|
# @param [Occi::Core::Kind,String] kind
|
|
83
83
|
# @return [Occi::Core::Kind]
|
|
84
84
|
def kind=(kind)
|
|
85
85
|
if kind.kind_of? String
|
|
86
86
|
scheme, term = kind.split '#'
|
|
87
|
-
kind = Occi::Core::
|
|
87
|
+
kind = Occi::Core::Kind.get_class scheme, term
|
|
88
88
|
end
|
|
89
89
|
@kind = kind
|
|
90
90
|
end
|
|
@@ -115,7 +115,7 @@ module Occi
|
|
|
115
115
|
|
|
116
116
|
# @return [UUIDTools::UUID] id of the entity
|
|
117
117
|
def id
|
|
118
|
-
@id ||= @attributes.
|
|
118
|
+
@id ||= @attributes.occi_.core_.id
|
|
119
119
|
@id
|
|
120
120
|
end
|
|
121
121
|
|
|
@@ -127,17 +127,20 @@ module Occi
|
|
|
127
127
|
|
|
128
128
|
# @return [String] title attribute of entity
|
|
129
129
|
def title
|
|
130
|
-
@attributes.
|
|
130
|
+
@attributes.occi_.core_.title
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
# @param [Occi::Model] model
|
|
134
134
|
# @return [Occi::Model]
|
|
135
135
|
def model=(model)
|
|
136
136
|
@model = model
|
|
137
|
+
|
|
137
138
|
@kind = (model.get_by_id(@kind.type_identifier) || @kind)
|
|
138
139
|
@kind.entities << self
|
|
140
|
+
|
|
139
141
|
@mixins.model = model
|
|
140
142
|
@mixins.each { |mixin| mixin.entities << self }
|
|
143
|
+
|
|
141
144
|
@actions.model = model
|
|
142
145
|
end
|
|
143
146
|
|
|
@@ -150,56 +153,29 @@ module Occi
|
|
|
150
153
|
# @return [String] location of the entity
|
|
151
154
|
def location
|
|
152
155
|
return @location if @location
|
|
153
|
-
kind.location
|
|
156
|
+
"#{kind.location}#{id.gsub('urn:uuid:', '')}" if id
|
|
154
157
|
end
|
|
155
158
|
|
|
156
159
|
# check attributes against their definitions and set defaults
|
|
157
|
-
# @param [
|
|
158
|
-
def check
|
|
159
|
-
|
|
160
|
+
# @param [true,false] set default values for all empty attributes
|
|
161
|
+
def check(set_defaults = false)
|
|
162
|
+
|
|
163
|
+
raise ArgumentError, 'No model has been assigned to this entity' unless @model # XXX: Needs error type
|
|
164
|
+
|
|
165
|
+
kind = @model.get_by_id(@kind.to_s)
|
|
166
|
+
raise Occi::Errors::KindNotDefinedError, "Kind not found for entity #{self.to_s}!" unless kind # XXX: Needs error type
|
|
167
|
+
|
|
160
168
|
definitions = Occi::Core::Attributes.new
|
|
161
|
-
definitions.merge!
|
|
162
|
-
|
|
163
|
-
|
|
169
|
+
definitions.merge! kind.attributes
|
|
170
|
+
|
|
171
|
+
@mixins.each do |mxn|
|
|
172
|
+
mixin = @model.get_by_id(mxn.to_s)
|
|
164
173
|
next if mixin.nil?
|
|
174
|
+
|
|
165
175
|
definitions.merge!(mixin.attributes) if mixin.attributes
|
|
166
176
|
end if @mixins
|
|
167
|
-
|
|
168
|
-
@attributes
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
# @param [Occi::Core::Attributes] attributes
|
|
172
|
-
# @param [Occi::Core::Attributes] definitions
|
|
173
|
-
# @param [true,false] set_defaults
|
|
174
|
-
# @return [Occi::Core::Attributes] attributes with their defaults set
|
|
175
|
-
def self.check(attributes, definitions, set_defaults=false)
|
|
176
|
-
attributes = Occi::Core::Attributes.new(attributes)
|
|
177
|
-
definitions.each_key do |key|
|
|
178
|
-
next if definitions.key?(key[1..-1])
|
|
179
|
-
if definitions[key].kind_of? Occi::Core::Attributes
|
|
180
|
-
attributes[key] = check(attributes[key], definitions[key])
|
|
181
|
-
else
|
|
182
|
-
properties = definitions[key]
|
|
183
|
-
value = attributes[key]
|
|
184
|
-
value ||= properties.default if set_defaults or properties.required?
|
|
185
|
-
raise "required attribute #{key} not found" if value.nil? && properties.required?
|
|
186
|
-
next if value.blank? and not properties.required?
|
|
187
|
-
case properties.type
|
|
188
|
-
when 'number'
|
|
189
|
-
raise "attribute #{key} value #{value} from class #{value.class.name} does not match attribute property type #{properties.type}" unless value.kind_of?(Numeric)
|
|
190
|
-
when 'boolean'
|
|
191
|
-
raise "attribute #{key} value #{value} from class #{value.class.name} does not match attribute property type #{properties.type}" unless !!value == value
|
|
192
|
-
when 'string'
|
|
193
|
-
raise "attribute #{key} with value #{value} from class #{value.class.name} does not match attribute property type #{properties.type}" unless value.kind_of?(String)
|
|
194
|
-
else
|
|
195
|
-
raise "property type #{properties.type} is not one of the allowed types number, boolean or string"
|
|
196
|
-
end
|
|
197
|
-
Occi::Log.warn "attribute #{key} with value #{value} does not match pattern #{properties.pattern}" if value.to_s.scan(Regexp.new(properties.pattern)).blank? if properties.pattern
|
|
198
|
-
attributes[key] = value
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
attributes.delete_if { |_, v| v.blank? } # remove empty attributes
|
|
202
|
-
attributes
|
|
177
|
+
|
|
178
|
+
@attributes.check!(definitions, set_defaults)
|
|
203
179
|
end
|
|
204
180
|
|
|
205
181
|
# @param [Hash] options
|
|
@@ -208,7 +184,7 @@ module Occi
|
|
|
208
184
|
entity = Hashie::Mash.new
|
|
209
185
|
entity.kind = @kind.to_s if @kind
|
|
210
186
|
entity.mixins = @mixins.join(' ').split(' ') if @mixins.any?
|
|
211
|
-
entity.actions = @actions if @actions.any?
|
|
187
|
+
entity.actions = @actions.as_json if @actions.any?
|
|
212
188
|
entity.attributes = @attributes.as_json if @attributes.as_json.any?
|
|
213
189
|
entity.id = id.to_s if id
|
|
214
190
|
entity
|
|
@@ -216,42 +192,38 @@ module Occi
|
|
|
216
192
|
|
|
217
193
|
# @return [String] text representation
|
|
218
194
|
def to_text
|
|
219
|
-
text =
|
|
195
|
+
text = "Category: #{self.kind.term};scheme=#{self.kind.scheme.inspect};class=\"kind\""
|
|
220
196
|
@mixins.each do |mixin|
|
|
221
197
|
scheme, term = mixin.to_s.split('#')
|
|
222
198
|
scheme << '#'
|
|
223
|
-
text << "\
|
|
224
|
-
end
|
|
225
|
-
@attributes.names.each_pair do |name, value|
|
|
226
|
-
value = value.inspect
|
|
227
|
-
text << "\n" + 'X-OCCI-Attribute: ' + name + '=' + value
|
|
228
|
-
end
|
|
229
|
-
@actions.each do |action|
|
|
230
|
-
_, term = action.split('#')
|
|
231
|
-
text << "\n" + 'Link: <' + self.location + '?action=' + term + '>;rel=' + action.inspect
|
|
199
|
+
text << "\nCategory: #{term};scheme=#{scheme.inspect};class=\"mixin\""
|
|
232
200
|
end
|
|
201
|
+
|
|
202
|
+
text << @attributes.to_text
|
|
203
|
+
|
|
204
|
+
@actions.each { |action| text << "\nLink: <#{self.location}?action=#{action.term}>;rel=#{action.to_s}" }
|
|
205
|
+
|
|
233
206
|
text
|
|
234
207
|
end
|
|
235
208
|
|
|
236
209
|
# @return [Hash] hash containing the HTTP headers of the text/occi rendering
|
|
237
210
|
def to_header
|
|
238
211
|
header = Hashie::Mash.new
|
|
239
|
-
header['Category'] = self.kind.term
|
|
212
|
+
header['Category'] = "#{self.kind.term};scheme=#{self.kind.scheme.inspect};class=\"kind\""
|
|
213
|
+
|
|
240
214
|
@mixins.each do |mixin|
|
|
241
215
|
scheme, term = mixin.to_s.split('#')
|
|
242
216
|
scheme << '#'
|
|
243
|
-
header['Category']
|
|
244
|
-
end
|
|
245
|
-
attributes = []
|
|
246
|
-
@attributes.names.each_pair do |name, value|
|
|
247
|
-
attributes << name + '=' + value.to_s.inspect
|
|
217
|
+
header['Category'] << ",#{term};scheme=#{scheme.inspect};class=\"mixin\""
|
|
248
218
|
end
|
|
249
|
-
|
|
219
|
+
|
|
220
|
+
attributes = @attributes.to_header
|
|
221
|
+
header['X-OCCI-Attribute'] = attributes unless attributes.blank?
|
|
222
|
+
|
|
250
223
|
links = []
|
|
251
|
-
@actions.each
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
end
|
|
224
|
+
@actions.each { |action| links << "<#{self.location}?action=#{action.term}>;rel=#{action.to_s}" }
|
|
225
|
+
header['Link'] = links.join(',') if links.any?
|
|
226
|
+
|
|
255
227
|
header
|
|
256
228
|
end
|
|
257
229
|
|
|
@@ -260,6 +232,11 @@ module Occi
|
|
|
260
232
|
self.location
|
|
261
233
|
end
|
|
262
234
|
|
|
235
|
+
# @return [Bool] Indicating whether this entity is "empty", i.e. required attributes are blank
|
|
236
|
+
def empty?
|
|
237
|
+
kind.blank? || attributes['occi.core.id'].blank?
|
|
238
|
+
end
|
|
239
|
+
|
|
263
240
|
end
|
|
264
241
|
end
|
|
265
242
|
end
|
data/lib/occi/core/kind.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Occi
|
|
|
21
21
|
@parent = [parent].flatten.first
|
|
22
22
|
@actions = Occi::Core::Actions.new(actions)
|
|
23
23
|
@entities = Occi::Core::Entities.new
|
|
24
|
-
location.blank? ? @location =
|
|
24
|
+
location.blank? ? @location = "/#{term}/" : @location = location
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# @param scheme [String] The categorisation scheme.
|
|
@@ -30,9 +30,12 @@ module Occi
|
|
|
30
30
|
# @return [Class] Ruby class with scheme as namespace, term as name and parent kind as super class.
|
|
31
31
|
def self.get_class(scheme, term, parent=Occi::Core::Entity.kind)
|
|
32
32
|
parent ||= Occi::Core::Entity.kind
|
|
33
|
+
raise ArgumentError, 'Mandatory argument cannot be nil' unless scheme && term
|
|
34
|
+
|
|
33
35
|
if parent.kind_of? Array
|
|
34
36
|
parent = parent.first
|
|
35
37
|
end
|
|
38
|
+
|
|
36
39
|
if parent.to_s == 'http://schemas.ogf.org/occi/core#entity'
|
|
37
40
|
parent = Occi::Core::Entity.kind
|
|
38
41
|
elsif parent.kind_of? Occi::Core::Kind
|
|
@@ -41,8 +44,11 @@ module Occi
|
|
|
41
44
|
parent = self.get_class(*parent.to_s.split('#')).kind
|
|
42
45
|
end
|
|
43
46
|
|
|
47
|
+
term = self.sanitize_term(term) if Occi::Settings.compatibility
|
|
48
|
+
raise ArgumentError, "Invalid characters in term #{term}" unless Occi::Core::Category.valid_term?(term)
|
|
49
|
+
|
|
44
50
|
unless scheme.end_with? '#'
|
|
45
|
-
scheme
|
|
51
|
+
scheme << '#'
|
|
46
52
|
end
|
|
47
53
|
|
|
48
54
|
uri = URI.parse(scheme)
|
|
@@ -60,7 +66,7 @@ module Occi
|
|
|
60
66
|
end
|
|
61
67
|
end
|
|
62
68
|
|
|
63
|
-
class_name =
|
|
69
|
+
class_name = term.classify
|
|
64
70
|
if namespace.const_defined? class_name
|
|
65
71
|
klass = namespace.const_get class_name
|
|
66
72
|
unless klass.ancestors.include? Occi::Core::Entity
|
|
@@ -113,20 +119,18 @@ module Occi
|
|
|
113
119
|
# @return [String] string representation of the kind
|
|
114
120
|
def to_string
|
|
115
121
|
string = super
|
|
116
|
-
string <<
|
|
117
|
-
string <<
|
|
118
|
-
string <<
|
|
119
|
-
string <<
|
|
122
|
+
string << ";rel=#{self.related.first.to_s.inspect}" if self.related.any?
|
|
123
|
+
string << ";location=#{self.location.inspect}"
|
|
124
|
+
string << self.attributes.to_string_short
|
|
125
|
+
string << ";actions=#{self.actions.join(' ').inspect}" if self.actions.any?
|
|
120
126
|
string
|
|
121
127
|
end
|
|
122
128
|
|
|
123
129
|
private
|
|
124
130
|
|
|
125
131
|
# Relaxed parser rules require additional checks on terms.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def self.sanitize_term_before_classify(term)
|
|
129
|
-
sanitized = term.downcase.gsub(/[\s\(\)\.\{\}\-;,\\\/\?\!\|\*\<\>]/, '_').gsub(/_+/, '_').chomp('_').reverse.chomp('_').reverse
|
|
132
|
+
def self.sanitize_term(term)
|
|
133
|
+
sanitized = term.downcase.gsub(/[^a-z0-9-]/, '_').gsub(/_+/, '_').gsub(/^_|_$/, '')
|
|
130
134
|
sanitized = "uuid_#{sanitized}" if sanitized.match(/^[0-9]/)
|
|
131
135
|
|
|
132
136
|
sanitized
|
data/lib/occi/core/kinds.rb
CHANGED
data/lib/occi/core/link.rb
CHANGED
|
@@ -4,6 +4,7 @@ module Occi
|
|
|
4
4
|
|
|
5
5
|
attr_accessor :rel, :source, :target
|
|
6
6
|
|
|
7
|
+
self.attributes = Occi::Core::Attributes.new(Occi::Core::Entity.attributes)
|
|
7
8
|
self.attributes['occi.core.target'] = {:mutable => true}
|
|
8
9
|
self.attributes['occi.core.source'] = {:mutable => true}
|
|
9
10
|
|
|
@@ -30,7 +31,7 @@ module Occi
|
|
|
30
31
|
|
|
31
32
|
# @return [String] target attribute of the link
|
|
32
33
|
def target
|
|
33
|
-
@target ||= self.attributes.
|
|
34
|
+
@target ||= self.attributes.occi_.core_.target
|
|
34
35
|
@target
|
|
35
36
|
end
|
|
36
37
|
|
|
@@ -43,7 +44,7 @@ module Occi
|
|
|
43
44
|
|
|
44
45
|
# @return [String] source attribute of the link
|
|
45
46
|
def source
|
|
46
|
-
@source ||= self.attributes.
|
|
47
|
+
@source ||= self.attributes.occi_.core_.source
|
|
47
48
|
@source
|
|
48
49
|
end
|
|
49
50
|
|
|
@@ -54,9 +55,9 @@ module Occi
|
|
|
54
55
|
@source = source
|
|
55
56
|
end
|
|
56
57
|
|
|
57
|
-
#
|
|
58
|
+
# Runs check on attributes
|
|
58
59
|
def check
|
|
59
|
-
raise "rel
|
|
60
|
+
raise ArgumentError, "Cannot run check on #{self.to_s} without relation (@rel attribute) set" unless @rel
|
|
60
61
|
super
|
|
61
62
|
end
|
|
62
63
|
|
|
@@ -72,25 +73,23 @@ module Occi
|
|
|
72
73
|
|
|
73
74
|
# @return [String] text representation of link reference
|
|
74
75
|
def to_string
|
|
75
|
-
string =
|
|
76
|
-
string <<
|
|
77
|
-
string <<
|
|
76
|
+
string = "<#{self.target.to_s}>"
|
|
77
|
+
string << ";rel=#{@rel.to_s.inspect}"
|
|
78
|
+
string << ";self=#{self.location.inspect}" if self.location
|
|
79
|
+
|
|
78
80
|
categories = [@kind] + @mixins.join(',').split(',')
|
|
79
|
-
string <<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
value = value.to_s.inspect
|
|
83
|
-
string << ';' + name + '=' + value
|
|
84
|
-
end
|
|
81
|
+
string << ";category=#{categories.join(' ').inspect}"
|
|
82
|
+
|
|
83
|
+
string << @attributes.to_string
|
|
85
84
|
|
|
86
85
|
string
|
|
87
86
|
end
|
|
88
87
|
|
|
89
88
|
# @return [String] text representation of link
|
|
90
89
|
def to_text_link
|
|
91
|
-
|
|
90
|
+
"Link: #{self.to_string}"
|
|
92
91
|
end
|
|
93
92
|
|
|
94
93
|
end
|
|
95
94
|
end
|
|
96
|
-
end
|
|
95
|
+
end
|
data/lib/occi/core/links.rb
CHANGED
data/lib/occi/core/mixin.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Occi
|
|
|
23
23
|
@depends = Occi::Core::Dependencies.new depends
|
|
24
24
|
@actions = Occi::Core::Actions.new actions
|
|
25
25
|
@entities = Occi::Core::Entities.new
|
|
26
|
-
location.blank? ? @location =
|
|
26
|
+
location.blank? ? @location = "/mixins/#{term}/" : @location = location
|
|
27
27
|
@applies = Occi::Core::Kinds.new applies
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -59,10 +59,10 @@ module Occi
|
|
|
59
59
|
# @return [String] text representation
|
|
60
60
|
def to_string
|
|
61
61
|
string = super
|
|
62
|
-
string <<
|
|
63
|
-
string <<
|
|
64
|
-
string <<
|
|
65
|
-
string <<
|
|
62
|
+
string << ";rel=#{self.related.join(' ').inspect}" if self.related.any?
|
|
63
|
+
string << ";location=#{self.location.inspect}"
|
|
64
|
+
string << self.attributes.to_string_short
|
|
65
|
+
string << ";actions=#{self.actions.join(' ').inspect}" if self.actions.any?
|
|
66
66
|
string
|
|
67
67
|
end
|
|
68
68
|
|
data/lib/occi/core/mixins.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Occi
|
|
|
11
11
|
|
|
12
12
|
def remove(mixin)
|
|
13
13
|
mixin = convert mixin
|
|
14
|
-
@entity.attributes.remove mixin.attributes
|
|
14
|
+
@entity.attributes.remove mixin.attributes if @entity
|
|
15
15
|
self.delete mixin
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -34,4 +34,4 @@ module Occi
|
|
|
34
34
|
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
|
-
end
|
|
37
|
+
end
|
data/lib/occi/core/properties.rb
CHANGED
|
@@ -3,33 +3,111 @@ module Occi
|
|
|
3
3
|
class Properties
|
|
4
4
|
|
|
5
5
|
include Occi::Helpers::Inspect
|
|
6
|
+
include Occi::Helpers::Comparators::Properties
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
PROPERTY_KEYS = [:type, :required, :mutable, :default, :description, :pattern]
|
|
9
|
+
attr_accessor :required, :mutable, :default, :description, :pattern
|
|
10
|
+
attr_reader :type
|
|
8
11
|
alias_method :required?, :required
|
|
9
12
|
alias_method :mutable?, :mutable
|
|
10
13
|
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
# Types supported in properties, and their mapping to Ruby Classes
|
|
15
|
+
SUPPORTED_TYPES = Hash.new
|
|
16
|
+
SUPPORTED_TYPES["string"] = [ String ]
|
|
17
|
+
SUPPORTED_TYPES["number"] = [ Numeric ]
|
|
18
|
+
SUPPORTED_TYPES["boolean"] = [ TrueClass, FalseClass ]
|
|
19
|
+
|
|
20
|
+
# @param source_hash [Hash]
|
|
21
|
+
def initialize(source_hash = {})
|
|
22
|
+
raise ArgumentError, 'Source_hash must be initialized from a hash-like structure!' unless source_hash.kind_of?(Hash)
|
|
23
|
+
raise ArgumentError, 'Source_hash must not be a Hashie::Mash instance!' if source_hash.kind_of?(Hashie::Mash)
|
|
24
|
+
source_hash = Occi::Core::Properties.normalize_props(source_hash)
|
|
25
|
+
|
|
26
|
+
self.type = source_hash[:type] ||= 'string'
|
|
27
|
+
raise Occi::Errors::AttributePropertyTypeError,
|
|
28
|
+
"Type \"#{self.type}\" unsupported in properties. " \
|
|
29
|
+
"Supported types are: #{Properties.supported_type_names}." unless SUPPORTED_TYPES.key?(self.type)
|
|
30
|
+
self.required = source_hash[:required] = source_hash[:required].nil? ? false : source_hash[:required]
|
|
31
|
+
self.mutable = source_hash[:mutable] = source_hash[:mutable].nil? ? false : source_hash[:mutable]
|
|
32
|
+
self.pattern = source_hash[:pattern] ||= '.*'
|
|
33
|
+
self.description = source_hash[:description]
|
|
34
|
+
self.default = source_hash[:default]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param type [String] Requested attribute type
|
|
38
|
+
def type=(type)
|
|
39
|
+
raise Occi::Errors::AttributePropertyTypeError,
|
|
40
|
+
"Type \"#{type}\" unsupported in properties. Supported " \
|
|
41
|
+
"types are: #{Properties.supported_type_names}." unless SUPPORTED_TYPES.key?(type)
|
|
42
|
+
@type = type
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @param value [Object] Object whose class will be checked against definition
|
|
46
|
+
def check_value_for_type(value, key_name = nil)
|
|
47
|
+
raise Occi::Errors::AttributePropertyTypeError,
|
|
48
|
+
"Property type #{@type} for #{key_name.inspect} is not one of the allowed " \
|
|
49
|
+
"types: #{Properties.supported_type_names}" unless SUPPORTED_TYPES.key?(@type)
|
|
50
|
+
raise Occi::Errors::AttributeTypeError,
|
|
51
|
+
"Attribute value #{value} for #{key_name.inspect} is class #{value.class.name}. " \
|
|
52
|
+
"It does not match attribute property type #{@type}" unless SUPPORTED_TYPES[@type].any? { |klasse| value.kind_of?(klasse) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_hash
|
|
56
|
+
as_json.to_hash
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def to_json(*a)
|
|
60
|
+
as_json(*a).to_json(*a)
|
|
20
61
|
end
|
|
21
62
|
|
|
22
63
|
def as_json(options={})
|
|
23
64
|
hash = Hashie::Mash.new
|
|
24
65
|
hash.default = self.default if self.default
|
|
25
66
|
hash.type = self.type if self.type
|
|
26
|
-
hash.required = self.required
|
|
27
|
-
hash.mutable = self.mutable
|
|
67
|
+
hash.required = self.required unless self.required.nil?
|
|
68
|
+
hash.mutable = self.mutable unless self.mutable.nil?
|
|
28
69
|
hash.pattern = self.pattern if self.pattern
|
|
29
70
|
hash.description = self.description if self.description
|
|
71
|
+
|
|
30
72
|
hash
|
|
31
73
|
end
|
|
32
74
|
|
|
75
|
+
# @return [Bool] Indicating whether this set of properties is "empty", i.e. no attributes are set
|
|
76
|
+
def empty?
|
|
77
|
+
as_json.empty?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.normalize_props(hash)
|
|
81
|
+
props = {}
|
|
82
|
+
|
|
83
|
+
PROPERTY_KEYS.each do |key|
|
|
84
|
+
found = hash.keys.select { |k| k.to_s.downcase.to_sym == key }.first
|
|
85
|
+
props[key] = hash[found] if found
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
props
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.contains_props?(hash)
|
|
92
|
+
# Not a hash == doesn't contain Properties
|
|
93
|
+
return false unless hash.kind_of? Hash
|
|
94
|
+
hash = normalize_props(hash)
|
|
95
|
+
|
|
96
|
+
# Are there any Property keys?
|
|
97
|
+
return false if hash.empty?
|
|
98
|
+
|
|
99
|
+
# Do all Property keys point to simple values?
|
|
100
|
+
complx_keys = hash.keys.select { |k| hash[k].kind_of?(Hash) }
|
|
101
|
+
return false unless complx_keys.empty?
|
|
102
|
+
|
|
103
|
+
true
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def self.supported_type_names()
|
|
109
|
+
SUPPORTED_TYPES.keys.join(', ')
|
|
110
|
+
end
|
|
33
111
|
end
|
|
34
112
|
end
|
|
35
113
|
end
|
data/lib/occi/core/resource.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Occi
|
|
|
4
4
|
|
|
5
5
|
attr_accessor :links
|
|
6
6
|
|
|
7
|
-
self.attributes = Occi::Core::Attributes.new
|
|
7
|
+
self.attributes = Occi::Core::Attributes.new(Occi::Core::Entity.attributes)
|
|
8
8
|
|
|
9
9
|
self.attributes['occi.core.summary'] = {:mutable => true}
|
|
10
10
|
|
|
@@ -31,7 +31,7 @@ module Occi
|
|
|
31
31
|
|
|
32
32
|
# @return [String] summary attribute of the resource
|
|
33
33
|
def summary
|
|
34
|
-
self.attributes.
|
|
34
|
+
self.attributes.occi_.core_.summary
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
# set summary attribute of resource
|
|
@@ -42,19 +42,23 @@ module Occi
|
|
|
42
42
|
|
|
43
43
|
def link(target, kind=Occi::Core::Link.kind, mixins=[], attributes=Occi::Core::Attributes.new, rel=Occi::Core::Resource.type_identifier)
|
|
44
44
|
link = kind.entity_type.new
|
|
45
|
+
|
|
45
46
|
link.rel = rel
|
|
46
47
|
link.attributes = attributes
|
|
48
|
+
link.id ||= UUIDTools::UUID.random_create.to_s
|
|
47
49
|
link.target = target
|
|
48
50
|
link.source = self
|
|
49
51
|
link.mixins = mixins
|
|
52
|
+
|
|
50
53
|
@links << link
|
|
54
|
+
|
|
51
55
|
link
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
# @return [String] text representation
|
|
55
59
|
def to_text
|
|
56
60
|
text = super
|
|
57
|
-
@links.each { |link| text << "\n
|
|
61
|
+
@links.each { |link| text << "\n#{link.to_text_link}" }
|
|
58
62
|
text
|
|
59
63
|
end
|
|
60
64
|
|
data/lib/occi/core/resources.rb
CHANGED