Class: TaliaCore::SemanticCollectionWrapper

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/talia_core/semantic_collection_wrapper.rb

Overview

Class for the collection of elements returned by the “semantic accessor” methods of a source (e.g. source)

Each wrapper contains the values for one predicate of one source (that is, for all triples of the form <thesource> <thepredicate> ?object).

The wrapper will lazy-load the data and only do a query to the database once the items are actually requested. If a database request is necessary, all data will be fetched in a single request.

Modifications of the wrapper will happen in memory. Only when the wrapper is saved using #save_items! will the modifications be written to the data store. #save_items! will be called by the “owning” source of this wrapper when the source is being saved.

Some of the methods work on the values, and other on the objects of the collection. See SemanticCollectionItem#value and SemanticCollectionItem#object for more on that.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, predicate) ⇒ SemanticCollectionWrapper

Initialize the collection with the given source and predicate. No database will take place during creation of the object



38
39
40
41
42
43
44
45
46
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 38

def initialize(source, predicate)
  @assoc_source = source
  @assoc_predicate = if(predicate.respond_to?(:uri))
    predicate.uri.to_s
  else
    predicate.to_s
  end
  @force_type = self.class.special_types[@assoc_predicate]
end

Instance Attribute Details

#force_typeObject (readonly)

Returns the value of attribute force_type.



25
26
27
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 25

def force_type
  @force_type
end

Class Method Details

.special_typesObject

Simple hash that checks if a type if property requires “special” handling This will cause the wrapper to accept ActiveSource relations and all sources will be casted to the given type



30
31
32
33
34
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 30

def self.special_types
  @special_types ||= {
    N::RDF.type.to_s => N::SourceClass
  }
end

Instance Method Details

#add_record(value, order = nil) ⇒ Object Also known as: <<, concat

Creates a record for a value and adds it. This will add the given value if it is a database record and otherwise create a property with the given value.

If a block is given, it will be called with the new element after the new element has been added to the collection. If value is a collection, the block will be called for each element of the collection.

The order, if not nil, can be used to have a fixed order of SemanticRelation records. This is mainly used by the Collection class

Raises:

  • (ArgumentError)


161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 161

def add_record(value, order = nil)
  raise(ArgumentError, "Blank value assigned") if(value.blank? && !value.is_a?(Enumerable))
  # We use order exclusively for "ordering" predicates
  assit_equal(TaliaCore::Collection.index_to_predicate(order), @assoc_predicate) if(order)

  value = [ value ] unless(value.kind_of?(Array))

  value.each do |val|
    rel = create_predicate(val)
    rel.rel_order = order if(order)
    block_given? ? yield(rel) : insert_item(rel)
  end
end

#at(index) ⇒ Object Also known as: []

Get the element value at the given index. See also SemanticCollectionItem#value



50
51
52
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 50

def at(index)
  items.at(index).value if(items.at(index))
end

#clean?Boolean

Indicates that the wraper is “clean”, that is it hasn’t been written to or read from

Returns:

  • (Boolean)


245
246
247
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 245

def clean?
  @items.nil?
end

#collectObject

Collect method for the semantic wrapper, iterating over the values of the collection



80
81
82
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 80

def collect
  items.collect { |item| yield(item.value) }
end

#eachObject

Iterates over each value of the items in the relation.



74
75
76
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 74

def each
  items.each { |item| yield(item.value) }
end

#each_itemObject

Iterates of each object of the items in the relation.



85
86
87
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 85

def each_item
  items.each { |item| yield(item.object) }
end

#empty?Boolean

Returns:

  • (Boolean)


249
250
251
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 249

def empty?
  self.size == 0
end

#firstObject

The first value in the collection



56
57
58
59
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 56

def first
  item = items.first
  item ? item.value : nil
end

#get_item_at(index) ⇒ Object

Gets the object at the given index. See SemanticCollectionItem#object



69
70
71
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 69

def get_item_at(index)
  items.at(index).object if(items.at(index))
end

#include?(value) ⇒ Boolean

Check if the collection includes the value given

Returns:

  • (Boolean)


148
149
150
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 148

def include?(value)
  items.include?(value)
end

#index(value) ⇒ Object

Index of the given value



143
144
145
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 143

def index(value)
  items.index(value)
end

#init_as_empty!Object

Forces this relation to be empty. This initializes the relation, assuming that no data exists in the database. The collection will be empty, and the database will not be queried.

Warning Only call this if you need an empty wrapper and you are sure that there are no corresponding values in the database

Raises:

  • (ArgumentError)


259
260
261
262
263
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 259

def init_as_empty!
  raise(ArgumentError, "Already initialized!") if(loaded?)
  @items = []
  @loaded = true
end

#insert_item(item) ⇒ Object

Insert a new relation directly. To be used with care!

Raises:

  • (ArgumentError)


266
267
268
269
270
271
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 266

def insert_item(item) # :nodoc:
  raise(ArgumentError, "Can only insert a SemanticRelation") unless(item.is_a?(SemanticRelation))
  raise(ArgumentError, "New relation does not match the predicate of the wrapper") if(item.predicate_uri != @assoc_predicate.to_s)
  @items ||= []
  @items << item
end

#join(join_str = ', ') ⇒ Object

Joins the values of the colle ction into a string



137
138
139
140
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 137

def join(join_str = ', ')
  strs = items.collect { |item| item.value.to_s }
  strs.join(join_str)
end

#lastObject

The last value in the collection



62
63
64
65
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 62

def last
  item = items.last
  item ? item.value : nil
end

#loaded?Boolean

Indicates of the internal collection is loaded

Returns:

  • (Boolean)


239
240
241
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 239

def loaded?
  @loaded
end

#remove(*params) ⇒ Object

Remove the given value. With no parameters, the whole list will be cleared and the RDF will be updated immediately (!).



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 207

def remove(*params)
  if(params.length > 0)
    params.each { |par| remove_relation(par) }
  else
    if(loaded?)
      items.each { |item| item.destroy }
    else
      SemanticRelation.destroy_all(
      :subject_id => @assoc_source.id,
      :predicate_uri => @assoc_predicate
      )
    end
    @assoc_source.my_rdf.remove(@assoc_predicate.to_uri) unless(@assoc_source.uri.to_s.blank?)
    @items = []
    @loaded = true
  end
end

#replace(*new_values) ⇒ Object

Replace the contents of the current wrapper with the values passed. Blank values are ignored by this method. If non new values are passed (or all values are blank), this will simply



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 189

def replace(*new_values)
  new_values.flatten! if(new_values.first.is_a?(Array)) # Flatten if used as #replace([a, b, c])
  new_values.reject! { |v| v.blank? }
  new_values.collect! { |v| create_predicate(v) }
  remaining_items = []      
  items.each do |item|
    if(new_values.include?(item))
      remaining_items << item
      new_values.delete(item)
    else
      item.destroy
    end
  end
  @items = remaining_items + new_values
end

#replace_value(old_value, new_value) ⇒ Object

Replace a value with a new one. Equivalent to removing the old value and adding the new one



179
180
181
182
183
184
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 179

def replace_value(old_value, new_value)
  idx = items.index(old_value)
  items[idx].destroy
  # Creates a new relation and adds it in the place of the old one
  add_record(new_value) { |new_item| items[idx] = new_item }
end

#save_items!Object

This attempts to save the items to the database. This will do nothing if the collection was never loaded to memory. It also tries to ignore data that is known to already exist in the data store and only write the records could actually have been modified.



229
230
231
232
233
234
235
236
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 229

def save_items!
  return if(clean?) # If there are no items, nothing was modified
  @assoc_source.save! unless(@assoc_source.id)
  @items.each do |item|
    item.save!
  end
  @items = nil unless(loaded?) # Otherwise we'll have trouble reload-and merging
end

#sizeObject

Size of the collection



123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 123

def size
return items.size if(loaded?)
if(@items)
  # This is not really possible without loading, so we do it
  load!
  items.size
else
  SemanticRelation.count(:conditions => {
    'subject_id' => @assoc_source.id,
    'predicate_uri' => @assoc_predicate })
  end
end

#valuesObject

Returns an array with all values in the collection



90
91
92
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 90

def values
  items.collect { |item| item.value }
end

#values_with_lang(language = 'en') ⇒ Object

Returns only the values of the given language. (At the moment this is not aware of region codes or any specialities, it just does a string matching)

If no values with the given locale are found, this will fall back on the default locale and then to the values that don’t have a locale at all.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/talia_core/semantic_collection_wrapper.rb', line 101

def values_with_lang(language = 'en')
  language_is_default = (language == I18n.default_locale.to_s)
  real = []
  default = []
  unset = []
  items.each do |item|
    # FIXME: At the moment, this only works for value attributes, not for 
    # sources
    if((val = item.value).respond_to?(:lang))
      real << val if(val.lang == language)
      default << val if(!language_is_default && (val.lang == I18n.default_locale.to_s))
      unset << val if(val.lang.blank?)
    else
      default << val
    end
  end
  return real unless(real.empty?)
  return default unless(default.empty?)
  unset
end