activefacts 0.8.6 → 0.8.8

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