occi-core 5.0.0.alpha.4 → 5.0.0.beta.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 196f824b580d6a90fe2da14cbf85b99deb088d93
4
- data.tar.gz: 8b06f630a141c702742c019529bf11184e8ce87f
3
+ metadata.gz: bac82f913d97840096bf9d40d0e492fec5ed3b8f
4
+ data.tar.gz: dd0af74945ae6464ddf58e91cb4fa220d3409968
5
5
  SHA512:
6
- metadata.gz: db0db57a71621cf8beb45e2682659831a8aff23356efbdf26d6b1160f4a36d8e69ef9ecb94b55819d7584825dbc74034f6c1a155bf62d374c98722602a8d2f52
7
- data.tar.gz: 93ef6536c47a7d0b3225f0ffb5280eaacc2b6b5611c4d902bcb5374bbf0cf162abfdbee0fdb58e35d0c914a514786a36ee8719ecd881c953afff81cc0b60e070
6
+ metadata.gz: 2fa653867bd073489c1b8f584125c6b5eff7d8675aad1298d0f5b1cef057d6327a076a7d938a70a0d1d1eb5a124d3258ccc57b8412c93fd6fe6a9cd150eb3a39
7
+ data.tar.gz: b8b8ce1728507099d3b932e4abf9388f53256a0692628868c96bb98ab16998ba2d57d74cf3ffb68fe1470e8074980d2f83b790a37e78cc2685b1bae42d9dc3c6
data/.rubocop.yml CHANGED
@@ -55,6 +55,10 @@ Style/FileName:
55
55
  Exclude:
56
56
  - 'lib/occi/infrastructure-ext.rb'
57
57
 
58
+ Style/YodaCondition:
59
+ Exclude:
60
+ - 'lib/occi/core/helpers/parser_dereferencer.rb'
61
+
58
62
  RSpec/MultipleExpectations:
59
63
  Max: 5
60
64
 
@@ -8,7 +8,7 @@ module Occi
8
8
  module ArgumentValidator
9
9
  # :nodoc:
10
10
  def default_args!(args)
11
- logger.debug "#{self.class}: Merging given args #{args.inspect} with defaults #{defaults.inspect}"
11
+ logger.debug "Merging #{self.class} args #{args.inspect} with defaults #{defaults.inspect}"
12
12
  args.merge!(defaults) { |_, oldval, _| oldval }
13
13
  sufficient_args!(args)
14
14
  end
@@ -128,6 +128,7 @@ module Occi
128
128
  # @param model [Occi::Core::Model] model instance for dereferencing (category look-up)
129
129
  # @return [Occi::Core::Category] instance located in the model
130
130
  def dereference_via_model(identifier, model)
131
+ logger.debug "Dereferencing #{identifier.inspect} by look-up in model"
131
132
  model.find_by_identifier!(identifier)
132
133
  end
133
134
 
@@ -138,6 +139,7 @@ module Occi
138
139
  # @param hash [Hash] hash with known attribute definitions for dereferencing
139
140
  # @return [Occi::Core::AttributeDefinition] definition located in the hash
140
141
  def dereference_via_hash(identifier, hash)
142
+ logger.debug "Dereferencing #{identifier.inspect} by look-up in hash"
141
143
  raise "Attribute definition #{identifier.inspect} not found in the hash" unless hash[identifier]
142
144
  hash[identifier]
143
145
  end
@@ -25,7 +25,7 @@ module Occi
25
25
  begin
26
26
  valid_term! term
27
27
  rescue Occi::Core::Errors::CategoryValidationError => ex
28
- logger.warn "#{self}: Term validation failed with #{ex.message}" if respond_to?(:logger)
28
+ logger.warn "Term validation for #{self} failed with #{ex.message}" if respond_to?(:logger)
29
29
  return false
30
30
  end
31
31
 
@@ -58,7 +58,7 @@ module Occi
58
58
  begin
59
59
  valid_schema! schema
60
60
  rescue URI::InvalidURIError, Occi::Core::Errors::CategoryValidationError => ex
61
- logger.warn "#{self}: Schema validation failed with #{ex.message}" if respond_to?(:logger)
61
+ logger.warn "Schema validation for #{self} failed with #{ex.message}" if respond_to?(:logger)
62
62
  return false
63
63
  end
64
64
 
@@ -96,7 +96,7 @@ module Occi
96
96
  begin
97
97
  valid_identifier! identifier
98
98
  rescue URI::InvalidURIError, Occi::Core::Errors::CategoryValidationError => ex
99
- logger.warn "#{self}: Identifier validation failed with #{ex.message}" if respond_to?(:logger)
99
+ logger.warn "Identifier validation for #{self} failed with #{ex.message}" if respond_to?(:logger)
100
100
  return false
101
101
  end
102
102
 
@@ -53,7 +53,7 @@ module Occi
53
53
  name_cache = attribute_names
54
54
  attributes.keep_if do |key, value|
55
55
  defined = name_cache.include?(key) && value && value.attribute_definition
56
- logger.debug "#{self.class}: Removing undefined attribute #{key.inspect}" unless defined
56
+ logger.debug "Removing undefined attribute #{key.inspect} on #{self.class}" unless defined
57
57
  defined
58
58
  end
59
59
  end
@@ -122,10 +122,10 @@ module Occi
122
122
  # @param force [TrueClass, FalseClass] forcibly change attribute value to default
123
123
  def reset_attribute(name, definition, force)
124
124
  if attributes[name]
125
- logger.debug "#{self.class}: Setting attribute definition for existing #{name.inspect}"
125
+ logger.debug "Setting attribute definition for existing #{name.inspect} on #{self.class}"
126
126
  attributes[name].attribute_definition = definition
127
127
  else
128
- logger.debug "#{self.class}: Creating attribute definition for new #{name.inspect}"
128
+ logger.debug "Creating attribute definition for new #{name.inspect} on #{self.class}"
129
129
  attributes[name] = Attribute.new(nil, definition)
130
130
  end
131
131
 
@@ -28,7 +28,7 @@ module Occi
28
28
  # @param parsed [Array] list of original parsed category structures
29
29
  def lookup_references!(cat, derefd, parsed)
30
30
  parsed_cat = parsed.detect { |pcat| "#{pcat[:scheme]}#{pcat[:term]}" == cat.identifier }
31
- raise Occi::Core::Errors::ParsingError, "#{self} -> #{cat.identifier} not in the model" unless parsed_cat
31
+ raise Occi::Core::Errors::ParsingError, "Category #{cat.identifier} not in the model" unless parsed_cat
32
32
  lookup_action_references!(cat, derefd, parsed_cat[:actions])
33
33
 
34
34
  if cat.is_a?(Occi::Core::Mixin)
@@ -44,7 +44,7 @@ module Occi
44
44
  # @param derefd [Array] list of all available category instances
45
45
  # @param parsed_actions [Array] textual representation of needed actions
46
46
  def lookup_action_references!(cat, derefd, parsed_actions)
47
- logger.debug "#{self}: Dereferencing actions #{parsed_actions.inspect} for #{cat.identifier.inspect}"
47
+ logger.debug "Dereferencing actions #{parsed_actions.inspect} for #{cat.identifier.inspect}"
48
48
  return if parsed_actions.blank?
49
49
  parsed_actions.each { |action| cat.actions << first_or_die(derefd, action) }
50
50
  end
@@ -54,11 +54,11 @@ module Occi
54
54
  # @param parsed_rel [Array] textual representation of needed parent(s)
55
55
  def lookup_parent_references!(kind, derefd, parsed_rel)
56
56
  return if parsed_rel.blank? || kind.parent.is_a?(Occi::Core::Kind)
57
- logger.debug "#{self}: Dereferencing parent #{parsed_rel.inspect} for #{kind.identifier.inspect}"
57
+ logger.debug "Dereferencing parent #{parsed_rel.inspect} for #{kind.identifier.inspect}"
58
58
  if parsed_rel.is_a?(Enumerable)
59
59
  if parsed_rel.count > 1
60
60
  raise Occi::Core::Errors::ParsingError,
61
- "#{self} -> Kind #{kind} with multiple parents #{parsed_rel.inspect}"
61
+ "Kind #{kind} with multiple parents #{parsed_rel.inspect}"
62
62
  end
63
63
  parsed_rel = parsed_rel.first
64
64
  end
@@ -85,11 +85,11 @@ module Occi
85
85
  # @param what [String] identifier of the desired item
86
86
  # @return [Object] desired item from `where`
87
87
  def first_or_die(where, what)
88
- logger.debug "#{self}: Looking for #{what.inspect} in #{where.class}"
88
+ logger.debug "Looking for #{what.inspect} in #{where.class}"
89
89
  found = where.detect { |elm| elm.identifier == what }
90
90
  unless found
91
91
  raise Occi::Core::Errors::ParsingError,
92
- "#{self} -> Category #{what.to_s.inspect} referenced but not provided"
92
+ "Category #{what.to_s.inspect} referenced but not provided"
93
93
  end
94
94
  found
95
95
  end
@@ -10,7 +10,7 @@ module Occi
10
10
  def raw_hash(body)
11
11
  JSON.parse body, symbolize_names: true
12
12
  rescue => ex
13
- raise Occi::Core::Errors::ParsingError, "#{self} -> JSON parsing failed: #{ex.message}"
13
+ raise Occi::Core::Errors::ParsingError, "JSON parsing failed: #{ex.message}"
14
14
  end
15
15
  end
16
16
  end
@@ -55,7 +55,7 @@ module Occi
55
55
  # @param base [Class] class receiving this module
56
56
  def self.included(base)
57
57
  renderer_factory.formats.each do |format|
58
- base.logger.debug "Renderable: Adding support for #{format} to #{base}" if base.respond_to?(:logger)
58
+ base.logger.debug "Adding support for format #{format} to #{base}" if base.respond_to?(:logger)
59
59
  base.send(:define_method, "to_#{format}", proc { render(format) })
60
60
  end
61
61
  end
@@ -25,7 +25,7 @@ module Occi
25
25
  raise 'This method cannot be invoked on instances' unless is_a? Class
26
26
  allowed_classes = respond_to?(:allowed_yaml_classes, true) ? allowed_yaml_classes : []
27
27
 
28
- logger.debug "#{self}: Loading YAML definition from #{path.inspect}"
28
+ logger.debug "Loading YAML definition for #{self} from #{path.inspect}"
29
29
  object_args = YAML.safe_load(File.read(path), allowed_classes)
30
30
  object_args.symbolize_keys!
31
31
  object_args.dereference_with!(self, model, attribute_definitions) if needs_dereferencing?
@@ -42,7 +42,7 @@ module Occi
42
42
  # @return [Object] constructed instance
43
43
  # @return [NilClass] if such an instance could not be constructed
44
44
  def build(identifier, args = {})
45
- logger.debug "#{self.class}: Building instance of #{identifier.inspect} with #{args.inspect}"
45
+ logger.debug "Building instance of #{identifier.inspect} with #{args.inspect}"
46
46
  k_args = args_with_kind(identifier, args)
47
47
  klass(identifier, parent_klass(k_args[:kind])).new k_args
48
48
  end
@@ -93,7 +93,7 @@ module Occi
93
93
  "#{found_klass} is not a sub-type of #{known_ancestor}"
94
94
  end
95
95
 
96
- logger.debug "#{self.class}: Found #{found_klass} for #{identifier.inspect}"
96
+ logger.debug "Found class #{found_klass} for #{identifier.inspect}"
97
97
  found_klass
98
98
  end
99
99
 
@@ -119,10 +119,10 @@ module Occi
119
119
  # @return [Class] located known parent class
120
120
  def parent_klass(kind)
121
121
  if kind.related? kind_instance(Occi::Core::Constants::RESOURCE_KIND)
122
- logger.debug "#{self.class}: Identified #{kind.identifier} as Resource"
122
+ logger.debug "Identified #{kind.identifier} as Resource"
123
123
  Occi::Core::Resource
124
124
  elsif kind.related? kind_instance(Occi::Core::Constants::LINK_KIND)
125
- logger.debug "#{self.class}: Identified #{kind.identifier} as Link"
125
+ logger.debug "Identified #{kind.identifier} as Link"
126
126
  Occi::Core::Link
127
127
  else
128
128
  raise Occi::Core::Errors::ModelLookupError,
@@ -242,7 +242,7 @@ module Occi
242
242
  # model = Occi::Core::Model.new
243
243
  # model.load_core!
244
244
  def load_core!
245
- logger.debug "#{self.class}: Loading Core from Warehouse"
245
+ logger.debug 'Loading Core definitions from Core::Warehouse'
246
246
  Occi::Core::Warehouse.bootstrap! self
247
247
  end
248
248
 
@@ -18,6 +18,10 @@ module Occi
18
18
 
19
19
  attr_accessor :model, :media_type
20
20
 
21
+ # Shortcuts to interesting methods on logger
22
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
23
+ delegate(*DELEGATED, to: :logger, prefix: true)
24
+
21
25
  # Constructs an instance of the parser that will use a particular model as the reference for every
22
26
  # parsed instance. Only instances allowed by the model will be successfuly parsed. In case of
23
27
  # `Occi::Core::Category` instances, only identifiers are parsed and existing instances from the model
@@ -32,6 +36,7 @@ module Occi
32
36
 
33
37
  @model = args.fetch(:model)
34
38
  @media_type = args.fetch(:media_type)
39
+ logger.debug "Initializing parser for #{media_type.inspect}"
35
40
 
36
41
  post_initialize(args)
37
42
  end
@@ -112,12 +117,16 @@ module Occi
112
117
  def lookup(identifier, klass)
113
118
  found = handle(Occi::Core::Errors::ParsingError) { model.find_by_identifier!(identifier) }
114
119
  unless found.is_a?(klass)
115
- raise Occi::Core::Errors::ParsingError, "#{self.class} -> #{identifier.inspect} isn't #{klass}"
120
+ raise Occi::Core::Errors::ParsingError, "#{identifier.inspect} is not of expected class #{klass}"
116
121
  end
117
122
  found
118
123
  end
119
124
 
120
125
  class << self
126
+ # Shortcuts to interesting methods on logger
127
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
128
+ delegate(*DELEGATED, to: :logger, prefix: true)
129
+
121
130
  # Returns a list of supported media types for this parser.
122
131
  #
123
132
  # @return [Array] list of supported media types
@@ -12,6 +12,10 @@ module Occi
12
12
  extend Helpers::RawJsonParser
13
13
 
14
14
  class << self
15
+ # Shortcuts to interesting methods on logger
16
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
17
+ delegate(*DELEGATED, to: :logger, prefix: true)
18
+
15
19
  # Parses action instances. Internal references between objects are converted from strings
16
20
  # to actual objects. Actions have to be declared in the provided model.
17
21
  #
@@ -20,12 +24,14 @@ module Occi
20
24
  # @return [Occi::Core::ActionInstance] action instance
21
25
  def json(body, model)
22
26
  parsed = raw_hash(body)
23
- ep = Entity.new(model: model)
27
+ action = handle(Occi::Core::Errors::ParsingError) { model.find_by_identifier! parsed[:action] }
24
28
 
25
- action = handle(Occi::Core::Errors::ParsingError) { model.find_by_identifier!(parsed[:action]) }
29
+ logger.debug "Identified #{action.class}[#{action.identifier}]"
26
30
  ai = Occi::Core::ActionInstance.new(action: action)
31
+ ep = Entity.new(model: model)
27
32
  ep.set_attributes!(ai.attributes, parsed[:attributes]) if parsed[:attributes]
28
33
 
34
+ logger.debug "Parsed into ActionInstance #{ai.inspect}" if logger_debug?
29
35
  ai
30
36
  end
31
37
  end
@@ -27,6 +27,10 @@ module Occi
27
27
  DEPENDS_KEY = :depends
28
28
 
29
29
  class << self
30
+ # Shortcuts to interesting methods on logger
31
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
32
+ delegate(*DELEGATED, to: :logger, prefix: true)
33
+
30
34
  # Parses categories into instances of subtypes of `Occi::Core::Category`. Internal references
31
35
  # between objects are converted from strings to actual objects. Categories provided in the model
32
36
  # will be reused but have to be declared in the parsed model as well.
@@ -37,10 +41,12 @@ module Occi
37
41
  def json(body, model)
38
42
  parsed = raw_hash(body)
39
43
  instantiate_hashes! parsed, model
44
+ logger.debug "Parsed into raw hashes #{parsed.inspect}" if logger_debug?
40
45
 
41
46
  raw_categories = [parsed[:kinds], parsed[:mixins]].flatten.compact
42
47
  dereference_identifiers! model.categories, raw_categories
43
48
 
49
+ logger.debug "Returning (updated) model #{model.inspect}" if logger_debug?
44
50
  model
45
51
  end
46
52
 
@@ -53,15 +59,19 @@ module Occi
53
59
 
54
60
  # :nodoc:
55
61
  def instatiate_hash(raw, klass)
62
+ logger.debug "Creating #{klass} from #{raw.inspect}" if logger_debug?
63
+
56
64
  obj = klass.new(
57
65
  term: raw[:term], schema: raw[:scheme], title: raw[:title],
58
66
  attributes: attribute_definitions(raw[:attributes])
59
67
  )
60
68
 
61
69
  if obj.respond_to?(:location)
70
+ logger.debug "Setting location #{raw[:location].inspect}" if logger_debug?
62
71
  obj.location = handle(Occi::Core::Errors::ParsingError) { URI.parse(raw[:location]) }
63
72
  end
64
73
 
74
+ logger.debug "Created category #{obj.inspect}" if logger_debug?
65
75
  obj
66
76
  end
67
77
 
@@ -71,9 +81,10 @@ module Occi
71
81
 
72
82
  attr_defs = {}
73
83
  raw.each_pair do |k, v|
84
+ logger.debug "Creating AttributeDefinition for #{k.inspect} from #{v.inspect}" if logger_debug?
74
85
  def_hsh = typecast(v)
75
86
  unless def_hsh[:type]
76
- raise Occi::Core::Errors::ParsingError, "#{self} -> Attribute #{k.to_s.inspect} has no type"
87
+ raise Occi::Core::Errors::ParsingError, "Attribute #{k.to_s.inspect} has no type"
77
88
  end
78
89
  attr_defs[k.to_s] = Occi::Core::AttributeDefinition.new def_hsh
79
90
  end
@@ -85,18 +96,23 @@ module Occi
85
96
  def typecast(hash)
86
97
  hash = hash.clone
87
98
  hash[:type] = TYPECASTER_HASH[hash[:type]]
88
- hash[:pattern] = handle(Occi::Core::Errors::ParsingError) { Regexp.new(hash[:pattern]) } if hash[:pattern]
99
+
100
+ return hash if hash[:pattern].blank?
101
+ hash[:pattern] = handle(Occi::Core::Errors::ParsingError) { Regexp.new(hash[:pattern]) }
102
+
89
103
  hash
90
104
  end
91
105
 
92
106
  # :nodoc:
93
107
  def lookup_applies_references!(mixin, derefd, parsed_rel)
108
+ logger.debug "Looking up applies from #{parsed_rel.inspect}" if logger_debug?
94
109
  return if parsed_rel.blank?
95
110
  parsed_rel.each { |kind| mixin.applies << first_or_die(derefd, kind) }
96
111
  end
97
112
 
98
113
  # :nodoc:
99
114
  def lookup_depends_references!(mixin, derefd, parsed_rel)
115
+ logger.debug "Looking up depens from #{parsed_rel.inspect}" if logger_debug?
100
116
  return if parsed_rel.blank?
101
117
  parsed_rel.each { |mxn| mixin.depends << first_or_die(derefd, mxn) }
102
118
  end
@@ -14,6 +14,10 @@ module Occi
14
14
  include Helpers::ErrorHandler
15
15
  extend Helpers::RawJsonParser
16
16
 
17
+ # Shortcuts to interesting methods on logger
18
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
19
+ delegate(*DELEGATED, to: :logger, prefix: true)
20
+
17
21
  # Constants
18
22
  SINGLE_INSTANCE_TYPES = %i[resource link].freeze
19
23
  MULTI_INSTANCE_TYPES = %i[entity-collection].freeze
@@ -46,14 +50,16 @@ module Occi
46
50
  # @param type [Symbol] `:resource`, `:link`, or `:'entity-collection'`
47
51
  # @return [Array] constructed instances
48
52
  def json(body, type)
49
- case type
50
- when *SINGLE_INSTANCE_TYPES
51
- json_single self.class.raw_hash(body)
52
- when *MULTI_INSTANCE_TYPES
53
- json_collection self.class.raw_hash(body)
54
- else
55
- raise Occi::Core::Errors::ParserError, "#{self.class} -> #{type.to_s.inspect} is not a valid type"
56
- end
53
+ symbol = case type
54
+ when *SINGLE_INSTANCE_TYPES
55
+ :json_single
56
+ when *MULTI_INSTANCE_TYPES
57
+ :json_collection
58
+ else
59
+ raise Occi::Core::Errors::ParserError, "#{type.inspect} is not a valid type"
60
+ end
61
+
62
+ send symbol, self.class.raw_hash(body)
57
63
  end
58
64
 
59
65
  # Builds an entity instance from the hash provided as input.
@@ -61,12 +67,14 @@ module Occi
61
67
  # @param hash [Hash] Hash body for parsing
62
68
  # @return [Array] constructed instances
63
69
  def json_single(hash)
70
+ logger.debug "Converting #{hash.inspect} into a single instance" if logger_debug?
64
71
  instance = @_ib.get hash[:kind], mixins: lookup(hash[:mixins]), actions: lookup(hash[:actions])
65
72
 
66
73
  set_attributes! instance.attributes, hash[:attributes]
67
74
  set_links! instance.links, hash[:links] if instance.respond_to?(:links)
68
75
  set_target! instance, hash[:target] if instance.respond_to?(:target)
69
76
 
77
+ logger.debug "Created instance #{instance.inspect}" if logger_debug?
70
78
  Set.new [instance]
71
79
  end
72
80
 
@@ -77,10 +85,12 @@ module Occi
77
85
  def json_collection(hash)
78
86
  all = []
79
87
 
88
+ logger.debug "Converting #{hash.inspect} into multiple instances" if logger_debug?
80
89
  all.concat hash[:resources] if hash[:resources]
81
90
  all.concat hash[:links] if hash[:links]
82
91
  all.map! { |a| json_single(a) }
83
92
 
93
+ logger.debug "Created instances #{all.inspect}" if logger_debug?
84
94
  Set.new(all).flatten
85
95
  end
86
96
 
@@ -96,10 +106,11 @@ module Occi
96
106
  def set_attributes!(attributes, hash)
97
107
  return if hash.blank?
98
108
  hash.each_pair do |name, value|
109
+ logger.debug "Setting attribute #{name} to #{value.inspect}" if logger_debug?
99
110
  attribute = attributes[name.to_s]
100
111
  unless attribute
101
112
  raise Occi::Core::Errors::ParsingError,
102
- "#{self.class} -> attribute #{name.to_s.inspect} is not allowed for this entity"
113
+ "Attribute #{name.inspect} is not allowed for this entity"
103
114
  end
104
115
  attribute.value = typecast(value, attribute.attribute_definition.type)
105
116
  end
@@ -121,11 +132,11 @@ module Occi
121
132
  # :nodoc:
122
133
  def typecast(value, type)
123
134
  if value.nil? || type.nil?
124
- raise Occi::Core::Errors::ParsingError,
125
- "#{self.class} -> Cannot typecast (un)set value to (un)set type"
135
+ raise Occi::Core::Errors::ParsingError, 'Cannot typecast (un)set value to (un)set type'
126
136
  end
127
137
  return value unless TYPECASTER_HASH.key?(type)
128
138
 
139
+ logger.debug "Typecasting value #{value.inspect} to #{type}" if logger_debug?
129
140
  TYPECASTER_HASH[type].call(value)
130
141
  end
131
142
 
@@ -7,12 +7,18 @@ module Occi
7
7
  #
8
8
  # @author Boris Parak <parak@cesnet.cz>
9
9
  class Validator
10
+ include Yell::Loggable
11
+
10
12
  # Repository constants
11
13
  SCHEMA_DIR = 'validator'.freeze
12
14
  SCHEMA_REPO = File.join(File.expand_path(File.dirname(__FILE__)), SCHEMA_DIR)
13
15
  BASE_SCHEMAS = %i[occi-schema].freeze
14
16
 
15
17
  class << self
18
+ # Shortcuts to interesting methods on logger
19
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
20
+ delegate(*DELEGATED, to: :logger, prefix: true)
21
+
16
22
  # Validates given `json` text with the appropriate schema for `type`.
17
23
  # This method raises `Occi::Core::Errors::ParsingError` on failure.
18
24
  #
@@ -20,10 +26,12 @@ module Occi
20
26
  # @param type [Symbol] schema selector
21
27
  # @raise [Occi::Core::Errors::ParsingError] on validation failure
22
28
  def validate!(json, type)
29
+ logger.debug "Validating #{json.inspect} as #{type}" if logger_debug?
30
+
23
31
  JSON::Validator.schema_reader = JSON::Schema::Reader.new(accept_uri: false, accept_file: true)
24
32
  JSON::Validator.validate!(schema_for(type), json, json: true)
25
33
  rescue JSON::Schema::JsonParseError, JSON::Schema::ValidationError => e
26
- raise Occi::Core::Errors::ParsingError, "#{self} -> #{e.message}"
34
+ raise Occi::Core::Errors::ParsingError, e.message
27
35
  end
28
36
 
29
37
  # :nodoc:
@@ -66,7 +74,10 @@ module Occi
66
74
  if type.blank? || BASE_SCHEMAS.include?(type)
67
75
  raise Occi::Core::Errors::ParserError, "Schema type #{type.inspect} is not allowed"
68
76
  end
69
- File.join(SCHEMA_REPO, "#{type}.json")
77
+ schema_path = File.join(SCHEMA_REPO, "#{type}.json")
78
+ logger.debug "Found JSON schema for #{type} in #{schema_path}" if logger_debug?
79
+
80
+ schema_path
70
81
  end
71
82
  private :schema_for
72
83
  end
@@ -34,13 +34,14 @@ module Occi
34
34
  # @return [Set] set of instances
35
35
  def entities(body, _headers = nil, expectation = nil)
36
36
  expectation ||= Occi::Core::Entity
37
+ logger.debug "Parsing #{expectation}(s) from #{body.inspect}" if logger_debug?
37
38
  type = validate_entities! body
38
39
 
39
40
  entity_parser = Json::Entity.new(model: model)
40
41
  entities = entity_parser.json body, type
41
42
  entities.each do |entity|
42
43
  unless entity.is_a?(expectation)
43
- raise Occi::Core::Errors::ParsingError, "#{self.class} -> Given entity isn't #{expectation}"
44
+ raise Occi::Core::Errors::ParsingError, "Entity is not of type #{expectation}"
44
45
  end
45
46
  end
46
47
 
@@ -54,6 +55,7 @@ module Occi
54
55
  # @param headers [Hash] raw headers as provided by the transport protocol
55
56
  # @return [Set] set of parsed instances
56
57
  def action_instances(body, _headers = nil)
58
+ logger.debug "Parsing Occi::Core::ActionInstance(s) from #{body.inspect}" if logger_debug?
57
59
  Json::Validator.validate_action_instance! body
58
60
  Set.new [Json::ActionInstance.json(body, model)]
59
61
  end
@@ -67,6 +69,7 @@ module Occi
67
69
  # @return [Set] set of instances
68
70
  def categories(body, _headers = nil, expectation = nil)
69
71
  expectation ||= Occi::Core::Category
72
+ logger.debug "Parsing #{expectation}(s) from #{body.inspect}" if logger_debug?
70
73
  Json::Validator.validate_category_identifiers! body
71
74
 
72
75
  cats = Set.new
@@ -81,14 +84,15 @@ module Occi
81
84
  found = nil
82
85
 
83
86
  %i[link resource entity-collection].each do |type|
87
+ logger.debug "Attempting to validate #{body.inspect} as #{type}" if logger_debug?
84
88
  begin
85
89
  Json::Validator.validate! body, type
86
90
  found = type
87
91
  rescue => ex
88
- logger.debug "#{self.class}: Body isn't #{type} - #{ex.message}"
92
+ logger.debug "Moving on, body does not contain valid #{type} - #{ex.message.inspect}"
89
93
  end
90
94
  end
91
- raise Occi::Core::Errors::ParsingError, "#{self.class} -> No entity sub-type instance found" unless found
95
+ raise Occi::Core::Errors::ParsingError, 'No acceptable entity rendering found' unless found
92
96
 
93
97
  found
94
98
  end
@@ -105,10 +109,13 @@ module Occi
105
109
  def model(body, _headers, media_type, model)
106
110
  unless media_types.include?(media_type)
107
111
  raise Occi::Core::Errors::ParsingError,
108
- "#{self} -> model cannot be parsed from #{media_type.inspect}"
112
+ "Model cannot be parsed from #{media_type.inspect}"
109
113
  end
114
+ logger.debug "Parsing model from #{media_type.inspect} in #{body.inspect}" if logger_debug?
115
+
110
116
  Json::Validator.validate_model! body
111
117
  Json::Category.json body, model
118
+
112
119
  model
113
120
  end
114
121
 
@@ -120,9 +127,10 @@ module Occi
120
127
  # @return [Array] list of extracted URIs
121
128
  def locations(body, _headers, media_type)
122
129
  unless media_types.include?(media_type)
123
- raise Occi::Core::Errors::ParsingError,
124
- "#{self} -> locations cannot be parsed from #{media_type.inspect}"
130
+ raise Occi::Core::Errors::ParsingError, "Locations cannot be parsed from #{media_type.inspect}"
125
131
  end
132
+ logger.debug "Parsing locations from #{media_type.inspect} in #{body.inspect}" if logger_debug?
133
+
126
134
  Json::Validator.validate_locations! body
127
135
  handle(Occi::Core::Errors::ParsingError) { JSON.parse(body).map { |i| URI.parse(i) } }
128
136
  end
@@ -20,6 +20,10 @@ module Occi
20
20
  DEPENDS_KEY = :rel
21
21
 
22
22
  class << self
23
+ # Shortcuts to interesting methods on logger
24
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
25
+ delegate(*DELEGATED, to: :logger, prefix: true)
26
+
23
27
  # Parses category lines into instances of subtypes of `Occi::Core::Category`. Internal references
24
28
  # between objects are converted from strings to actual objects. Categories provided in the model
25
29
  # will be reused but have to be declared in the parsed model as well. This mechanism can be used to
@@ -37,6 +41,7 @@ module Occi
37
41
  end
38
42
  dereference_identifiers! model.categories, raw_categories
39
43
 
44
+ logger.debug "Returning (updated) model #{model.inspect}" if logger_debug?
40
45
  model
41
46
  end
42
47
 
@@ -47,19 +52,33 @@ module Occi
47
52
  # @param full [TrueClass, FalseClass] parse full definition, defaults to `true`
48
53
  # @return [Hash] raw category hash for further processing
49
54
  def plain_category(line, full = true)
55
+ logger.debug "Parsing line #{line.inspect}" if logger_debug?
50
56
  matched = line.match(CATEGORY_REGEXP)
51
57
  unless matched
52
- raise Occi::Core::Errors::ParsingError,
53
- "#{self} -> #{line.inspect} does not match expectations for Category"
58
+ raise Occi::Core::Errors::ParsingError, "#{line.inspect} does not match expectations for Category"
54
59
  end
55
60
 
56
61
  cat = matchdata_to_hash(matched)
57
- return cat unless full
62
+ full ? plain_category_extended(cat) : plain_category_partial(cat)
63
+ end
58
64
 
65
+ # Cleans up partially parsed hash. Removes all potentially inconsitent or unfinished data structures.
66
+ #
67
+ # @param cat [Hash] partially parsed hash
68
+ # @return [Hash] clean partially parsed hash
69
+ def plain_category_partial(cat)
70
+ %i[attributes rel actions].each { |el| cat[el] = nil }
71
+ cat
72
+ end
73
+
74
+ # Finishes parsing of attributes, actions, and referenced categories.
75
+ #
76
+ # @param cat [Hash] partially parsed hash
77
+ # @return [Hash] fully parsed hash
78
+ def plain_category_extended(cat)
59
79
  cat[:attributes] = plain_attributes(cat[:attributes]) if cat[:attributes]
60
80
  cat[:rel] = plain_identifiers(cat[:rel]) if cat[:rel]
61
81
  cat[:actions] = plain_identifiers(cat[:actions]) if cat[:actions]
62
-
63
82
  cat
64
83
  end
65
84
 
@@ -77,6 +96,7 @@ module Occi
77
96
 
78
97
  attributes = {}
79
98
  line.split.each { |attribute| attributes.merge! plain_attribute(attribute) }
99
+ logger.debug "Matched attributes as #{attributes.inspect}" if logger_debug?
80
100
 
81
101
  attributes
82
102
  end
@@ -92,11 +112,12 @@ module Occi
92
112
  def plain_attribute(line)
93
113
  # TODO: find a better approach to fixing split
94
114
  line.gsub!(/\{(immutable|required)_(required|immutable)\}/, '{\1 \2}')
115
+ logger.debug "Parsing attribute line #{line.inspect}" if logger_debug?
95
116
 
96
117
  matched = line.match(ATTRIBUTE_REGEXP)
97
118
  unless matched && matched[1]
98
119
  raise Occi::Core::Errors::ParsingError,
99
- "#{self} -> #{line.inspect} does not match expectations for Attribute"
120
+ "#{line.inspect} does not match expectations for Attribute"
100
121
  end
101
122
 
102
123
  { matched[1] => plain_attribute_definition(matched[-2]) }
@@ -4,7 +4,7 @@ module Occi
4
4
  module Text
5
5
  module Constants
6
6
  # Base regular expressions
7
- REGEXP_QUOTED_STRING = /([^"\\]|\\.)*/
7
+ REGEXP_QUOTED_STRING = /([^\\"]|\\\\|\\")*/
8
8
  REGEXP_LOALPHA = /[a-z]/
9
9
  REGEXP_ALPHA = /[a-zA-Z]/
10
10
  REGEXP_DIGIT = /[0-9]/
@@ -13,6 +13,10 @@ module Occi
13
13
  include Helpers::ArgumentValidator
14
14
  include Helpers::ErrorHandler
15
15
 
16
+ # Shortcuts to interesting methods on logger
17
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
18
+ delegate(*DELEGATED, to: :logger, prefix: true)
19
+
16
20
  # Regexp constants
17
21
  ATTRIBUTE_REGEXP = /#{Constants::REGEXP_ATTRIBUTE}/
18
22
  LINK_REGEXP = /#{Constants::REGEXP_LINK}/
@@ -57,7 +61,8 @@ module Occi
57
61
  def plain(lines)
58
62
  cats = plain_categories(lines)
59
63
  kind = cats.detect { |c| c.is_a?(Occi::Core::Kind) }
60
- raise Occi::Core::Errors::ParsingError, "#{self.class} -> Entity does not specify its kind" unless kind
64
+ raise Occi::Core::Errors::ParsingError, 'Entity does not specify its kind' unless kind
65
+ logger.debug "Identified entity kind #{kind.inspect}" if logger_debug?
61
66
 
62
67
  entity = @_ib.build(kind.identifier)
63
68
  cats.each { |cat| cat.is_a?(Occi::Core::Mixin) && entity << cat }
@@ -65,6 +70,7 @@ module Occi
65
70
  plain_attributes! lines, entity.attributes
66
71
  plain_links! lines, entity
67
72
 
73
+ logger.debug "Created instance #{entity.inspect}" if logger_debug?
68
74
  entity
69
75
  end
70
76
 
@@ -73,11 +79,12 @@ module Occi
73
79
  # @param lines [Array] list of lines containing a single entity rendering
74
80
  # @return [Array] list of identified category instances
75
81
  def plain_categories(lines)
76
- lines.map do |line|
82
+ categories = lines.map do |line|
77
83
  next unless line.start_with?(TextParser::CATEGORY_KEYS.first)
78
84
  cat = Category.plain_category(line, false)
79
85
  handle(Occi::Core::Errors::ParsingError) { model.find_by_identifier!("#{cat[:scheme]}#{cat[:term]}") }
80
- end.compact
86
+ end
87
+ categories.compact
81
88
  end
82
89
 
83
90
  # Parses attributes from entity lines. Every attribute value is typed according to the attribute
@@ -89,15 +96,18 @@ module Occi
89
96
  def plain_attributes!(lines, attributes)
90
97
  lines.each do |line|
91
98
  next unless line.start_with?(TextParser::ATTRIBUTE_KEYS.first)
99
+
92
100
  name, value = raw_attribute(line)
93
101
  unless attributes[name]
94
102
  raise Occi::Core::Errors::ParsingError,
95
- "#{self.class} -> attribute #{name.inspect} is not allowed for this entity"
103
+ "Attribute #{name.inspect} is not allowed for this entity"
96
104
  end
105
+
97
106
  attributes[name].value = handle(Occi::Core::Errors::ParsingError) do
98
107
  typecast value, attributes[name].attribute_definition.type
99
108
  end
100
109
  end
110
+
101
111
  attributes
102
112
  end
103
113
 
@@ -106,10 +116,10 @@ module Occi
106
116
  # @param line [String] line containing a single entity attribute
107
117
  # @return [Array] two-element array with name and value of the attribute
108
118
  def raw_attribute(line)
119
+ logger.debug "Parsing attribute line #{line.inspect}" if logger_debug?
109
120
  matched = line.match(ATTRIBUTE_REGEXP)
110
121
  unless matched
111
- raise Occi::Core::Errors::ParsingError,
112
- "#{self.class} -> #{line.inspect} does not match expectations for Attribute"
122
+ raise Occi::Core::Errors::ParsingError, "#{line.inspect} does not match expectations for Attribute"
113
123
  end
114
124
  [matched[:name], matched[:string] || matched[:number] || matched[:bool]]
115
125
  end
@@ -123,13 +133,16 @@ module Occi
123
133
  def plain_links!(lines, entity)
124
134
  lines.each do |line|
125
135
  next unless line.start_with?(TextParser::LINK_KEYS.first)
136
+ logger.debug "Parsing link line #{line.inspect}" if logger_debug?
137
+
126
138
  matched = line.match(LINK_REGEXP)
127
139
  unless matched
128
- raise Occi::Core::Errors::ParsingError,
129
- "#{self.class} -> #{line.inspect} does not match expectations for Link"
140
+ raise Occi::Core::Errors::ParsingError, "#{line.inspect} does not match expectations for Link"
130
141
  end
142
+
131
143
  plain_link! matched, entity
132
144
  end
145
+
133
146
  entity
134
147
  end
135
148
 
@@ -157,7 +170,7 @@ module Occi
157
170
  def plain_oglink!(md, entity)
158
171
  unless entity.respond_to?(:links)
159
172
  raise Occi::Core::Errors::ParsingError,
160
- "#{self.class} -> Cannot assign links to entity #{entity.id} which does not support them"
173
+ "Cannot assign links to entity #{entity.id} which does not support them"
161
174
  end
162
175
 
163
176
  link = plain_oglink_instance(md)
@@ -169,24 +182,25 @@ module Occi
169
182
  entity
170
183
  end
171
184
 
172
- # Constructs a single link instance based on the provided data. The returned instance does include contain
185
+ # Constructs a single link instance based on the provided data. The returned instance does include
173
186
  # action instance attributes!
174
187
  #
175
188
  # @param md [MatchData] Hash-like structure with matched parts of the link
176
189
  # @return [Occi::Core::Link] constructed link instance
177
190
  def plain_oglink_instance(md)
178
191
  if md[:category].blank? || md[:self].blank?
179
- raise Occi::Core::Errors::ParsingError,
180
- "#{self.class} -> Link #{md[:uri].inspect} is missing type and location information"
192
+ raise Occi::Core::Errors::ParsingError, "Link #{md[:uri].inspect} missing type and location information"
181
193
  end
182
194
 
183
195
  categories = md[:category].split
184
196
  target_kind = handle(Occi::Core::Errors::ParsingError) { model.find_by_identifier!(md[:rel]) }
185
197
  link = @_ib.build(categories.shift, target_kind: target_kind)
186
198
  categories.each do |mxn|
199
+ logger.debug "Adding mixin #{mxn.inspect} to link instance" if logger_debug?
187
200
  link << handle(Occi::Core::Errors::ParsingError) { model.find_by_identifier!(mxn) }
188
201
  end
189
202
 
203
+ logger.debug "Created link instance #{link.inspect} from #{md.inspect}" if logger_debug?
190
204
  link
191
205
  end
192
206
 
@@ -196,13 +210,16 @@ module Occi
196
210
  # @param link [Occi::Core::Link] partially constructed link instance to be updated
197
211
  def plain_oglink_attributes!(md, link)
198
212
  if md[:attributes].blank?
199
- raise Occi::Core::Errors::ParsingError,
200
- "#{self.class} -> Link #{link.id} is missing attribute information"
213
+ raise Occi::Core::Errors::ParsingError, "Link #{link.id} is missing attribute information"
201
214
  end
215
+ logger.debug "Parsing inline link attributes from line #{md[:attributes].inspect}" if logger_debug?
202
216
 
217
+ regexp = Regexp.new "(\\s*#{Constants::REGEXP_ATTRIBUTE_REPR})"
203
218
  line = md[:attributes].strip.gsub(/^;\s*/, '')
204
- attrs = line.split(';').map { |attrb| "#{TextParser::ATTRIBUTE_KEYS.first}: #{attrb}" }
205
- plain_attributes! attrs, link.attributes
219
+ plain_attributes!(
220
+ line.scan(regexp).map { |attrb| "#{TextParser::ATTRIBUTE_KEYS.first}: #{attrb.first}" },
221
+ link.attributes
222
+ )
206
223
 
207
224
  link
208
225
  end
@@ -214,10 +231,10 @@ module Occi
214
231
  # @return [Object] typecasted value
215
232
  def typecast(value, type)
216
233
  if value.nil? || type.nil?
217
- raise Occi::Core::Errors::ParsingError,
218
- "#{self.class} -> Cannot typecast (un)set value to (un)set type"
234
+ raise Occi::Core::Errors::ParsingError, 'Cannot typecast (un)set value to (un)set type'
219
235
  end
220
236
 
237
+ logger.debug "Typecasting value #{value.inspect} to #{type}" if logger_debug?
221
238
  self.class.typecaster[type].call(value)
222
239
  end
223
240
 
@@ -11,6 +11,10 @@ module Occi
11
11
  include Helpers::ErrorHandler
12
12
 
13
13
  class << self
14
+ # Shortcuts to interesting methods on logger
15
+ DELEGATED = %i[debug? info? warn? error? fatal?].freeze
16
+ delegate(*DELEGATED, to: :logger, prefix: true)
17
+
14
18
  # Parses text/plain OCCI locations into `URI` instances suitable for futher processing.
15
19
  # Every location line is expected to begin with 'X-OCCI-Location'.
16
20
  #
@@ -18,15 +22,19 @@ module Occi
18
22
  # @return [Array] list of locations (URIs)
19
23
  def plain(lines)
20
24
  regexp = Regexp.new(Constants::REGEXP_LOCATION)
21
- lines.map do |line|
25
+
26
+ locations = lines.map do |line|
22
27
  next if line.blank?
28
+ logger.debug "Parsing location from line #{line.inspect}" if logger_debug?
29
+
23
30
  matched = line.match(regexp)
24
31
  unless matched
25
- raise Occi::Core::Errors::ParsingError,
26
- "#{self} -> #{line.inspect} does not match 'X-OCCI-Location: URI'"
32
+ raise Occi::Core::Errors::ParsingError, "#{line.inspect} does not match 'X-OCCI-Location: URI'"
27
33
  end
28
34
  handle(Occi::Core::Errors::ParsingError) { URI.parse(matched[:location].strip) }
29
- end.compact
35
+ end
36
+
37
+ locations.compact
30
38
  end
31
39
 
32
40
  # Parses text/uri-list lines into `URI` instances suitable for futher processing.
@@ -35,10 +43,14 @@ module Occi
35
43
  # @param lines [Array] list of lines to parse
36
44
  # @return [Array] list of locations (URIs)
37
45
  def uri_list(lines)
38
- lines.map do |line|
46
+ uris = lines.map do |line|
39
47
  next if line.blank? || line.start_with?('#')
48
+ logger.debug "Parsing location from line #{line.inspect}" if logger_debug?
49
+
40
50
  handle(Occi::Core::Errors::ParsingError) { URI.parse(line.strip) }
41
- end.compact
51
+ end
52
+
53
+ uris.compact
42
54
  end
43
55
  end
44
56
  end
@@ -50,14 +50,15 @@ module Occi
50
50
  # @return [Set] set of instances
51
51
  def entities(body, headers, expectation = nil)
52
52
  expectation ||= Occi::Core::Entity
53
+ logger.debug "Parsing #{expectation} from #{body.inspect} and #{headers.inspect}" if logger_debug?
53
54
 
54
55
  entity_parser = Text::Entity.new(model: model)
55
56
  entity = entity_parser.plain transform(body, headers)
56
57
  unless entity.is_a?(expectation)
57
- raise Occi::Core::Errors::ParsingError, "#{self.class} -> Given entity isn't #{expectation}"
58
+ raise Occi::Core::Errors::ParsingError, "Entity is not of type #{expectation}"
58
59
  end
59
60
 
60
- Set.new([entity].compact)
61
+ setify(entity)
61
62
  end
62
63
 
63
64
  # Parses action instances from the given body/headers. Only actions already declared in the model are
@@ -67,16 +68,15 @@ module Occi
67
68
  # @param headers [Hash] raw headers as provided by the transport protocol
68
69
  # @return [Set] set of parsed instances
69
70
  def action_instances(body, headers)
71
+ logger.debug "Parsing Occi::Core::ActionInstance from #{body.inspect} and #{headers.inspect}" if logger_debug?
70
72
  entity_parser = Text::Entity.new(model: model)
71
73
  tformed = transform(body, headers)
72
74
 
73
- cats = entity_parser.plain_categories tformed
74
- action = cats.detect { |c| c.is_a? Occi::Core::Action }
75
- raise Occi::Core::Errors::ParsingError, "#{self.class} -> AI does not specify action" unless action
76
-
77
- ai = Occi::Core::ActionInstance.new(action: action)
78
- entity_parser.plain_attributes! tformed, ai.attributes
79
- Set.new([ai].compact)
75
+ action_instance = Occi::Core::ActionInstance.new(
76
+ action: action_instance_category(entity_parser, tformed)
77
+ )
78
+ entity_parser.plain_attributes! tformed, action_instance.attributes
79
+ setify(action_instance)
80
80
  end
81
81
 
82
82
  # Parses categories from the given body/headers and returns corresponding instances
@@ -88,11 +88,14 @@ module Occi
88
88
  # @return [Set] set of instances
89
89
  def categories(body, headers, expectation = nil)
90
90
  expectation ||= Occi::Core::Category
91
+ logger.debug "Parsing #{expectation} from #{body.inspect} and #{headers.inspect}" if logger_debug?
92
+
91
93
  cats = transform(body, headers).map do |line|
92
94
  cat = Text::Category.plain_category(line, false)
93
95
  lookup "#{cat[:scheme]}#{cat[:term]}", expectation
94
96
  end
95
- Set.new(cats)
97
+
98
+ setify(cats)
96
99
  end
97
100
 
98
101
  # Transforms `body` and `headers` into an array of lines parsable by 'text/plain'
@@ -116,13 +119,16 @@ module Occi
116
119
  # @param model [Occi::Core::Model] `Model`-like instance to be populated (may contain existing categories)
117
120
  # @return [Occi::Core::Model] model instance filled with parsed categories
118
121
  def model(body, headers, media_type, model)
122
+ if logger_debug?
123
+ logger.debug "Parsing model from #{media_type.inspect} in #{body.inspect} and #{headers.inspect}"
124
+ end
125
+
119
126
  if HEADERS_TEXT_TYPES.include? media_type
120
127
  Text::Category.plain transform_headers(headers), model
121
128
  elsif PLAIN_TEXT_TYPES.include? media_type
122
129
  Text::Category.plain transform_body(body), model
123
130
  else
124
- raise Occi::Core::Errors::ParsingError,
125
- "#{self} -> model cannot be parsed from #{media_type.inspect}"
131
+ raise Occi::Core::Errors::ParsingError, "Model cannot be parsed from #{media_type.inspect}"
126
132
  end
127
133
  end
128
134
 
@@ -133,6 +139,10 @@ module Occi
133
139
  # @param media_type [String] media type string as provided by the transport protocol
134
140
  # @return [Array] list of extracted URIs
135
141
  def locations(body, headers, media_type)
142
+ if logger_debug?
143
+ logger.debug "Parsing locations from #{media_type.inspect} in #{body.inspect} and #{headers.inspect}"
144
+ end
145
+
136
146
  if URI_LIST_TYPES.include? media_type
137
147
  Text::Location.uri_list transform_body(body)
138
148
  elsif HEADERS_TEXT_TYPES.include? media_type
@@ -148,6 +158,7 @@ module Occi
148
158
  # @param body [String] multi-line body
149
159
  # @return [Array] an array of lines
150
160
  def transform_body(body)
161
+ return [] if body.blank?
151
162
  lines = body.respond_to?(:lines) ? body.lines : body.split("\n")
152
163
  lines.map(&:strip)
153
164
  end
@@ -159,6 +170,7 @@ module Occi
159
170
  # @param headers [Hash] hash with raw header key-value pairs
160
171
  # @return [Array] an array of body-like lines
161
172
  def transform_headers(headers)
173
+ logger.debug "Transforming headers #{headers.inspect}" if logger_debug?
162
174
  unify_headers(
163
175
  canonize_headers(
164
176
  normalize_headers(headers)
@@ -172,11 +184,15 @@ module Occi
172
184
  # @param headers [Hash] hash with raw header key-value pairs
173
185
  # @return [Hash] a cleaner hash with relevant headers
174
186
  def normalize_headers(headers)
187
+ return {} unless headers
188
+
175
189
  headers = Hash[
176
190
  headers.map { |k, v| [k.gsub(HEADER_HTTP_PREFIX, '').capitalize, v] }
177
191
  ] # remove 'HTTP_' prefix in keys
178
192
  headers.delete_if { |_k, v| v.blank? } # remove pairs with empty values
179
193
  headers.keep_if { |k, _v| OCCI_KEYS.include?(k) } # drop non-OCCI pairs
194
+
195
+ logger.debug "Normalized headers #{headers.inspect}" if logger_debug?
180
196
  headers
181
197
  end
182
198
 
@@ -194,6 +210,7 @@ module Occi
194
210
  canonical[pref.first] = [canonize_header_value(value)].flatten
195
211
  end
196
212
 
213
+ logger.debug "Canonized headers #{canonical.inspect}" if logger_debug?
197
214
  canonical
198
215
  end
199
216
 
@@ -219,6 +236,8 @@ module Occi
219
236
  headers.each_pair do |k, v|
220
237
  lines << v.map { |val| "#{k}: #{val}" }
221
238
  end
239
+
240
+ logger.debug "Unified headers #{lines.inspect}" if logger_debug?
222
241
  lines.flatten.sort
223
242
  end
224
243
 
@@ -230,8 +249,7 @@ module Occi
230
249
  def validate_header_keys!(headers_keys)
231
250
  return unless key_name_groups.any? { |elm| (headers_keys & elm).count > 1 }
232
251
 
233
- raise Occi::Core::Errors::ParsingError,
234
- "#{self} -> Headers #{headers_keys.inspect} contain mixed key notations"
252
+ raise Occi::Core::Errors::ParsingError, "Headers #{headers_keys.inspect} contain mixed key notations"
235
253
  end
236
254
 
237
255
  # Returns a list of available key name groups accessible as constants by name on this class.
@@ -244,6 +262,19 @@ module Occi
244
262
 
245
263
  protected
246
264
 
265
+ # :nodoc:
266
+ def action_instance_category(entity_parser, action_instance)
267
+ cats = entity_parser.plain_categories action_instance
268
+ action = cats.detect { |c| c.is_a? Occi::Core::Action }
269
+ raise Occi::Core::Errors::ParsingError, 'ActionInstance does not specify action' unless action
270
+ action
271
+ end
272
+
273
+ # :nodoc:
274
+ def setify(object)
275
+ object.is_a?(Enumerable) ? Set.new(object) : Set.new([object].compact)
276
+ end
277
+
247
278
  # :nodoc:
248
279
  def post_initialize(args)
249
280
  super
@@ -31,7 +31,7 @@ module Occi
31
31
  def initialize(args = {})
32
32
  default_args! args
33
33
 
34
- logger.debug "RendererFactory: Initializing with #{args.inspect}"
34
+ logger.debug "Initializing RendererFactory with #{args.inspect}"
35
35
  @required_methods = args.fetch(:required_methods)
36
36
  @namespace = args.fetch(:namespace)
37
37
 
@@ -40,7 +40,7 @@ module Occi
40
40
 
41
41
  #
42
42
  def reload!
43
- logger.debug 'RendererFactory: Clearing cache for renderer reload'
43
+ logger.debug 'Clearing RendererFactory cache for renderer reload'
44
44
  @ravail_cache = nil
45
45
  end
46
46
 
@@ -65,7 +65,7 @@ module Occi
65
65
  @ravail_cache = {}
66
66
 
67
67
  renderer_classes.each do |rndr_klass|
68
- logger.debug "RendererFactory: Registering #{rndr_klass} for #{rndr_klass.formats}"
68
+ logger.debug "RendererFactory registering #{rndr_klass} for #{rndr_klass.formats}"
69
69
  rndr_klass.formats.each { |rndr_klass_f| @ravail_cache[rndr_klass_f] = rndr_klass }
70
70
  end
71
71
 
@@ -113,7 +113,7 @@ module Occi
113
113
  renderer_with_methods! candidate
114
114
  renderer_with_formats! candidate
115
115
  rescue Occi::Core::Errors::RendererError => ex
116
- logger.debug "RendererFactory: Renderer validation failed with #{ex.message}"
116
+ logger.debug "Renderer validation failed with #{ex.message}"
117
117
  return false
118
118
  end
119
119
 
@@ -176,7 +176,7 @@ module Occi
176
176
  raise Occi::Core::Errors::RendererError, "#{namespace.inspect} " \
177
177
  'is not a Module'
178
178
  end
179
- logger.debug "RendererFactory: Looking for renderers in #{namespace}"
179
+ logger.debug "RendererFactory looking for renderers in #{namespace}"
180
180
  namespace.constants.collect { |const| namespace.const_get(const) }
181
181
  end
182
182
 
@@ -3,7 +3,7 @@ module Occi
3
3
  MAJOR_VERSION = 5 # Major update constant
4
4
  MINOR_VERSION = 0 # Minor update constant
5
5
  PATCH_VERSION = 0 # Patch/Fix version constant
6
- STAGE_VERSION = 'alpha.4'.freeze # use `nil` for production releases
6
+ STAGE_VERSION = 'beta.1'.freeze # use `nil` for production releases
7
7
 
8
8
  unless defined?(::Occi::Core::VERSION)
9
9
  VERSION = [
@@ -29,7 +29,7 @@ module Occi
29
29
  #
30
30
  # @param model [Occi::Core::Model] model to be bootstrapped
31
31
  def bootstrap!(model)
32
- logger.debug "#{self}: Bootstrapping#{model.empty? ? ' empty' : ''} model"
32
+ logger.debug "Bootstrapping#{model.empty? ? ' empty' : ''} model"
33
33
  actions! model
34
34
  kinds! model
35
35
  mixins! model
@@ -67,7 +67,7 @@ module Occi
67
67
  def kinds!(model)
68
68
  attribute_definitions = attribute_definitions_for(kinds_path)
69
69
  yamls_in(kinds_path).each do |file|
70
- logger.debug "#{self}: Loading kind from #{file.inspect}"
70
+ logger.debug "Warehouse loading kind from #{file.inspect}"
71
71
  model << Occi::Core::Kind.from_yaml(file, model, attribute_definitions)
72
72
  end
73
73
  end
@@ -76,7 +76,7 @@ module Occi
76
76
  def mixins!(model)
77
77
  attribute_definitions = attribute_definitions_for(mixins_path)
78
78
  yamls_in(mixins_path).each do |file|
79
- logger.debug "#{self}: Loading mixin from #{file.inspect}"
79
+ logger.debug "Warehouse loading mixin from #{file.inspect}"
80
80
  model << Occi::Core::Mixin.from_yaml(file, model, attribute_definitions)
81
81
  end
82
82
  end
@@ -86,7 +86,7 @@ module Occi
86
86
  # TODO: work with separate attribute definitions
87
87
  attribute_definitions = {}
88
88
  yamls_in(actions_path).each do |file|
89
- logger.debug "#{self}: Loading action from #{file.inspect}"
89
+ logger.debug "Warehouse loading action from #{file.inspect}"
90
90
  model << Occi::Core::Action.from_yaml(file, model, attribute_definitions)
91
91
  end
92
92
  end
@@ -98,7 +98,7 @@ module Occi
98
98
  attr_defs_path = File.join(categories_path, ATTRIBS)
99
99
  yamls_in(attr_defs_path).each do |file|
100
100
  name = attribute_name_from(file)
101
- logger.debug "#{self}: Loading attribute definition for #{name.inspect} from #{file.inspect}"
101
+ logger.debug "Warehouse loading attribute definition for #{name.inspect} from #{file.inspect}"
102
102
  attribute_definitions[name] = Occi::Core::AttributeDefinition.from_yaml(file)
103
103
  end
104
104
 
@@ -10,7 +10,7 @@ module Occi
10
10
  # model = Occi::Infrastructure::Model.new
11
11
  # model.load_infrastructure!
12
12
  def load_infrastructure!
13
- logger.debug "#{self.class}: Loading Infrastructure from Warehouse"
13
+ logger.debug 'Loading Infrastructure from Infrastructure::Warehouse'
14
14
  Occi::Infrastructure::Warehouse.bootstrap! self
15
15
  self << Occi::Infrastructure::Mixins::OsTpl.new
16
16
  self << Occi::Infrastructure::Mixins::ResourceTpl.new
@@ -10,7 +10,7 @@ module Occi
10
10
  # model = Occi::InfrastructureExt::Model.new
11
11
  # model.load_infrastructure_ext!
12
12
  def load_infrastructure_ext!
13
- logger.debug "#{self.class}: Loading InfrastructureExt from Warehouse"
13
+ logger.debug 'Loading InfrastructureExt from InfrastructureExt::Warehouse'
14
14
  Occi::InfrastructureExt::Warehouse.bootstrap! self
15
15
  self << Occi::InfrastructureExt::Mixins::AvailabilityZone.new
16
16
  nil
@@ -1,4 +1,5 @@
1
1
  # :nodoc:
2
2
  class Hash
3
+ include Yell::Loggable
3
4
  include Occi::Core::Helpers::HashDereferencer
4
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: occi-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.alpha.4
4
+ version: 5.0.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boris Parak
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-05-15 00:00:00.000000000 Z
13
+ date: 2017-06-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
@@ -566,7 +566,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
566
566
  version: 1.3.1
567
567
  requirements: []
568
568
  rubyforge_project:
569
- rubygems_version: 2.6.8
569
+ rubygems_version: 2.6.10
570
570
  signing_key:
571
571
  specification_version: 4
572
572
  summary: The rOCCI toolkit