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.
Files changed (118) hide show
  1. data/Manifest.txt +33 -2
  2. data/README.rdoc +30 -36
  3. data/Rakefile +16 -20
  4. data/bin/afgen +17 -11
  5. data/bin/cql +313 -36
  6. data/download.html +43 -19
  7. data/examples/CQL/Address.cql +15 -15
  8. data/examples/CQL/Blog.cql +8 -8
  9. data/examples/CQL/CompanyDirectorEmployee.cql +6 -5
  10. data/examples/CQL/Death.cql +3 -3
  11. data/examples/CQL/Diplomacy.cql +48 -0
  12. data/examples/CQL/Genealogy.cql +41 -41
  13. data/examples/CQL/Insurance.cql +311 -0
  14. data/examples/CQL/JoinEquality.cql +35 -0
  15. data/examples/CQL/Marriage.cql +1 -1
  16. data/examples/CQL/Metamodel.cql +290 -185
  17. data/examples/CQL/MetamodelNext.cql +420 -0
  18. data/examples/CQL/Monogamy.cql +24 -0
  19. data/examples/CQL/MonthInSeason.cql +27 -0
  20. data/examples/CQL/Moon.cql +23 -0
  21. data/examples/CQL/MultiInheritance.cql +4 -4
  22. data/examples/CQL/NonRoleId.cql +14 -0
  23. data/examples/CQL/OddIdentifier.cql +18 -0
  24. data/examples/CQL/OilSupply.cql +24 -24
  25. data/examples/CQL/OneToOnes.cql +17 -0
  26. data/examples/CQL/Orienteering.cql +55 -55
  27. data/examples/CQL/OrienteeringER.cql +58 -0
  28. data/examples/CQL/PersonPlaysGame.cql +2 -2
  29. data/examples/CQL/RedundantDependency.cql +34 -0
  30. data/examples/CQL/SchoolActivities.cql +5 -5
  31. data/examples/CQL/SeparateSubtype.cql +28 -0
  32. data/examples/CQL/ServiceDirector.cql +283 -0
  33. data/examples/CQL/SimplestUnary.cql +2 -2
  34. data/examples/CQL/SubtypePI.cql +11 -11
  35. data/examples/CQL/Supervision.cql +38 -0
  36. data/examples/CQL/Tests.Test5.Load.cql +38 -0
  37. data/examples/CQL/WaiterTips.cql +33 -0
  38. data/examples/CQL/Warehousing.cql +55 -53
  39. data/examples/CQL/WindowInRoomInBldg.cql +9 -9
  40. data/examples/CQL/unit.cql +433 -544
  41. data/examples/index.html +314 -170
  42. data/examples/intro.html +6 -176
  43. data/examples/local.css +8 -4
  44. data/index.html +40 -25
  45. data/lib/activefacts/api/concept.rb +2 -2
  46. data/lib/activefacts/api/constellation.rb +4 -4
  47. data/lib/activefacts/api/instance.rb +2 -2
  48. data/lib/activefacts/api/instance_index.rb +4 -0
  49. data/lib/activefacts/api/numeric.rb +3 -1
  50. data/lib/activefacts/api/role.rb +1 -1
  51. data/lib/activefacts/api/standard_types.rb +23 -16
  52. data/lib/activefacts/api/support.rb +3 -1
  53. data/lib/activefacts/api/vocabulary.rb +4 -0
  54. data/lib/activefacts/cql/CQLParser.treetop +87 -39
  55. data/lib/activefacts/cql/Concepts.treetop +95 -69
  56. data/lib/activefacts/cql/Context.treetop +11 -2
  57. data/lib/activefacts/cql/Expressions.treetop +23 -59
  58. data/lib/activefacts/cql/FactTypes.treetop +141 -95
  59. data/lib/activefacts/cql/Language/English.treetop +33 -21
  60. data/lib/activefacts/cql/LexicalRules.treetop +6 -1
  61. data/lib/activefacts/cql/Terms.treetop +75 -26
  62. data/lib/activefacts/cql/ValueTypes.treetop +52 -54
  63. data/lib/activefacts/cql/compiler.rb +46 -1691
  64. data/lib/activefacts/cql/compiler/constraint.rb +602 -0
  65. data/lib/activefacts/cql/compiler/entity_type.rb +425 -0
  66. data/lib/activefacts/cql/compiler/fact.rb +300 -0
  67. data/lib/activefacts/cql/compiler/fact_type.rb +230 -0
  68. data/lib/activefacts/cql/compiler/reading.rb +832 -0
  69. data/lib/activefacts/cql/compiler/shared.rb +109 -0
  70. data/lib/activefacts/cql/compiler/value_type.rb +104 -0
  71. data/lib/activefacts/cql/parser.rb +132 -81
  72. data/lib/activefacts/generate/cql.rb +397 -274
  73. data/lib/activefacts/generate/oo.rb +13 -12
  74. data/lib/activefacts/generate/ordered.rb +107 -117
  75. data/lib/activefacts/generate/ruby.rb +34 -38
  76. data/lib/activefacts/generate/sql/mysql.rb +62 -45
  77. data/lib/activefacts/generate/sql/server.rb +59 -42
  78. data/lib/activefacts/input/cql.rb +6 -3
  79. data/lib/activefacts/input/orm.rb +991 -557
  80. data/lib/activefacts/persistence/columns.rb +16 -12
  81. data/lib/activefacts/persistence/foreignkey.rb +7 -4
  82. data/lib/activefacts/persistence/index.rb +3 -4
  83. data/lib/activefacts/persistence/reference.rb +5 -2
  84. data/lib/activefacts/support.rb +20 -14
  85. data/lib/activefacts/version.rb +1 -1
  86. data/lib/activefacts/vocabulary.rb +1 -0
  87. data/lib/activefacts/vocabulary/extensions.rb +328 -44
  88. data/lib/activefacts/vocabulary/metamodel.rb +145 -20
  89. data/lib/activefacts/vocabulary/verbaliser.rb +621 -0
  90. data/spec/absorption_spec.rb +4 -4
  91. data/spec/api/value_type.rb +1 -1
  92. data/spec/cql/context_spec.rb +45 -22
  93. data/spec/cql/deontic_spec.rb +88 -0
  94. data/spec/cql/matching_spec.rb +517 -0
  95. data/spec/cql/samples_spec.rb +88 -31
  96. data/spec/cql/unit_spec.rb +58 -37
  97. data/spec/cql_cql_spec.rb +12 -7
  98. data/spec/cql_mysql_spec.rb +3 -7
  99. data/spec/cql_parse_spec.rb +0 -4
  100. data/spec/cql_ruby_spec.rb +1 -4
  101. data/spec/cql_sql_spec.rb +5 -18
  102. data/spec/cql_symbol_tables_spec.rb +3 -0
  103. data/spec/cqldump_spec.rb +0 -2
  104. data/spec/helpers/array_matcher.rb +35 -0
  105. data/spec/helpers/ctrl_c_support.rb +52 -0
  106. data/spec/helpers/diff_matcher.rb +38 -0
  107. data/spec/helpers/file_matcher.rb +5 -3
  108. data/spec/helpers/string_matcher.rb +39 -0
  109. data/spec/helpers/test_parser.rb +13 -0
  110. data/spec/norma_cql_spec.rb +13 -5
  111. data/spec/norma_ruby_spec.rb +11 -3
  112. data/spec/{absorption_ruby_spec.rb → norma_ruby_sql_spec.rb} +37 -32
  113. data/spec/norma_sql_spec.rb +11 -5
  114. data/spec/norma_tables_spec.rb +33 -29
  115. data/spec/spec_helper.rb +4 -1
  116. data/status.html +92 -23
  117. metadata +102 -36
  118. 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 is a semantic modeling toolkit, comprising an implementation
8
- of the Constellation Query Language, the Constellation API, and code
9
- generators that receive CQL or ORM (Object Role Modeling files, from
10
- NORMA) to emit CQL, Ruby and SQL.
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
- Semantic modeling is a refinement of fact-based modeling techniques
13
- that draw on natural language verbalisation and formal logic. Fact
14
- based modeling is essentially the same as relational modeling in the
15
- sixth normal form. The tools provided here automatically condense
16
- that to third normal form for efficient storage. They also generate
17
- object models as a Ruby module which has an effective mapping to
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
- == FEATURES/PROBLEMS:
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
- * Queries are parsed, but not yet generated to SQL. DDL is complete.
26
+ == SYNOPSIS:
28
27
 
29
- * The Constellation API lacks SQL persistence (but is already useful;
30
- the CQL compiler uses the generated Ruby code extensively)
28
+ afgen --sql/server myfile.cql
29
+ afgen --ruby myfile.cql
30
+ afgen --cql myfile.orm
31
31
 
32
- * Re-invoking a fact type to add new readings doesn't work
32
+ == INSTALL:
33
33
 
34
- * Some types of external constraints (when adjectives mis-match)
35
- don't yet pass the CQL parser's semantic analysis.
34
+ * sudo gem install activefacts
36
35
 
37
- * Validation of semantic models (and many other areas) is incomplete
36
+ == UNIMPLEMENTED FEATURES
38
37
 
39
- * There's no interactive CQL interpreter yet; the cql command merely
40
- shows the parse tree.
38
+ * Queries are parsed, but not yet generated to SQL.
41
39
 
42
- == SYNOPSIS:
40
+ * The Constellation API lacks SQL persistence (but is already useful;
41
+ the CQL compiler uses the generated Ruby code extensively)
43
42
 
44
- afgen --sql/server myfile.cql
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
- == INSTALL:
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
- require 'hanna/rdoctask'
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 is a semantic modeling toolkit, comprising an implementation
14
- of the Constellation Query Language, the Constellation API, and code
15
- generators that receive CQL or ORM (Object Role Modeling files, from
16
- NORMA) to emit CQL, Ruby and SQL.
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] = %w{
46
- -S -T hanna
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
- # ActiveFacts: Read a Vocabulary (from a NORMA, CQL or other file) and run a generator
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 ENV['DEBUG']
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) # Stop when an exception is thrown, but before it's rescued
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
- true # Ok, got the stack set up, continue to the fault
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 "#{e}:\n\t#{e.backtrace*"\n\t"}" if debug
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
- # ActiveFacts: Interactive CQL command-line. Incomplete; only parses CQL and shows the parse trees
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 ENV['DEBUG']
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
- debugger if debug :exception
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
- puts "This is a stub for the CQL interactive commandline. At the moment it only parses CQL and shows the parse trees."
19
+ require 'activefacts'
20
+ require 'activefacts/cql/compiler'
23
21
 
24
- parser = ActiveFacts::CQL::Parser.new
25
- parser.root = :definition
26
- statement = nil
27
- while line = Readline::readline(statement ? "CQL+ " : "CQL? ", [])
28
- statement = statement ? statement + "\n"+line : line
29
- if line =~ %r{\A/}
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
- case (words = line.split).shift
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
- parser.root = words[0] && words[0].to_sym || :definition
34
- puts "ok"
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
- puts "Unknown metacommand #{line}, did you mean /root <rule>?"
37
- end
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
- p parser.failure_reason
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