rtm-activerecord 0.2.0
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/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
|