Class: TaliaCore::ActiveSource
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- TaliaCore::ActiveSource
- Extended by:
- TaliaCore::ActiveSourceParts::ClassMethods, TaliaCore::ActiveSourceParts::Finders, TaliaCore::ActiveSourceParts::PredicateHandler::ClassMethods, TaliaCore::ActiveSourceParts::SqlHelper, TaliaUtil::Progressable
- Includes:
- ActiveRDF::ResourceLike, TaliaCore::ActiveSourceParts::PredicateHandler, TaliaCore::ActiveSourceParts::Rdf
- Defined in:
- lib/talia_core/active_source.rb
Overview
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!)
Direct Known Subclasses
Instance Method Summary collapse
-
#[](attribute) ⇒ Object
(also: #get_attribute)
Works in the normal way for database attributes.
-
#[]=(attribute, value) ⇒ Object
Assignment to an attribute.
-
#add_additional_rdf_types ⇒ Object
Add the additional types to the source that were configured in the class.
-
#add_semantic_attributes(overwrite, attributes) ⇒ Object
Helper to update semantic attributes from the given hash.
-
#attach_files(files) ⇒ Object
Attaches files from the given hash.
-
#data(type = nil, location = nil) ⇒ Object
This will return a list of DataRecord objects.
-
#db_attr?(attribute) ⇒ Boolean
True if the given attribute is a database attribute.
-
#direct_predicates ⇒ Object
Gets the direct predicates (using the database).
-
#inverse ⇒ Object
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.
-
#inverse_predicates ⇒ Object
Gets the inverse predicates.
-
#predicate(namespace, name) ⇒ Object
Accessor that allows to lookup a namespace/name combination.
-
#predicate_replace(namespace, name, value) ⇒ Object
Replaces the given predicate with the value.
-
#predicate_set(namespace, name, value) ⇒ Object
Setter method for predicates by namespace/name combination.
-
#predicate_set_uniq(namespace, name, value) ⇒ Object
Setter method that will only add the value if it doesn’t exist already.
-
#rdf_selftype ⇒ Object
The RDF type that is used for objects of the current class.
-
#rewrite_attributes(attributes) {|_self| ... } ⇒ Object
Works like update_attributes, but will replace the semantic attributes rather than adding to them.
-
#rewrite_attributes!(attributes) {|_self| ... } ⇒ Object
Like rewrite_attributes, but calling save!.
-
#short_uri ⇒ Object
Uri in short notation.
-
#to_rdf ⇒ Object
Creates an RDF/XML resprentation of the source.
-
#to_s ⇒ Object
To string: Just return the URI.
-
#to_uri ⇒ Object
Create a new uri object.
-
#to_xml ⇒ Object
XML Representation of the source.
-
#update_attributes(attributes) {|_self| ... } ⇒ Object
Updates all attributes of this source.
-
#update_attributes!(attributes) {|_self| ... } ⇒ Object
As update_attributes, but uses save! to save the source.
-
#update_attributes_orig ⇒ Object
Make aliases for the original updating methods.
- #update_attributes_orig! ⇒ Object
-
#update_source(properties, mode) ⇒ Object
Updates the source with the given properties.
-
#value_for(thing) ⇒ Object
Helper.
-
#write_predicate_direct(predicate, value) ⇒ Object
Writes the predicate directly to the database and the rdf store.
Methods included from TaliaCore::ActiveSourceParts::ClassMethods
additional_rdf_types, create_from_xml, create_multi_from, create_source, exists?, expand_uri, new, paginate, rewrite, split_attribute_hash, update
Methods included from TaliaCore::ActiveSourceParts::Finders
count, find, find_by_partial_local, find_by_partial_uri, find_by_uri_token
Methods included from TaliaCore::ActiveSourceParts::SqlHelper
default_inv_joins, default_joins, props_join, sources_join
Methods included from TaliaCore::ActiveSourceParts::PredicateHandler::ClassMethods
Methods included from TaliaUtil::Progressable
progressor, progressor=, run_with_progress
Methods included from TaliaCore::ActiveSourceParts::Rdf
#autosave_rdf=, #autosave_rdf?, #create_rdf, #my_rdf
Methods included from TaliaCore::ActiveSourceParts::PredicateHandler
#each_cached_wrapper, #get_objects_on, #has_type?, #inject_predicate, #reset!, #save_wrappers, #types
Instance Method Details
#[](attribute) ⇒ Object Also known as: get_attribute
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.
97 98 99 100 101 102 103 |
# File 'lib/talia_core/active_source.rb', line 97 def [](attribute) if(db_attr?(attribute)) super(attribute) else get_objects_on(attribute) end end |
#[]=(attribute, value) ⇒ Object
Assignment to an attribute. This will overwrite all current triples.
107 108 109 110 111 112 113 114 115 |
# File 'lib/talia_core/active_source.rb', line 107 def []=(attribute, value) if(db_attr?(attribute)) super(attribute, value) else pred = get_attribute(attribute) pred.remove pred << value end end |
#add_additional_rdf_types ⇒ Object
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
326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/talia_core/active_source.rb', line 326 def add_additional_rdf_types # return if(self.class.additional_rdf_types.empty?) type_hash = {} self.types.each { |type| type_hash[type.respond_to?(:uri) ? type.uri.to_s : type.to_s] = true } # Add the "class" default type type (unless this is the source for the self type itself).0 self.types << rdf_selftype unless(type_hash[rdf_selftype.to_s] || (rdf_selftype.to_s == self.uri.to_s)) # Add the user-configured types self.class.additional_rdf_types.each do |type| self.types << type unless(type_hash[type.respond_to?(:uri) ? type.uri.to_s : type.to_s]) end end |
#add_semantic_attributes(overwrite, attributes) ⇒ Object
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
205 206 207 208 209 210 211 212 |
# File 'lib/talia_core/active_source.rb', line 205 def add_semantic_attributes(overwrite, attributes) attributes.each do |attr, value| value = [ value ] unless(value.is_a?(Array)) attr_wrap = self[attr] attr_wrap.remove if(overwrite) value.each { |val |self[attr] << target_for(val) } end end |
#attach_files(files) ⇒ Object
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.
348 349 350 351 352 353 354 355 356 357 |
# File 'lib/talia_core/active_source.rb', line 348 def attach_files(files) files = [ files ] unless(files.is_a?(Array)) files.each do |file| filename = file[:url] || file['url'] assit(filename) = file[:options] || file['options'] || {} records = DataTypes::FileRecord.create_from_url(filename, ) records.each { |rec| self.data_records << rec } end end |
#data(type = nil, location = nil) ⇒ Object
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
363 364 365 366 367 368 369 370 |
# File 'lib/talia_core/active_source.rb', line 363 def data(type = nil, location= nil) find_type = location ? :first : :all # Find just one element if a location is given type = type.name if(type.is_a?(Class)) = {} [:conditions] = [ "type = ?", type ] if(type && !location) [:conditions] = [ "type = ? AND location = ?", type, location ] if(type && location) data_records.find(find_type, ) end |
#db_attr?(attribute) ⇒ Boolean
True if the given attribute is a database attribute
280 281 282 |
# File 'lib/talia_core/active_source.rb', line 280 def db_attr?(attribute) ActiveSource.db_attr?(attribute) end |
#direct_predicates ⇒ Object
Gets the direct predicates (using the database)
266 267 268 269 270 |
# File 'lib/talia_core/active_source.rb', line 266 def direct_predicates raise(ActiveRecord::RecordNotFound, "Cannot do this on unsaved record.") if(new_record?) rels = SemanticRelation.find_by_sql("SELECT DISTINCT predicate_uri FROM semantic_relations WHERE subject_id = #{self.id}") rels.collect { |rel| N::Predicate.new(rel.predicate_uri) } end |
#inverse ⇒ Object
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.
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/talia_core/active_source.rb', line 223 def inverse inverseobj = Object.new inverseobj.instance_variable_set(:@assoc_source, self) class << inverseobj def [](property) @assoc_source.subjects.find(:all, :conditions => { 'semantic_relations.predicate_uri' => property.to_s } ) end private :type end inverseobj end |
#inverse_predicates ⇒ Object
Gets the inverse predicates
273 274 275 276 277 |
# File 'lib/talia_core/active_source.rb', line 273 def inverse_predicates raise(ActiveRecord::RecordNotFound, "Cannot do this on unsaved record.") if(new_record?) rels = SemanticRelation.find_by_sql("SELECT DISTINCT predicate_uri FROM semantic_relations WHERE object_id = #{self.id}") rels.collect { |rel| N::Predicate.new(rel.predicate_uri) } end |
#predicate(namespace, name) ⇒ Object
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.
242 243 244 |
# File 'lib/talia_core/active_source.rb', line 242 def predicate(namespace, name) get_objects_on(get_namespace(namespace, name)) end |
#predicate_replace(namespace, name, value) ⇒ Object
Replaces the given predicate with the value. Good for one-value predicates
259 260 261 262 263 |
# File 'lib/talia_core/active_source.rb', line 259 def predicate_replace(namespace, name, value) pred = predicate(namespace, name) pred.remove pred << value end |
#predicate_set(namespace, name, value) ⇒ Object
Setter method for predicates by namespace/name combination. This will *add a precdicate triple, not replace one!*
248 249 250 |
# File 'lib/talia_core/active_source.rb', line 248 def predicate_set(namespace, name, value) predicate(namespace, name) << value end |
#predicate_set_uniq(namespace, name, value) ⇒ Object
Setter method that will only add the value if it doesn’t exist already
253 254 255 256 |
# File 'lib/talia_core/active_source.rb', line 253 def predicate_set_uniq(namespace, name, value) pred = predicate(namespace, name) pred << value unless(pred.include?(value)) end |
#rdf_selftype ⇒ Object
The RDF type that is used for objects of the current class
373 374 375 |
# File 'lib/talia_core/active_source.rb', line 373 def rdf_selftype (N::TALIA + self.class.name.demodulize) end |
#rewrite_attributes(attributes) {|_self| ... } ⇒ Object
Works like update_attributes, but will replace the semantic attributes rather than adding to them.
187 188 189 190 |
# File 'lib/talia_core/active_source.rb', line 187 def rewrite_attributes(attributes) yield self if(block_given?) update_attributes_orig(process_attributes(true, attributes)) end |
#rewrite_attributes!(attributes) {|_self| ... } ⇒ Object
Like rewrite_attributes, but calling save!
193 194 195 196 |
# File 'lib/talia_core/active_source.rb', line 193 def rewrite_attributes!(attributes) yield self if(block_given?) update_attributes_orig!(process_attributes(true, attributes)) end |
#short_uri ⇒ Object
Uri in short notation
72 73 74 |
# File 'lib/talia_core/active_source.rb', line 72 def short_uri N::URI.new(self.uri).to_name_s end |
#to_rdf ⇒ Object
Creates an RDF/XML resprentation of the source. The object is saved if this is a new record.
316 317 318 319 |
# File 'lib/talia_core/active_source.rb', line 316 def to_rdf save! if(new_record?) ActiveSourceParts::Xml::RdfBuilder.build_source(self) end |
#to_s ⇒ Object
To string: Just return the URI. Use to_xml if you need something more involved.
83 84 85 |
# File 'lib/talia_core/active_source.rb', line 83 def to_s self[:uri] end |
#to_uri ⇒ Object
Create a new uri object
88 89 90 |
# File 'lib/talia_core/active_source.rb', line 88 def to_uri self[:uri].to_uri end |
#to_xml ⇒ Object
XML Representation of the source. The object is saved if this is a new record.
309 310 311 312 |
# File 'lib/talia_core/active_source.rb', line 309 def to_xml save! if(new_record?) ActiveSourceParts::Xml::SourceBuilder.build_source(self) end |
#update_attributes(attributes) {|_self| ... } ⇒ Object
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.
174 175 176 177 |
# File 'lib/talia_core/active_source.rb', line 174 def update_attributes(attributes) yield self if(block_given?) super(process_attributes(false, attributes)) end |
#update_attributes!(attributes) {|_self| ... } ⇒ Object
As update_attributes, but uses save! to save the source
180 181 182 183 |
# File 'lib/talia_core/active_source.rb', line 180 def update_attributes!(attributes) yield self if(block_given?) super(process_attributes(false, attributes)) end |
#update_attributes_orig ⇒ Object
Make aliases for the original updating methods
118 |
# File 'lib/talia_core/active_source.rb', line 118 alias :update_attributes_orig :update_attributes |
#update_attributes_orig! ⇒ Object
119 |
# File 'lib/talia_core/active_source.rb', line 119 alias :update_attributes_orig! :update_attributes! |
#update_source(properties, mode) ⇒ Object
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)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/talia_core/active_source.rb', line 128 def update_source(properties, mode) properties. mode = :update if(self.is_a?(SourceTypes::DummySource)) # Dummy sources are always updated mode ||= :skip mode = mode.to_sym return self if(mode == :skip) # If we're told to ignore updates # Deal with already existing sources files = properties.delete(:files) if(mode == :overwrite) # If we are to overwrite, delete all relations and update normally self.semantic_relations.destroy_all self.data_records.destroy_all mode = :update elsif(mode == :update && files && self.data_records.size > 0) # On updating we should only remove the files if there are new ones self.data_records.destroy_all end # Add any files attach_files(files) if(files) # Rewrite the type, if neccessary type = properties[:type] switch_type = type && (self.type != type) # Warn to the log if we have a problematic type change TaliaCore.logger.warn("WARNING: Type change from #{self.type} to #{type}") if(switch_type && !self.is_a?(SourceTypes::DummySource)) self.type = type if(switch_type) # Now we should either be adding or updating assit(mode == :update || mode == :add) update = (mode == :update) # Overwrite with or add the imported attributes update ? rewrite_attributes(properties) : update_attributes(properties) self end |
#value_for(thing) ⇒ Object
Helper
77 78 79 |
# File 'lib/talia_core/active_source.rb', line 77 def value_for(thing) self.class.value_for(thing) end |
#write_predicate_direct(predicate, value) ⇒ Object
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.
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/talia_core/active_source.rb', line 288 def write_predicate_direct(predicate, value) autosave = self.autosave_rdf? value.save! if(value.is_a?(ActiveSource) && value.new_record?) self.autosave_rdf = false self[predicate] << value uri_res = N::URI.new(predicate) # Now add the RDF data by hand if(value.kind_of?(Array)) value.each do |v| my_rdf.direct_write_predicate(uri_res, v) end else my_rdf.direct_write_predicate(uri_res, value) end save! # Save without RDF save self.autosave_rdf = autosave end |