Module: TaliaCore::ActiveSourceParts::ClassMethods

Included in:
TaliaCore::ActiveSource
Defined in:
lib/talia_core/active_source_parts/class_methods.rb

Overview

Class methods for ActiveSource:

  • Property definitions for source classes (singular_property, multi_property, manual_property)

  • Logic for the creation of new sources, and things like exists?

  • “Import” methods for the class: create_from_xml, create_multi_from

  • autofill_uri logic

  • Various utility method

Instance Method Summary collapse

Instance Method Details

#additional_rdf_typesObject

Accessor for additional rdf types that will automatically be added to each object of that Source class



15
16
17
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 15

def additional_rdf_types 
  @additional_rdf_types ||= []
end

#create_from_xml(xml, options = {}) ⇒ Object

Create sources from XML. The result is either a single source or an Array of sources, depending on wether the XML contains multiple sources.

The imported sources will be saved during import, to ensure that relations between them are resolved correctly. If one of the imported elements does already exist, the existing source will be rewritten using ActiveSource#rewrite_attributes

The options may contain:

reader

The reader class that the import should use

progressor

The progress reporting object, which must respond to run_with_progress(message, size, &block)

errors

If given, all erors will be looged to this array instead of raising an exception. See the create_multi_from method for more.

duplicates

How to treat alredy existing sources. See ImportJobHelper for more documentation

base_file_uri

The base uri to import file from



88
89
90
91
92
93
94
95
96
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 88

def create_from_xml(xml, options = {})
  options.to_options!
  options.assert_valid_keys(:reader, :progressor, :errors, :duplicates, :base_file_uri)
  reader = options[:reader] ? options.delete(:reader).to_s.classify.constantize : TaliaCore::ActiveSourceParts::Xml::SourceReader
  source_properties = reader.sources_from(xml, options[:progressor], options.delete(:base_file_uri))
  self.progressor = options.delete(:progressor)
  sources = create_multi_from(source_properties, options)
  (sources.size > 1) ? sources : sources.first
end

#create_multi_from(sources, options = {}) ⇒ Object

Creates multiple sources from the given array of attribute hashes. The sources are saved during import, ensuring that the relations are resolved correctly.

Options:

errors

If given, all erors will be logged to this array instead of raising an exception. Each “entry” in the error array will be an Error object containing the origianl stack trace of the error

duplicates

Indicates how to deal with sources that already exist in the datastore. See the ImportJobHelper class for a documentation of this option. Default is :skip



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 109

def create_multi_from(sources, options = {})
  options.to_options!
  options.assert_valid_keys(:errors, :duplicates)
  source_objects = []
  run_with_progress('Writing imported', sources.size) do |progress|
    source_objects = sources.collect do |props|
      props.to_options!
      src = nil
      begin
        props[:uri] = uri_string_for(props[:uri], false)
        assit(props[:uri], "Must have a valid uri at this step")
        if(src = ActiveSource.find(:first, :conditions => { :uri => props[:uri] }))
          src.update_source(props, options[:duplicates])
        else
          src = ActiveSource.create_source(props)
        end
        src.save!
      rescue Exception => e
        if(options[:errors]) 
          err = Errors::ImportError.new("ERROR during import of #{props[:uri]}: #{e.message}")
          err.set_backtrace(e.backtrace)
          options[:errors] <<  err
          TaliaCore.logger.warn("Problems importing #{props[:uri]} (logged): #{e.message}")
        else
          raise
        end
      end
      progress.inc
      src
    end
  end
  source_objects
end

#create_source(args) ⇒ Object

Retrieves a new source with the given type. This gets a propety hash like #new, but it will correctly initialize a source of the type given in the hash. If no type is given, this will create a plain ActiveSource.



65
66
67
68
69
70
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 65

def create_source(args)
  args.to_options!
  type = args.delete(:type) || 'TaliaCore::ActiveSource'
  klass = type.constantize
  klass.new(args)
end

#db_attr?(attribute) ⇒ Boolean

Returns true if the given attribute is one that is stored in the database

Returns:

  • (Boolean)


184
185
186
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 184

def db_attr?(attribute)
  db_attributes.include?(attribute.to_s)
end

#defined_property?(prop_name) ⇒ Boolean

Returns:

  • (Boolean)


241
242
243
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 241

def defined_property?(prop_name)
  defined_props.include?(prop_name.to_s) || superclass.try_call.defined_property?(prop_name.to_s)
end

#exists?(value) ⇒ Boolean

This method is slightly expanded to allow passing uris and uri objects as an “id”

Returns:

  • (Boolean)


145
146
147
148
149
150
151
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 145

def exists?(value)
  if(uri_s = uri_string_for(value))
    super(:uri => uri_s)
  else
    super
  end
end

#expand_uri(uri) ⇒ Object

Tries to expand a generic URI value that is either given as a full URL or a namespace:name value.

This will assume a full URL if it finds a “:/” string inside the URI. Otherwise it will construct a namespace - name URI



193
194
195
196
197
198
199
200
201
202
203
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 193

def expand_uri(uri) # TODO: Merge with uri_for ?
  assit_block do |errors| 
    unless(uri.respond_to?(:uri) || uri.kind_of?(String)) || uri.kind_of?(Symbol)
      errors << "Found strange object of type #{uri.class}"
    end
    true
  end
  uri = uri.respond_to?(:uri) ? uri.uri.to_s : uri.to_s
  return uri if(uri.include?(':/'))
  N::URI.make_uri(uri).to_s
end

#new(*args) ⇒ Object

New method for ActiveSources. If a URL of an existing Source is given as the only parameter, that source will be returned. This makes the class work smoothly with our ActiveRDF version query interface.

Note that any semantic properties that were passed in to the constructor will be assigned after the ActiveRecord “create” callbacks have been called.

The option hash may contain a “files” option, which can be used to add data files directly on creation. This will call the attach_files method on the object.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 28

def new(*args)
  the_source = if((args.size == 1) && (args.first.is_a?(Hash)))
    options = args.first
    options.to_options!

    # We have an option hash to init the source
    files = options.delete(:files)
    options[:uri] = uri_string_for(options[:uri], false)
    if(autofill_overwrites?)
      options[:uri] = auto_uri
    elsif(autofill_uri?)
      options[:uri] ||= auto_uri
    end
    attributes = split_attribute_hash(options)
    the_source = super(attributes[:db_attributes])
    the_source.add_semantic_attributes(false, attributes[:semantic_attributes])
    the_source.attach_files(files) if(files)
    the_source
  elsif(args.size == 1 && ( uri_s = uri_string_for(args[0]))) # One string argument should be the uri
    # Either the current object from the db, or a new one if it doesn't exist in the db
    find(:first, :conditions => { :uri => uri_s } ) || super(:uri => uri_s)
  elsif(args.size == 0 && autofill_uri?)
    auto = auto_uri
    raise(ArgumentError, "Record already exists #{auto}") if(ActiveSource.exists?(auto))
    super(:uri => auto)
  else
    # In this case, it's a generic "new" call
    super
  end
  the_source.add_additional_rdf_types if(the_source.new_record?)
  the_source
end

#paginate(*args) ⇒ Object

The pagination will also use the prepare_options! to have access to the advanced finder options



172
173
174
175
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 172

def paginate(*args)
  prepare_options!(args.last) if(args.last.is_a?(Hash))
  super
end

#property_options_for(property) ⇒ Object



230
231
232
233
234
235
236
237
238
239
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 230

def property_options_for(property)
  property = defined_props[property.to_s] if(defined_props[property.to_s])
  this_options = my_property_options[property.to_s]
  parent_options = superclass.try_call.property_options_for(property)
  if(this_options && parent_options)
    parent_options.merge(this_options)
  else
    this_options || parent_options || {}
  end
end

#props_to_destroyObject

All the options that should be destroy for :dependent => :destroy settings



246
247
248
249
250
251
252
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 246

def props_to_destroy
  to_destroy = (superclass.try_call.props_to_destroy || [])
  my_property_options.each do |prop, options|
    to_destroy << prop if(options[:dependent] == :destroy)
  end
  to_destroy
end

#rewrite(id, attributes) ⇒ Object

Like update, only that it will overwrite the given attributes instead of adding to themƒ

Raises:

  • (ActiveRecord::RecordNotFound)


164
165
166
167
168
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 164

def rewrite(id, attributes)
  record = find(id)
  raise(ActiveRecord::RecordNotFound) unless(record)
  record.rewrite_attributes(attributes)
end

#split_attribute_hash(attributes) ⇒ Object

Splits the attribute hash that is given for new, update and the like. This will return another hash, where result will contain the hash of the database attributes while result will contain the other attributes.

The semantic attributes will be expanded to full URIs whereever possible.

This method will not check for attributes that correspond to singular property names.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 214

def split_attribute_hash(attributes)
  assit_kind_of(Hash, attributes)
  db_attributes = {}
  semantic_attributes = {}
  attributes.each do |field, value|
    if(db_attr?(field))
      db_attributes[field] = value
    elsif(defined_property?(field))
      semantic_attributes[field] = value
    else
      semantic_attributes[expand_uri(field)] = value
    end
  end
  { :semantic_attributes => semantic_attributes, :db_attributes => db_attributes }
end

#update(id, attributes) ⇒ Object

Semantic version of ActiveRecord::Base#update - the id may be a record id or an URL, and the attributes may contain semantic attributes. See the update_attributes method for details on how the semantic attributes behave.

Raises:

  • (ActiveRecord::RecordNotFound)


156
157
158
159
160
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 156

def update(id, attributes)
  record = find(id)
  raise(ActiveRecord::RecordNotFound) unless(record)
  record.update_attributes(attributes)
end

#value_for(thing) ⇒ Object

If will return itself unless the value is a SemanticProperty, in which case it will return the property’s value.



179
180
181
# File 'lib/talia_core/active_source_parts/class_methods.rb', line 179

def value_for(thing)
  thing.is_a?(SemanticProperty) ? thing.value : thing
end