activefacts 1.6.0 → 1.7.1

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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +60 -0
  8. data/Rakefile +3 -80
  9. data/activefacts.gemspec +36 -0
  10. data/bin/afgen +4 -2
  11. data/bin/cql +5 -1
  12. data/lib/activefacts.rb +3 -12
  13. data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
  14. data/lib/activefacts/version.rb +2 -2
  15. metadata +48 -296
  16. data/History.txt +0 -4
  17. data/LICENSE +0 -19
  18. data/Manifest.txt +0 -165
  19. data/README.rdoc +0 -81
  20. data/css/offline.css +0 -3
  21. data/css/orm2.css +0 -124
  22. data/css/print.css +0 -8
  23. data/css/style-print.css +0 -357
  24. data/css/style.css +0 -387
  25. data/download.html +0 -110
  26. data/examples/CQL/Address.cql +0 -44
  27. data/examples/CQL/Blog.cql +0 -54
  28. data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
  29. data/examples/CQL/Death.cql +0 -17
  30. data/examples/CQL/Diplomacy.cql +0 -48
  31. data/examples/CQL/Genealogy.cql +0 -98
  32. data/examples/CQL/Insurance.cql +0 -320
  33. data/examples/CQL/Marriage.cql +0 -18
  34. data/examples/CQL/Metamodel.cql +0 -493
  35. data/examples/CQL/Monogamy.cql +0 -24
  36. data/examples/CQL/MultiInheritance.cql +0 -22
  37. data/examples/CQL/NonRoleId.cql +0 -14
  38. data/examples/CQL/OddIdentifier.cql +0 -18
  39. data/examples/CQL/OilSupply.cql +0 -53
  40. data/examples/CQL/OneToOnes.cql +0 -17
  41. data/examples/CQL/Orienteering.cql +0 -111
  42. data/examples/CQL/PersonPlaysGame.cql +0 -18
  43. data/examples/CQL/RedundantDependency.cql +0 -34
  44. data/examples/CQL/SchoolActivities.cql +0 -33
  45. data/examples/CQL/SeparateSubtype.cql +0 -30
  46. data/examples/CQL/ServiceDirector.cql +0 -276
  47. data/examples/CQL/SimplestUnary.cql +0 -12
  48. data/examples/CQL/Supervision.cql +0 -34
  49. data/examples/CQL/WaiterTips.cql +0 -33
  50. data/examples/CQL/Warehousing.cql +0 -101
  51. data/examples/CQL/WindowInRoomInBldg.cql +0 -28
  52. data/examples/CQL/unit.cql +0 -474
  53. data/examples/index.html +0 -420
  54. data/examples/intro.html +0 -327
  55. data/examples/local.css +0 -24
  56. data/index.html +0 -111
  57. data/lib/activefacts/cql.rb +0 -35
  58. data/lib/activefacts/cql/CQLParser.treetop +0 -158
  59. data/lib/activefacts/cql/Context.treetop +0 -48
  60. data/lib/activefacts/cql/Expressions.treetop +0 -67
  61. data/lib/activefacts/cql/FactTypes.treetop +0 -358
  62. data/lib/activefacts/cql/Language/English.treetop +0 -315
  63. data/lib/activefacts/cql/LexicalRules.treetop +0 -253
  64. data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
  65. data/lib/activefacts/cql/Rakefile +0 -14
  66. data/lib/activefacts/cql/Terms.treetop +0 -183
  67. data/lib/activefacts/cql/ValueTypes.treetop +0 -202
  68. data/lib/activefacts/cql/compiler.rb +0 -156
  69. data/lib/activefacts/cql/compiler/clause.rb +0 -1137
  70. data/lib/activefacts/cql/compiler/constraint.rb +0 -581
  71. data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
  72. data/lib/activefacts/cql/compiler/expression.rb +0 -443
  73. data/lib/activefacts/cql/compiler/fact.rb +0 -390
  74. data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
  75. data/lib/activefacts/cql/compiler/query.rb +0 -106
  76. data/lib/activefacts/cql/compiler/shared.rb +0 -161
  77. data/lib/activefacts/cql/compiler/value_type.rb +0 -174
  78. data/lib/activefacts/cql/nodes.rb +0 -49
  79. data/lib/activefacts/cql/parser.rb +0 -241
  80. data/lib/activefacts/dependency_analyser.rb +0 -182
  81. data/lib/activefacts/generate/absorption.rb +0 -70
  82. data/lib/activefacts/generate/composition.rb +0 -118
  83. data/lib/activefacts/generate/cql.rb +0 -714
  84. data/lib/activefacts/generate/dm.rb +0 -279
  85. data/lib/activefacts/generate/help.rb +0 -64
  86. data/lib/activefacts/generate/helpers/inject.rb +0 -16
  87. data/lib/activefacts/generate/helpers/oo.rb +0 -162
  88. data/lib/activefacts/generate/helpers/ordered.rb +0 -605
  89. data/lib/activefacts/generate/helpers/rails.rb +0 -57
  90. data/lib/activefacts/generate/html/glossary.rb +0 -461
  91. data/lib/activefacts/generate/json.rb +0 -337
  92. data/lib/activefacts/generate/null.rb +0 -32
  93. data/lib/activefacts/generate/rails/models.rb +0 -246
  94. data/lib/activefacts/generate/rails/schema.rb +0 -216
  95. data/lib/activefacts/generate/records.rb +0 -46
  96. data/lib/activefacts/generate/ruby.rb +0 -133
  97. data/lib/activefacts/generate/sql/mysql.rb +0 -280
  98. data/lib/activefacts/generate/sql/server.rb +0 -273
  99. data/lib/activefacts/generate/stats.rb +0 -69
  100. data/lib/activefacts/generate/text.rb +0 -27
  101. data/lib/activefacts/generate/topics.rb +0 -265
  102. data/lib/activefacts/generate/traits/datavault.rb +0 -241
  103. data/lib/activefacts/generate/traits/oo.rb +0 -73
  104. data/lib/activefacts/generate/traits/ordered.rb +0 -33
  105. data/lib/activefacts/generate/traits/ruby.rb +0 -210
  106. data/lib/activefacts/generate/transform/datavault.rb +0 -266
  107. data/lib/activefacts/generate/transform/surrogate.rb +0 -214
  108. data/lib/activefacts/generate/version.rb +0 -26
  109. data/lib/activefacts/input/cql.rb +0 -43
  110. data/lib/activefacts/input/orm.rb +0 -1636
  111. data/lib/activefacts/mapping/rails.rb +0 -132
  112. data/lib/activefacts/persistence.rb +0 -15
  113. data/lib/activefacts/persistence/columns.rb +0 -446
  114. data/lib/activefacts/persistence/foreignkey.rb +0 -187
  115. data/lib/activefacts/persistence/index.rb +0 -240
  116. data/lib/activefacts/persistence/object_type.rb +0 -198
  117. data/lib/activefacts/persistence/reference.rb +0 -434
  118. data/lib/activefacts/persistence/tables.rb +0 -380
  119. data/lib/activefacts/registry.rb +0 -11
  120. data/lib/activefacts/support.rb +0 -132
  121. data/lib/activefacts/vocabulary.rb +0 -9
  122. data/lib/activefacts/vocabulary/extensions.rb +0 -1348
  123. data/lib/activefacts/vocabulary/metamodel.rb +0 -570
  124. data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
  125. data/script/txt2html +0 -71
  126. data/spec/absorption_spec.rb +0 -95
  127. data/spec/cql/comparison_spec.rb +0 -89
  128. data/spec/cql/context_spec.rb +0 -94
  129. data/spec/cql/contractions_spec.rb +0 -224
  130. data/spec/cql/deontic_spec.rb +0 -88
  131. data/spec/cql/entity_type_spec.rb +0 -320
  132. data/spec/cql/expressions_spec.rb +0 -66
  133. data/spec/cql/fact_type_matching_spec.rb +0 -338
  134. data/spec/cql/french_spec.rb +0 -21
  135. data/spec/cql/parser/bad_literals_spec.rb +0 -86
  136. data/spec/cql/parser/constraints_spec.rb +0 -19
  137. data/spec/cql/parser/entity_types_spec.rb +0 -106
  138. data/spec/cql/parser/expressions_spec.rb +0 -199
  139. data/spec/cql/parser/fact_types_spec.rb +0 -44
  140. data/spec/cql/parser/literals_spec.rb +0 -312
  141. data/spec/cql/parser/pragmas_spec.rb +0 -89
  142. data/spec/cql/parser/value_types_spec.rb +0 -42
  143. data/spec/cql/role_matching_spec.rb +0 -148
  144. data/spec/cql/samples_spec.rb +0 -244
  145. data/spec/cql_cql_spec.rb +0 -73
  146. data/spec/cql_dm_spec.rb +0 -136
  147. data/spec/cql_mysql_spec.rb +0 -69
  148. data/spec/cql_parse_spec.rb +0 -34
  149. data/spec/cql_ruby_spec.rb +0 -73
  150. data/spec/cql_sql_spec.rb +0 -72
  151. data/spec/cql_symbol_tables_spec.rb +0 -261
  152. data/spec/cqldump_spec.rb +0 -170
  153. data/spec/helpers/array_matcher.rb +0 -23
  154. data/spec/helpers/ctrl_c_support.rb +0 -52
  155. data/spec/helpers/diff_matcher.rb +0 -39
  156. data/spec/helpers/file_matcher.rb +0 -34
  157. data/spec/helpers/parse_to_ast_matcher.rb +0 -80
  158. data/spec/helpers/string_matcher.rb +0 -30
  159. data/spec/helpers/test_parser.rb +0 -15
  160. data/spec/norma_cql_spec.rb +0 -66
  161. data/spec/norma_ruby_spec.rb +0 -62
  162. data/spec/norma_ruby_sql_spec.rb +0 -107
  163. data/spec/norma_sql_spec.rb +0 -57
  164. data/spec/norma_tables_spec.rb +0 -95
  165. data/spec/ruby_api_spec.rb +0 -23
  166. data/spec/spec_helper.rb +0 -35
  167. data/spec/transform_surrogate_spec.rb +0 -59
  168. data/status.html +0 -138
  169. data/why.html +0 -60
@@ -1,337 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Generate json output from a vocabulary, for loading into APRIMO
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- require 'json'
8
- require 'digest/sha1'
9
-
10
- module ActiveFacts
11
- module Generate
12
- # Generate json output from a vocabulary, for loading into APRIMO.
13
- # Invoke as
14
- # afgen --json <file>.cql=diagrams
15
- class JSON
16
- private
17
- def initialize(vocabulary)
18
- @vocabulary = vocabulary
19
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
20
- end
21
-
22
- def puts(*a)
23
- @out.puts *a
24
- end
25
-
26
- public
27
- def generate(out = $>)
28
- @out = out
29
- uuids = {}
30
-
31
- puts "{ model: '#{@vocabulary.name}',\n" +
32
- "diagrams: [\n#{
33
- @vocabulary.all_diagram.sort_by{|o| o.name.gsub(/ /,'')}.map do |d|
34
- j = {:uuid => (uuids[d] ||= uuid_from_id(d)), :name => d.name}
35
- " #{j.to_json}"
36
- end*",\n"
37
- }\n ],"
38
-
39
- object_types = @vocabulary.all_object_type.sort_by{|o| o.name.gsub(/ /,'')}
40
- puts " object_types: [\n#{
41
- object_types.sort_by{|o|o.identifying_role_values.inspect}.map do |o|
42
- uuids[o] ||= uuid_from_id(o)
43
- ref_mode = nil
44
- if o.is_a?(ActiveFacts::Metamodel::EntityType) and
45
- p = o.preferred_identifier and
46
- (rrs = p.role_sequence.all_role_ref).size == 1 and
47
- (r = rrs.single.role).fact_type != o.fact_type and
48
- r.object_type.is_a?(ActiveFacts::Metamodel::ValueType) and
49
- !r.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
50
- ref_mode = "#{r.object_type.name}"
51
- ref_mode.sub!(%r{#{o.name} *}, '.')
52
- end
53
- j = {
54
- :uuid => uuids[o],
55
- :name => o.name,
56
- :shapes => o.all_object_type_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
57
- x = { :diagram => uuids[shape.orm_diagram],
58
- :is_expanded => shape.is_expanded,
59
- :uuid => uuid_from_id(shape),
60
- :x => shape.location.x,
61
- :y => shape.location.y
62
- }
63
- x[:is_expanded] = true if ref_mode && shape.is_expanded # Don't show the reference mode
64
- x
65
- end
66
- }
67
- j[:ref_mode] = ref_mode if ref_mode
68
- j[:independent] = true if o.is_independent
69
-
70
- if o.is_a?(ActiveFacts::Metamodel::EntityType)
71
- # Entity Type may be objectified, and may have supertypes:
72
- if o.fact_type
73
- uuid = (uuids[o.fact_type] ||= uuid_from_id(o.fact_type))
74
- j[:objectifies] = uuid
75
- j[:implicit] = true if o.concept.implication_rule
76
- end
77
- if o.all_type_inheritance_as_subtype.size > 0
78
- j[:supertypes] = o.
79
- all_type_inheritance_as_subtype.
80
- sort_by{|ti| ti.provides_identification ? 0 : 1}.
81
- map{|ti|
82
- [ uuids[ti.supertype] ||= uuid_from_id(ti.supertype),
83
- uuids[ti.supertype_role] = uuid_from_id(ti.supertype_role)
84
- ]
85
- }
86
- end
87
- else
88
- # ValueType usually has a supertype:
89
- if (o.supertype)
90
- j[:supertype] = (uuids[o.supertype] ||= uuid_from_id(o.supertype))
91
- end
92
- end
93
- # REVISIT: Place a ValueConstraint and shape
94
- " #{j.to_json}"
95
- end*",\n"
96
- }\n ],"
97
-
98
- fact_types = @vocabulary.constellation.
99
- FactType.values.
100
- reject{|ft|
101
- ActiveFacts::Metamodel::LinkFactType === ft || ActiveFacts::Metamodel::TypeInheritance === ft
102
- }
103
- puts " fact_types: [\n#{
104
- fact_types.sort_by{|f| f.identifying_role_values.inspect}.map do |f|
105
- uuids[f] ||= uuid_from_id(f)
106
- j = {:uuid => uuids[f]}
107
-
108
- if f.entity_type
109
- j[:objectified_as] = uuids[f.entity_type]
110
- end
111
-
112
- # Emit roles
113
- roles = f.all_role.sort_by{|r| r.ordinal }
114
- j[:roles] = roles.map do |role|
115
- uuid = (uuids[role] ||= uuid_from_id(role))
116
- # REVISIT: Internal Mandatory Constraints
117
- # REVISIT: Place a ValueConstraint and shape
118
- # REVISIT: Place a RoleName shape
119
- {:uuid => uuid, :player => uuids[role.object_type]}
120
- # N.B. The object_type shape to which this role is attached is not in the meta-model
121
- # Attach to the closest instance on this diagram (if any)
122
- end
123
-
124
- # Emit readings. Each is a [role_order, text] pair
125
- j[:readings] = f.all_reading.map do |r|
126
- role_refs = r.role_sequence.all_role_ref_in_order
127
- [
128
- role_order(uuids, role_refs.map{|rr| rr.role}, roles),
129
- r.text.gsub(/\{([0-9])\}/) do |insert|
130
- role_ref = role_refs[$1.to_i]
131
- la = role_ref.leading_adjective
132
- la = nil if la == ''
133
- ta = role_ref.trailing_adjective
134
- ta = nil if ta == ''
135
- (la ? la+'-' : '') +
136
- (la && la.index(' ') ? ' ' : '') +
137
- insert +
138
- (ta && ta.index(' ') ? ' ' : '') +
139
- (ta ? '-'+ta : '')
140
- end
141
- ]
142
- end.sort_by{|(ro,text)| ro }.map do |(ro,text)|
143
- [ ro, text ]
144
- end
145
-
146
- # Emit shapes
147
- j[:shapes] = f.all_fact_type_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
148
- sj = {
149
- :diagram => uuids[shape.orm_diagram],
150
- :uuid => uuid_from_id(shape),
151
- :x => shape.location.x,
152
- :y => shape.location.y
153
- }
154
-
155
- # Add the role_order, if specified
156
- if shape.all_role_display.size > 0
157
- if shape.all_role_display.size != roles.size
158
- raise "Invalid RoleDisplay for #{f.default_reading} in #{shape.orm_diagram.name} diagram"
159
- end
160
- ro = role_order(
161
- uuids,
162
- shape.all_role_display.sort_by{|rd| rd.ordinal }.map{|rd| rd.role },
163
- roles
164
- )
165
- sj[:role_order] = ro if ro
166
- end
167
-
168
- # REVISIT: Place the ReadingShape
169
-
170
- # Emit the location of the name, if objectified
171
- if n = shape.objectified_fact_type_name_shape
172
- sj[:name_shape] = {:x => n.location.x, :y => n.location.y}
173
- end
174
- sj
175
- end
176
-
177
- # Emit Internal Presence Constraints
178
- f.internal_presence_constraints.to_a.sort_by{|ipc, z|
179
- [ipc.is_preferred_identifier ? 0 : 1, ipc.is_mandatory ? 0 : 1, ipc.min_frequency || 0, ipc.max_frequency || 1_000]
180
- }.each do |ipc|
181
- uuid = (uuids[ipc] ||= uuid_from_id(ipc))
182
-
183
- constraint = {
184
- :uuid => uuid,
185
- :min => ipc.min_frequency,
186
- :max => ipc.max_frequency,
187
- :is_preferred => ipc.is_preferred_identifier,
188
- :mandatory => ipc.is_mandatory
189
- }
190
-
191
- # Get the role (or excluded role, for a UC)
192
- roles = ipc.role_sequence.all_role_ref_in_order.map{|r| r.role}
193
- if roles.size > 1 || (!ipc.is_mandatory && ipc.max_frequency == 1)
194
- # This can be only a uniqueness constraint. Record the missing role, if any
195
- role = (f.all_role.to_a - roles)[0]
196
- constraint[:uniqueExcept] = uuids[role]
197
- else
198
- # An internal mandatory or frequency constraint applies to only one role.
199
- # If it's also unique (max == 1), that applies on the counterpart role.
200
- # You can also have a mandatory frequency constraint, but that applies on this role.
201
- constraint[:role] = uuids[roles[0]]
202
- end
203
- (j[:constraints] ||= []) << constraint
204
- end
205
-
206
- # Add ring constraints
207
- f.all_role_in_order.
208
- map{|r| r.all_ring_constraint.to_a+r.all_ring_constraint_as_other_role.to_a }.
209
- flatten.uniq.each do |ring|
210
- (j[:constraints] ||= []) << {
211
- :uuid => (uuids[ring] ||= uuid_from_id(ring)),
212
- :shapes => ring.all_constraint_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
213
- { :diagram => uuids[shape.orm_diagram],
214
- :uuid => uuid_from_id(shape),
215
- :x => shape.location.x,
216
- :y => shape.location.y
217
- }
218
- end,
219
- :ringKind => ring.ring_type,
220
- :roles => [uuids[ring.role], uuids[ring.other_role]]
221
- # REVISIT: Deontic, enforcement
222
- }
223
- end
224
-
225
- # REVISIT: RotationSetting
226
-
227
- " #{j.to_json}"
228
- end*",\n"
229
- }\n ],"
230
-
231
- constraints = @vocabulary.constellation.
232
- Constraint.values
233
- puts " constraints: [\n#{
234
- constraints.sort_by{|c|c.identifying_role_values.inspect}.select{|c| !uuids[c]}.map do |c|
235
- uuid = uuids[c] ||= uuid_from_id(c)
236
- j = {
237
- :uuid => uuid,
238
- :type => c.class.basename,
239
- :shapes => c.all_constraint_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
240
- { :diagram => uuids[shape.orm_diagram],
241
- :uuid => uuid_from_id(shape),
242
- :x => shape.location.x,
243
- :y => shape.location.y
244
- }
245
- end
246
- }
247
-
248
- if (c.enforcement)
249
- # REVISIT: Deontic constraint
250
- end
251
- if (c.concept.all_context_note_as_relevant_concept.size > 0)
252
- # REVISIT: Context Notes
253
- end
254
-
255
- case c
256
- when ActiveFacts::Metamodel::PresenceConstraint
257
- j[:min_frequency] = c.min_frequency
258
- j[:max_frequency] = c.max_frequency
259
- j[:is_mandatory] = c.is_mandatory
260
- j[:is_preferred_identifier] = c.is_preferred_identifier
261
- rss = [c.role_sequence.all_role_ref_in_order.map(&:role)]
262
-
263
- # Ignore internal presence constraints on TypeInheritance fact types
264
- next nil if !c.role_sequence.all_role_ref.
265
- detect{|rr|
266
- !rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
267
- }
268
-
269
- when ActiveFacts::Metamodel::RingConstraint
270
- next nil # These are emitted with the corresponding fact type
271
-
272
- when ActiveFacts::Metamodel::SetComparisonConstraint
273
- rss = c.
274
- all_set_comparison_roles.sort_by{|scr| scr.ordinal}.
275
- map{|scr| scr.role_sequence.all_role_ref_in_order.map(&:role) }
276
- if (ActiveFacts::Metamodel::SetExclusionConstraint === c)
277
- j[:is_mandatory] = c.is_mandatory
278
- end
279
-
280
- when ActiveFacts::Metamodel::SubsetConstraint
281
- rss = [c.subset_role_sequence, c.superset_role_sequence].
282
- map{|rs| rs.all_role_ref_in_order.map(&:role) }
283
-
284
- when ActiveFacts::Metamodel::ValueConstraint
285
- next nil # REVISIT: Should have been handled elsewhere
286
- if (c.role)
287
- # Should have been handled as role.role_value_constraint
288
- elsif (c.value_type)
289
- # Should have been handled as object_type.value_constraint
290
- end
291
- j[:allowed_ranges] = c.all_allowed_range.map{|ar|
292
- [ ar.value_range.minimum_bound, ar.value_range.maximum_bound ].
293
- map{|b| [b.value.literal, b.value.unit.name, b.is_inclusive] }
294
- }
295
-
296
- else
297
- raise "REVISIT: Constraint type not yet dumped to JSON"
298
- end
299
-
300
- # rss contains the constrained role sequences; map to uuids
301
- j[:role_sequences] = rss.map{|rs|
302
- rs.map do |role|
303
- uuids[role]
304
- end
305
- }
306
-
307
- " #{j.to_json}"
308
- end.compact*",\n"
309
- }\n ]"
310
-
311
- puts "}"
312
- end
313
-
314
- def role_order(uuids, roles, order)
315
- if (roles.size > 9)
316
- roles.map{|r| uuids[r] }
317
- else
318
- roles.map{|r| order.index(r).to_s }*''
319
- end
320
- end
321
-
322
- def uuid_from_id o
323
- irvs = o.identifying_role_values.inspect
324
- d = Digest::SHA1.digest irvs
325
- # $stderr.puts "#{o.class.basename}: #{irvs}"
326
- d[0,4].unpack("H8")[0]+'-'+
327
- d[4,2].unpack("H4")[0]+'-'+
328
- d[6,2].unpack("H4")[0]+'-'+
329
- d[8,2].unpack("H4")[0]+'-'+
330
- d[10,6].unpack("H6")[0]
331
- end
332
-
333
- end
334
- end
335
- end
336
-
337
- ActiveFacts::Registry.generator('json', ActiveFacts::Generate::JSON)
@@ -1,32 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Generate *no* output for ActiveFacts vocabularies; i.e. just a stub
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- require 'activefacts/persistence'
8
-
9
- module ActiveFacts
10
- module Generate
11
- # Generate nothing from an ActiveFacts vocabulary. This is useful to check the file can be read ok.
12
- # Invoke as
13
- # afgen --null <file>.cql
14
- class NULL
15
- private
16
- def initialize(vocabulary, *options)
17
- @vocabulary = vocabulary
18
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
19
- @tables = options.include? "tables"
20
- @columns = options.include? "columns"
21
- @indices = options.include? "indices"
22
- end
23
-
24
- public
25
- def generate(out = $>)
26
- @vocabulary.tables if @tables || @columns || @indices
27
- end
28
- end
29
- end
30
- end
31
-
32
- ActiveFacts::Registry.generator('null', ActiveFacts::Generate::NULL)
@@ -1,246 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Generate models for Rails from an ActiveFacts vocabulary.
4
- #
5
- # Models should normally be generated into "app/models/auto",
6
- # then extend(ed) into your real models.
7
- #
8
- # Copyright (c) 2013 Clifford Heath. Read the LICENSE file.
9
- #
10
- require 'activefacts/vocabulary'
11
- require 'activefacts/persistence'
12
- #require 'activefacts/generate/helpers/rails'
13
- require 'activefacts/mapping/rails'
14
- require 'active_support'
15
-
16
- module ActiveFacts
17
- module Generate
18
- module Rails
19
- # Generate Rails models for the vocabulary
20
- # Invoke as
21
- # afgen --rails/schema[=options] <file>.cql
22
- class Models
23
-
24
- HEADER = "# Auto-generated from CQL, edits will be lost"
25
-
26
- private
27
-
28
- def initialize(vocabulary, *options)
29
- @vocabulary = vocabulary
30
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
31
- help if options.include? "help"
32
- options.delete_if { |option| @output = $1 if option =~ /^output=(.*)/ }
33
- @concern = nil
34
- options.delete_if { |option| @concern = $1 if option =~ /^concern=(.*)/ }
35
- @validations = true
36
- options.delete_if { |option| @validations = eval($1) if option =~ /^validation=(.*)/ }
37
- end
38
-
39
- def help
40
- @helping = true
41
- warn %Q{Options for --rails/schema:
42
- output=dir Overwrite model files into this output directory
43
- concern=name Namespace for the concerns
44
- validation=false Disable generation of validations
45
- }
46
- end
47
-
48
- def warn *a
49
- $stderr.puts *a
50
- end
51
-
52
- def puts s
53
- @out.puts s
54
- end
55
-
56
- public
57
- def generate(out = $>) #:nodoc:
58
- return if @helping
59
- @out = out
60
- list_extant_files if @output
61
-
62
- # Populate all foreignkeys first:
63
- @vocabulary.tables.each { |table| table.foreign_keys }
64
- ok = true
65
- @vocabulary.tables.each do |table|
66
- ok &= generate_table(table)
67
- end
68
- $stderr.puts "\# #{@vocabulary.name} generated with errors" unless ok
69
- delete_old_generated_files if @output
70
- ok
71
- end
72
-
73
- def list_extant_files
74
- @preexisting_files = Dir[@output+'/*.rb']
75
- end
76
-
77
- def delete_old_generated_files
78
- remaining = []
79
- cleaned = 0
80
- @preexisting_files.each do |pathname|
81
- if generated_file_exists(pathname) == true
82
- File.unlink(pathname)
83
- cleaned += 1
84
- else
85
- remaining << pathname
86
- end
87
- end
88
- $stderr.puts "Cleaned up #{cleaned} old generated files" if @preexisting_files.size > 0
89
- $stderr.puts "Remaining non-generated files:\n\t#{remaining*"\n\t"}" if remaining.size > 0
90
- end
91
-
92
- def generated_file_exists pathname
93
- File.open(pathname, 'r') do |existing|
94
- first_lines = existing.read(1024) # Make it possible to pass over a magic charset comment
95
- if first_lines.length == 0 or first_lines =~ %r{^#{HEADER}}
96
- return true
97
- end
98
- end
99
- return false # File exists, but is not generated
100
- rescue Errno::ENOENT
101
- return nil # File does not exist
102
- end
103
-
104
- def create_if_ok filename
105
- # Create a file in the output directory, being careful not to overwrite carelessly
106
- if @output
107
- pathname = (@output+'/'+filename).gsub(%r{//+}, '/')
108
- @preexisting_files.reject!{|f| f == pathname } # Don't clean up this file
109
- if generated_file_exists(pathname) == false
110
- $stderr.puts "not overwriting non-generated file #{pathname}"
111
- @individual_file = nil
112
- return
113
- end
114
- @individual_file = @out = File.open(pathname, 'w')
115
- puts "#{HEADER}"
116
- end
117
- true
118
- end
119
-
120
- def to_associations table
121
- # belongs_to Associations
122
- table.foreign_keys.map do |fk|
123
- association_name = fk.rails_from_association_name
124
-
125
- if association_name != fk.to.rails_singular_name
126
- # A different class_name is implied, emit an explicit one:
127
- class_name = ", :class_name => '#{fk.to.rails_class_name}'"
128
- end
129
- foreign_key = ", :foreign_key => :#{fk.from_columns[0].rails_name}"
130
- if foreign_key == fk.to.rails_singular_name+'_id'
131
- # See lib/active_record/reflection.rb, method #derive_foreign_key
132
- foreign_key = ''
133
- end
134
-
135
- %Q{
136
- \# #{fk.verbalised_path}
137
- belongs_to :#{association_name}#{class_name}#{foreign_key}}
138
- end
139
- end
140
-
141
- def from_associations table
142
- # has_one/has_many Associations
143
- table.foreign_keys_to.sort_by{|fk| fk.describe}.map do |fk|
144
- # Get the jump reference
145
-
146
- if fk.from_columns.size > 1
147
- raise "Can't emit Rails associations for multi-part foreign key with #{fk.references.inspect}. Did you mean to use --transform/surrogate"
148
- end
149
-
150
- association_type, association_name = *fk.rails_to_association
151
-
152
- ref = fk.jump_reference
153
- [
154
- "\n \# #{fk.verbalised_path(true)}" +
155
- "\n" +
156
- %Q{ #{association_type} :#{association_name}} +
157
- %Q{, :class_name => '#{fk.from.rails_class_name}'} +
158
- %Q{, :foreign_key => :#{fk.from_columns[0].rails_name}} +
159
- %Q{, :dependent => :destroy}
160
- ] +
161
- # If ref.from is a join table, we can emit a has_many :through for each other key
162
- # REVISIT Could alternately do this for all belongs_to's in ref.from
163
- if ref.from.identifier_columns.length > 1
164
- ref.from.identifier_columns.map do |ic|
165
- next nil if ic.references[0] == ref or # Skip the back-reference
166
- ic.references[0].is_unary # or use rails_plural_name(ic.references[0].to_names) ?
167
- # This far association name needs to be augmented for its role name
168
- far_association_name = ic.references[0].to.rails_name
169
- %Q{ has_many :#{far_association_name}, :through => :#{association_name}} # \# via #{ic.name}}
170
- end
171
- else
172
- []
173
- end
174
- end.flatten.compact
175
- end
176
-
177
- def column_constraints table
178
- return [] unless @validations
179
- ccs =
180
- table.columns.map do |column|
181
- name = column.rails_name
182
- column.is_mandatory &&
183
- !column.is_auto_assigned && !column.is_auto_timestamp ? [
184
- " validates :#{name}, :presence => true"
185
- ] : []
186
- end.flatten
187
- ccs.unshift("") unless ccs.empty?
188
- ccs
189
- end
190
-
191
- def model_body table
192
- %Q{module #{table.rails_class_name}
193
- extend ActiveSupport::Concern
194
- included do} +
195
- (table.identifier_columns.length == 1 ? %Q{
196
- self.primary_key = '#{table.identifier_columns[0].rails_name}'
197
- } : ''
198
- ) +
199
-
200
- (
201
- to_associations(table) +
202
- from_associations(table) +
203
- column_constraints(table)
204
- ) * "\n" +
205
- %Q{
206
- end
207
- end
208
- }
209
- end
210
-
211
- def generate_table table
212
- old_out = @out
213
- filename = table.rails_singular_name+'.rb'
214
-
215
- return unless create_if_ok filename
216
-
217
- puts "\n"
218
- puts "module #{@concern}" if @concern
219
- puts model_body(table).gsub(/^./, @concern ? ' \0' : '\0')
220
- puts 'end' if @concern
221
-
222
- true # We succeeded
223
- ensure
224
- @out = old_out
225
- @individual_file.close if @individual_file
226
- end
227
-
228
- end
229
- end
230
- end
231
-
232
- module Persistence
233
- class Column
234
- def is_auto_timestamp
235
- case name('_')
236
- when /\A(created|updated)_(at|on)\Z/i
237
- true
238
- else
239
- false
240
- end
241
- end
242
- end
243
- end
244
- end
245
-
246
- ActiveFacts::Registry.generator('rails/models', ActiveFacts::Generate::Rails::Models)