activefacts-generators 1.8.3 → 1.9.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.
@@ -18,7 +18,7 @@ module ActiveFacts
18
18
  private
19
19
  def vocabulary_start
20
20
  puts "vocabulary #{@vocabulary.name};\n\n"
21
- build_indices
21
+ build_indices
22
22
  end
23
23
 
24
24
  def vocabulary_end
@@ -29,7 +29,7 @@ module ActiveFacts
29
29
  end
30
30
 
31
31
  def unit_dump unit
32
- puts unit.as_cql
32
+ puts unit.as_cql
33
33
  end
34
34
 
35
35
  def units_end
@@ -45,7 +45,7 @@ module ActiveFacts
45
45
  end
46
46
 
47
47
  def data_type_dump(o)
48
- value_type_dump(o, o.name, {}) if o.all_role.size > 0
48
+ value_type_dump(o, o.name, {}) if o.all_role.size > 0
49
49
  end
50
50
 
51
51
  def value_type_dump(o, super_type_name, facets)
@@ -54,22 +54,22 @@ module ActiveFacts
54
54
 
55
55
  # REVISIT: A ValueType that is only used as a reference mode need not be emitted here.
56
56
 
57
- puts o.as_cql
57
+ puts o.as_cql
58
58
  end
59
59
 
60
60
  def entity_type_dump(o)
61
- o.ordered_dumped!
62
- pi = o.preferred_identifier
63
-
64
- supers = o.supertypes
65
- if (supers.size > 0)
66
- # Ignore identification by a supertype:
67
- pi = nil if pi && pi.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) }
68
- subtype_dump(o, supers, pi)
69
- else
70
- non_subtype_dump(o, pi)
71
- end
72
- pi.ordered_dumped! if pi
61
+ o.ordered_dumped!
62
+ pi = o.preferred_identifier
63
+
64
+ supers = o.supertypes
65
+ if (supers.size > 0)
66
+ # Ignore identification by a supertype:
67
+ pi = nil if pi && pi.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) }
68
+ subtype_dump(o, supers, pi)
69
+ else
70
+ non_subtype_dump(o, pi)
71
+ end
72
+ pi.ordered_dumped! if pi
73
73
  end
74
74
 
75
75
  def append_ring_to_reading(reading, ring)
@@ -193,9 +193,9 @@ module ActiveFacts
193
193
  end
194
194
  (entity_type.is_independent ? ' independent' : '') +
195
195
  " identified by its #{value_residual}#{constraint_text}#{mapping_pragma(entity_type, true)}" +
196
- entity_type.concept.all_context_note_as_relevant_concept.map do |cn|
197
- cn.verbalise
198
- end.join("\n") +
196
+ entity_type.concept.all_context_note_as_relevant_concept.map do |cn|
197
+ cn.verbalise
198
+ end.join("\n") +
199
199
  (fact_readings.size > 0 ? " where\n\t" : "") +
200
200
  fact_readings*",\n\t"
201
201
  end
@@ -230,9 +230,9 @@ module ActiveFacts
230
230
  (entity_type.is_independent ? ' independent' : '') +
231
231
  " identified by #{ irn*" and " }" +
232
232
  mapping_pragma(entity_type, true) +
233
- entity_type.concept.all_context_note_as_relevant_concept.map do |cn|
234
- cn.verbalise
235
- end.join("\n") +
233
+ entity_type.concept.all_context_note_as_relevant_concept.map do |cn|
234
+ cn.verbalise
235
+ end.join("\n") +
236
236
  " where\n\t"+identifying_fact_text
237
237
  end
238
238
 
@@ -294,8 +294,8 @@ module ActiveFacts
294
294
  # Alternate identification of objectified fact type?
295
295
  primary_supertype = supertypes[0]
296
296
  if fact_type.all_role.size > 1 and
297
- pi = fact_type.entity_type.preferred_identifier and
298
- primary_supertype && primary_supertype.preferred_identifier != pi
297
+ pi = fact_type.entity_type.preferred_identifier and
298
+ primary_supertype && primary_supertype.preferred_identifier != pi
299
299
  puts identified_by(o, pi) + ';'
300
300
  return
301
301
  end
@@ -369,7 +369,7 @@ module ActiveFacts
369
369
  if role_proximity == :proximate
370
370
  verbaliser.role_refs_have_subtype_steps(c.role_sequence)
371
371
  else
372
- roles = c.role_sequence.all_role_ref.map{|rr|rr.role}
372
+ roles = c.role_sequence.all_role_ref.map{|rr|rr.role}
373
373
  join_over, joined_roles = ActiveFacts::Metamodel.plays_over(roles, role_proximity)
374
374
  verbaliser.roles_have_same_player(joined_roles) if join_over
375
375
  end
@@ -514,18 +514,18 @@ module ActiveFacts
514
514
  end
515
515
 
516
516
  def constraint_dump(c)
517
- case c
518
- when ActiveFacts::Metamodel::PresenceConstraint
519
- dump_presence_constraint(c)
520
- when ActiveFacts::Metamodel::RingConstraint
521
- dump_ring_constraint(c)
522
- when ActiveFacts::Metamodel::SetComparisonConstraint # includes SetExclusionConstraint, SetEqualityConstraint
523
- dump_set_comparison_constraint(c)
524
- when ActiveFacts::Metamodel::SubsetConstraint
525
- dump_subset_constraint(c)
526
- else
527
- "#{c.class.basename} #{c.name}: unhandled constraint type"
528
- end
517
+ case c
518
+ when ActiveFacts::Metamodel::PresenceConstraint
519
+ dump_presence_constraint(c)
520
+ when ActiveFacts::Metamodel::RingConstraint
521
+ dump_ring_constraint(c)
522
+ when ActiveFacts::Metamodel::SetComparisonConstraint # includes SetExclusionConstraint, SetEqualityConstraint
523
+ dump_set_comparison_constraint(c)
524
+ when ActiveFacts::Metamodel::SubsetConstraint
525
+ dump_subset_constraint(c)
526
+ else
527
+ "#{c.class.basename} #{c.name}: unhandled constraint type"
528
+ end
529
529
  end
530
530
 
531
531
  # Find the common supertype of these object_types.
@@ -586,7 +586,7 @@ module ActiveFacts
586
586
  end
587
587
 
588
588
  expanded = verbaliser.expand_reading(reading, frequency_constraints, define_role_names, value_constraints)
589
- expanded = "it is not the case that "+expanded if (reading.is_negative)
589
+ expanded = "it is not the case that "+expanded if (reading.is_negative)
590
590
 
591
591
  if (ft_rings = @ring_constraints_by_fact[reading.fact_type]) &&
592
592
  (ring = ft_rings.detect{|rc| !rc.ordered_dumped})
@@ -608,29 +608,29 @@ module ActiveFacts
608
608
  end
609
609
  frequency_constraints = [] unless frequency_constraints.detect{|fc| fc[0] != "some" }
610
610
 
611
- expanded = verbaliser.expand_reading(reading, frequency_constraints)
612
- expanded = "it is not the case that "+expanded if (reading.is_negative)
613
- expanded
611
+ expanded = verbaliser.expand_reading(reading, frequency_constraints)
612
+ expanded = "it is not the case that "+expanded if (reading.is_negative)
613
+ expanded
614
614
  end
615
615
 
616
616
  def build_indices
617
- @presence_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
618
- @ring_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
619
-
620
- @vocabulary.all_constraint.each { |c|
621
- case c
622
- when ActiveFacts::Metamodel::PresenceConstraint
623
- fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq # All fact types spanned by this constraint
624
- if fact_types.size == 1 # There's only one, save it:
625
- # trace "Single-fact constraint on #{fact_types[0].concept.guid}: #{c.name}"
626
- (@presence_constraints_by_fact[fact_types[0]] ||= []) << c
627
- end
628
- when ActiveFacts::Metamodel::RingConstraint
629
- (@ring_constraints_by_fact[c.role.fact_type] ||= []) << c
630
- else
631
- # trace "Found unhandled constraint #{c.class} #{c.name}"
632
- end
633
- }
617
+ @presence_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
618
+ @ring_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
619
+
620
+ @vocabulary.all_constraint.each { |c|
621
+ case c
622
+ when ActiveFacts::Metamodel::PresenceConstraint
623
+ fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq # All fact types spanned by this constraint
624
+ if fact_types.size == 1 # There's only one, save it:
625
+ # trace "Single-fact constraint on #{fact_types[0].concept.guid}: #{c.name}"
626
+ (@presence_constraints_by_fact[fact_types[0]] ||= []) << c
627
+ end
628
+ when ActiveFacts::Metamodel::RingConstraint
629
+ (@ring_constraints_by_fact[c.role.fact_type] ||= []) << c
630
+ else
631
+ # trace "Found unhandled constraint #{c.class} #{c.name}"
632
+ end
633
+ }
634
634
  end
635
635
 
636
636
  end
@@ -655,12 +655,12 @@ module ActiveFacts
655
655
  }#{
656
656
  unit && " "+unit.name
657
657
  }#{
658
- transaction_phase && " auto-assigned at "+transaction_phase
658
+ transaction_phase && " auto-assigned at "+transaction_phase
659
+ }#{
660
+ concept.all_context_note_as_relevant_concept.map do |cn|
661
+ cn.verbalise
662
+ end.join("\n")
659
663
  }#{
660
- concept.all_context_note_as_relevant_concept.map do |cn|
661
- cn.verbalise
662
- end.join("\n")
663
- }#{
664
664
  value_constraint && " "+value_constraint.describe
665
665
  };"
666
666
  end
@@ -675,20 +675,20 @@ module ActiveFacts
675
675
 
676
676
  if d = coefficient.denominator and d != 1
677
677
  "/#{d}"
678
- else
679
- ''
678
+ else
679
+ ''
680
680
  end +
681
681
 
682
682
  ' '
683
683
  else
684
684
  '1 '
685
685
  end
686
- else
687
- ''
686
+ else
687
+ ''
688
688
  end +
689
689
 
690
- all_derivation_as_derived_unit.
691
- sort_by{|d| d.base_unit.name}.
690
+ all_derivation_as_derived_unit.
691
+ sort_by{|d| d.base_unit.name}.
692
692
  # REVISIT: Sort base units
693
693
  # REVISIT: convert negative powers to division?
694
694
  map do |der|
@@ -698,15 +698,15 @@ module ActiveFacts
698
698
 
699
699
  if o = offset and o != 0
700
700
  "+ #{o.to_s('F')} "
701
- else
702
- ''
701
+ else
702
+ ''
703
703
  end +
704
704
 
705
705
  "converts to #{name}#{plural_name ? '/'+plural_name : ''}" +
706
706
 
707
- (coefficient && !coefficient.is_precise ? ' approximately' : '') +
707
+ (coefficient && !coefficient.is_precise ? ' approximately' : '') +
708
708
 
709
- (ephemera_url ? " ephemera #{ephemera_url}" : '') +
709
+ (ephemera_url ? " ephemera #{ephemera_url}" : '') +
710
710
 
711
711
  ';'
712
712
  end
@@ -16,322 +16,322 @@ module ActiveFacts
16
16
  # afgen --diagrams/json <file>.cql=diagrams
17
17
  class JSON
18
18
  private
19
- def initialize(vocabulary)
20
- @vocabulary = vocabulary
21
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
22
- end
19
+ def initialize(vocabulary)
20
+ @vocabulary = vocabulary
21
+ @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
22
+ end
23
23
 
24
- def puts(*a)
25
- @out.puts *a
26
- end
24
+ def puts(*a)
25
+ @out.puts *a
26
+ end
27
27
 
28
28
  public
29
- def generate(out = $>)
30
- @out = out
31
- uuids = {}
32
-
33
- puts "{ model: '#{@vocabulary.name}',\n" +
34
- "diagrams: [\n#{
35
- @vocabulary.all_diagram.sort_by{|o| o.name.gsub(/ /,'')}.map do |d|
36
- j = {:uuid => (uuids[d] ||= uuid_from_id(d)), :name => d.name}
37
- " #{j.to_json}"
38
- end*",\n"
39
- }\n ],"
40
-
41
- object_types = @vocabulary.all_object_type.sort_by{|o| o.name.gsub(/ /,'')}
42
- puts " object_types: [\n#{
43
- object_types.sort_by{|o|o.identifying_role_values.inspect}.map do |o|
44
- uuids[o] ||= uuid_from_id(o)
45
- ref_mode = nil
46
- if o.is_a?(ActiveFacts::Metamodel::EntityType) and
47
- p = o.preferred_identifier and
48
- (rrs = p.role_sequence.all_role_ref).size == 1 and
49
- !(o.fact_type && o.fact_type.all_role.size == 1) and
50
- (r = rrs.single.role).fact_type != o.fact_type and
51
- r.object_type.is_a?(ActiveFacts::Metamodel::ValueType) and
52
- !r.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
53
- ref_mode = "#{r.object_type.name}"
54
- ref_mode.sub!(%r{#{o.name} *}, '.')
55
- end
56
- j = {
57
- :uuid => uuids[o],
58
- :name => o.name,
59
- :shapes => o.all_object_type_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
60
- x = { :diagram => uuids[shape.orm_diagram],
61
- :is_expanded => shape.is_expanded,
62
- :uuid => uuid_from_id(shape),
63
- :x => shape.location.x,
64
- :y => shape.location.y
65
- }
66
- x[:is_expanded] = true if ref_mode && shape.is_expanded # Don't show the reference mode
67
- x
68
- end
69
- }
70
- j[:ref_mode] = ref_mode if ref_mode
71
- j[:independent] = true if o.is_independent
72
-
73
- if o.is_a?(ActiveFacts::Metamodel::EntityType)
74
- # Entity Type may be objectified, and may have supertypes:
75
- if o.fact_type
76
- uuid = (uuids[o.fact_type] ||= uuid_from_id(o.fact_type))
77
- j[:objectifies] = uuid
78
- j[:implicit] = true if o.concept.implication_rule
79
- end
80
- if o.all_type_inheritance_as_subtype.size > 0
81
- j[:supertypes] = o.
82
- all_type_inheritance_as_subtype.
83
- sort_by{|ti| ti.provides_identification ? 0 : 1}.
84
- map{|ti|
85
- [ uuids[ti.supertype] ||= uuid_from_id(ti.supertype),
86
- uuids[ti.supertype_role] = uuid_from_id(ti.supertype_role)
87
- ]
88
- }
89
- end
90
- else
91
- # ValueType usually has a supertype:
92
- if (o.supertype)
93
- j[:supertype] = (uuids[o.supertype] ||= uuid_from_id(o.supertype))
94
- end
95
- end
96
- # REVISIT: Place a ValueConstraint and shape
97
- " #{j.to_json}"
98
- end*",\n"
99
- }\n ],"
100
-
101
- fact_types = @vocabulary.constellation.
102
- FactType.values.
103
- reject{|ft|
104
- ActiveFacts::Metamodel::LinkFactType === ft || ActiveFacts::Metamodel::TypeInheritance === ft
105
- }
106
- puts " fact_types: [\n#{
107
- fact_types.sort_by{|f| f.identifying_role_values.inspect}.map do |f|
108
- uuids[f] ||= uuid_from_id(f)
109
- j = {:uuid => uuids[f]}
110
-
111
- if f.entity_type
112
- j[:objectified_as] = uuids[f.entity_type]
113
- end
114
-
115
- # Emit roles
116
- roles = f.all_role.sort_by{|r| r.ordinal }
117
- j[:roles] = roles.map do |role|
118
- uuid = (uuids[role] ||= uuid_from_id(role))
119
- # REVISIT: Internal Mandatory Constraints
120
- # REVISIT: Place a ValueConstraint and shape
121
- # REVISIT: Place a RoleName shape
122
- {:uuid => uuid, :player => uuids[role.object_type]}
123
- # N.B. The object_type shape to which this role is attached is not in the meta-model
124
- # Attach to the closest instance on this diagram (if any)
125
- end
126
-
127
- # Emit readings. Each is a [role_order, text] pair
128
- j[:readings] = f.all_reading.map do |r|
129
- role_refs = r.role_sequence.all_role_ref_in_order
130
- [
131
- role_order(uuids, role_refs.map{|rr| rr.role}, roles),
132
- r.text.gsub(/\{([0-9])\}/) do |insert|
133
- role_ref = role_refs[$1.to_i]
134
- la = role_ref.leading_adjective
135
- la = nil if la == ''
136
- ta = role_ref.trailing_adjective
137
- ta = nil if ta == ''
138
- (la ? la+'-' : '') +
139
- (la && la.index(' ') ? ' ' : '') +
140
- insert +
141
- (ta && ta.index(' ') ? ' ' : '') +
142
- (ta ? '-'+ta : '')
143
- end
144
- ]
145
- end.sort_by{|(ro,text)| ro }.map do |(ro,text)|
146
- [ ro, text ]
147
- end
148
-
149
- # Emit shapes
150
- j[:shapes] = f.all_fact_type_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
151
- sj = {
152
- :diagram => uuids[shape.orm_diagram],
153
- :uuid => uuid_from_id(shape),
154
- :x => shape.location.x,
155
- :y => shape.location.y
156
- }
157
-
158
- # Add the role_order, if specified
159
- if shape.all_role_display.size > 0
160
- if shape.all_role_display.size != roles.size
161
- raise "Invalid RoleDisplay for #{f.default_reading} in #{shape.orm_diagram.name} diagram"
162
- end
163
- ro = role_order(
164
- uuids,
165
- shape.all_role_display.sort_by{|rd| rd.ordinal }.map{|rd| rd.role },
166
- roles
167
- )
168
- sj[:role_order] = ro if ro
169
- end
170
-
171
- # REVISIT: Place the ReadingShape
172
-
173
- # Emit the location of the name, if objectified
174
- if n = shape.objectified_fact_type_name_shape
175
- sj[:name_shape] = {:x => n.location.x, :y => n.location.y}
176
- end
177
- sj
178
- end
179
-
180
- # Emit Internal Presence Constraints
181
- f.internal_presence_constraints.to_a.sort_by{|ipc, z|
182
- [ipc.is_preferred_identifier ? 0 : 1, ipc.is_mandatory ? 0 : 1, ipc.min_frequency || 0, ipc.max_frequency || 1_000]
183
- }.each do |ipc|
184
- uuid = (uuids[ipc] ||= uuid_from_id(ipc))
185
-
186
- constraint = {
187
- :uuid => uuid,
188
- :min => ipc.min_frequency,
189
- :max => ipc.max_frequency,
190
- :is_preferred => ipc.is_preferred_identifier,
191
- :mandatory => ipc.is_mandatory
192
- }
193
-
194
- # Get the role (or excluded role, for a UC)
195
- roles = ipc.role_sequence.all_role_ref_in_order.map{|r| r.role}
196
- if roles.size > 1 || (!ipc.is_mandatory && ipc.max_frequency == 1)
197
- # This can be only a uniqueness constraint. Record the missing role, if any
198
- role = (f.all_role.to_a - roles)[0]
199
- constraint[:uniqueExcept] = uuids[role]
200
- else
201
- # An internal mandatory or frequency constraint applies to only one role.
202
- # If it's also unique (max == 1), that applies on the counterpart role.
203
- # You can also have a mandatory frequency constraint, but that applies on this role.
204
- constraint[:role] = uuids[roles[0]]
205
- end
206
- (j[:constraints] ||= []) << constraint
207
- end
208
-
209
- # Add ring constraints
210
- f.all_role_in_order.
211
- map{|r| r.all_ring_constraint.to_a+r.all_ring_constraint_as_other_role.to_a }.
212
- flatten.uniq.each do |ring|
213
- (j[:constraints] ||= []) << {
214
- :uuid => (uuids[ring] ||= uuid_from_id(ring)),
215
- :shapes => ring.all_constraint_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
216
- { :diagram => uuids[shape.orm_diagram],
217
- :uuid => uuid_from_id(shape),
218
- :x => shape.location.x,
219
- :y => shape.location.y
220
- }
221
- end,
222
- :ringKind => ring.ring_type,
223
- :roles => [uuids[ring.role], uuids[ring.other_role]]
224
- # REVISIT: Deontic, enforcement
225
- }
226
- end
227
-
228
- # REVISIT: RotationSetting
229
-
230
- " #{j.to_json}"
231
- end*",\n"
232
- }\n ],"
233
-
234
- constraints = @vocabulary.constellation.
235
- Constraint.values
236
- puts " constraints: [\n#{
237
- constraints.sort_by{|c|c.identifying_role_values.inspect}.select{|c| !uuids[c]}.map do |c|
238
- uuid = uuids[c] ||= uuid_from_id(c)
239
- j = {
240
- :uuid => uuid,
241
- :type => c.class.basename,
242
- :shapes => c.all_constraint_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
243
- { :diagram => uuids[shape.orm_diagram],
244
- :uuid => uuid_from_id(shape),
245
- :x => shape.location.x,
246
- :y => shape.location.y
247
- }
248
- end
249
- }
250
-
251
- if (c.enforcement)
252
- # REVISIT: Deontic constraint
253
- end
254
- if (c.concept.all_context_note_as_relevant_concept.size > 0)
255
- # REVISIT: Context Notes
256
- end
257
-
258
- case c
259
- when ActiveFacts::Metamodel::PresenceConstraint
260
- j[:min_frequency] = c.min_frequency
261
- j[:max_frequency] = c.max_frequency
262
- j[:is_mandatory] = c.is_mandatory
263
- j[:is_preferred_identifier] = c.is_preferred_identifier
264
- rss = [c.role_sequence.all_role_ref_in_order.map(&:role)]
265
-
266
- # Ignore internal presence constraints on TypeInheritance fact types
267
- next nil if !c.role_sequence.all_role_ref.
268
- detect{|rr|
269
- !rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
270
- }
271
-
272
- when ActiveFacts::Metamodel::RingConstraint
273
- next nil # These are emitted with the corresponding fact type
274
-
275
- when ActiveFacts::Metamodel::SetComparisonConstraint
276
- rss = c.
277
- all_set_comparison_roles.sort_by{|scr| scr.ordinal}.
278
- map{|scr| scr.role_sequence.all_role_ref_in_order.map(&:role) }
279
- if (ActiveFacts::Metamodel::SetExclusionConstraint === c)
280
- j[:is_mandatory] = c.is_mandatory
281
- end
282
-
283
- when ActiveFacts::Metamodel::SubsetConstraint
284
- rss = [c.subset_role_sequence, c.superset_role_sequence].
285
- map{|rs| rs.all_role_ref_in_order.map(&:role) }
286
-
287
- when ActiveFacts::Metamodel::ValueConstraint
288
- next nil # REVISIT: Should have been handled elsewhere
289
- if (c.role)
290
- # Should have been handled as role.role_value_constraint
291
- elsif (c.value_type)
292
- # Should have been handled as object_type.value_constraint
293
- end
294
- j[:allowed_ranges] = c.all_allowed_range.map{|ar|
295
- [ ar.value_range.minimum_bound, ar.value_range.maximum_bound ].
296
- map{|b| [b.value.literal, b.value.unit.name, b.is_inclusive] }
297
- }
298
-
299
- else
300
- raise "REVISIT: Constraint type not yet dumped to JSON"
301
- end
302
-
303
- # rss contains the constrained role sequences; map to uuids
304
- j[:role_sequences] = rss.map{|rs|
305
- rs.map do |role|
306
- uuids[role]
307
- end
308
- }
309
-
310
- " #{j.to_json}"
311
- end.compact*",\n"
312
- }\n ]"
313
-
314
- puts "}"
315
- end
316
-
317
- def role_order(uuids, roles, order)
318
- if (roles.size > 9)
319
- roles.map{|r| uuids[r] }
320
- else
321
- roles.map{|r| order.index(r).to_s }*''
322
- end
323
- end
324
-
325
- def uuid_from_id o
326
- irvs = o.identifying_role_values.inspect
327
- d = Digest::SHA1.digest irvs
328
- # $stderr.puts "#{o.class.basename}: #{irvs}"
329
- d[0,4].unpack("H8")[0]+'-'+
330
- d[4,2].unpack("H4")[0]+'-'+
331
- d[6,2].unpack("H4")[0]+'-'+
332
- d[8,2].unpack("H4")[0]+'-'+
333
- d[10,6].unpack("H6")[0]
334
- end
29
+ def generate(out = $>)
30
+ @out = out
31
+ uuids = {}
32
+
33
+ puts "{ model: '#{@vocabulary.name}',\n" +
34
+ "diagrams: [\n#{
35
+ @vocabulary.all_diagram.sort_by{|o| o.name.gsub(/ /,'')}.map do |d|
36
+ j = {:uuid => (uuids[d] ||= uuid_from_id(d)), :name => d.name}
37
+ " #{j.to_json}"
38
+ end*",\n"
39
+ }\n ],"
40
+
41
+ object_types = @vocabulary.all_object_type.sort_by{|o| o.name.gsub(/ /,'')}
42
+ puts " object_types: [\n#{
43
+ object_types.sort_by{|o|o.identifying_role_values.inspect}.map do |o|
44
+ uuids[o] ||= uuid_from_id(o)
45
+ ref_mode = nil
46
+ if o.is_a?(ActiveFacts::Metamodel::EntityType) and
47
+ p = o.preferred_identifier and
48
+ (rrs = p.role_sequence.all_role_ref).size == 1 and
49
+ !(o.fact_type && o.fact_type.all_role.size == 1) and
50
+ (r = rrs.single.role).fact_type != o.fact_type and
51
+ r.object_type.is_a?(ActiveFacts::Metamodel::ValueType) and
52
+ !r.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
53
+ ref_mode = "#{r.object_type.name}"
54
+ ref_mode.sub!(%r{#{o.name} *}, '.')
55
+ end
56
+ j = {
57
+ :uuid => uuids[o],
58
+ :name => o.name,
59
+ :shapes => o.all_object_type_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
60
+ x = { :diagram => uuids[shape.orm_diagram],
61
+ :is_expanded => shape.is_expanded,
62
+ :uuid => uuid_from_id(shape),
63
+ :x => shape.location.x,
64
+ :y => shape.location.y
65
+ }
66
+ x[:is_expanded] = true if ref_mode && shape.is_expanded # Don't show the reference mode
67
+ x
68
+ end
69
+ }
70
+ j[:ref_mode] = ref_mode if ref_mode
71
+ j[:independent] = true if o.is_independent
72
+
73
+ if o.is_a?(ActiveFacts::Metamodel::EntityType)
74
+ # Entity Type may be objectified, and may have supertypes:
75
+ if o.fact_type
76
+ uuid = (uuids[o.fact_type] ||= uuid_from_id(o.fact_type))
77
+ j[:objectifies] = uuid
78
+ j[:implicit] = true if o.concept.implication_rule
79
+ end
80
+ if o.all_type_inheritance_as_subtype.size > 0
81
+ j[:supertypes] = o.
82
+ all_type_inheritance_as_subtype.
83
+ sort_by{|ti| ti.provides_identification ? 0 : 1}.
84
+ map{|ti|
85
+ [ uuids[ti.supertype] ||= uuid_from_id(ti.supertype),
86
+ uuids[ti.supertype_role] = uuid_from_id(ti.supertype_role)
87
+ ]
88
+ }
89
+ end
90
+ else
91
+ # ValueType usually has a supertype:
92
+ if (o.supertype)
93
+ j[:supertype] = (uuids[o.supertype] ||= uuid_from_id(o.supertype))
94
+ end
95
+ end
96
+ # REVISIT: Place a ValueConstraint and shape
97
+ " #{j.to_json}"
98
+ end*",\n"
99
+ }\n ],"
100
+
101
+ fact_types = @vocabulary.constellation.
102
+ FactType.values.
103
+ reject{|ft|
104
+ ActiveFacts::Metamodel::LinkFactType === ft || ActiveFacts::Metamodel::TypeInheritance === ft
105
+ }
106
+ puts " fact_types: [\n#{
107
+ fact_types.sort_by{|f| f.identifying_role_values.inspect}.map do |f|
108
+ uuids[f] ||= uuid_from_id(f)
109
+ j = {:uuid => uuids[f]}
110
+
111
+ if f.entity_type
112
+ j[:objectified_as] = uuids[f.entity_type]
113
+ end
114
+
115
+ # Emit roles
116
+ roles = f.all_role.sort_by{|r| r.ordinal }
117
+ j[:roles] = roles.map do |role|
118
+ uuid = (uuids[role] ||= uuid_from_id(role))
119
+ # REVISIT: Internal Mandatory Constraints
120
+ # REVISIT: Place a ValueConstraint and shape
121
+ # REVISIT: Place a RoleName shape
122
+ {:uuid => uuid, :player => uuids[role.object_type]}
123
+ # N.B. The object_type shape to which this role is attached is not in the meta-model
124
+ # Attach to the closest instance on this diagram (if any)
125
+ end
126
+
127
+ # Emit readings. Each is a [role_order, text] pair
128
+ j[:readings] = f.all_reading.map do |r|
129
+ role_refs = r.role_sequence.all_role_ref_in_order
130
+ [
131
+ role_order(uuids, role_refs.map{|rr| rr.role}, roles),
132
+ r.text.gsub(/\{([0-9])\}/) do |insert|
133
+ role_ref = role_refs[$1.to_i]
134
+ la = role_ref.leading_adjective
135
+ la = nil if la == ''
136
+ ta = role_ref.trailing_adjective
137
+ ta = nil if ta == ''
138
+ (la ? la+'-' : '') +
139
+ (la && la.index(' ') ? ' ' : '') +
140
+ insert +
141
+ (ta && ta.index(' ') ? ' ' : '') +
142
+ (ta ? '-'+ta : '')
143
+ end
144
+ ]
145
+ end.sort_by{|(ro,text)| ro }.map do |(ro,text)|
146
+ [ ro, text ]
147
+ end
148
+
149
+ # Emit shapes
150
+ j[:shapes] = f.all_fact_type_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
151
+ sj = {
152
+ :diagram => uuids[shape.orm_diagram],
153
+ :uuid => uuid_from_id(shape),
154
+ :x => shape.location.x,
155
+ :y => shape.location.y
156
+ }
157
+
158
+ # Add the role_order, if specified
159
+ if shape.all_role_display.size > 0
160
+ if shape.all_role_display.size != roles.size
161
+ raise "Invalid RoleDisplay for #{f.default_reading} in #{shape.orm_diagram.name} diagram"
162
+ end
163
+ ro = role_order(
164
+ uuids,
165
+ shape.all_role_display.sort_by{|rd| rd.ordinal }.map{|rd| rd.role },
166
+ roles
167
+ )
168
+ sj[:role_order] = ro if ro
169
+ end
170
+
171
+ # REVISIT: Place the ReadingShape
172
+
173
+ # Emit the location of the name, if objectified
174
+ if n = shape.objectified_fact_type_name_shape
175
+ sj[:name_shape] = {:x => n.location.x, :y => n.location.y}
176
+ end
177
+ sj
178
+ end
179
+
180
+ # Emit Internal Presence Constraints
181
+ f.internal_presence_constraints.to_a.sort_by{|ipc, z|
182
+ [ipc.is_preferred_identifier ? 0 : 1, ipc.is_mandatory ? 0 : 1, ipc.min_frequency || 0, ipc.max_frequency || 1_000]
183
+ }.each do |ipc|
184
+ uuid = (uuids[ipc] ||= uuid_from_id(ipc))
185
+
186
+ constraint = {
187
+ :uuid => uuid,
188
+ :min => ipc.min_frequency,
189
+ :max => ipc.max_frequency,
190
+ :is_preferred => ipc.is_preferred_identifier,
191
+ :mandatory => ipc.is_mandatory
192
+ }
193
+
194
+ # Get the role (or excluded role, for a UC)
195
+ roles = ipc.role_sequence.all_role_ref_in_order.map{|r| r.role}
196
+ if roles.size > 1 || (!ipc.is_mandatory && ipc.max_frequency == 1)
197
+ # This can be only a uniqueness constraint. Record the missing role, if any
198
+ role = (f.all_role.to_a - roles)[0]
199
+ constraint[:uniqueExcept] = uuids[role]
200
+ else
201
+ # An internal mandatory or frequency constraint applies to only one role.
202
+ # If it's also unique (max == 1), that applies on the counterpart role.
203
+ # You can also have a mandatory frequency constraint, but that applies on this role.
204
+ constraint[:role] = uuids[roles[0]]
205
+ end
206
+ (j[:constraints] ||= []) << constraint
207
+ end
208
+
209
+ # Add ring constraints
210
+ f.all_role_in_order.
211
+ map{|r| r.all_ring_constraint.to_a+r.all_ring_constraint_as_other_role.to_a }.
212
+ flatten.uniq.each do |ring|
213
+ (j[:constraints] ||= []) << {
214
+ :uuid => (uuids[ring] ||= uuid_from_id(ring)),
215
+ :shapes => ring.all_constraint_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
216
+ { :diagram => uuids[shape.orm_diagram],
217
+ :uuid => uuid_from_id(shape),
218
+ :x => shape.location.x,
219
+ :y => shape.location.y
220
+ }
221
+ end,
222
+ :ringKind => ring.ring_type,
223
+ :roles => [uuids[ring.role], uuids[ring.other_role]]
224
+ # REVISIT: Deontic, enforcement
225
+ }
226
+ end
227
+
228
+ # REVISIT: RotationSetting
229
+
230
+ " #{j.to_json}"
231
+ end*",\n"
232
+ }\n ],"
233
+
234
+ constraints = @vocabulary.constellation.
235
+ Constraint.values
236
+ puts " constraints: [\n#{
237
+ constraints.sort_by{|c|c.identifying_role_values.inspect}.select{|c| !uuids[c]}.map do |c|
238
+ uuid = uuids[c] ||= uuid_from_id(c)
239
+ j = {
240
+ :uuid => uuid,
241
+ :type => c.class.basename,
242
+ :shapes => c.all_constraint_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
243
+ { :diagram => uuids[shape.orm_diagram],
244
+ :uuid => uuid_from_id(shape),
245
+ :x => shape.location.x,
246
+ :y => shape.location.y
247
+ }
248
+ end
249
+ }
250
+
251
+ if (c.enforcement)
252
+ # REVISIT: Deontic constraint
253
+ end
254
+ if (c.concept.all_context_note_as_relevant_concept.size > 0)
255
+ # REVISIT: Context Notes
256
+ end
257
+
258
+ case c
259
+ when ActiveFacts::Metamodel::PresenceConstraint
260
+ j[:min_frequency] = c.min_frequency
261
+ j[:max_frequency] = c.max_frequency
262
+ j[:is_mandatory] = c.is_mandatory
263
+ j[:is_preferred_identifier] = c.is_preferred_identifier
264
+ rss = [c.role_sequence.all_role_ref_in_order.map(&:role)]
265
+
266
+ # Ignore internal presence constraints on TypeInheritance fact types
267
+ next nil if !c.role_sequence.all_role_ref.
268
+ detect{|rr|
269
+ !rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
270
+ }
271
+
272
+ when ActiveFacts::Metamodel::RingConstraint
273
+ next nil # These are emitted with the corresponding fact type
274
+
275
+ when ActiveFacts::Metamodel::SetComparisonConstraint
276
+ rss = c.
277
+ all_set_comparison_roles.sort_by{|scr| scr.ordinal}.
278
+ map{|scr| scr.role_sequence.all_role_ref_in_order.map(&:role) }
279
+ if (ActiveFacts::Metamodel::SetExclusionConstraint === c)
280
+ j[:is_mandatory] = c.is_mandatory
281
+ end
282
+
283
+ when ActiveFacts::Metamodel::SubsetConstraint
284
+ rss = [c.subset_role_sequence, c.superset_role_sequence].
285
+ map{|rs| rs.all_role_ref_in_order.map(&:role) }
286
+
287
+ when ActiveFacts::Metamodel::ValueConstraint
288
+ next nil # REVISIT: Should have been handled elsewhere
289
+ if (c.role)
290
+ # Should have been handled as role.role_value_constraint
291
+ elsif (c.value_type)
292
+ # Should have been handled as object_type.value_constraint
293
+ end
294
+ j[:allowed_ranges] = c.all_allowed_range.map{|ar|
295
+ [ ar.value_range.minimum_bound, ar.value_range.maximum_bound ].
296
+ map{|b| [b.value.literal, b.value.unit.name, b.is_inclusive] }
297
+ }
298
+
299
+ else
300
+ raise "REVISIT: Constraint type not yet dumped to JSON"
301
+ end
302
+
303
+ # rss contains the constrained role sequences; map to uuids
304
+ j[:role_sequences] = rss.map{|rs|
305
+ rs.map do |role|
306
+ uuids[role]
307
+ end
308
+ }
309
+
310
+ " #{j.to_json}"
311
+ end.compact*",\n"
312
+ }\n ]"
313
+
314
+ puts "}"
315
+ end
316
+
317
+ def role_order(uuids, roles, order)
318
+ if (roles.size > 9)
319
+ roles.map{|r| uuids[r] }
320
+ else
321
+ roles.map{|r| order.index(r).to_s }*''
322
+ end
323
+ end
324
+
325
+ def uuid_from_id o
326
+ irvs = o.identifying_role_values.inspect
327
+ d = Digest::SHA1.digest irvs
328
+ # $stderr.puts "#{o.class.basename}: #{irvs}"
329
+ d[0,4].unpack("H8")[0]+'-'+
330
+ d[4,2].unpack("H4")[0]+'-'+
331
+ d[6,2].unpack("H4")[0]+'-'+
332
+ d[8,2].unpack("H4")[0]+'-'+
333
+ d[10,6].unpack("H6")[0]
334
+ end
335
335
 
336
336
  end
337
337
  end