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.
Files changed (122) hide show
  1. data/VERSION.yml +2 -2
  2. data/config/talia_core.yml.example +37 -35
  3. data/generators/talia_admin/templates/app/models/fake_source.rb +93 -0
  4. data/generators/talia_admin/templates/app/models/talia_collection.rb +13 -37
  5. data/generators/talia_base/talia_base_generator.rb +0 -1
  6. data/generators/talia_base/templates/app/controllers/custom_templates_controller.rb +2 -1
  7. data/generators/talia_base/templates/app/controllers/sources_controller.rb +1 -1
  8. data/generators/talia_base/templates/script/configure_talia +56 -73
  9. data/generators/talia_swicky/talia_swicky_generator.rb +18 -0
  10. data/generators/talia_swicky/templates/app/controllers/swicky_notebooks_controller.rb +111 -0
  11. data/generators/talia_swicky/templates/app/helpers/swicky_notebooks_helper.rb +29 -0
  12. data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.builder +6 -0
  13. data/generators/talia_swicky/templates/app/views/swicky_notebooks/index.html.erb +10 -0
  14. data/generators/talia_swicky/templates/app/views/swicky_notebooks/show.html.erb +11 -0
  15. data/generators/talia_swicky/templates/test/fixtures/notebook.rdf +862 -0
  16. data/generators/talia_swicky/templates/test/functional/swicky_notebooks_controller_test.rb +44 -0
  17. data/lib/core_ext/boolean.rb +23 -0
  18. data/lib/core_ext/jdbc_rake_monkeypatch.rb +22 -0
  19. data/lib/core_ext/nil_class.rb +11 -0
  20. data/lib/core_ext/object.rb +34 -0
  21. data/lib/core_ext/string.rb +15 -0
  22. data/lib/custom_template.rb +3 -1
  23. data/lib/loader_helper.rb +16 -3
  24. data/lib/mysql.rb +7 -7
  25. data/lib/progressbar.rb +2 -2
  26. data/lib/swicky/exhibit_json/item.rb +129 -0
  27. data/lib/swicky/exhibit_json/item_collection.rb +129 -0
  28. data/lib/swicky/fragment.rb +0 -0
  29. data/lib/swicky/note.rb +7 -0
  30. data/lib/swicky/notebook.rb +78 -12
  31. data/lib/talia_core/active_source.rb +45 -13
  32. data/lib/talia_core/active_source_parts/class_methods.rb +154 -26
  33. data/lib/talia_core/active_source_parts/finders.rb +49 -26
  34. data/lib/talia_core/active_source_parts/predicate_handler.rb +71 -23
  35. data/lib/talia_core/active_source_parts/rdf/ntriples_reader.rb +13 -0
  36. data/lib/talia_core/active_source_parts/rdf/rdf_reader.rb +99 -0
  37. data/lib/talia_core/active_source_parts/rdf/rdfxml_reader.rb +12 -0
  38. data/lib/talia_core/active_source_parts/{rdf.rb → rdf_handler.rb} +52 -19
  39. data/lib/talia_core/active_source_parts/xml/generic_reader.rb +151 -260
  40. data/lib/talia_core/active_source_parts/xml/generic_reader_add_statements.rb +97 -0
  41. data/lib/talia_core/active_source_parts/xml/generic_reader_helpers.rb +88 -0
  42. data/lib/talia_core/active_source_parts/xml/generic_reader_import_statements.rb +239 -0
  43. data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +14 -7
  44. data/lib/talia_core/active_source_parts/xml/source_builder.rb +7 -3
  45. data/lib/talia_core/active_source_parts/xml/source_reader.rb +17 -2
  46. data/lib/talia_core/collection.rb +192 -1
  47. data/lib/talia_core/data_types/data_loader.rb +88 -18
  48. data/lib/talia_core/data_types/data_record.rb +24 -2
  49. data/lib/talia_core/data_types/delayed_copier.rb +13 -3
  50. data/lib/talia_core/data_types/file_record.rb +24 -13
  51. data/lib/talia_core/data_types/file_store.rb +111 -94
  52. data/lib/talia_core/data_types/iip_data.rb +104 -23
  53. data/lib/talia_core/data_types/iip_loader.rb +102 -56
  54. data/lib/talia_core/data_types/image_data.rb +3 -1
  55. data/lib/talia_core/data_types/media_link.rb +4 -1
  56. data/lib/talia_core/data_types/mime_mapping.rb +65 -38
  57. data/lib/talia_core/data_types/path_helpers.rb +23 -17
  58. data/lib/talia_core/data_types/pdf_data.rb +9 -6
  59. data/lib/talia_core/data_types/simple_text.rb +5 -4
  60. data/lib/talia_core/data_types/xml_data.rb +53 -25
  61. data/lib/talia_core/dummy_handler.rb +3 -2
  62. data/lib/talia_core/errors.rb +13 -27
  63. data/lib/talia_core/initializer.rb +44 -4
  64. data/lib/talia_core/oai/active_source_model.rb +13 -6
  65. data/lib/talia_core/oai/active_source_oai_adapter.rb +13 -12
  66. data/lib/talia_core/rdf_import.rb +1 -1
  67. data/lib/talia_core/rdf_resource.rb +2 -1
  68. data/lib/talia_core/semantic_collection_wrapper.rb +143 -151
  69. data/lib/talia_core/semantic_property.rb +4 -0
  70. data/lib/talia_core/semantic_relation.rb +84 -33
  71. data/lib/talia_core/source.rb +45 -25
  72. data/lib/talia_core/source_fragment.rb +7 -0
  73. data/lib/talia_core/source_transfer_object.rb +3 -1
  74. data/lib/talia_core/source_types/agent.rb +16 -0
  75. data/lib/talia_core/source_types/dc_resource.rb +3 -3
  76. data/lib/talia_core/source_types/marcont_resource.rb +15 -0
  77. data/lib/talia_core/source_types/skos_concept.rb +17 -0
  78. data/lib/talia_dependencies.rb +1 -1
  79. data/lib/talia_util.rb +1 -1
  80. data/lib/talia_util/bar_progressor.rb +1 -1
  81. data/lib/talia_util/image_conversions.rb +8 -2
  82. data/lib/talia_util/import_job_helper.rb +40 -3
  83. data/lib/talia_util/io_helper.rb +15 -4
  84. data/lib/talia_util/progressable.rb +50 -1
  85. data/lib/talia_util/rake_tasks.rb +3 -21
  86. data/lib/talia_util/test_helpers.rb +6 -1
  87. data/lib/talia_util/util.rb +108 -27
  88. data/lib/talia_util/xml/base_builder.rb +28 -1
  89. data/lib/talia_util/xml/rdf_builder.rb +81 -5
  90. data/lib/tasks/talia_core_tasks.rake +2 -0
  91. data/test/core_ext/boolean_test.rb +26 -0
  92. data/test/core_ext/nil_class_test.rb +14 -0
  93. data/test/core_ext/object_test.rb +26 -0
  94. data/test/core_ext/string_test.rb +11 -0
  95. data/test/swicky/json_encoder_test.rb +51 -42
  96. data/test/swicky/notebook_test.rb +13 -6
  97. data/test/talia_core/active_source_finder_interface_test.rb +30 -0
  98. data/test/talia_core/active_source_test.rb +445 -34
  99. data/test/talia_core/collection_test.rb +332 -0
  100. data/test/talia_core/data_types/file_record_test.rb +2 -23
  101. data/test/talia_core/ntriples_reader_test.rb +49 -0
  102. data/test/talia_core/rdfxml_reader_test.rb +51 -0
  103. data/test/talia_core/source_test.rb +12 -0
  104. data/test/talia_util/import_job_helper_test.rb +19 -12
  105. metadata +190 -90
  106. data/config/database.yml +0 -19
  107. data/config/rdfstore.yml +0 -13
  108. data/config/talia_core.yml +0 -24
  109. data/generators/talia_base/templates/migrations/bj_migration.rb +0 -10
  110. data/lib/JXslt/jxslt.rb +0 -60
  111. data/lib/swicky/json_encoder.rb +0 -179
  112. data/lib/talia_core/agent.rb +0 -14
  113. data/lib/talia_core/background_jobs/job.rb +0 -82
  114. data/lib/talia_core/background_jobs/progress_job.rb +0 -68
  115. data/lib/talia_core/data_types/temp_file_handling.rb +0 -85
  116. data/lib/talia_core/ordered_source.rb +0 -228
  117. data/lib/talia_core/semantic_collection_item.rb +0 -94
  118. data/lib/talia_core/source_types/collection.rb +0 -15
  119. data/lib/talia_util/progressbar.rb +0 -236
  120. data/tasks/talia_core_tasks.rake +0 -2
  121. data/test/talia_core/ordered_source_test.rb +0 -394
  122. 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
- # Builds the RDF for a single source
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
- # build an attribute entry in a source
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
- # Helper class to read an attribute hash from a Source XML
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 the data from the given URL. If the mime_type option is given, the handler will always
11
- # use the parameter for the MIME type (which can be a Mime::Type object or a string like
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
- # *Attention:* This method will return an *Array* of data objects. This is for those cases,
15
- # where a single data file will be processed into multiple objects (e.g. IIP data).
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
- # If the mime type is not given, the method will attempt to automatically determine the
18
- # type, using the file extension or the response code.
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
- # The :http_credentials option may be used to pass login information for http like this:
21
- # http_credentials = { :http_basic_authentication => [login, password] }
22
- # See the openuri documentation for more.
82
+ # *Options*
23
83
  #
24
- # You may pass the :location parameter to identify the "location" value for the new
25
- # data record. In general, this is not neccessary. If the location is given, the system
26
- # will *always* attempt to determine the mime type through the location parameter, unless
27
- # an explicit mime type is given.
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
- Mime::Type.lookup_by_extension(File.extname(location)[1..-1].downcase)
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
- raise(ArgumentError, "No handler found for loading: #{data_type}") unless(self.respond_to?(data_type))
83
- MimeMapping.class_type_from(mime_type).send(data_type, mime_type, location, source, is_file)
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
- # ActiveRecord interface to the data record in the database
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