rtm 0.1.6 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/DISCLAIMER +10 -33
- data/LICENSE +201 -0
- data/README +3 -3
- data/lib/rtm.rb +148 -74
- data/lib/rtm/axes.rb +295 -0
- data/lib/rtm/axes/association.rb +76 -0
- data/lib/rtm/axes/associations.rb +96 -0
- data/lib/rtm/axes/assocs_names_occs.rb +56 -0
- data/lib/rtm/axes/characteristic.rb +68 -0
- data/lib/rtm/axes/characteristics.rb +93 -0
- data/lib/rtm/axes/string.rb +76 -0
- data/lib/rtm/axes/strings.rb +87 -0
- data/lib/rtm/axes/topic.rb +233 -0
- data/lib/rtm/axes/topics.rb +280 -0
- data/lib/rtm/{backward_compatibility.rb → deprecated/index_property_set.rb} +3 -0
- data/lib/rtm/engine.rb +58 -0
- data/lib/rtm/extensions.rb +11 -1
- data/lib/rtm/{locator_helpers.rb → helpers/locator.rb} +15 -4
- data/lib/rtm/{helpers.rb → helpers/no_output.rb} +3 -0
- data/lib/rtm/helpers/uri.rb +13 -0
- data/lib/rtm/io.rb +18 -0
- data/lib/rtm/io/from_xtm2_libxml.rb +2 -1
- data/lib/rtm/io/ontopia_io.rb +25 -0
- data/lib/rtm/io/tmapix.rb +234 -0
- data/lib/rtm/io/to_hash.rb +116 -0
- data/lib/rtm/io/to_jtm.rb +53 -103
- data/lib/rtm/io/to_rdf.rb +30 -0
- data/lib/rtm/io/to_string.rb +8 -6
- data/lib/rtm/io/to_xtm1.rb +6 -4
- data/lib/rtm/io/to_xtm2.rb +10 -8
- data/lib/rtm/io/to_yaml.rb +29 -98
- data/lib/rtm/navigation.rb +37 -0
- data/lib/rtm/navigation/association/players.rb +25 -0
- data/lib/rtm/navigation/name/atomify.rb +19 -0
- data/lib/rtm/navigation/name/characteristics.rb +33 -0
- data/lib/rtm/navigation/occurrence/atomify.rb +19 -0
- data/lib/rtm/navigation/occurrence/characteristics.rb +33 -0
- data/lib/rtm/navigation/topic/characteristics.rb +33 -0
- data/lib/rtm/navigation/topic/indicators.rb +31 -0
- data/lib/rtm/navigation/topic/items.rb +31 -0
- data/lib/rtm/navigation/topic/locators.rb +31 -0
- data/lib/rtm/navigation/topic/players.rb +27 -0
- data/lib/rtm/navigation/topic/supertypes.rb +162 -0
- data/lib/rtm/navigation/topic/traverse.rb +51 -0
- data/lib/rtm/navigation/topic/types.rb +107 -0
- data/lib/rtm/psi.rb +33 -2
- data/lib/rtm/sugar.rb +34 -0
- data/lib/rtm/sugar/association/hash_access.rb +46 -0
- data/lib/rtm/sugar/occurrence/dynamic_value.rb +75 -0
- data/lib/rtm/{pimp_my_api.rb → sugar/occurrence/externalize.rb} +3 -0
- data/lib/rtm/sugar/role/counterparts.rb +133 -46
- data/lib/rtm/sugar/topic/characteristics.rb +126 -12
- data/lib/rtm/sugar/topic/counterparts.rb +130 -7
- data/lib/rtm/sugar/topic/hash_access.rb +140 -30
- data/lib/rtm/sugar/topic/scoped.rb +65 -0
- data/lib/rtm/sugar/topic/topic_ref.rb +35 -0
- data/lib/rtm/sugar/topic/typed.rb +159 -0
- data/lib/rtm/sugar/typed/types.rb +38 -0
- data/lib/rtm/validation.rb +8 -5
- data/lib/rtm/version.rb +18 -0
- data/spec/helpers/spec_exampleexamplegroup.rb +14 -0
- data/spec/rtm/axes/association_spec.rb +88 -0
- data/spec/rtm/axes/associations_spec.rb +60 -0
- data/spec/rtm/axes/assocs_names_occs_spec.rb +9 -0
- data/spec/rtm/axes/characteristic_spec.rb +90 -0
- data/spec/rtm/axes/characteristics_spec.rb +85 -0
- data/spec/rtm/axes/string_spec.rb +145 -0
- data/spec/rtm/axes/strings_spec.rb +168 -0
- data/spec/rtm/axes/topic_spec.rb +124 -0
- data/spec/rtm/axes/topics_spec.rb +103 -0
- data/spec/rtm/base_spec.rb +32 -0
- data/spec/rtm/io/tmapix_spec.rb +85 -0
- data/spec/rtm/navigation/association/players_spec.rb +58 -0
- data/spec/rtm/navigation/association_spec.rb +52 -0
- data/spec/rtm/navigation/name/atomify_spec.rb +27 -0
- data/spec/rtm/navigation/name/characteristics_spec.rb +34 -0
- data/spec/rtm/navigation/name_spec.rb +52 -0
- data/spec/rtm/navigation/occurrence/atomify_spec.rb +27 -0
- data/spec/rtm/navigation/occurrence/characteristics_spec.rb +34 -0
- data/spec/rtm/navigation/occurrence_spec.rb +52 -0
- data/spec/rtm/navigation/string_spec.rb +51 -0
- data/spec/rtm/navigation/topic/characteristics_spec.rb +55 -0
- data/spec/rtm/navigation/topic/indicators_spec.rb +43 -0
- data/spec/rtm/navigation/topic/items_spec.rb +44 -0
- data/spec/rtm/navigation/topic/locators_spec.rb +44 -0
- data/spec/rtm/navigation/topic/players_spec.rb +48 -0
- data/spec/rtm/navigation/topic/scope_spec.rb +41 -0
- data/spec/rtm/navigation/topic/supertypes_spec.rb +376 -0
- data/spec/rtm/navigation/topic/traverse_spec.rb +64 -0
- data/spec/rtm/navigation/topic/types_spec.rb +195 -0
- data/spec/rtm/navigation/topic_spec.rb +153 -0
- data/spec/rtm/sugar/association/hash_access_spec.rb +55 -0
- data/spec/rtm/sugar/occurrence/dynamic_value_spec.rb +16 -0
- data/spec/rtm/sugar/role/counterparts_spec.rb +191 -0
- data/spec/rtm/sugar/topic/characteristics_spec.rb +318 -0
- data/spec/rtm/sugar/topic/counterparts_spec.rb +184 -0
- data/spec/rtm/sugar/topic/hash_access_spec.rb +234 -0
- data/spec/rtm/sugar/topic/scoped_spec.rb +131 -0
- data/spec/rtm/sugar/topic/topic_ref_spec.rb +44 -0
- data/spec/rtm/sugar/topic/typed_spec.rb +155 -0
- data/spec/rtm/sugar/typed/types_spec.rb +24 -0
- data/spec/rtm/tmapi/core/association_spec.rb +169 -0
- data/spec/rtm/tmapi/core/construct_spec.rb +25 -0
- data/spec/rtm/tmapi/core/name_spec.rb +85 -0
- data/spec/rtm/tmapi/core/occurrence_spec.rb +96 -0
- data/spec/rtm/tmapi/core/reifiable_spec.rb +168 -0
- data/spec/rtm/tmapi/core/role_spec.rb +73 -0
- data/spec/rtm/tmapi/core/scoped_spec.rb +403 -0
- data/spec/rtm/tmapi/core/topic_map_spec.rb +648 -0
- data/spec/rtm/tmapi/core/topic_spec.rb +992 -0
- data/spec/rtm/tmapi/core/typed_spec.rb +112 -0
- data/spec/rtm/tmapi/core/variant_spec.rb +52 -0
- data/spec/rtm/tmapi/ext/java_util_set_spec.rb +34 -0
- data/spec/rtm/tmapi_spec.rb +44 -0
- data/spec/rtm/utils/sparql_spec.rb +26 -0
- data/spec/rtm_spec.rb +94 -0
- data/spec/spec_helper.rb +23 -0
- data/test/base_unit_test.rb +161 -0
- data/test/{base_test.rb → base_unit_test_tmapi.rb} +46 -43
- metadata +122 -66
- data/COPYRIGHT +0 -4
- data/lib/Rakefile.rb +0 -42
- data/lib/activetopicmaps.rb +0 -278
- data/lib/rtm/backend/active_record.rb +0 -58
- data/lib/rtm/backend/active_record/001_initial_schema.rb +0 -116
- data/lib/rtm/backend/active_record/association_and_role.rb +0 -33
- data/lib/rtm/backend/active_record/locators.rb +0 -55
- data/lib/rtm/backend/active_record/name_variant_occurrence.rb +0 -45
- data/lib/rtm/backend/active_record/quaaxtm2rtm.rb +0 -113
- data/lib/rtm/backend/active_record/quaaxtm2rtmviews.rb +0 -134
- data/lib/rtm/backend/active_record/set_wrapper.rb +0 -98
- data/lib/rtm/backend/active_record/tm_construct.rb +0 -62
- data/lib/rtm/backend/active_record/tm_delegator.rb +0 -345
- data/lib/rtm/backend/active_record/tm_set_delegator.rb +0 -195
- data/lib/rtm/backend/active_record/tmdm.rb +0 -298
- data/lib/rtm/backend/active_record/topic.rb +0 -87
- data/lib/rtm/backend/active_record/topic_map.rb +0 -314
- data/lib/rtm/backend/active_record/traverse_associations.rb +0 -87
- data/lib/rtm/base.rb +0 -92
- data/lib/rtm/connect.rb +0 -92
- data/lib/rtm/core_ext.rb +0 -6
- data/lib/rtm/io/from_xtm2.rb +0 -263
- data/lib/rtm/merging/merging.rb +0 -307
- data/lib/rtm/sugar/topic/identifier_direct.rb +0 -11
- data/lib/rtm/sugar/topic/predefined_associations.rb +0 -42
- data/lib/run_main_project.rb +0 -16
@@ -1,298 +0,0 @@
|
|
1
|
-
old_verbose=$VERBOSE
|
2
|
-
$VERBOSE=false
|
3
|
-
require 'active_record'
|
4
|
-
$VERBOSE=old_verbose
|
5
|
-
|
6
|
-
module RTM::AR
|
7
|
-
# The Active Record TMDM backend
|
8
|
-
module TMDM
|
9
|
-
# Moves all fields in a collection to another owner (for classes using belongs_to in AR::Base class)
|
10
|
-
module Movable
|
11
|
-
# Takes a list of [field,from, to] arguments.
|
12
|
-
# RTM::AR::TMDM::ItemIdentifier.move_all(
|
13
|
-
# ["topic_map_construct_id", other.__getobj__.id, self.__getobj__.id],
|
14
|
-
# ["topic_map_construct_type", other.__getobj__.class.name, self.__getobj__.class.name]
|
15
|
-
# )
|
16
|
-
# or
|
17
|
-
# RTM::AR::TMDM::Variant.move_all(["topic_name_id", other.__getobj__.id, self.__getobj__.id])
|
18
|
-
|
19
|
-
#
|
20
|
-
def move_all(*args)
|
21
|
-
raise "All parameters must have a size of 3: [field_name, from, to]" unless args.all?{|a| a.size == 3}
|
22
|
-
set_part = ""
|
23
|
-
where_part = ""
|
24
|
-
args.each do |field, from, to|
|
25
|
-
set_part += ", " unless set_part.empty?
|
26
|
-
where_part += " and " unless where_part.empty?
|
27
|
-
from = "'#{from}'" unless from.is_a? Numeric
|
28
|
-
to = "'#{to}'" unless to.is_a? Numeric
|
29
|
-
where_part += "#{field} = #{from}"
|
30
|
-
set_part += "#{field} = #{to}"
|
31
|
-
end
|
32
|
-
#puts "setpart: #{set_part.inspect}\nwherepart: #{where_part.inspect}"
|
33
|
-
res = self.update_all(set_part, where_part)
|
34
|
-
#puts "result: #{res.inspect}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
class TopicMapConstruct < ActiveRecord::Base
|
39
|
-
self.store_full_sti_class = false
|
40
|
-
extend Movable
|
41
|
-
class << self
|
42
|
-
def abstract_class?
|
43
|
-
self == TopicMapConstruct
|
44
|
-
end
|
45
|
-
def alias_ar_relation(new,old)
|
46
|
-
alias_method new, old
|
47
|
-
alias_method "#{new}=", "#{old}="
|
48
|
-
end
|
49
|
-
alias :alias_belongs_to :alias_ar_relation
|
50
|
-
alias :alias_has_many :alias_ar_relation
|
51
|
-
def belongs_to_with_alias(name, synonym)
|
52
|
-
belongs_to name
|
53
|
-
alias_belongs_to synonym, name
|
54
|
-
end
|
55
|
-
def has_many_with_alias(name, synonym, *args)
|
56
|
-
has_many name, *args
|
57
|
-
alias_has_many synonym, name
|
58
|
-
end
|
59
|
-
def belongs_to_parent(parent)
|
60
|
-
belongs_to parent
|
61
|
-
alias_belongs_to :parent, parent
|
62
|
-
end
|
63
|
-
def this_is_a_typed_object
|
64
|
-
belongs_to :ttype, :class_name => "Topic", :foreign_key => :ttype_id
|
65
|
-
module_eval(<<-EOS, "(__RTM_AR_TMDM_TYPED_OBJECT__)", 1)
|
66
|
-
def type=(ptype)
|
67
|
-
self.ttype=ptype
|
68
|
-
end
|
69
|
-
def type
|
70
|
-
self.ttype
|
71
|
-
end
|
72
|
-
EOS
|
73
|
-
end
|
74
|
-
end
|
75
|
-
has_many :item_identifiers, :as => :topic_map_construct, :dependent => :destroy
|
76
|
-
def topic_map
|
77
|
-
parent.topic_map
|
78
|
-
end
|
79
|
-
def move_to(new_parent)
|
80
|
-
self.parent = new_parent
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
84
|
-
class Reifiable < TopicMapConstruct
|
85
|
-
def self.abstract_class?
|
86
|
-
self == Reifiable
|
87
|
-
end
|
88
|
-
has_one :reifier, :class_name => "Topic", :as => :reified
|
89
|
-
end
|
90
|
-
class ScopedObject < Reifiable
|
91
|
-
def self.abstract_class?
|
92
|
-
self == ScopedObject
|
93
|
-
end
|
94
|
-
has_many :scoped_objects_topics, :as => :scoped_object, :dependent => :destroy
|
95
|
-
has_many :scope, :through => :scoped_objects_topics, :source => :topic
|
96
|
-
# def scope
|
97
|
-
# self.scoped_objects_topics.map { |sot| sot.topic }
|
98
|
-
# end
|
99
|
-
# def add_scoping_topic(topic) # this is not ruby-ish but at least it works, would need a complete association proxy instead...
|
100
|
-
# sot = ScopedObjectsTopic.create :topic => topic, :scoped_object => self
|
101
|
-
# self
|
102
|
-
# # sot = ScopedObjectsTopic.new :topic => topic, :scoped_object => self
|
103
|
-
# # self.scoped_objects_topics << sot
|
104
|
-
# # self
|
105
|
-
# end
|
106
|
-
# def remove_scoping_topic(topic) # this is not ruby-ish but at least it works, would need a complete association proxy instead...
|
107
|
-
# self.scoped_objects_topics.select { |sot| sot.topic == topic }.destroy
|
108
|
-
# self
|
109
|
-
# end
|
110
|
-
end
|
111
|
-
class ScopedObjectsTopic < ActiveRecord::Base
|
112
|
-
self.store_full_sti_class = false
|
113
|
-
extend Movable
|
114
|
-
belongs_to :topic
|
115
|
-
belongs_to :scoped_object, :polymorphic => true
|
116
|
-
belongs_to :association, :class_name => 'RTM::AR::TMDM::Association', :foreign_key => "scoped_object_id"
|
117
|
-
belongs_to :topic_name, :class_name => 'RTM::AR::TMDM::TopicName', :foreign_key => "scoped_object_id"
|
118
|
-
belongs_to :variant, :class_name => 'RTM::AR::TMDM::Variant', :foreign_key => "scoped_object_id"
|
119
|
-
belongs_to :occurrence, :class_name => 'RTM::AR::TMDM::Occurrence', :foreign_key => "scoped_object_id"
|
120
|
-
end
|
121
|
-
|
122
|
-
class Locator < ActiveRecord::Base
|
123
|
-
self.store_full_sti_class = false
|
124
|
-
extend Movable
|
125
|
-
class << self
|
126
|
-
def abstract_class?
|
127
|
-
self == Locator
|
128
|
-
end
|
129
|
-
end
|
130
|
-
belongs_to :topic_map
|
131
|
-
end
|
132
|
-
|
133
|
-
class ItemIdentifier < Locator
|
134
|
-
belongs_to :topic_map_construct, :polymorphic => true
|
135
|
-
def to_s
|
136
|
-
self.reference
|
137
|
-
end
|
138
|
-
def move_to(new_tmc)
|
139
|
-
#puts "\n\nmoving\n\t#{self.inspect}\n\nto\n\t#{new_tmc.inspect}"
|
140
|
-
#self.update_all "topic_map_construct_id = #{new_tmc.id}, topic_map_construct_type = '#{new_tmc.class.name}'",
|
141
|
-
#puts "changing id"
|
142
|
-
#puts self.topic_map_construct_id = new_tmc.id
|
143
|
-
#puts "changing type"
|
144
|
-
#puts self.topic_map_construct_type = new_tmc.class.name
|
145
|
-
self.topic_map_construct = new_tmc
|
146
|
-
#puts "saving"
|
147
|
-
self.save
|
148
|
-
#
|
149
|
-
# das geht!!!
|
150
|
-
#self.class.update( self.id, "topic_map_construct_id" => new_tmc.id)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
class SubjectLocator < Locator
|
154
|
-
belongs_to :topic
|
155
|
-
def to_s
|
156
|
-
self.reference
|
157
|
-
end
|
158
|
-
end
|
159
|
-
class SubjectIdentifier < Locator
|
160
|
-
belongs_to :topic
|
161
|
-
def to_s
|
162
|
-
self.reference
|
163
|
-
end
|
164
|
-
end
|
165
|
-
# http://www.isotopicmaps.org/sam/sam-model/#d0e736
|
166
|
-
class Topic < TopicMapConstruct
|
167
|
-
belongs_to :reified, :polymorphic => true
|
168
|
-
belongs_to_parent :topic_map
|
169
|
-
has_many :subject_locators, :dependent => :destroy
|
170
|
-
has_many :subject_identifiers, :dependent => :destroy
|
171
|
-
has_many :occurrences, :dependent => :destroy
|
172
|
-
has_many_with_alias :topic_names, :names, :dependent => :destroy
|
173
|
-
has_many_with_alias :association_roles, :roles, :include => :association
|
174
|
-
has_many :associations, :through => :association_roles
|
175
|
-
#has_many :played_types, :through => :association_roles, :source => :type
|
176
|
-
|
177
|
-
has_many :associations_typed, :class_name => "Association", :foreign_key => :ttype_id
|
178
|
-
has_many :association_roles_typed, :class_name => "AssociationRole", :foreign_key => :ttype_id
|
179
|
-
has_many :topic_names_typed, :class_name => "TopicName", :foreign_key => :ttype_id
|
180
|
-
has_many :occurrences_typed, :class_name => "Occurrence", :foreign_key => :ttype_id
|
181
|
-
|
182
|
-
has_many :scoped_objects_topics
|
183
|
-
has_many :scoped_associations, :through => :scoped_objects_topics, :source => :association,
|
184
|
-
:conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Association'"
|
185
|
-
has_many :scoped_topic_names, :through => :scoped_objects_topics, :source => :topic_name,
|
186
|
-
:conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::TopicName'"
|
187
|
-
has_many :scoped_variants, :through => :scoped_objects_topics, :source => :variant,
|
188
|
-
:conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Variant'"
|
189
|
-
has_many :scoped_occurrences, :through => :scoped_objects_topics, :source => :occurrence,
|
190
|
-
:conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Occurrence'"
|
191
|
-
|
192
|
-
# def scoped_objects
|
193
|
-
# self.scoped_objects_topics.collect { |a| a.scoped_object } # temporary hack polymorphic has_many_through
|
194
|
-
# end
|
195
|
-
def scoped_objects
|
196
|
-
scoped_associations + scoped_topic_names + scoped_variants + scoped_occurrences
|
197
|
-
end
|
198
|
-
|
199
|
-
end
|
200
|
-
|
201
|
-
class AssociationRole < Reifiable
|
202
|
-
belongs_to_parent :association
|
203
|
-
belongs_to_with_alias :topic, :player
|
204
|
-
this_is_a_typed_object
|
205
|
-
end
|
206
|
-
|
207
|
-
class TopicName < ScopedObject
|
208
|
-
belongs_to_parent :topic
|
209
|
-
this_is_a_typed_object
|
210
|
-
has_many :variants, :dependent => :destroy
|
211
|
-
end
|
212
|
-
|
213
|
-
class Association < ScopedObject
|
214
|
-
belongs_to_parent :topic_map
|
215
|
-
this_is_a_typed_object
|
216
|
-
has_many_with_alias :association_roles, :roles, :dependent => :destroy
|
217
|
-
def create_role(rplayer, ttype)
|
218
|
-
AssociationRole.create :parent => self, :player => rplayer, :ttype => ttype
|
219
|
-
end
|
220
|
-
alias :create_association_role :create_role
|
221
|
-
has_many :role_players, :through => :association_roles, :source => :topic
|
222
|
-
has_many :role_types, :through => :association_roles, :source => :ttype
|
223
|
-
end
|
224
|
-
|
225
|
-
class AssociationCache < TopicMapConstruct
|
226
|
-
set_table_name "associations_cache"
|
227
|
-
belongs_to_parent :topic_map
|
228
|
-
this_is_a_typed_object
|
229
|
-
has_many_with_alias :association_roles, :roles
|
230
|
-
belongs_to :role1, :class_name => "RTM::AR::TMDM::AssociationRole", :foreign_key => "role1_id"
|
231
|
-
belongs_to :player1, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "player1_id"
|
232
|
-
belongs_to :type1, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "type1_id"
|
233
|
-
belongs_to :role2, :class_name => "RTM::AR::TMDM::AssociationRole", :foreign_key => "role2_id"
|
234
|
-
belongs_to :player2, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "player2_id"
|
235
|
-
belongs_to :type2, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "type2_id"
|
236
|
-
# rolecount -> rcnt
|
237
|
-
end
|
238
|
-
|
239
|
-
class Occurrence < ScopedObject
|
240
|
-
belongs_to_parent :topic
|
241
|
-
this_is_a_typed_object
|
242
|
-
end
|
243
|
-
|
244
|
-
class Variant < ScopedObject
|
245
|
-
belongs_to_parent :topic_name
|
246
|
-
end
|
247
|
-
|
248
|
-
class TopicMap < Reifiable
|
249
|
-
# real properties
|
250
|
-
has_many :topics, :dependent => :destroy, :include => [:subject_identifiers, :subject_locators]
|
251
|
-
has_many :associations, :dependent => :destroy, :include => :association_roles
|
252
|
-
|
253
|
-
# access to subproperties
|
254
|
-
has_many :locators, :class_name => "ItemIdentifier", :dependent => :destroy
|
255
|
-
has_many :subject_locators, :dependent => :destroy
|
256
|
-
has_many :subject_identifiers, :dependent => :destroy
|
257
|
-
|
258
|
-
has_many :topic_names, :through => :topics
|
259
|
-
alias :names :topic_names
|
260
|
-
has_many :occurrences, :through => :topics
|
261
|
-
has_many :association_roles, :through => :associations
|
262
|
-
alias :roles :association_roles
|
263
|
-
|
264
|
-
%w[association association_role topic_name occurrence].each do |m|
|
265
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET__)", 1)
|
266
|
-
def #{m}_types
|
267
|
-
topics.select{|t| t.#{m}s_typed.size > 0}
|
268
|
-
end
|
269
|
-
EOS
|
270
|
-
end
|
271
|
-
|
272
|
-
#typing
|
273
|
-
# has_many :association_types, :class_name => "Association", :foreign_key => :ttype_id
|
274
|
-
# has_many :association_role_types, :class_name => "AssociationRole", :foreign_key => :ttype_id
|
275
|
-
# has_many :topic_name_types, :class_name => "TopicName", :foreign_key => :ttype_id
|
276
|
-
# has_many :occurrence_types, :class_name => "Occurrence", :foreign_key => :ttype_id
|
277
|
-
|
278
|
-
# has_many :association_types, :aka => :at, :type => :Topic, :wrap => true
|
279
|
-
# has_many :association_role_types, :aka => [:role_types,:art,:rt], :type => :Topic, :wrap => true
|
280
|
-
# has_many :topic_name_types, :aka => [:name_types,:tnt,:nt], :type => :Topic, :wrap => true
|
281
|
-
# has_many :occurrence_types, :aka => :ot, :type => :Topic, :wrap => true
|
282
|
-
|
283
|
-
|
284
|
-
def topic_map
|
285
|
-
self
|
286
|
-
end
|
287
|
-
|
288
|
-
# # Creates a new Locator in this TopicMap
|
289
|
-
# def create_locator(reference, notation=nil)
|
290
|
-
# if notation
|
291
|
-
# ItemIdentifier.create :reference => reference, :notation => notation
|
292
|
-
# else
|
293
|
-
# ItemIdentifier.create :reference => reference # is there a better way to preserve the database default notation if none given?
|
294
|
-
# end
|
295
|
-
# end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module RTM::AR
|
2
|
-
class Topic < TopicMapConstruct
|
3
|
-
include RTM::Topic
|
4
|
-
wrapper_cache
|
5
|
-
|
6
|
-
parent :topic_map
|
7
|
-
property_set :subject_identifiers, :aka => [:si,:sid], :type => :SubjectIdentifier, :wrap => true,
|
8
|
-
#:create => :subject_identifier, :create_aka => [:csi,:csid],
|
9
|
-
#:create_args => [{:name => :reference, :type => :String}]
|
10
|
-
:add => true, :remove => true
|
11
|
-
property_set :subject_locators, :aka => [:sl,:slo], :type => :SubjectLocator, :wrap => true,
|
12
|
-
#:create => :subject_locator, :create_aka => [:csl, :cslo],
|
13
|
-
#:create_args => [{:name => :reference, :type => :String}]
|
14
|
-
:add => true, :remove => true
|
15
|
-
|
16
|
-
property :reified, :computable => true, :type => :Reifiable, :wrap => true
|
17
|
-
|
18
|
-
property_set :topic_names, :aka => [:n, :names], :type => :TopicName, :wrap => true,
|
19
|
-
:create => :topic_name, :create_aka => [:create_name, :cn],
|
20
|
-
:create_args => [ {:name => :value, :type => :String}, {:name => :type, :type => :Topic, :optional => true}, {:name => :scope, :type => :Collection} ]
|
21
|
-
|
22
|
-
property_set :occurrences, :aka => :o, :type => :Occurrence, :wrap => true,
|
23
|
-
:create => :occurrence, :create_aka => :co,
|
24
|
-
:create_args => [ {:name => :value, :type => [:String, :Locator]}, {:name => :type, :type => :Topic}, {:name => :scope, :type => :Collection} ]
|
25
|
-
|
26
|
-
property_set :roles, :aka => [:r, :roles_played, :association_roles], :computable => true, :type => :AssociationRole, :wrap => true
|
27
|
-
|
28
|
-
property_set :associations, :aka => [:a, :associations_played], :type => :Association, :wrap => true
|
29
|
-
|
30
|
-
property_set :scoped_objects, :type => :TopicMapConstruct, :wrap => true
|
31
|
-
property_set :scoped_associations, :type => :Association, :wrap => true
|
32
|
-
property_set :scoped_topic_names, :aka => :scoped_names, :type => :TopicName, :wrap => true
|
33
|
-
property_set :scoped_variants, :type => :Variant, :wrap => true
|
34
|
-
property_set :scoped_occurrences, :type => :Occurrence, :wrap => true
|
35
|
-
|
36
|
-
property_set :associations_typed, :aka => :at, :type => :Association, :wrap => true
|
37
|
-
property_set :association_roles_typed, :aka => [:roles_typed,:art,:rt], :type => :AssociationRole, :wrap => true
|
38
|
-
property_set :topic_names_typed, :aka => [:names_typed,:tnt,:nt], :type => :TopicName, :wrap => true
|
39
|
-
property_set :occurrences_typed, :aka => :ot, :type => :Occurrence, :wrap => true
|
40
|
-
|
41
|
-
require 'rtm/sugar/topic/characteristics'
|
42
|
-
include RTM::Sugar::Topic::Characteristics
|
43
|
-
require 'rtm/sugar/topic/counterparts'
|
44
|
-
include RTM::Sugar::Topic::Counterparts
|
45
|
-
require 'rtm/sugar/topic/identifier_direct'
|
46
|
-
include RTM::Sugar::Topic::IdentifierDirect
|
47
|
-
require 'rtm/sugar/topic/hash_access'
|
48
|
-
include RTM::Sugar::Topic::HashAccess
|
49
|
-
require 'rtm/sugar/topic/predefined_associations'
|
50
|
-
include RTM::Sugar::Topic::PredefinedAssociations
|
51
|
-
|
52
|
-
# class:Topic equality, http://www.isotopicmaps.org/sam/sam-model/#d0e1029
|
53
|
-
#
|
54
|
-
# This method is all crap. These ActiveRecord Arrays can't be intersected,
|
55
|
-
# so I map the identifiers to their reference which seems long winded.
|
56
|
-
# Still I find it better than using their ID in the long.
|
57
|
-
#
|
58
|
-
def ==(o)
|
59
|
-
return false unless o
|
60
|
-
# Two topic items are equal if they have:
|
61
|
-
# * at least one equal string in their [subject identifiers] properties,
|
62
|
-
# -> test if intersection are > 0
|
63
|
-
my_si = self.subject_identifiers.map{|si| si.reference}
|
64
|
-
ot_si = o.subject_identifiers.map{|si| si.reference}
|
65
|
-
return true if ( my_si & ot_si).size > 0
|
66
|
-
|
67
|
-
# * at least one equal string in their [item identifiers] properties,
|
68
|
-
my_ii = self.item_identifiers.map{|ii| ii.reference}
|
69
|
-
ot_ii = o.item_identifiers.map{|ii| ii.reference}
|
70
|
-
return true if (my_ii & ot_ii).size > 0
|
71
|
-
|
72
|
-
# * at least one equal string in their [subject locators] properties,
|
73
|
-
my_sl = self.subject_locators.map{|sl| sl.reference}
|
74
|
-
ot_sl = o.subject_locators.map{|sl| sl.reference}
|
75
|
-
return true if (my_sl & ot_sl).size > 0
|
76
|
-
|
77
|
-
# * an equal string in the [subject identifiers] property of the one topic item and the [item identifiers] property of the other, or
|
78
|
-
return true if (my_si & ot_ii).size > 0
|
79
|
-
return true if (my_ii & ot_si).size > 0
|
80
|
-
|
81
|
-
# * the same information item in their [reified] properties.
|
82
|
-
return true if self.reified != nil && o.reified != nil && (self.reified == o.reified)
|
83
|
-
# ... otherwise
|
84
|
-
false
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
@@ -1,314 +0,0 @@
|
|
1
|
-
module RTM::AR
|
2
|
-
class TopicMap < Reifiable
|
3
|
-
include RTM::TopicMap
|
4
|
-
wrapper_cache
|
5
|
-
property_set :topics, :aka => :t, :type => :Topic, :wrap => true,
|
6
|
-
:create => :topic, :create_aka => :ct
|
7
|
-
|
8
|
-
property_set :associations, :aka => [:a, :assocs], :type => :Association, :wrap => true,
|
9
|
-
:create => :association, :create_aka => :ca,
|
10
|
-
:create_args => [{:name => :type, :type => :Topic}]
|
11
|
-
|
12
|
-
|
13
|
-
delegate :base_locator
|
14
|
-
|
15
|
-
property_set :association_types, :aka => :at, :type => :Topic, :wrap => true
|
16
|
-
property_set :association_role_types, :aka => [:role_types,:art,:rt], :type => :Topic, :wrap => true
|
17
|
-
property_set :topic_name_types, :aka => [:name_types,:tnt,:nt], :type => :Topic, :wrap => true
|
18
|
-
property_set :occurrence_types, :aka => :ot, :type => :Topic, :wrap => true
|
19
|
-
|
20
|
-
property_set :topic_names, :aka => [:names,:n], :type => :TopicName, :wrap => :true
|
21
|
-
property_set :occurrences, :aka => :o, :type => :Occurrence, :wrap => :true
|
22
|
-
property_set :association_roles, :aka => [:roles, :r], :type => :AssociationRole, :wrap => :true
|
23
|
-
|
24
|
-
def types
|
25
|
-
topics.select{|t| t.instances.size > 0}
|
26
|
-
end
|
27
|
-
alias :topic_types :types
|
28
|
-
def fast_types
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
# This fetches all topics who have no topic-instances (but they might be types for associations etc.).
|
33
|
-
# See indivduals
|
34
|
-
def non_types
|
35
|
-
topics.select{|t| t.instances.size == 0}
|
36
|
-
end
|
37
|
-
|
38
|
-
# This fetches all topics which are not type for something else (including topics, associations etc.).
|
39
|
-
# See non_types
|
40
|
-
def individuals
|
41
|
-
non_types.select{|t| t.associations_typed.size==0 && t.roles_typed.size==0 && t.names_typed.size==0 && t.occurrences_typed.size==0}
|
42
|
-
end
|
43
|
-
def instances
|
44
|
-
topics.select{|t| t.types.size > 0}
|
45
|
-
end
|
46
|
-
def non_instances
|
47
|
-
topics.reject{|t| t.types.size > 0}
|
48
|
-
end
|
49
|
-
def internal_occurrences
|
50
|
-
occurrences.select{|o| o.datatype != RTM::PSI[:IRI]}
|
51
|
-
end
|
52
|
-
def external_occurrences
|
53
|
-
occurrences.select{|o| o.datatype == RTM::PSI[:IRI]}
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.create(base_locator, params={})
|
57
|
-
bl_uri = URI.parse(base_locator)
|
58
|
-
raise "The locator for the Topic Map must be absolute! \"#{base_locator}\" is not an absolute locator." unless bl_uri.absolute?
|
59
|
-
tm = self.wrap(TMDM::TopicMap.find_or_create_by_base_locator(base_locator))
|
60
|
-
yield tm if block_given?
|
61
|
-
tm
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.topic_maps
|
65
|
-
TopicMaps.wrap(TMDM::TopicMap.find(:all))
|
66
|
-
end
|
67
|
-
|
68
|
-
# Resolves an IRI or fragment relative to the base_locator of this topic_map or an optional given alternative_base_locator
|
69
|
-
#
|
70
|
-
# Absolute IRIs are taken as is.
|
71
|
-
#
|
72
|
-
# Relative IRIs:
|
73
|
-
# If the base_locator is a directory (ends with "/") it is appended like a file, i.e. directly
|
74
|
-
# If the base_locator is a file it is appended as a fragment (with # in between)
|
75
|
-
def resolve(obj,alternative_base_locator=nil)
|
76
|
-
uri = obj.to_s
|
77
|
-
# TODO uri = URI.decode(obj.to_s) # this InvalidURIError somethimes :(
|
78
|
-
begin
|
79
|
-
uri_uri = URI.parse(uri)
|
80
|
-
rescue URI::InvalidComponentError => ice
|
81
|
-
warn "Catched an URI::InvalidComponentError for URI: #{uri}, message was \"#{ice.message}\"\n" +
|
82
|
-
"Will continue using the UNRESOLVED IRI, claiming it is absolute."
|
83
|
-
return uri
|
84
|
-
end
|
85
|
-
if uri_uri.absolute?
|
86
|
-
return uri_uri.to_s
|
87
|
-
end
|
88
|
-
|
89
|
-
uri = uri[1..-1] if uri[0] == "#"[0]
|
90
|
-
bl = alternative_base_locator || base_locator
|
91
|
-
if bl[-1,1] == "/"
|
92
|
-
return bl + uri
|
93
|
-
else
|
94
|
-
return bl + "#" + uri
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
#private
|
99
|
-
|
100
|
-
def _item_identifier(iid)
|
101
|
-
__getobj__.locators.find_by_reference(resolve(iid)) # doesn't work :( --> , :include => [ :topic_map_construct ])
|
102
|
-
end
|
103
|
-
def _item_identifier!(iid)
|
104
|
-
__getobj__.locators.find_or_create_by_reference(resolve(iid)) # doesn't work :( --> , :include => [ :topic_map_construct ])
|
105
|
-
end
|
106
|
-
|
107
|
-
def _subject_identifier(iid)
|
108
|
-
__getobj__.subject_identifiers.find_by_reference(iid, :include => :topic)
|
109
|
-
end
|
110
|
-
def _subject_identifier!(iid)
|
111
|
-
__getobj__.subject_identifiers.find_or_create_by_reference(iid, :include => :topic)
|
112
|
-
end
|
113
|
-
|
114
|
-
def _subject_locator(iid)
|
115
|
-
__getobj__.subject_locators.find_by_reference(iid, :include => :topic)
|
116
|
-
end
|
117
|
-
def _subject_locator!(iid)
|
118
|
-
__getobj__.subject_locators.find_or_create_by_reference(iid, :include => :topic)
|
119
|
-
end
|
120
|
-
|
121
|
-
|
122
|
-
# internal helper for by_item_identifier, doesn't wrap result
|
123
|
-
def _by_item_identifier(iid)
|
124
|
-
iid = RTM::LocatorHelpers.iid2iri(iid) if RTM::LocatorHelpers.is_a_iid?(iid)
|
125
|
-
ii = __getobj__.locators.find_by_reference(resolve(iid)) #, :include => [ :topic_map_construct ])
|
126
|
-
return ii.topic_map_construct if ii
|
127
|
-
nil
|
128
|
-
end
|
129
|
-
def _topic_by_item_identifier(iid)
|
130
|
-
t = _by_item_identifier(iid)
|
131
|
-
return nil unless t
|
132
|
-
return t if t.class.name =~ /::Topic$/ # only return something if the thing is a topic
|
133
|
-
nil
|
134
|
-
end
|
135
|
-
|
136
|
-
# internal helper for topic_by_item_identifier!, doesn't wrap result
|
137
|
-
def _topic_by_item_identifier!(iid)
|
138
|
-
iid = RTM::LocatorHelpers.iid2iri(iid) if RTM::LocatorHelpers.is_a_iid?(iid)
|
139
|
-
ii = __getobj__.locators.find_or_create_by_reference(resolve(iid))#, :include => [ :topic_map_construct ])
|
140
|
-
return ii.topic_map_construct if ii.topic_map_construct && ii.topic_map_construct_type =~ /::Topic$/
|
141
|
-
top2 = _topic_by_subject_identifier(resolve(iid))
|
142
|
-
if top2
|
143
|
-
ii.topic_map_construct = top2
|
144
|
-
else
|
145
|
-
ii.topic_map_construct = create_topic.__getobj__
|
146
|
-
end
|
147
|
-
ii.save
|
148
|
-
ii.topic_map_construct
|
149
|
-
end
|
150
|
-
# internal helper for topic_by_subject_identifier, doesn't wrap result
|
151
|
-
def _topic_by_subject_identifier(sid)
|
152
|
-
si = __getobj__.subject_identifiers.find_by_reference(sid, :include => [ :topic ])
|
153
|
-
return si.topic if si
|
154
|
-
nil
|
155
|
-
end
|
156
|
-
# internal helper for topic_by_subject_identifier!, doesn't wrap result
|
157
|
-
def _topic_by_subject_identifier!(sid)
|
158
|
-
si = __getobj__.subject_identifiers.find_or_create_by_reference(sid, :include => [ :topic ])
|
159
|
-
return si.topic if si.topic
|
160
|
-
begin
|
161
|
-
top2 = _by_item_identifier(sid)
|
162
|
-
rescue ActiveRecord::RecordNotFound => rnf
|
163
|
-
si.topic = create_topic.__getobj__
|
164
|
-
else
|
165
|
-
if top2 && top2.respond_to?(:subject_identifiers)
|
166
|
-
si.topic = top2
|
167
|
-
else
|
168
|
-
si.topic = create_topic.__getobj__
|
169
|
-
end
|
170
|
-
end
|
171
|
-
si.save
|
172
|
-
si.topic
|
173
|
-
end
|
174
|
-
|
175
|
-
# internal helper for topic_by_subject_locator, doesn't wrap result
|
176
|
-
def _topic_by_subject_locator(slo)
|
177
|
-
sl = __getobj__.subject_locators.find_by_reference(RTM::LocatorHelpers.slo2iri(slo)) #, :include => [ :topic ])
|
178
|
-
return sl.topic if sl
|
179
|
-
nil
|
180
|
-
end
|
181
|
-
|
182
|
-
# internal helper for topic_by_subject_locator!, doesn't wrap result
|
183
|
-
def _topic_by_subject_locator!(slo)
|
184
|
-
sl = __getobj__.subject_locators.find_or_create_by_reference(RTM::LocatorHelpers.slo2iri(slo), :include => [ :topic ])
|
185
|
-
return sl.topic if sl.topic
|
186
|
-
sl.topic = create_topic.__getobj__
|
187
|
-
sl.save
|
188
|
-
sl.topic
|
189
|
-
end
|
190
|
-
def _topic_by_locator(iri)
|
191
|
-
raise "Locator may not be nil" unless iri
|
192
|
-
if RTM::LocatorHelpers.is_a_slo?(iri)
|
193
|
-
_topic_by_subject_locator(iri)
|
194
|
-
elsif RTM::LocatorHelpers.is_a_iid?(iri)
|
195
|
-
_topic_by_item_identifier(iri)
|
196
|
-
elsif URI.parse(iri).absolute?
|
197
|
-
_topic_by_subject_identifier(iri)
|
198
|
-
else
|
199
|
-
_topic_by_item_identifier(iri)
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def _topic_by_locator!(iri)
|
204
|
-
raise "Locator may not be nil" unless iri
|
205
|
-
if RTM::LocatorHelpers.is_a_slo?(iri)
|
206
|
-
_topic_by_subject_locator!(iri)
|
207
|
-
elsif RTM::LocatorHelpers.is_a_iid?(iri)
|
208
|
-
_topic_by_item_identifier!(iri)
|
209
|
-
elsif URI.parse(iri).absolute?
|
210
|
-
_topic_by_subject_identifier!(iri)
|
211
|
-
else
|
212
|
-
_topic_by_item_identifier!(iri)
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
%w[topic association role name occurrence variant].each do |x|
|
217
|
-
eval <<-EOI
|
218
|
-
def _#{x}_by_id(id)
|
219
|
-
__getobj__.#{x}s.find(id)
|
220
|
-
end
|
221
|
-
EOI
|
222
|
-
end
|
223
|
-
public
|
224
|
-
# returns an item identifier from the topic_map if it exists
|
225
|
-
def item_identifier(iid)
|
226
|
-
ItemIdentifier.wrap(_item_identifier(iid))
|
227
|
-
end
|
228
|
-
# returns an item identififier from the topic_map or creates it if it doesn't exist
|
229
|
-
def item_identifier!(iid)
|
230
|
-
ItemIdentifier.wrap(_item_identifier!(iid))
|
231
|
-
end
|
232
|
-
alias :create_locator :item_identifier!
|
233
|
-
# Returns a topic map construct by it's item identifier or nil if not found.
|
234
|
-
# It's the equivalent to TMAPI's TopicMapObjectIndex.getTopicMapObjectBySourceLocator
|
235
|
-
def by_item_identifier(iid)
|
236
|
-
TopicMapConstruct.wrap(_by_item_identifier(iid))
|
237
|
-
end
|
238
|
-
# Returns a topic by it's item identifier. The topic will be created if not found.
|
239
|
-
def topic_by_item_identifier!(iid)
|
240
|
-
Topic.wrap(_topic_by_item_identifier!(iid))
|
241
|
-
end
|
242
|
-
# Returns a topic by it's subject identifier or nil if not found.
|
243
|
-
# It's the equivalent to TMAPI's TopicsIndex.getTopicBySubjectIdentifier.
|
244
|
-
def topic_by_subject_identifier(sid)
|
245
|
-
Topic.wrap(_topic_by_subject_identifier(sid))
|
246
|
-
end
|
247
|
-
# returns a topic by it's subject identifier. The topic will be created if not found.
|
248
|
-
def topic_by_subject_identifier!(sid)
|
249
|
-
Topic.wrap(_topic_by_subject_identifier!(sid))
|
250
|
-
end
|
251
|
-
# Returns a topic by it's subject locator or nil if not found.
|
252
|
-
# It's the equivalent to TMAPI's TopicsIndex.getTopicBySubjectLocator
|
253
|
-
def topic_by_subject_locator(slo)
|
254
|
-
Topic.wrap(_topic_by_subject_locator(slo))
|
255
|
-
end
|
256
|
-
# returns a topic by it's subject locator. The topic will be created if not found.
|
257
|
-
def topic_by_subject_locator!(slo)
|
258
|
-
Topic.wrap(_topic_by_subject_locator!(slo))
|
259
|
-
end
|
260
|
-
|
261
|
-
# Gets a topic from this topic map using its (relative) item identifier,
|
262
|
-
# its (absolute) subject identifier or its (absolute and by "=" prepended) subject locator)
|
263
|
-
#
|
264
|
-
# Returns nil if the Topic does not exist.
|
265
|
-
#
|
266
|
-
# It's also possible to pass a number, which is used to fetch a topic using the internal id. In this case, an exception is thrown, if the topic does not exist.
|
267
|
-
#
|
268
|
-
def topic_by_locator(iri)
|
269
|
-
return iri if iri.is_a? Topic
|
270
|
-
return topic_by_id(iri) if iri.is_a? Integer
|
271
|
-
# @tblc ||= {}
|
272
|
-
# t = @tblc[iri]
|
273
|
-
# return t if t
|
274
|
-
t = Topic.wrap(_topic_by_locator(iri))
|
275
|
-
# @tblc[iri] = t if t
|
276
|
-
# t
|
277
|
-
end
|
278
|
-
alias :get :topic_by_locator
|
279
|
-
|
280
|
-
# Gets a topic from this topic map using its (relative) item identifier,
|
281
|
-
# its (absolute) subject identifier or its (absolute and by "=" prepended) subject locator)
|
282
|
-
#
|
283
|
-
# If there is no topic with this item identifier, subject identifier or subject locator, it is created.
|
284
|
-
# Please be aware, the creation does not work with the internal (numeric) ids.
|
285
|
-
#
|
286
|
-
def topic_by_locator!(iri)
|
287
|
-
return iri if iri.is_a? Topic
|
288
|
-
return topic_by_id(iri) if iri.is_a? Integer
|
289
|
-
# @tblc ||= {}
|
290
|
-
# t = @tblc[iri]
|
291
|
-
# return t if t
|
292
|
-
t = Topic.wrap(_topic_by_locator!(iri))
|
293
|
-
# @tblc[iri] = t
|
294
|
-
# t
|
295
|
-
end
|
296
|
-
alias :get! :topic_by_locator!
|
297
|
-
|
298
|
-
%w[topic association role name occurrence variant].each do |x|
|
299
|
-
eval <<-EOI
|
300
|
-
def #{x}_by_id(id)
|
301
|
-
#{x.camelize}.wrap(_#{x}_by_id(id))
|
302
|
-
end
|
303
|
-
alias :#{x[0].chr}id :#{x}_by_id
|
304
|
-
EOI
|
305
|
-
end
|
306
|
-
|
307
|
-
# I am not sure if this is at all correct. TMDM doesn't say a word about it
|
308
|
-
# and the approach to compare topic maps is CXTM. I chose this because we
|
309
|
-
# should (at least at the time of writing) have only one topic with a given
|
310
|
-
# base locator in RTM. If you don't like it, drop me a mail and explain why
|
311
|
-
# and propose something better.
|
312
|
-
equality [:base_locator]
|
313
|
-
end
|
314
|
-
end
|