activefacts 0.8.9 → 0.8.10

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.
Files changed (120) hide show
  1. data/.gemtest +0 -0
  2. data/Manifest.txt +28 -33
  3. data/Rakefile +11 -12
  4. data/bin/cql +90 -46
  5. data/examples/CQL/Blog.cql +2 -1
  6. data/examples/CQL/CompanyDirectorEmployee.cql +2 -2
  7. data/examples/CQL/Death.cql +1 -1
  8. data/examples/CQL/Diplomacy.cql +9 -9
  9. data/examples/CQL/Genealogy.cql +3 -2
  10. data/examples/CQL/Insurance.cql +10 -7
  11. data/examples/CQL/JoinEquality.cql +2 -2
  12. data/examples/CQL/Marriage.cql +1 -1
  13. data/examples/CQL/Metamodel.cql +73 -53
  14. data/examples/CQL/MetamodelNext.cql +89 -67
  15. data/examples/CQL/OneToOnes.cql +2 -2
  16. data/examples/CQL/ServiceDirector.cql +10 -5
  17. data/examples/CQL/Supervision.cql +3 -3
  18. data/examples/CQL/Tests.Test5.Load.cql +1 -1
  19. data/examples/CQL/Warehousing.cql +4 -2
  20. data/lib/activefacts/cql/CQLParser.treetop +26 -60
  21. data/lib/activefacts/cql/Context.treetop +12 -2
  22. data/lib/activefacts/cql/Expressions.treetop +14 -30
  23. data/lib/activefacts/cql/FactTypes.treetop +165 -110
  24. data/lib/activefacts/cql/Language/English.treetop +167 -54
  25. data/lib/activefacts/cql/LexicalRules.treetop +16 -2
  26. data/lib/activefacts/cql/{Concepts.treetop → ObjectTypes.treetop} +36 -37
  27. data/lib/activefacts/cql/Terms.treetop +57 -27
  28. data/lib/activefacts/cql/ValueTypes.treetop +39 -13
  29. data/lib/activefacts/cql/compiler.rb +5 -3
  30. data/lib/activefacts/cql/compiler/{reading.rb → clause.rb} +407 -285
  31. data/lib/activefacts/cql/compiler/constraint.rb +178 -275
  32. data/lib/activefacts/cql/compiler/entity_type.rb +73 -64
  33. data/lib/activefacts/cql/compiler/expression.rb +418 -0
  34. data/lib/activefacts/cql/compiler/fact.rb +146 -145
  35. data/lib/activefacts/cql/compiler/fact_type.rb +197 -80
  36. data/lib/activefacts/cql/compiler/join.rb +159 -0
  37. data/lib/activefacts/cql/compiler/shared.rb +51 -23
  38. data/lib/activefacts/cql/compiler/value_type.rb +56 -2
  39. data/lib/activefacts/cql/parser.rb +15 -4
  40. data/lib/activefacts/generate/absorption.rb +7 -7
  41. data/lib/activefacts/generate/cql.rb +100 -37
  42. data/lib/activefacts/generate/oo.rb +28 -51
  43. data/lib/activefacts/generate/ordered.rb +60 -36
  44. data/lib/activefacts/generate/ruby.rb +6 -6
  45. data/lib/activefacts/generate/sql/server.rb +4 -4
  46. data/lib/activefacts/input/orm.rb +71 -53
  47. data/lib/activefacts/persistence.rb +1 -1
  48. data/lib/activefacts/persistence/columns.rb +27 -23
  49. data/lib/activefacts/persistence/foreignkey.rb +6 -6
  50. data/lib/activefacts/persistence/index.rb +17 -17
  51. data/lib/activefacts/persistence/{concept.rb → object_type.rb} +9 -9
  52. data/lib/activefacts/persistence/reference.rb +61 -36
  53. data/lib/activefacts/persistence/tables.rb +61 -59
  54. data/lib/activefacts/support.rb +54 -29
  55. data/lib/activefacts/version.rb +1 -1
  56. data/lib/activefacts/vocabulary/extensions.rb +99 -54
  57. data/lib/activefacts/vocabulary/metamodel.rb +43 -37
  58. data/lib/activefacts/vocabulary/verbaliser.rb +134 -109
  59. data/spec/absorption_spec.rb +8 -8
  60. data/spec/cql/comparison_spec.rb +91 -0
  61. data/spec/cql/contractions_spec.rb +251 -0
  62. data/spec/cql/entity_type_spec.rb +319 -0
  63. data/spec/cql/expressions_spec.rb +63 -0
  64. data/spec/cql/fact_type_matching_spec.rb +283 -0
  65. data/spec/cql/french_spec.rb +21 -0
  66. data/spec/cql/parser/bad_literals_spec.rb +86 -0
  67. data/spec/cql/parser/constraints_spec.rb +19 -0
  68. data/spec/cql/parser/entity_types_spec.rb +106 -0
  69. data/spec/cql/parser/expressions_spec.rb +179 -0
  70. data/spec/cql/parser/fact_types_spec.rb +41 -0
  71. data/spec/cql/parser/literals_spec.rb +312 -0
  72. data/spec/cql/parser/pragmas_spec.rb +89 -0
  73. data/spec/cql/parser/value_types_spec.rb +42 -0
  74. data/spec/cql/role_matching_spec.rb +147 -0
  75. data/spec/cql/samples_spec.rb +9 -9
  76. data/spec/cql_cql_spec.rb +1 -1
  77. data/spec/cql_dm_spec.rb +116 -0
  78. data/spec/cql_mysql_spec.rb +1 -1
  79. data/spec/cql_ruby_spec.rb +1 -1
  80. data/spec/cql_sql_spec.rb +3 -3
  81. data/spec/cql_symbol_tables_spec.rb +30 -30
  82. data/spec/cqldump_spec.rb +4 -4
  83. data/spec/helpers/array_matcher.rb +32 -27
  84. data/spec/helpers/diff_matcher.rb +6 -26
  85. data/spec/helpers/file_matcher.rb +41 -32
  86. data/spec/helpers/parse_to_ast_matcher.rb +76 -0
  87. data/spec/helpers/string_matcher.rb +32 -31
  88. data/spec/norma_cql_spec.rb +1 -1
  89. data/spec/norma_ruby_spec.rb +1 -1
  90. data/spec/norma_ruby_sql_spec.rb +1 -1
  91. data/spec/norma_sql_spec.rb +3 -1
  92. data/spec/norma_tables_spec.rb +1 -1
  93. data/spec/ruby_api_spec.rb +23 -0
  94. data/spec/spec_helper.rb +5 -4
  95. metadata +66 -66
  96. data/examples/CQL/OrienteeringER.cql +0 -58
  97. data/lib/activefacts/api.rb +0 -44
  98. data/lib/activefacts/api/concept.rb +0 -410
  99. data/lib/activefacts/api/constellation.rb +0 -128
  100. data/lib/activefacts/api/entity.rb +0 -256
  101. data/lib/activefacts/api/instance.rb +0 -60
  102. data/lib/activefacts/api/instance_index.rb +0 -80
  103. data/lib/activefacts/api/numeric.rb +0 -167
  104. data/lib/activefacts/api/role.rb +0 -80
  105. data/lib/activefacts/api/role_proxy.rb +0 -70
  106. data/lib/activefacts/api/role_values.rb +0 -117
  107. data/lib/activefacts/api/standard_types.rb +0 -87
  108. data/lib/activefacts/api/support.rb +0 -65
  109. data/lib/activefacts/api/value.rb +0 -135
  110. data/lib/activefacts/api/vocabulary.rb +0 -82
  111. data/spec/api/autocounter.rb +0 -82
  112. data/spec/api/constellation.rb +0 -130
  113. data/spec/api/entity_type.rb +0 -103
  114. data/spec/api/instance.rb +0 -461
  115. data/spec/api/roles.rb +0 -124
  116. data/spec/api/value_type.rb +0 -112
  117. data/spec/api_spec.rb +0 -13
  118. data/spec/cql/matching_spec.rb +0 -517
  119. data/spec/cql/unit_spec.rb +0 -394
  120. data/spec/spec.opts +0 -1
@@ -1,128 +0,0 @@
1
- #
2
- # ActiveFacts Runtime API
3
- # Constellation class
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
-
8
- module ActiveFacts
9
- module API #:nodoc:
10
- # A Constellation is a population of instances of the Concept classes of a Vocabulary.
11
- # Every concept class is either a Value type or an Entity type.
12
- #
13
- # Value types are uniquely identified by their value, and a constellation will only
14
- # ever have a single instance of a given value of that class.
15
- #
16
- # Entity instances are uniquely identified by their identifying roles, and again, a
17
- # constellation will only ever have a single entity instance for the values of those
18
- # identifying roles.
19
- #
20
- # As a result, you cannot "create" an object in a constellation - you merely _assert_
21
- # its existence. This is done using method_missing; @constellation.Thing(3) creates
22
- # an instance (or returns the existing instance) of Thing identified by the value 3.
23
- # You can also use the populate() method to apply a block of assertions.
24
- #
25
- # You can instance##retract any instance, and that removes it from the constellation (will
26
- # delete it from the database when the constellation is saved), and nullifies any
27
- # references to it.
28
- #
29
- # A Constellation may or not be valid according to the vocabulary's constraints,
30
- # but it may also represent a portion of a larger population (a database) with
31
- # which it may be merged to form a valid population. In other words, an invalid
32
- # Constellation may be invalid only because it lacks some of the facts.
33
- #
34
- class Constellation
35
- attr_reader :vocabulary
36
- # All instances are indexed in this hash, keyed by the class object. Each instance is indexed for every supertype it has (including multiply-inherited ones). It's a bad idea to try to modify these indexes!
37
- attr_reader :instances # Can say c.instances[MyClass].each{|k, v| ... }
38
- # Can also say c.MyClass.each{|k, v| ... }
39
-
40
- # Create a new empty Constellation over the given Vocabulary
41
- def initialize(vocabulary)
42
- @vocabulary = vocabulary
43
- @instances = Hash.new do |h,k|
44
- raise "A constellation over #{@vocabulary.name} can only index instances of concepts in that vocabulary, not #{k.inspect}" unless k.is_a?(Class) and k.modspace == vocabulary
45
- h[k] = InstanceIndex.new
46
- end
47
- end
48
-
49
- def inspect #:nodoc:
50
- "Constellation:#{object_id}"
51
- end
52
-
53
- # Evaluate assertions against the population of this Constellation
54
- def populate *args, &block
55
- # REVISIT: Use args for something? Like options to enable/disable validation?
56
- instance_eval(&block)
57
- end
58
-
59
- # Delete instances from the constellation, nullifying (or cascading) the roles each plays
60
- def retract(*instances)
61
- Array(instances).each do |i|
62
- i.retract
63
- end
64
- end
65
-
66
- # Constellations verbalise all members of all classes in alphabetical order, showing
67
- # non-identifying role values as well
68
- def verbalise
69
- "Constellation over #{vocabulary.name}:\n" +
70
- vocabulary.concept.keys.sort.map{|concept|
71
- klass = vocabulary.const_get(concept)
72
-
73
- # REVISIT: It would be better not to rely on the role name pattern here:
74
- single_roles, multiple_roles = klass.roles.keys.sort_by(&:to_s).partition{|r| r.to_s !~ /\Aall_/ }
75
- single_roles -= klass.identifying_role_names if (klass.is_entity_type)
76
- # REVISIT: Need to include superclass roles also.
77
-
78
- instances = send(concept.to_sym)
79
- next nil unless instances.size > 0
80
- "\tEvery #{concept}:\n" +
81
- instances.map{|key, instance|
82
- s = "\t\t" + instance.verbalise
83
- if (single_roles.size > 0)
84
- role_values =
85
- single_roles.map{|role|
86
- [ role_name = role.to_s.camelcase(true),
87
- value = instance.send(role)]
88
- }.select{|role_name, value|
89
- value
90
- }.map{|role_name, value|
91
- "#{role_name} = #{value ? value.verbalise : "nil"}"
92
- }
93
- s += " where " + role_values*", " if role_values.size > 0
94
- end
95
- s
96
- } * "\n"
97
- }.compact*"\n"
98
- end
99
-
100
- # This method removes the given instance from this constellation's indexes
101
- # It must be called before the identifying roles get deleted or nullified.
102
- def __retract(instance) #:nodoc:
103
- # REVISIT: Need to search, as key values are gone already. Is there a faster way?
104
- ([instance.class]+instance.class.supertypes_transitive).each do |klass|
105
- @instances[klass].delete_if{|k,v| v == instance }
106
- end
107
- # REVISIT: Need to nullify all the roles this object plays.
108
- # If mandatory on the counterpart side, this may/must propagate the delete (without mutual recursion!)
109
- end
110
-
111
- # With parameters, assert an instance of the concept whose name is the missing method, identified by the values passed as *args*.
112
- # With no parameters, return the collection of all instances of that concept.
113
- def method_missing(m, *args)
114
- if klass = @vocabulary.const_get(m)
115
- if args.size == 0
116
- # Return the collection of all instances of this class in the constellation:
117
- @instances[klass]
118
- else
119
- # Assert a new ground fact (concept instance) of the specified class, identified by args:
120
- # REVISIT: create a constructor method here instead?
121
- instance, key = klass.assert_instance(self, args)
122
- instance
123
- end
124
- end
125
- end
126
- end
127
- end
128
- end
@@ -1,256 +0,0 @@
1
- #
2
- # ActiveFacts Runtime API
3
- # Entity class (a mixin module for the class Class)
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- module ActiveFacts
8
- module API
9
- # An Entity type is any Concept that isn't a value type.
10
- # All Entity types must have an identifier made up of one or more roles.
11
- module Entity
12
- include Instance
13
-
14
- # Assign the identifying roles to initialise a new Entity instance.
15
- # The role values are asserted in the constellation first, so you
16
- # can pass bare values (array, string, integer, etc) for any role
17
- # whose instances can be constructed using those values.
18
- #
19
- # A value must be provided for every identifying role, but if the
20
- # last argument is a hash, they may come from there.
21
- #
22
- # Any additional (non-identifying) roles may also be passed in the final hash.
23
- def initialize(*args)
24
- super(args)
25
- klass = self.class
26
- hash = {}
27
- hash = args.pop.clone if Hash === args[-1]
28
-
29
- # Pick any missing identifying roles out of the hash if possible:
30
- while args.size < (ir = klass.identifying_role_names).size
31
- value = hash[role = ir[args.size]]
32
- hash.delete(role)
33
- args.push value
34
- end
35
-
36
- # If one arg is expected but more are passed, they might be the args for the object that plays the identifying role:
37
- args = [args] if klass.identifying_role_names.size == 1 && args.size > 1
38
-
39
- # This should now only occur when there are too many args passed:
40
- raise "Wrong number of parameters to #{klass}.new, " +
41
- "expect (#{klass.identifying_role_names*","}) " +
42
- "got (#{args.map{|a| a.to_s.inspect}*", "})" if args.size != klass.identifying_role_names.size
43
-
44
- # Assign the identifying roles in order, then the other roles passed as a hash:
45
- (klass.identifying_role_names.zip(args) + hash.entries).each do |role_name, value|
46
- role = klass.roles(role_name)
47
- send("#{role_name}=", value)
48
- end
49
- end
50
-
51
- def inspect #:nodoc:
52
- "\#<#{
53
- self.class.basename
54
- }:#{
55
- object_id
56
- }#{
57
- constellation ? " in #{constellation.inspect}" : ""
58
- } #{
59
- # REVISIT: Where there are one-to-one roles, this cycles
60
- self.class.identifying_role_names.map{|role| "@#{role}="+send(role).inspect }*" "
61
- }>"
62
- end
63
-
64
- # When used as a hash key, the hash key of this entity instance is calculated
65
- # by hashing the values of its identifying roles
66
- def hash
67
- self.class.identifying_role_names.map{|role|
68
- instance_variable_get("@#{role}")
69
- }.inject(0) { |h,v|
70
- h ^= v.hash
71
- h
72
- }
73
- end
74
-
75
- # When used as a hash key, this entity instance is compared with another by
76
- # comparing the values of its identifying roles
77
- def eql?(other)
78
- return false unless self.class == other.class
79
- self.class.identifying_role_names.each{|role|
80
- return false unless send(role).eql?(other.send(role))
81
- }
82
- return true
83
- end
84
-
85
- # Verbalise this entity instance
86
- def verbalise(role_name = nil)
87
- "#{role_name || self.class.basename}(#{
88
- self.class.identifying_role_names.map{|role_sym|
89
- value = send(role_sym)
90
- role_name = self.class.roles(role_sym).name.to_s.camelcase(true)
91
- value ? value.verbalise(role_name) : "nil"
92
- }*", "
93
- })"
94
- end
95
-
96
- # Return the array of the values of this entity instance's identifying roles
97
- def identifying_role_values
98
- self.class.identifying_role_names.map{|role|
99
- send(role)
100
- }
101
- end
102
-
103
- # All classes that become Entity types receive the methods of this class as class methods:
104
- module ClassMethods
105
- include Instance::ClassMethods
106
-
107
- # Return the array of Role objects that define the identifying relationships of this Entity type:
108
- def identifying_role_names
109
- @identifying_role_names ||= []
110
- end
111
-
112
- def identifying_roles
113
- debug :persistence, "Identifying roles for #{basename}" do
114
- @identifying_role_names.map{|name|
115
- role = roles[name] || (!superclass.is_entity_type || superclass.roles[name])
116
- debug :persistence, "#{name} -> #{role ? "found" : "NOT FOUND"}"
117
- role
118
- }
119
- end
120
- end
121
-
122
- # Convert the passed arguments into an array of Instance objects that can identify an instance of this Entity type:
123
- def identifying_role_values(*args)
124
- #puts "Getting identifying role values #{identifying_role_names.inspect} of #{basename} using #{args.inspect}"
125
-
126
- # If the single arg is an instance of the correct class or a subclass,
127
- # use the instance's identifying_role_values
128
- if (args.size == 1 and
129
- (arg = args[0]).is_a?(self)) # REVISIT: or a secondary supertype
130
- arg = arg.__getobj__ if RoleProxy === arg
131
- return arg.identifying_role_values
132
- end
133
-
134
- ir = identifying_role_names
135
- args, arg_hash = ActiveFacts::extract_hash_args(ir, args)
136
- if args.size < ir.size
137
- raise "#{basename} requires all identifying values, you're missing #{ir[args.size..-1].map(&:to_sym)*', '}"
138
- elsif args.size > ir.size
139
- raise "#{basename} requires all identifying values, you have #{args.size-ir.size} extras #{args[ir.size..-1].map(&:inspect)*', '}"
140
- end
141
-
142
- role_args = ir.map{|role_sym| roles(role_sym)}.zip(args)
143
- role_args.map do |role, arg|
144
- #puts "Getting identifying_role_value for #{role.counterpart_concept.basename} using #{arg.inspect}"
145
- next nil unless arg
146
- next !!arg unless role.counterpart # Unary
147
- arg = arg.__getobj__ if RoleProxy === arg
148
- if arg.is_a?(role.counterpart_concept) # REVISIT: or a secondary supertype
149
- # Note that with a secondary supertype, it must still return the values of these identifying_role_names
150
- next arg.identifying_role_values
151
- end
152
- role.counterpart_concept.identifying_role_values(*arg)
153
- end
154
- end
155
-
156
- def assert_instance(constellation, args) #:nodoc:
157
- # Build the key for this instance from the args
158
- # The key of an instance is the value or array of keys of the identifying values.
159
- # The key values aren't necessarily present in the constellation, even after this.
160
- key = identifying_role_values(*args)
161
-
162
- # Find and return an existing instance matching this key
163
- instances = constellation.instances[self] # All instances of this class in this constellation
164
- instance = instances[key]
165
- # DEBUG: puts "assert #{self.basename} #{key.inspect} #{instance ? "exists" : "new"}"
166
- return instance, key if instance # A matching instance of this class
167
-
168
- # Now construct each of this object's identifying roles
169
- ir = identifying_role_names
170
- args, arg_hash = ActiveFacts::extract_hash_args(ir, args)
171
- role_values = ir.map{|role_sym| roles(role_sym)}.zip(args)
172
- key = [] # Gather the actual key (AutoCounters are special)
173
- values = role_values.map do |role, arg|
174
- if !arg
175
- value = role_key = nil # No value
176
- elsif !role.counterpart
177
- value = role_key = !!arg # Unary
178
- elsif arg.is_a?(role.counterpart_concept) # REVISIT: or a secondary supertype
179
- arg = arg.__getobj__ if RoleProxy === arg
180
- raise "Connecting values across constellations" unless arg.constellation == constellation
181
- value, role_key = arg, arg.identifying_role_values
182
- else
183
- value, role_key = role.counterpart_concept.assert_instance(constellation, Array(arg))
184
- end
185
- key << role_key
186
- value
187
- end
188
- values << arg_hash if arg_hash and !arg_hash.empty?
189
-
190
- #puts "Creating new #{basename} using #{values.inspect}"
191
- instance = new(*values)
192
-
193
- # Make the new entity instance a member of this constellation:
194
- instance.constellation = constellation
195
- return *index_instance(instance, key, ir)
196
- end
197
-
198
- def index_instance(instance, key = nil, key_roles = nil) #:nodoc:
199
- # Derive a new key if we didn't receive one or if the roles are different:
200
- unless key && key_roles && key_roles == identifying_role_names
201
- key = (key_roles = identifying_role_names).map do |role_name|
202
- instance.send role_name
203
- end
204
- end
205
-
206
- # Index the instance for this class in the constellation
207
- instances = instance.constellation.instances[self]
208
- instances[key] = instance
209
- # DEBUG: puts "indexing entity #{basename} using #{key.inspect} in #{constellation.object_id}"
210
-
211
- # Index the instance for each supertype:
212
- supertypes.each do |supertype|
213
- supertype.index_instance(instance, key, key_roles)
214
- end
215
-
216
- return instance, key
217
- end
218
-
219
- # A concept that isn't a ValueType must have an identification scheme,
220
- # which is a list of roles it plays. The identification scheme may be
221
- # inherited from a superclass.
222
- def initialise_entity_type(*args) #:nodoc:
223
- #puts "Initialising entity type #{self} using #{args.inspect}"
224
- @identifying_role_names = superclass.identifying_role_names if superclass.is_entity_type
225
- # REVISIT: @identifying_role_names here are the symbols passed in, not the Role objects we should use.
226
- # We'd need late binding to use Role objects...
227
- @identifying_role_names = args if args.size > 0 || !@identifying_role_names
228
- end
229
-
230
- def inherited(other) #:nodoc:
231
- other.identified_by *identifying_role_names
232
- subtypes << other unless subtypes.include? other
233
- #puts "#{self.name} inherited by #{other.name}"
234
- vocabulary.__add_concept(other)
235
- end
236
-
237
- # verbalise this concept
238
- def verbalise
239
- "#{basename} is identified by #{identifying_role_names.map{|role_sym| role_sym.to_s.camelcase(true)}*" and "};"
240
- end
241
- end
242
-
243
- def Entity.included other #:nodoc:
244
- other.send :extend, ClassMethods
245
-
246
- # Register ourselves with the parent module, which has become a Vocabulary:
247
- vocabulary = other.modspace
248
- # puts "Entity.included(#{other.inspect})"
249
- unless vocabulary.respond_to? :concept # Extend module with Vocabulary if necessary
250
- vocabulary.send :extend, Vocabulary
251
- end
252
- vocabulary.__add_concept(other)
253
- end
254
- end
255
- end
256
- end
@@ -1,60 +0,0 @@
1
- #
2
- # ActiveFacts Runtime API
3
- # Instance (mixin module for instances of a Concept - a class with Concept mixed in)
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- # Instance methods are extended into all instances, whether of value or entity types.
8
- #
9
- module ActiveFacts
10
- module API
11
- # Every Instance of a Concept (A Value type or an Entity type) includes the methods of this module:
12
- module Instance
13
- # What constellation does this Instance belong to (if any):
14
- attr_accessor :constellation
15
-
16
- def initialize(args = []) #:nodoc:
17
- unless (self.class.is_entity_type)
18
- #if (self.class.superclass != Object)
19
- # puts "constructing #{self.class.superclass} with #{args.inspect}"
20
- super(*args)
21
- end
22
- end
23
-
24
- # Verbalise this instance
25
- def verbalise
26
- # This method should always be overridden in subclasses
27
- raise "#{self.class} Instance verbalisation needed"
28
- end
29
-
30
- # De-assign all functional roles and remove from constellation, if any.
31
- def retract
32
- # Delete from the constellation first, so it can remember our identifying role values
33
- @constellation.__retract(self) if @constellation
34
-
35
- # Now, for all roles (from this class and all supertypes), assign nil to all functional roles
36
- # The counterpart roles get cleared automatically.
37
- ([self.class]+self.class.supertypes_transitive).each do |klass|
38
- klass.roles.each do |role_name, role|
39
- next if role.unary?
40
- next if !role.unique
41
-
42
- counterpart = role.counterpart
43
- puts "Nullifying mandatory role #{role.name} of #{role.owner.name}" if counterpart.mandatory
44
-
45
- send "#{role.name}=", nil
46
- end
47
- end
48
- end
49
-
50
- module ClassMethods #:nodoc:
51
- include Concept
52
- # Add Instance class methods here
53
- end
54
-
55
- def Instance.included other #:nodoc:
56
- other.send :extend, ClassMethods
57
- end
58
- end
59
- end
60
- end
@@ -1,80 +0,0 @@
1
- #
2
- # ActiveFacts Runtime API
3
- # InstanceIndex class
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- module ActiveFacts
8
- module API
9
- #
10
- # Each Constellation maintains an InstanceIndex for each Concept in its Vocabulary.
11
- # The InstanceIndex object is returned when you call @constellation.Concept with no
12
- # arguments (where Concept is the concept name you're interested in)
13
- #
14
- class InstanceIndex
15
- def []=(key, value) #:nodoc:
16
- raise "Adding RoleProxy to InstanceIndex" if value && RoleProxy === value
17
- h[key] = value
18
- end
19
-
20
- def [](*args)
21
- a = args
22
- #a = naked(args)
23
- # p "vvvv",
24
- # args,
25
- # a,
26
- # keys.map{|k| v=super(k); (RoleProxy === k ? "*" : "")+k.to_s+"=>"+(RoleProxy === v ? "*" : "")+v.to_s}*",",
27
- # "^^^^"
28
- h[*a]
29
- #super(*a)
30
- end
31
-
32
- def size
33
- h.size
34
- end
35
-
36
- def each &b
37
- h.each &b
38
- end
39
-
40
- def map &b
41
- h.map &b
42
- end
43
-
44
- def detect &b
45
- r = h.detect &b
46
- r ? r[1] : nil
47
- end
48
-
49
- # Return an array of all the instances of this concept
50
- def values
51
- h.values
52
- end
53
-
54
- # Return an array of the identifying role values arrays for all the instances of this concept
55
- def keys
56
- h.keys
57
- end
58
-
59
- def delete_if(&b) #:nodoc:
60
- h.delete_if &b
61
- end
62
-
63
- private
64
- def h
65
- @hash ||= {}
66
- end
67
-
68
- def naked(o)
69
- case o
70
- when Array
71
- o.map{|e| naked(e) }
72
- when RoleProxy
73
- o.__getobj__
74
- else
75
- o
76
- end
77
- end
78
- end
79
- end
80
- end