Class TaliaCore::ActiveSource
In: lib/talia_core/active_source.rb
Parent: ActiveRecord::Base

This class encapsulate the basic "Source" behaviour for an element in the semantic store. This is the baseclass for all things that are represented as an "Resource" (with URL) in the semantic store.

If an object is modified but not saved, the ActiveSource does not guarantee that the RDF will always be in sync with the database. However, a subsequent saving of the object will re-sync the RDF.

An effort is made to treat RDF and database writes in the same way, so that they should usually be in sync:

  • Write operations are usually lazy, the data should only be saved once save! is called. However, ActiveRecord may still decide that the objects need to be saved if they are involved in other operations.
  • Operations that clear a predicate are immediate. That also means that using singular property setter, if used will immediately erase the old value. If the record is not saved, the property will be left empty (and not revert to the original value!)

Methods

Included Modules

ActiveRDF::ResourceLike ActiveSourceParts::PredicateHandler ActiveSourceParts::RdfHandler

External Aliases

update_attributes -> update_attributes_orig
  Make aliases for the original updating methods
update_attributes! -> update_attributes_orig!

Public Instance methods

Works in the normal way for database attributes. If the value is not an attribute, it tries to find objects related to this source with the value as a predicate URL and returns a collection of those.

The assignment operator remains as it is for the ActiveRecord.

[Source]

     # File lib/talia_core/active_source.rb, line 99
 99:     def [](attribute)
100:       if(db_attr?(attribute))
101:         super(attribute)
102:       elsif(defined_property?(attribute))
103:         self.send(attribute)
104:       else
105:         get_objects_on(attribute)
106:       end
107:     end

Assignment to an attribute. This will overwrite all current triples.

[Source]

     # File lib/talia_core/active_source.rb, line 111
111:     def []=(attribute, value)
112:       if(db_attr?(attribute))
113:         super(attribute, value)
114:       elsif(defined_property?(attribute))
115:         self.send("#{attribute}=", value)
116:       else
117:          get_wrapper_on(attribute).replace(value)
118:       end
119:     end

Add the additional types to the source that were configured in the class. Usually this will not need to be called directly, but will be automatically called during construction.

This will check the existing types to avoid duplication

[Source]

     # File lib/talia_core/active_source.rb, line 341
341:     def add_additional_rdf_types
342:       # return if(self.class.additional_rdf_types.empty?)
343:       type_hash = {}
344:       self.types.each { |type| type_hash[type.respond_to?(:uri) ? type.uri.to_s : type.to_s] = true }
345:       # Add the "class" default type type (unless this is the source for the self type itself).0
346:       self.types << rdf_selftype unless(type_hash[rdf_selftype.to_s] || (rdf_selftype.to_s == self.uri.to_s))
347:       # Add the user-configured types
348:       self.class.additional_rdf_types.each do |type|
349:         self.types << type unless(type_hash[type.respond_to?(:uri) ? type.uri.to_s : type.to_s])
350:       end
351:     end

Helper to update semantic attributes from the given hash. If there is a "<value>" string, it will be treated as a reference to an URI. Hash values may be arrays.

If overwrite is set to yes, the given attributes (and only those) are replaced with the values from the hash. Otherwise the attribute values will be added to the existing ones

[Source]

     # File lib/talia_core/active_source.rb, line 209
209:     def add_semantic_attributes(overwrite, attributes)
210:       attributes.each do |attr, value|
211:         if(defined_property?(attr))
212:           self[attr] = value
213:         else
214:           attr_wrap = self[attr]
215:           attr_wrap.remove if(overwrite)
216:           value.to_a.each { |val| self[attr] << target_for(val) }
217:         end
218:       end
219:     end

Attaches files from the given hash. See the new method on ActiveSource for the details.

The call in this case should look like this:

 attach_files([{ url => 'url_or_filename', :options => { .. }}, ...])

Have a look at the DataLoader module to see how the options work. You may also provide a single hash for :files (instead of an array) if you have just one file. Files will be saved immediately.

[Source]

     # File lib/talia_core/active_source.rb, line 363
363:     def attach_files(files)
364:       files = [ files ] unless(files.is_a?(Array))
365:       files.each do |file|
366:         file.to_options!
367:         filename = file[:url]
368:         assit(filename)
369:         options = file[:options] || {}
370:         records = DataTypes::FileRecord.create_from_url(filename, options)
371:         records.each { |rec| self.data_records << rec }
372:       end
373:     end

This will return a list of DataRecord objects. Without parameters, this returns all data elements on the source. If a type is given, it will return only the elements of the given type. If both type and location are given, it will retrieve only the specified data element

[Source]

     # File lib/talia_core/active_source.rb, line 379
379:     def data(type = nil, location= nil)
380:       find_type = location ? :first : :all # Find just one element if a location is given
381:       type = type.name if(type.is_a?(Class))
382:       options = {}
383:       options[:conditions] = [ "type = ?", type ] if(type && !location)
384:       options[:conditions] = [ "type = ? AND location = ?", type, location ] if(type && location)
385:       data_records.find(find_type, options)
386:     end

True if the given attribute is a database attribute

[Source]

     # File lib/talia_core/active_source.rb, line 287
287:     def db_attr?(attribute)
288:       ActiveSource.db_attr?(attribute)
289:     end

[Source]

     # File lib/talia_core/active_source.rb, line 291
291:     def defined_property?(prop_name)
292:       self.class.defined_property?(prop_name)
293:     end

Gets the direct predicates (using the database)

[Source]

     # File lib/talia_core/active_source.rb, line 273
273:     def direct_predicates
274:       raise(ActiveRecord::RecordNotFound, "Cannot do this on unsaved record.") if(new_record?)
275:       rels = SemanticRelation.find_by_sql("SELECT DISTINCT predicate_uri FROM semantic_relations WHERE subject_id = #{self.id}")
276:       rels.collect { |rel| N::Predicate.new(rel.predicate_uri) }
277:     end
get_attribute(attribute)

Alias for #[]

Returns a special object which collects the "inverse" properties of the Source - these are all RDF properties which have the current Source as the object.

The returned object supports the [] operator, which allows to fetch the "inverse" (the RDF subjects) for the given predicate.

Example: person.inverse[N::FOO::creator] would return a list of all the elements of which the current person is the creator.

[Source]

     # File lib/talia_core/active_source.rb, line 230
230:     def inverse
231:       inverseobj = Object.new
232:       inverseobj.instance_variable_set(:@assoc_source, self)
233:       
234:       class << inverseobj     
235:         
236:         def [](property)
237:           @assoc_source.subjects.find(:all, :conditions => { 'semantic_relations.predicate_uri' => property.to_s } )
238:         end
239:         
240:         private :type
241:       end
242:       
243:       inverseobj
244:     end

Gets the inverse predicates

[Source]

     # File lib/talia_core/active_source.rb, line 280
280:     def inverse_predicates
281:       raise(ActiveRecord::RecordNotFound, "Cannot do this on unsaved record.") if(new_record?)
282:       rels = SemanticRelation.find_by_sql("SELECT DISTINCT predicate_uri FROM semantic_relations WHERE object_id = #{self.id}")
283:       rels.collect { |rel| N::Predicate.new(rel.predicate_uri) }
284:     end

Accessor that allows to lookup a namespace/name combination. This works like the [] method: I will return an array-like object on predicates can be manipulated.

[Source]

     # File lib/talia_core/active_source.rb, line 249
249:     def predicate(namespace, name)
250:       get_objects_on(get_namespace(namespace, name))
251:     end

Replaces the given predicate with the value. Good for one-value predicates

[Source]

     # File lib/talia_core/active_source.rb, line 266
266:     def predicate_replace(namespace, name, value)
267:       pred = predicate(namespace, name)
268:       pred.remove
269:       pred << value
270:     end

Setter method for predicates by namespace/name combination. This will *add a precdicate triple, not replace one!*

[Source]

     # File lib/talia_core/active_source.rb, line 255
255:     def predicate_set(namespace, name, value)
256:       predicate(namespace, name) << value
257:     end

Setter method that will only add the value if it doesn‘t exist already

[Source]

     # File lib/talia_core/active_source.rb, line 260
260:     def predicate_set_uniq(namespace, name, value)
261:       pred = predicate(namespace, name)
262:       pred << value unless(pred.include?(value))
263:     end

[Source]

     # File lib/talia_core/active_source.rb, line 295
295:     def property_options_for(property)
296:       self.class.property_options_for(property)
297:     end

The RDF type that is used for objects of the current class

[Source]

     # File lib/talia_core/active_source.rb, line 389
389:     def rdf_selftype
390:       (N::TALIA + self.class.name.demodulize)
391:     end

[Source]

     # File lib/talia_core/active_source.rb, line 393
393:     def reload
394:       reset! # Clear the property cache
395:       super
396:     end

Works like update_attributes, but will replace the semantic attributes rather than adding to them.

[Source]

     # File lib/talia_core/active_source.rb, line 191
191:     def rewrite_attributes(attributes)
192:       yield self if(block_given?)
193:       update_attributes_orig(process_attributes(true, attributes)) 
194:     end

Like rewrite_attributes, but calling save!

[Source]

     # File lib/talia_core/active_source.rb, line 197
197:     def rewrite_attributes!(attributes)
198:       yield self if(block_given?)
199:       update_attributes_orig!(process_attributes(true, attributes))
200:     end

Uri in short notation

[Source]

    # File lib/talia_core/active_source.rb, line 74
74:     def short_uri
75:       N::URI.new(self.uri).to_name_s
76:     end

Creates an RDF/XML resprentation of the source. The object is saved if this is a new record.

[Source]

     # File lib/talia_core/active_source.rb, line 331
331:     def to_rdf
332:       save! if(new_record?)
333:       ActiveSourceParts::Xml::RdfBuilder.build_source(self) 
334:     end

To string: Just return the URI. Use to_xml if you need something more involved.

[Source]

    # File lib/talia_core/active_source.rb, line 85
85:     def to_s
86:       self[:uri]
87:     end

Create a new uri object

[Source]

    # File lib/talia_core/active_source.rb, line 90
90:     def to_uri
91:       self[:uri].to_uri
92:     end

XML Representation of the source. The object is saved if this is a new record.

[Source]

     # File lib/talia_core/active_source.rb, line 324
324:     def to_xml
325:       save! if(new_record?)
326:       ActiveSourceParts::Xml::SourceBuilder.build_source(self)
327:     end

Updates all attributes of this source. For the database attributes, this works exactly like ActiveRecord::Base#update_attributes

If semantic attributes are present, they will be updated on the semantic store.

After the update, the source will be saved.

[Source]

     # File lib/talia_core/active_source.rb, line 178
178:     def update_attributes(attributes)
179:       yield self if(block_given?)
180:       super(process_attributes(false, attributes))
181:     end

As update_attributes, but uses save! to save the source

[Source]

     # File lib/talia_core/active_source.rb, line 184
184:     def update_attributes!(attributes)
185:       yield self if(block_given?)
186:       super(process_attributes(false, attributes))
187:     end

Updates the source with the given properties. The ‘mode’ field indicates if and how the update will be performed. See the ImportJobHelper class for the different modes.

As opposed to the *_attributes method, this will also handle file elements. The default mode is :skip (do nothing)

[Source]

     # File lib/talia_core/active_source.rb, line 132
132:     def update_source(properties, mode)
133:       properties.to_options!
134:       mode = :update if(self.is_a?(SourceTypes::DummySource)) # Dummy sources are always updated
135:       mode ||= :skip
136:       mode = mode.to_sym
137:       return self if(mode == :skip) # If we're told to ignore updates
138:       
139:       # Deal with already existing sources
140:       files = properties.delete(:files)
141:       
142:       if(mode == :overwrite)
143:         # If we are to overwrite, delete all relations and update normally
144:         self.semantic_relations.destroy_all
145:         self.data_records.destroy_all
146:         mode = :update
147:       elsif(mode == :update && files && self.data_records.size > 0)
148:         # On updating we should only remove the files if there are new ones
149:         self.data_records.destroy_all
150:       end
151:       
152:       # Add any files
153:       attach_files(files) if(files)
154:       
155:       # Rewrite the type, if neccessary
156:       type = properties[:type]
157:       switch_type = type && (self.type != type)
158:       # Warn to the log if we have a problematic type change
159:       TaliaCore.logger.warn("WARNING: Type change from #{self.type} to #{type}") if(switch_type && !self.is_a?(SourceTypes::DummySource))
160:       self.type = type if(switch_type)
161:       
162:       # Now we should either be adding or updating
163:       assit(mode == :update || mode == :add)
164:       update = (mode == :update)
165:       
166:       # Overwrite with or add the imported attributes
167:       update ? rewrite_attributes(properties) : update_attributes(properties)
168:       
169:       self
170:     end

Helper

[Source]

    # File lib/talia_core/active_source.rb, line 79
79:     def value_for(thing)
80:       self.class.value_for(thing)
81:     end

Writes the predicate directly to the database and the rdf store. The Source does not need to be saved and no data is loaded from the database. This is faster than adding the data normally and doing a full save, at least if only one or two predicates are written.

[Source]

     # File lib/talia_core/active_source.rb, line 303
303:     def write_predicate_direct(predicate, value)
304:       autosave = self.autosave_rdf?
305:       value.save! if(value.is_a?(ActiveSource) && value.new_record?)
306:       self.autosave_rdf = false
307:       self[predicate] << value
308:       uri_res = N::URI.new(predicate)
309:       # Now add the RDF data by hand
310:       if(value.kind_of?(Array))
311:         value.each do |v|
312:           my_rdf.direct_write_predicate(uri_res, v)
313:         end
314:       else
315:         my_rdf.direct_write_predicate(uri_res, value)
316:       end
317:       save! # Save without RDF save
318:       self.autosave_rdf = autosave
319:     end

[Validate]