talia_core 0.5.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/config/talia_core.yml.example +37 -35
- data/generators/talia_admin/templates/app/models/fake_source.rb +93 -0
- data/generators/talia_admin/templates/app/models/talia_collection.rb +13 -37
- data/generators/talia_base/talia_base_generator.rb +0 -1
- data/generators/talia_base/templates/app/controllers/custom_templates_controller.rb +2 -1
- data/generators/talia_base/templates/app/controllers/sources_controller.rb +1 -1
- data/generators/talia_base/templates/script/configure_talia +56 -73
- data/generators/talia_swicky/talia_swicky_generator.rb +18 -0
- data/generators/talia_swicky/templates/app/controllers/swicky_notebooks_controller.rb +111 -0
- data/generators/talia_swicky/templates/app/helpers/swicky_notebooks_helper.rb +29 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.builder +6 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.html.erb +10 -0
- data/generators/talia_swicky/templates/app/views/swicky_notebooks/show.html.erb +11 -0
- data/generators/talia_swicky/templates/test/fixtures/notebook.rdf +862 -0
- data/generators/talia_swicky/templates/test/functional/swicky_notebooks_controller_test.rb +44 -0
- data/lib/core_ext/boolean.rb +23 -0
- data/lib/core_ext/jdbc_rake_monkeypatch.rb +22 -0
- data/lib/core_ext/nil_class.rb +11 -0
- data/lib/core_ext/object.rb +34 -0
- data/lib/core_ext/string.rb +15 -0
- data/lib/custom_template.rb +3 -1
- data/lib/loader_helper.rb +16 -3
- data/lib/mysql.rb +7 -7
- data/lib/progressbar.rb +2 -2
- data/lib/swicky/exhibit_json/item.rb +129 -0
- data/lib/swicky/exhibit_json/item_collection.rb +129 -0
- data/lib/swicky/fragment.rb +0 -0
- data/lib/swicky/note.rb +7 -0
- data/lib/swicky/notebook.rb +78 -12
- data/lib/talia_core/active_source.rb +45 -13
- data/lib/talia_core/active_source_parts/class_methods.rb +154 -26
- data/lib/talia_core/active_source_parts/finders.rb +49 -26
- data/lib/talia_core/active_source_parts/predicate_handler.rb +71 -23
- data/lib/talia_core/active_source_parts/rdf/ntriples_reader.rb +13 -0
- data/lib/talia_core/active_source_parts/rdf/rdf_reader.rb +99 -0
- data/lib/talia_core/active_source_parts/rdf/rdfxml_reader.rb +12 -0
- data/lib/talia_core/active_source_parts/{rdf.rb → rdf_handler.rb} +52 -19
- data/lib/talia_core/active_source_parts/xml/generic_reader.rb +151 -260
- data/lib/talia_core/active_source_parts/xml/generic_reader_add_statements.rb +97 -0
- data/lib/talia_core/active_source_parts/xml/generic_reader_helpers.rb +88 -0
- data/lib/talia_core/active_source_parts/xml/generic_reader_import_statements.rb +239 -0
- data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +14 -7
- data/lib/talia_core/active_source_parts/xml/source_builder.rb +7 -3
- data/lib/talia_core/active_source_parts/xml/source_reader.rb +17 -2
- data/lib/talia_core/collection.rb +192 -1
- data/lib/talia_core/data_types/data_loader.rb +88 -18
- data/lib/talia_core/data_types/data_record.rb +24 -2
- data/lib/talia_core/data_types/delayed_copier.rb +13 -3
- data/lib/talia_core/data_types/file_record.rb +24 -13
- data/lib/talia_core/data_types/file_store.rb +111 -94
- data/lib/talia_core/data_types/iip_data.rb +104 -23
- data/lib/talia_core/data_types/iip_loader.rb +102 -56
- data/lib/talia_core/data_types/image_data.rb +3 -1
- data/lib/talia_core/data_types/media_link.rb +4 -1
- data/lib/talia_core/data_types/mime_mapping.rb +65 -38
- data/lib/talia_core/data_types/path_helpers.rb +23 -17
- data/lib/talia_core/data_types/pdf_data.rb +9 -6
- data/lib/talia_core/data_types/simple_text.rb +5 -4
- data/lib/talia_core/data_types/xml_data.rb +53 -25
- data/lib/talia_core/dummy_handler.rb +3 -2
- data/lib/talia_core/errors.rb +13 -27
- data/lib/talia_core/initializer.rb +44 -4
- data/lib/talia_core/oai/active_source_model.rb +13 -6
- data/lib/talia_core/oai/active_source_oai_adapter.rb +13 -12
- data/lib/talia_core/rdf_import.rb +1 -1
- data/lib/talia_core/rdf_resource.rb +2 -1
- data/lib/talia_core/semantic_collection_wrapper.rb +143 -151
- data/lib/talia_core/semantic_property.rb +4 -0
- data/lib/talia_core/semantic_relation.rb +84 -33
- data/lib/talia_core/source.rb +45 -25
- data/lib/talia_core/source_fragment.rb +7 -0
- data/lib/talia_core/source_transfer_object.rb +3 -1
- data/lib/talia_core/source_types/agent.rb +16 -0
- data/lib/talia_core/source_types/dc_resource.rb +3 -3
- data/lib/talia_core/source_types/marcont_resource.rb +15 -0
- data/lib/talia_core/source_types/skos_concept.rb +17 -0
- data/lib/talia_dependencies.rb +1 -1
- data/lib/talia_util.rb +1 -1
- data/lib/talia_util/bar_progressor.rb +1 -1
- data/lib/talia_util/image_conversions.rb +8 -2
- data/lib/talia_util/import_job_helper.rb +40 -3
- data/lib/talia_util/io_helper.rb +15 -4
- data/lib/talia_util/progressable.rb +50 -1
- data/lib/talia_util/rake_tasks.rb +3 -21
- data/lib/talia_util/test_helpers.rb +6 -1
- data/lib/talia_util/util.rb +108 -27
- data/lib/talia_util/xml/base_builder.rb +28 -1
- data/lib/talia_util/xml/rdf_builder.rb +81 -5
- data/lib/tasks/talia_core_tasks.rake +2 -0
- data/test/core_ext/boolean_test.rb +26 -0
- data/test/core_ext/nil_class_test.rb +14 -0
- data/test/core_ext/object_test.rb +26 -0
- data/test/core_ext/string_test.rb +11 -0
- data/test/swicky/json_encoder_test.rb +51 -42
- data/test/swicky/notebook_test.rb +13 -6
- data/test/talia_core/active_source_finder_interface_test.rb +30 -0
- data/test/talia_core/active_source_test.rb +445 -34
- data/test/talia_core/collection_test.rb +332 -0
- data/test/talia_core/data_types/file_record_test.rb +2 -23
- data/test/talia_core/ntriples_reader_test.rb +49 -0
- data/test/talia_core/rdfxml_reader_test.rb +51 -0
- data/test/talia_core/source_test.rb +12 -0
- data/test/talia_util/import_job_helper_test.rb +19 -12
- metadata +190 -90
- data/config/database.yml +0 -19
- data/config/rdfstore.yml +0 -13
- data/config/talia_core.yml +0 -24
- data/generators/talia_base/templates/migrations/bj_migration.rb +0 -10
- data/lib/JXslt/jxslt.rb +0 -60
- data/lib/swicky/json_encoder.rb +0 -179
- data/lib/talia_core/agent.rb +0 -14
- data/lib/talia_core/background_jobs/job.rb +0 -82
- data/lib/talia_core/background_jobs/progress_job.rb +0 -68
- data/lib/talia_core/data_types/temp_file_handling.rb +0 -85
- data/lib/talia_core/ordered_source.rb +0 -228
- data/lib/talia_core/semantic_collection_item.rb +0 -94
- data/lib/talia_core/source_types/collection.rb +0 -15
- data/lib/talia_util/progressbar.rb +0 -236
- data/tasks/talia_core_tasks.rake +0 -2
- data/test/talia_core/ordered_source_test.rb +0 -394
- data/test/talia_core/semantic_collection_item_test.rb +0 -125
@@ -27,13 +27,17 @@ module TaliaCore
|
|
27
27
|
# </source>
|
28
28
|
# ...
|
29
29
|
# </sources>
|
30
|
+
#
|
31
|
+
# Also see the parent class, TaliaUtil::Xml::BaseBuilder, for more information
|
30
32
|
class SourceBuilder < TaliaUtil::Xml::BaseBuilder
|
31
33
|
|
34
|
+
# Builds the XML for a single source, and returns the result as
|
35
|
+
# a string
|
32
36
|
def self.build_source(source)
|
33
37
|
make_xml_string { |build| build.write_source(source) }
|
34
38
|
end
|
35
39
|
|
36
|
-
#
|
40
|
+
# Build the XML for a single source.
|
37
41
|
def write_source(source)
|
38
42
|
@builder.source do
|
39
43
|
source.attributes.each { |attrib, value| write_attribute(attrib, value) }
|
@@ -43,7 +47,7 @@ module TaliaCore
|
|
43
47
|
|
44
48
|
private
|
45
49
|
|
46
|
-
#
|
50
|
+
# Builds an attribute tag (with contents) in a source
|
47
51
|
def write_attribute(predicate, values)
|
48
52
|
predicate = predicate.respond_to?(:uri) ? predicate.uri.to_s : predicate.to_s
|
49
53
|
values = [ values ] unless(values.respond_to?(:each))
|
@@ -53,7 +57,7 @@ module TaliaCore
|
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
|
-
# Writes a value or object tag, depeding on the target
|
60
|
+
# Writes a value or object tag, depeding on the target.
|
57
61
|
def write_target(target)
|
58
62
|
if(target.respond_to?(:uri))
|
59
63
|
@builder.object { @builder.text!(target.uri.to_s) }
|
@@ -1,21 +1,36 @@
|
|
1
|
+
require 'guid'
|
1
2
|
module TaliaCore
|
2
3
|
module ActiveSourceParts
|
3
4
|
module Xml
|
4
5
|
|
5
|
-
#
|
6
|
+
# A Reader for the "TaliaInternal" XML format. Check the code of this
|
7
|
+
# class as a simple example of how an import reader works.
|
8
|
+
#
|
9
|
+
# An example of the import format can be found in the SourceBuilder
|
10
|
+
# documentation.
|
6
11
|
class SourceReader < GenericReader
|
7
12
|
|
13
|
+
# Match the XML tags called "source", creating a new source for
|
14
|
+
# each of them
|
8
15
|
element :source do
|
16
|
+
# Match each "attribute" tag
|
9
17
|
nested :attribute do
|
18
|
+
# Read the predicate name(s) from "predicate" tag(s)
|
10
19
|
predicate = from_element(:predicate)
|
11
20
|
# We need to treat each value separately, as the can have 'xml:lang'
|
12
|
-
# attributes
|
21
|
+
# attributes, so we match each of the "value tags"
|
13
22
|
nested :value do
|
23
|
+
# Add the internationalized value from the current element, using
|
24
|
+
# the "xml:lang" attribute for the language
|
14
25
|
add_i18n predicate, from_element(:self), from_attribute('xml:lang')
|
15
26
|
end
|
27
|
+
# Match all the "object" tag and add their contents as relations
|
16
28
|
add_rel predicate, all_elements(:object)
|
17
29
|
end
|
30
|
+
# Use the content of the "file" tag as a URI/filename for loading a data
|
31
|
+
# file
|
18
32
|
add_file all_elements(:file)
|
33
|
+
@current.attributes["uri"] ||= Guid.new
|
19
34
|
end
|
20
35
|
|
21
36
|
end
|
@@ -1,4 +1,195 @@
|
|
1
1
|
module TaliaCore
|
2
|
+
|
3
|
+
# Represents a collection of sources. In addition to being a container for
|
4
|
+
# sources, the Collection class will also provide an ordering of the contained
|
5
|
+
# sources.
|
6
|
+
#
|
7
|
+
# In a nutshell, this behaves like an array of sources that preserves
|
8
|
+
# the order when saved.
|
9
|
+
#
|
10
|
+
# The ordering will always assign a ''unique'' integer value to each contained
|
11
|
+
# source that defines its position in the order of elements. The collection will
|
12
|
+
# keep an internal array where each object's index maps directly to its position
|
13
|
+
# in the collection; the array and ordering are saved to the data store when
|
14
|
+
# the collection itself is saved.
|
15
|
+
#
|
16
|
+
# The collection class is relatively lightweight and will behave mostly like
|
17
|
+
# the underlying array - most operations are simply passed through to the array and
|
18
|
+
# nothing is saved before the collection itself is saved.
|
19
|
+
#
|
20
|
+
# Operations that are passed to the underlying array are: +, <<, ==, []=, at, clear,
|
21
|
+
# collect, delete_at, delete, each, each_index, empty?, include?, index, join,
|
22
|
+
# last, length and size.
|
23
|
+
#
|
24
|
+
# This also means that all checks on added objects will only be performed when
|
25
|
+
# the collection is saved, and not much checking is done when the array is
|
26
|
+
# modified.
|
27
|
+
#
|
28
|
+
# Important: it is required that no object in the list be present more than once.
|
29
|
+
#
|
30
|
+
# In the RDF, the collection is represented as a seqContainer, using a predicate of
|
31
|
+
# "http://www.w3.org/1999/02/22-rdf-syntax-ns#_[index of element x]" to connect an
|
32
|
+
# element x with the collection.
|
33
|
+
#
|
34
|
+
# *Note*: This class replaces the previous OrderedSource class
|
2
35
|
class Collection < Source
|
36
|
+
|
37
|
+
include Enumerable
|
38
|
+
|
39
|
+
has_rdf_type N::DCNS.Collection
|
40
|
+
has_rdf_type N::SKOS.Collection
|
41
|
+
has_rdf_type N::DCMIT.Collection
|
42
|
+
|
43
|
+
before_save :rewrite_order_relations
|
44
|
+
after_save :force_rdf_rewrite
|
45
|
+
|
46
|
+
singular_property :title, N::DCNS.title
|
47
|
+
|
48
|
+
def after_initialize
|
49
|
+
@autosave_rdf = false
|
50
|
+
end
|
51
|
+
|
52
|
+
# Creates a new Collection. Takes the same parameters as
|
53
|
+
# ActiveSource.new
|
54
|
+
def self.new(*params)
|
55
|
+
collection = super(*params)
|
56
|
+
# collection.autosave_rdf = false # Will do this by ourselves
|
57
|
+
collection
|
58
|
+
end
|
59
|
+
|
60
|
+
# Many methods are directly forwarded to the underlying array
|
61
|
+
[:+, :<<, :==, :[]=, :at, :clear, :collect, :delete_at, :delete, :each,
|
62
|
+
:each_index, :empty?, :include?, :index, :join, :last, :length, :size].each do |method|
|
63
|
+
eval <<-EOM
|
64
|
+
def #{method}(*args, &block)
|
65
|
+
ordered_objects.send(:#{method}, *args, &block)
|
66
|
+
end
|
67
|
+
EOM
|
68
|
+
end
|
69
|
+
|
70
|
+
# This accessor can be used for both collection items and predicates.
|
71
|
+
# If a number is passed in, the object will behave like an Array and
|
72
|
+
# the source at the given index is returned. Otherwise the parameter
|
73
|
+
# is treated like a predicate and it behaves like ActiveSource#[].
|
74
|
+
def [](index_or_predicate)
|
75
|
+
if(index_or_predicate.is_a?(Fixnum))
|
76
|
+
ordered_objects[index_or_predicate]
|
77
|
+
else
|
78
|
+
super
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Writer that behaves in the same way as []
|
83
|
+
def []=(index_or_predicate, value)
|
84
|
+
if(index_or_predicate.is_a?(Fixnum))
|
85
|
+
ordered_objects[index_or_predicate] = value
|
86
|
+
else
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns all contained sources in an ordered array.
|
92
|
+
#
|
93
|
+
# The contained sources will appear in the sequential order in which they
|
94
|
+
# are contained in the collection, but there is no direct relation between
|
95
|
+
# the index in the collection and the index returned through this method.
|
96
|
+
# Repeated elements in the collection will be ignored.
|
97
|
+
def elements
|
98
|
+
# execute query
|
99
|
+
ordered_objects.compact.uniq
|
100
|
+
end
|
101
|
+
|
102
|
+
# See Collection.index_to_predicate
|
103
|
+
def index_to_predicate(index)
|
104
|
+
self.class.index_to_predicate(index)
|
105
|
+
end
|
106
|
+
|
107
|
+
# See Collection.predicate_to_index
|
108
|
+
def predicate_to_index(predicate)
|
109
|
+
self.class.predicate_to_index(predicate)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns the predicate that will be used for the collection element with the
|
113
|
+
# given index. The result will be:
|
114
|
+
# http://www.w3.org/1999/02/22-rdf-syntax-ns#_<index>
|
115
|
+
def self.index_to_predicate(index)
|
116
|
+
'http://www.w3.org/1999/02/22-rdf-syntax-ns#_' << ("%06d" % index.to_i)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Takes a predicate of the form produced by index_to_predicate and returns
|
120
|
+
# the numeric index of the element
|
121
|
+
def self.predicate_to_index(predicate)
|
122
|
+
predicate.sub('http://www.w3.org/1999/02/22-rdf-syntax-ns#_', '').to_i
|
123
|
+
end
|
124
|
+
|
125
|
+
# Reloading from database by clearing the internal array
|
126
|
+
def reload # :nodoc:
|
127
|
+
@ordered_objects = nil
|
128
|
+
ordered_objects
|
129
|
+
super
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns the element next to the one passed as parameter.
|
133
|
+
# Returns nil if there is no next object.
|
134
|
+
# Requires that no object in the collection is present more than once.
|
135
|
+
def next(object)
|
136
|
+
elements[elements.index(object) + 1]
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns the element previous to the one passed as parameter.
|
140
|
+
# Returns nil if there is no previous object.
|
141
|
+
# Requires that no object in the collection is present more than once.
|
142
|
+
def prev(object)
|
143
|
+
return nil if elements.index(object) == 0
|
144
|
+
elements[elements.index(object) - 1]
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns all the objects that are ordered in an array where the array
|
148
|
+
# index equals the position of the object in the ordered set. The array
|
149
|
+
# is zero-based, position that don't have an object attached will be set to
|
150
|
+
# nil.
|
151
|
+
def ordered_objects
|
152
|
+
return @ordered_objects if(@ordered_objects)
|
153
|
+
relations = query
|
154
|
+
# Let's assume the follwing is a sane assumption ;-)
|
155
|
+
# Even if a one-base collection comes in, we need to push just one element
|
156
|
+
@ordered_objects = Array.new(relations.size)
|
157
|
+
# Now add the elements so that the relation property is reflected
|
158
|
+
# on the position in the array
|
159
|
+
relations.each do |rel|
|
160
|
+
index = rel.rel_order
|
161
|
+
@ordered_objects[index] = rel.object
|
162
|
+
end
|
163
|
+
|
164
|
+
@ordered_objects
|
165
|
+
end
|
166
|
+
|
167
|
+
# This will be called before saving and will completely rewrite the relations
|
168
|
+
# that make up the ordered store, based on the internal array
|
169
|
+
def rewrite_order_relations
|
170
|
+
return unless(@ordered_objects) # If this is nil, the relations weren't loaded in the first place
|
171
|
+
objects = ordered_objects # Fetch them before deleting
|
172
|
+
# Now destroy the existing elements
|
173
|
+
SemanticRelation.destroy_all(['subject_id = ? AND rel_order IS NOT NULL', self.id])
|
174
|
+
SemanticRelation.destroy_all(['subject_id = ? AND predicate_uri = ?', self.id, N::DCT.hasPart.to_s])
|
175
|
+
# rewrite from the relations array
|
176
|
+
objects.each_index do |index|
|
177
|
+
if(obj = objects.at(index)) # Check if there's a value to handle
|
178
|
+
# Create a new relation with an order
|
179
|
+
self[index_to_predicate(index)].add_record(obj, index)
|
180
|
+
self[N::DCT.hasPart] << obj
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def force_rdf_rewrite
|
186
|
+
create_rdf(:force)
|
187
|
+
end
|
188
|
+
|
189
|
+
# execute query and return the result
|
190
|
+
def query(scope = :all)
|
191
|
+
# execute query
|
192
|
+
self.semantic_relations.find(scope, :conditions => 'rel_order IS NOT NULL', :order => :rel_order)
|
193
|
+
end
|
3
194
|
end
|
4
|
-
end
|
195
|
+
end
|
@@ -2,29 +2,94 @@ module TaliaCore
|
|
2
2
|
module DataTypes
|
3
3
|
|
4
4
|
# Used for attaching data items by laoding them from files and/or URLs. This will also attempt to
|
5
|
-
# create the correct data type for any given file.
|
5
|
+
# create the correct data type for any given file. See DataLoader::ClassMethods
|
6
|
+
|
6
7
|
module DataLoader
|
7
8
|
|
9
|
+
# The create_from_url method will create a new FileRecord from a
|
10
|
+
# data source (file or web URL). The exact mechanism for creating
|
11
|
+
# the record will depend on the MIME type of the data.
|
12
|
+
#
|
13
|
+
# =How the MIME type is determined
|
14
|
+
#
|
15
|
+
# * If the :mime_type options is provided, the system will _always_ use
|
16
|
+
# that MIME type for the new record
|
17
|
+
# * If the :location option is provided, the system will _always_ attempt
|
18
|
+
# to determine the MIME type from the "file extension" of the location,
|
19
|
+
# unless the :mime_type option is set
|
20
|
+
# * If the uri is a file, the system will use the file extension to
|
21
|
+
# determine the MIME type automatically
|
22
|
+
# * If the uri is a web URL, the system will first check if the server
|
23
|
+
# provided a MIME type in the response. If not, it will use the
|
24
|
+
# "file extension" of the uri to determine the MIME type as above
|
25
|
+
#
|
26
|
+
# =If the loader is a FileRecord class (no loader method)
|
27
|
+
#
|
28
|
+
# If no loader method is specified, the loader will simply create a
|
29
|
+
# new FileRecord object of the type specified in the loader. It will
|
30
|
+
# then use create_from_file (for files) or create_from_data (for
|
31
|
+
# a web uri) to load the data into the new record.
|
32
|
+
#
|
33
|
+
# Example:
|
34
|
+
#
|
35
|
+
# # Set a loader for png (usually done in the initializer,
|
36
|
+
# # this one is equal to the default)
|
37
|
+
# TaliaCore::DataTypes::MimeMapping.add_mapping(:png, DataTypes::ImageData)
|
38
|
+
#
|
39
|
+
# # Call the loader
|
40
|
+
# FileRecord.create_from_url('test.png')
|
41
|
+
# # This will result in the following:
|
42
|
+
# # DataTypes::ImageData.new.create_from_file('test.png', 'test.png')
|
43
|
+
#
|
44
|
+
# = If the loader is a method
|
45
|
+
#
|
46
|
+
# In case a loader method is specified, the system will simply call that
|
47
|
+
# method on the _class_ provided by the loader. The loader method must
|
48
|
+
# take the following paramters: mime_type, location, source, is_file:
|
49
|
+
#
|
50
|
+
# * _mime_type_ is the MIME type for the object being imported
|
51
|
+
# * _location_ is the location string for the current record. This
|
52
|
+
# is either the location passed in as an option, or the base name
|
53
|
+
# of the uri
|
54
|
+
# * _source_ is either the io object from which to read the data,
|
55
|
+
# or a file name
|
56
|
+
# * _is_file_ is set to true in case the _source_ is a file name
|
57
|
+
#
|
58
|
+
# Example:
|
59
|
+
#
|
60
|
+
# # Set the handler for tiff files, usually done in the initializer
|
61
|
+
# TaliaCore::DataTypes::MimeMapping.add_mapping(:tiff, :image_data, :create_iip)
|
62
|
+
#
|
63
|
+
# # Call the loader
|
64
|
+
# FileRecord.create_from_url('test.tiff')
|
65
|
+
# # This will result in the following:
|
66
|
+
# # DataTypes::ImageData.create_iip(Mime::Type.lookup(:tiff), 'test.tif', 'test.tif', true)
|
8
67
|
module ClassMethods
|
9
68
|
|
10
|
-
# Load
|
11
|
-
#
|
12
|
-
# 'text/html', or a mime type symbol).
|
69
|
+
# Load data from the given url and create FileRecord objects,
|
70
|
+
# as appropriate.
|
13
71
|
#
|
14
|
-
#
|
15
|
-
#
|
72
|
+
# The way the FileRecord is created is determined by the MIME type
|
73
|
+
# for the data. Talia has a "loader" for each MIME type - see the
|
74
|
+
# MimeMapping class to see the default loaders and to find out how to
|
75
|
+
# configure them.
|
16
76
|
#
|
17
|
-
#
|
18
|
-
#
|
77
|
+
# Each "loader" contains the FileRecord class that is used for new
|
78
|
+
# records, and (optionally) the name of a loader method which
|
79
|
+
# creates the new records. If no loader method is provided, a default
|
80
|
+
# mechanism is used.
|
19
81
|
#
|
20
|
-
#
|
21
|
-
# http_credentials = { :http_basic_authentication => [login, password] }
|
22
|
-
# See the openuri documentation for more.
|
82
|
+
# *Options*
|
23
83
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
84
|
+
# [*mime_type*] Specify the MIME type to use for the import. The parameter can either be
|
85
|
+
# a MIME::TYPE object, a string like 'text/html' or a MIME type symbol like :jpeg
|
86
|
+
# [*http_credentials*] Credentials for http authentication, if the uri requires
|
87
|
+
# that. These are the same options that openuri accepts, so see
|
88
|
+
# the documentation for that library for more information.
|
89
|
+
# _Example_: :http_credentials => { :http_basic_authentication => [login, password] }
|
90
|
+
# [*location*] The location (e.g. filename) for the new FileRecord. If a location is
|
91
|
+
# given, it will _always_ be used to determine the MIME type, unless a
|
92
|
+
# MIME type is passed explicitly as an option
|
28
93
|
def create_from_url(uri, options = {})
|
29
94
|
options.to_options!
|
30
95
|
options.assert_valid_keys(:mime_type, :location, :http_credentials)
|
@@ -51,6 +116,8 @@ module TaliaCore
|
|
51
116
|
# File.basename would use the system file separator)
|
52
117
|
location ||= uri.rindex('/') ? uri[(uri.rindex('/') + 1)..-1] : uri
|
53
118
|
|
119
|
+
assit(!location.blank?)
|
120
|
+
|
54
121
|
if(is_file)
|
55
122
|
mime_type ||= mime_by_location(location)
|
56
123
|
open_and_create(mime_type, location, uri, true)
|
@@ -69,7 +136,9 @@ module TaliaCore
|
|
69
136
|
|
70
137
|
# Get the mime type from the location
|
71
138
|
def mime_by_location(location)
|
72
|
-
|
139
|
+
extname = File.extname(location)[1..-1]
|
140
|
+
assit(!extname.blank?, 'No extname found for ' << location)
|
141
|
+
Mime::Type.lookup_by_extension(extname.downcase)
|
73
142
|
end
|
74
143
|
|
75
144
|
# The main loader. This will handle the lookup from the mapping and the creating of the
|
@@ -79,8 +148,9 @@ module TaliaCore
|
|
79
148
|
def open_and_create(mime_type, location, source, is_file)
|
80
149
|
data_type = MimeMapping.loader_type_from(mime_type)
|
81
150
|
if(data_type.is_a?(Symbol))
|
82
|
-
|
83
|
-
|
151
|
+
type = MimeMapping.class_type_from(mime_type)
|
152
|
+
raise(ArgumentError, "No handler found for loading: #{data_type}") unless(type.respond_to?(data_type))
|
153
|
+
type.send(data_type, mime_type, location, source, is_file)
|
84
154
|
else
|
85
155
|
raise(ArgumentError, "Registered handler for loading must be a method symbol or class. (#{data_type})") unless(data_type.is_a?(Class))
|
86
156
|
data_record = data_type.new
|
@@ -1,10 +1,27 @@
|
|
1
1
|
module TaliaCore
|
2
2
|
|
3
3
|
# Contains all data types that are handled by the Talia system. All data elements
|
4
|
-
# should be subclasses of DataRecord
|
4
|
+
# should be subclasses of DataRecord. Records that have data files attached are
|
5
|
+
# subclasses of FileRecord
|
5
6
|
module DataTypes
|
6
7
|
|
7
|
-
#
|
8
|
+
# Base class for all data records in Talia. This only contains a basic interface,
|
9
|
+
# without much functionality. All data-related methods will return a
|
10
|
+
# NotImplementedError
|
11
|
+
#
|
12
|
+
# The DataRecord provides an interface to access a generic array/buffer of bytes,
|
13
|
+
# with the base class not making any assumptions on how these bytes are stored.
|
14
|
+
#
|
15
|
+
# Subclasses should usually provide the inferface of this class, which is more
|
16
|
+
# or less like the standard file interface.
|
17
|
+
#
|
18
|
+
# Each data record has a "location" field, which is roughly equivalent to the file
|
19
|
+
# name, and a MIME type. The default behaviour is that, if not set manually,
|
20
|
+
# the MIME type is automatically set before saving. It will be determined by
|
21
|
+
# the "file extension" of the location field.
|
22
|
+
#
|
23
|
+
# Each data record must belong to an ActiveSource. For more information on how to
|
24
|
+
# handle records with files, see the FileRecord class
|
8
25
|
class DataRecord < ActiveRecord::Base
|
9
26
|
# Attention: These need to come before the extends, otherwise it'll blow the
|
10
27
|
# tests
|
@@ -20,6 +37,7 @@ module TaliaCore
|
|
20
37
|
|
21
38
|
# returns all bytes in the object as an array of unsigned integers
|
22
39
|
def all_bytes
|
40
|
+
raise NotImplementedError
|
23
41
|
end
|
24
42
|
|
25
43
|
# Returns all_bytes as an binary string
|
@@ -29,18 +47,22 @@ module TaliaCore
|
|
29
47
|
|
30
48
|
# returns the next byte from the object, or nil at EOS
|
31
49
|
def get_byte(close_after_single_read=false)
|
50
|
+
raise NotImplementedError
|
32
51
|
end
|
33
52
|
|
34
53
|
# returns the current position of the read cursor
|
35
54
|
def position
|
55
|
+
raise NotImplementedError
|
36
56
|
end
|
37
57
|
|
38
58
|
# adjust the position of the read cursor
|
39
59
|
def seek(new_position)
|
60
|
+
raise NotImplementedError
|
40
61
|
end
|
41
62
|
|
42
63
|
# returns the size of the object in bytes
|
43
64
|
def size
|
65
|
+
raise NotImplementedError
|
44
66
|
end
|
45
67
|
|
46
68
|
# reset the cursor to the initial state
|