activefacts 0.8.6 → 0.8.8
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.
- data/Manifest.txt +33 -2
- data/README.rdoc +30 -36
- data/Rakefile +16 -20
- data/bin/afgen +17 -11
- data/bin/cql +313 -36
- data/download.html +43 -19
- data/examples/CQL/Address.cql +15 -15
- data/examples/CQL/Blog.cql +8 -8
- data/examples/CQL/CompanyDirectorEmployee.cql +6 -5
- data/examples/CQL/Death.cql +3 -3
- data/examples/CQL/Diplomacy.cql +48 -0
- data/examples/CQL/Genealogy.cql +41 -41
- data/examples/CQL/Insurance.cql +311 -0
- data/examples/CQL/JoinEquality.cql +35 -0
- data/examples/CQL/Marriage.cql +1 -1
- data/examples/CQL/Metamodel.cql +290 -185
- data/examples/CQL/MetamodelNext.cql +420 -0
- data/examples/CQL/Monogamy.cql +24 -0
- data/examples/CQL/MonthInSeason.cql +27 -0
- data/examples/CQL/Moon.cql +23 -0
- data/examples/CQL/MultiInheritance.cql +4 -4
- data/examples/CQL/NonRoleId.cql +14 -0
- data/examples/CQL/OddIdentifier.cql +18 -0
- data/examples/CQL/OilSupply.cql +24 -24
- data/examples/CQL/OneToOnes.cql +17 -0
- data/examples/CQL/Orienteering.cql +55 -55
- data/examples/CQL/OrienteeringER.cql +58 -0
- data/examples/CQL/PersonPlaysGame.cql +2 -2
- data/examples/CQL/RedundantDependency.cql +34 -0
- data/examples/CQL/SchoolActivities.cql +5 -5
- data/examples/CQL/SeparateSubtype.cql +28 -0
- data/examples/CQL/ServiceDirector.cql +283 -0
- data/examples/CQL/SimplestUnary.cql +2 -2
- data/examples/CQL/SubtypePI.cql +11 -11
- data/examples/CQL/Supervision.cql +38 -0
- data/examples/CQL/Tests.Test5.Load.cql +38 -0
- data/examples/CQL/WaiterTips.cql +33 -0
- data/examples/CQL/Warehousing.cql +55 -53
- data/examples/CQL/WindowInRoomInBldg.cql +9 -9
- data/examples/CQL/unit.cql +433 -544
- data/examples/index.html +314 -170
- data/examples/intro.html +6 -176
- data/examples/local.css +8 -4
- data/index.html +40 -25
- data/lib/activefacts/api/concept.rb +2 -2
- data/lib/activefacts/api/constellation.rb +4 -4
- data/lib/activefacts/api/instance.rb +2 -2
- data/lib/activefacts/api/instance_index.rb +4 -0
- data/lib/activefacts/api/numeric.rb +3 -1
- data/lib/activefacts/api/role.rb +1 -1
- data/lib/activefacts/api/standard_types.rb +23 -16
- data/lib/activefacts/api/support.rb +3 -1
- data/lib/activefacts/api/vocabulary.rb +4 -0
- data/lib/activefacts/cql/CQLParser.treetop +87 -39
- data/lib/activefacts/cql/Concepts.treetop +95 -69
- data/lib/activefacts/cql/Context.treetop +11 -2
- data/lib/activefacts/cql/Expressions.treetop +23 -59
- data/lib/activefacts/cql/FactTypes.treetop +141 -95
- data/lib/activefacts/cql/Language/English.treetop +33 -21
- data/lib/activefacts/cql/LexicalRules.treetop +6 -1
- data/lib/activefacts/cql/Terms.treetop +75 -26
- data/lib/activefacts/cql/ValueTypes.treetop +52 -54
- data/lib/activefacts/cql/compiler.rb +46 -1691
- data/lib/activefacts/cql/compiler/constraint.rb +602 -0
- data/lib/activefacts/cql/compiler/entity_type.rb +425 -0
- data/lib/activefacts/cql/compiler/fact.rb +300 -0
- data/lib/activefacts/cql/compiler/fact_type.rb +230 -0
- data/lib/activefacts/cql/compiler/reading.rb +832 -0
- data/lib/activefacts/cql/compiler/shared.rb +109 -0
- data/lib/activefacts/cql/compiler/value_type.rb +104 -0
- data/lib/activefacts/cql/parser.rb +132 -81
- data/lib/activefacts/generate/cql.rb +397 -274
- data/lib/activefacts/generate/oo.rb +13 -12
- data/lib/activefacts/generate/ordered.rb +107 -117
- data/lib/activefacts/generate/ruby.rb +34 -38
- data/lib/activefacts/generate/sql/mysql.rb +62 -45
- data/lib/activefacts/generate/sql/server.rb +59 -42
- data/lib/activefacts/input/cql.rb +6 -3
- data/lib/activefacts/input/orm.rb +991 -557
- data/lib/activefacts/persistence/columns.rb +16 -12
- data/lib/activefacts/persistence/foreignkey.rb +7 -4
- data/lib/activefacts/persistence/index.rb +3 -4
- data/lib/activefacts/persistence/reference.rb +5 -2
- data/lib/activefacts/support.rb +20 -14
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary.rb +1 -0
- data/lib/activefacts/vocabulary/extensions.rb +328 -44
- data/lib/activefacts/vocabulary/metamodel.rb +145 -20
- data/lib/activefacts/vocabulary/verbaliser.rb +621 -0
- data/spec/absorption_spec.rb +4 -4
- data/spec/api/value_type.rb +1 -1
- data/spec/cql/context_spec.rb +45 -22
- data/spec/cql/deontic_spec.rb +88 -0
- data/spec/cql/matching_spec.rb +517 -0
- data/spec/cql/samples_spec.rb +88 -31
- data/spec/cql/unit_spec.rb +58 -37
- data/spec/cql_cql_spec.rb +12 -7
- data/spec/cql_mysql_spec.rb +3 -7
- data/spec/cql_parse_spec.rb +0 -4
- data/spec/cql_ruby_spec.rb +1 -4
- data/spec/cql_sql_spec.rb +5 -18
- data/spec/cql_symbol_tables_spec.rb +3 -0
- data/spec/cqldump_spec.rb +0 -2
- data/spec/helpers/array_matcher.rb +35 -0
- data/spec/helpers/ctrl_c_support.rb +52 -0
- data/spec/helpers/diff_matcher.rb +38 -0
- data/spec/helpers/file_matcher.rb +5 -3
- data/spec/helpers/string_matcher.rb +39 -0
- data/spec/helpers/test_parser.rb +13 -0
- data/spec/norma_cql_spec.rb +13 -5
- data/spec/norma_ruby_spec.rb +11 -3
- data/spec/{absorption_ruby_spec.rb → norma_ruby_sql_spec.rb} +37 -32
- data/spec/norma_sql_spec.rb +11 -5
- data/spec/norma_tables_spec.rb +33 -29
- data/spec/spec_helper.rb +4 -1
- data/status.html +92 -23
- metadata +102 -36
- data/lib/activefacts/generate/cql/html.rb +0 -403
data/Manifest.txt
CHANGED
|
@@ -15,16 +15,33 @@ examples/CQL/Address.cql
|
|
|
15
15
|
examples/CQL/Blog.cql
|
|
16
16
|
examples/CQL/CompanyDirectorEmployee.cql
|
|
17
17
|
examples/CQL/Death.cql
|
|
18
|
+
examples/CQL/Diplomacy.cql
|
|
18
19
|
examples/CQL/Genealogy.cql
|
|
20
|
+
examples/CQL/Insurance.cql
|
|
21
|
+
examples/CQL/JoinEquality.cql
|
|
19
22
|
examples/CQL/Marriage.cql
|
|
20
23
|
examples/CQL/Metamodel.cql
|
|
24
|
+
examples/CQL/MetamodelNext.cql
|
|
25
|
+
examples/CQL/Monogamy.cql
|
|
26
|
+
examples/CQL/MonthInSeason.cql
|
|
27
|
+
examples/CQL/Moon.cql
|
|
21
28
|
examples/CQL/MultiInheritance.cql
|
|
29
|
+
examples/CQL/NonRoleId.cql
|
|
30
|
+
examples/CQL/OddIdentifier.cql
|
|
22
31
|
examples/CQL/OilSupply.cql
|
|
32
|
+
examples/CQL/OneToOnes.cql
|
|
23
33
|
examples/CQL/Orienteering.cql
|
|
34
|
+
examples/CQL/OrienteeringER.cql
|
|
24
35
|
examples/CQL/PersonPlaysGame.cql
|
|
36
|
+
examples/CQL/RedundantDependency.cql
|
|
25
37
|
examples/CQL/SchoolActivities.cql
|
|
38
|
+
examples/CQL/SeparateSubtype.cql
|
|
39
|
+
examples/CQL/ServiceDirector.cql
|
|
26
40
|
examples/CQL/SimplestUnary.cql
|
|
27
41
|
examples/CQL/SubtypePI.cql
|
|
42
|
+
examples/CQL/Supervision.cql
|
|
43
|
+
examples/CQL/Tests.Test5.Load.cql
|
|
44
|
+
examples/CQL/WaiterTips.cql
|
|
28
45
|
examples/CQL/Warehousing.cql
|
|
29
46
|
examples/CQL/WindowInRoomInBldg.cql
|
|
30
47
|
examples/CQL/unit.cql
|
|
@@ -59,10 +76,16 @@ lib/activefacts/cql/Rakefile
|
|
|
59
76
|
lib/activefacts/cql/Terms.treetop
|
|
60
77
|
lib/activefacts/cql/ValueTypes.treetop
|
|
61
78
|
lib/activefacts/cql/compiler.rb
|
|
79
|
+
lib/activefacts/cql/compiler/constraint.rb
|
|
80
|
+
lib/activefacts/cql/compiler/entity_type.rb
|
|
81
|
+
lib/activefacts/cql/compiler/fact.rb
|
|
82
|
+
lib/activefacts/cql/compiler/fact_type.rb
|
|
83
|
+
lib/activefacts/cql/compiler/reading.rb
|
|
84
|
+
lib/activefacts/cql/compiler/shared.rb
|
|
85
|
+
lib/activefacts/cql/compiler/value_type.rb
|
|
62
86
|
lib/activefacts/cql/parser.rb
|
|
63
87
|
lib/activefacts/generate/absorption.rb
|
|
64
88
|
lib/activefacts/generate/cql.rb
|
|
65
|
-
lib/activefacts/generate/cql/html.rb
|
|
66
89
|
lib/activefacts/generate/null.rb
|
|
67
90
|
lib/activefacts/generate/oo.rb
|
|
68
91
|
lib/activefacts/generate/ordered.rb
|
|
@@ -84,8 +107,8 @@ lib/activefacts/version.rb
|
|
|
84
107
|
lib/activefacts/vocabulary.rb
|
|
85
108
|
lib/activefacts/vocabulary/extensions.rb
|
|
86
109
|
lib/activefacts/vocabulary/metamodel.rb
|
|
110
|
+
lib/activefacts/vocabulary/verbaliser.rb
|
|
87
111
|
script/txt2html
|
|
88
|
-
spec/absorption_ruby_spec.rb
|
|
89
112
|
spec/absorption_spec.rb
|
|
90
113
|
spec/api/autocounter.rb
|
|
91
114
|
spec/api/constellation.rb
|
|
@@ -95,6 +118,8 @@ spec/api/roles.rb
|
|
|
95
118
|
spec/api/value_type.rb
|
|
96
119
|
spec/api_spec.rb
|
|
97
120
|
spec/cql/context_spec.rb
|
|
121
|
+
spec/cql/deontic_spec.rb
|
|
122
|
+
spec/cql/matching_spec.rb
|
|
98
123
|
spec/cql/samples_spec.rb
|
|
99
124
|
spec/cql/unit_spec.rb
|
|
100
125
|
spec/cql_cql_spec.rb
|
|
@@ -104,9 +129,15 @@ spec/cql_ruby_spec.rb
|
|
|
104
129
|
spec/cql_sql_spec.rb
|
|
105
130
|
spec/cql_symbol_tables_spec.rb
|
|
106
131
|
spec/cqldump_spec.rb
|
|
132
|
+
spec/helpers/array_matcher.rb
|
|
133
|
+
spec/helpers/ctrl_c_support.rb
|
|
134
|
+
spec/helpers/diff_matcher.rb
|
|
107
135
|
spec/helpers/file_matcher.rb
|
|
136
|
+
spec/helpers/string_matcher.rb
|
|
137
|
+
spec/helpers/test_parser.rb
|
|
108
138
|
spec/norma_cql_spec.rb
|
|
109
139
|
spec/norma_ruby_spec.rb
|
|
140
|
+
spec/norma_ruby_sql_spec.rb
|
|
110
141
|
spec/norma_sql_spec.rb
|
|
111
142
|
spec/norma_tables_spec.rb
|
|
112
143
|
spec/spec.opts
|
data/README.rdoc
CHANGED
|
@@ -2,58 +2,52 @@
|
|
|
2
2
|
|
|
3
3
|
* http://dataconstellation.com/ActiveFacts/
|
|
4
4
|
|
|
5
|
-
== DESCRIPTION
|
|
5
|
+
== DESCRIPTION
|
|
6
6
|
|
|
7
|
-
ActiveFacts
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
ActiveFacts provides a semantic modeling language, the Constellation
|
|
8
|
+
Query Language (CQL). CQL combines natural language verbalisation and
|
|
9
|
+
formal logic, producing a formal language that reads like plain
|
|
10
|
+
English. ActiveFacts converts semantic models from CQL to relational
|
|
11
|
+
and object models in SQL, Ruby and other languages.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
both the original semantic model and to the generated SQL.
|
|
19
|
-
|
|
20
|
-
The result is a formal language that reads like plain English, and
|
|
21
|
-
allows creation of relational and object models that are guaranteed
|
|
22
|
-
equivalent, and much more stable in the face of schema evolution than
|
|
23
|
-
SQL is.
|
|
13
|
+
The generated models are guaranteed congruent, which eliminates the
|
|
14
|
+
object-relational impedance mismatch. Semantic models are much more
|
|
15
|
+
stable under evolving requirements than either relational or
|
|
16
|
+
object-oriented models, because they directly express the underlying
|
|
17
|
+
elementary facts, so are not susceptible to ramifying change in the
|
|
18
|
+
way those attribute-oriented approaches are.
|
|
24
19
|
|
|
25
|
-
|
|
20
|
+
Semantic modeling is a refinement of fact-based modeling techniques
|
|
21
|
+
such as ORM2, NIAM and others. ActiveFacts can convert ORM2 files from
|
|
22
|
+
NORMA to CQL. Fact-based modeling is closely related to relational
|
|
23
|
+
modeling in the sixth normal form, but doesn't suffer from 6NF
|
|
24
|
+
inefficiency. The relational models it derives are highly efficient.
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
== SYNOPSIS:
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
afgen --sql/server myfile.cql
|
|
29
|
+
afgen --ruby myfile.cql
|
|
30
|
+
afgen --cql myfile.orm
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
== INSTALL:
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
don't yet pass the CQL parser's semantic analysis.
|
|
34
|
+
* sudo gem install activefacts
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
== UNIMPLEMENTED FEATURES
|
|
38
37
|
|
|
39
|
-
*
|
|
40
|
-
shows the parse tree.
|
|
38
|
+
* Queries are parsed, but not yet generated to SQL.
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
* The Constellation API lacks SQL persistence (but is already useful;
|
|
41
|
+
the CQL compiler uses the generated Ruby code extensively)
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
afgen --ruby myfile.cql
|
|
46
|
-
afgen --cql myfile.orm
|
|
43
|
+
* Validation of semantic models is incomplete
|
|
47
44
|
|
|
48
45
|
== REQUIREMENTS:
|
|
49
46
|
|
|
50
47
|
* Treetop parser generator
|
|
51
|
-
* Optional: NORMA, see <http://www.ormfoundation.org/files/>
|
|
52
|
-
(needs Visual Studio pro edition), if you want to use ORM
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* sudo gem install activefacts
|
|
49
|
+
* NORMA (see <http://www.ormfoundation.org/files/>), if you want to
|
|
50
|
+
use ORM (needs Visual Studio Pro edition)
|
|
57
51
|
|
|
58
52
|
== LICENSE:
|
|
59
53
|
|
data/Rakefile
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
%w[rubygems hoe rake rake/clean fileutils newgem rubigen spec spec/rake/spectask].each { |f| require f }
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Use mislav-hanna to the API format documentation, if it's installed:
|
|
4
|
+
begin
|
|
5
|
+
require 'hanna/rdoctask'
|
|
6
|
+
HANNA = true
|
|
7
|
+
rescue
|
|
8
|
+
HANNA = false
|
|
9
|
+
end
|
|
4
10
|
|
|
5
11
|
require File.dirname(__FILE__) + '/lib/activefacts'
|
|
6
12
|
|
|
@@ -10,23 +16,11 @@ $hoe = Hoe.spec('activefacts') do |p|
|
|
|
10
16
|
p.version = ActiveFacts::VERSION
|
|
11
17
|
p.summary = "A semantic modeling and query language (CQL) and application runtime (the Constellation API)"
|
|
12
18
|
p.description = %q{
|
|
13
|
-
ActiveFacts
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Semantic modeling is a refinement of fact-based modeling techniques
|
|
19
|
-
that draw on natural language verbalisation and formal logic. Fact
|
|
20
|
-
based modeling is essentially the same as relational modeling in the
|
|
21
|
-
sixth normal form. The tools provided here automatically condense
|
|
22
|
-
that to third normal form for efficient storage. They also generate
|
|
23
|
-
object models as a Ruby module which has an effective mapping to
|
|
24
|
-
both the original semantic model and to the generated SQL.
|
|
25
|
-
|
|
26
|
-
The result is a formal language that reads like plain English, and
|
|
27
|
-
allows creation of relational and object models that are guaranteed
|
|
28
|
-
equivalent, and much more stable in the face of schema evolution than
|
|
29
|
-
SQL is.
|
|
19
|
+
ActiveFacts provides a semantic modeling language, the Constellation
|
|
20
|
+
Query Language (CQL). CQL combines natural language verbalisation and
|
|
21
|
+
formal logic, producing a formal language that reads like plain
|
|
22
|
+
English. ActiveFacts converts semantic models from CQL to relational
|
|
23
|
+
and object models in SQL, Ruby and other languages.
|
|
30
24
|
}
|
|
31
25
|
p.url = "http://dataconstellation.com/ActiveFacts/"
|
|
32
26
|
p.developer('Clifford Heath', 'cjh@dataconstellation.org')
|
|
@@ -35,6 +29,7 @@ SQL is.
|
|
|
35
29
|
p.rubyforge_name = "cjheath@rubyforge.org"
|
|
36
30
|
p.extra_deps = [
|
|
37
31
|
['treetop','>= 1.4.1'],
|
|
32
|
+
['rake','>= 0.8.7'],
|
|
38
33
|
]
|
|
39
34
|
p.extra_dev_deps = [
|
|
40
35
|
['newgem', ">= #{::Newgem::VERSION}"]
|
|
@@ -42,8 +37,9 @@ SQL is.
|
|
|
42
37
|
p.spec_extras[:extensions] = 'lib/activefacts/cql/Rakefile'
|
|
43
38
|
# Magic Hoe hook to prevent the generation of diagrams:
|
|
44
39
|
ENV['NODOT'] = 'yes'
|
|
45
|
-
p.spec_extras[:rdoc_options] =
|
|
46
|
-
|
|
40
|
+
p.spec_extras[:rdoc_options] = ['-S'] +
|
|
41
|
+
(HANNA ? %w{ -S -T hanna} : []) +
|
|
42
|
+
%w{
|
|
47
43
|
-A has_one -A one_to_one -A maybe
|
|
48
44
|
-x lib/activefacts/cql/.*.rb
|
|
49
45
|
-x lib/activefacts/vocabulary/.*.rb
|
data/bin/afgen
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
1
1
|
#! /usr/bin/env ruby
|
|
2
2
|
#
|
|
3
|
-
#
|
|
3
|
+
# ActiveFacts: Read a Vocabulary (from a NORMA, CQL or other file) and run a generator
|
|
4
4
|
#
|
|
5
5
|
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
6
6
|
#
|
|
7
7
|
$:.unshift File.dirname(File.expand_path(__FILE__))+"/../lib"
|
|
8
8
|
|
|
9
9
|
require 'rubygems'
|
|
10
|
-
require 'activefacts'
|
|
11
|
-
require 'activefacts/vocabulary'
|
|
12
10
|
|
|
13
|
-
if
|
|
11
|
+
# Load the ruby debugger before everything else, if requested
|
|
12
|
+
if d = ENV['DEBUG'] and d.split(/,/).include?('debug')
|
|
14
13
|
begin
|
|
15
14
|
require 'ruby-debug'
|
|
16
|
-
Debugger.start(:post_mortem => true)
|
|
15
|
+
Debugger.start(:post_mortem => true) # Stop when an exception is thrown, but before it's rescued
|
|
17
16
|
rescue LoadError
|
|
18
17
|
# Ok, no debugger, tough luck.
|
|
19
18
|
end
|
|
20
19
|
end
|
|
21
|
-
|
|
20
|
+
|
|
21
|
+
require 'activefacts'
|
|
22
|
+
require 'activefacts/vocabulary'
|
|
22
23
|
|
|
23
24
|
arg = ARGV.shift
|
|
24
25
|
|
|
25
26
|
# Load the required generator, or the default "text" generator:
|
|
26
27
|
generator = "text"
|
|
28
|
+
generator_options = []
|
|
27
29
|
if arg =~ /^--([^=]*)(?:=(.*))?/
|
|
28
30
|
generator = $1
|
|
29
31
|
generator_options = ($2||"").split(/,/)
|
|
30
32
|
arg = ARGV.shift
|
|
31
33
|
end
|
|
34
|
+
|
|
32
35
|
output_handler = "activefacts/generate/#{generator.downcase}"
|
|
33
36
|
require output_handler
|
|
34
37
|
output_class = generator.upcase.gsub(%r{[/\\]+},'::')
|
|
@@ -36,20 +39,23 @@ output_klass = eval("ActiveFacts::Generate::#{output_class}")
|
|
|
36
39
|
raise "Expected #{output_handler} to define #{output_class}" unless output_klass
|
|
37
40
|
|
|
38
41
|
# Load the file type input method
|
|
42
|
+
arg, *options = *arg.split(/=/)
|
|
39
43
|
extension = arg.sub(/\A.*\./,'').downcase
|
|
40
44
|
input_handler = "activefacts/input/#{extension}"
|
|
41
45
|
require input_handler
|
|
46
|
+
|
|
42
47
|
input_class = extension.upcase
|
|
43
48
|
input_klass = ActiveFacts::Input.const_get(input_class.to_sym)
|
|
44
49
|
raise "Expected #{input_handler} to define #{input_class}" unless input_klass
|
|
45
50
|
|
|
46
51
|
# Read the input file:
|
|
47
52
|
begin
|
|
48
|
-
vocabulary = input_klass.readfile(arg)
|
|
53
|
+
vocabulary = input_klass.readfile(arg, *options)
|
|
54
|
+
|
|
55
|
+
# Generate the output:
|
|
56
|
+
output_klass.new(vocabulary, *generator_options).generate if vocabulary
|
|
49
57
|
rescue => e
|
|
50
58
|
puts "#{e.message}"
|
|
51
|
-
puts "
|
|
59
|
+
# puts "\t#{e.backtrace*"\n\t"}"
|
|
60
|
+
puts "\t#{e.backtrace*"\n\t"}" if debug :exception
|
|
52
61
|
end
|
|
53
|
-
|
|
54
|
-
# Generate the output:
|
|
55
|
-
output_klass.new(vocabulary, *generator_options).generate if vocabulary
|
data/bin/cql
CHANGED
|
@@ -1,62 +1,339 @@
|
|
|
1
1
|
#! /usr/bin/env ruby
|
|
2
2
|
#
|
|
3
|
-
#
|
|
3
|
+
# ActiveFacts: Interactive CQL command-line. Incomplete; only parses CQL and shows the parse trees
|
|
4
4
|
#
|
|
5
5
|
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
6
6
|
#
|
|
7
|
-
|
|
8
|
-
require 'activefacts'
|
|
9
|
-
require 'activefacts/cql/parser'
|
|
10
7
|
require 'readline'
|
|
11
8
|
|
|
12
|
-
if
|
|
9
|
+
# Load the ruby debugger before everything else, if requested
|
|
10
|
+
if d = ENV['DEBUG'] and d.split(/,/).include?('debug')
|
|
13
11
|
begin
|
|
14
12
|
require 'ruby-debug'
|
|
15
|
-
|
|
13
|
+
Debugger.start(:post_mortem => true) # Stop when an exception is thrown, but before it's rescued
|
|
16
14
|
rescue LoadError
|
|
17
15
|
# Ok, no debugger, tough luck.
|
|
18
16
|
end
|
|
19
17
|
end
|
|
20
|
-
true # Ok, got the stack set up, continue to the fault
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
require 'activefacts'
|
|
20
|
+
require 'activefacts/cql/compiler'
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
class InteractiveCQL < ActiveFacts::CQL::Compiler
|
|
23
|
+
def initialize *a
|
|
24
|
+
@show_tree = false # Show the raw Treetop parse tree
|
|
25
|
+
super *a
|
|
26
|
+
self.root = :definition
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def metacommand(line)
|
|
30
30
|
# meta-commands start with /
|
|
31
|
-
|
|
31
|
+
words = line.split
|
|
32
|
+
case cmd = words.shift
|
|
33
|
+
when "/tree"
|
|
34
|
+
@show_tree = !@show_tree
|
|
35
|
+
puts "Will #{@show_tree ? "" : "not "}show the parse tree"
|
|
32
36
|
when "/root"
|
|
33
|
-
|
|
34
|
-
puts "
|
|
37
|
+
self.root = words[0] && words[0].to_sym || :definition
|
|
38
|
+
puts "Looking for a #{self.root}"
|
|
39
|
+
when "/list"
|
|
40
|
+
concepts_by_vocabulary = {}
|
|
41
|
+
@constellation.Concept.keys.
|
|
42
|
+
each do |v,t|
|
|
43
|
+
(concepts_by_vocabulary[v[0]] ||= []) << t
|
|
44
|
+
end
|
|
45
|
+
concepts_by_vocabulary.keys.sort.each do |v|
|
|
46
|
+
puts "#{v}:\n\t" + concepts_by_vocabulary[v].sort*"\n\t"
|
|
47
|
+
end
|
|
48
|
+
when "/about"
|
|
49
|
+
concept = @constellation.Concept[[@vocabulary.identifying_role_values, words[0]]]
|
|
50
|
+
unless concept
|
|
51
|
+
puts "Concept #{words[0]} is unknown in #{@vocabulary.name}"
|
|
52
|
+
return
|
|
53
|
+
end
|
|
54
|
+
if concept.is_a?(ActiveFacts::Metamodel::ValueType)
|
|
55
|
+
puts "\t#{concept.name} is written as #{concept.supertype.name};" if concept.supertype
|
|
56
|
+
concept.all_value_type_as_supertype.each do |st|
|
|
57
|
+
puts "#{st.name} is written as #{concept.name};"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
concept.all_role.map{|role| role.fact_type}.uniq.each do |fact_type|
|
|
61
|
+
puts "\t#{fact_type.default_reading}"
|
|
62
|
+
end
|
|
63
|
+
when "/load"
|
|
64
|
+
begin
|
|
65
|
+
vocabularies = @constellation.Vocabulary.keys
|
|
66
|
+
@results = []
|
|
67
|
+
compile_file words*' '
|
|
68
|
+
new_vocabularies = @constellation.Vocabulary.keys-vocabularies
|
|
69
|
+
puts "Loaded new vocabularies: #{new_vocabularies*', '}" unless new_vocabularies.empty?
|
|
70
|
+
rescue Errno::ENOENT => e
|
|
71
|
+
$stderr.puts e.message
|
|
72
|
+
end
|
|
35
73
|
else
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
statement = nil
|
|
39
|
-
elsif parser.root != :definition or
|
|
40
|
-
line.gsub(/(['"])([^\1\\]|\\.)*\1/,'') =~ /;/
|
|
41
|
-
# After stripping string literals the line contains a ';', it's the last line of the command:
|
|
42
|
-
begin
|
|
43
|
-
result = parser.parse(statement)
|
|
44
|
-
if result
|
|
45
|
-
begin
|
|
46
|
-
p result.value
|
|
47
|
-
rescue => e
|
|
48
|
-
puts e.to_s+":"
|
|
49
|
-
puts e.backtrace*"\n\t" if ENV["DEBUG"] =~ /exception/
|
|
50
|
-
p result # In case the root is changed and there's no value()
|
|
51
|
-
end
|
|
52
|
-
#p parser.definition(result)
|
|
74
|
+
if cmd == "/help" or cmd == "/"
|
|
75
|
+
help words
|
|
53
76
|
else
|
|
54
|
-
|
|
77
|
+
puts "Unknown metacommand #{line}?"
|
|
78
|
+
help
|
|
55
79
|
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def process(statement)
|
|
84
|
+
begin
|
|
85
|
+
@results = []
|
|
86
|
+
compile(statement)
|
|
87
|
+
puts(@results.map{|r| "\t"+r.inspect}*"\n")
|
|
56
88
|
rescue => e
|
|
57
89
|
puts e
|
|
58
|
-
puts "\t"+e.backtrace*"\n\t"
|
|
90
|
+
puts "\t"+e.backtrace*"\n\t" if ENV["DEBUG"] =~ /exception/
|
|
59
91
|
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def compile_definition ast
|
|
95
|
+
# Accumulate the results:
|
|
96
|
+
p ast if @show_tree
|
|
97
|
+
@results += Array(result = super)
|
|
98
|
+
result
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def help words = []
|
|
102
|
+
if words.empty?
|
|
103
|
+
puts %Q{
|
|
104
|
+
Meta-commands are:
|
|
105
|
+
/about term\t\tDisplay the fact types in which term plays a part
|
|
106
|
+
/help\t\t\tThis help message
|
|
107
|
+
/help topic\t\thelp on a specific topic
|
|
108
|
+
/help topics\t\tList the available help topics
|
|
109
|
+
/list\t\t\tList all object type names (terms)
|
|
110
|
+
/load file.cql\tLoad a CQL file
|
|
111
|
+
/root rule\t\tParse just a fragment of a CQL statement, matching syntax rule only
|
|
112
|
+
/tree\t\t\tDisplay the abstract syntax tree from each statement parsed
|
|
113
|
+
}
|
|
114
|
+
else
|
|
115
|
+
words.each do |word|
|
|
116
|
+
case word
|
|
117
|
+
when /topics/
|
|
118
|
+
puts %Q{
|
|
119
|
+
constraint\tHow to enter external constraints
|
|
120
|
+
entity\t\tHow to define a new entity type
|
|
121
|
+
fact\t\tHow to define a new fact type
|
|
122
|
+
instance\tHow to assert instance data (facts)
|
|
123
|
+
query\tHow to formulate queries (and derived fact types)
|
|
124
|
+
term\t\tHow to name object types
|
|
125
|
+
value\t\tHow to define a new value type
|
|
126
|
+
vocabulary\tHow to specify the target vocabulary
|
|
127
|
+
}
|
|
128
|
+
when /constraint/
|
|
129
|
+
puts %Q{
|
|
130
|
+
External Constraints are of various types, and use fact readings with
|
|
131
|
+
role players that may occur in more than one reading. Adjectives, role
|
|
132
|
+
names and subscripts may be used to disambiguate multiple occurrences
|
|
133
|
+
of the same term.
|
|
134
|
+
|
|
135
|
+
// A subset constraint:
|
|
136
|
+
Person is an Employee
|
|
137
|
+
only if Person has Tax File Number;
|
|
138
|
+
|
|
139
|
+
// Mandatory constraint:
|
|
140
|
+
each Person occurs at least one time in
|
|
141
|
+
Person has mobile Phone Nr,
|
|
142
|
+
Person has mailing Address;
|
|
143
|
+
// Alternate syntax:
|
|
144
|
+
either Person has mobile Phone Nr or Phone has mailing Address;
|
|
145
|
+
|
|
146
|
+
// Uniqueness constraint:
|
|
147
|
+
each combination Series, Number occurs at most one time in
|
|
148
|
+
Event is in Series,
|
|
149
|
+
Event has Number;
|
|
150
|
+
|
|
151
|
+
// Disjunctive mandatory constraint:
|
|
152
|
+
each Person occurs one time in
|
|
153
|
+
Person is employeed by Company,
|
|
154
|
+
Person receives Unemployment Benefits;
|
|
155
|
+
Person is unsupported,
|
|
156
|
+
// Alternate syntax
|
|
157
|
+
either Employee reports to Manager or Employee runs Company but not both;
|
|
158
|
+
|
|
159
|
+
// Equality constraint with joins:
|
|
160
|
+
Ticket is for Seat that is at Venue
|
|
161
|
+
if and only if
|
|
162
|
+
Ticket is for Event that is held at Venue;
|
|
163
|
+
}
|
|
164
|
+
when /entity/
|
|
165
|
+
puts %q{
|
|
166
|
+
Entity Type with simple identification (a one-to-one with a value type):
|
|
167
|
+
|
|
168
|
+
Employee is identified by its Nr; // Asserts the value type 'Employee Nr'
|
|
169
|
+
|
|
170
|
+
The Value Type 'Employee Nr' is created if necessary, and the supertype 'Nr'
|
|
171
|
+
also. You may add alternate readings (to "...has..." and "...is for...")
|
|
172
|
+
in a where clause.
|
|
173
|
+
|
|
174
|
+
Entity Type with a compound identifier:
|
|
175
|
+
|
|
176
|
+
Person is identified by given Name and family Name where
|
|
177
|
+
Person is called given-Name,
|
|
178
|
+
Person has family-Name;
|
|
179
|
+
|
|
180
|
+
An Entity Type may be a subtype of one or more other Entity Types.
|
|
181
|
+
If no identification is declared for a subtype, it uses the identification
|
|
182
|
+
of its first supertype:
|
|
183
|
+
|
|
184
|
+
Vehicle Policy is a kind of Insurance Policy;
|
|
185
|
+
}
|
|
186
|
+
when /fact/
|
|
187
|
+
puts %Q{
|
|
188
|
+
A Fact Type consists of one or more readings, where every reading has
|
|
189
|
+
the same role players interspersed amongst unrestricted (almost!) text.
|
|
190
|
+
Each role player is a Term (/help term) which denotes a Value Type or
|
|
191
|
+
Entity Type (including an objectified Fact Type). Terms are always
|
|
192
|
+
singular (except where a singular group is indicated).
|
|
193
|
+
|
|
194
|
+
The last role player in each reading may be preceded by a quantifier
|
|
195
|
+
(one, at most one, at least one, etc). Note that "one" or "at least one"
|
|
196
|
+
make the relevant fact instance mandatory:
|
|
197
|
+
|
|
198
|
+
Person directs Company,
|
|
199
|
+
Company is directed by at least 2 Person;
|
|
200
|
+
|
|
201
|
+
Any role player may be preceeded or followed by an adjective, using
|
|
202
|
+
an adjacent hyphen to indicate the adjective. The hyphen is required
|
|
203
|
+
only for one occurrence of the adjective, and other occurrences will
|
|
204
|
+
be recognised. Other hyphenated words are allowed in readings, as
|
|
205
|
+
long as neither word is an existing term.
|
|
206
|
+
|
|
207
|
+
// Using the Entity Type 'Person' and Value Type 'Name':
|
|
208
|
+
Person has one family Name, family-Name is of Person;
|
|
209
|
+
|
|
210
|
+
// Using the Entity Type 'Personne' and Value Type 'Nom':
|
|
211
|
+
Personne à Nom-donné;
|
|
212
|
+
|
|
213
|
+
Multiple adjectives may be used, as long as the hyphen has adjacent space:
|
|
214
|
+
|
|
215
|
+
Person driving semi-trailer avoided stray- farm Animal;
|
|
216
|
+
|
|
217
|
+
Any role player may define a Role Name, which is used to refer to
|
|
218
|
+
this player in other readings of this fact type:
|
|
219
|
+
|
|
220
|
+
Person (as Director) directs Company,
|
|
221
|
+
Company is directed by Director;
|
|
222
|
+
|
|
223
|
+
Any role player may be followed by a role value restriction (/help constraint):
|
|
224
|
+
|
|
225
|
+
Person was born on one birth-Date restricted to {'1900/01/01'..};
|
|
226
|
+
|
|
227
|
+
A Fact Type which has no embedded uniqueness constraint must be
|
|
228
|
+
objectified (named) by prefixing it with an "is where" clause.
|
|
229
|
+
An objectified fact type is an Entity Type, so maye be used as a
|
|
230
|
+
player in subsequent Fact Types:
|
|
231
|
+
|
|
232
|
+
Directorship is where
|
|
233
|
+
Person directs Company;
|
|
234
|
+
Directorship began on at most one appointment-Date;
|
|
235
|
+
|
|
236
|
+
Finally, an objectified Fact Type may be a subtype, and may also have
|
|
237
|
+
separate identification like an Entity Type (/help entity):
|
|
238
|
+
|
|
239
|
+
Vehicle Claim is a kind of Insurance Claim identified by Incident ID where
|
|
240
|
+
Incident ID is of one Vehicle Claim,
|
|
241
|
+
Vehicle Claim has one Incident ID,
|
|
242
|
+
Insured Person claimed against Policy on Date;
|
|
243
|
+
}
|
|
244
|
+
when /instance/
|
|
245
|
+
puts %Q{
|
|
246
|
+
An instance (or a collection of instances) is a reading or term (or
|
|
247
|
+
joined collection of readings) with values following the Value Types.
|
|
248
|
+
Simply-identified entities may be contracted by providing the value directly.
|
|
249
|
+
Adjectives, role names and subscripts may be used to differentiate multiple
|
|
250
|
+
occurrences of the same object types.
|
|
251
|
+
|
|
252
|
+
Company Name 'Microsoft'; // An instance of Company Name (a Value Type)
|
|
253
|
+
Company 'Sun'; // An instance of Company identified by the Company Name 'Sun'
|
|
254
|
+
Company 'Sun' was founded on Date '1982-02-24'; // A simple binary fact over two objects
|
|
255
|
+
family Name 'Smith' is of Person, Person has given Name 'Daniel'; // Two facts joined
|
|
256
|
+
family Name 'Smith' is of Person who has given Name 'Daniel'; // The same, contracted
|
|
257
|
+
// A collection of facts involving several kinds of join:
|
|
258
|
+
Directorship (where Person directs Company 'Sun') began in Year '1982',
|
|
259
|
+
family Name 'Joy' is of Person that has given Name 'Bill',
|
|
260
|
+
Person was born on Date '1954-11-8;
|
|
261
|
+
}
|
|
262
|
+
when /query/
|
|
263
|
+
puts %Q{
|
|
264
|
+
Queries are not yet implemented
|
|
265
|
+
}
|
|
266
|
+
when /term/
|
|
267
|
+
puts %Q{
|
|
268
|
+
A Term is used to identify a Value Type or Entity Type (collectively, Object
|
|
269
|
+
Types). A Term may be any word or sequence of words, each word being one
|
|
270
|
+
or more alphanumeric characters (or underscore) but not starting with a
|
|
271
|
+
digit. Terms are preferably capitalised; this makes it easier to construct
|
|
272
|
+
unambiguous fact type readings.
|
|
273
|
+
|
|
274
|
+
Many keywords are disallowed as Terms, but not all.
|
|
275
|
+
}
|
|
276
|
+
when /value/
|
|
277
|
+
puts %Q{
|
|
278
|
+
A Value Type is a kind of Object Type which has an accepted written form.
|
|
279
|
+
For example, a Name or a Date can be written, but a Person cannot. A Year
|
|
280
|
+
is not a Value Type, but a Year Number is.
|
|
281
|
+
|
|
282
|
+
Every written value must uniquely identify one instance of that Value Type.
|
|
283
|
+
A value may have more than one written form. For example, the number 10000
|
|
284
|
+
may also be written 10E4. A written value may identify a single instance of
|
|
285
|
+
more than one value type however; the string '9/11' may identify a fraction,
|
|
286
|
+
or an event.
|
|
287
|
+
|
|
288
|
+
Value Types are asserted by the phrase "is written as":
|
|
289
|
+
|
|
290
|
+
Birth Date is written as Date;
|
|
291
|
+
Employee Nr is written as Integer;
|
|
292
|
+
|
|
293
|
+
If the supertype (the value type after "is written as") is unknown, it is
|
|
294
|
+
also asserted as a Value Type.
|
|
295
|
+
|
|
296
|
+
A Value Type may have implicit length and scale properties, and in future,
|
|
297
|
+
may also have custom properties. Property values are defined in parentheses
|
|
298
|
+
after the supertype:
|
|
299
|
+
|
|
300
|
+
Money Amount is written as Decimal(14, 2);
|
|
301
|
+
Company Name is written as String(60);
|
|
302
|
+
|
|
303
|
+
After any parameter list, a Value Type may be associated with a Unit, and be
|
|
304
|
+
subject to a Value Restriction (using "restricted to { <values or ranges> }").
|
|
305
|
+
Either the low end or the high end of a range may be omitted for an open range.
|
|
306
|
+
|
|
307
|
+
Drill Size is written as Real in mm restricted to { 0.3, 0.5..15.0};
|
|
308
|
+
}
|
|
309
|
+
when /vocabulary/
|
|
310
|
+
%q{
|
|
311
|
+
Every CQL definition or instance exists in some vocabulary, so you must
|
|
312
|
+
specify a vocabulary name before any other definitions:
|
|
313
|
+
|
|
314
|
+
vocabulary Employment;
|
|
315
|
+
... definitions...
|
|
316
|
+
}
|
|
317
|
+
else
|
|
318
|
+
puts "topic #{word} is unknown"
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
compiler = InteractiveCQL.new
|
|
326
|
+
statement = nil
|
|
327
|
+
puts "Enter / for help on special commands"
|
|
328
|
+
while line = Readline::readline(statement ? "CQL+ " : "CQL? ", [])
|
|
329
|
+
statement = statement ? statement + "\n"+line : line
|
|
330
|
+
if line =~ %r{\A/}
|
|
331
|
+
compiler.metacommand(line)
|
|
332
|
+
statement = nil
|
|
333
|
+
elsif compiler.root != :definition or
|
|
334
|
+
line.gsub(/(['"])([^\1\\]|\\.)*\1/,'') =~ /[;?]/
|
|
335
|
+
# After stripping string literals the line contains a ';' or /?', we've found the last line of the command:
|
|
336
|
+
compiler.process(statement)
|
|
60
337
|
statement = nil
|
|
61
338
|
end
|
|
62
339
|
end
|