rtm-activerecord 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/DISCLAIMER +13 -0
- data/LICENSE +201 -0
- data/README +4 -0
- data/lib/rtm/activerecord/001_initial_schema.rb +119 -0
- data/lib/rtm/activerecord/association_and_role.rb +54 -0
- data/lib/rtm/activerecord/base.rb +83 -0
- data/lib/rtm/activerecord/connect.rb +106 -0
- data/lib/rtm/activerecord/io/from_xtm2.rb +266 -0
- data/lib/rtm/activerecord/io/from_xtm2_libxml.rb +97 -0
- data/lib/rtm/activerecord/io/to_jtm.rb +141 -0
- data/lib/rtm/activerecord/io/to_string.rb +130 -0
- data/lib/rtm/activerecord/io/to_xtm1.rb +162 -0
- data/lib/rtm/activerecord/io/to_xtm2.rb +163 -0
- data/lib/rtm/activerecord/io/to_yaml.rb +132 -0
- data/lib/rtm/activerecord/literal_index.rb +38 -0
- data/lib/rtm/activerecord/locators.rb +58 -0
- data/lib/rtm/activerecord/merging.rb +310 -0
- data/lib/rtm/activerecord/name_variant_occurrence.rb +86 -0
- data/lib/rtm/activerecord/persistent_code_output.rb +22 -0
- data/lib/rtm/activerecord/quaaxtm2rtm.rb +116 -0
- data/lib/rtm/activerecord/quaaxtm2rtmviews.rb +137 -0
- data/lib/rtm/activerecord/set_wrapper.rb +101 -0
- data/lib/rtm/activerecord/sugar/association/hash_access.rb +22 -0
- data/lib/rtm/activerecord/sugar/role/counterparts.rb +56 -0
- data/lib/rtm/activerecord/sugar/topic/characteristics.rb +15 -0
- data/lib/rtm/activerecord/sugar/topic/counterparts.rb +18 -0
- data/lib/rtm/activerecord/sugar/topic/hash_access.rb +78 -0
- data/lib/rtm/activerecord/sugar/topic/identifier_direct.rb +14 -0
- data/lib/rtm/activerecord/sugar/topic/predefined_associations.rb +53 -0
- data/lib/rtm/activerecord/tm_construct.rb +66 -0
- data/lib/rtm/activerecord/tm_delegator.rb +417 -0
- data/lib/rtm/activerecord/tm_set_delegator.rb +226 -0
- data/lib/rtm/activerecord/tmdm.rb +309 -0
- data/lib/rtm/activerecord/topic.rb +204 -0
- data/lib/rtm/activerecord/topic_map.rb +435 -0
- data/lib/rtm/activerecord/traverse_associations.rb +90 -0
- data/lib/rtm/activerecord.rb +106 -0
- metadata +120 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR::Sugar
|
5
|
+
module Association
|
6
|
+
# This module implements methods for Hash-like access in Associations.
|
7
|
+
module HashAccess
|
8
|
+
# Returns the roles of the association which match the given role type.
|
9
|
+
# The role type can be specified as String-reference or as Topic.
|
10
|
+
def [](type_reference=:any)
|
11
|
+
return roles if type_reference == :any
|
12
|
+
return roles unless type_reference
|
13
|
+
if type_reference.is_a? String
|
14
|
+
roles.select{|o| o.type == topic_map.get(type_reference)}
|
15
|
+
else
|
16
|
+
# assume topics are given
|
17
|
+
roles.select{|o| o.type == type_reference}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR::Sugar
|
5
|
+
module Role
|
6
|
+
module Counterparts
|
7
|
+
|
8
|
+
# Fetches all roles from the parent association of this role,
|
9
|
+
# except itself (i.e. current role).
|
10
|
+
# A filter-hash may be used to filter for the type of the other role (:otype =>topic_reference).
|
11
|
+
# Examples:
|
12
|
+
# this_role.counterparts # returns all
|
13
|
+
# this_role.counterparts(:otype => some_topic) # returns only other roles which have type some_topic
|
14
|
+
# this_role.counterparts(:otype => "some_reference") # as above, looking up the reference first
|
15
|
+
def counterparts(filter={})
|
16
|
+
self.parent.roles.reject{|r| r.id==self.id}.
|
17
|
+
select{|r| filter[:otype] ? r.type == self.topic_map.get(filter[:otype]) : true}
|
18
|
+
end
|
19
|
+
|
20
|
+
# This methods fetches all players of the parent association of this role, except the player of itself.
|
21
|
+
# It accepts a filter-hash like the counterparts-method.
|
22
|
+
def counterplayers(*args)
|
23
|
+
self.counterparts(*args).map{|r| r.player}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Fetches the other role, if the parent association is binary.
|
27
|
+
def counterpart
|
28
|
+
n = self.parent.roles.size
|
29
|
+
raise "Association must be unary or binary to use counterpart method. Please use counterparts for n-ary associations." if n > 2
|
30
|
+
return nil if n == 1
|
31
|
+
self.counterparts.first
|
32
|
+
end
|
33
|
+
|
34
|
+
# Fetches the player of the other role, if the parent association is binary.
|
35
|
+
def counterplayer
|
36
|
+
n = self.parent.roles.size
|
37
|
+
raise "Association must be unary or binary to use counterplayer method. Please use counterplayers for n-ary associations." if n > 2
|
38
|
+
return nil if n == 1
|
39
|
+
self.counterparts.first.player
|
40
|
+
end
|
41
|
+
|
42
|
+
# Fetches all roles of the (binary) parent associations which play the same role in the same with the counterplayer
|
43
|
+
# TODO: filter not only otype but also atype and rtype.
|
44
|
+
def peers
|
45
|
+
cp = self.counterpart
|
46
|
+
cp.player.roles.select{|r| r.type == cp.type}.map{|r| r.counterpart}
|
47
|
+
end
|
48
|
+
# Fetches all players of roles being in the same association with another topic as self
|
49
|
+
# Example: current_role is a role of player "me" and type "employee"
|
50
|
+
# current_role.peerplayers # returns all employees of my company (including me)
|
51
|
+
def peerplayers
|
52
|
+
self.peers.map{|r| r.player}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR::Sugar
|
5
|
+
module Topic
|
6
|
+
module Characteristics
|
7
|
+
def internal_occurrences
|
8
|
+
occurrences.select{|o| o.datatype != RTM::PSI[:IRI]}
|
9
|
+
end
|
10
|
+
def external_occurrences
|
11
|
+
occurrences.select{|o| o.datatype == RTM::PSI[:IRI]}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR::Sugar
|
5
|
+
module Topic
|
6
|
+
module Counterparts
|
7
|
+
def counterparts(filter={})
|
8
|
+
self.roles.
|
9
|
+
select{|r| filter[:rtype] ? r.type == self.topic_map.get(filter[:rtype]) : true}.
|
10
|
+
select{|r| filter[:atype] ? r.parent.type == self.topic_map.get(filter[:atype]) : true}.
|
11
|
+
inject([]){|all,r| all+=r.counterparts(filter)}
|
12
|
+
end
|
13
|
+
def counterplayers(*args)
|
14
|
+
return self.counterparts(*args).map{|r| r.player}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR::Sugar
|
5
|
+
module Topic
|
6
|
+
# This module implements methods for Hash-like access in Topics.
|
7
|
+
module HashAccess
|
8
|
+
|
9
|
+
# Returns a list of names or occurrences depending on the arguments given.
|
10
|
+
#
|
11
|
+
def [](cref)
|
12
|
+
# return occurrences by type if topic is given
|
13
|
+
return occurrences.select{|o| o.type == cref} if cref.is_a? Topic
|
14
|
+
raise "Characteristic reference must be a Topic or a String" unless cref.is_a? String
|
15
|
+
# parse the given String to extract kind (name/occ), type and scope
|
16
|
+
is_name, type_reference, scope_reference = resolve_characteristic(cref)
|
17
|
+
if is_name
|
18
|
+
type_reference = RTM::PSI[:name_type] if type_reference == :any
|
19
|
+
ret = names.select{|n| n.type == topic_map.get(type_reference)}
|
20
|
+
else
|
21
|
+
raise "No occurrence type given" if type_reference == :any
|
22
|
+
ret = occurrences.select{|o| o.type == topic_map.get(type_reference)}
|
23
|
+
end
|
24
|
+
# we now have a list of names or occurrences, now we have to select for scope
|
25
|
+
return ret if scope_reference == :any
|
26
|
+
if scope_reference == :ucs
|
27
|
+
ret.select{|n| n.scope.size == 0}
|
28
|
+
else
|
29
|
+
ret.select{|n| scope_reference.all?{|sr| srt = topic_map.get(sr); srt && n.scope.include?(srt)}}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def []=(cref, value)
|
34
|
+
is_name, type_reference, scope_reference = resolve_characteristic(cref)
|
35
|
+
if is_name
|
36
|
+
type_reference = nil if type_reference == :any
|
37
|
+
nametype = type_reference || topic_map.get!(RTM::PSI[:name_type])
|
38
|
+
ret = create_name(nametype, value)
|
39
|
+
else
|
40
|
+
raise "No occurrence type given" if type_reference == :any
|
41
|
+
ret = create_occurrence(type_reference,value)
|
42
|
+
end
|
43
|
+
# return object without scope if any or ucs
|
44
|
+
return ret if [:any, :ucs].include? scope_reference
|
45
|
+
# set scope
|
46
|
+
scope_reference.each do |sr|
|
47
|
+
ret.scope << topic_map.get!(sr)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def resolve_characteristic(ref)
|
53
|
+
ref =~ /^(-\s*)?(.+)?$/
|
54
|
+
is_name = $1 ? true : false
|
55
|
+
type, scope = resolve_type_and_scope($2)
|
56
|
+
[is_name, type, scope]
|
57
|
+
end
|
58
|
+
|
59
|
+
def resolve_type_and_scope(ref)
|
60
|
+
return [:any, :any] unless ref
|
61
|
+
return [ref, :ucs] if ref.is_a? Topic
|
62
|
+
type, scope = ref.split('@', -1)
|
63
|
+
if type.blank?
|
64
|
+
type = :any
|
65
|
+
else
|
66
|
+
type.strip!
|
67
|
+
end
|
68
|
+
if scope
|
69
|
+
scope = scope.strip.split(/\s+/)
|
70
|
+
scope = :ucs if scope.blank?
|
71
|
+
else
|
72
|
+
scope = :any
|
73
|
+
end
|
74
|
+
[type, scope]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR::Sugar
|
5
|
+
module Topic
|
6
|
+
module IdentifierDirect
|
7
|
+
def identifiers
|
8
|
+
subject_identifiers.map{|si| si.to_s} +
|
9
|
+
subject_locators.map{|sl| "=#{sl.to_s}"} +
|
10
|
+
item_identifiers.map{|ii| "^#{ii.to_s}"}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR::Sugar
|
5
|
+
module Topic
|
6
|
+
module PredefinedAssociations
|
7
|
+
extend RTM::AR::TraverseAssociations
|
8
|
+
# maybe these pairs could be declared each with a single statement and a reversible option
|
9
|
+
define_association :types, :type => :Topic, :rule => {
|
10
|
+
:transitive => false,
|
11
|
+
:role_type => RTM::PSI[:instance],
|
12
|
+
:association_type => RTM::PSI[:type_instance],
|
13
|
+
:association_arity => 2,
|
14
|
+
:other_role_type => RTM::PSI[:type],
|
15
|
+
:infer_other => :supertypes,
|
16
|
+
:add => :type,
|
17
|
+
}
|
18
|
+
alias :addType :add_type
|
19
|
+
|
20
|
+
define_association :instances, :type => :Topic, :rule => {
|
21
|
+
:transitive => false,
|
22
|
+
:role_type => RTM::PSI[:type],
|
23
|
+
:association_type => RTM::PSI[:type_instance],
|
24
|
+
:association_arity => 2,
|
25
|
+
:other_role_type => RTM::PSI[:instance],
|
26
|
+
:infer => :subtypes,
|
27
|
+
:add => :instance,
|
28
|
+
}
|
29
|
+
alias :addInstance :add_instance
|
30
|
+
|
31
|
+
define_association :supertypes, :type => :Topic, :rule => {
|
32
|
+
:transitive => true,
|
33
|
+
:role_type => RTM::PSI[:subtype],
|
34
|
+
:association_type => RTM::PSI[:supertype_subtype],
|
35
|
+
:association_arity => 2,
|
36
|
+
:other_role_type => RTM::PSI[:supertype],
|
37
|
+
:add => :supertype,
|
38
|
+
}
|
39
|
+
alias :addSupertype :add_supertype
|
40
|
+
|
41
|
+
define_association :subtypes, :type => :Topic, :rule => {
|
42
|
+
:transitive => true,
|
43
|
+
:role_type => RTM::PSI[:supertype],
|
44
|
+
:association_type => RTM::PSI[:supertype_subtype],
|
45
|
+
:association_arity => 2,
|
46
|
+
:other_role_type => RTM::PSI[:subtype],
|
47
|
+
:add => :subtype,
|
48
|
+
}
|
49
|
+
alias :addSubtype :add_subtype
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR
|
5
|
+
class Construct < TMDelegator
|
6
|
+
include RTM::Construct
|
7
|
+
|
8
|
+
def self.abstract_class?
|
9
|
+
self == Construct
|
10
|
+
end
|
11
|
+
property_set :item_identifiers, :aka => [:ii, :iid, :source_locators], :type => :ItemIdentifier, :wrap => true,
|
12
|
+
#:create => :item_identifier, :create_aka => :cii
|
13
|
+
:add => true, :remove => true
|
14
|
+
alias :getItemIdentifiers :item_identifiers
|
15
|
+
|
16
|
+
delegate :remove, :to => :destroy
|
17
|
+
|
18
|
+
delegate :id
|
19
|
+
# property_parent :parent # mmh..
|
20
|
+
|
21
|
+
property :topic_map, :rw => true, :type => :TopicMap, :wrap => true
|
22
|
+
|
23
|
+
#class_delegate :create
|
24
|
+
|
25
|
+
def self.wrap(obj)
|
26
|
+
return nil unless obj
|
27
|
+
raise "Double wrapping" if obj.respond_to?(:__getobj__)
|
28
|
+
case obj.class.name
|
29
|
+
when "RTM::AR::TMDM::Topic"
|
30
|
+
Topic.wrap(obj)
|
31
|
+
when "RTM::AR::TMDM::Variant"
|
32
|
+
Variant.wrap(obj)
|
33
|
+
when "RTM::AR::TMDM::Name"
|
34
|
+
Name.wrap(obj)
|
35
|
+
when "RTM::AR::TMDM::Occurrence"
|
36
|
+
Occurrence.wrap(obj)
|
37
|
+
when "RTM::AR::TMDM::Association"
|
38
|
+
Association.wrap(obj)
|
39
|
+
when "RTM::AR::TMDM::Role"
|
40
|
+
Role.wrap(obj)
|
41
|
+
when "RTM::AR::TMDM::TopicMap"
|
42
|
+
TopicMap.wrap(obj)
|
43
|
+
else
|
44
|
+
raise "Can't wrap object. Class for wrapping #{obj.class} unknown (object: #{obj})"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.find(*args)
|
49
|
+
res = RTM::AR::TMDM.const_get(name.split("::").last).find(*args)
|
50
|
+
if res.respond_to? :each
|
51
|
+
Constructs.wrap(res)
|
52
|
+
else
|
53
|
+
Construct.wrap(res)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Reifiable < Construct
|
59
|
+
include RTM::Reifiable
|
60
|
+
|
61
|
+
def self.abstract_class?
|
62
|
+
self == Reifiable
|
63
|
+
end
|
64
|
+
property :reifier, :type => :Topic, :rw => :true, :wrap => true
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,417 @@
|
|
1
|
+
# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
|
2
|
+
# License: Apache License, Version 2.0
|
3
|
+
|
4
|
+
module RTM::AR
|
5
|
+
class TMDelegator
|
6
|
+
def initialize(obj)
|
7
|
+
@obj = obj
|
8
|
+
end
|
9
|
+
|
10
|
+
def __getobj__
|
11
|
+
@obj
|
12
|
+
end
|
13
|
+
|
14
|
+
def __setobj__(obj)
|
15
|
+
@obj = obj
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.delegate(sym, options={})
|
19
|
+
to = options[:to] || sym
|
20
|
+
options[:reload] ||= sym==:remove ? true : false # dirty hack to get a bit of reloading after delete
|
21
|
+
module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
|
22
|
+
def #{sym}(*args, &block)
|
23
|
+
__getobj__.send(:#{to}, *args, &block)
|
24
|
+
#{options[:reload] ? "parent.__getobj__.reload" :""}
|
25
|
+
end
|
26
|
+
EOS
|
27
|
+
|
28
|
+
if options[:rw]
|
29
|
+
module_eval(<<-EOS, "(__TMDELEGATOR2__)", 1)
|
30
|
+
def #{sym}=(*args, &block)
|
31
|
+
__getobj__.send(:#{to}=, *args, &block)
|
32
|
+
#{options[:save] ? "__getobj__.save" : "" }
|
33
|
+
end
|
34
|
+
EOS
|
35
|
+
end
|
36
|
+
|
37
|
+
if options[:aka]
|
38
|
+
options[:aka] = [options[:aka]] unless options[:aka].respond_to? :each
|
39
|
+
options[:aka].each do |aka|
|
40
|
+
module_eval(<<-EOS, "(__TMDELEGATOR3__)", 1)
|
41
|
+
alias :#{aka} :#{sym}
|
42
|
+
EOS
|
43
|
+
|
44
|
+
if options[:rw]
|
45
|
+
module_eval(<<-EOS, "(__TMDELEGATOR3__)", 1)
|
46
|
+
alias :#{aka}= :#{sym}=
|
47
|
+
EOS
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.class_delegate(sym, options={})
|
54
|
+
module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
|
55
|
+
class << self
|
56
|
+
def #{sym}(*args, &block)
|
57
|
+
__getobj__.send(:#{sym}, *args, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
EOS
|
61
|
+
|
62
|
+
if options[:aka]
|
63
|
+
options[:aka] = [options[:aka]] unless options[:aka].respond_to? :each
|
64
|
+
options[:aka].each do |aka|
|
65
|
+
module_eval(<<-EOS, "(__TMDELEGATOR2__)", 1)
|
66
|
+
class << self
|
67
|
+
alias :#{aka} :#{sym}
|
68
|
+
end
|
69
|
+
EOS
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.parent(sym, options={})
|
75
|
+
module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
|
76
|
+
def #{sym}
|
77
|
+
Construct.wrap(__getobj__.send(:#{sym}))
|
78
|
+
end
|
79
|
+
EOS
|
80
|
+
aka_property(sym, [:parent, :p])
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.property_set(prop, options={})
|
84
|
+
# puts "In #{self.name.to_s.ljust(20)} we have type #{options[:type].to_s.ljust(20)} for property #{prop}"
|
85
|
+
if options[:wrap]
|
86
|
+
#puts "#{self}: #{options[:type]}"
|
87
|
+
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_W__)", 1)
|
88
|
+
def #{prop}(*args)
|
89
|
+
if args.size == 0
|
90
|
+
# fetch normal
|
91
|
+
#{options[:type]}s.wrap(__getobj__.#{prop}, self, :#{options[:type]})
|
92
|
+
else
|
93
|
+
# fetch with filter
|
94
|
+
# see if we have a custom filtering method
|
95
|
+
if self.respond_to?(:filter_#{prop})
|
96
|
+
res = filter_#{prop}(*args) # tries a custom query, returns false if it doesn't know how to handle args
|
97
|
+
return res if res # return if successful, go on otherwise
|
98
|
+
end
|
99
|
+
# no custom filtering, use regular one
|
100
|
+
#puts args.inspect
|
101
|
+
# TODO enhance/fix condition transform code
|
102
|
+
a1 = args.first
|
103
|
+
unless a1.is_a?(Hash)
|
104
|
+
a1 = topic_map.get(a1) || {}
|
105
|
+
end
|
106
|
+
a = {}.merge(a1)
|
107
|
+
if a[:type] && !a[:ttype]
|
108
|
+
a[:ttype] = a[:type]
|
109
|
+
a.delete(:type)
|
110
|
+
end
|
111
|
+
puts "#{"#"}{self.class}:#{prop} -- #{"#"}{args.first.inspect}"
|
112
|
+
puts
|
113
|
+
puts a.inspect
|
114
|
+
b = {}
|
115
|
+
a.each do |k,v|
|
116
|
+
if RTM::AR::TMDM::#{options[:type]}.columns.map{|c| c.name}.include?(k)
|
117
|
+
puts "#{options[:type]} hat spalte: #{"#"}{k}"
|
118
|
+
else
|
119
|
+
puts "#{options[:type]} hat NICHT spalte: #{"#"}{k}"
|
120
|
+
b[k] = v
|
121
|
+
a.delete(k)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
a.each do |k,v|
|
126
|
+
if v.respond_to?(:__getobj__)
|
127
|
+
a[(k.to_s + "_id").to_sym] = v.id
|
128
|
+
end
|
129
|
+
end
|
130
|
+
res = #{options[:type]}s.wrap(__getobj__.#{prop}.find(:all, :conditions=> a), self, :#{options[:type]})
|
131
|
+
if args.size == 1
|
132
|
+
a1 = args.first
|
133
|
+
res = res.select{|t| t}
|
134
|
+
end
|
135
|
+
res
|
136
|
+
end
|
137
|
+
end
|
138
|
+
EOS
|
139
|
+
else
|
140
|
+
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_NW__)", 1)
|
141
|
+
def #{prop}
|
142
|
+
__getobj__.#{prop}
|
143
|
+
end
|
144
|
+
EOS
|
145
|
+
end
|
146
|
+
|
147
|
+
if options[:create]
|
148
|
+
# some :create_args:
|
149
|
+
#
|
150
|
+
# create_locator reference:string
|
151
|
+
# [ :name => :reference, :type => :String]
|
152
|
+
#
|
153
|
+
# create_topic_name value:String, scope:Collection
|
154
|
+
# create_topic_name value:String, type: Topic, scope:Collection
|
155
|
+
# [ {:name => :value, :type => :String}, {:name => :type, :type => :Topic, :optional => true}, {:name => :scope, :type => :Collection} ]
|
156
|
+
#
|
157
|
+
# create_occurrence value:String, type: Topic, scope:Collection
|
158
|
+
# create_occurrence resource: Locator, type: Topic, scope:Collection
|
159
|
+
# [ {:name => :value, :type => [:String, :Locator]}, {:name => :type, :type => :Topic}, {:name => :scope, :type => :Collection} ]
|
160
|
+
#
|
161
|
+
# create_association_role player:topic, type: topic
|
162
|
+
# [ {:name => :player, :type => :Topic}, {:name => :type, :type => :Topic}]
|
163
|
+
#
|
164
|
+
# create_variant value:string, :scope:Collection
|
165
|
+
# create_variant resource:locator, :scope:Collection
|
166
|
+
# [ {:name => :value, :type => [:String, :Locator]}, {:name => :scope, :type => :Collection}]
|
167
|
+
|
168
|
+
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_CREATE__)", 1)
|
169
|
+
def create_#{ options[:create]}(*args, &block)
|
170
|
+
#puts "#{ options[:create]}"
|
171
|
+
#puts args.inspect
|
172
|
+
arg_defs = #{ (options[:create_args] || nil ).inspect}
|
173
|
+
|
174
|
+
a = parse_args(args, arg_defs)
|
175
|
+
#raise "could not parse parameters:" + a.inspect + " from " + args.inspect if a.empty?
|
176
|
+
|
177
|
+
a = enhance_args_hash(a, arg_defs) if arg_defs
|
178
|
+
|
179
|
+
a = a.reject{|k,v| v.nil?}
|
180
|
+
|
181
|
+
# hack to change :type to :ttype for AR backend
|
182
|
+
# puts a.inspect unless a.is_a? Hash
|
183
|
+
if a[:type] && !a[:ttype]
|
184
|
+
a[:ttype] = a[:type]
|
185
|
+
a.delete(:type)
|
186
|
+
end
|
187
|
+
if [:Locator,:ItemIdentifier, :SubjectIdentifier, :SubjectLocator].include?(:#{options[:type]})
|
188
|
+
unless a[:topic_map]
|
189
|
+
a[:topic_map] = topic_map.__getobj__
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
if block_given?
|
194
|
+
# if a.respond_to?(:__getobj__)
|
195
|
+
# a = a.__getobj__
|
196
|
+
# end
|
197
|
+
obj = #{options[:type]}.wrap( __getobj__.#{prop}.new(a) )
|
198
|
+
yield obj
|
199
|
+
obj.save
|
200
|
+
else
|
201
|
+
# if a.respond_to?(:__getobj__)
|
202
|
+
# a = a.__getobj__
|
203
|
+
# end
|
204
|
+
# raise a.inspect unless a.is_a?(RTM::AR::TMDM::Topic)
|
205
|
+
obj = #{options[:type]}.wrap( __getobj__.#{prop}.create(a) )
|
206
|
+
end
|
207
|
+
self.reload
|
208
|
+
obj
|
209
|
+
end
|
210
|
+
EOS
|
211
|
+
|
212
|
+
if options[:create_aka]
|
213
|
+
aka_property("create_#{options[:create]}", options[:create_aka])
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
if options[:add] && options[:add] == :scope
|
218
|
+
module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_ADD__)", 1)
|
219
|
+
def add_scope(theme)
|
220
|
+
if theme.is_a?(Array)
|
221
|
+
theme.each {|s| add_scope(s)}
|
222
|
+
end
|
223
|
+
scope.add(theme.__getobj__)
|
224
|
+
end
|
225
|
+
RUBY
|
226
|
+
# elsif options[:add] && (options[:add] == :subject_identifier || options[:add] == :subject_locator)
|
227
|
+
# module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_ADD__)", 1)
|
228
|
+
# def add_#{prop.to_s.singularize}(*args, &block)
|
229
|
+
# puts "adding something to #{prop}: #{"#"}{args.inspect}"
|
230
|
+
# obj.#{prop}.add(*args, &block)
|
231
|
+
# end
|
232
|
+
# RUBY
|
233
|
+
# aka_property("add_#{prop.to_s.singularize}", options[:aka].map{|a| "add_#{a}"})
|
234
|
+
# aka_property("add_#{prop.to_s.singularize}", options[:aka].map{|a| "a#{a}"})
|
235
|
+
elsif options[:add]
|
236
|
+
module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_ADD__)", 1)
|
237
|
+
def add_#{prop.to_s.singularize}(*args, &block)
|
238
|
+
#{prop}.add(*args, &block)
|
239
|
+
end
|
240
|
+
RUBY
|
241
|
+
aka_property("add_#{prop.to_s.singularize}", options[:aka].map{|a| "add_#{a}"})
|
242
|
+
aka_property("add_#{prop.to_s.singularize}", options[:aka].map{|a| "a#{a}"})
|
243
|
+
end
|
244
|
+
|
245
|
+
if options[:remove] && options[:remove] == :scope
|
246
|
+
module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_REMOVE__)", 1)
|
247
|
+
def remove_scope(theme)
|
248
|
+
scope.remove(theme)
|
249
|
+
end
|
250
|
+
RUBY
|
251
|
+
elsif options[:remove]
|
252
|
+
module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_REMOVE__)", 1)
|
253
|
+
def remove_#{prop.to_s.singularize}(*args, &block)
|
254
|
+
#{prop}.remove(*args, &block)
|
255
|
+
end
|
256
|
+
RUBY
|
257
|
+
aka_property("remove_#{prop.to_s.singularize}", options[:aka].map{|a| "remove_#{a}"})
|
258
|
+
aka_property("remove_#{prop.to_s.singularize}", options[:aka].map{|a| "r#{a}"})
|
259
|
+
end
|
260
|
+
|
261
|
+
# TODO: aliases for property_set.add as add_property
|
262
|
+
|
263
|
+
aka_property(prop, options[:aka]) if options[:aka]
|
264
|
+
end
|
265
|
+
|
266
|
+
private
|
267
|
+
def parse_args(args, arg_defs)
|
268
|
+
a = {}
|
269
|
+
a = args.pop if args.last.is_a? Hash
|
270
|
+
# We are finished if there are no more parameters or we have no arg_def.
|
271
|
+
# Special case: non optional parameters must have been in the Hash, just a hash is also allowed.
|
272
|
+
return a if args.size == 0 || arg_defs == nil
|
273
|
+
|
274
|
+
# we have some args
|
275
|
+
if args.size == arg_defs.size # all are given
|
276
|
+
return args2hash(a, args,arg_defs)
|
277
|
+
elsif args.size == arg_defs.reject { |d| d[:optional]}
|
278
|
+
return args2hash(a, args, arg_defs.reject {|d| d[:optional]})
|
279
|
+
end
|
280
|
+
#warn("Functions with more than one optional parameter are not supported. This will only work if the left out ones are the last.")
|
281
|
+
return args2hash(a, args,arg_defs)
|
282
|
+
end
|
283
|
+
|
284
|
+
def args2hash(a, args, arg_defs)
|
285
|
+
arg_defs.zip(args) do |argd,arg|
|
286
|
+
a[argd[:name]] = arg
|
287
|
+
end
|
288
|
+
|
289
|
+
return a
|
290
|
+
end
|
291
|
+
|
292
|
+
def enhance_args_hash(a, arg_defs)
|
293
|
+
#puts "enhance_args: #{a.inspect} ---\n#{arg_defs.inspect}"
|
294
|
+
return a if a.empty?
|
295
|
+
arg_defs.each do |argd|
|
296
|
+
#puts "enhancing #{argd[:name]}, which is a #{a[argd[:name]].class}"
|
297
|
+
if argd[:type] == :Topic
|
298
|
+
if a[argd[:name]].is_a? String
|
299
|
+
a[argd[:name]] = topic_map._topic_by_locator!(a[argd[:name]])
|
300
|
+
elsif a[argd[:name]].is_a?(RTM::Topic)
|
301
|
+
a[argd[:name]] = a[argd[:name]].__getobj__
|
302
|
+
end
|
303
|
+
end
|
304
|
+
if argd[:type] == :Locator || (argd[:type].respond_to?(:include?) && argd[:type].include?(:Locator))
|
305
|
+
a[argd[:name]] = a[argd[:name]].to_s
|
306
|
+
end
|
307
|
+
end
|
308
|
+
a
|
309
|
+
end
|
310
|
+
|
311
|
+
public
|
312
|
+
def self.property(prop, options={})
|
313
|
+
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY__)", 1)
|
314
|
+
def #{prop}
|
315
|
+
#{options[:wrap]? "#{options[:type]}.wrap":""}( __getobj__.#{prop})
|
316
|
+
end
|
317
|
+
EOS
|
318
|
+
|
319
|
+
if options[:rw]
|
320
|
+
case options[:type]
|
321
|
+
when :Topic
|
322
|
+
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
|
323
|
+
def #{prop}=(obj)
|
324
|
+
obj = topic_map.topic_by_locator!(obj) unless obj.is_a? #{options[:type]}
|
325
|
+
__getobj__.#{prop} = obj.__getobj__
|
326
|
+
__getobj__.save
|
327
|
+
end
|
328
|
+
EOS
|
329
|
+
when :TopicMap
|
330
|
+
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
|
331
|
+
def #{prop}=(obj)
|
332
|
+
obj = RTM.create obj.to_s unless obj.is_a? #{options[:type]}
|
333
|
+
__getobj__.#{prop} = obj.__getobj__
|
334
|
+
__getobj__.save
|
335
|
+
end
|
336
|
+
EOS
|
337
|
+
when :String, :Locator
|
338
|
+
module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
|
339
|
+
def #{prop}=(obj)
|
340
|
+
__getobj__.#{prop} = obj.to_s
|
341
|
+
__getobj__.save
|
342
|
+
end
|
343
|
+
EOS
|
344
|
+
else
|
345
|
+
raise "Don't know how to do wrapping for #{options[:type]}"
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|
349
|
+
|
350
|
+
aka_property(prop, options[:aka]) if options[:aka]
|
351
|
+
end
|
352
|
+
|
353
|
+
def self.aka_property(prop, aka)
|
354
|
+
aka = [aka].flatten
|
355
|
+
aka.each do |a|
|
356
|
+
#puts "generating alias #{a} for #{prop}"
|
357
|
+
module_eval(<<-EOS, "(__AR_DELEGATOR_AKA_PROPERTY__)", 1)
|
358
|
+
alias :#{a} :#{prop}
|
359
|
+
EOS
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def self.equality(eqfields, options={})
|
364
|
+
field_condition = eqfields.map {|f| "self.#{f} == o.#{f}" }.join(" && ")
|
365
|
+
module_eval(<<-EOS, "(__AR_EQUALITY__)", 1)
|
366
|
+
def ==(o)
|
367
|
+
#puts "hoho: #{"#"}{self.inspect} vs. #{"#"}{o.inspect}"
|
368
|
+
return false unless o
|
369
|
+
#{eqfields.map{|x| "#puts '#{x}'; puts self.#{x}.inspect;puts o.#{x}.inspect\n"}}
|
370
|
+
# puts '#{field_condition}'
|
371
|
+
return true if #{field_condition}
|
372
|
+
false
|
373
|
+
end
|
374
|
+
EOS
|
375
|
+
end
|
376
|
+
def eql?(o)
|
377
|
+
return false unless o
|
378
|
+
return true if self.class == o.class && self.id == o.id
|
379
|
+
false
|
380
|
+
end
|
381
|
+
def hash
|
382
|
+
return self.id.hash
|
383
|
+
end
|
384
|
+
|
385
|
+
def self.wrapper_cache
|
386
|
+
module_eval(<<-EOS, "(__AR_WRAPPER_CACHE__)", 1)
|
387
|
+
def self.wrap(obj)
|
388
|
+
return nil unless obj
|
389
|
+
raise "Double wrapping" if obj.respond_to?(:__getobj__)
|
390
|
+
t = self.wrapped(obj)
|
391
|
+
if t
|
392
|
+
t.__setobj__(obj)
|
393
|
+
return t
|
394
|
+
end
|
395
|
+
self.new(obj)
|
396
|
+
end
|
397
|
+
|
398
|
+
def self.wrapped(unwrapped_obj)
|
399
|
+
@@wrapped ||= {}
|
400
|
+
return @@wrapped[unwrapped_obj.id] if unwrapped_obj.respond_to? :id
|
401
|
+
@@wrapped[unwrapped_obj]
|
402
|
+
end
|
403
|
+
def self.reset_wrapped
|
404
|
+
@@wrapped = {}
|
405
|
+
end
|
406
|
+
def initialize(*args)
|
407
|
+
super
|
408
|
+
@@wrapped ||= {}
|
409
|
+
@@wrapped[self.id]=self
|
410
|
+
end
|
411
|
+
EOS
|
412
|
+
end
|
413
|
+
|
414
|
+
alias :i :id
|
415
|
+
delegate :reload
|
416
|
+
end
|
417
|
+
end
|