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
@@ -0,0 +1,97 @@
1
+ module TaliaCore
2
+ module ActiveSourceParts
3
+ module Xml
4
+
5
+ # These are statements that can be used in handlers
6
+ # (see GenericReaderImportStatements to learn about handlers). They will
7
+ # add data to the source that is currently being imported.
8
+ module GenericReaderAddStatements
9
+
10
+ # Adds a value for the given predicate (may also be a database field). Example:
11
+ #
12
+ # add :uri, "http://foobar.org" # Set the uri of the current source to http://foobar.org
13
+ # add 'dct:creator', ['John Doe', 'Jane Doe'] # Sets the dct:creator property
14
+ #
15
+ # To add relations between source, see #add_rel
16
+ def add(predicate, object, required = false)
17
+ # We need to check if the object elements are already strings -
18
+ # otherwise we would *.to_s the PropertyString objects, which would
19
+ # destroy the metadata in them.
20
+ if(object.kind_of?(Array))
21
+ object.each { |obj| set_element(predicate, obj.is_a?(String) ? obj : obj.to_s, required) }
22
+ else
23
+ set_element(predicate, object.is_a?(String) ? object : object.to_s, required)
24
+ end
25
+ end
26
+
27
+ # Works as #add, but also encodes the language (and potentially the type of the literal)
28
+ # into the value.
29
+ def add_i18n(predicate, object, lang, type=nil)
30
+ object = object.blank? ? nil : TaliaCore::PropertyString.new(object, lang, type)
31
+ add(predicate, object)
32
+ end
33
+
34
+ # Adds a date field. This will attempt to parse the original string
35
+ # and write the result as an ISO 8061 compliant date string. Note
36
+ # that this won't be able to parse everything you throw at it, though.
37
+ def add_date(predicate, date, required = false, fmt = nil)
38
+ add(predicate, to_iso8601(parse_date(date, fmt)), required)
39
+ end
40
+
41
+ # Adds a date interval as an ISO 8061 compliant date string. See
42
+ # add_date for more info. If only one of the dates is given this
43
+ # will add a normal date string instead of an interval.
44
+ def add_date_interval(predicate, start_date, end_date, fmt = nil)
45
+ return if(start_date.blank? && end_date.blank?)
46
+ if(start_date.blank?)
47
+ add_date(predicate, start_date, true, fmt)
48
+ elsif(end_date.blank?)
49
+ add_date(predicate, end_date, true, fmt)
50
+ else
51
+ add(predicate, "#{to_iso8601(parse_date(start_date, fmt))}/#{to_iso8601(parse_date(end_date, fmt))}", required)
52
+ end
53
+ end
54
+
55
+ # Adds a relation for the given predicate. This works as #add,
56
+ # but with the difference that it takes an object uri instead of
57
+ # a literal value. (See the #add method to add literal values):
58
+ #
59
+ # add_rel 'dct:create', 'local:John', 'local:Jane'
60
+ def add_rel(predicate, object, required = false)
61
+ object = check_objects(object)
62
+ if(!object)
63
+ raise(ArgumentError, "Relation with empty object on #{predicate} (#{@current.attributes['uri']}).") if(required)
64
+ return
65
+ end
66
+ if(object.kind_of?(Array))
67
+ object.each do |obj|
68
+ raise(ArgumentError, "Cannot add relation on database field <#{predicate}> - <#{object.inspect}>") if(ActiveSource.db_attr?(predicate))
69
+ set_element(predicate, "<#{irify(obj)}>", required)
70
+ end
71
+ else
72
+ raise(ArgumentError, "Cannot add relation on database field") if(ActiveSource.db_attr?(predicate))
73
+ set_element(predicate, "<#{irify(object)}>", required)
74
+ end
75
+ end
76
+
77
+ # Add a file to the source being imported. See the DataLoader module for a description of
78
+ # the possible options.
79
+ #
80
+ # Note that the import reader will not be able to resolve URLs or file names that are relative
81
+ # to the original XML file or URL. File names should be absolute (otherwise they'll be treated
82
+ # as relative to the current Talia working directory), as should be URLs. Furthermore,
83
+ # the file names/paths must be valid on the machine _where the import takes place_.
84
+ def add_file(urls, options = {})
85
+ return if(urls.blank?)
86
+ urls = [ urls ] unless(urls.is_a?(Array))
87
+ files = urls.collect { |url| { :url => get_absolute_file_url(url), :options => options } }
88
+ @current.attributes[:files] = files if(files.size > 0)
89
+ end
90
+
91
+
92
+
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,88 @@
1
+ module TaliaCore
2
+ module ActiveSourceParts
3
+ module Xml
4
+
5
+ # Helper methods that can be used during the import operation
6
+ module GenericReaderHelpers
7
+
8
+ # Returns true if the given source was already imported. This can return false
9
+ # if you call this for the currently importing source.
10
+ def source_exists?(uri)
11
+ !@sources[uri].blank?
12
+ end
13
+
14
+ # Returns true if the currently imported element already contains type information
15
+ # AND is of the given type.
16
+ def current_is_a?(type)
17
+ assit_kind_of(Class, type)
18
+ @current.attributes['type'] && ("TaliaCore::#{@current.attributes['type']}".constantize <= type)
19
+ end
20
+
21
+ # Get the iso8601 string for the date
22
+ def to_iso8601(date)
23
+ return nil unless(date)
24
+ date = DateTime.parse(date) unless(date.respond_to?(:strftime))
25
+ date.strftime('%Y-%m-%dT%H:%M:%SZ')
26
+ end
27
+
28
+ # Parses the given string and returns it as a date object
29
+ def parse_date(date, fmt = nil)
30
+ return nil if(date.blank?)
31
+ return DateTime.strptime(date, fmt) if(fmt) # format given
32
+ return DateTime.new(date.to_i) if(date.size < 5) # this short should be a year
33
+ DateTime.parse(date)
34
+ end
35
+
36
+ # Gets an absolute path to the given file url, using the base_file_url
37
+ def get_absolute_file_url(url)
38
+ orig_url = url.to_s.strip
39
+
40
+ url = file_url(orig_url)
41
+ # If a file:// was stripped from the url, this means it will always point
42
+ # to a file
43
+ force_file = (orig_url != url)
44
+ # Indicates wether the base url is a network url or a file/directory
45
+ base_is_net = !base_file_url.is_a?(String)
46
+ # Try to find if we have a "net" URL if we aren't sure if this is a file. In
47
+ # case the base url is a network url, we'll always assume that the
48
+ # url is also a net thing. Otherwise we only have a net url if it contains a
49
+ # '://' string
50
+ is_net_url = !force_file && (base_is_net || url.include?('://'))
51
+ # The url is absolute if there is a : character to be found
52
+
53
+
54
+ if(is_net_url)
55
+ base_is_net ? join_url(base_file_url, url) : url
56
+ else
57
+ base_is_net ? url : join_files(base_file_url, url)
58
+ end
59
+ end
60
+
61
+ # Joins the two files. If the path is an absolute path,
62
+ # the base_dir is ignored
63
+ def join_files(base_dir, path)
64
+ if(Pathname.new(path).relative?)
65
+ File.join(base_dir, path)
66
+ else
67
+ path
68
+ end
69
+ end
70
+
71
+ # Joins the two url parts. If the path is an absolute URL,
72
+ # the base_url is ignored.
73
+ def join_url(base_url, path)
74
+ return path if(path.include?(':')) # Absolute URL contains ':'
75
+ if(path[0..0] == '/')
76
+ new_url = base_url.clone
77
+ new_url.path = path
78
+ new_url.to_s
79
+ else
80
+ (base_file_url + path).to_s
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,239 @@
1
+ module TaliaCore
2
+ module ActiveSourceParts
3
+ module Xml
4
+
5
+ # These are the statements that are use to add handler for elements or which are
6
+ # used to otherwise read data for the element
7
+ #
8
+ # = What is an element handler?
9
+ #
10
+ # The methods in the Handlers submodule create element handlers. Handlers are the
11
+ # starting point for the import operation and are the only statements at the top
12
+ # level of the import description.
13
+ #
14
+ # Each handler will match a specific XML tag in the "current" XML content. At the
15
+ # beginning of the import the "current" content will be either the root element
16
+ # or all of its child elements (depending on wether the can_use_root flag is set).
17
+ #
18
+ # The handlers will automatically attempt to match the element(s) at the starting
19
+ # level:
20
+ #
21
+ # class SampleReader < GenericReader
22
+ #
23
+ # can_use_root CAN_BE_TRUE_OR_FALSE
24
+ #
25
+ # element :foo do
26
+ # # Code for foo tags
27
+ # end
28
+ #
29
+ # element :bar
30
+ # # Code for bar tags
31
+ # end
32
+ #
33
+ # element :foobar
34
+ # # Code for foobar tags
35
+ # end
36
+ #
37
+ # end
38
+ #
39
+ # With this importer, there would be three handlers, for "foo", "bar" and
40
+ # "foobar" tags. If you had the following XML
41
+ #
42
+ # <foobar>
43
+ # <foo>Hello</foo>
44
+ # <bar>World</bar>
45
+ # </foobar>
46
+ #
47
+ # When reader above is run on the sample XML, the follwoing will happen:
48
+ #
49
+ # * In case can_use_root has been set to true, the importer will start
50
+ # at the root element. In this case, the "Code for foobar tags" will
51
+ # be executed
52
+ # * In case can_use_root has not been set, or set to false, the importer
53
+ # will work on the elements _inside_ the root tag. This means that
54
+ # it will first check the "foo" tag and call the "Code for foo tags"
55
+ # and then check the the "bar" tag and call the "Code for bar tags".
56
+ #
57
+ # Obviously an XML can also contain the same element multiple times, in
58
+ # which case the handler will be called multiple time.
59
+ #
60
+ # = What happens inside a handler?
61
+ #
62
+ # When a handler is called, the "current" XML will be set to the inner
63
+ # part of the current document. That is, in case of the "foobar" handler
64
+ # the "current" XML would consist of the "foo" and "bar" tags (and their)
65
+ # content. For the "foo" and "bar" handler, the "current" XML would be
66
+ # just the text nodes inside it.
67
+ #
68
+ # The handler handler also has a "current" source that is being imported.
69
+ # In case of a handler that was declared with .element, a new, empty
70
+ # source is created whenever the handler is called. If the handler was
71
+ # declared with .plain_element, the handler "inherits" the current source
72
+ # that was active when it was called.
73
+ #
74
+ # Inside the handler, the GenericReaderAddStatements are used in order
75
+ # to add data and properties to the current source.
76
+ #
77
+ # All handlers are executed as instance methods of the current reader.
78
+ #
79
+ # = How are handlers called?
80
+ #
81
+ # The handlers that are declared in the importer are
82
+ # matched against the "starting" tags in the XML and called
83
+ # automatically. Inside the handler methods like #add_source can be
84
+ # used to call a handler on sub-elements. Example for the
85
+ # reader given above (with can_use_root set):
86
+ #
87
+ # element :foobar do
88
+ # # At this point a new empty source has been created
89
+ # # and is set as the "current" source. The "current" XML
90
+ # # is the foo and bar tags
91
+ # add_source :foo # Takes the "foo" tag and calls the handler
92
+ # add_source :bar # Takes the "bar" tag and calls the handler
93
+ # # Alternatively: add_source :from_all_sources -> do both automatically
94
+ # end
95
+ #
96
+ # If the "foo" hanlder was defined as a .plain_element
97
+ #
98
+ # plain_element :foo { }
99
+ #
100
+ # then the "foo" handler would inherit the source from the "foobar" handler
101
+ # through wich it was called.
102
+ #
103
+ # = Accessing data within in the handlers
104
+ #
105
+ # While the handlers allow you to navigate through the XML structure, you
106
+ # will also have to read the data in order to construct the sources.
107
+ #
108
+ # The from_* methods allow to read data from the current XML:
109
+ #
110
+ # element :foobar do
111
+ # the_thing = from_element :foo
112
+ # end
113
+ #
114
+ # In this case, inside the handler for the "foobar" tag, you attempt to
115
+ # read the text from the :foo element. With the XML given above, the
116
+ # result of this would be the string "Hello"
117
+ module GenericReaderImportStatements
118
+
119
+ # Methods to create handlers. See GenericReaderImportStatements
120
+ module Handlers
121
+
122
+ # Creates a handler for the element_name tag. Each time the handler
123
+ # is called, a new, empty source is created and set as current.
124
+ #
125
+ # The handler block will be executed as an instance method on the
126
+ # current reader object and the "current" XML inside the handler
127
+ # block will be the inner XML of the "element_name" tag that is
128
+ # currently being processed
129
+ def element(element_name, &handler_block)
130
+ element_handler(element_name, true, &handler_block)
131
+ end
132
+
133
+ # Works as #element, except that no new source is created. The
134
+ # current source in the block will be the one that is active
135
+ # at the point where the handler was called.
136
+ def plain_element(element_name, &handler_block)
137
+ element_handler(element_name, false, &handler_block)
138
+ end
139
+
140
+ end # End handlers
141
+
142
+ # Gets the data for an attribute of the current XML element. E.g. if
143
+ # you have XML for
144
+ #
145
+ # <foobar name="myself">
146
+ # <foo>Hello World</foo>
147
+ # </foobar>
148
+ #
149
+ # And this handler
150
+ #
151
+ # element :foobar do
152
+ # my_attr = from_attribute :name
153
+ # end
154
+ #
155
+ # then the my_attr variable will be set to "myself"
156
+ def from_attribute(attrib)
157
+ @current.element[attrib]
158
+ end
159
+
160
+ # Gets data from the XML tag "elem" inside the currently active XML
161
+ #
162
+ # <foobar><foo>Hello World</foo></foobar>
163
+ #
164
+ # Inside the "foobar" handler `from_element :foo` would return
165
+ # "Hello World" with the XML given above.
166
+ def from_element(elem)
167
+ return @current.element.inner_text.strip if(elem == :self)
168
+ elements = all_elements(elem)
169
+ elements = elements.uniq if(elements.size > 1) # Try to ignore dupes
170
+ raise(ArgumentError, "More than one element of #{elem} in #{@current.element.inspect}") if(elements.size > 1)
171
+ elements.first
172
+ end
173
+
174
+ # This works like #from_element, except that it will return an array with the
175
+ # values of *all* "elem" tags inside the current XML.
176
+ def all_elements(elem)
177
+ result = []
178
+ @current.element.search("/#{elem}").each { |el| result << el.inner_text.strip }
179
+ result
180
+ end
181
+
182
+ # Adds a nested element. This will not change the currently importing source, but
183
+ # it will set the currently active XML to the nested element.
184
+ # If a block is given, it will execute for each of the nested elements that
185
+ # are found. Otherwise, a method name must be given, and that method will
186
+ # be executed instead of the block
187
+ def nested(sub_element, handler_method = nil)
188
+ original_element = @current.element
189
+ begin
190
+ @current.element.search("#{sub_element}").each do |sub_elem|
191
+ @current.element = sub_elem
192
+ assit(block_given? ^ (handler_method.is_a?(Symbol)), 'Must have either a handler (x)or a block.')
193
+ block_given? ? yield : self.send(handler_method)
194
+ end
195
+ ensure
196
+ @current.element = original_element
197
+ end
198
+ end
199
+
200
+ # Adds a source from the given sub-element. You may either pass a block with
201
+ # the code to import or the name of an already registered element. If the
202
+ # special value :from_all_sources is given, it will read from all sub-elements for which
203
+ # there are registered handlers.
204
+ #
205
+ # If the method is used with a block, it will call the block as a handler for the _current_
206
+ # element.l
207
+ def add_source(sub_element = nil, &block)
208
+ if(sub_element)
209
+ if(sub_element == :from_all_sources)
210
+ read_children_of(@current.element)
211
+ else
212
+ @current.element.search("/#{sub_element}").each { |sub_elem| read_source(sub_elem, &block) }
213
+ end
214
+ else
215
+ raise(ArgumentError, "When adding elements on the fly, you must use a block") unless(block)
216
+ attribs = call_handler(@current.element, &block)
217
+ add_source_with_check(attribs) if(attribs)
218
+ end
219
+ end
220
+
221
+ # Imports another source like add_source and also assigns the new source as
222
+ # a part of the current one.
223
+ def add_part(sub_element = nil, &block)
224
+ raise(RuntimeError, "Cannot add child before having an uri to refer to.") unless(@current.attributes['uri'])
225
+ @current.element.search("/#{sub_element}").each do |sub_elem|
226
+ attribs = call_handler(sub_elem, &block)
227
+ if(attribs)
228
+ attribs[N::TALIA.part_of.to_s] ||= []
229
+ attribs[N::TALIA.part_of.to_s] << "<#{@current.attributes['uri']}>"
230
+ add_source_with_check(attribs)
231
+ end
232
+ end
233
+ end
234
+
235
+ end
236
+
237
+ end
238
+ end
239
+ end
@@ -2,15 +2,19 @@ module TaliaCore
2
2
  module ActiveSourceParts
3
3
  module Xml
4
4
 
5
- # Class for creating xml-rdf data
5
+ # Class for creating xml-rdf Data from a source. See the parent class, TaliaUtil::Xml::RdfBuilder, for
6
+ # more information.
6
7
  class RdfBuilder < TaliaUtil::Xml::RdfBuilder
7
8
 
9
+ # Builds the RDF for a source and returns the result as a string
8
10
  def self.build_source(source)
9
11
  make_xml_string { |build| build.write_source(source) }
10
- end
12
+ end
11
13
 
12
- # Writes a complete source to the rdf
14
+ # Builds the RDF for a source. This will include both the "direct" predicates as well as the
15
+ # "inverse" (incoming predicates of a source)
13
16
  def write_source(source)
17
+ # The source is written as subject, with all the triples nested inside it.
14
18
  @builder.rdf :Description, 'rdf:about' => source.uri.to_s do # Element describing this resource
15
19
  # loop through the predicates
16
20
  source.direct_predicates.each do |predicate|
@@ -18,6 +22,9 @@ module TaliaCore
18
22
  end
19
23
  end
20
24
 
25
+ # Each of the inverse properties creates another subject entry, that just contains the one
26
+ # triple relating it to the current source. (In this case, the subject and predicate entries
27
+ # aren't merged any further)
21
28
  source.inverse_predicates.each do |predicate|
22
29
  source.inverse[predicate].each do |inverse_subject|
23
30
  @builder.rdf :Description, 'rdf:about' => inverse_subject do
@@ -28,7 +35,7 @@ module TaliaCore
28
35
  end
29
36
 
30
37
 
31
- end
32
- end
33
- end
34
- end
38
+ end
39
+ end
40
+ end
41
+ end