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
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SwickyNotebooksControllerTest < ActionController::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@notebook = Swicky::Notebook.new('dan', 'booky')
|
7
|
+
@notebook_url = (N::LOCAL + 'users/dan/swicky_notebooks/bookyurl').to_s
|
8
|
+
@testpointer = "http://dbin.org/swickynotes/demo/HanselAndGretel.htm#xpointer(start-point(string-range(//BODY/DIV[1]/TABLE[1]/TBODY[1]/TR[1]/TD[2]/P[46]/SPAN[1]/SPAN[1]/text()[1],'',7))/range-to(string-range(//BODY/DIV[1]/TABLE[1]/TBODY[1]/TR[1]/TD[2]/P[47]/SPAN[1]/text()[1],'',189)))"
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@notebook.delete
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_index_empty
|
16
|
+
get(:index, :user_name => 'admin')
|
17
|
+
assert_response(:success)
|
18
|
+
assert_tag :ul, :children => { :count => 0 }
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_index
|
22
|
+
load_notebook
|
23
|
+
get(:index, :user_name => 'admin')
|
24
|
+
assert_response(:success)
|
25
|
+
assert_select('ul') { assert_select 'li', @notebook_url }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_index_xml
|
29
|
+
load_notebook
|
30
|
+
get(:index, { :user_name => 'admin' }, :headers => { :accept => 'application/xml' })
|
31
|
+
assert_select('notebooks') { assert_select 'notebook', @notebook_url }
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_user_missing
|
35
|
+
assert_raises(ActiveRecord::RecordNotFound) { get(:index, :user_name => 'foo') }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def load_notebook
|
41
|
+
@notebook.load(File.join(ActiveSupport::TestCase.fixture_path, "notebook.rdf"))
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class TrueClass
|
2
|
+
|
3
|
+
# See String#yes? from the core extensions. Always true here.
|
4
|
+
def yes? ; true ; end
|
5
|
+
alias_method :true?, :yes?
|
6
|
+
|
7
|
+
# See String#no? from the core extensions. Always false here.
|
8
|
+
def no? ; false ; end
|
9
|
+
alias_method :false?, :no?
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class FalseClass
|
14
|
+
|
15
|
+
# See String#yes? from the core extensions. Always false here.
|
16
|
+
def yes? ; false ; end
|
17
|
+
alias_method :true?, :yes?
|
18
|
+
|
19
|
+
# See String#no? from the core extensions. Always true here.
|
20
|
+
def no? ; true ; end
|
21
|
+
alias_method :false?, :no?
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Patches a problem that prevents the default rake unit test task working nicely with the
|
2
|
+
# JDBC adapter. Note that for this to work correctly, the database type must be set
|
3
|
+
# to "mysql" instead of "jdbcmysql"
|
4
|
+
|
5
|
+
if((RUBY_PLATFORM =~ /java/) && defined?(ActiveRecord::ConnectionAdapters::JdbcAdapter))
|
6
|
+
|
7
|
+
require 'jdbc_adapter/jdbc_mysql'
|
8
|
+
|
9
|
+
assit(defined?(JdbcSpec::MySQL))
|
10
|
+
|
11
|
+
module JdbcSpec # :nodoc:
|
12
|
+
module MySQL # :nodoc:
|
13
|
+
|
14
|
+
alias_method :real_recreate_database, :recreate_database
|
15
|
+
def recreate_database(name, dummy = nil) # :nodoc:
|
16
|
+
real_recreate_database(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class NilClass
|
2
|
+
|
3
|
+
# See String#yes? from the core extensions. Always false here
|
4
|
+
def yes? ; false ; end
|
5
|
+
alias_method :true?, :yes?
|
6
|
+
|
7
|
+
# See String#no? from the core extensions. Always true here
|
8
|
+
def no? ; true ; end
|
9
|
+
alias_method :false?, :no?
|
10
|
+
|
11
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
|
4
|
+
class TryObject
|
5
|
+
|
6
|
+
def initialize(original_object)
|
7
|
+
@original_object = original_object
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(method, *args, &block)
|
12
|
+
@original_object.send(method, *args, &block) if(@original_object.respond_to? method)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Hacky, Hacky, make all public private (we always want to call on @original_object)
|
16
|
+
# new and alloc etc will automatically be ignored as they raise an exception
|
17
|
+
public_instance_methods.each do |pub_method|
|
18
|
+
begin ; private pub_method ; rescue NameError ; end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Tries to call the given method if it exists. If the method doesn't
|
25
|
+
# exist, it will just return nil
|
26
|
+
def try_call(*args, &block)
|
27
|
+
if args.empty?
|
28
|
+
TryObject.new(self)
|
29
|
+
else
|
30
|
+
self.send(*args, &block) if(self.respond_to?(args.first))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/lib/core_ext/string.rb
CHANGED
@@ -9,4 +9,19 @@ class String
|
|
9
9
|
N::URI.new(self)
|
10
10
|
end
|
11
11
|
|
12
|
+
# Returns true if the string is "yes" or "true", regardless
|
13
|
+
# of capitalization and leading/trailing spaces
|
14
|
+
def yes?
|
15
|
+
me = self.downcase.strip
|
16
|
+
me == 'yes' || me == 'true'
|
17
|
+
end
|
18
|
+
alias_method :true?, :yes?
|
19
|
+
|
20
|
+
# Like #yes?, just checking for "no" or "false"
|
21
|
+
def no?
|
22
|
+
me = self.downcase.strip
|
23
|
+
me == 'no' || me == 'false'
|
24
|
+
end
|
25
|
+
alias_method :false?, :no?
|
26
|
+
|
12
27
|
end
|
data/lib/custom_template.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# Class for custom templates (e.g. css and xslt). Mainly created for customization in the
|
2
|
+
# Discovery project. May need a major rework prior of being generally useful.
|
3
|
+
class CustomTemplate < ActiveRecord::Base # :nodoc:
|
2
4
|
hobo_model # Don't put anything above this
|
3
5
|
|
4
6
|
validates_presence_of :name, :content
|
data/lib/loader_helper.rb
CHANGED
@@ -42,7 +42,13 @@ module TLoad
|
|
42
42
|
require_module("actionpack", "action_controller", "/../../../rails/actionpack", RAILS_GEM_VERSION)
|
43
43
|
# This sets the automatic loader path for Talia, allowing the ActiveSupport
|
44
44
|
# classes to automatically load classes from this directory.
|
45
|
-
|
45
|
+
# From 2.3.9(?) onward a new method autoload_path is "suggested" but 2.3.8 does not know it and gives error.
|
46
|
+
# This is to avoid the error:
|
47
|
+
begin
|
48
|
+
load_paths = ActiveSupport::Dependencies.autoload_paths
|
49
|
+
rescue NoMethodError
|
50
|
+
load_paths = ActiveSupport::Dependencies.load_paths
|
51
|
+
end
|
46
52
|
load_paths << TLoad.start_dir unless(load_paths.include?(TLoad.start_dir))
|
47
53
|
# Add the other plugins to the path, if we have a Rails root
|
48
54
|
if(defined?(RAILS_ROOT))
|
@@ -58,7 +64,14 @@ module TLoad
|
|
58
64
|
root_dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
59
65
|
Kernel.const_set(:TALIA_CODE_ROOT, root_dir) unless(defined?(TALIA_CODE_ROOT))
|
60
66
|
lib_dir = File.join(root_dir, 'lib')
|
61
|
-
|
67
|
+
# From 2.3.9(?) onward a new method autoload_path is "suggested" but 2.3.8 does not know it and gives error.
|
68
|
+
# This is to avoid the error:
|
69
|
+
begin
|
70
|
+
load_paths = ActiveSupport::Dependencies.autoload_paths
|
71
|
+
rescue NoMethodError
|
72
|
+
load_paths = ActiveSupport::Dependencies.load_paths
|
73
|
+
end
|
74
|
+
load_paths << lib_dir unless(load_paths.include?(lib_dir))
|
62
75
|
end
|
63
76
|
|
64
77
|
private
|
@@ -75,4 +88,4 @@ module TLoad
|
|
75
88
|
|
76
89
|
end
|
77
90
|
|
78
|
-
TLoad.start_dir # Load the paths and start directory
|
91
|
+
TLoad.start_dir # Load the paths and start directory
|
data/lib/mysql.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# tommy@tmtm.org
|
5
5
|
#
|
6
6
|
|
7
|
-
class Mysql
|
7
|
+
class Mysql # :nodoc:
|
8
8
|
|
9
9
|
VERSION = "4.0-ruby-0.2.6-plus-changes"
|
10
10
|
|
@@ -576,7 +576,7 @@ class Mysql
|
|
576
576
|
raise Error::new(@errno, @error)
|
577
577
|
end
|
578
578
|
|
579
|
-
class Result
|
579
|
+
class Result # :nodoc:
|
580
580
|
def initialize(mysql, fields, field_count, data=nil)
|
581
581
|
@handle = mysql
|
582
582
|
@fields = fields
|
@@ -691,7 +691,7 @@ class Mysql
|
|
691
691
|
|
692
692
|
end
|
693
693
|
|
694
|
-
class Field
|
694
|
+
class Field # :nodoc:
|
695
695
|
# Field type
|
696
696
|
TYPE_DECIMAL = 0
|
697
697
|
TYPE_TINY = 1
|
@@ -759,7 +759,7 @@ class Mysql
|
|
759
759
|
end
|
760
760
|
end
|
761
761
|
|
762
|
-
class Error < StandardError
|
762
|
+
class Error < StandardError # :nodoc:
|
763
763
|
# Server Error
|
764
764
|
ER_HASHCHK = 1000
|
765
765
|
ER_NISAMCHK = 1001
|
@@ -1076,7 +1076,7 @@ class Mysql
|
|
1076
1076
|
end
|
1077
1077
|
end
|
1078
1078
|
|
1079
|
-
class Net
|
1079
|
+
class Net # :nodoc:
|
1080
1080
|
def initialize(sock)
|
1081
1081
|
@sock = sock
|
1082
1082
|
@pkt_nr = 0
|
@@ -1145,7 +1145,7 @@ class Mysql
|
|
1145
1145
|
|
1146
1146
|
end
|
1147
1147
|
|
1148
|
-
class Random
|
1148
|
+
class Random # :nodoc:
|
1149
1149
|
def initialize(seed1, seed2)
|
1150
1150
|
@max_value = 0x3FFFFFFF
|
1151
1151
|
@seed1 = seed1 % @max_value
|
@@ -1161,7 +1161,7 @@ class Mysql
|
|
1161
1161
|
|
1162
1162
|
end
|
1163
1163
|
|
1164
|
-
class << Mysql
|
1164
|
+
class << Mysql # :nodoc:
|
1165
1165
|
def init()
|
1166
1166
|
Mysql::new :INIT
|
1167
1167
|
end
|
data/lib/progressbar.rb
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
# of Ruby's license.
|
10
10
|
#
|
11
11
|
|
12
|
-
class ProgressBar
|
12
|
+
class ProgressBar # :nodoc:
|
13
13
|
VERSION = "0.9"
|
14
14
|
|
15
15
|
def initialize (title, total, out = STDERR)
|
@@ -228,7 +228,7 @@ class ProgressBar
|
|
228
228
|
end
|
229
229
|
end
|
230
230
|
|
231
|
-
class ReversedProgressBar < ProgressBar
|
231
|
+
class ReversedProgressBar < ProgressBar # :nodoc:
|
232
232
|
def do_percentage
|
233
233
|
100 - super
|
234
234
|
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Swicky
|
4
|
+
module ExhibitJson
|
5
|
+
|
6
|
+
# An item in the Exhibit JSON. Each item belongs to a collection.
|
7
|
+
class Item
|
8
|
+
|
9
|
+
attr_reader :element, :collection
|
10
|
+
|
11
|
+
|
12
|
+
def initialize(element, collection)
|
13
|
+
raise(ArgumentError, "Element must have an URI, was a #{element.class.name}: #{element.inspect}") unless(element.respond_to?(:uri))
|
14
|
+
raise(ArgumentError, "Element must always belong to a collection") unless(collection)
|
15
|
+
@original_properties = {}
|
16
|
+
@element = element
|
17
|
+
@properties = {}
|
18
|
+
@collection = collection
|
19
|
+
create_label!
|
20
|
+
@properties['uri'] = self.uri
|
21
|
+
@properties['id'] = @collection.make_id(self)
|
22
|
+
@properties['hash'] = ('h_' << Digest::MD5.hexdigest(self.uri))
|
23
|
+
end
|
24
|
+
|
25
|
+
def uri
|
26
|
+
@element.uri.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def id
|
30
|
+
@properties['id']
|
31
|
+
end
|
32
|
+
|
33
|
+
def label
|
34
|
+
@properties['label']
|
35
|
+
end
|
36
|
+
|
37
|
+
def [](key)
|
38
|
+
@properties[key]
|
39
|
+
end
|
40
|
+
|
41
|
+
def []=(key, value)
|
42
|
+
@properties[key] = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_properties(properties)
|
46
|
+
@original_properties = properties
|
47
|
+
create_label!
|
48
|
+
create_types!
|
49
|
+
create_properties!
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_json(*a)
|
53
|
+
@properties.to_json(*a)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def create_label!
|
59
|
+
label = delete_with_key(N::RDFS.label) # Get the "real" label from the RDFS
|
60
|
+
if(@properties['label'].blank?)
|
61
|
+
# In this case we have no existing label on the item,
|
62
|
+
# so if we don't have the RDFS label we create one from the URI
|
63
|
+
label = label.blank? ? label_for(self.uri) : label.first
|
64
|
+
@properties['label'] = label
|
65
|
+
else
|
66
|
+
# We already have a label on the item, which we only
|
67
|
+
# overwrite in case there is a "real" label
|
68
|
+
@properties['label'] = label.first unless(label.blank?)
|
69
|
+
end
|
70
|
+
assit_kind_of(String, @properties['label'])
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_types!
|
74
|
+
types = delete_with_key(N::RDF.type)
|
75
|
+
types = [ N::RDF.Resource ] if(types.blank?)
|
76
|
+
types.collect! { |t| collection.add_type(t) }
|
77
|
+
types.uniq!
|
78
|
+
@properties['type'] = types
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_properties!
|
82
|
+
@original_properties.each do |key, values|
|
83
|
+
value_type = values.first.respond_to?(:uri) ? 'item' : 'text'
|
84
|
+
prop = collection.add_property(key, value_type)
|
85
|
+
prop_values = values.collect do |object|
|
86
|
+
object.respond_to?(:uri) ? collection.add_item(object) : object
|
87
|
+
end
|
88
|
+
prop_values.uniq!
|
89
|
+
if(@properties[prop].blank?)
|
90
|
+
@properties[prop] = (prop_values.size == 1) ? prop_values.first : prop_values
|
91
|
+
else
|
92
|
+
if(@properties[prop].is_a?(Array))
|
93
|
+
@properties[prop] += prop_values
|
94
|
+
else
|
95
|
+
@properties[prop] = (prop_values << @properties[prop])
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Little kludge for getting badly-specified keys
|
102
|
+
def delete_with_key(key)
|
103
|
+
real_key = @original_properties.keys.find { |k| k.to_s == key.to_s }
|
104
|
+
@original_properties.delete(real_key)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Get the part of the the uri that can be used as a label
|
108
|
+
def label_for(uri)
|
109
|
+
if(uri =~ /xpointer/)
|
110
|
+
'An Xpointer'
|
111
|
+
else
|
112
|
+
uri_fragment(uri)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def uri_fragment(uri)
|
117
|
+
raise(ArgumentError, "Must have a real uri") unless(uri)
|
118
|
+
fragment_match = /[\/#]?([^\/#]+)\Z/.match(uri.to_s)
|
119
|
+
fragment_match ||= /([^\.\/]+)\.[^\.]*\Z/.match(uri.to_s)
|
120
|
+
if(fragment_match && fragment_match[1] && (fragment_match[1].size > 2))
|
121
|
+
URI.escape(fragment_match[1])
|
122
|
+
else
|
123
|
+
Digest::MD5.hexdigest(uri.to_s)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Swicky
|
4
|
+
module ExhibitJson
|
5
|
+
|
6
|
+
# Takes a number of triples and encodes them in the SIMILE JSON format.
|
7
|
+
# See http://simile.mit.edu/wiki/Exhibit/Understanding_Exhibit_Database
|
8
|
+
class ItemCollection
|
9
|
+
|
10
|
+
# Intialize with the given triples. The original xpointer will (optionally)
|
11
|
+
# be passed into the resulting JSON for reference
|
12
|
+
def initialize(triples, original_xpointer = nil)
|
13
|
+
@triples = triples
|
14
|
+
@original_xpointer = original_xpointer
|
15
|
+
triple_hash.each { |object, values| add_item(object, values) }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the Exhibit-compatible JSON representation
|
19
|
+
def to_json(*a)
|
20
|
+
my_types = {}
|
21
|
+
types.values.each { |t| my_types[t.id] = t }
|
22
|
+
my_properties = {}
|
23
|
+
properties.values.each { |p| my_properties[p.id] = p }
|
24
|
+
result = {
|
25
|
+
'items' => items.values,
|
26
|
+
'types' => my_types,
|
27
|
+
'properties' => my_properties
|
28
|
+
}
|
29
|
+
if(@original_xpointer)
|
30
|
+
result['annotation-for'] = {
|
31
|
+
'uri' => @original_xpointer,
|
32
|
+
'hash' => ('h_' << Digest::MD5.hexdigest(@original_xpointer))
|
33
|
+
}
|
34
|
+
end
|
35
|
+
result.to_json(*a)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add a new item to the collection. This passes in a resource-like
|
39
|
+
# object and returns the id of the resulting item
|
40
|
+
def add_item(item, values = nil)
|
41
|
+
items[item.to_s] = Item.new(item, self) if(!items[item.to_s])
|
42
|
+
items[item.to_s].add_properties(values) if(values)
|
43
|
+
items[item.to_s].id
|
44
|
+
end
|
45
|
+
|
46
|
+
# As #add_item, but for types
|
47
|
+
def add_type(type)
|
48
|
+
types[type.to_s] = Item.new(type, self) if(!types[type.to_s])
|
49
|
+
types[type.to_s].id
|
50
|
+
end
|
51
|
+
|
52
|
+
# As #add_item, but for properties. This must have a value type
|
53
|
+
# which will be added to the resulting property description
|
54
|
+
def add_property(prop, value_type)
|
55
|
+
properties[prop.to_s] = Item.new(prop, self) if(!properties[prop.to_s])
|
56
|
+
if(!properties[prop.to_s]['valueType'])
|
57
|
+
properties[prop.to_s]['valueType'] = value_type
|
58
|
+
end
|
59
|
+
properties[prop.to_s].id
|
60
|
+
end
|
61
|
+
|
62
|
+
# Make a unique id for the given item, based on the label of the item
|
63
|
+
def make_id(item)
|
64
|
+
if(id_hash_inv[item.uri]) # Already existing id
|
65
|
+
id_hash_inv[item.uri]
|
66
|
+
else
|
67
|
+
first_free(item.label, item.uri)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def triple_hash
|
74
|
+
@triple_hash ||= begin
|
75
|
+
triple_hash = {}
|
76
|
+
# Sort all the triples into a hash, mapping all predicates
|
77
|
+
# to a single subject entry and all objects into a single
|
78
|
+
# predicate entry for each subject or predicate
|
79
|
+
@triples.each do |triple|
|
80
|
+
subject = triple.shift.to_uri
|
81
|
+
triple_hash[subject] ||= {}
|
82
|
+
predicate = triple.shift.to_uri
|
83
|
+
triple_hash[subject][predicate] ||= []
|
84
|
+
triple_hash[subject][predicate] << triple.first
|
85
|
+
end
|
86
|
+
triple_hash
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Finds the first "free" element in the hash. This checks
|
91
|
+
# if hash[initial_value] is empty or equal to "value", if that is not the
|
92
|
+
# case if will try "initial_value2", "initial_value3", ... until the
|
93
|
+
# condition is fulfilled
|
94
|
+
def first_free(initial_key, uri)
|
95
|
+
candidate = initial_key
|
96
|
+
id_hash[candidate] ||= uri
|
97
|
+
count = 1
|
98
|
+
while(id_hash[candidate] != uri)
|
99
|
+
count += 1
|
100
|
+
candidate = "#{initial_key}#{count}"
|
101
|
+
id_hash[candidate] ||= uri
|
102
|
+
end
|
103
|
+
id_hash_inv[uri] ||= candidate
|
104
|
+
candidate
|
105
|
+
end
|
106
|
+
|
107
|
+
def types
|
108
|
+
@types ||= {}
|
109
|
+
end
|
110
|
+
|
111
|
+
def properties
|
112
|
+
@properties ||= {}
|
113
|
+
end
|
114
|
+
|
115
|
+
def id_hash
|
116
|
+
@id_hash ||= {}
|
117
|
+
end
|
118
|
+
|
119
|
+
def items
|
120
|
+
@items ||= {}
|
121
|
+
end
|
122
|
+
|
123
|
+
def id_hash_inv
|
124
|
+
@id_hash_inv ||= {}
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|