talia_core 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +6 -27
- data/VERSION.yml +3 -2
- data/config/database.yml +11 -11
- data/config/talia_core.yml +11 -6
- data/config/talia_core.yml.example +11 -6
- data/generators/talia_base/talia_base_generator.rb +3 -0
- data/generators/talia_base/templates/README +1 -1
- data/generators/talia_base/templates/app/controllers/source_data_controller.rb +1 -1
- data/generators/talia_base/templates/app/controllers/sources_controller.rb +31 -12
- data/generators/talia_base/templates/app/helpers/sources_helper.rb +77 -1
- data/generators/talia_base/templates/app/views/layouts/sources.html.erb +22 -0
- data/generators/talia_base/templates/app/views/sources/_data_list.html.erb +17 -0
- data/generators/talia_base/templates/app/views/sources/_property_item.html.erb +10 -0
- data/generators/talia_base/templates/app/views/sources/_property_list.html.erb +13 -0
- data/generators/talia_base/templates/app/views/sources/index.html.erb +16 -11
- data/generators/talia_base/templates/app/views/sources/semantic_templates/default/default.html.erb +8 -19
- data/generators/talia_base/templates/config/routes.rb +11 -0
- data/generators/talia_base/templates/migrations/create_semantic_relations.rb +2 -1
- data/generators/talia_base/templates/public/images/core/arrow.png +0 -0
- data/generators/talia_base/templates/public/images/core/building.png +0 -0
- data/generators/talia_base/templates/public/images/core/contents_top_left.gif +0 -0
- data/generators/talia_base/templates/public/images/core/document-horizontal-text.png +0 -0
- data/generators/talia_base/templates/public/images/core/document.png +0 -0
- data/generators/talia_base/templates/public/images/core/gear.png +0 -0
- data/generators/talia_base/templates/public/images/core/group.png +0 -0
- data/generators/talia_base/templates/public/images/core/header_bg.gif +0 -0
- data/generators/talia_base/templates/public/images/core/image.png +0 -0
- data/generators/talia_base/templates/public/images/core/imagebig.png +0 -0
- data/generators/talia_base/templates/public/images/core/left_edge.gif +0 -0
- data/generators/talia_base/templates/public/images/core/letter.png +0 -0
- data/generators/talia_base/templates/public/images/core/line.png +0 -0
- data/generators/talia_base/templates/public/images/core/logo.gif +0 -0
- data/generators/talia_base/templates/public/images/core/map.png +0 -0
- data/generators/talia_base/templates/public/images/core/period.png +0 -0
- data/generators/talia_base/templates/public/images/core/person.png +0 -0
- data/generators/talia_base/templates/public/images/core/person_default.png +0 -0
- data/generators/talia_base/templates/public/images/core/place.png +0 -0
- data/generators/talia_base/templates/public/images/core/source.png +0 -0
- data/generators/talia_base/templates/public/images/core/television.png +0 -0
- data/generators/talia_base/templates/public/images/core/text.png +0 -0
- data/generators/talia_base/templates/public/images/core/type.png +0 -0
- data/generators/talia_base/templates/public/images/core/video.png +0 -0
- data/generators/talia_base/templates/public/stylesheets/img/arrow.png +0 -0
- data/generators/talia_base/templates/public/stylesheets/main.css +276 -0
- data/generators/talia_base/templates/script/configure_talia +1 -1
- data/generators/talia_base/templates/script/setup_talia_backend +2 -0
- data/lib/core_ext/platform.rb +1 -0
- data/lib/core_ext/string.rb +6 -0
- data/lib/talia_core/active_source.rb +62 -3
- data/lib/talia_core/active_source_parts/class_methods.rb +36 -122
- data/lib/talia_core/active_source_parts/finders.rb +158 -0
- data/lib/talia_core/active_source_parts/predicate_handler.rb +7 -8
- data/lib/talia_core/active_source_parts/xml/generic_reader.rb +95 -11
- data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +6 -13
- data/lib/talia_core/active_source_parts/xml/source_reader.rb +8 -3
- data/lib/talia_core/data_types/data_loader.rb +14 -6
- data/lib/talia_core/data_types/data_record.rb +5 -1
- data/lib/talia_core/data_types/iip_data.rb +1 -1
- data/lib/talia_core/data_types/mime_mapping.rb +8 -3
- data/lib/talia_core/errors.rb +4 -0
- data/lib/talia_core/initializer.rb +1 -8
- data/lib/talia_core/property_string.rb +58 -0
- data/lib/talia_core/semantic_collection_item.rb +3 -2
- data/lib/talia_core/semantic_collection_wrapper.rb +236 -198
- data/lib/talia_core/source.rb +130 -178
- data/lib/talia_core/source_types/collection.rb +15 -0
- data/lib/talia_core/source_types/dc_resource.rb +22 -0
- data/lib/talia_core/source_types/dummy_source.rb +22 -0
- data/lib/talia_core.rb +0 -1
- data/lib/talia_util/import_job_helper.rb +44 -16
- data/lib/talia_util/io_helper.rb +21 -1
- data/lib/talia_util/rake_tasks.rb +48 -72
- data/lib/talia_util/rdf_update.rb +22 -13
- data/lib/talia_util/test_helpers.rb +1 -1
- data/lib/talia_util.rb +0 -2
- data/test/core_ext/string_test.rb +5 -0
- data/test/talia_core/active_source_test.rb +151 -14
- data/test/talia_core/generic_xml_test.rb +46 -2
- data/test/talia_core/initializer_test.rb +0 -1
- data/test/talia_core/property_string_test.rb +78 -0
- data/test/talia_core/source_reader_test.rb +5 -1
- data/test/talia_core/source_test.rb +23 -32
- data/test/talia_util/import_job_helper_test.rb +1 -1
- data/test/talia_util/io_helper_test.rb +44 -0
- metadata +399 -373
- data/generators/talia_base/templates/app/views/sources/semantic_templates/default/province.html.erb +0 -19
- data/lib/acts_as_roled.rb +0 -11
- data/lib/talia_core/collection.rb +0 -13
- data/lib/talia_core/dc_resource.rb +0 -20
- data/lib/talia_core/dummy_source.rb +0 -20
- data/lib/talia_core/rails_ext/actionpack/action_controller/record_identifier.rb +0 -13
- data/lib/talia_core/rails_ext/actionpack/action_controller.rb +0 -1
- data/lib/talia_core/rails_ext/actionpack.rb +0 -1
- data/lib/talia_core/rails_ext.rb +0 -1
- data/lib/talia_util/data_import.rb +0 -91
- data/lib/talia_util/yaml_import.rb +0 -80
@@ -0,0 +1,158 @@
|
|
1
|
+
module TaliaCore
|
2
|
+
module ActiveSourceParts
|
3
|
+
|
4
|
+
# All class methods that are used for finding sources.
|
5
|
+
module Finders
|
6
|
+
|
7
|
+
|
8
|
+
# Finder also accepts uris as "ids". There are also some additional options
|
9
|
+
# that are accepted:
|
10
|
+
#
|
11
|
+
# [*:find_through*] accepts and array with an predicate name and an object
|
12
|
+
# value/uri, to search for predicates that match the given predicate/value
|
13
|
+
# combination
|
14
|
+
# [*:type*] specifically looks for sources with the given type.
|
15
|
+
# [*:find_through_inv*] like :find_through, but for the "inverse" lookup
|
16
|
+
# [*:prefetch_relations*] if set to "true", this will pre-load all semantic
|
17
|
+
# relations for the sources (experimental, not fully implemented yet)
|
18
|
+
def find(*args)
|
19
|
+
prefetching = false
|
20
|
+
if(args.last.is_a?(Hash))
|
21
|
+
options = args.last
|
22
|
+
options.to_options!
|
23
|
+
prefetching = options.delete(:prefetch_relations)
|
24
|
+
if(options.empty?) # If empty we remove the args hash, so that the 1-param uri search works
|
25
|
+
args.pop
|
26
|
+
else
|
27
|
+
prepare_options!(options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
result = if(args.size == 1 && (uri_s = uri_string_for(args[0])))
|
32
|
+
src = super(:first, :conditions => { :uri => uri_s })
|
33
|
+
raise(ActiveRecord::RecordNotFound, "Not found: #{uri_s}") unless(src)
|
34
|
+
src
|
35
|
+
else
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
prefetch_relations_for(result) if(prefetching)
|
40
|
+
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
# Modify the count helper so that it can use the advanced options of the
|
45
|
+
# ActiveSource #find routine
|
46
|
+
def count(*args)
|
47
|
+
if((options = args.last).is_a?(Hash))
|
48
|
+
options.to_options!
|
49
|
+
options.delete(:prefetch_relations) # This is not relevant for counting
|
50
|
+
prepare_options!(options)
|
51
|
+
end
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
55
|
+
# Find a list of sources which contains the given token inside the local name.
|
56
|
+
# This means that the namespace it will be excluded.
|
57
|
+
#
|
58
|
+
# Sources in system:
|
59
|
+
# * http://talia.org/one
|
60
|
+
# * http://talia.org/two
|
61
|
+
#
|
62
|
+
# Source.find_by_uri_token('a') # => [ ]
|
63
|
+
# Source.find_by_uri_token('o') # => [ 'http://talia.org/one', 'http://talia.org/two' ]
|
64
|
+
#
|
65
|
+
# NOTE: It internally use a MySQL function, as sql condition, to find the local name of the uri.
|
66
|
+
def find_by_uri_token(token, options = {})
|
67
|
+
find(:all, {
|
68
|
+
:conditions => [ "LOWER(SUBSTRING_INDEX(uri, '/', -1)) LIKE ?", '%' + token.downcase + '%' ],
|
69
|
+
:order => "uri ASC" }.merge!(options))
|
70
|
+
end
|
71
|
+
|
72
|
+
# Find the Sources within the given namespace by a partial local name
|
73
|
+
def find_by_partial_local(namespace, local_part, options = {})
|
74
|
+
namesp = N::URI[namespace]
|
75
|
+
return [] unless(namesp)
|
76
|
+
find(:all, {
|
77
|
+
:conditions => [ 'uri LIKE ?', "#{namesp.uri}#{local_part}%" ],
|
78
|
+
:order => "uri ASC"}.merge!(options))
|
79
|
+
end
|
80
|
+
|
81
|
+
# Find the fist Source that matches the given URI.
|
82
|
+
# It's useful for admin pane, because users visit:
|
83
|
+
# /admin/sources/<source_id>/edit
|
84
|
+
# but that information is not enough, since we store
|
85
|
+
# into the database the whole reference as URI:
|
86
|
+
# http://localnode.org/av_media_sources/source_id
|
87
|
+
def find_by_partial_uri(id, options = {})
|
88
|
+
find(:all, { :conditions => ["uri LIKE ?", '%' + id + '%'] }.merge!(options))
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Checks if the :find_through option is set. If so, this expects the
|
94
|
+
# option to have 2 values: The first representing the URL of the predicate
|
95
|
+
# and the second the URL or value that should be matched.
|
96
|
+
#
|
97
|
+
# An optional third parameter can be used to force an object search on the
|
98
|
+
# semantic_properties table (instead of active_sources) - if not present
|
99
|
+
# this will be auto-guessed from the "object value", checking if it appears
|
100
|
+
# to be an URL or not.
|
101
|
+
#
|
102
|
+
# ...find(:find_through => [N::RDF::something, 'value', true]
|
103
|
+
def check_for_find_through!(options)
|
104
|
+
if(f_through = options.delete(:find_through))
|
105
|
+
assit_kind_of(Array, f_through)
|
106
|
+
raise(ArgumentError, "Passed non-hash conditions with :find_through") if(options.has_key?(:conditions) && !options[:conditions].is_a?(Hash))
|
107
|
+
raise(ArgumentError, "Cannot pass custom join conditions with :find_through") if(options.has_key?(:joins))
|
108
|
+
predicate = f_through[0]
|
109
|
+
obj_val = f_through[1]
|
110
|
+
search_prop = (f_through.size > 2) ? f_through[2] : !(obj_val.to_s =~ /:/)
|
111
|
+
options[:joins] = default_joins(!search_prop, search_prop)
|
112
|
+
options[:conditions] ||= {}
|
113
|
+
options[:conditions]['semantic_relations.predicate_uri'] = predicate.to_s
|
114
|
+
if(search_prop)
|
115
|
+
options[:conditions]['obj_props.value'] = obj_val.to_s
|
116
|
+
else
|
117
|
+
options[:conditions]['obj_sources.uri'] = obj_val.to_s
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Check for the :find_through_inv option. This expects the 2 basic values
|
123
|
+
# in the same way as :find_through.
|
124
|
+
#
|
125
|
+
# find(:find_through_inv => [N::RDF::to_me, my_uri]
|
126
|
+
def check_for_find_through_inv!(options)
|
127
|
+
if(f_through = options.delete(:find_through_inv))
|
128
|
+
assit_kind_of(Array, f_through)
|
129
|
+
raise(ArgumentError, "Passed non-hash conditions with :find_through") if(options.has_key?(:conditions) && !options[:conditions].is_a?(Hash))
|
130
|
+
raise(ArgumentError, "Cannot pass custom join conditions with :find_through") if(options.has_key?(:joins))
|
131
|
+
options[:joins] = default_inv_joins
|
132
|
+
options[:conditions] ||= {}
|
133
|
+
options[:conditions]['semantic_relations.predicate_uri'] = f_through[0].to_s
|
134
|
+
options[:conditions]['sub_sources.uri'] = f_through[1].to_s
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
# Checks for the :type option in the find options. This is the same as
|
140
|
+
# doing a :find_through on the rdf type
|
141
|
+
def check_for_type_find!(options)
|
142
|
+
if(f_type = options.delete(:type))
|
143
|
+
options[:find_through] = [N::RDF::type, f_type.to_s, false]
|
144
|
+
check_for_find_through!(options)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Takes the "advanced" options that can be passed to the find method and
|
149
|
+
# converts them into "standard" find options.
|
150
|
+
def prepare_options!(options)
|
151
|
+
check_for_find_through!(options)
|
152
|
+
check_for_type_find!(options)
|
153
|
+
check_for_find_through_inv!(options)
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -17,7 +17,7 @@ module TaliaCore
|
|
17
17
|
raise(RangeError, "Too many sources for prefetching.") if(sources.size > limit)
|
18
18
|
src_hash = {}
|
19
19
|
sources.each { |src| src_hash[src.id] = src }
|
20
|
-
conditions =
|
20
|
+
conditions = { :subject_id => src_hash.keys }
|
21
21
|
joins = ActiveSource.sources_join
|
22
22
|
joins << ActiveSource.props_join
|
23
23
|
relations = SemanticRelation.find(:all, :conditions => conditions,
|
@@ -51,20 +51,19 @@ module TaliaCore
|
|
51
51
|
# so that the object will always be the same as long as the parent source
|
52
52
|
# lives.
|
53
53
|
def get_objects_on(predicate)
|
54
|
-
TaliaCore::logger.warn "GETTING OBJECTS (#{predicate}) #{@type_cache.inspect}"
|
55
54
|
@type_cache ||= {}
|
56
55
|
active_wrapper = @type_cache[predicate.to_s]
|
57
56
|
|
58
|
-
|
59
57
|
if(active_wrapper.nil?)
|
60
|
-
# If this is a prefetched source we have everything - no use looking further
|
61
|
-
# TODO: Returns an Array instead of a wrapper
|
62
|
-
return [] if(@prefetched)
|
63
|
-
|
64
58
|
active_wrapper = SemanticCollectionWrapper.new(self, predicate)
|
59
|
+
|
60
|
+
# If this is a prefetched source we have everything, so we can
|
61
|
+
# initialize the wrapper without loading anything
|
62
|
+
active_wrapper.init_as_empty! if(@prefetched)
|
63
|
+
|
65
64
|
@type_cache[predicate.to_s] = active_wrapper
|
66
65
|
end
|
67
|
-
|
66
|
+
|
68
67
|
active_wrapper
|
69
68
|
end
|
70
69
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'hpricot'
|
2
|
+
require 'pathname'
|
2
3
|
|
3
4
|
module TaliaCore
|
4
5
|
module ActiveSourceParts
|
@@ -16,6 +17,7 @@ module TaliaCore
|
|
16
17
|
class GenericReader
|
17
18
|
|
18
19
|
extend TaliaUtil::IoHelper
|
20
|
+
include TaliaUtil::IoHelper
|
19
21
|
include TaliaUtil::Progressable
|
20
22
|
|
21
23
|
# Helper class for state
|
@@ -28,11 +30,14 @@ module TaliaCore
|
|
28
30
|
# See the IoHelper class for help on the options. A progressor may
|
29
31
|
# be supplied on which the importer will report it's progress.
|
30
32
|
def sources_from_url(url, options = nil, progressor = nil)
|
31
|
-
open_generic(url, options) { |io| sources_from(io, progressor) }
|
33
|
+
open_generic(url, options) { |io| sources_from(io, progressor, url) }
|
32
34
|
end
|
33
35
|
|
34
|
-
|
36
|
+
# Reader the sources from the given IO stream. You may specify a base
|
37
|
+
# url to help the reader to decide from where files should be opened.
|
38
|
+
def sources_from(source, progressor = nil, base_url=nil)
|
35
39
|
reader = self.new(source)
|
40
|
+
reader.base_file_url = base_url if(base_url)
|
36
41
|
reader.progressor = progressor
|
37
42
|
reader.sources
|
38
43
|
end
|
@@ -91,6 +96,17 @@ module TaliaCore
|
|
91
96
|
end
|
92
97
|
@sources.values
|
93
98
|
end
|
99
|
+
|
100
|
+
# This is the "base" for resolving file URLs. If a file URL is found
|
101
|
+
# to be relative, it will be relative to this URL
|
102
|
+
def base_file_url
|
103
|
+
@base_file_url ||= TALIA_ROOT
|
104
|
+
end
|
105
|
+
|
106
|
+
# Assign a new base url
|
107
|
+
def base_file_url=(new_base_url)
|
108
|
+
@base_file_url = base_for(new_base_url)
|
109
|
+
end
|
94
110
|
|
95
111
|
def add_source_with_check(source_attribs)
|
96
112
|
assit_kind_of(Hash, source_attribs)
|
@@ -103,10 +119,10 @@ module TaliaCore
|
|
103
119
|
@sources[uri].each do |key, value|
|
104
120
|
next unless(new_value = source_attribs.delete(key))
|
105
121
|
|
106
|
-
assit(!((key.to_sym == :type) && (value != 'TaliaCore::DummySource') && (value != new_value)), "Type should not change during import, may be a format problem. (From #{value} to #{new_value})")
|
122
|
+
assit(!((key.to_sym == :type) && (value != 'TaliaCore::SourceTypes::DummySource') && (value != new_value)), "Type should not change during import, may be a format problem. (From #{value} to #{new_value})")
|
107
123
|
if(new_value.is_a?(Array) && value.is_a?(Array))
|
108
124
|
# If both are Array-types, the new elements will be appended
|
109
|
-
# and duplicates
|
125
|
+
# and duplicates will be removed
|
110
126
|
@sources[uri][key] = (value + new_value).uniq
|
111
127
|
else
|
112
128
|
# Otherwise just replace
|
@@ -184,18 +200,27 @@ module TaliaCore
|
|
184
200
|
|
185
201
|
# Adds a value for the given predicate (may also be a database field)
|
186
202
|
def add(predicate, object, required = false)
|
203
|
+
# We need to check if the object elements are already strings -
|
204
|
+
# otherwise we would *.to_s the PropertyString objects, which would
|
205
|
+
# destroy the metadata in them.
|
187
206
|
if(object.kind_of?(Array))
|
188
|
-
object.each { |obj| set_element(predicate, obj.to_s, required) }
|
207
|
+
object.each { |obj| set_element(predicate, obj.is_a?(String) ? obj : obj.to_s, required) }
|
189
208
|
else
|
190
|
-
set_element(predicate, object.to_s, required)
|
209
|
+
set_element(predicate, object.is_a?(String) ? object : object.to_s, required)
|
191
210
|
end
|
192
211
|
end
|
193
212
|
|
213
|
+
# Adds a value with the given prediate and language/type information
|
214
|
+
def add_i18n(predicate, object, lang, type=nil)
|
215
|
+
object = object.blank? ? nil : TaliaCore::PropertyString.new(object, lang, type)
|
216
|
+
add(predicate, object)
|
217
|
+
end
|
218
|
+
|
194
219
|
# Adds a date field. This will attempt to parse the original string
|
195
220
|
# and write the result as an ISO 8061 compliant date string. Note
|
196
221
|
# that this won't be able to parse everything you throw at it, though.
|
197
222
|
def add_date(predicate, date, required = false, fmt = nil)
|
198
|
-
add(predicate, parse_date(date, fmt), required)
|
223
|
+
add(predicate, to_iso8601(parse_date(date, fmt)), required)
|
199
224
|
end
|
200
225
|
|
201
226
|
# Adds a date interval as an ISO 8061 compliant date string. See
|
@@ -208,7 +233,7 @@ module TaliaCore
|
|
208
233
|
elsif(end_date.blank?)
|
209
234
|
add_date(predicate, end_date, true, fmt)
|
210
235
|
else
|
211
|
-
add(predicate, "#{parse_date(start_date, fmt)}/#{parse_date(end_date, fmt)}", required)
|
236
|
+
add(predicate, "#{to_iso8601(parse_date(start_date, fmt))}/#{to_iso8601(parse_date(end_date, fmt))}", required)
|
212
237
|
end
|
213
238
|
end
|
214
239
|
|
@@ -221,7 +246,7 @@ module TaliaCore
|
|
221
246
|
end
|
222
247
|
if(object.kind_of?(Array))
|
223
248
|
object.each do |obj|
|
224
|
-
raise(ArgumentError, "Cannot add relation on database field") if(ActiveSource.db_attr?(predicate))
|
249
|
+
raise(ArgumentError, "Cannot add relation on database field <#{predicate}> - <#{object.inspect}>") if(ActiveSource.db_attr?(predicate))
|
225
250
|
set_element(predicate, "<#{irify(obj)}>", required)
|
226
251
|
end
|
227
252
|
else
|
@@ -230,14 +255,63 @@ module TaliaCore
|
|
230
255
|
end
|
231
256
|
end
|
232
257
|
|
233
|
-
# Add a file to the source being imported
|
258
|
+
# Add a file to the source being imported. See the DataLoader module for a description of
|
259
|
+
# the possible options
|
234
260
|
def add_file(urls, options = {})
|
235
261
|
return if(urls.blank?)
|
236
262
|
urls = [ urls ] unless(urls.is_a?(Array))
|
237
|
-
files = urls.collect { |url| { :url => url
|
263
|
+
files = urls.collect { |url| { :url => get_absolute_file_url(url), :options => options } }
|
238
264
|
@current.attributes[:files] = files if(files.size > 0)
|
239
265
|
end
|
240
266
|
|
267
|
+
# Gets an absolute path to the given file url, using the base_file_url
|
268
|
+
def get_absolute_file_url(url)
|
269
|
+
orig_url = url.to_s.strip
|
270
|
+
|
271
|
+
url = file_url(orig_url)
|
272
|
+
# If a file:// was stripped from the url, this means it will always point
|
273
|
+
# to a file
|
274
|
+
force_file = (orig_url != url)
|
275
|
+
# Indicates wether the base url is a network url or a file/directory
|
276
|
+
base_is_net = !base_file_url.is_a?(String)
|
277
|
+
# Try to find if we have a "net" URL if we aren't sure if this is a file. In
|
278
|
+
# case the base url is a network url, we'll always assume that the
|
279
|
+
# url is also a net thing. Otherwise we only have a net url if it contains a
|
280
|
+
# '://' string
|
281
|
+
is_net_url = !force_file && (base_is_net || url.include?('://'))
|
282
|
+
# The url is absolute if there is a : character to be found
|
283
|
+
|
284
|
+
|
285
|
+
if(is_net_url)
|
286
|
+
base_is_net ? join_url(base_file_url, url) : url
|
287
|
+
else
|
288
|
+
base_is_net ? url : join_files(base_file_url, url)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# Joins the two files. If the path is an absolute path,
|
293
|
+
# the base_dir is ignored
|
294
|
+
def join_files(base_dir, path)
|
295
|
+
if(Pathname.new(path).relative?)
|
296
|
+
File.join(base_dir, path)
|
297
|
+
else
|
298
|
+
path
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# Joins the two url parts. If the path is an absolute URL,
|
303
|
+
# the base_url is ignored.
|
304
|
+
def join_url(base_url, path)
|
305
|
+
return path if(path.include?(':')) # Absolute URL contains ':'
|
306
|
+
if(path[0..0] == '/')
|
307
|
+
new_url = base_url.clone
|
308
|
+
new_url.path = path
|
309
|
+
new_url.to_s
|
310
|
+
else
|
311
|
+
(base_file_url + path).to_s
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
241
315
|
# Returns true if the given source was already imported. This can return false
|
242
316
|
# if you call this for the currently importing source.
|
243
317
|
def source_exists?(uri)
|
@@ -337,7 +411,10 @@ module TaliaCore
|
|
337
411
|
|
338
412
|
# Get the content of exactly one child element of type "elem" of the
|
339
413
|
# currently importing element.
|
414
|
+
#
|
415
|
+
# If elem is set to :self, this will give the content of the current element
|
340
416
|
def from_element(elem)
|
417
|
+
return @current.element.inner_text.strip if(elem == :self)
|
341
418
|
elements = all_elements(elem)
|
342
419
|
elements = elements.uniq if(elements.size > 1) # Try to ignore dupes
|
343
420
|
raise(ArgumentError, "More than one element of #{elem} in #{@current.element.inspect}") if(elements.size > 1)
|
@@ -352,6 +429,13 @@ module TaliaCore
|
|
352
429
|
result
|
353
430
|
end
|
354
431
|
|
432
|
+
# Get the iso8601 string for the date
|
433
|
+
def to_iso8601(date)
|
434
|
+
return nil unless(date)
|
435
|
+
date = DateTime.parse(date) unless(date.respond_to?(:strftime))
|
436
|
+
date.strftime('%Y-%m-%dT%H:%M:%SZ')
|
437
|
+
end
|
438
|
+
|
355
439
|
# Parses the given string and returns it as a date object
|
356
440
|
def parse_date(date, fmt = nil)
|
357
441
|
return nil if(date.blank?)
|
@@ -66,22 +66,15 @@ module TaliaCore
|
|
66
66
|
# Splits up the value, extracting encoded language codes and RDF data types. The
|
67
67
|
# result will be returned as a hash, with the "true" value being "value"
|
68
68
|
def extract_values(value)
|
69
|
+
prop_string = PropertyString.parse(value)
|
69
70
|
result = {}
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
result['rdf:datatype'] = type_split.last if(type_split.size > 1)
|
75
|
-
result['value'] = (type_split.first || '')
|
71
|
+
result['value'] = prop_string
|
72
|
+
result['rdf:datatype'] = prop_string.type if(prop_string.type)
|
73
|
+
result['xml:lang'] = prop_string.lang if(prop_string.lang)
|
74
|
+
|
76
75
|
result
|
77
76
|
end
|
78
|
-
|
79
|
-
# Helper to extract a language string. The lang value, if any, will be added to the hash
|
80
|
-
def extract_lang(value, hash)
|
81
|
-
lang_split = value.split('@')
|
82
|
-
hash['xml:lang'] = lang_split.last if(lang_split.size > 1)
|
83
|
-
lang_split.first || ''
|
84
|
-
end
|
77
|
+
|
85
78
|
end
|
86
79
|
end
|
87
80
|
end
|
@@ -6,9 +6,14 @@ module TaliaCore
|
|
6
6
|
class SourceReader < GenericReader
|
7
7
|
|
8
8
|
element :source do
|
9
|
-
nested :attribute do
|
10
|
-
|
11
|
-
|
9
|
+
nested :attribute do
|
10
|
+
predicate = from_element(:predicate)
|
11
|
+
# We need to treat each value separately, as the can have 'xml:lang'
|
12
|
+
# attributes
|
13
|
+
nested :value do
|
14
|
+
add_i18n predicate, from_element(:self), from_attribute('xml:lang')
|
15
|
+
end
|
16
|
+
add_rel predicate, all_elements(:object)
|
12
17
|
end
|
13
18
|
add_file all_elements(:file)
|
14
19
|
end
|
@@ -26,13 +26,14 @@ module TaliaCore
|
|
26
26
|
# will *always* attempt to determine the mime type through the location parameter, unless
|
27
27
|
# an explicit mime type is given.
|
28
28
|
def create_from_url(uri, options = {})
|
29
|
-
|
30
|
-
|
29
|
+
options.to_options!
|
30
|
+
options.assert_valid_keys(:mime_type, :location, :http_credentials)
|
31
|
+
|
32
|
+
mime_type = options[:mime_type]
|
33
|
+
location = options[:location]
|
31
34
|
# If a Mime type is given, use that.
|
32
35
|
if(mime_type)
|
33
36
|
mime_type = Mime::Type.lookup(mime_type) if(mime_type.is_a?(String))
|
34
|
-
elsif(location)
|
35
|
-
mime_type = Mime::Type.lookup_by_extension(File.extname(location)[1..-1])
|
36
37
|
end
|
37
38
|
|
38
39
|
data_records = []
|
@@ -49,13 +50,15 @@ module TaliaCore
|
|
49
50
|
# If we have a "standard" uri, we cut off at the last slash (the
|
50
51
|
# File.basename would use the system file separator)
|
51
52
|
location ||= uri.rindex('/') ? uri[(uri.rindex('/') + 1)..-1] : uri
|
52
|
-
|
53
|
+
|
53
54
|
if(is_file)
|
54
|
-
mime_type ||=
|
55
|
+
mime_type ||= mime_by_location(location)
|
55
56
|
open_and_create(mime_type, location, uri, true)
|
56
57
|
else
|
57
58
|
open_from_url(uri, options[:http_credentials]) do |io|
|
58
59
|
mime_type ||= Mime::Type.lookup(io.content_type)
|
60
|
+
# Just in case we didn't get any content type
|
61
|
+
mime_type ||= mime_by_location(location)
|
59
62
|
open_and_create(mime_type, location, io, false)
|
60
63
|
end
|
61
64
|
end
|
@@ -63,6 +66,11 @@ module TaliaCore
|
|
63
66
|
end
|
64
67
|
|
65
68
|
private
|
69
|
+
|
70
|
+
# Get the mime type from the location
|
71
|
+
def mime_by_location(location)
|
72
|
+
Mime::Type.lookup_by_extension(File.extname(location)[1..-1].downcase)
|
73
|
+
end
|
66
74
|
|
67
75
|
# The main loader. This will handle the lookup from the mapping and the creating of the
|
68
76
|
# data objects. Depending on the setting of is_file, the source parameter will be interpreted
|
@@ -11,6 +11,8 @@ module TaliaCore
|
|
11
11
|
belongs_to :source, :class_name => 'TaliaCore::ActiveSource'
|
12
12
|
before_create :set_mime_type # Mime type must be saved before the record is written
|
13
13
|
|
14
|
+
# validates_presence_of :source
|
15
|
+
|
14
16
|
extend MimeMapping
|
15
17
|
|
16
18
|
# Declaration of main abstract methods ======================
|
@@ -74,7 +76,9 @@ module TaliaCore
|
|
74
76
|
#
|
75
77
|
# source_data = source_data_type.classify.constantize.find_by_location(location, :limit => 1)
|
76
78
|
#
|
77
|
-
|
79
|
+
data_type = "TaliaCore::DataTypes::#{source_data_type.camelize}"
|
80
|
+
source_data = self.find(:first, :conditions => ["type = ? AND location = ?", data_type, location])
|
81
|
+
|
78
82
|
raise ActiveRecord::RecordNotFound if source_data.nil?
|
79
83
|
source_data
|
80
84
|
end
|
@@ -2,12 +2,15 @@ module TaliaCore
|
|
2
2
|
module DataTypes
|
3
3
|
|
4
4
|
# Mapping from Mime types to data classes and importing methods. Currently uses a fixed
|
5
|
-
# default mapping
|
5
|
+
# default mapping. If the mime type is not known, it will use a fallback default handler.
|
6
6
|
module MimeMapping
|
7
7
|
|
8
8
|
def mapping_for(mime_type)
|
9
9
|
mime_type = Mime::Type.lookup(mime_type) if(mime_type.is_a?(String))
|
10
10
|
mapping = mapping_hash[mime_type.to_sym]
|
11
|
+
TaliaCore.logger.warn { "No data class registered for mime type #{mime_type.inspect}, trying default handler." } unless(mapping)
|
12
|
+
mapping ||= mapping_hash[:default]
|
13
|
+
|
11
14
|
raise(ArgumentError, "No data class registered for type #{mime_type.inspect}") unless(mapping)
|
12
15
|
mapping
|
13
16
|
end
|
@@ -22,7 +25,7 @@ module TaliaCore
|
|
22
25
|
map[:loader] || map[:type]
|
23
26
|
end
|
24
27
|
|
25
|
-
# Currently
|
28
|
+
# Currently there is only the default mapping
|
26
29
|
def mapping_hash
|
27
30
|
@mapping ||= {
|
28
31
|
:xml => { :type => XmlData },
|
@@ -38,7 +41,9 @@ module TaliaCore
|
|
38
41
|
:png => { :type => ImageData, :loader => :create_iip },
|
39
42
|
:gif => { :type => ImageData, :loader => :create_iip },
|
40
43
|
:pdf => { :type => PdfData },
|
41
|
-
:text => { :type => SimpleText }
|
44
|
+
:text => { :type => SimpleText },
|
45
|
+
# Default fallback handler
|
46
|
+
:default => { :type => FileRecord }
|
42
47
|
}
|
43
48
|
end
|
44
49
|
|
data/lib/talia_core/errors.rb
CHANGED
@@ -160,9 +160,6 @@ module TaliaCore
|
|
160
160
|
# The name of the local node
|
161
161
|
config["local_uri"] = "http://test.dummy/"
|
162
162
|
|
163
|
-
# The "default" namespace
|
164
|
-
config["default_namespace_uri"] = "http://default.dummy/"
|
165
|
-
|
166
163
|
# Connect options for ActiveRDF
|
167
164
|
# Defaults to in-memory RDFLite
|
168
165
|
config["rdf_connection"] = {
|
@@ -315,10 +312,6 @@ module TaliaCore
|
|
315
312
|
N::Namespace.shortcut(:local, @config["local_uri"])
|
316
313
|
talia_logger.info("Local Domain: #{N::LOCAL}")
|
317
314
|
|
318
|
-
# Register the default name
|
319
|
-
N::Namespace.shortcut(:default, @config["default_namespace_uri"])
|
320
|
-
talia_logger.debug("Default Domain: #{N::DEFAULT}")
|
321
|
-
|
322
315
|
# Register namespace for database dupes
|
323
316
|
N::Namespace.shortcut(:talia, "http://talia.discovery-project.eu/wiki/TaliaInternal#")
|
324
317
|
|
@@ -387,7 +380,7 @@ module TaliaCore
|
|
387
380
|
end
|
388
381
|
|
389
382
|
def load_core_ext
|
390
|
-
path_to_core_ext = File.join(
|
383
|
+
path_to_core_ext = File.join(TALIA_CODE_ROOT, 'lib', 'core_ext')
|
391
384
|
Dir[path_to_core_ext + '/**/*.rb'].each { |f| require f}
|
392
385
|
end
|
393
386
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module TaliaCore
|
2
|
+
|
3
|
+
# Handling of RDF string values. These values can contain both locale (language)
|
4
|
+
# and type information. (E.g. "Some value^^string@en")
|
5
|
+
#
|
6
|
+
# This class will parse the value string an make all elements available as separate
|
7
|
+
# accessors.
|
8
|
+
class PropertyString < String
|
9
|
+
|
10
|
+
attr_accessor :type, :lang
|
11
|
+
|
12
|
+
# Create a new object by parsing the given property string
|
13
|
+
def self.parse(property_string)
|
14
|
+
self.new.parse(property_string)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a new object from the given values. No parsing is done here.
|
18
|
+
def initialize(property_string = '', language = nil, type = nil)
|
19
|
+
@lang = language
|
20
|
+
@type = type
|
21
|
+
self.replace(property_string)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parses the given string into a PropertyString
|
25
|
+
def parse(property_string)
|
26
|
+
# First split for the type
|
27
|
+
type_split = property_string.split('^^')
|
28
|
+
# Check if any of the elements contains a language string
|
29
|
+
type_split = type_split.collect { |el| extract_lang(el) }
|
30
|
+
@type = (type_split.size > 1) ? type_split.last : nil
|
31
|
+
self.replace(type_split.first || '')
|
32
|
+
end
|
33
|
+
|
34
|
+
# Gives the "internal representation" - this should be equivalent
|
35
|
+
# to the string from which the object was created
|
36
|
+
def to_rdf
|
37
|
+
value = self.clone
|
38
|
+
value << '^^' << type if(type)
|
39
|
+
value << '@' << lang if(lang)
|
40
|
+
value
|
41
|
+
end
|
42
|
+
|
43
|
+
# Inspect shows the real content
|
44
|
+
def inspect
|
45
|
+
"\"#{self}\" <lang: #{lang.inspect} - type: #{type.inspect}>"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Helper to extract a language string. The lang value, if any, will be added to the hash
|
51
|
+
def extract_lang(value)
|
52
|
+
lang_split = value.split('@')
|
53
|
+
@lang ||= (lang_split.size > 1) ? lang_split.last : nil
|
54
|
+
lang_split.first || ''
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -27,7 +27,8 @@ module TaliaCore
|
|
27
27
|
@fat_relation || @plain_relation
|
28
28
|
end
|
29
29
|
|
30
|
-
# Return the "value" (Semantic relation value or the related ActiveSource)
|
30
|
+
# Return the "value" (Semantic relation value or the related ActiveSource).
|
31
|
+
# String values will actually be PropertyString strings
|
31
32
|
def value
|
32
33
|
semprop = object.is_a?(SemanticProperty)
|
33
34
|
if(@object_type)
|
@@ -36,7 +37,7 @@ module TaliaCore
|
|
36
37
|
@object_type.new(object.uri.to_s)
|
37
38
|
else
|
38
39
|
# Plain, return the object or the value for SemanticProperties
|
39
|
-
semprop ? object.value : object
|
40
|
+
semprop ? PropertyString.parse(object.value) : object
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|