activefacts 1.6.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
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)