Class: Ecoportal::API::Common::Content::CollectionModel

Inherits:
DoubleModel
  • Object
show all
Includes:
Enumerable
Defined in:
lib/ecoportal/api/common/content/collection_model.rb

Overview

Note:

to be able to refer to the correct element of the Collection, it is required that those elements have a unique key that allows to identify them

CollectionModel aims to deal with Arrays of actual objects.

Constant Summary

Constants inherited from DoubleModel

DoubleModel::NOT_USED

Constants included from ClassHelpers

Ecoportal::API::Common::Content::ClassHelpers::NOT_USED

Class Attribute Summary collapse

Attributes inherited from DoubleModel

#_key, #_parent, #_read_only

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from DoubleModel

#as_json, #as_update, #consolidate!, #dirty?, #doc, embeds_many, embeds_one, enforce!, #key, #key=, key?, new_uuid, #original_doc, pass_reader, pass_writer, passarray, passboolean, passdate, passforced, passkey, passthrough, #print_pretty, #replace_doc, #reset!, #root, #to_json

Methods included from ClassHelpers

#inheritable_attrs, #inheritable_class_vars, #inherited, #instance_variable_name, #new_class, #resolve_class, #to_constant, #to_time, #uid, #used_param?

Constructor Details

#initialize(ini_doc = [], parent: self, key: nil, read_only: false) ⇒ CollectionModel

Returns a new instance of CollectionModel.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 91

def initialize(ini_doc = [], parent: self, key: nil, read_only: false)
  unless self.class.klass?
    raise "Undefined base 'klass' or 'new_item' callback for #{self.class}"
  end

  ini_doc = case ini_doc
            when Array
              ini_doc
            when Enumerable
              ini_doc.to_a
            else
              []
            end

  super(ini_doc, parent: parent, key: key, read_only: read_only)
end

Class Attribute Details

.klass(value = NOT_USED) {|doc| ... } ⇒ Klass

Note:
  • use block to define klass callback

Resolves to the nuclear Class of the elements

Parameters:

  • value (Hash) (defaults to: NOT_USED)

    base doc (raw object) to create the object with

Yields:

  • (doc)

    identifies the target class of the raw object

Yield Parameters:

  • doc (Hash)

Yield Returns:

  • (Klass)

    the target class

Returns:

  • (Klass)

    the target class



30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 30

def klass(value = NOT_USED, &block)
  if block
    @klass = block
    block.call(value) if value != NOT_USED
  elsif used_param?(value)
    if @klass.is_a?(Proc)
      @klass.call(value)
    else
      resolve_class(@klass, exception: false)
    end
  else
    resolve_class(@klass, exception: false)
  end
end

.order_keyObject

Returns the value of attribute order_key.



12
13
14
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 12

def order_key
  @order_key
end

.order_mattersObject

Returns the value of attribute order_matters.



12
13
14
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 12

def order_matters
  @order_matters
end

Class Method Details

.doc_class(name) ⇒ Object



79
80
81
82
83
84
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 79

def doc_class(name)
  dim_class = new_class(name, inherits: Common::Content::ArrayModel) do |klass|
    klass.order_matters = order_matters
    klass.uniq          = uniq
  end
end

.items_keyObject



14
15
16
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 14

def items_key
  @items_key ||= "id"
end

.items_key=(value) ⇒ Object



18
19
20
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 18

def items_key=(value)
  @items_key = value && value.to_s.freeze
end

.klass?Boolean

Returns are there the factory logics to build item objects defined?.

Returns:

  • (Boolean)

    are there the factory logics to build item objects defined?



75
76
77
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 75

def klass?
  @klass || @new_item
end

.new_item(doc = NOT_USED, parent: nil, key: nil, read_only: false) {|doc, parent, key| ... } ⇒ Klass

Note:
  • use block to define new_item callback, which will prevail over klass
  • if new_item callback was not defined, it is required to defnie klass
Note:

if block is given, it ignores doc

Generates a new object of the target class

Parameters:

  • doc (Hash) (defaults to: NOT_USED)

    doc to parse

Yields:

  • (doc, parent, key)

    creates an object instance of the target klass

Yield Parameters:

  • doc (Hash)

Yield Returns:

  • (Klass)

    instance object of the target klass

Returns:

  • (Klass)

    instance object of the target klass



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 55

def new_item(doc = NOT_USED, parent: nil, key: nil, read_only: false, &block)
  if block
    @new_item = block
  elsif used_param?(doc)
    raise "You should define either a 'klass' or a 'new_item' callback first" unless klass?
    if @new_item
      @new_item.call(doc, parent, key)
    else
      if target_class = self.klass(doc)
        doc.is_a?(target_class) ? doc : target_class.new(doc, parent: parent, key: key, read_only: read_only)
      else
        raise "Could not find a class for: #{doc}"
      end
    end
  else
    raise "To define the 'new_item' callback (factory), you need to use a block"
  end
end

Instance Method Details

#[](value) ⇒ Object

Get an element usign the key.

Parameters:

Returns:

  • (Object)

    the items_class element object



156
157
158
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 156

def [](value)
  items_by_key[get_key(value)]
end

#_doc_key(value) ⇒ Object

Note:
  • The name of the method is after the paren't class method
  • This method would have been better called _doc_pos :)

Transforms value into the actual key to access the object in the doc Array



121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 121

def _doc_key(value)
  #print "*(#{value.class})"
  return super(value) unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
  if id = get_key(value)
    #print "^"
    _doc_items.index {|item| get_key(item) == id}.tap do |p|
      #print "{{#{p}}}"
    end
  else
    raise UnlinkedModel.new("Can't find child: #{value}")
  end
end

#_doc_pos(value) ⇒ Object



113
114
115
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 113

def _doc_pos(value)
  _doc_key(value)
end

#_itemsObject



143
144
145
146
147
148
149
150
151
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 143

def _items
  return @_items if @_items
  [].tap do |elements|
    variable_set(:@_items, elements)
    _doc_items.each do |item_doc|
      elements << new_item(item_doc)
    end
  end
end

#clearObject

Deletes all the elements of this CollectionModel instance



196
197
198
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 196

def clear
  self.to_a.each {|item| delete!(item)}
end

#delete!(value) ⇒ Object

Deletes value from this CollectionModel instance

Parameters:

  • value (String, Hash, Ecoportal::API::Common::Content::DoubleModel)
    • When used as String, the key value (i.e. id value) is expected
    • When used as Hash, it should be the doc of the target element
    • When used as DoubleModel, it should be the specific object to be deleted


205
206
207
208
209
210
211
212
213
214
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 205

def delete!(value)
  unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel) || value.is_a?(String)
    raise "'Content::DoubleModel' or 'Hash' doc required"
  end
  if item = self[value]
    _doc_delete(item.doc)
    @indexed = false
    _items.delete(item)
  end
end

#each(&block) ⇒ Object



138
139
140
141
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 138

def each(&block)
  return to_enum(:each) unless block
  _items.each(&block)
end

#empty?Boolean

Returns:

  • (Boolean)


135
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 135

def empty?;   count == 0; end

#include?(value) ⇒ Boolean

Checks if an element exists in the collection

Parameters:

Returns:

  • (Boolean)

    whether or not it is included



163
164
165
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 163

def include?(value)
  items_by_key.key?(get_key(value))
end

#items_classClass

Returns the class of the elements of the Collection.

Returns:

  • (Class)

    the class of the elements of the Collection



109
110
111
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 109

def items_class
  self.class.klass
end

#lengthObject



134
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 134

def length;   count;      end

#present?Boolean

Returns:

  • (Boolean)


136
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 136

def present?; count > 0;  end

#upsert!(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED) ⇒ Object

Tries to find the element value, if it exists, it updates it Otherwise it pushes it to the end

Returns:

  • (Object)

    the items_class element object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 176

def upsert!(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
  unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
    raise "'Content::DoubleModel' or 'Hash' doc required. Given #{value.class}"
  end
  item_doc = value.is_a?(Content::DoubleModel)? value.doc : value
  item_doc = JSON.parse(item_doc.to_json)
  if item = self[value]
    item.replace_doc(item_doc)
  else
    _doc_upsert(item_doc, pos: pos, before: before, after: after).tap do |pos_idx|
      _items.insert(pos_idx, new_item(item_doc))
      @indexed = false
    end
  end
  (item || self[item_doc]).tap do |item|
    yield(item) if block_given?
  end
end

#values_at(*keys) ⇒ Array<Object>

Returns the items_class element object.

Returns:

  • (Array<Object>)

    the items_class element object



168
169
170
# File 'lib/ecoportal/api/common/content/collection_model.rb', line 168

def values_at(*keys)
  keys.map {|key| self[key]}
end