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

Sign up to get free protection for your applications and to get access to all the features.
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