activefacts 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,8 +26,11 @@ lib/activefacts/api/concept.rb
26
26
  lib/activefacts/api/constellation.rb
27
27
  lib/activefacts/api/entity.rb
28
28
  lib/activefacts/api/instance.rb
29
+ lib/activefacts/api/instance_index.rb
29
30
  lib/activefacts/api/numeric.rb
30
31
  lib/activefacts/api/role.rb
32
+ lib/activefacts/api/role_proxy.rb
33
+ lib/activefacts/api/role_values.rb
31
34
  lib/activefacts/api/standard_types.rb
32
35
  lib/activefacts/api/support.rb
33
36
  lib/activefacts/api/value.rb
@@ -55,6 +58,7 @@ lib/activefacts/input/cql.rb
55
58
  lib/activefacts/input/orm.rb
56
59
  lib/activefacts/persistence.rb
57
60
  lib/activefacts/persistence/columns.rb
61
+ lib/activefacts/persistence/concept.rb
58
62
  lib/activefacts/persistence/foreignkey.rb
59
63
  lib/activefacts/persistence/index.rb
60
64
  lib/activefacts/persistence/reference.rb
@@ -16,6 +16,7 @@ Length is defined as UnsignedInteger(32);
16
16
  Name is defined as VariableLengthText(64);
17
17
  Numerator is defined as Decimal();
18
18
  Ordinal is defined as UnsignedSmallInteger(32);
19
+ Pronoun is defined as VariableLengthText() restricted to {'feminine', 'masculine', 'personal'};
19
20
  RingType is defined as VariableLengthText();
20
21
  RoleSequenceId is defined as AutoCounter();
21
22
  Scale is defined as UnsignedInteger(32);
@@ -142,8 +143,8 @@ SetExclusionConstraint is mandatory;
142
143
  Alias is a kind of Feature;
143
144
 
144
145
  Concept is a kind of Feature;
146
+ Concept uses at most one Pronoun;
145
147
  Concept is independent;
146
- Concept is personal;
147
148
  Instance is of one Concept;
148
149
  Role is where
149
150
  FactType has Ordinal role played by Concept,
@@ -165,12 +166,12 @@ RoleRef is where
165
166
  Role has Ordinal place in RoleSequence;
166
167
  RoleRef has at most one leading-Adjective;
167
168
  RoleRef has at most one trailing-Adjective;
168
- JoinPath is where
169
- RoleRef has Ordinal (as JoinStep) path;
170
- JoinPath traverses at most one Concept,
171
- Concept is traversed by JoinPath;
172
- JoinPath has one input-Role;
173
- JoinPath has one output-Role;
169
+ Join is where
170
+ RoleRef has Ordinal (as JoinStep) join;
171
+ Join traverses at most one Concept,
172
+ Concept is traversed by Join;
173
+ Join has at most one input-Role;
174
+ Join has at most one output-Role;
174
175
 
175
176
  EntityType is a kind of Concept;
176
177
  EntityType nests at most one FactType,
@@ -227,6 +228,9 @@ each combination EntityType, TypeInheritance occurs at most one time in
227
228
  TypeInheritance provides identification;
228
229
  each FactType occurs at least one time in
229
230
  FactType has Ordinal role played by Concept;
231
+ each Join occurs at least one time in
232
+ Join has input-Role,
233
+ Join has output-Role;
230
234
  each PresenceConstraint occurs at least one time in
231
235
  PresenceConstraint has min-Frequency,
232
236
  PresenceConstraint has max-Frequency,
@@ -121,6 +121,10 @@ module ActiveFacts
121
121
  end
122
122
  end
123
123
 
124
+ def subtypes
125
+ @subtypes ||= []
126
+ end
127
+
124
128
  # Every new role added or inherited comes through here:
125
129
  def realise_role(role) #:nodoc:
126
130
  #puts "Realising role #{role.counterpart_concept.basename rescue role.counterpart_concept}.#{role.name} in #{basename}"
@@ -137,6 +141,10 @@ module ActiveFacts
137
141
 
138
142
  # REVISIT: Use method_missing to catch all_some_role_as_other_role_and_third_role, to sort_by those roles?
139
143
 
144
+ def is_a? klass
145
+ super || supertypes_transitive.include?(klass)
146
+ end
147
+
140
148
  private
141
149
 
142
150
  def realise_supertypes(concept, all_supertypes = nil)
@@ -146,6 +154,7 @@ module ActiveFacts
146
154
  s.each {|t|
147
155
  next if all_supertypes.include? t
148
156
  realise_supertypes(t, all_supertypes)
157
+ t.subtypes << self
149
158
  all_supertypes << t
150
159
  }
151
160
  #puts "Realising roles of #{concept.basename} in #{basename}"
@@ -174,6 +183,7 @@ module ActiveFacts
174
183
  else
175
184
  target.roles[related_role_name] = role.counterpart = Role.new(target, definer, role, related_role_name, false, false)
176
185
  end
186
+ role.counterpart_concept = target
177
187
  #puts "Realising role pair #{definer.basename}.#{role_name} <-> #{target.basename}.#{related_role_name}"
178
188
  realise_role(role)
179
189
  target.realise_role(role.counterpart)
@@ -219,6 +219,8 @@ module ActiveFacts
219
219
 
220
220
  def inherited(other) #:nodoc:
221
221
  other.identified_by *identifying_role_names
222
+ subtypes << other unless subtypes.include? other
223
+ #puts "#{self.name} inherited by #{other.name}"
222
224
  vocabulary.add_concept(other)
223
225
  end
224
226
 
@@ -0,0 +1,71 @@
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 map &b
37
+ h.map &b
38
+ end
39
+
40
+ # Return an array of all the instances of this concept
41
+ def values
42
+ h.values
43
+ end
44
+
45
+ # Return an array of the identifying role values arrays for all the instances of this concept
46
+ def keys
47
+ h.keys
48
+ end
49
+
50
+ def delete_if(&b) #:nodoc:
51
+ h.delete_if &b
52
+ end
53
+
54
+ private
55
+ def h
56
+ @hash ||= {}
57
+ end
58
+
59
+ def naked(o)
60
+ case o
61
+ when Array
62
+ o.map{|e| naked(e) }
63
+ when RoleProxy
64
+ o.__getobj__
65
+ else
66
+ o
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,70 @@
1
+ #
2
+ # ActiveFacts Runtime API
3
+ # RoleProxy class, still somewhat experimental
4
+ #
5
+ # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
+ #
7
+ require 'delegate'
8
+
9
+ module ActiveFacts
10
+ module API
11
+ #
12
+ # When you use the accessor method created by has_one, one_to_one, or maybe, you get a RoleProxy for the actual value.
13
+ # This behaves almost exactly as the value, but it knows through which role you fetched it.
14
+ # That will allow it to verbalise itself using the correct reading for that role.
15
+ #
16
+ # Don't use "SomeClass === role_value" to test the type, use "role_value.is_a?(SomeClass)" instead.
17
+ #
18
+ # In future, retrieving a value by indexing into a RoleValues array will do the same thing.
19
+ #
20
+ class RoleProxy < SimpleDelegator
21
+ def initialize(role, o = nil) #:nodoc:
22
+ @role = role # REVISIT: Use this to implement verbalise()
23
+ __setobj__(o)
24
+ end
25
+
26
+ def method_missing(m, *a, &b) #:nodoc:
27
+ begin
28
+ super # Delegate first
29
+ rescue NoMethodError => e
30
+ __getobj__.method_missing(m, *a, &b)
31
+ rescue => e
32
+ raise
33
+ end
34
+ end
35
+
36
+ def class #:nodoc:
37
+ __getobj__.class
38
+ end
39
+
40
+ def is_a? klass #:nodoc:
41
+ __getobj__.is_a? klass
42
+ end
43
+
44
+ def to_s #:nodoc:
45
+ __getobj__.to_s
46
+ end
47
+
48
+ def object_id #:nodoc:
49
+ __getobj__.object_id
50
+ end
51
+
52
+ # REVISIT: Should Proxies hash and eql? the same as their wards?
53
+ def hash #:nodoc:
54
+ __getobj__.hash ^ self.class.hash
55
+ end
56
+
57
+ def eql?(o) #:nodoc:
58
+ self.class == o.class and __getobj__.eql?(o)
59
+ end
60
+
61
+ def ==(o) #:nodoc:
62
+ __getobj__.==(o)
63
+ end
64
+
65
+ def inspect #:nodoc:
66
+ "Proxy:#{__getobj__.inspect}"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,117 @@
1
+ #
2
+ # ActiveFacts Runtime API
3
+ # RoleValues, manages the set of instances involved in a many_to_one relationship.
4
+ #
5
+ # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
+ #
7
+ # There are two implementations here, one using an array and one using a hash.
8
+ # The hash one has problems with keys being changed during object deletion, so
9
+ # cannot be used yet; a fix is upcoming and will improve performance of large sets.
10
+ #
11
+ module ActiveFacts
12
+ module API
13
+
14
+ class RoleValues #:nodoc:
15
+ include Enumerable
16
+
17
+ #=begin
18
+ def initialize
19
+ @a = []
20
+ end
21
+
22
+ def each &b
23
+ # REVISIT: Provide a configuration variable to enable this heckling during testing:
24
+ #@a.sort_by{rand}.each &b
25
+ @a.each &b
26
+ end
27
+
28
+ def size
29
+ @a.size
30
+ end
31
+
32
+ def empty?
33
+ @a.size == 0
34
+ end
35
+
36
+ def +(a)
37
+ @a.+(a.is_a?(RoleValues) ? Array(a) : a)
38
+ end
39
+
40
+ def -(a)
41
+ @a - a
42
+ end
43
+
44
+ def single
45
+ @a.size > 1 ? nil : @a[0]
46
+ end
47
+
48
+ def update(old, value)
49
+ @a.delete(old) if old
50
+ @a << value if value
51
+ raise "Adding RoleProxy to RoleValues collection" if value && RoleProxy === value
52
+ end
53
+
54
+ def verbalise
55
+ "["+@a.to_a.map{|e| e.verbalise}*", "+"]"
56
+ end
57
+ #=end
58
+
59
+ =begin
60
+ def initialize
61
+ @h = {}
62
+ end
63
+
64
+ def each &b
65
+ @h.keys.each &b
66
+ end
67
+
68
+ def size
69
+ @h.size
70
+ end
71
+
72
+ def empty?
73
+ @h.size == 0
74
+ end
75
+
76
+ def +(a)
77
+ @h.keys.+(a.is_a?(RoleValues) ? Array(a) : a)
78
+ end
79
+
80
+ def -(a)
81
+ @h.keys - a
82
+ end
83
+
84
+ def single
85
+ @h.size > 1 ? nil : @h.keys[0]
86
+ end
87
+
88
+ def update(old, value)
89
+ if old
90
+ unless @h.delete(old)
91
+ @h.each { |k, v|
92
+ next if k != old
93
+ puts "#{@h.object_id}: Didn't delete #{k.verbalise} (hash=#{k.hash}) matching #{old.verbalise} (hash=#{old.hash})"
94
+ puts "They are #{k.eql?(old) ? "" : "not "}eql?"
95
+ found = @h[k]
96
+ puts "found #{found.inspect}" if found
97
+ debugger
98
+ x = k.eql?(old)
99
+ y = old.eql?(k)
100
+ p y
101
+ }
102
+ raise "failed to delete #{old.verbalise}, have #{map{|e| e.verbalise}.inspect}"
103
+ end
104
+ end
105
+ puts "#{@h.object_id}: Adding #{value.inspect}" if value && (value.name == 'Meetingisboardmeeting' rescue false)
106
+ @h[value] = true if value
107
+ end
108
+
109
+ def verbalise
110
+ "["+@h.keys.map{|e| e.verbalise}*", "+"]"
111
+ end
112
+ =end
113
+
114
+ end
115
+
116
+ end
117
+ end
@@ -14,7 +14,7 @@ module ActiveFacts
14
14
  # afgen --absorption[=options] <file>.cql"
15
15
  # Options are comma or space separated:
16
16
  # * no_columns Don't emit the columns
17
- # * dependent Show Concepts that are not tables as well
17
+ # * all Show Concepts that are not tables as well
18
18
  # * paths Show the references paths through which each column was defined
19
19
  # * no_identifier Don't show the identified_by columns for an EntityType
20
20
 
@@ -25,7 +25,6 @@ module ActiveFacts
25
25
  @vocabulary = vocabulary
26
26
  @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
27
27
  @no_columns = options.include? "no_columns"
28
- @dependent = options.include? "dependent"
29
28
  @paths = options.include? "paths"
30
29
  @no_identifier = options.include? "no_identifier"
31
30
  end
@@ -38,39 +37,30 @@ module ActiveFacts
38
37
  multi_absorption_ets = 0
39
38
  @vocabulary.tables
40
39
  @vocabulary.all_feature.sort_by{|c| c.name}.each do |o|
41
- # Don't dump imported (base) ValueTypes:
42
- next if ValueType === o && !o.supertype
40
+ next if !o.is_table
43
41
  show(o)
44
42
  end
45
43
  end
46
44
 
47
45
  def show concept #:nodoc:
48
- return unless concept.is_table || @dependent
49
-
50
- print "#{concept.name}"
51
- print " (#{concept.tentative ? "tentatively " : ""}#{concept.is_table ? "in" : ""}dependent)" if @dependent
52
-
53
- if !@no_identifier && concept.is_a?(EntityType)
54
- print " is identified by:\n\t#{
55
- "REVISIT" # concept.references_from.to_s
56
- }"
57
- end
58
- print "\n"
59
-
60
- unless @no_columns
61
- puts "#{ concept.references_from.map do |role_ref|
62
- "\t#{role_ref.column_name(".")}\n"
63
- end*"" }"
64
- end
65
-
66
- if (@paths)
67
- ap = concept.absorption_paths
68
- puts "#{ ap.map {|role|
69
- prr = role.preferred_reference.describe
70
- player = role.fact_type.entity_type == concept ? role.concept : (role.fact_type.all_role-[role])[0].concept
71
- "\tcan absorb #{prr != role.concept.name ? "(via #{prr}) " : "" }into #{player.name}\n"
72
- }*"" }"
73
- end
46
+ indices = concept.indices
47
+ pk = indices.select(&:is_primary)[0]
48
+ indices = indices.clone
49
+ indices.delete pk
50
+ puts "#{concept.name}: #{
51
+ # "[#{concept.indices.size} indices] "
52
+ # } #{
53
+ concept.columns.sort_by do |column|
54
+ column.name(nil)
55
+ end.map do |column|
56
+ index_nrs =
57
+ [pk && pk.columns.include?(column) ? "*" : nil] +
58
+ (0...indices.size).select{|i| indices[i].columns.include?(column)}.map{|i| (i+1).to_i }
59
+ index_nrs.compact!
60
+ (@paths ? column.references.map{|r| r.to_names}.flatten : column.name(nil)) * "." +
61
+ (index_nrs.empty? ? "" : "["+index_nrs*""+"]")
62
+ end*", "
63
+ }"
74
64
 
75
65
  end
76
66
  end