rtm 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/activetopicmaps.rb +229 -0
- data/lib/rtm/backend/active_record/association_and_role.rb +54 -0
- data/lib/rtm/backend/active_record/locators.rb +53 -0
- data/lib/rtm/backend/active_record/name_variant_occurrence.rb +44 -0
- data/lib/rtm/backend/active_record/quaaxtm2rtm.rb +113 -0
- data/lib/rtm/backend/active_record/quaaxtm2rtmviews.rb +134 -0
- data/lib/rtm/backend/active_record/set_wrapper.rb +98 -0
- data/lib/rtm/backend/active_record/tm_construct.rb +62 -0
- data/lib/rtm/backend/active_record/tm_delegator.rb +420 -0
- data/lib/rtm/backend/active_record/tm_set_delegator.rb +195 -0
- data/lib/rtm/backend/active_record/tmdm.rb +0 -1
- data/lib/rtm/backend/active_record/topic.rb +153 -0
- data/lib/rtm/backend/active_record/topic_map.rb +285 -0
- data/lib/rtm/backend/active_record.rb +9 -1350
- data/lib/rtm/io/to_jtm.rb +5 -1
- metadata +74 -68
@@ -41,1354 +41,13 @@ end
|
|
41
41
|
module RTM::AR
|
42
42
|
require 'uri'
|
43
43
|
require 'rtm/backend/active_record/tmdm'
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
def __setobj__(obj)
|
55
|
-
@obj = obj
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.delegate(sym, options={})
|
59
|
-
to = options[:to] || sym
|
60
|
-
module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
|
61
|
-
def #{sym}(*args, &block)
|
62
|
-
__getobj__.send(:#{to}, *args, &block)
|
63
|
-
end
|
64
|
-
EOS
|
65
|
-
|
66
|
-
if options[:rw]
|
67
|
-
module_eval(<<-EOS, "(__TMDELEGATOR2__)", 1)
|
68
|
-
def #{sym}=(*args, &block)
|
69
|
-
__getobj__.send(:#{to}=, *args, &block)
|
70
|
-
#{options[:save] ? "__getobj__.save" : "" }
|
71
|
-
end
|
72
|
-
EOS
|
73
|
-
end
|
74
|
-
|
75
|
-
if options[:aka]
|
76
|
-
options[:aka] = [options[:aka]] unless options[:aka].respond_to? :each
|
77
|
-
options[:aka].each do |aka|
|
78
|
-
module_eval(<<-EOS, "(__TMDELEGATOR3__)", 1)
|
79
|
-
alias :#{aka} :#{sym}
|
80
|
-
EOS
|
81
|
-
|
82
|
-
if options[:rw]
|
83
|
-
module_eval(<<-EOS, "(__TMDELEGATOR3__)", 1)
|
84
|
-
alias :#{aka}= :#{sym}=
|
85
|
-
EOS
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def self.class_delegate(sym, options={})
|
92
|
-
module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
|
93
|
-
class << self
|
94
|
-
def #{sym}(*args, &block)
|
95
|
-
__getobj__.send(:#{sym}, *args, &block)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
EOS
|
99
|
-
|
100
|
-
if options[:aka]
|
101
|
-
options[:aka] = [options[:aka]] unless options[:aka].respond_to? :each
|
102
|
-
options[:aka].each do |aka|
|
103
|
-
module_eval(<<-EOS, "(__TMDELEGATOR2__)", 1)
|
104
|
-
class << self
|
105
|
-
alias :#{aka} :#{sym}
|
106
|
-
end
|
107
|
-
EOS
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.parent(sym, options={})
|
113
|
-
module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
|
114
|
-
def #{sym}
|
115
|
-
TopicMapConstruct.wrap(__getobj__.send(:#{sym}))
|
116
|
-
end
|
117
|
-
EOS
|
118
|
-
aka_property(sym, [:parent, :p])
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.property_set(prop, options={})
|
122
|
-
# puts "In #{self.name.to_s.ljust(20)} we have type #{options[:type].to_s.ljust(20)} for property #{prop}"
|
123
|
-
if options[:wrap]
|
124
|
-
#puts "#{self}: #{options[:type]}"
|
125
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_W__)", 1)
|
126
|
-
def #{prop}(*args)
|
127
|
-
if args.size == 0
|
128
|
-
# fetch normal
|
129
|
-
#{options[:type]}s.wrap(__getobj__.#{prop}, self, :#{options[:type]})
|
130
|
-
else
|
131
|
-
# fetch with filter
|
132
|
-
#puts args.inspect
|
133
|
-
# TODO enhance/fix condition transform code
|
134
|
-
a = {}.merge(args.first)
|
135
|
-
if a[:type] && !a[:ttype]
|
136
|
-
a[:ttype] = a[:type]
|
137
|
-
a.delete(:type)
|
138
|
-
end
|
139
|
-
a.each do |k,v|
|
140
|
-
if v.respond_to?(:__getobj__)
|
141
|
-
a[(k.to_s + "_id").to_sym] = v.id
|
142
|
-
end
|
143
|
-
end
|
144
|
-
#{options[:type]}s.wrap(__getobj__.#{prop}.find(:all, :conditions=> a), self, :#{options[:type]})
|
145
|
-
end
|
146
|
-
end
|
147
|
-
EOS
|
148
|
-
else
|
149
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_NW__)", 1)
|
150
|
-
def #{prop}
|
151
|
-
__getobj__.#{prop}
|
152
|
-
end
|
153
|
-
EOS
|
154
|
-
end
|
155
|
-
|
156
|
-
if options[:create]
|
157
|
-
# some :create_args:
|
158
|
-
#
|
159
|
-
# create_locator reference:string
|
160
|
-
# [ :name => :reference, :type => :String]
|
161
|
-
#
|
162
|
-
# create_topic_name value:String, scope:Collection
|
163
|
-
# create_topic_name value:String, type: Topic, scope:Collection
|
164
|
-
# [ {:name => :value, :type => :String}, {:name => :type, :type => :Topic, :optional => true}, {:name => :scope, :type => :Collection} ]
|
165
|
-
#
|
166
|
-
# create_occurrence value:String, type: Topic, scope:Collection
|
167
|
-
# create_occurrence resource: Locator, type: Topic, scope:Collection
|
168
|
-
# [ {:name => :value, :type => [:String, :Locator]}, {:name => :type, :type => :Topic}, {:name => :scope, :type => :Collection} ]
|
169
|
-
#
|
170
|
-
# create_association_role player:topic, type: topic
|
171
|
-
# [ {:name => :player, :type => :Topic}, {:name => :type, :type => :Topic}]
|
172
|
-
#
|
173
|
-
# create_variant value:string, :scope:Collection
|
174
|
-
# create_variant resource:locator, :scope:Collection
|
175
|
-
# [ {:name => :value, :type => [:String, :Locator]}, {:name => :scope, :type => :Collection}]
|
176
|
-
|
177
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_CREATE__)", 1)
|
178
|
-
def create_#{ options[:create]}(*args, &block)
|
179
|
-
arg_defs = #{ (options[:create_args] || nil ).inspect}
|
180
|
-
|
181
|
-
a = parse_args(args, arg_defs)
|
182
|
-
|
183
|
-
a = enhance_args_hash(a, arg_defs) if arg_defs
|
184
|
-
|
185
|
-
a = a.reject{|k,v| v.nil?}
|
186
|
-
|
187
|
-
# hack to change :type to :ttype for AR backend
|
188
|
-
# puts a.inspect unless a.is_a? Hash
|
189
|
-
if a[:type] && !a[:ttype]
|
190
|
-
a[:ttype] = a[:type]
|
191
|
-
a.delete(:type)
|
192
|
-
end
|
193
|
-
if [:Locator,:ItemIdentifier, :SubjectIdentifier, :SubjectLocator].include?(:#{options[:type]})
|
194
|
-
unless a[:topic_map]
|
195
|
-
a[:topic_map] = topic_map.__getobj__
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
if block_given?
|
200
|
-
obj = #{options[:type]}.wrap( __getobj__.#{options[:create]}s.new(a) )
|
201
|
-
yield obj
|
202
|
-
obj.save
|
203
|
-
else
|
204
|
-
obj = #{options[:type]}.wrap( __getobj__.#{options[:create]}s.create(a) )
|
205
|
-
end
|
206
|
-
obj
|
207
|
-
end
|
208
|
-
EOS
|
209
|
-
|
210
|
-
if options[:create_aka]
|
211
|
-
aka_property("create_#{options[:create]}", options[:create_aka])
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
if options[:add]
|
216
|
-
module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_ADD__)", 1)
|
217
|
-
def add_#{prop.to_s.singularize}(*args, &block)
|
218
|
-
#{prop}.add(*args, &block)
|
219
|
-
end
|
220
|
-
RUBY
|
221
|
-
aka_property("add_#{prop.to_s.singularize}", options[:aka].map{|a| "add_#{a}"})
|
222
|
-
aka_property("add_#{prop.to_s.singularize}", options[:aka].map{|a| "a#{a}"})
|
223
|
-
end
|
224
|
-
|
225
|
-
if options[:remove]
|
226
|
-
module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_REMOVE__)", 1)
|
227
|
-
def remove_#{prop.to_s.singularize}(*args, &block)
|
228
|
-
#{prop}.remove(*args, &block)
|
229
|
-
end
|
230
|
-
RUBY
|
231
|
-
aka_property("remove_#{prop.to_s.singularize}", options[:aka].map{|a| "remove_#{a}"})
|
232
|
-
aka_property("remove_#{prop.to_s.singularize}", options[:aka].map{|a| "r#{a}"})
|
233
|
-
end
|
234
|
-
|
235
|
-
# TODO: aliases for property_set.add as add_property
|
236
|
-
|
237
|
-
aka_property(prop, options[:aka]) if options[:aka]
|
238
|
-
end
|
239
|
-
|
240
|
-
private
|
241
|
-
def parse_args(args, arg_defs)
|
242
|
-
a = {}
|
243
|
-
a = args.pop if args.last.is_a? Hash
|
244
|
-
# We are finished if there are no more parameters or we have no arg_def.
|
245
|
-
# Special case: non optional parameters must have been in the Hash, just a hash is also allowed.
|
246
|
-
return a if args.size == 0 || arg_defs == nil
|
247
|
-
|
248
|
-
# we have some args
|
249
|
-
if args.size == arg_defs.size # all are given
|
250
|
-
return args2hash(a, args,arg_defs)
|
251
|
-
elsif args.size == arg_defs.reject { |d| d[:optional]}
|
252
|
-
return args2hash(a, args, arg_defs.reject {|d| d[:optional]})
|
253
|
-
end
|
254
|
-
#warn("Functions with more than one optional parameter are not supported. This will only work if the left out ones are the last.")
|
255
|
-
return args2hash(a, args,arg_defs)
|
256
|
-
end
|
257
|
-
|
258
|
-
def args2hash(a, args, arg_defs)
|
259
|
-
arg_defs.zip(args) do |argd,arg|
|
260
|
-
a[argd[:name]] = arg
|
261
|
-
end
|
262
|
-
|
263
|
-
return a
|
264
|
-
end
|
265
|
-
|
266
|
-
def enhance_args_hash(a, arg_defs)
|
267
|
-
#puts "enhance_args: #{a.inspect} ---\n#{arg_defs.inspect}"
|
268
|
-
return a if a.empty?
|
269
|
-
arg_defs.each do |argd|
|
270
|
-
#puts "enhancing #{argd[:name]}, which is a #{a[argd[:name]].class}"
|
271
|
-
if argd[:type] == :Topic
|
272
|
-
if a[argd[:name]].is_a? String
|
273
|
-
a[argd[:name]] = topic_map._topic_by_locator!(a[argd[:name]])
|
274
|
-
elsif a[argd[:name]].is_a?(RTM::Topic)
|
275
|
-
a[argd[:name]] = a[argd[:name]].__getobj__
|
276
|
-
end
|
277
|
-
end
|
278
|
-
if argd[:type] == :Locator || (argd[:type].respond_to?(:include?) && argd[:type].include?(:Locator))
|
279
|
-
a[argd[:name]] = a[argd[:name]].to_s
|
280
|
-
end
|
281
|
-
end
|
282
|
-
a
|
283
|
-
end
|
284
|
-
|
285
|
-
public
|
286
|
-
def self.property(prop, options={})
|
287
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY__)", 1)
|
288
|
-
def #{prop}
|
289
|
-
#{options[:wrap]? "#{options[:type]}.wrap":""}( __getobj__.#{prop})
|
290
|
-
end
|
291
|
-
EOS
|
292
|
-
|
293
|
-
if options[:rw]
|
294
|
-
case options[:type]
|
295
|
-
when :Topic
|
296
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
|
297
|
-
def #{prop}=(obj)
|
298
|
-
obj = topic_map.topic_by_locator!(obj) unless obj.is_a? #{options[:type]}
|
299
|
-
__getobj__.#{prop} = obj.__getobj__
|
300
|
-
__getobj__.save
|
301
|
-
end
|
302
|
-
EOS
|
303
|
-
when :TopicMap
|
304
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
|
305
|
-
def #{prop}=(obj)
|
306
|
-
obj = RTM.create obj.to_s unless obj.is_a? #{options[:type]}
|
307
|
-
__getobj__.#{prop} = obj.__getobj__
|
308
|
-
__getobj__.save
|
309
|
-
end
|
310
|
-
EOS
|
311
|
-
when :String, :Locator
|
312
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
|
313
|
-
def #{prop}=(obj)
|
314
|
-
__getobj__.#{prop} = obj.to_s
|
315
|
-
__getobj__.save
|
316
|
-
end
|
317
|
-
EOS
|
318
|
-
else
|
319
|
-
raise "Don't know how to do wrapping for #{options[:type]}"
|
320
|
-
end
|
321
|
-
|
322
|
-
end
|
323
|
-
|
324
|
-
aka_property(prop, options[:aka]) if options[:aka]
|
325
|
-
end
|
326
|
-
|
327
|
-
def self.aka_property(prop, aka)
|
328
|
-
aka = [aka].flatten
|
329
|
-
aka.each do |a|
|
330
|
-
#puts "generating alias #{a} for #{prop}"
|
331
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_AKA_PROPERTY__)", 1)
|
332
|
-
alias :#{a} :#{prop}
|
333
|
-
EOS
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
def self.index_property_set(prop, options={})
|
338
|
-
r = options[:rule]
|
339
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET__)", 1)
|
340
|
-
def direct_#{prop}_roles
|
341
|
-
# prefetch typing topics
|
342
|
-
rtype = @ips_#{prop}_rtype ||= self.topic_map.get("#{r[:role_type]}")
|
343
|
-
atype = @ips_#{prop}_atype ||= self.topic_map.get("#{r[:association_type]}")
|
344
|
-
otype = @ips_#{prop}_otype ||= self.topic_map.get("#{r[:other_role_type]}")
|
345
|
-
# return nothing if any of the typing topics does not exist
|
346
|
-
return [] unless rtype && atype && otype
|
347
|
-
# we do that only here and not earlier because some might me nil
|
348
|
-
rtype = rtype.id
|
349
|
-
atype = atype.id
|
350
|
-
otype = otype.id
|
351
|
-
self.__getobj__.roles.map{|r|
|
352
|
-
r.ttype_id != nil &&
|
353
|
-
r.ttype_id == rtype &&
|
354
|
-
r.parent.roles.size == #{r[:association_arity]} &&
|
355
|
-
r.parent != nil &&
|
356
|
-
r.parent.ttype_id == atype &&
|
357
|
-
(r2 = r.parent.roles.select{|r2| r2.ttype_id != nil &&
|
358
|
-
r2.ttype_id == otype}.first) &&
|
359
|
-
r2}.select{|r2| r2}.map{|r2| AssociationRole.wrap(r2)}
|
360
|
-
end
|
361
|
-
def direct_#{prop}
|
362
|
-
direct_#{prop}_roles.map{|r2| r2.player}.uniq
|
363
|
-
end
|
364
|
-
EOS
|
365
|
-
|
366
|
-
if r[:transitive]
|
367
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET2__)", 1)
|
368
|
-
def #{prop}
|
369
|
-
d = todo = self.direct_#{prop}
|
370
|
-
while todo.size > 0
|
371
|
-
todo = todo.map{|dt| dt.direct_#{prop}}.flatten.uniq - d
|
372
|
-
d += todo
|
373
|
-
end
|
374
|
-
d
|
375
|
-
#d2 = self.direct_#{prop}.map {|dt| dt.#{prop}}.flatten
|
376
|
-
#(d+d2).uniq
|
377
|
-
end
|
378
|
-
EOS
|
379
|
-
else
|
380
|
-
if r[:infer]
|
381
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET3__)", 1)
|
382
|
-
def #{prop}
|
383
|
-
(self.direct_#{prop} + self.#{r[:infer]}.map{|d2| d2.direct_#{prop}}).flatten.uniq
|
384
|
-
end
|
385
|
-
EOS
|
386
|
-
elsif r[:infer_other]
|
387
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET4__)", 1)
|
388
|
-
def #{prop}
|
389
|
-
d = self.direct_#{prop}
|
390
|
-
(d + d.map{|d2| d2.#{r[:infer_other]}}).flatten.uniq
|
391
|
-
end
|
392
|
-
EOS
|
393
|
-
end
|
394
|
-
end
|
395
|
-
if r[:add]
|
396
|
-
module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET5__)", 1)
|
397
|
-
def add_#{r[:add]}(t)
|
398
|
-
a = self.topic_map.create_association("#{r[:association_type]}")
|
399
|
-
a.create_role self, "#{r[:role_type]}"
|
400
|
-
a.create_role t, "#{r[:other_role_type]}"
|
401
|
-
a
|
402
|
-
# TODO add_x in index_property_set needs to trigger reload of the topics somewhere
|
403
|
-
end
|
404
|
-
def remove_#{r[:add]}(t)
|
405
|
-
direct_#{prop}_roles.select{|r| r.player == t}.each{|r| r.parent.remove}
|
406
|
-
# TODO remove_x in index_property_set needs to trigger reload of the topics somewhere
|
407
|
-
end
|
408
|
-
EOS
|
409
|
-
end
|
410
|
-
end
|
411
|
-
|
412
|
-
def self.equality(eqfields, options={})
|
413
|
-
field_condition = eqfields.map {|f| "self.#{f} == o.#{f}" }.join(" && ")
|
414
|
-
module_eval(<<-EOS, "(__AR_EQUALITY__)", 1)
|
415
|
-
def ==(o)
|
416
|
-
return false unless o
|
417
|
-
return true if #{field_condition}
|
418
|
-
false
|
419
|
-
end
|
420
|
-
EOS
|
421
|
-
end
|
422
|
-
def eql?(o)
|
423
|
-
return false unless o
|
424
|
-
return true if self.class == o.class && self.id == o.id
|
425
|
-
false
|
426
|
-
end
|
427
|
-
def hash
|
428
|
-
return self.id.hash
|
429
|
-
end
|
430
|
-
|
431
|
-
def self.wrapper_cache
|
432
|
-
module_eval(<<-EOS, "(__AR_WRAPPER_CACHE__)", 1)
|
433
|
-
def self.wrap(obj)
|
434
|
-
return nil unless obj
|
435
|
-
raise "Double wrapping" if obj.respond_to?(:__getobj__)
|
436
|
-
t = self.wrapped(obj)
|
437
|
-
if t
|
438
|
-
t.__setobj__(obj)
|
439
|
-
return t
|
440
|
-
end
|
441
|
-
self.new(obj)
|
442
|
-
end
|
443
|
-
|
444
|
-
def self.wrapped(unwrapped_obj)
|
445
|
-
@@wrapped ||= {}
|
446
|
-
return @@wrapped[unwrapped_obj.id] if unwrapped_obj.respond_to? :id
|
447
|
-
@@wrapped[unwrapped_obj]
|
448
|
-
end
|
449
|
-
def self.reset_wrapped
|
450
|
-
@@wrapped = {}
|
451
|
-
end
|
452
|
-
def initialize(*args)
|
453
|
-
super
|
454
|
-
@@wrapped ||= {}
|
455
|
-
@@wrapped[self.id]=self
|
456
|
-
end
|
457
|
-
EOS
|
458
|
-
end
|
459
|
-
|
460
|
-
alias :i :id
|
461
|
-
delegate :reload
|
462
|
-
end
|
463
|
-
|
464
|
-
class TMSetDelegator < TMDelegator
|
465
|
-
include Enumerable
|
466
|
-
# attr_reader :content_class_name
|
467
|
-
def initialize(obj,parent,type)
|
468
|
-
@obj = obj
|
469
|
-
@parent = parent
|
470
|
-
@type = type
|
471
|
-
end
|
472
|
-
|
473
|
-
# This class method wraps a Set completely while the instance method wraps one single contained object
|
474
|
-
def self.wrap(obj, parent=nil, type=nil)
|
475
|
-
return nil unless obj
|
476
|
-
raise "Double wrapping" if obj.respond_to?(:__getobj__)
|
477
|
-
self.new(obj, parent, type)
|
478
|
-
end
|
479
|
-
|
480
|
-
def add(obj)
|
481
|
-
return unless obj
|
482
|
-
|
483
|
-
old = @obj.detect { |x| x == obj } # can't that be done easier?
|
484
|
-
if old
|
485
|
-
old.merge obj
|
486
|
-
else
|
487
|
-
if obj.respond_to? :__getobj__
|
488
|
-
@obj << obj.__getobj__
|
489
|
-
else
|
490
|
-
case @type
|
491
|
-
when :Topic
|
492
|
-
@obj << @parent.topic_map.get!(obj).__getobj__
|
493
|
-
@parent.__getobj__.reload
|
494
|
-
|
495
|
-
when :ItemIdentifier
|
496
|
-
if @parent.class.name.to_s =~ /::Topic$/
|
497
|
-
tbi = @parent.topic_map._item_identifier(obj)
|
498
|
-
if tbi && tmc=tbi.topic_map_construct
|
499
|
-
if tmc.class.name =~ /::Topic$/
|
500
|
-
return @parent if tmc == @parent.__getobj__
|
501
|
-
result = Topic.wrap(tmc).merge @parent
|
502
|
-
return result
|
503
|
-
else
|
504
|
-
raise "Duplicate Item Identifier"
|
505
|
-
end
|
506
|
-
end
|
507
|
-
tbsi = @parent.topic_map._subject_identifier(obj.to_s)
|
508
|
-
if tbsi
|
509
|
-
if t=tbsi.topic
|
510
|
-
return @parent if t == @parent.__getobj__
|
511
|
-
result = Topic.wrap(t).merge @parent
|
512
|
-
# after merging, we still need to add the II
|
513
|
-
result.__getobj__.item_identifiers.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
|
514
|
-
return result
|
515
|
-
end
|
516
|
-
end
|
517
|
-
end
|
518
|
-
result = @obj << @parent.topic_map._item_identifier!(obj.to_s)
|
519
|
-
return result
|
520
|
-
|
521
|
-
when :SubjectIdentifier
|
522
|
-
# check for existing item identifier
|
523
|
-
tbi = @parent.topic_map._item_identifier(obj)
|
524
|
-
if tbi && tmc=tbi.topic_map_construct
|
525
|
-
if tmc.class.name =~ /::Topic$/
|
526
|
-
return @parent if tmc == @parent.__getobj__
|
527
|
-
result = Topic.wrap(tmc).merge @parent
|
528
|
-
# after merging, we still need to add the SI
|
529
|
-
result.__getobj__.subject_identifiers.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
|
530
|
-
return result
|
531
|
-
else
|
532
|
-
warn("This subject identifier IRI already belongs to another topic map construct (not a topic)")
|
533
|
-
end
|
534
|
-
end
|
535
|
-
# check for existing subject identifier
|
536
|
-
tbsi = @parent.topic_map._subject_identifier(obj.to_s)
|
537
|
-
if tbsi
|
538
|
-
if true && t=tbsi.topic #the single = is intentional, the "true &&" just makes netbeans not raise a warning
|
539
|
-
return @parent if t == @parent.__getobj__
|
540
|
-
result = Topic.wrap(t).merge @parent
|
541
|
-
return result
|
542
|
-
end
|
543
|
-
end
|
544
|
-
@obj.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
|
545
|
-
|
546
|
-
when :SubjectLocator
|
547
|
-
tbsl = @parent.topic_map._subject_locator(obj.to_s)
|
548
|
-
if tbsl
|
549
|
-
if true && t=tbsl.topic #the single = is intentional, the "true &&" just makes netbeans not raise a warning
|
550
|
-
return @parent if t == @parent.__getobj__
|
551
|
-
result = Topic.wrap(t).merge @parent
|
552
|
-
return result
|
553
|
-
end
|
554
|
-
end
|
555
|
-
@obj.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
|
556
|
-
|
557
|
-
end
|
558
|
-
end
|
559
|
-
end
|
560
|
-
end
|
561
|
-
alias :<< :add
|
562
|
-
|
563
|
-
def add_all(objs)
|
564
|
-
return unless objs
|
565
|
-
objs.each {|obj| add(obj)}
|
566
|
-
true
|
567
|
-
end
|
568
|
-
|
569
|
-
def each(&b)
|
570
|
-
@obj.each { |e| yield wrap(e)}
|
571
|
-
end
|
572
|
-
|
573
|
-
def size
|
574
|
-
@obj.size
|
575
|
-
end
|
576
|
-
alias :length :size
|
577
|
-
|
578
|
-
def empty?
|
579
|
-
@obj.empty?
|
580
|
-
end
|
581
|
-
|
582
|
-
def delete(obj)
|
583
|
-
obj = obj.__getobj__ if obj.respond_to? :__getobj__
|
584
|
-
case @type
|
585
|
-
when :ItemIdentifier, :SubjectIdentifier, :SubjectLocator
|
586
|
-
obj = @obj.find_by_reference(@parent.topic_map.resolve(obj.to_s)) if obj.is_a? String
|
587
|
-
end
|
588
|
-
@obj.delete(obj)
|
589
|
-
# item_identifiers: remove also from topicMap
|
590
|
-
#removed_event obj if respond_to? :removed_event
|
591
|
-
end
|
592
|
-
alias :remove :delete
|
593
|
-
|
594
|
-
def include?(obj)
|
595
|
-
return @obj.include?(obj)
|
596
|
-
#@obj.each { |e| return true if e == obj } # T#ODO support for get
|
597
|
-
#false
|
598
|
-
end
|
599
|
-
|
600
|
-
def first
|
601
|
-
wrap(@obj.entries.first)
|
602
|
-
end
|
603
|
-
def last
|
604
|
-
wrap(@obj.entries.last)
|
605
|
-
end
|
606
|
-
|
607
|
-
def to_s
|
608
|
-
"[#{@obj.entries.map { |e| wrap(e).to_s }.join(", ") }]"
|
609
|
-
end
|
610
|
-
def [](i)
|
611
|
-
wrap(@obj[i])
|
612
|
-
end
|
613
|
-
|
614
|
-
def content_class
|
615
|
-
# @content_class ||= RTM.const_get(@content_class_name)
|
616
|
-
@content_class ||= RTM.const_get("#{@content_class_name}MemImpl")
|
617
|
-
end
|
618
|
-
|
619
|
-
def find(*args)
|
620
|
-
res = @obj.find(*args)
|
621
|
-
if res.respond_to? :each
|
622
|
-
TopicMapConstructs.wrap(res)
|
623
|
-
else
|
624
|
-
TopicMapConstruct.wrap(res)
|
625
|
-
end
|
626
|
-
end
|
627
|
-
|
628
|
-
def &(other)
|
629
|
-
@obj.to_a & other.to_a
|
630
|
-
end
|
631
|
-
|
632
|
-
alias :old_method_missing :method_missing
|
633
|
-
def method_missing(method_name, *args)
|
634
|
-
if @obj.size > 0 && first.respond_to?(method_name) && (![:__getobj__, :__setobj__].include?(method_name))
|
635
|
-
a = []
|
636
|
-
inject(a) {|all,single| all << single.send(method_name, *args)}
|
637
|
-
a
|
638
|
-
else
|
639
|
-
old_method_missing(method_name, *args)
|
640
|
-
end
|
641
|
-
end
|
642
|
-
|
643
|
-
alias :old_respond_to? :respond_to?
|
644
|
-
def respond_to?(method_name)
|
645
|
-
resp = old_respond_to?(method_name)
|
646
|
-
return resp if resp # i.e. if true
|
647
|
-
return false if [:__getobj__, :__setobj__].include?(method_name)
|
648
|
-
# ... and ask first child otherwise
|
649
|
-
@obj.size > 0 && first.respond_to?(method_name)
|
650
|
-
end
|
651
|
-
|
652
|
-
# TMSetDelegator#to_a doesn't help as thought, but maybe we come back to that l8r...
|
653
|
-
#def to_a
|
654
|
-
# @obj.map {|o| wrap(o)}
|
655
|
-
#end
|
656
|
-
end
|
657
|
-
|
658
|
-
class TopicMapConstruct < TMDelegator
|
659
|
-
include RTM::TopicMapConstruct
|
660
|
-
|
661
|
-
def self.abstract_class?
|
662
|
-
self == TopicMapConstruct
|
663
|
-
end
|
664
|
-
property_set :item_identifiers, :aka => [:ii, :iid, :source_locators], :type => :ItemIdentifier, :wrap => true,
|
665
|
-
#:create => :item_identifier, :create_aka => :cii
|
666
|
-
:add => true, :remove => true
|
667
|
-
|
668
|
-
delegate :remove, :to => :destroy
|
669
|
-
|
670
|
-
delegate :id
|
671
|
-
# property_parent :parent # mmh..
|
672
|
-
|
673
|
-
property :topic_map, :rw => true, :type => :TopicMap, :wrap => true
|
674
|
-
|
675
|
-
#class_delegate :create
|
676
|
-
|
677
|
-
def self.wrap(obj)
|
678
|
-
return nil unless obj
|
679
|
-
raise "Double wrapping" if obj.respond_to?(:__getobj__)
|
680
|
-
case obj.class.name
|
681
|
-
when "RTM::AR::TMDM::Topic"
|
682
|
-
Topic.wrap(obj)
|
683
|
-
when "RTM::AR::TMDM::Variant"
|
684
|
-
Variant.wrap(obj)
|
685
|
-
when "RTM::AR::TMDM::TopicName"
|
686
|
-
TopicName.wrap(obj)
|
687
|
-
when "RTM::AR::TMDM::Occurrence"
|
688
|
-
Occurrence.wrap(obj)
|
689
|
-
when "RTM::AR::TMDM::Association"
|
690
|
-
Association.wrap(obj)
|
691
|
-
when "RTM::AR::TMDM::AssociationRole"
|
692
|
-
AssociationRole.wrap(obj)
|
693
|
-
when "RTM::AR::TMDM::TopicMap"
|
694
|
-
TopicMap.wrap(obj)
|
695
|
-
else
|
696
|
-
raise "Can't wrap object. Class for wrapping #{obj.class} unknown (object: #{obj})"
|
697
|
-
end
|
698
|
-
end
|
699
|
-
|
700
|
-
def self.find(*args)
|
701
|
-
res = RTM::AR::TMDM.const_get(name.split("::").last).find(*args)
|
702
|
-
if res.respond_to? :each
|
703
|
-
TopicMapConstructs.wrap(res)
|
704
|
-
else
|
705
|
-
TopicMapConstruct.wrap(res)
|
706
|
-
end
|
707
|
-
end
|
708
|
-
end
|
709
|
-
|
710
|
-
class Reifiable < TopicMapConstruct
|
711
|
-
include RTM::Reifiable
|
712
|
-
|
713
|
-
def self.abstract_class?
|
714
|
-
self == Reifiable
|
715
|
-
end
|
716
|
-
property :reifier, :type => :Topic, :rw => :true, :wrap => true
|
717
|
-
end
|
718
|
-
|
719
|
-
class TopicMap < Reifiable
|
720
|
-
include RTM::TopicMap
|
721
|
-
wrapper_cache
|
722
|
-
property_set :topics, :aka => :t, :type => :Topic, :wrap => true,
|
723
|
-
:create => :topic, :create_aka => :ct
|
724
|
-
|
725
|
-
property_set :associations, :aka => [:a, :assocs], :type => :Association, :wrap => true,
|
726
|
-
:create => :association, :create_aka => :ca,
|
727
|
-
:create_args => [{:name => :type, :type => :Topic}]
|
728
|
-
|
729
|
-
|
730
|
-
delegate :base_locator
|
731
|
-
|
732
|
-
property_set :association_types, :aka => :at, :type => :Topic, :wrap => true
|
733
|
-
property_set :association_role_types, :aka => [:role_types,:art,:rt], :type => :Topic, :wrap => true
|
734
|
-
property_set :topic_name_types, :aka => [:name_types,:tnt,:nt], :type => :Topic, :wrap => true
|
735
|
-
property_set :occurrence_types, :aka => :ot, :type => :Topic, :wrap => true
|
736
|
-
|
737
|
-
property_set :topic_names, :aka => [:names,:n], :type => :TopicName, :wrap => :true
|
738
|
-
property_set :occurrences, :aka => :o, :type => :Occurrence, :wrap => :true
|
739
|
-
property_set :association_roles, :aka => [:roles, :r], :type => :AssociationRole, :wrap => :true
|
740
|
-
|
741
|
-
def types
|
742
|
-
topics.select{|t| t.instances.size > 0}
|
743
|
-
end
|
744
|
-
alias :topic_types :types
|
745
|
-
def fast_types
|
746
|
-
|
747
|
-
end
|
748
|
-
|
749
|
-
# This fetches all topics who have no topic-instances (but they might be types for associations etc.).
|
750
|
-
# See indivduals
|
751
|
-
def non_types
|
752
|
-
topics.select{|t| t.instances.size == 0}
|
753
|
-
end
|
754
|
-
|
755
|
-
# This fetches all topics which are not type for something else (including topics, associations etc.).
|
756
|
-
# See non_types
|
757
|
-
def individuals
|
758
|
-
non_types.select{|t| t.associations_typed.size==0 && t.roles_typed.size==0 && t.names_typed.size==0 && t.occurrences_typed.size==0}
|
759
|
-
end
|
760
|
-
def instances
|
761
|
-
topics.select{|t| t.types.size > 0}
|
762
|
-
end
|
763
|
-
def non_instances
|
764
|
-
topics.reject{|t| t.types.size > 0}
|
765
|
-
end
|
766
|
-
def internal_occurrences
|
767
|
-
occurrences.select{|o| o.datatype != RTM::PSI[:IRI]}
|
768
|
-
end
|
769
|
-
def external_occurrences
|
770
|
-
occurrences.select{|o| o.datatype == RTM::PSI[:IRI]}
|
771
|
-
end
|
772
|
-
|
773
|
-
def self.create(base_locator, params={})
|
774
|
-
tm = self.wrap(TMDM::TopicMap.find_or_create_by_base_locator(base_locator))
|
775
|
-
yield tm if block_given?
|
776
|
-
tm
|
777
|
-
end
|
778
|
-
|
779
|
-
def self.topic_maps
|
780
|
-
TopicMaps.wrap(TMDM::TopicMap.find(:all))
|
781
|
-
end
|
782
|
-
|
783
|
-
# Resolves an IRI or fragment relative to the base_locator of this topic_map or an optional given alternative_base_locator
|
784
|
-
#
|
785
|
-
# Absolute IRIs are taken as is.
|
786
|
-
#
|
787
|
-
# Relative IRIs:
|
788
|
-
# If the base_locator is a directory (ends with "/") it is appended like a file, i.e. directly
|
789
|
-
# If the base_locator is a file it is appended as a fragment (with # in between)
|
790
|
-
def resolve(obj,alternative_base_locator=nil)
|
791
|
-
uri = obj.to_s
|
792
|
-
# TODO uri = URI.decode(obj.to_s) # this InvalidURIError somethimes :(
|
793
|
-
begin
|
794
|
-
uri_uri = URI.parse(uri)
|
795
|
-
rescue URI::InvalidComponentError => ice
|
796
|
-
warn "Catched an URI::InvalidComponentError for URI: #{uri}, message was \"#{ice.message}\"\n" +
|
797
|
-
"Will continue using the UNRESOLVED IRI, claiming it is absolute."
|
798
|
-
return uri
|
799
|
-
end
|
800
|
-
if uri_uri.absolute?
|
801
|
-
return uri_uri.to_s
|
802
|
-
end
|
803
|
-
|
804
|
-
uri = uri[1..-1] if uri[0] == "#"[0]
|
805
|
-
bl = alternative_base_locator || base_locator
|
806
|
-
if bl[-1,1] == "/"
|
807
|
-
return bl + uri
|
808
|
-
else
|
809
|
-
return bl + "#" + uri
|
810
|
-
end
|
811
|
-
end
|
812
|
-
|
813
|
-
#private
|
814
|
-
|
815
|
-
def _item_identifier(iid)
|
816
|
-
__getobj__.locators.find_by_reference(resolve(iid)) # doesn't work :( --> , :include => [ :topic_map_construct ])
|
817
|
-
end
|
818
|
-
def _item_identifier!(iid)
|
819
|
-
__getobj__.locators.find_or_create_by_reference(resolve(iid)) # doesn't work :( --> , :include => [ :topic_map_construct ])
|
820
|
-
end
|
821
|
-
|
822
|
-
def _subject_identifier(iid)
|
823
|
-
__getobj__.subject_identifiers.find_by_reference(iid, :include => :topic)
|
824
|
-
end
|
825
|
-
def _subject_identifier!(iid)
|
826
|
-
__getobj__.subject_identifiers.find_or_create_by_reference(iid, :include => :topic)
|
827
|
-
end
|
828
|
-
|
829
|
-
def _subject_locator(iid)
|
830
|
-
__getobj__.subject_locators.find_by_reference(iid, :include => :topic)
|
831
|
-
end
|
832
|
-
def _subject_locator!(iid)
|
833
|
-
__getobj__.subject_locators.find_or_create_by_reference(iid, :include => :topic)
|
834
|
-
end
|
835
|
-
|
836
|
-
|
837
|
-
# internal helper for by_item_identifier, doesn't wrap result
|
838
|
-
def _by_item_identifier(iid)
|
839
|
-
ii = __getobj__.locators.find_by_reference(resolve(iid)) #, :include => [ :topic_map_construct ])
|
840
|
-
return ii.topic_map_construct if ii
|
841
|
-
nil
|
842
|
-
end
|
843
|
-
def _topic_by_item_identifier(iid)
|
844
|
-
t = _by_item_identifier(iid)
|
845
|
-
return nil unless t
|
846
|
-
return t if t.class.name =~ /::Topic$/ # only return something if the thing is a topic
|
847
|
-
nil
|
848
|
-
end
|
849
|
-
|
850
|
-
# internal helper for topic_by_item_identifier!, doesn't wrap result
|
851
|
-
def _topic_by_item_identifier!(iid)
|
852
|
-
ii = __getobj__.locators.find_or_create_by_reference(resolve(iid))#, :include => [ :topic_map_construct ])
|
853
|
-
return ii.topic_map_construct if ii.topic_map_construct && ii.topic_map_construct_type =~ /::Topic$/
|
854
|
-
top2 = _topic_by_subject_identifier(resolve(iid))
|
855
|
-
if top2
|
856
|
-
ii.topic_map_construct = top2
|
857
|
-
else
|
858
|
-
ii.topic_map_construct = create_topic.__getobj__
|
859
|
-
end
|
860
|
-
ii.save
|
861
|
-
ii.topic_map_construct
|
862
|
-
end
|
863
|
-
# internal helper for topic_by_subject_identifier, doesn't wrap result
|
864
|
-
def _topic_by_subject_identifier(sid)
|
865
|
-
si = __getobj__.subject_identifiers.find_by_reference(sid, :include => [ :topic ])
|
866
|
-
return si.topic if si
|
867
|
-
nil
|
868
|
-
end
|
869
|
-
# internal helper for topic_by_subject_identifier!, doesn't wrap result
|
870
|
-
def _topic_by_subject_identifier!(sid)
|
871
|
-
si = __getobj__.subject_identifiers.find_or_create_by_reference(sid, :include => [ :topic ])
|
872
|
-
return si.topic if si.topic
|
873
|
-
begin
|
874
|
-
top2 = _by_item_identifier(sid)
|
875
|
-
rescue ActiveRecord::RecordNotFound => rnf
|
876
|
-
si.topic = create_topic.__getobj__
|
877
|
-
else
|
878
|
-
if top2 && top2.respond_to?(:subject_identifiers)
|
879
|
-
si.topic = top2
|
880
|
-
else
|
881
|
-
si.topic = create_topic.__getobj__
|
882
|
-
end
|
883
|
-
end
|
884
|
-
si.save
|
885
|
-
si.topic
|
886
|
-
end
|
887
|
-
|
888
|
-
# internal helper for topic_by_subject_locator, doesn't wrap result
|
889
|
-
def _topic_by_subject_locator(slo)
|
890
|
-
sl = __getobj__.subject_locators.find_by_reference(RTM::LocatorHelpers.slo2iri(slo)) #, :include => [ :topic ])
|
891
|
-
return sl.topic if sl
|
892
|
-
nil
|
893
|
-
end
|
894
|
-
|
895
|
-
# internal helper for topic_by_subject_locator!, doesn't wrap result
|
896
|
-
def _topic_by_subject_locator!(slo)
|
897
|
-
sl = __getobj__.subject_locators.find_or_create_by_reference(RTM::LocatorHelpers.slo2iri(slo), :include => [ :topic ])
|
898
|
-
return sl.topic if sl.topic
|
899
|
-
sl.topic = create_topic.__getobj__
|
900
|
-
sl.save
|
901
|
-
sl.topic
|
902
|
-
end
|
903
|
-
def _topic_by_locator(iri)
|
904
|
-
raise "Locator may not be nil" unless iri
|
905
|
-
if RTM::LocatorHelpers.is_a_slo?(iri)
|
906
|
-
_topic_by_subject_locator(iri)
|
907
|
-
elsif URI.parse(iri).absolute?
|
908
|
-
_topic_by_subject_identifier(iri)
|
909
|
-
else
|
910
|
-
_topic_by_item_identifier(iri)
|
911
|
-
end
|
912
|
-
end
|
913
|
-
|
914
|
-
def _topic_by_locator!(iri)
|
915
|
-
raise "Locator may not be nil" unless iri
|
916
|
-
if RTM::LocatorHelpers.is_a_slo?(iri)
|
917
|
-
_topic_by_subject_locator!(iri)
|
918
|
-
elsif URI.parse(iri).absolute?
|
919
|
-
_topic_by_subject_identifier!(iri)
|
920
|
-
else
|
921
|
-
_topic_by_item_identifier!(iri)
|
922
|
-
end
|
923
|
-
end
|
924
|
-
|
925
|
-
public
|
926
|
-
# returns an item identifier from the topic_map if it exists
|
927
|
-
def item_identifier(iid)
|
928
|
-
ItemIdentifier.wrap(_item_identifier(iid))
|
929
|
-
end
|
930
|
-
# returns an item identififier from the topic_map or creates it if it doesn't exist
|
931
|
-
def item_identifier!(iid)
|
932
|
-
ItemIdentifier.wrap(_item_identifier!(iid))
|
933
|
-
end
|
934
|
-
alias :create_locator :item_identifier!
|
935
|
-
# Returns a topic map construct by it's item identifier or nil if not found.
|
936
|
-
# It's the equivalent to TMAPI's TopicMapObjectIndex.getTopicMapObjectBySourceLocator
|
937
|
-
def by_item_identifier(iid)
|
938
|
-
TopicMapConstruct.wrap(_by_item_identifier(iid))
|
939
|
-
end
|
940
|
-
# Returns a topic by it's item identifier. The topic will be created if not found.
|
941
|
-
def topic_by_item_identifier!(iid)
|
942
|
-
Topic.wrap(_topic_by_item_identifier!(iid))
|
943
|
-
end
|
944
|
-
# Returns a topic by it's subject identifier or nil if not found.
|
945
|
-
# It's the equivalent to TMAPI's TopicsIndex.getTopicBySubjectIdentifier.
|
946
|
-
def topic_by_subject_identifier(sid)
|
947
|
-
Topic.wrap(_topic_by_subject_identifier(sid))
|
948
|
-
end
|
949
|
-
# returns a topic by it's subject identifier. The topic will be created if not found.
|
950
|
-
def topic_by_subject_identifier!(sid)
|
951
|
-
Topic.wrap(_topic_by_subject_identifier!(sid))
|
952
|
-
end
|
953
|
-
# Returns a topic by it's subject locator or nil if not found.
|
954
|
-
# It's the equivalent to TMAPI's TopicsIndex.getTopicBySubjectLocator
|
955
|
-
def topic_by_subject_locator(slo)
|
956
|
-
Topic.wrap(_topic_by_subject_locator(slo))
|
957
|
-
end
|
958
|
-
# returns a topic by it's subject locator. The topic will be created if not found.
|
959
|
-
def topic_by_subject_locator!(slo)
|
960
|
-
Topic.wrap(_topic_by_subject_locator!(slo))
|
961
|
-
end
|
962
|
-
|
963
|
-
# Gets a topic from this topic map using its (relative) item identifier,
|
964
|
-
# its (absolute) subject identifier or its (absolute and by "=" prepended) subject locator)
|
965
|
-
#
|
966
|
-
# Returns nil if the Topic does not exist.
|
967
|
-
#
|
968
|
-
def topic_by_locator(iri)
|
969
|
-
return iri if iri.is_a? Topic
|
970
|
-
# @tblc ||= {}
|
971
|
-
# t = @tblc[iri]
|
972
|
-
# return t if t
|
973
|
-
t = Topic.wrap(_topic_by_locator(iri))
|
974
|
-
# @tblc[iri] = t if t
|
975
|
-
# t
|
976
|
-
end
|
977
|
-
alias :get :topic_by_locator
|
978
|
-
|
979
|
-
# Gets a topic from this topic map using its (relative) item identifier,
|
980
|
-
# its (absolute) subject identifier or its (absolute and by "=" prepended) subject locator)
|
981
|
-
#
|
982
|
-
# If there is no topic with this item identifier, subject identifier or subject locator, it is created.
|
983
|
-
#
|
984
|
-
def topic_by_locator!(iri)
|
985
|
-
return iri if iri.is_a? Topic
|
986
|
-
# @tblc ||= {}
|
987
|
-
# t = @tblc[iri]
|
988
|
-
# return t if t
|
989
|
-
t = Topic.wrap(_topic_by_locator!(iri))
|
990
|
-
# @tblc[iri] = t
|
991
|
-
# t
|
992
|
-
end
|
993
|
-
alias :get! :topic_by_locator!
|
994
|
-
|
995
|
-
# I am not sure if this is at all correct. TMDM doesn't say a word about it
|
996
|
-
# and the approach to compare topic maps is CXTM. I chose this because we
|
997
|
-
# should (at least at the time of writing) have only one topic with a given
|
998
|
-
# base locator in RTM. If you don't like it, drop me a mail and explain why
|
999
|
-
# and propose something better.
|
1000
|
-
equality [:base_locator]
|
1001
|
-
end
|
1002
|
-
|
1003
|
-
class Topic < TopicMapConstruct
|
1004
|
-
include RTM::Topic
|
1005
|
-
wrapper_cache
|
1006
|
-
|
1007
|
-
parent :topic_map
|
1008
|
-
property_set :subject_identifiers, :aka => [:si,:sid], :type => :SubjectIdentifier, :wrap => true,
|
1009
|
-
#:create => :subject_identifier, :create_aka => [:csi,:csid],
|
1010
|
-
#:create_args => [{:name => :reference, :type => :String}]
|
1011
|
-
:add => true, :remove => true
|
1012
|
-
property_set :subject_locators, :aka => [:sl,:slo], :type => :SubjectLocator, :wrap => true,
|
1013
|
-
#:create => :subject_locator, :create_aka => [:csl, :cslo],
|
1014
|
-
#:create_args => [{:name => :reference, :type => :String}]
|
1015
|
-
:add => true, :remove => true
|
1016
|
-
|
1017
|
-
property :reified, :computable => true, :type => :Reifiable, :wrap => true
|
1018
|
-
|
1019
|
-
property_set :topic_names, :aka => [:n, :names], :type => :TopicName, :wrap => true,
|
1020
|
-
:create => :topic_name, :create_aka => [:create_name, :cn],
|
1021
|
-
:create_args => [ {:name => :value, :type => :String}, {:name => :type, :type => :Topic, :optional => true}, {:name => :scope, :type => :Collection} ]
|
1022
|
-
|
1023
|
-
property_set :occurrences, :aka => :o, :type => :Occurrence, :wrap => true,
|
1024
|
-
:create => :occurrence, :create_aka => :co,
|
1025
|
-
:create_args => [ {:name => :value, :type => [:String, :Locator]}, {:name => :type, :type => :Topic}, {:name => :scope, :type => :Collection} ]
|
1026
|
-
|
1027
|
-
def internal_occurrences
|
1028
|
-
occurrences.select{|o| o.datatype != RTM::PSI[:IRI]}
|
1029
|
-
end
|
1030
|
-
def external_occurrences
|
1031
|
-
occurrences.select{|o| o.datatype == RTM::PSI[:IRI]}
|
1032
|
-
end
|
1033
|
-
|
1034
|
-
property_set :roles, :aka => [:r, :roles_played, :association_roles], :computable => true, :type => :AssociationRole, :wrap => true
|
1035
|
-
|
1036
|
-
property_set :associations, :aka => [:a, :associations_played], :type => :Association, :wrap => true
|
1037
|
-
|
1038
|
-
property_set :scoped_objects, :type => :TopicMapConstruct, :wrap => true
|
1039
|
-
property_set :scoped_associations, :type => :Association, :wrap => true
|
1040
|
-
property_set :scoped_topic_names, :aka => :scoped_names, :type => :TopicName, :wrap => true
|
1041
|
-
property_set :scoped_variants, :type => :Variant, :wrap => true
|
1042
|
-
property_set :scoped_occurrences, :type => :Occurrence, :wrap => true
|
1043
|
-
|
1044
|
-
property_set :associations_typed, :aka => :at, :type => :Association, :wrap => true
|
1045
|
-
property_set :association_roles_typed, :aka => [:roles_typed,:art,:rt], :type => :AssociationRole, :wrap => true
|
1046
|
-
property_set :topic_names_typed, :aka => [:names_typed,:tnt,:nt], :type => :TopicName, :wrap => true
|
1047
|
-
property_set :occurrences_typed, :aka => :ot, :type => :Occurrence, :wrap => true
|
1048
|
-
|
1049
|
-
# maybe these pairs could be declared each with a single statement and a reversible option
|
1050
|
-
index_property_set :types, :type => :Topic, :rule => {
|
1051
|
-
:transitive => false,
|
1052
|
-
:role_type => RTM::PSI[:instance],
|
1053
|
-
:association_type => RTM::PSI[:type_instance],
|
1054
|
-
:association_arity => 2,
|
1055
|
-
:other_role_type => RTM::PSI[:type],
|
1056
|
-
:infer_other => :supertypes,
|
1057
|
-
:add => :type,
|
1058
|
-
}
|
1059
|
-
index_property_set :instances, :type => :Topic, :rule => {
|
1060
|
-
:transitive => false,
|
1061
|
-
:role_type => RTM::PSI[:type],
|
1062
|
-
:association_type => RTM::PSI[:type_instance],
|
1063
|
-
:association_arity => 2,
|
1064
|
-
:other_role_type => RTM::PSI[:instance],
|
1065
|
-
:infer => :subtypes,
|
1066
|
-
:add => :instance,
|
1067
|
-
}
|
1068
|
-
index_property_set :supertypes, :type => :Topic, :rule => {
|
1069
|
-
:transitive => true,
|
1070
|
-
:role_type => RTM::PSI[:subtype],
|
1071
|
-
:association_type => RTM::PSI[:supertype_subtype],
|
1072
|
-
:association_arity => 2,
|
1073
|
-
:other_role_type => RTM::PSI[:supertype],
|
1074
|
-
:add => :supertype,
|
1075
|
-
}
|
1076
|
-
index_property_set :subtypes, :type => :Topic, :rule => {
|
1077
|
-
:transitive => true,
|
1078
|
-
:role_type => RTM::PSI[:supertype],
|
1079
|
-
:association_type => RTM::PSI[:supertype_subtype],
|
1080
|
-
:association_arity => 2,
|
1081
|
-
:other_role_type => RTM::PSI[:subtype],
|
1082
|
-
:add => :subtype,
|
1083
|
-
}
|
1084
|
-
|
1085
|
-
def [](topicref)
|
1086
|
-
topicref =~ /^(-\s*)?(.+)?$/
|
1087
|
-
if $1
|
1088
|
-
nametype = $2 || RTM::PSI[:name_type]
|
1089
|
-
names.select{|n| n.type == topic_map.get(nametype)}
|
1090
|
-
else
|
1091
|
-
raise "No occurrence type given" unless $2 and !$2.empty?
|
1092
|
-
occurrences.select{|o| o.type == topic_map.get($2)}
|
1093
|
-
end
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
def []=(topicref, value)
|
1097
|
-
topicref =~ /^(-\s*)?(.+)?$/
|
1098
|
-
if $1
|
1099
|
-
nametype = $2 || topic_map.get!(RTM::PSI[:name_type])
|
1100
|
-
n = create_name(value, nametype)
|
1101
|
-
n
|
1102
|
-
else
|
1103
|
-
raise "No occurrence type given" unless $2
|
1104
|
-
o = create_occurrence(value, $2)
|
1105
|
-
o
|
1106
|
-
end
|
1107
|
-
end
|
1108
|
-
|
1109
|
-
# class:Topic equality, http://www.isotopicmaps.org/sam/sam-model/#d0e1029
|
1110
|
-
#
|
1111
|
-
# This method is all crap. These ActiveRecord Arrays can't be intersected,
|
1112
|
-
# so I map the identifiers to their reference which seems long winded.
|
1113
|
-
# Still I find it better than using their ID in the long.
|
1114
|
-
#
|
1115
|
-
def ==(o)
|
1116
|
-
return false unless o
|
1117
|
-
# Two topic items are equal if they have:
|
1118
|
-
# * at least one equal string in their [subject identifiers] properties,
|
1119
|
-
# -> test if intersection are > 0
|
1120
|
-
my_si = self.subject_identifiers.map{|si| si.reference}
|
1121
|
-
ot_si = o.subject_identifiers.map{|si| si.reference}
|
1122
|
-
return true if ( my_si & ot_si).size > 0
|
1123
|
-
|
1124
|
-
# * at least one equal string in their [item identifiers] properties,
|
1125
|
-
my_ii = self.item_identifiers.map{|ii| ii.reference}
|
1126
|
-
ot_ii = o.item_identifiers.map{|ii| ii.reference}
|
1127
|
-
return true if (my_ii & ot_ii).size > 0
|
1128
|
-
|
1129
|
-
# * at least one equal string in their [subject locators] properties,
|
1130
|
-
my_sl = self.subject_locators.map{|sl| sl.reference}
|
1131
|
-
ot_sl = o.subject_locators.map{|sl| sl.reference}
|
1132
|
-
return true if (my_sl & ot_sl).size > 0
|
1133
|
-
|
1134
|
-
# * an equal string in the [subject identifiers] property of the one topic item and the [item identifiers] property of the other, or
|
1135
|
-
return true if (my_si & ot_ii).size > 0
|
1136
|
-
return true if (my_ii & ot_si).size > 0
|
1137
|
-
|
1138
|
-
# * the same information item in their [reified] properties.
|
1139
|
-
return true if self.reified != nil && o.reified != nil && (self.reified == o.reified)
|
1140
|
-
# ... otherwise
|
1141
|
-
false
|
1142
|
-
end
|
1143
|
-
end
|
1144
|
-
|
1145
|
-
class Association < Reifiable
|
1146
|
-
include RTM::Association
|
1147
|
-
wrapper_cache
|
1148
|
-
|
1149
|
-
parent :topic_map
|
1150
|
-
property :type, :aka => [:ty,:t], :rw => true, :type => :Topic, :wrap => true
|
1151
|
-
property_set :scope, :type => :Topic, :wrap => true
|
1152
|
-
property_set :roles, :aka => [:r, :association_roles], :type => :AssociationRole, :wrap => true,
|
1153
|
-
:create => :role, :create_aka => [:cr, :create_association_role],
|
1154
|
-
:create_args => [ {:name => :player, :type => :Topic}, {:name => :type, :type => :Topic}]
|
1155
|
-
|
1156
|
-
property_set :role_players, :aka => [:players, :rp, :pl], :type => :Topic, :wrap => true
|
1157
|
-
property_set :role_types, :aka => [:types, :rt], :type => :Topic, :wrap => true
|
1158
|
-
|
1159
|
-
equality [:scope, :type, :roles]
|
1160
|
-
end
|
1161
|
-
|
1162
|
-
class AssociationRole < Reifiable
|
1163
|
-
include RTM::AssociationRole
|
1164
|
-
wrapper_cache
|
1165
|
-
|
1166
|
-
parent :association
|
1167
|
-
property :player, :aka => [:pl,:topic], :rw => true, :type => :Topic, :wrap => true
|
1168
|
-
property :type, :aka => [:ty,:t], :rw => true, :type => :Topic, :wrap => true
|
1169
|
-
|
1170
|
-
def counterparts
|
1171
|
-
self.parent.roles.reject{|r| r.id==self.id}
|
1172
|
-
end
|
1173
|
-
def counterplayers
|
1174
|
-
self.counterparts.map{|r| r.player}
|
1175
|
-
end
|
1176
|
-
def counterpart
|
1177
|
-
n = self.parent.roles.size
|
1178
|
-
raise "Association must be unary or binary to use counterpart method. Please use counterparts for n-ary associations." if n > 2
|
1179
|
-
return nil if n == 1
|
1180
|
-
self.parent.roles.reject{|r| r.id==self.id}.first
|
1181
|
-
end
|
1182
|
-
def counterplayer
|
1183
|
-
n = self.parent.roles.size
|
1184
|
-
raise "Association must be unary or binary to use counterplayer method. Please use counterplayers for n-ary associations." if n > 2
|
1185
|
-
return nil if n == 1
|
1186
|
-
self.parent.roles.reject{|r| r.id==self.id}.first.player
|
1187
|
-
end
|
1188
|
-
def peers
|
1189
|
-
self.counterpart.player.roles.select{|r| r.type == cp.type}.counterpart
|
1190
|
-
end
|
1191
|
-
def peerplayers
|
1192
|
-
self.peers.map{|r| r.player}
|
1193
|
-
end
|
1194
|
-
|
1195
|
-
equality [:type, :player, :parent]
|
1196
|
-
end
|
1197
|
-
|
1198
|
-
class TopicName < Reifiable
|
1199
|
-
include RTM::TopicName
|
1200
|
-
wrapper_cache
|
1201
|
-
|
1202
|
-
parent :topic
|
1203
|
-
property :type, :aka => [:ty,:t], :rw => true, :type => :Topic, :wrap => true
|
1204
|
-
property_set :scope, :type => :Topic, :wrap => true
|
1205
|
-
|
1206
|
-
property_set :variants, :aka => :v, :type => :Variant, :wrap => true,
|
1207
|
-
:create => :variant, :create_aka => :cv,
|
1208
|
-
:create_args => [ {:name => :value, :type => [:String, :Locator]}, {:name => :scope, :type => :Collection}]
|
1209
|
-
|
1210
|
-
property :value, :rw => true, :type => :String
|
1211
|
-
|
1212
|
-
equality [:value, :type, :scope, :parent]
|
1213
|
-
end
|
1214
|
-
|
1215
|
-
class Occurrence < Reifiable
|
1216
|
-
include RTM::Occurrence
|
1217
|
-
wrapper_cache
|
1218
|
-
|
1219
|
-
parent :topic
|
1220
|
-
property :value, :rw => true, :type => :String
|
1221
|
-
property :datatype, :rw => true, :type => :String
|
1222
|
-
|
1223
|
-
property_set :scope, :type => :Topic, :wrap => true
|
1224
|
-
property :type, :aka => [:ty,:t], :rw => true, :type => :Topic, :wrap => true
|
1225
|
-
|
1226
|
-
equality [:value, :datatype, :scope, :type, :parent]
|
1227
|
-
end
|
1228
|
-
|
1229
|
-
class Variant < Reifiable
|
1230
|
-
include RTM::Variant
|
1231
|
-
wrapper_cache
|
1232
|
-
|
1233
|
-
parent :topic_name, :aka => :name
|
1234
|
-
property :value, :rw => true, :type => :String
|
1235
|
-
property :datatype, :rw => true, :type => :Locator #, :wrap => true
|
1236
|
-
property_set :scope, :type => :Topic, :wrap => true
|
1237
|
-
|
1238
|
-
equality [:value, :datatype, :scope, :parent]
|
1239
|
-
|
1240
|
-
end
|
1241
|
-
|
1242
|
-
class Locator < TMDelegator
|
1243
|
-
include RTM::Locator
|
1244
|
-
|
1245
|
-
delegate :+
|
1246
|
-
delegate :-
|
1247
|
-
#delegate :==
|
1248
|
-
delegate :id
|
1249
|
-
|
1250
|
-
delegate :get
|
1251
|
-
delegate :hash
|
1252
|
-
delegate :resolve_relative
|
1253
|
-
delegate :to_s, :to => :reference
|
1254
|
-
delegate :to_uri
|
1255
|
-
delegate :uri
|
1256
|
-
delegate :reference, :rw => true, :save => true
|
1257
|
-
alias :value :reference
|
1258
|
-
alias :value= :reference=
|
1259
|
-
|
1260
|
-
equality [:reference]
|
1261
|
-
|
1262
|
-
def self.wrap(obj)
|
1263
|
-
return nil unless obj
|
1264
|
-
raise "Double wrapping" if obj.respond_to?(:__getobj__)
|
1265
|
-
case obj.class.name
|
1266
|
-
when "RTM::AR::TMDM::ItemIdentifier"
|
1267
|
-
ItemIdentifier.wrap(obj)
|
1268
|
-
when "RTM::AR::TMDM::SubjectIdentifier"
|
1269
|
-
SubjectIdentifier.wrap(obj)
|
1270
|
-
when "RTM::AR::TMDM::SubjectLocator"
|
1271
|
-
SubjectLocator.wrap(obj)
|
1272
|
-
else
|
1273
|
-
raise "Can't wrap object. Class for wrapping #{obj.class} unknown (object: #{obj})"
|
1274
|
-
end
|
1275
|
-
end
|
1276
|
-
|
1277
|
-
|
1278
|
-
end
|
1279
|
-
|
1280
|
-
|
1281
|
-
class ItemIdentifier < Locator
|
1282
|
-
include RTM::ItemIdentifier
|
1283
|
-
wrapper_cache
|
1284
|
-
property :topic_map_construct, :type => :TopicMapConstruct, :wrap => true
|
1285
|
-
end
|
1286
|
-
class SubjectIdentifier < Locator
|
1287
|
-
include RTM::SubjectIdentifier
|
1288
|
-
wrapper_cache
|
1289
|
-
property :topic, :type => :Topic, :wrap => true
|
1290
|
-
end
|
1291
|
-
class SubjectLocator < Locator
|
1292
|
-
include RTM::SubjectLocator
|
1293
|
-
wrapper_cache
|
1294
|
-
property :topic, :type => :Topic, :wrap => true
|
1295
|
-
end
|
1296
|
-
class Topics < TMSetDelegator
|
1297
|
-
def wrap(obj)
|
1298
|
-
Topic.wrap(obj)
|
1299
|
-
end
|
1300
|
-
end
|
1301
|
-
class TopicMapConstructs < TMSetDelegator
|
1302
|
-
def wrap(obj)
|
1303
|
-
TopicMapConstruct.wrap(obj)
|
1304
|
-
end
|
1305
|
-
end
|
1306
|
-
class Associations < TMSetDelegator
|
1307
|
-
def wrap(obj)
|
1308
|
-
Association.wrap(obj)
|
1309
|
-
end
|
1310
|
-
end
|
1311
|
-
class TopicNames < TMSetDelegator
|
1312
|
-
def wrap(obj)
|
1313
|
-
TopicName.wrap(obj)
|
1314
|
-
end
|
1315
|
-
end
|
1316
|
-
class Occurrences < TMSetDelegator
|
1317
|
-
def wrap(obj)
|
1318
|
-
Occurrence.wrap(obj)
|
1319
|
-
end
|
1320
|
-
end
|
1321
|
-
class AssociationRoles < TMSetDelegator
|
1322
|
-
def wrap(obj)
|
1323
|
-
AssociationRole.wrap(obj)
|
1324
|
-
end
|
1325
|
-
end
|
1326
|
-
class Reifiables < TMSetDelegator
|
1327
|
-
def wrap(obj)
|
1328
|
-
TopicMapConstruct.wrap(obj)
|
1329
|
-
end
|
1330
|
-
end
|
1331
|
-
class Variants < TMSetDelegator
|
1332
|
-
def wrap(obj)
|
1333
|
-
Variant.wrap(obj)
|
1334
|
-
end
|
1335
|
-
end
|
1336
|
-
class TopicMaps < TMSetDelegator
|
1337
|
-
def [](obj)
|
1338
|
-
# support for getting topic_map by base_locator
|
1339
|
-
if obj.is_a? String
|
1340
|
-
# return wrap(__getobj__.find { |tm| tm.base_locator == obj })
|
1341
|
-
return wrap(TMDM::TopicMap.find_by_base_locator(obj))
|
1342
|
-
end
|
1343
|
-
# normal index retrieval
|
1344
|
-
super
|
1345
|
-
end
|
1346
|
-
|
1347
|
-
def wrap(obj)
|
1348
|
-
TopicMap.wrap(obj)
|
1349
|
-
end
|
1350
|
-
end
|
1351
|
-
class Locators < TMSetDelegator
|
1352
|
-
def [](obj)
|
1353
|
-
# support for getting locators by reference
|
1354
|
-
if obj.is_a? String
|
1355
|
-
return wrap(__getobj__.find { |tm| tm.reference == obj })
|
1356
|
-
end
|
1357
|
-
# normal index retrieval
|
1358
|
-
super
|
1359
|
-
end
|
1360
|
-
def wrap(obj)
|
1361
|
-
return nil unless obj
|
1362
|
-
return obj if obj.respond_to? :__getobj__
|
1363
|
-
case obj.class.name
|
1364
|
-
when "RTM::AR::TMDM::ItemIdentifier"
|
1365
|
-
ItemIdentifier.wrap(obj)
|
1366
|
-
when "RTM::AR::TMDM::SubjectIdentifier"
|
1367
|
-
SubjectIdentifier.wrap(obj)
|
1368
|
-
when "RTM::AR::TMDM::SubjectLocator"
|
1369
|
-
SubjectLocator.wrap(obj)
|
1370
|
-
else
|
1371
|
-
Locator.wrap(obj)
|
1372
|
-
end
|
1373
|
-
end
|
1374
|
-
end
|
1375
|
-
|
1376
|
-
class ItemIdentifiers < Locators
|
1377
|
-
def wrap(obj)
|
1378
|
-
ItemIdentifier.wrap(obj)
|
1379
|
-
end
|
1380
|
-
end
|
1381
|
-
class SubjectIdentifiers < Locators
|
1382
|
-
def wrap(obj)
|
1383
|
-
SubjectIdentifier.wrap(obj)
|
1384
|
-
end
|
1385
|
-
|
1386
|
-
end
|
1387
|
-
class SubjectLocators < Locators
|
1388
|
-
def wrap(obj)
|
1389
|
-
SubjectLocator.wrap(obj)
|
1390
|
-
end
|
1391
|
-
end
|
1392
|
-
|
44
|
+
require 'rtm/backend/active_record/tm_delegator'
|
45
|
+
require 'rtm/backend/active_record/tm_set_delegator'
|
46
|
+
require 'rtm/backend/active_record/tm_construct'
|
47
|
+
require 'rtm/backend/active_record/topic_map'
|
48
|
+
require 'rtm/backend/active_record/topic'
|
49
|
+
require 'rtm/backend/active_record/association_and_role'
|
50
|
+
require 'rtm/backend/active_record/name_variant_occurrence'
|
51
|
+
require 'rtm/backend/active_record/locators'
|
52
|
+
require 'rtm/backend/active_record/set_wrapper'
|
1393
53
|
end
|
1394
|
-
|