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
@@ -7,69 +7,93 @@ require 'activefacts/support'
7
7
  require 'activefacts/api/support'
8
8
  require 'activefacts/input/cql'
9
9
 
10
+ require 'set'
11
+
10
12
  describe "Sample data" do
11
13
  SamplePrefix = %q{
12
14
  vocabulary V;
13
15
 
14
- CompanyName is written as String;
16
+ Company Name is written as String;
15
17
  Company is identified by its Name;
16
- Person is identified by its Name where Person is called PersonName;
18
+ Person is identified by its Name where Person is called Person Name;
17
19
  Directorship is where
18
20
  Company is directed by Person;
19
21
  }
20
22
 
21
- Samples = [
23
+ GoodSamples = [
22
24
  [ # A simple ValueType instance
23
- "CompanyName 'Microsoft';",
24
- [{:facts=>[], :instances=>["CompanyName 'Microsoft'"]}]
25
+ "Company Name 'Microsoft';",
26
+ [{:facts=>Set[], :instances=>Set["Company Name 'Microsoft'"]}]
25
27
  ],
26
28
  [ # Re-assert the same instance
27
- "CompanyName 'Microsoft'; CompanyName 'Microsoft';",
28
- [{:facts=>[], :instances=>["CompanyName 'Microsoft'"]}]
29
+ "Company Name 'Microsoft'; Company Name 'Microsoft';",
30
+ [{:facts=>Set[], :instances=>Set["Company Name 'Microsoft'"]}]
29
31
  ],
30
32
  [ # The same instance, but in a named population
31
- "example: CompanyName 'Microsoft';",
32
- [{:facts=>[], :instances=>["CompanyName 'Microsoft'"]}]
33
+ "example: Company Name 'Microsoft';",
34
+ [{:facts=>Set[], :instances=>Set["Company Name 'Microsoft'"]}]
33
35
  ],
34
36
  [ # A simply-identified EntityType instance
35
37
  "Company 'Microsoft';",
36
- [{:facts=>["Company has CompanyName 'Microsoft'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'"]}]
38
+ [{:facts=>Set["Company has Company Name 'Microsoft'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'"]}]
37
39
  ],
38
40
  [ # Re-assert the same instance
39
41
  "Company 'Microsoft'; Company 'Microsoft';",
40
- [{:facts=>["Company has CompanyName 'Microsoft'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'"]}]
42
+ [{:facts=>Set["Company has Company Name 'Microsoft'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'"]}]
41
43
  ],
42
44
  [ # The same instance in a named population
43
45
  "example: Company 'Microsoft';",
44
- [{:facts=>["Company has CompanyName 'Microsoft'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'"]}]
46
+ [{:facts=>Set["Company has Company Name 'Microsoft'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'"]}]
45
47
  ],
46
48
  [ # The Company instance asserted with an explicit identifying fact
47
- "Company has CompanyName 'Microsoft';",
48
- [{:facts=>["Company has CompanyName 'Microsoft'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'"]}]
49
+ "Company has Company Name 'Microsoft';",
50
+ [{:facts=>Set["Company has Company Name 'Microsoft'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'"]}]
49
51
  ],
50
52
  [ # The Company instance asserted with an joined identifying instance
51
- "Company has CompanyName, CompanyName 'Microsoft';",
52
- [{:facts=>["Company has CompanyName 'Microsoft'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'"]}]
53
+ "Company has Company Name, Company Name 'Microsoft';",
54
+ [{:facts=>Set["Company has Company Name 'Microsoft'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'"]}]
53
55
  ],
54
56
  [ # The same, with an explicit identifying instance join
55
- "CompanyName 'Microsoft', Company has CompanyName;",
56
- [{:facts=>["Company has CompanyName 'Microsoft'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'"]}]
57
+ "Company Name 'Microsoft', Company has Company Name;",
58
+ [{:facts=>Set["Company has Company Name 'Microsoft'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'"]}]
57
59
  ],
58
60
  [ # A simple fact instance with two simply-identified entities
59
61
  "Company 'Microsoft' is directed by Person 'Gates';",
60
- [{:facts=>["Company has CompanyName 'Microsoft'", "Company is directed by Person", "Person is called PersonName 'Gates'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by PersonName where Person is called PersonName 'Gates'", "PersonName 'Gates'"]}]
62
+ [{:facts=>Set["Company has Company Name 'Microsoft'", "Company is directed by Person", "Person is called Person Name 'Gates'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by Person Name where Person is called Person Name 'Gates'", "Person Name 'Gates'"]}]
61
63
  ],
62
64
  [ # Same with an explicit joined fact
63
- "Company 'Microsoft' is directed by Person, Person is called PersonName 'Gates';",
64
- [{:facts=>["Company has CompanyName 'Microsoft'", "Company is directed by Person", "Person is called PersonName 'Gates'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by PersonName where Person is called PersonName 'Gates'", "PersonName 'Gates'"]}]
65
+ "Company 'Microsoft' is directed by Person, Person is called Person Name 'Gates';",
66
+ [{:facts=>Set["Company has Company Name 'Microsoft'", "Company is directed by Person", "Person is called Person Name 'Gates'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by Person Name where Person is called Person Name 'Gates'", "Person Name 'Gates'"]}]
65
67
  ],
66
68
  [ # Same with explicitly joined facts and instances
67
- "Company is directed by Person, Person is called PersonName, PersonName 'Gates', Company has CompanyName, CompanyName 'Microsoft';",
68
- [{:facts=>["Company has CompanyName 'Microsoft'", "Company is directed by Person", "Person is called PersonName 'Gates'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by PersonName where Person is called PersonName 'Gates'", "PersonName 'Gates'"]}]
69
+ "Company is directed by Person, Person is called Person Name, Person Name 'Gates', Company has Company Name, Company Name 'Microsoft';",
70
+ [{:facts=>Set["Company has Company Name 'Microsoft'", "Company is directed by Person", "Person is called Person Name 'Gates'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by Person Name where Person is called Person Name 'Gates'", "Person Name 'Gates'"]}]
69
71
  ],
70
72
  [ # Same in a named population
71
- "example: Company is directed by Person, Person is called PersonName, PersonName 'Gates', Company has CompanyName, CompanyName 'Microsoft';",
72
- [{:facts=>["Company has CompanyName 'Microsoft'", "Company is directed by Person", "Person is called PersonName 'Gates'"], :instances=>["Company is identified by CompanyName where Company has CompanyName 'Microsoft'", "CompanyName 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by PersonName where Person is called PersonName 'Gates'", "PersonName 'Gates'"]}]
73
+ "example: Company is directed by Person, Person is called Person Name, Person Name 'Gates', Company has Company Name, Company Name 'Microsoft';",
74
+ [{:facts=>Set["Company has Company Name 'Microsoft'", "Company is directed by Person", "Person is called Person Name 'Gates'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by Person Name where Person is called Person Name 'Gates'", "Person Name 'Gates'"]}]
75
+ ],
76
+
77
+ # Objectification examples
78
+ [ # Same in a named population
79
+ "Directorship (where Company 'Microsoft' is directed by Person 'Gates');",
80
+ :pending # [{:facts=>Set["Company has Company Name 'Microsoft'", "Company is directed by Person", "Person is called Person Name 'Gates'"], :instances=>Set["Company is identified by Company Name where Company has Company Name 'Microsoft'", "Company Name 'Microsoft'", "Directorship where Company is directed by Person", "Person is identified by Person Name where Person is called Person Name 'Gates'", "Person Name 'Gates'"]}]
81
+ ],
82
+ ]
83
+
84
+ BadSamples =
85
+ [
86
+ [
87
+ "Company Name",
88
+ "Company Name",
89
+ ],
90
+ [
91
+ "foo: Company Name",
92
+ "Company Name",
93
+ ],
94
+ [ # Omit the company name:
95
+ "example: Company is directed by Person, Person is called Person Name, Person Name 'Gates', Company has Company Name;",
96
+ [ "Company (lacking Company Name)", "Company Name (needs a value)" ]
73
97
  ],
74
98
  ]
75
99
 
@@ -104,7 +128,7 @@ describe "Sample data" do
104
128
  " is identified by " +
105
129
  identifying_role_refs.map do |rr|
106
130
  [ (l = rr.leading_adjective) ? l+"-" : nil,
107
- rr.role_name || rr.role.concept.name,
131
+ rr.role.role_name || rr.role.concept.name,
108
132
  (t = rr.trailing_adjective) ? l+"-" : nil
109
133
  ].compact*""
110
134
  end * " and " +
@@ -123,17 +147,23 @@ describe "Sample data" do
123
147
  populations.keys.sort.map do |popname|
124
148
  popvalue = populations[popname]
125
149
  {
126
- :instances => popvalue.all_instance.map { |i| instance_name(i) }.sort,
127
- :facts => popvalue.all_fact.map { |fact| instance_name(fact) }.sort
150
+ :instances => Set[*popvalue.all_instance.map { |i| instance_name(i) }],
151
+ :facts => Set[*popvalue.all_fact.map { |fact| instance_name(fact) }]
128
152
  }
129
153
  end
130
154
  end
131
155
 
132
- Samples.each do |c|
156
+ # [].
157
+ GoodSamples.
158
+ each do |c|
133
159
  source, expected = *Array(c)
160
+
134
161
  it "should handle #{source.inspect}" do
135
162
  @text = SamplePrefix+source
136
- @vocabulary = ActiveFacts::Input::CQL.readstring(@text)
163
+ pending if expected == :pending
164
+ lambda do
165
+ @vocabulary = ActiveFacts::Input::CQL.readstring(@text)
166
+ end.should_not raise_error
137
167
  result = instance_data(@vocabulary)
138
168
 
139
169
  if expected
@@ -146,9 +176,36 @@ describe "Sample data" do
146
176
  it "should de-duplicate #{source.inspect}" do
147
177
  # Make sure you don't get anything duplicated
148
178
  @text = SamplePrefix+source+source
149
- @vocabulary = ActiveFacts::Input::CQL.readstring(@text)
179
+ pending if expected == :pending
180
+ lambda do
181
+ @vocabulary = ActiveFacts::Input::CQL.readstring(@text)
182
+ end.should_not raise_error
150
183
  result = instance_data(@vocabulary)
151
184
  result[0].should == expected[0]
152
185
  end
186
+
153
187
  end
188
+
189
+ BadSamples.each do |c|
190
+ source, missing = *Array(c)
191
+ it "should detect missing joins in #{source.inspect}" do
192
+ @text = SamplePrefix+source
193
+ lambda do
194
+ begin
195
+ @vocabulary = ActiveFacts::Input::CQL.readstring(@text)
196
+ rescue => @exception
197
+ raise
198
+ end
199
+ end.should raise_error
200
+
201
+ if missing
202
+ missing.each do |m|
203
+ @exception.message.should =~ (m.is_a?(Regexp) ? m : Regexp.new(Regexp.escape(m)))
204
+ end
205
+ else
206
+ pending "raised #{@exception}"
207
+ end
208
+ end
209
+ end
210
+
154
211
  end
@@ -3,13 +3,19 @@
3
3
  # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
4
  #
5
5
 
6
+ =begin
7
+ REVISIT: These tests are important, but the intermediate layer they test no longer exists. Find another solution!
8
+
9
+ require 'spec/helpers/test_parser'
6
10
  require 'activefacts/support'
7
11
  require 'activefacts/api/support'
8
12
  require 'activefacts/cql/parser'
13
+ require File.dirname(__FILE__) + '/../helpers/test_parser'
9
14
 
10
15
  describe "Valid Numbers, Strings and Ranges" do
11
16
  ValidNumbersEtc = [
12
17
  "a is written as b;", # Value type declaration, no params, minimal whitespace
18
+ "a is written as B;", # Value type declaration, no params, minimal whitespace
13
19
  "a is written as b();", # Value type declaration, minimal whitespace
14
20
  "a is written as b ;", # Value type declaration, no params, trailing whitespace
15
21
  "a is written as b ( ) ; ", # Value type declaration, maximal whitespace
@@ -58,7 +64,7 @@ describe "Valid Numbers, Strings and Ranges" do
58
64
  "a is written as b inch^2/minute^-1;", # Value type declaration with unit and divided unit with exponents
59
65
  "a is written as b() second^-1/mm^-1 mm^-1;", # Value type declaration with repeated divided unit
60
66
 
61
- # Integer value restrictions
67
+ # Integer value constraints
62
68
  "a is written as b()restricted to{1};", # Integer, minimal whitespace
63
69
  "a is written as b() restricted to { 1 } ;", # Integer, maximal whitespace
64
70
  "a is written as b() restricted to {1..2};", # Integer range, minimal whitespace
@@ -76,7 +82,7 @@ describe "Valid Numbers, Strings and Ranges" do
76
82
  "a is written as b() restricted to { 1e-4 } ;", # Integer with negative exponent
77
83
  "a is written as b() restricted to { -1e-4 } ;", # Negative integer with negative exponent
78
84
 
79
- # Real value restrictions
85
+ # Real value constraints
80
86
  "a is written as b() restricted to {1.0};", # Real, minimal whitespace
81
87
  "a is written as b() restricted to { 1.0 } ;", # Real, maximal whitespace
82
88
  "a is written as b() restricted to { 1.0e4 } ;", # Real with exponent
@@ -91,7 +97,7 @@ describe "Valid Numbers, Strings and Ranges" do
91
97
  "a is written as b() restricted to { 1.1.. };", # Real range with open end
92
98
  "a is written as b() restricted to { 1.1.., 2 };", # Real range with open end and following integer
93
99
 
94
- # Strings and string value restrictions
100
+ # Strings and string value constraints
95
101
  "a is written as b() restricted to {''};", # String, empty, minimal whitespace
96
102
  "a is written as b() restricted to {'A'};", # String, minimal whitespace
97
103
  "a is written as b() restricted to { 'A' };", # String, maximal whitespace
@@ -107,13 +113,13 @@ describe "Valid Numbers, Strings and Ranges" do
107
113
  "a is written as b() restricted to { ..'F' };", # String range, open start
108
114
  "a is written as b() restricted to { 'A'.. };", # String range, open end
109
115
 
110
- # Value restrictions with units
111
- "a is written as b() restricted to {1} inches^2/second;", # restriction with units and exponent
112
- "a is written as b() second^-1/mm^-1 mm^-1 restricted to {1} inches^2/second;", # type with unit and restriction with units and exponent
116
+ # Value constraints with units
117
+ "a is written as b() restricted to {1} inches^2/second;", # constraint with units and exponent
118
+ "a is written as b() second^-1/mm^-1 mm^-1 restricted to {1} inches^2/second;", # type with unit and constraint with units and exponent
113
119
  ]
114
120
 
115
121
  before :each do
116
- @parser = ActiveFacts::CQL::Parser.new
122
+ @parser = TestParser.new
117
123
  end
118
124
 
119
125
  ValidNumbersEtc.each do |c|
@@ -150,7 +156,7 @@ describe "Invalid Numbers and Strings" do
150
156
  ]
151
157
 
152
158
  before :each do
153
- @parser = ActiveFacts::CQL::Parser.new
159
+ @parser = TestParser.new
154
160
  end
155
161
 
156
162
  InvalidValueTypes.each do |c|
@@ -175,7 +181,7 @@ describe "Value Types" do
175
181
  ]
176
182
 
177
183
  before :each do
178
- @parser = ActiveFacts::CQL::Parser.new
184
+ @parser = TestParser.new
179
185
  end
180
186
 
181
187
  ValueTypes.each do |c|
@@ -195,49 +201,49 @@ end
195
201
  describe "Entity Types" do
196
202
  EntityTypes_RefMode = [
197
203
  [ "a is identified by its id;", # Entity type declaration with reference mode
198
- [["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :restriction=>nil}, [], nil]]]
204
+ [["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :value_constraint=>nil}, [], nil]]]
199
205
  ],
200
206
  [ "a is identified by its number(12);", # Entity type declaration with reference mode
201
- [["a", [:entity_type, [], {:enforcement=>nil, :mode=>"number", :parameters=>[12], :restriction=>nil}, [], nil]]]
207
+ [["a", [:entity_type, [], {:enforcement=>nil, :mode=>"number", :parameters=>[12], :value_constraint=>nil}, [], nil]]]
202
208
  ],
203
209
  [ "a is identified by its id:c;", # Entity type declaration with reference mode and fact type(s)
204
- [["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :restriction=>nil}, [], [[:fact_clause, [], [{:word=>"c"}], nil]]]]]
210
+ [["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :value_constraint=>nil}, [], [[:fact_clause, [], ["c"], nil]]]]]
205
211
  ],
206
212
  [ "a is identified by its id where c;", # Entity type declaration with reference mode and where
207
- [["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :restriction=>nil}, [], [[:fact_clause, [], [{:word=>"c"}], nil]]]]]
213
+ [["a", [:entity_type, [], {:enforcement=>nil, :mode=>"id", :parameters=>[], :value_constraint=>nil}, [], [[:fact_clause, [], ["c"], nil]]]]]
208
214
  ],
209
215
  ]
210
216
 
211
217
  EntityTypes_Simple = [
212
218
  [ "a is identified by b: c;", # Entity type declaration
213
- [["a", [:entity_type, [], {:roles=>[["b"]]}, [], [[:fact_clause, [], [{:word=>"c"}], nil]]]]]
219
+ [["a", [:entity_type, [], {:roles=>[["b"]]}, [], [[:fact_clause, [], ["c"], nil]]]]]
214
220
  ],
215
221
  [ "a is identified by b where c;", # Entity type declaration with where
216
- [["a", [:entity_type, [], {:roles=>[["b"]]}, [], [[:fact_clause, [], [{:word=>"c"}], nil]]]]]
222
+ [["a", [:entity_type, [], {:roles=>[["b"]]}, [], [[:fact_clause, [], ["c"], nil]]]]]
217
223
  ],
218
224
  [ "a is identified by b and c: d;", # Entity type declaration with two-part identifier
219
- [["a", [:entity_type, [], {:roles=>[["b"], ["c"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
225
+ [["a", [:entity_type, [], {:roles=>[["b"], ["c"]]}, [], [[:fact_clause, [], ["d"], nil]]]]]
220
226
  ],
221
227
  [ "a is identified by b, c: d;", # Entity type declaration with two-part identifier
222
- [["a", [:entity_type, [], {:roles=>[["b"], ["c"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
228
+ [["a", [:entity_type, [], {:roles=>[["b"], ["c"]]}, [], [[:fact_clause, [], ["d"], nil]]]]]
223
229
  ],
224
230
  [ "a is written as b(); c is identified by a:d;",
225
- [["a", [:value_type, "b", [], [], [], [], nil]], ["c", [:entity_type, [], {:roles=>[["a"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
231
+ [["a", [:value_type, "b", [], [], [], [], nil]], ["c", [:entity_type, [], {:roles=>[["a"]]}, [], [[:fact_clause, [], ["d"], nil]]]]]
226
232
  ],
227
233
  [ " a is written as b ( ) ; c is identified by a : d ; ",
228
- [["a", [:value_type, "b", [], [], [], [], nil]], ["c", [:entity_type, [], {:roles=>[["a"]]}, [], [[:fact_clause, [], [{:word=>"d"}], nil]]]]]
234
+ [["a", [:value_type, "b", [], [], [], [], nil]], ["c", [:entity_type, [], {:roles=>[["a"]]}, [], [[:fact_clause, [], ["d"], nil]]]]]
229
235
  ],
230
236
  [ "a is identified by c:maybe d;",
231
- [["a", [:entity_type, [], {:roles=>[["c"]]}, [], [[:fact_clause, ["maybe"], [{:word=>"d"}], nil]]]]]
237
+ [["a", [:entity_type, [], {:roles=>[["c"]]}, [], [[:fact_clause, ["maybe"], ["d"], nil]]]]]
232
238
  ],
233
239
  ]
234
240
 
235
241
  EntityTypes_Objectified = [
236
242
  [ "Director is where Person directs Company, Company is directed by Person;",
237
- [["Director", [:fact_type, [[:fact_clause, [], [{:word=>"Person"}, {:word=>"directs"}, {:word=>"Company"}], nil], [:fact_clause, [], [{:word=>"Company"}, {:word=>"is"}, {:word=>"directed"}, {:word=>"by"}, {:word=>"Person"}], nil]], []]]]
243
+ [["Director", [:fact_type, [[:fact_clause, [], [{:word=>"Person", :term=>"Person"}, "directs", {:word=>"Company", :term=>"Company"}], nil], [:fact_clause, [], [{:word=>"Company", :term=>"Company"}, "is", "directed", "by", {:word=>"Person", :term=>"Person"}], nil]], []]]]
238
244
  ],
239
245
  [ "Director: Person directs company;",
240
- [[nil, [:fact_type, [[:fact_clause, [], [{:word=>"Director"}], nil]], [[:fact_clause, [], [{:word=>"Person"}, {:word=>"directs"}, {:word=>"company"}], nil]]]]]
246
+ [[nil, [:fact_type, [[:fact_clause, [], [{:word=>"Director", :term=>"Director"}], nil]], [[:fact_clause, [], [{:word=>"Person", :term=>"Person"}, "directs", "company"], nil]]]]]
241
247
  ],
242
248
  ]
243
249
 
@@ -269,7 +275,7 @@ describe "Entity Types" do
269
275
  EntityTypes_Subtypes
270
276
 
271
277
  before :each do
272
- @parser = ActiveFacts::CQL::Parser.new
278
+ @parser = TestParser.new
273
279
  end
274
280
 
275
281
  EntityTypes.each do |c|
@@ -291,31 +297,43 @@ end
291
297
 
292
298
  describe "Fact Types" do
293
299
  FactTypes = [
294
- [ "Director is old: Person directs company, Person is of age, age > 60;",
295
- [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Director"}, {:word=>"is"}, {:word=>"old"}], nil]], [[:fact_clause, [], [{:word=>"Person"}, {:word=>"directs"}, {:word=>"company"}], nil], [:fact_clause, [], [{:word=>"Person"}, {:word=>"is"}, {:word=>"of"}, {:word=>"age"}], nil], [">", [:variable, "age"], 60]]]]
300
+ [ "Foo has at most one Bar, Bar is of one Foo restricted to {1..10};",
301
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Foo", :term=>"Foo"}, "has", {:quantifier_restriction=>[], :word=>"Bar", :term=>"Bar", :quantifier=>[nil, 1]}], nil], [:fact_clause, [], [{:word=>"Bar", :term=>"Bar"}, "is", "of", {:value_constraint=>[[1, 10]], :quantifier_restriction=>[], :word=>"Foo", :term=>"Foo", :quantifier=>[1, 1], :value_constraint_enforcement=>[]}], nil]], []]]
302
+ ],
303
+ [ "Bar(1) is related to Bar(2), primary-Bar(1) has secondary-Bar(2);",
304
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Bar", :term=>"Bar", :role_name=>1}, "is", "related", "to", {:word=>"Bar", :term=>"Bar", :role_name=>2}], nil], [:fact_clause, [], [{:leading_adjective=>"primary", :word=>"primary Bar", :term=>"Bar", :role_name=>1}, "has", {:leading_adjective=>"secondary", :word=>"secondary Bar", :term=>"Bar", :role_name=>2}], nil]], []]]
305
+ ],
306
+ [ "Director is old: Person directs company, Person is of Age, Age > 60;",
307
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Director", :term=>"Director"}, "is", "old"], nil]], [[:fact_clause, [], [{:word=>"Person", :term=>"Person"}, "directs", "company"], nil], [:fact_clause, [], [{:word=>"Person", :term=>"Person"}, "is", "of", {:word=>"Age", :term=>"Age"}], nil], [">", [:variable, "Age"], 60]]]]
296
308
  ],
297
- [ "a: maybe a has completely- green b -totally [transitive, acyclic], b -c = 2;",
298
- [nil, [:fact_type, [[:fact_clause, [], [{:word=>"a"}], nil]], [[:fact_clause, ["maybe", "transitive", "acyclic"], [{:word=>"a"}, {:word=>"has"}, {:leading_adjective=>"completely", :word=>"green"}, {:trailing_adjective=>"totally", :word=>"b"}], nil], ["=", [:+, [:variable, "b"], [:-, [:variable, "c"]]], 2]]]]
309
+ [ "A is a farce: maybe A has completely- B [transitive, acyclic], B -c = 2;",
310
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"A", :term=>"A"}, "is", "a", "farce"], nil]], [[:fact_clause, ["maybe", "transitive", "acyclic"], [{:word=>"A", :term=>"A"}, "has", {:leading_adjective=>"completely", :word=>"completely B", :term=>"B"}], nil], ["=", [:variable, "B c"], 2]]]]
311
+ ],
312
+ [ "A is a farce: maybe A has completely- green B [transitive, acyclic], B -c = 2;",
313
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"A", :term=>"A"}, "is", "a", "farce"], nil]], [[:fact_clause, ["maybe", "transitive", "acyclic"], [{:word=>"A", :term=>"A"}, "has", {:leading_adjective=>"completely green", :word=>"completely green B", :term=>"B"}], nil], ["=", [:variable, "B c"], 2]]]]
314
+ ],
315
+ [ "A is a farce: maybe A has B green -totally [transitive, acyclic], B -c = 2;",
316
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"A", :term=>"A"}, "is", "a", "farce"], nil]], [[:fact_clause, ["maybe", "transitive", "acyclic"], [{:word=>"A", :term=>"A"}, "has", {:trailing_adjective=>"green totally", :word=>"B green totally", :term=>"B"}], nil], ["=", [:variable, "B c"], 2]]]]
299
317
  ],
300
318
  [ "Person is independent: Person has taxable- Income, taxable Income >= 20000 dollars;",
301
- [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Person"}, {:word=>"is"}, {:word=>"independent"}], nil]], [[:fact_clause, [], [{:word=>"Person"}, {:word=>"has"}, {:leading_adjective=>"taxable", :word=>"Income"}], nil], [">=", [:variable, "taxable", "Income"], [20000, "dollars"]]]]]
319
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Person", :term=>"Person"}, "is", "independent"], nil]], [[:fact_clause, [], [{:word=>"Person", :term=>"Person"}, "has", {:leading_adjective=>"taxable", :word=>"taxable Income", :term=>"Income"}], nil], [">=", [:variable, "taxable Income"], [20000, "dollars"]]]]]
302
320
  ],
303
- [ "Window requires toughening: Window has width-mm, Window has height-mm, width mm * height mm >= 10 foot^2;",
304
- [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Window"}, {:word=>"requires"}, {:word=>"toughening"}], nil]], [[:fact_clause, [], [{:word=>"Window"}, {:word=>"has"}, {:leading_adjective=>"width", :word=>"mm"}], nil], [:fact_clause, [], [{:word=>"Window"}, {:word=>"has"}, {:leading_adjective=>"height", :word=>"mm"}], nil], [">=", [:*, [:variable, "width", "mm"], [:variable, "height", "mm"]], [10, "foot^2"]]]]]
321
+ [ "Window requires toughening: Window has Width -mm, Window has Height -mm, Width mm * Height mm >= 10 foot^2;",
322
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"Window", :term=>"Window"}, "requires", "toughening"], nil]], [[:fact_clause, [], [{:word=>"Window", :term=>"Window"}, "has", {:trailing_adjective=>"mm", :word=>"Width mm", :term=>"Width"}], nil], [:fact_clause, [], [{:word=>"Window", :term=>"Window"}, "has", {:trailing_adjective=>"mm", :word=>"Height mm", :term=>"Height"}], nil], [">=", [:*, [:variable, "Width mm"], [:variable, "Height mm"]], [10, "foot^2"]]]]]
305
323
  ],
306
324
  # REVISIT: Test all quantifiers
307
325
  # REVISIT: Test all post-qualifiers
308
326
  # REVISIT: Test functions
309
- [ "AnnualIncome is where Person has total- Income in Year: Person has total- Income.sum(), Income was earned in current- time.Year() (as Year);",
310
- ["AnnualIncome", [:fact_type, [[:fact_clause, [], [{:word=>"Person"}, {:word=>"has"}, {:leading_adjective=>"total", :word=>"Income"}, {:word=>"in"}, {:word=>"Year"}], nil]], [[:fact_clause, [], [{:word=>"Person"}, {:word=>"has"}, {:leading_adjective=>"total", :function=>[:"(", "sum"], :word=>"Income"}], nil], [:fact_clause, [], [{:word=>"Income"}, {:word=>"was"}, {:word=>"earned"}, {:word=>"in"}, {:role_name=>"Year", :leading_adjective=>"current", :function=>[:"(", "Year"], :word=>"time"}], nil]]]]
327
+ [ "AnnualIncome is where Person has total- Income in Year: Person has total- Income.sum(), Income was earned in current- Time.Year() (as Year);",
328
+ ["AnnualIncome", [:fact_type, [[:fact_clause, [], [{:word=>"Person", :term=>"Person"}, "has", {:leading_adjective=>"total", :word=>"total Income", :term=>"Income"}, "in", {:word=>"Year", :term=>"Year"}], nil]], [[:fact_clause, [], [{:word=>"Person", :term=>"Person"}, "has", {:leading_adjective=>"total", :function=>[:"(", "sum"], :word=>"total Income", :term=>"Income"}], nil], [:fact_clause, [], [{:word=>"Income", :term=>"Income"}, "was", "earned", "in", {:leading_adjective=>"current", :function=>[:"(", "Year"], :role_name=>"Year", :word=>"current Time", :term=>"Time"}], nil]]]]
311
329
  ],
312
- [ "a is interesting : b- c -d has e- f -g;",
313
- [nil, [:fact_type, [[:fact_clause, [], [{:word=>"a"}, {:word=>"is"}, {:word=>"interesting"}], nil]], [[:fact_clause, [], [{:leading_adjective=>"b", :trailing_adjective=>"d", :word=>"c"}, {:word=>"has"}, {:leading_adjective=>"e", :trailing_adjective=>"g", :word=>"f"}], nil]]]]
330
+ [ "A is interesting : b- C has F -g;",
331
+ [nil, [:fact_type, [[:fact_clause, [], [{:word=>"A", :term=>"A"}, "is", "interesting"], nil]], [[:fact_clause, [], [{:leading_adjective=>"b", :word=>"b C", :term=>"C"}, "has", {:trailing_adjective=>"g", :word=>"F g", :term=>"F"}], nil]]]]
314
332
  ]
315
333
  ]
316
334
 
317
335
  before :each do
318
- @parser = ActiveFacts::CQL::Parser.new
336
+ @parser = TestParser.new
319
337
  end
320
338
 
321
339
  FactTypes.each do |c|
@@ -338,15 +356,17 @@ describe "Fact Types" do
338
356
  puts result.map{|d| d.value}.inspect unless ast
339
357
  end
340
358
  end
359
+ end
341
360
 
361
+ describe "Constraint" do
342
362
  Constraints = [
343
363
  [ "each combination FamilyName, GivenName occurs at most one time in Competitor has FamilyName, Competitor has GivenName;",
344
- [nil, [:constraint, :presence, [["FamilyName"], ["GivenName"]], [nil, 1], [[[{:word=>"Competitor"}, {:word=>"has"}, {:word=>"FamilyName"}]], [[{:word=>"Competitor"}, {:word=>"has"}, {:word=>"GivenName"}]]], nil, []]]
364
+ [nil, [:constraint, :presence, [["FamilyName"], ["GivenName"]], [nil, 1], [[[{:word=>"Competitor", :term=>"Competitor"}, "has", {:word=>"FamilyName", :term=>"FamilyName"}]], [[{:word=>"Competitor", :term=>"Competitor"}, "has", {:word=>"GivenName", :term=>"GivenName"}]]], nil, []]]
345
365
  ],
346
366
  ]
347
367
 
348
368
  before :each do
349
- @parser = ActiveFacts::CQL::Parser.new
369
+ @parser = TestParser.new
350
370
  end
351
371
 
352
372
  Constraints.each do |c|
@@ -371,3 +391,4 @@ describe "Fact Types" do
371
391
  end
372
392
  end
373
393
  end
394
+ =end
data/spec/cql_cql_spec.rb CHANGED
@@ -10,18 +10,17 @@ require 'activefacts/support'
10
10
  require 'activefacts/input/cql'
11
11
  require 'activefacts/generate/cql'
12
12
 
13
- include ActiveFacts
14
-
15
13
  describe "CQL Loader" do
16
14
  cql_failures = {
17
15
  "Airline" => "Contains queries, unsupported",
18
16
  "CompanyQuery" => "Contains queries, unsupported",
19
- "MetamodelNext" => "Fails due to weak adjective/role matching",
20
- "OrienteeringER" => "Doesn't parse due to difficult fact type match",
21
- "ServiceDirector" => "Doesn't parse some constraints due to mis-matched adjectives"
17
+ #"MetamodelNext" => "Fails due to weak adjective/role matching",
18
+ #"ServiceDirector" => "Doesn't parse some constraints due to mis-matched adjectives",
19
+ #"OddIdentifier" => "The odd identifier is built correctly but cannot be found by the current implementation",
20
+ "units" => "Unit verbalisation into CQL is not implemented"
22
21
  }
23
22
  cql_cql_failures = {
24
- "Insurance" => "Misses a subtype join in a constraint verbalisation",
23
+ # "Insurance" => "Misses a join in a subset constraint",
25
24
  # "OddIdentifier" => "Doesn't support identification of object fact types using mixed external/internal roles",
26
25
  }
27
26
  # Generate and return the CQL for the given vocabulary
@@ -45,7 +44,13 @@ describe "CQL Loader" do
45
44
  vocabulary = ActiveFacts::Input::CQL.readfile(cql_file)
46
45
  }
47
46
  else
48
- vocabulary = ActiveFacts::Input::CQL.readfile(cql_file)
47
+ begin
48
+ vocabulary = ActiveFacts::Input::CQL.readfile(cql_file)
49
+ rescue => e
50
+ debug :exception, "#{e.message}\n" +
51
+ "\t#{e.backtrace*"\n\t"}"
52
+ raise
53
+ end
49
54
  end
50
55
 
51
56
  # Build and save the actual file: