rtm 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/README +38 -3
  2. data/lib/rtm.rb +25 -47
  3. data/lib/rtm/axes.rb +7 -4
  4. data/lib/rtm/axes/association.rb +1 -1
  5. data/lib/rtm/axes/associations.rb +1 -1
  6. data/lib/rtm/axes/characteristic.rb +1 -1
  7. data/lib/rtm/axes/characteristics.rb +1 -1
  8. data/lib/rtm/axes/topic.rb +3 -3
  9. data/lib/rtm/axes/topics.rb +3 -3
  10. data/lib/rtm/engine.rb +48 -5
  11. data/lib/rtm/extensions.rb +58 -8
  12. data/lib/rtm/io.rb +2 -1
  13. data/lib/rtm/io/tmapix_from.rb +155 -0
  14. data/lib/rtm/io/tmapix_to.rb +223 -0
  15. data/lib/rtm/io/to_hash.rb +79 -41
  16. data/lib/rtm/io/to_jtm.rb +1 -1
  17. data/lib/rtm/io/to_rdf.rb +20 -5
  18. data/lib/rtm/io/to_string.rb +13 -2
  19. data/lib/rtm/io/to_yaml.rb +39 -11
  20. data/lib/rtm/navigation.rb +1 -15
  21. data/lib/rtm/navigation/association/players.rb +1 -1
  22. data/lib/rtm/navigation/name/characteristics.rb +1 -1
  23. data/lib/rtm/navigation/occurrence/characteristics.rb +1 -1
  24. data/lib/rtm/navigation/topic/characteristics.rb +1 -1
  25. data/lib/rtm/navigation/topic/players.rb +1 -1
  26. data/lib/rtm/navigation/topic/supertypes.rb +21 -17
  27. data/lib/rtm/navigation/topic/traverse.rb +1 -1
  28. data/lib/rtm/navigation/topic/types.rb +6 -4
  29. data/lib/rtm/psi.rb +6 -0
  30. data/lib/rtm/sugar.rb +42 -29
  31. data/lib/rtm/sugar/association/hash_access.rb +3 -3
  32. data/lib/rtm/sugar/occurrence/dynamic_value.rb +39 -56
  33. data/lib/rtm/sugar/occurrence/external.rb +53 -0
  34. data/lib/rtm/sugar/reifiable/reifier.rb +21 -0
  35. data/lib/rtm/sugar/role/counterparts.rb +12 -6
  36. data/lib/rtm/sugar/topic/best_name.rb +74 -0
  37. data/lib/rtm/sugar/topic/characteristics.rb +10 -10
  38. data/lib/rtm/sugar/topic/counterparts.rb +131 -119
  39. data/lib/rtm/sugar/topic/scoped.rb +102 -53
  40. data/lib/rtm/sugar/topic/topic_ref.rb +63 -12
  41. data/lib/rtm/sugar/topic/typed.rb +50 -2
  42. data/lib/rtm/sugar/topic_map/query_cache.rb +66 -0
  43. data/lib/rtm/sugar/topic_map/themes.rb +53 -0
  44. data/lib/rtm/sugar/typed/types.rb +1 -1
  45. data/lib/rtm/validation.rb +2 -2
  46. data/lib/rtm/version.rb +18 -6
  47. data/spec/rtm/axes/string_spec.rb +7 -7
  48. data/spec/rtm/axes/strings_spec.rb +10 -10
  49. data/spec/rtm/io/tmapix_from_spec.rb +76 -0
  50. data/spec/rtm/io/tmapix_to_spec.rb +159 -0
  51. data/spec/rtm/io/to_hash_spec.rb +90 -0
  52. data/spec/rtm/io/to_rdf_spec.rb +37 -0
  53. data/spec/rtm/io/to_string_spec.rb +122 -0
  54. data/spec/rtm/io/to_yaml_spec.rb +89 -0
  55. data/spec/rtm/sugar/occurrence/dynamic_value_spec.rb +156 -1
  56. data/spec/rtm/sugar/occurrence/external_spec.rb +129 -0
  57. data/spec/rtm/sugar/reifiable/reifier_spec.rb +41 -0
  58. data/spec/rtm/sugar/role/counterparts_spec.rb +174 -172
  59. data/spec/rtm/sugar/topic/best_name_spec.rb +25 -0
  60. data/spec/rtm/sugar/topic/characteristics_spec.rb +20 -5
  61. data/spec/rtm/sugar/topic/counterparts_spec.rb +41 -1
  62. data/spec/rtm/sugar/topic/hash_access_spec.rb +1 -1
  63. data/spec/rtm/sugar/topic/scoped_spec.rb +178 -114
  64. data/spec/rtm/sugar/topic/topic_ref_spec.rb +10 -10
  65. data/spec/rtm/sugar/topic/typed_spec.rb +196 -134
  66. data/spec/rtm/sugar/topic_map/themes_spec.rb +67 -0
  67. data/spec/rtm/sugar/typed/types_spec.rb +1 -1
  68. data/spec/rtm/tmapi/core/association_spec.rb +2 -2
  69. data/spec/rtm/tmapi/core/datatype_aware_spec.rb +236 -0
  70. data/spec/rtm/tmapi/core/name_spec.rb +186 -1
  71. data/spec/rtm/tmapi/core/occurrence_spec.rb +24 -67
  72. data/spec/rtm/tmapi/core/reifiable_spec.rb +2 -2
  73. data/spec/rtm/tmapi/core/scoped_spec.rb +40 -2
  74. data/spec/rtm/tmapi/core/topic_map_spec.rb +98 -30
  75. data/spec/rtm/tmapi/core/topic_spec.rb +558 -82
  76. data/spec/rtm/tmapi/core/variant_spec.rb +3 -3
  77. data/spec/rtm_spec.rb +0 -1
  78. data/spec/spec_helper.rb +7 -2
  79. data/test/javalibs/junit-4.5.jar +0 -0
  80. data/test/javalibs/tmapi-2.0-tests.jar +0 -0
  81. data/test/tmapi_tests.rb +25 -0
  82. metadata +66 -11
  83. data/lib/rtm/io/ontopia_io.rb +0 -25
  84. data/lib/rtm/io/tmapix.rb +0 -234
  85. data/lib/rtm/sugar/occurrence/externalize.rb +0 -31
  86. data/spec/rtm/io/tmapix_spec.rb +0 -85
  87. data/test/base_unit_test.rb +0 -161
  88. data/test/base_unit_test_tmapi.rb +0 -165
data/README CHANGED
@@ -1,4 +1,39 @@
1
- Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
2
- License: Apache License, Version 2.0
1
+ ==== Ruby Topic Maps (RTM)
2
+ RTM is a Topic Maps engine written in Ruby. See http://rtm.topicmapslab.de/ for instructions.
3
+ Several backends and extensions are available as separate gems.
3
4
 
4
- See http://rtm.topicmapslab.de/ for instructions.
5
+ ==== Overview
6
+ From a developer's perspective, RTM is a schema-less database management system.
7
+ The Topic Maps standard (described below) on which RTM is based provides a way of creating a self-describing schema just by using it.
8
+
9
+ ==== Quickstart
10
+ require 'rtm'
11
+ connection = RTM.connect # uses the default Ontopia in-memory backend
12
+ topic_map = connection.create "http://example.org/my_topic_map/"
13
+ some_topic = topicmap.get!("identifier_of_the_topic")
14
+ some_topic["-"] = "default name for the topic"
15
+ topic_map.to_xtm("my_xtm_file.xtm")
16
+
17
+ ==== Topic Maps
18
+ Topic Maps is an international industry standard (ISO13250) for interchangeably representing information
19
+ about the structure of information resources used to define topics, and the relationships between topics.
20
+ A set of one or more interrelated documents that employs the notation defined by this International Standard is called a topic map.
21
+ A topic map defines a multidimensional topic space - a space in which the locations are topics,
22
+ and in which the distances between topics are measurable in terms of the number of intervening topics
23
+ which must be visited in order to get from one topic to another, and the kinds of relationships that define
24
+ the path from one topic to another, if any, through the intervening topics, if any.
25
+ In addition, information objects can have properties, as well as values for those properties, assigned to them.
26
+ The Topic Maps Data Model which is used in this implementation can be found on http://www.isotopicmaps.org/sam/sam-model/.
27
+
28
+ ==== Backends
29
+ * rtm-ontopia: JRuby only, recommended, uses Ontopia: http://code.google.com/p/ontopia/
30
+ * rtm-tinytim: JRuby only, uses TinyTiM: http://tinytim.sourceforge.net/
31
+ * rtm-activerecord: uses a custom ActiveRecord schema
32
+
33
+ ==== Extensions
34
+ * rtm-tmql: Adds support for the Topic Maps Query Language (TMQL), http://isotopicmaps.org/tmql/
35
+ * rtm-tmcl: Adds support for the Topic Maps Constraint Language (TMCL), http://isotopicmaps.org/tmcl/
36
+
37
+ ==== License
38
+ Copyright 2009 Topic Maps Lab, University of Leipzig.
39
+ Apache License, Version 2.0
data/lib/rtm.rb CHANGED
@@ -1,12 +1,15 @@
1
- # (J)RTM: (J)Ruby Topic Maps.
2
- # Copyright: Topic Maps Lab www.topicmapslab.de
3
- # License: Apache License, Version 2.0
4
- # Project lead: Benjamin Bock bock(at)informatik.uni-leipzig.de
5
- # Responsible for (J)RTM: Arnim Bleier bleier(at)informatik.uni-leipzig.de
6
- # Responsible for Documentation: Uta Schulze uta.schulze(at)informatik.uni-leipzig.de
7
- # Responsible for ActiveTM: Daniel Exner exner(at)informatik.uni-leipzig.de
8
-
9
- $: << File.expand_path(File.dirname(__FILE__))
1
+ # Ruby Topic Maps (RTM)
2
+ # Copyright: Topic Maps Lab http://www.topicmapslab.de
3
+ # License: Apache License, Version 2.0
4
+ # Project lead: Benjamin Bock bock(at)informatik.uni-leipzig.de
5
+ # Developers: Benjamin Bock bock(at)informatik.uni-leipzig.de
6
+ # Arnim Bleier bleier(at)informatik.uni-leipzig.de
7
+ # Uta Schulze uta.schulze(at)informatik.uni-leipzig.de
8
+ # Daniel Exner exner(at)informatik.uni-leipzig.de
9
+ # Testing: Uta Schulze uta.schulze(at)informatik.uni-leipzig.de
10
+ # Documentation: Uta Schulze uta.schulze(at)informatik.uni-leipzig.de
11
+
12
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__))
10
13
 
11
14
  module RTM
12
15
  module Topic
@@ -49,6 +52,9 @@ module RTM
49
52
  attr_accessor :engine
50
53
  end
51
54
 
55
+ module TopicMapSystem
56
+ end
57
+
52
58
  module ItemIdentifier
53
59
  end
54
60
 
@@ -57,14 +63,14 @@ module RTM
57
63
 
58
64
  module SubjectLocator
59
65
  end
60
-
61
- module TopicMapSystem
66
+
67
+ module DatatypeAware
62
68
  end
63
69
  end
64
70
 
65
71
  require 'rtm/version'
66
- require "rtm/engine"
67
72
  require 'rtm/extensions'
73
+ require "rtm/engine"
68
74
  require 'rtm/psi'
69
75
  require "rtm/navigation"
70
76
  require "rtm/axes"
@@ -84,41 +90,9 @@ module RTM
84
90
  # RTM.connect(:implementation => :merged) -> Merged TMAPI backend
85
91
  #
86
92
  def self.connect(params = {}, *args)
87
- implementation = params[:implementation]
88
-
89
- unless implementation
90
- if Engine.list.first
91
- implementation = Engine.list.first
92
- warn("No engine implementation was specified for RTM.connect. Using the first already loaded engine (#{implementation.inspect}).")
93
- else
94
- if RUBY_PLATFORM =~ /java/
95
- implementation = :ontopia
96
- else
97
- implementation = :activerecord
98
- warn("No engine implementation was specified for RTM.connect. Choosing default (#{implementation.inspect}).")
99
- end
100
- end
101
- params[:implementation] = implementation
102
- end
103
-
104
- unless Engine.list.include?(implementation)
105
- warn("Requested engine '#{implementation}' not loaded. Trying to autoload it.")
106
- Engine.load(implementation)
107
- if Engine.list.include?(implementation)
108
- warn("Autoloading '#{implementation}' was successful")
109
- else
110
- raise "Autoloading '#{implementation}' failed. Make sure rtm-#{implementation} exists and is installed or require it manually."
111
- end
112
- end
113
-
114
- engine = RTM::Engine[implementation]
115
-
93
+ engine = Engine.load!(params[:implementation])
116
94
  connection = engine.new(params)
117
-
118
- @connections ||= {}
119
- @connections[implementation] ||= []
120
- @connections[implementation] << connection
121
-
95
+ add_connection(connection)
122
96
  connection
123
97
  end
124
98
 
@@ -128,7 +102,7 @@ module RTM
128
102
  # connections -> Hash
129
103
  #
130
104
  def self.connections
131
- @connections ||= {}
105
+ @connections ||= Hash.new{|h,k| h[k] = []}
132
106
  @connections
133
107
  end
134
108
 
@@ -153,4 +127,8 @@ module RTM
153
127
  self.included_modules.each {|im| klass.extend(im)}
154
128
  end
155
129
 
130
+ private
131
+ def self.add_connection(connection)
132
+ self.connections[connection.class.identifier] << connection
133
+ end
156
134
  end
data/lib/rtm/axes.rb CHANGED
@@ -226,7 +226,8 @@ module RTM
226
226
  end
227
227
  end
228
228
 
229
- module RTM::Topic
229
+ module RTM::AxesExtension;end
230
+ module RTM::AxesExtension::Topic
230
231
 
231
232
  # Changes from TMAPI-mode to Axes-mode.
232
233
  #
@@ -238,7 +239,7 @@ module RTM::Topic
238
239
  end
239
240
  end
240
241
 
241
- module RTM::Name
242
+ module RTM::AxesExtension::Name
242
243
 
243
244
  # Changes from TMAPI-mode to Axes-mode.
244
245
  #
@@ -250,7 +251,7 @@ module RTM::Name
250
251
  end
251
252
  end
252
253
 
253
- module RTM::Occurrence
254
+ module RTM::AxesExtension::Occurrence
254
255
 
255
256
  # Changes from TMAPI-mode to Axes-mode.
256
257
  #
@@ -262,7 +263,7 @@ module RTM::Occurrence
262
263
  end
263
264
  end
264
265
 
265
- module RTM::Association
266
+ module RTM::AxesExtension::Association
266
267
 
267
268
  # Changes from TMAPI-mode to Axes-mode.
268
269
  #
@@ -288,6 +289,8 @@ class String
288
289
  end
289
290
  end
290
291
 
292
+ RTM.register_extension(RTM::AxesExtension)
293
+
291
294
  require "rtm/axes/topics"
292
295
  require "rtm/axes/associations"
293
296
  require "rtm/axes/characteristics"
@@ -10,7 +10,7 @@ module RTM::Axes
10
10
  # Returns all Role players of Roles in this Association.
11
11
  #
12
12
  # The optional identifier specifies the type of the Roles to be considered.
13
- # The identifier may be a Topic or Topic-Reference.
13
+ # The identifier may be a topic reference.
14
14
  #
15
15
  # Multiple instances of the same Topic are possible.
16
16
  # The result may be empty.
@@ -18,7 +18,7 @@ module RTM::Axes
18
18
  # Returns all Role players of Roles in these Associations.
19
19
  #
20
20
  # The optional identifier specifies the type of the Roles to be considered.
21
- # The identifier may be a Topic or Topic-Reference.
21
+ # The identifier may be a topic reference.
22
22
  #
23
23
  # Multiple instances of the same Topic are possible.
24
24
  # The result may be empty.
@@ -24,7 +24,7 @@ module RTM::Axes
24
24
  # Characteristic for its type. If the type
25
25
  # does not match, nil is returned.
26
26
  #
27
- # The identifier may be a Topic or Topic-Reference.
27
+ # The identifier may be a topic reference.
28
28
  #
29
29
  # :call-seq:
30
30
  # reverse_characteristics -> Topic
@@ -37,7 +37,7 @@ module RTM::Axes
37
37
  # Characteristics for their types. If the type
38
38
  # does not match, the Topic is not returned.
39
39
  #
40
- # The identifier may be a Topic or Topic-Reference.
40
+ # The identifier may be a topic reference.
41
41
  #
42
42
  # :call-seq:
43
43
  # reverse_characteristics -> Array of Topic
@@ -11,7 +11,7 @@ module RTM::Axes
11
11
  # If an identifier is given, only those Names and Occurrences are returned,
12
12
  # whose type or supertypes include the identifier.
13
13
  #
14
- # Identifier may be a Topic or Topic-Reference.
14
+ # Identifier may be a topic reference.
15
15
  #
16
16
  # The result may be empty.
17
17
  #
@@ -68,7 +68,7 @@ module RTM::Axes
68
68
  #
69
69
  # The optional
70
70
  # identifier specifies the type of the Roles to be considered.
71
- # The identifier may be a Topic or Topic-Reference.
71
+ # The identifier may be a topic reference.
72
72
  #
73
73
  # Multiple instances of the same Association are possible.
74
74
  # The result may be empty.
@@ -177,7 +177,7 @@ module RTM::Axes
177
177
  # The current Topic is deducted ones from the returned Array.
178
178
  # The result may be empty.
179
179
  #
180
- # The identifier may be a Topic or Topic-Reference.
180
+ # The identifier may be a topic reference.
181
181
  #
182
182
  # :call-seq:
183
183
  # traverse(identifier) -> Array of Topics
@@ -19,7 +19,7 @@ module RTM::Axes
19
19
  # If an identifier is given, only those Names and Occurrences are returned,
20
20
  # whose type or supertypes include the identifier.
21
21
  #
22
- # Identifier may be a Topic or Topic-Reference.
22
+ # Identifier may be a topic reference.
23
23
  #
24
24
  # The result may be empty.
25
25
  #
@@ -90,7 +90,7 @@ module RTM::Axes
90
90
  #
91
91
  # The optional
92
92
  # identifier specifies the type of the Roles to be considered.
93
- # The identifier may be a Topic or Topic-Reference.
93
+ # The identifier may be a topic reference.
94
94
  #
95
95
  # Multiple instances of the same Association are possible.
96
96
  # The result may be empty.
@@ -209,7 +209,7 @@ module RTM::Axes
209
209
  # Each Topic is deducted ones from the returned Array.
210
210
  # The result may be empty.
211
211
  #
212
- # The identifier may be a Topic or Topic-Reference.
212
+ # The identifier may be a topic reference.
213
213
  #
214
214
  # :call-seq:
215
215
  # traverse(identifier) -> Array of Topics
data/lib/rtm/engine.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module RTM
2
- class Engine
2
+ class Engine
3
+ include RTM::TopicMapSystem
4
+
3
5
  def self.abstract?
4
6
  self == Engine
5
7
  end
@@ -38,21 +40,62 @@ module RTM
38
40
  end
39
41
 
40
42
  def self.load(engine_name)
41
- begin
43
+ if Object.const_defined?("Gem") && rtmgem = Gem.loaded_specs["rtm"]
42
44
  require "rtm/#{engine_name}"
43
- rescue LoadError
45
+ else
44
46
  engine_path = File.expand_path(File.join(File.dirname(__FILE__), "../../../rtm-#{engine_name}/lib"))
45
47
  if File.directory?(engine_path)
46
- $:.unshift engine_path
48
+ $LOAD_PATH.unshift engine_path
47
49
  require "rtm/#{engine_name}"
48
50
  end
49
51
  end
52
+ self[engine_name]
53
+ end
54
+
55
+ def self.load!(engine_name=nil)
56
+ engine_name = self.detect unless engine_name
57
+ unless list.include?(engine_name)
58
+ warn("Requested engine '#{engine_name}' not loaded. Trying to autoload it.")
59
+ engine = load(engine_name)
60
+ if list.include?(engine_name)
61
+ warn("Autoloading '#{engine_name}' was successful")
62
+ else
63
+ raise "Autoloading '#{engine_name}' failed. Make sure rtm-#{engine_name} exists and is installed or require it manually."
64
+ end
65
+ end
66
+ engine || load(engine_name)
50
67
  end
51
68
 
69
+ def self.detect(preferred=nil)
70
+ if preferred # return the users preference, if given
71
+ implementation = preferred
72
+ elsif engine_name = ENV['RTM_IMPLEMENTATION'] # inspect system environment
73
+ implementation = engine_name.to_sym
74
+ elsif engine_name = ENV['RTM_ENGINE'] # inspect system environment (alternative)
75
+ implementation = engine_name.to_sym
76
+ elsif implementation = self.list.first # check if one is already loaded
77
+ warn("No engine implementation was specified for RTM.connect. Using the first already loaded engine (#{implementation.inspect}).")
78
+ else
79
+ implementation = self.default # use hardcoded default
80
+ warn("No engine implementation was specified for RTM.connect. Choosing default (#{implementation.inspect}).")
81
+ implementation
82
+ end
83
+ implementation
84
+ end
85
+
86
+ def self.default
87
+ if RUBY_PLATFORM =~ /java/
88
+ :ontopia
89
+ else
90
+ :activerecord
91
+ end
92
+ end
93
+
52
94
  attr_reader :connections
95
+
53
96
  def initialize(params={})
54
97
  @params = params
55
98
  end
56
-
99
+
57
100
  end
58
101
  end
@@ -2,7 +2,7 @@
2
2
  # License: Apache License, Version 2.0
3
3
 
4
4
  module RTM
5
- # Register a module as extension.
5
+ # Register a module as extension to RTM.
6
6
  #
7
7
  # Example:
8
8
  # module MyExtension
@@ -14,16 +14,66 @@ module RTM
14
14
  # RTM.register_extension(self)
15
15
  # end
16
16
  #
17
- def self.register_extension(plugin_mod)
18
- plugin_mod.constants.each do |const|
19
- const_get(const).send(:include, plugin_mod.const_get(const) ) if const_defined?(const)
17
+ def self.register_extension(module_with_modules)
18
+ # puts "[RTMEXT] registering extension #{module_with_modules}"
19
+ module_with_modules.constants.each do |sub_module|
20
+ self.const_get(sub_module).register_extension(module_with_modules.const_get(sub_module)) if self.const_defined?(sub_module)
20
21
  end
21
22
  end
22
- module AR
23
- def self.register_extension(plugin_mod)
24
- plugin_mod.constants.each do |const|
25
- const_get(const).send(:include, plugin_mod.const_get(const) ) if const_defined?(const)
23
+
24
+ # Extend a module or class with this method to make it a receiver for RTM extensions.
25
+ # E.g. MyModule.extend(Extendable) or MyClass.extend(Extendable).
26
+ #
27
+ # A extension can then be registered using
28
+ # MyModule.register_extension(MyExtension)
29
+ #
30
+ # The module will then keep track of all modules or classes it's included in.
31
+ # These modules and classes are called implementations here.
32
+ # If an extension is added later, the implementations will also be updated which would not be the case if normal includes were used.
33
+ module Extendable
34
+ # Register a module as an extension to an Entity in RTM.
35
+ # An entity may be e.g. RTM::TopicMap, RTM::Topic or any Module which was extended with RTM::Extendable
36
+ #
37
+ # Besides normal ruby inclusion of the module, this module keeps track of its implementations which are also updated in this method.
38
+ def register_extension(mod)
39
+ include mod
40
+ return unless @implementations
41
+ @implementations.each do |impl|
42
+ next if impl.ancestors.include?(mod)
43
+ impl.send(:include, mod)
44
+ end
45
+ end
46
+
47
+ # A standard Ruby hook to be notified about inclusions of this module.
48
+ # This normally eliminates the need to register a module as implementa
49
+ def included(klass)
50
+ # super
51
+ # puts "[RTMEXT] including #{self} into #{klass} in #{caller(1).first}"
52
+ register_implementation(klass)
53
+ klass.class_eval do
54
+ def self.included(klass2)
55
+ # puts "[RTMIMPLEXT] #{self} was included into #{klass2} in #{caller(1).first}"
56
+ # self.ancestors.select {|anc| anc.respond_to?(:register_implementation)}.each{|anc| anc.register_implementation(klass2) }
57
+ self.ancestors.find {|anc| anc.respond_to?(:register_implementation)}.register_implementation(klass2)
58
+ end
26
59
  end
27
60
  end
61
+
62
+ # Register an implementation to this module.
63
+ # Registred implementations will be updated if later any extensions are added.
64
+ # This method should normally be called from the included hook.
65
+ # Due to Ruby's restrictions on calling protected methods from other modules extending the very same module Extendable,
66
+ # this method must be public.
67
+ def register_implementation(klass)
68
+ # super if self.class.superclass.respond_to?(:register_implementation)
69
+ @implementations ||= []
70
+ @implementations << klass
71
+ end
28
72
  end
73
+ [
74
+ TopicMapSystem, Construct, Reifiable,
75
+ DatatypeAware, Scoped, Typed,
76
+ TopicMap, Topic, Name, Occurrence, Variant, Association, Role,
77
+ Locator, ItemIdentifier, SubjectIdentifier, SubjectLocator
78
+ ].each{|mod| mod.extend(Extendable)}
29
79
  end