activefacts 0.8.9 → 0.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gemtest +0 -0
- data/Manifest.txt +28 -33
- data/Rakefile +11 -12
- data/bin/cql +90 -46
- data/examples/CQL/Blog.cql +2 -1
- data/examples/CQL/CompanyDirectorEmployee.cql +2 -2
- data/examples/CQL/Death.cql +1 -1
- data/examples/CQL/Diplomacy.cql +9 -9
- data/examples/CQL/Genealogy.cql +3 -2
- data/examples/CQL/Insurance.cql +10 -7
- data/examples/CQL/JoinEquality.cql +2 -2
- data/examples/CQL/Marriage.cql +1 -1
- data/examples/CQL/Metamodel.cql +73 -53
- data/examples/CQL/MetamodelNext.cql +89 -67
- data/examples/CQL/OneToOnes.cql +2 -2
- data/examples/CQL/ServiceDirector.cql +10 -5
- data/examples/CQL/Supervision.cql +3 -3
- data/examples/CQL/Tests.Test5.Load.cql +1 -1
- data/examples/CQL/Warehousing.cql +4 -2
- data/lib/activefacts/cql/CQLParser.treetop +26 -60
- data/lib/activefacts/cql/Context.treetop +12 -2
- data/lib/activefacts/cql/Expressions.treetop +14 -30
- data/lib/activefacts/cql/FactTypes.treetop +165 -110
- data/lib/activefacts/cql/Language/English.treetop +167 -54
- data/lib/activefacts/cql/LexicalRules.treetop +16 -2
- data/lib/activefacts/cql/{Concepts.treetop → ObjectTypes.treetop} +36 -37
- data/lib/activefacts/cql/Terms.treetop +57 -27
- data/lib/activefacts/cql/ValueTypes.treetop +39 -13
- data/lib/activefacts/cql/compiler.rb +5 -3
- data/lib/activefacts/cql/compiler/{reading.rb → clause.rb} +407 -285
- data/lib/activefacts/cql/compiler/constraint.rb +178 -275
- data/lib/activefacts/cql/compiler/entity_type.rb +73 -64
- data/lib/activefacts/cql/compiler/expression.rb +418 -0
- data/lib/activefacts/cql/compiler/fact.rb +146 -145
- data/lib/activefacts/cql/compiler/fact_type.rb +197 -80
- data/lib/activefacts/cql/compiler/join.rb +159 -0
- data/lib/activefacts/cql/compiler/shared.rb +51 -23
- data/lib/activefacts/cql/compiler/value_type.rb +56 -2
- data/lib/activefacts/cql/parser.rb +15 -4
- data/lib/activefacts/generate/absorption.rb +7 -7
- data/lib/activefacts/generate/cql.rb +100 -37
- data/lib/activefacts/generate/oo.rb +28 -51
- data/lib/activefacts/generate/ordered.rb +60 -36
- data/lib/activefacts/generate/ruby.rb +6 -6
- data/lib/activefacts/generate/sql/server.rb +4 -4
- data/lib/activefacts/input/orm.rb +71 -53
- data/lib/activefacts/persistence.rb +1 -1
- data/lib/activefacts/persistence/columns.rb +27 -23
- data/lib/activefacts/persistence/foreignkey.rb +6 -6
- data/lib/activefacts/persistence/index.rb +17 -17
- data/lib/activefacts/persistence/{concept.rb → object_type.rb} +9 -9
- data/lib/activefacts/persistence/reference.rb +61 -36
- data/lib/activefacts/persistence/tables.rb +61 -59
- data/lib/activefacts/support.rb +54 -29
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/extensions.rb +99 -54
- data/lib/activefacts/vocabulary/metamodel.rb +43 -37
- data/lib/activefacts/vocabulary/verbaliser.rb +134 -109
- data/spec/absorption_spec.rb +8 -8
- data/spec/cql/comparison_spec.rb +91 -0
- data/spec/cql/contractions_spec.rb +251 -0
- data/spec/cql/entity_type_spec.rb +319 -0
- data/spec/cql/expressions_spec.rb +63 -0
- data/spec/cql/fact_type_matching_spec.rb +283 -0
- data/spec/cql/french_spec.rb +21 -0
- data/spec/cql/parser/bad_literals_spec.rb +86 -0
- data/spec/cql/parser/constraints_spec.rb +19 -0
- data/spec/cql/parser/entity_types_spec.rb +106 -0
- data/spec/cql/parser/expressions_spec.rb +179 -0
- data/spec/cql/parser/fact_types_spec.rb +41 -0
- data/spec/cql/parser/literals_spec.rb +312 -0
- data/spec/cql/parser/pragmas_spec.rb +89 -0
- data/spec/cql/parser/value_types_spec.rb +42 -0
- data/spec/cql/role_matching_spec.rb +147 -0
- data/spec/cql/samples_spec.rb +9 -9
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/cql_dm_spec.rb +116 -0
- data/spec/cql_mysql_spec.rb +1 -1
- data/spec/cql_ruby_spec.rb +1 -1
- data/spec/cql_sql_spec.rb +3 -3
- data/spec/cql_symbol_tables_spec.rb +30 -30
- data/spec/cqldump_spec.rb +4 -4
- data/spec/helpers/array_matcher.rb +32 -27
- data/spec/helpers/diff_matcher.rb +6 -26
- data/spec/helpers/file_matcher.rb +41 -32
- data/spec/helpers/parse_to_ast_matcher.rb +76 -0
- data/spec/helpers/string_matcher.rb +32 -31
- data/spec/norma_cql_spec.rb +1 -1
- data/spec/norma_ruby_spec.rb +1 -1
- data/spec/norma_ruby_sql_spec.rb +1 -1
- data/spec/norma_sql_spec.rb +3 -1
- data/spec/norma_tables_spec.rb +1 -1
- data/spec/ruby_api_spec.rb +23 -0
- data/spec/spec_helper.rb +5 -4
- metadata +66 -66
- data/examples/CQL/OrienteeringER.cql +0 -58
- data/lib/activefacts/api.rb +0 -44
- data/lib/activefacts/api/concept.rb +0 -410
- data/lib/activefacts/api/constellation.rb +0 -128
- data/lib/activefacts/api/entity.rb +0 -256
- data/lib/activefacts/api/instance.rb +0 -60
- data/lib/activefacts/api/instance_index.rb +0 -80
- data/lib/activefacts/api/numeric.rb +0 -167
- data/lib/activefacts/api/role.rb +0 -80
- data/lib/activefacts/api/role_proxy.rb +0 -70
- data/lib/activefacts/api/role_values.rb +0 -117
- data/lib/activefacts/api/standard_types.rb +0 -87
- data/lib/activefacts/api/support.rb +0 -65
- data/lib/activefacts/api/value.rb +0 -135
- data/lib/activefacts/api/vocabulary.rb +0 -82
- data/spec/api/autocounter.rb +0 -82
- data/spec/api/constellation.rb +0 -130
- data/spec/api/entity_type.rb +0 -103
- data/spec/api/instance.rb +0 -461
- data/spec/api/roles.rb +0 -124
- data/spec/api/value_type.rb +0 -112
- data/spec/api_spec.rb +0 -13
- data/spec/cql/matching_spec.rb +0 -517
- data/spec/cql/unit_spec.rb +0 -394
- data/spec/spec.opts +0 -1
data/spec/api/roles.rb
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts tests: Roles of concept classes in the Runtime API
|
|
3
|
-
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
|
4
|
-
#
|
|
5
|
-
require 'activefacts/api'
|
|
6
|
-
|
|
7
|
-
describe "Roles" do
|
|
8
|
-
before :each do
|
|
9
|
-
Object.send :remove_const, :Mod if Object.const_defined?("Mod")
|
|
10
|
-
module Mod
|
|
11
|
-
class Name < String
|
|
12
|
-
value_type
|
|
13
|
-
end
|
|
14
|
-
class LegalEntity
|
|
15
|
-
identified_by :name
|
|
16
|
-
has_one :name
|
|
17
|
-
end
|
|
18
|
-
class Contract
|
|
19
|
-
identified_by :first, :second
|
|
20
|
-
has_one :first, :class => LegalEntity
|
|
21
|
-
has_one :second, :class => LegalEntity
|
|
22
|
-
end
|
|
23
|
-
class Person < LegalEntity
|
|
24
|
-
# identified_by # No identifier needed, inherit from superclass
|
|
25
|
-
# New identifier:
|
|
26
|
-
identified_by :family, :given
|
|
27
|
-
has_one :family, :class => Name
|
|
28
|
-
has_one :given, :class => Name
|
|
29
|
-
has_one :related_to, :class => LegalEntity
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
# print "concept: "; p Mod.concept
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it "should associate a role name with a matching existing concept" do
|
|
36
|
-
module Mod
|
|
37
|
-
class Existing1 < String
|
|
38
|
-
value_type
|
|
39
|
-
has_one :name
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
role = Mod::Existing1.roles(:name)
|
|
43
|
-
role.should_not be_nil
|
|
44
|
-
role.counterpart_concept.should == Mod::Name
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "should inject the respective role name into the matching concept" do
|
|
48
|
-
module Mod
|
|
49
|
-
class Existing1 < String
|
|
50
|
-
value_type
|
|
51
|
-
has_one :name
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
Mod::Name.roles(:all_existing1).should_not be_nil
|
|
55
|
-
Mod::LegalEntity.roles(:all_contract_as_first).should_not be_nil
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it "should associate a role name with a matching concept after it's created" do
|
|
59
|
-
module Mod
|
|
60
|
-
class Existing2 < String
|
|
61
|
-
value_type
|
|
62
|
-
has_one :given_name
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
# print "Mod::Existing2.roles = "; p Mod::Existing2.roles
|
|
66
|
-
r = Mod::Existing2.roles(:given_name)
|
|
67
|
-
r.should_not be_nil
|
|
68
|
-
Symbol.should === r.counterpart_concept
|
|
69
|
-
module Mod
|
|
70
|
-
class GivenName < String
|
|
71
|
-
value_type
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
# puts "Should resolve now:"
|
|
75
|
-
r = Mod::Existing2.roles(:given_name)
|
|
76
|
-
r.should_not be_nil
|
|
77
|
-
r.counterpart_concept.should == Mod::GivenName
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
it "should handle subtyping a value type" do
|
|
81
|
-
module Mod
|
|
82
|
-
class FamilyName < Name
|
|
83
|
-
value_type
|
|
84
|
-
one_to_one :patriarch, :class => Person
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
r = Mod::FamilyName.roles(:patriarch)
|
|
88
|
-
r.should_not be_nil
|
|
89
|
-
r.counterpart_concept.should == Mod::Person
|
|
90
|
-
r.counterpart_concept.roles(:family_name_as_patriarch).counterpart_concept.should == Mod::FamilyName
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it "should instantiate the matching concept on assignment" do
|
|
94
|
-
c = ActiveFacts::API::Constellation.new(Mod)
|
|
95
|
-
bloggs = c.LegalEntity("Bloggs")
|
|
96
|
-
acme = c.LegalEntity("Acme, Inc")
|
|
97
|
-
contract = c.Contract("Bloggs", acme)
|
|
98
|
-
#contract = c.Contract("Bloggs", "Acme, Inc")
|
|
99
|
-
contract.first.should == bloggs
|
|
100
|
-
contract.second.should == acme
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
it "should append the counterpart into the respective role array in the matching concept" do
|
|
104
|
-
foo = Mod::Name.new("Foo")
|
|
105
|
-
le = Mod::LegalEntity.new(foo)
|
|
106
|
-
le.respond_to?(:name).should be_true
|
|
107
|
-
name = le.name
|
|
108
|
-
name.respond_to?(:all_legal_entity).should be_true
|
|
109
|
-
|
|
110
|
-
#pending
|
|
111
|
-
Array(name.all_legal_entity).should === [le]
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
it "should instantiate subclasses sensibly" do
|
|
115
|
-
c = ActiveFacts::API::Constellation.new(Mod)
|
|
116
|
-
bloggs = c.LegalEntity("Bloggs & Co")
|
|
117
|
-
#pending
|
|
118
|
-
p = c.Person("Fred", "Bloggs")
|
|
119
|
-
p.related_to = "Bloggs & Co"
|
|
120
|
-
p.related_to.should be_is_a(Mod::LegalEntity)
|
|
121
|
-
bloggs.object_id.should == p.related_to.object_id
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
end
|
data/spec/api/value_type.rb
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts tests: Value types in the Runtime API
|
|
3
|
-
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
|
4
|
-
#
|
|
5
|
-
describe "Value Type class definitions" do
|
|
6
|
-
before :each do
|
|
7
|
-
Object.send :remove_const, :Mod if Object.const_defined?("Mod")
|
|
8
|
-
module Mod
|
|
9
|
-
class Name < String
|
|
10
|
-
value_type
|
|
11
|
-
has_one :name
|
|
12
|
-
end
|
|
13
|
-
class Year < Int
|
|
14
|
-
value_type
|
|
15
|
-
has_one :name
|
|
16
|
-
end
|
|
17
|
-
class Weight < Real
|
|
18
|
-
value_type
|
|
19
|
-
has_one :name
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
@classes = [Mod::Name, Mod::Year,Mod::Weight]
|
|
24
|
-
@attrs = [:name, :name, :name]
|
|
25
|
-
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it "should respond_to verbalise" do
|
|
29
|
-
@classes.each { |klass|
|
|
30
|
-
klass.respond_to?(:verbalise).should be_true
|
|
31
|
-
}
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "should not pollute the value class" do
|
|
35
|
-
@classes.each { |klass|
|
|
36
|
-
klass.superclass.respond_to?(:verbalise).should_not be_true
|
|
37
|
-
}
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it "should return a string from verbalise" do
|
|
41
|
-
@classes.each { |klass|
|
|
42
|
-
v = klass.verbalise
|
|
43
|
-
v.should_not be_nil
|
|
44
|
-
v.should_not =~ /REVISIT/
|
|
45
|
-
}
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "should respond_to vocabulary" do
|
|
49
|
-
@classes.each { |klass|
|
|
50
|
-
klass.respond_to?(:vocabulary).should be_true
|
|
51
|
-
}
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it "should return the parent module as the vocabulary" do
|
|
55
|
-
@classes.each { |klass|
|
|
56
|
-
vocabulary = klass.vocabulary
|
|
57
|
-
vocabulary.should == Mod
|
|
58
|
-
}
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
it "should return a vocabulary that knows about this concept" do
|
|
62
|
-
@classes.each { |klass|
|
|
63
|
-
vocabulary = klass.vocabulary
|
|
64
|
-
vocabulary.respond_to?(:concept).should be_true
|
|
65
|
-
vocabulary.concept.has_key?(klass.basename).should be_true
|
|
66
|
-
}
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it "should respond to roles()" do
|
|
70
|
-
@classes.each { |klass|
|
|
71
|
-
klass.respond_to?(:roles).should be_true
|
|
72
|
-
}
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "should contain only the added role definitions" do
|
|
76
|
-
Mod::Name.roles.size.should == 4
|
|
77
|
-
(@classes-[Mod::Name]).each { |klass|
|
|
78
|
-
klass.roles.size.should == 1
|
|
79
|
-
}
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it "should return the role definition" do
|
|
83
|
-
# Check the role definition may not be accessed by passing an index:
|
|
84
|
-
Mod::Name.roles(0).should be_nil
|
|
85
|
-
|
|
86
|
-
@classes.zip(@attrs).each { |pair|
|
|
87
|
-
klass, attr = *pair
|
|
88
|
-
role = klass.roles(attr)
|
|
89
|
-
role.should_not be_nil
|
|
90
|
-
|
|
91
|
-
role = klass.roles(attr.to_s)
|
|
92
|
-
role.should_not be_nil
|
|
93
|
-
|
|
94
|
-
# Check the role definition may be accessed by indexing the returned array:
|
|
95
|
-
role = klass.roles[attr]
|
|
96
|
-
role.should_not be_nil
|
|
97
|
-
|
|
98
|
-
# Check the role definition array by .include?
|
|
99
|
-
klass.roles.include?(attr).should be_true
|
|
100
|
-
}
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# REVISIT: role value constraints
|
|
104
|
-
|
|
105
|
-
it "should fail on a non-ValueClass" do
|
|
106
|
-
lambda{
|
|
107
|
-
class NameNotString
|
|
108
|
-
value_type
|
|
109
|
-
end
|
|
110
|
-
}.should raise_error
|
|
111
|
-
end
|
|
112
|
-
end
|
data/spec/api_spec.rb
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts tests: Run the API tests
|
|
3
|
-
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
|
4
|
-
#
|
|
5
|
-
require 'activefacts/api'
|
|
6
|
-
|
|
7
|
-
base = File.dirname(__FILE__)+"/"
|
|
8
|
-
require base+'api/constellation'
|
|
9
|
-
require base+'api/entity_type'
|
|
10
|
-
require base+'api/instance'
|
|
11
|
-
require base+'api/autocounter'
|
|
12
|
-
require base+'api/value_type'
|
|
13
|
-
require base+'api/roles'
|
data/spec/cql/matching_spec.rb
DELETED
|
@@ -1,517 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts CQL Fact Type matching tests
|
|
3
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
require 'activefacts/support'
|
|
7
|
-
require 'activefacts/api/support'
|
|
8
|
-
require 'activefacts/cql/compiler'
|
|
9
|
-
# require File.dirname(__FILE__) + '/../helpers/compiler_helper' # Can't see how to include/extend these methods correctly
|
|
10
|
-
|
|
11
|
-
describe "Fact Type Role Matching" do
|
|
12
|
-
MatchingPrefix = %q{
|
|
13
|
-
vocabulary Tests;
|
|
14
|
-
Boy is written as String;
|
|
15
|
-
Girl is written as String;
|
|
16
|
-
}
|
|
17
|
-
BaseConcepts = 3 # String, Boy, Girl
|
|
18
|
-
|
|
19
|
-
def self.SingleFact &b
|
|
20
|
-
lambda {|c|
|
|
21
|
-
real_fact_types = c.FactType.values-c.ImplicitFactType.values
|
|
22
|
-
real_fact_types.size.should == 1
|
|
23
|
-
@fact_type = real_fact_types[0]
|
|
24
|
-
b.call(@fact_type) if b
|
|
25
|
-
@fact_type
|
|
26
|
-
}
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def self.FactHavingPlayers(*a, &b)
|
|
30
|
-
lambda {|c|
|
|
31
|
-
@fact_type = c.FactType.detect do |key, ft|
|
|
32
|
-
ft.all_role.map{|r| r.concept.name}.sort == a.sort
|
|
33
|
-
end
|
|
34
|
-
b.call(@fact_type) if b
|
|
35
|
-
@fact_type
|
|
36
|
-
}
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def self.PresenceConstraints fact_type, &b
|
|
40
|
-
@presence_constraints =
|
|
41
|
-
fact_type.all_role.map{|r|
|
|
42
|
-
r.all_role_ref.map{|rr|
|
|
43
|
-
rr.role_sequence.all_presence_constraint.to_a
|
|
44
|
-
}
|
|
45
|
-
}.flatten.uniq
|
|
46
|
-
b.call(@presence_constraints) if b
|
|
47
|
-
@presence_constraints
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def self.Readings fact_type, &b
|
|
51
|
-
@readings = fact_type.all_reading.sort_by{|r| r.ordinal}
|
|
52
|
-
b.call(@readings) if b
|
|
53
|
-
@readings
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def self.ReadingCount n
|
|
57
|
-
lambda {|c|
|
|
58
|
-
unless @fact_type.all_reading.size == n
|
|
59
|
-
puts "SPEC FAILED, wrong number of readings (should be #{n}):\n\t#{
|
|
60
|
-
@fact_type.all_reading.map{ |r| r.expand}*"\n\t"
|
|
61
|
-
}"
|
|
62
|
-
end
|
|
63
|
-
@fact_type.all_reading.size.should == n
|
|
64
|
-
}
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def self.PresenceConstraintCount n
|
|
68
|
-
lambda{ |c|
|
|
69
|
-
@fact_type.all_role.map{|r|
|
|
70
|
-
r.all_role_ref.map{|rr|
|
|
71
|
-
rr.role_sequence.all_presence_constraint.to_a
|
|
72
|
-
}
|
|
73
|
-
}.flatten.uniq.size.should == n
|
|
74
|
-
}
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def self.ConceptCount n
|
|
78
|
-
lambda {|c|
|
|
79
|
-
@constellation = c
|
|
80
|
-
c.Concept.values.size.should == n
|
|
81
|
-
}
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def self.Concept name, &b
|
|
85
|
-
lambda {|c|
|
|
86
|
-
@concept = c.Concept[[["Tests"], name]]
|
|
87
|
-
@concept.should_not == nil
|
|
88
|
-
b.call(@concept) if b
|
|
89
|
-
@concept
|
|
90
|
-
}
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def self.WrittenAs name
|
|
94
|
-
lambda {|c|
|
|
95
|
-
@base_type = c.Concept[[["Tests"], name]]
|
|
96
|
-
@base_type.class.should == ActiveFacts::Metamodel::ValueType
|
|
97
|
-
@concept.class.should == ActiveFacts::Metamodel::ValueType
|
|
98
|
-
@concept.supertype.should == @base_type
|
|
99
|
-
}
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def self.PreferredIdentifier num_roles
|
|
103
|
-
lambda {|c|
|
|
104
|
-
@preferred_identifier = @concept.preferred_identifier
|
|
105
|
-
@preferred_identifier.should_not == nil
|
|
106
|
-
@preferred_identifier.role_sequence.all_role_ref.size.should == num_roles
|
|
107
|
-
#@preferred_identifier.min_frequency.should == 1
|
|
108
|
-
@preferred_identifier.max_frequency.should == 1
|
|
109
|
-
@preferred_identifier.is_preferred_identifier.should == true
|
|
110
|
-
}
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def self.PreferredIdentifierRolePlayedBy name, num = 0
|
|
114
|
-
lambda {|c|
|
|
115
|
-
@preferred_identifier.role_sequence.all_role_ref.sort_by{|rr| rr.ordinal}[num].role.concept.name.should == name
|
|
116
|
-
}
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
class BlackHole
|
|
120
|
-
def method_missing(m,*a,&b)
|
|
121
|
-
self
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
class PendingSilencer
|
|
125
|
-
def STDOUT; BlackHole.new; end
|
|
126
|
-
def puts; BlackHole.new; end
|
|
127
|
-
def p; BlackHole.new; end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def self.pending(msg = "TODO", &b)
|
|
131
|
-
lambda {|*c|
|
|
132
|
-
raised = nil
|
|
133
|
-
begin
|
|
134
|
-
example = b.call
|
|
135
|
-
eval(lambda { example.call(*c) }, BlackHole.new)
|
|
136
|
-
rescue => raised
|
|
137
|
-
end
|
|
138
|
-
raise Spec::Example::PendingExampleFixedError.new(msg) unless raised
|
|
139
|
-
raise Spec::Example::ExamplePendingError.new(msg)
|
|
140
|
-
}
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def self.ReadingContainsHyphenatedWord reading_num
|
|
144
|
-
lambda {|c|
|
|
145
|
-
hyphenated_reading =
|
|
146
|
-
c.FactType.values[0].all_reading.select {|reading|
|
|
147
|
-
reading.ordinal == reading_num
|
|
148
|
-
}[0]
|
|
149
|
-
hyphenated_reading.should_not == nil
|
|
150
|
-
(hyphenated_reading.text =~ /[a-z]-[a-z]/).should_not == nil
|
|
151
|
-
}
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
SimpleBinaryFactTypeTests = [
|
|
155
|
-
[ # Simple create
|
|
156
|
-
%q{Girl is going out with at most one Boy; },
|
|
157
|
-
SingleFact() do |fact_type|
|
|
158
|
-
Readings(fact_type).size.should == 1
|
|
159
|
-
PresenceConstraints(fact_type) do |pcs|
|
|
160
|
-
pcs.size.should == 1
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
],
|
|
164
|
-
[ # Create with explicit adjective
|
|
165
|
-
%q{Girl is going out with at most one ugly-Boy;},
|
|
166
|
-
SingleFact() do |fact_type|
|
|
167
|
-
Readings(fact_type).size.should == 1
|
|
168
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
169
|
-
end
|
|
170
|
-
],
|
|
171
|
-
[ # Simple match
|
|
172
|
-
%q{Girl is going out with at most one Boy; },
|
|
173
|
-
%q{
|
|
174
|
-
Girl is going out with Boy,
|
|
175
|
-
Boy is going out with Girl;
|
|
176
|
-
},
|
|
177
|
-
SingleFact() do |fact_type|
|
|
178
|
-
Readings(fact_type).size.should == 2
|
|
179
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
180
|
-
end
|
|
181
|
-
],
|
|
182
|
-
[ # Simple match with repetition
|
|
183
|
-
%q{Girl is going out with at most one Boy; },
|
|
184
|
-
%q{
|
|
185
|
-
Girl is going out with Boy,
|
|
186
|
-
Girl is going out with Boy,
|
|
187
|
-
Boy is going out with Girl,
|
|
188
|
-
Boy is going out with Girl;
|
|
189
|
-
},
|
|
190
|
-
SingleFact() do |fact_type|
|
|
191
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
192
|
-
pending("duplicate new clauses are not eliminated") do
|
|
193
|
-
Readings(fact_type).size.should == 2
|
|
194
|
-
end.call # Must call the pending block
|
|
195
|
-
end,
|
|
196
|
-
# pending("duplicate new clauses are not eliminated") do
|
|
197
|
-
# @readings.size.should == 2
|
|
198
|
-
# end
|
|
199
|
-
],
|
|
200
|
-
[ # Simple match with a new presence Constraint
|
|
201
|
-
%q{Girl is going out with at most one Boy; },
|
|
202
|
-
%q{
|
|
203
|
-
Girl is going out with Boy,
|
|
204
|
-
Boy is going out with at most one Girl;
|
|
205
|
-
},
|
|
206
|
-
SingleFact() do |fact_type|
|
|
207
|
-
Readings(fact_type).size.should == 2
|
|
208
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
209
|
-
end
|
|
210
|
-
],
|
|
211
|
-
[ # RoleName matching
|
|
212
|
-
%q{Girl is going out with at most one Boy;},
|
|
213
|
-
%q{
|
|
214
|
-
Boy is going out with Girlfriend,
|
|
215
|
-
Girl (as Girlfriend) is going out with at most one Boy;
|
|
216
|
-
},
|
|
217
|
-
SingleFact() do |fact_type|
|
|
218
|
-
Readings(fact_type).size.should == 3
|
|
219
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
220
|
-
end
|
|
221
|
-
],
|
|
222
|
-
[ # Match with explicit adjective
|
|
223
|
-
%q{Girl is going out with at most one ugly-Boy;},
|
|
224
|
-
%q{Girl is going out with at most one ugly-Boy,
|
|
225
|
-
ugly-Boy is best friend of Girl;
|
|
226
|
-
},
|
|
227
|
-
SingleFact() do |fact_type|
|
|
228
|
-
Readings(fact_type).size.should == 2
|
|
229
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
230
|
-
end
|
|
231
|
-
],
|
|
232
|
-
[ # Match with implicit adjective
|
|
233
|
-
%q{Girl is going out with at most one ugly-Boy;},
|
|
234
|
-
%q{Girl is going out with ugly Boy,
|
|
235
|
-
Boy is going out with Girl;
|
|
236
|
-
},
|
|
237
|
-
SingleFact() do |fact_type|
|
|
238
|
-
Readings(fact_type).size.should == 2
|
|
239
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
240
|
-
end
|
|
241
|
-
],
|
|
242
|
-
[ # Match with explicit trailing adjective
|
|
243
|
-
%q{Girl is going out with at most one Boy-monster;},
|
|
244
|
-
%q{Girl is going out with Boy-monster,
|
|
245
|
-
Boy is going out with Girl;
|
|
246
|
-
},
|
|
247
|
-
SingleFact() do |fact_type|
|
|
248
|
-
Readings(fact_type).size.should == 2
|
|
249
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
250
|
-
end
|
|
251
|
-
],
|
|
252
|
-
[ # Match with implicit trailing adjective
|
|
253
|
-
%q{Girl is going out with at most one Boy-monster;},
|
|
254
|
-
%q{Girl is going out with Boy monster,
|
|
255
|
-
Boy is going out with Girl;
|
|
256
|
-
},
|
|
257
|
-
SingleFact() do |fact_type|
|
|
258
|
-
Readings(fact_type).size.should == 2
|
|
259
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
260
|
-
end
|
|
261
|
-
],
|
|
262
|
-
[ # Match with two explicit adjectives
|
|
263
|
-
%q{Girl is going out with at most one ugly- bad Boy;},
|
|
264
|
-
%q{Girl is going out with ugly- bad Boy,
|
|
265
|
-
ugly- bad Boy is going out with Girl;
|
|
266
|
-
},
|
|
267
|
-
SingleFact() do |fact_type|
|
|
268
|
-
Readings(fact_type).size.should == 2
|
|
269
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
270
|
-
end
|
|
271
|
-
],
|
|
272
|
-
[ # Match with two implicit adjective
|
|
273
|
-
%q{Girl is going out with at most one ugly- bad Boy;},
|
|
274
|
-
%q{Girl is going out with ugly bad Boy,
|
|
275
|
-
Boy is going out with Girl;
|
|
276
|
-
},
|
|
277
|
-
SingleFact(),
|
|
278
|
-
ReadingCount(2),
|
|
279
|
-
PresenceConstraintCount(1)
|
|
280
|
-
],
|
|
281
|
-
[ # Match with two explicit trailing adjective
|
|
282
|
-
%q{Girl is going out with at most one Boy real -monster;},
|
|
283
|
-
%q{Girl is going out with Boy real -monster,
|
|
284
|
-
Boy is going out with Girl;
|
|
285
|
-
},
|
|
286
|
-
SingleFact() do |fact_type|
|
|
287
|
-
Readings(fact_type).size.should == 2
|
|
288
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
289
|
-
end
|
|
290
|
-
],
|
|
291
|
-
[ # Match with two implicit trailing adjectives
|
|
292
|
-
%q{Girl is going out with at most one Boy real -monster;},
|
|
293
|
-
%q{Girl is going out with Boy real monster,
|
|
294
|
-
Boy is going out with Girl;
|
|
295
|
-
},
|
|
296
|
-
SingleFact() do |fact_type|
|
|
297
|
-
Readings(fact_type).size.should == 2
|
|
298
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
299
|
-
end
|
|
300
|
-
],
|
|
301
|
-
[ # Match with hyphenated word
|
|
302
|
-
%q{Girl is going out with at most one Boy; },
|
|
303
|
-
%q{
|
|
304
|
-
Girl is going out with Boy,
|
|
305
|
-
Boy is out driving a semi-trailer with Girl;
|
|
306
|
-
},
|
|
307
|
-
SingleFact() do |fact_type|
|
|
308
|
-
(readings = Readings(fact_type)).size.should == 2
|
|
309
|
-
## REVISIT: Refactor test
|
|
310
|
-
#ReadingContainsHyphenatedWord(readings[1])
|
|
311
|
-
ReadingContainsHyphenatedWord(1)
|
|
312
|
-
PresenceConstraintCount(1)
|
|
313
|
-
end
|
|
314
|
-
],
|
|
315
|
-
[ # Match with implicit leading ignoring explicit trailing adjective
|
|
316
|
-
%q{Girl is going out with at most one ugly-Boy;},
|
|
317
|
-
%q{Girl is going out with ugly Boy-monster,
|
|
318
|
-
Boy is going out with Girl;
|
|
319
|
-
},
|
|
320
|
-
SingleFact() do |fact_type|
|
|
321
|
-
Readings(fact_type).size.should == 3
|
|
322
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
323
|
-
end
|
|
324
|
-
],
|
|
325
|
-
[ # Match with implicit leading ignoring implicit trailing adjective
|
|
326
|
-
%q{Girl is going out with at most one ugly-Boy;},
|
|
327
|
-
%q{Girl is going out with ugly Boy monster,
|
|
328
|
-
Boy-monster is going out with Girl;
|
|
329
|
-
},
|
|
330
|
-
SingleFact(),
|
|
331
|
-
ReadingCount(3),
|
|
332
|
-
PresenceConstraintCount(1)
|
|
333
|
-
],
|
|
334
|
-
[ # Match with implicit trailing ignoring explicit leading adjective
|
|
335
|
-
%q{Girl is going out with at most one Boy-monster;},
|
|
336
|
-
%q{Girl is going out with ugly-Boy monster,
|
|
337
|
-
Boy is going out with Girl;
|
|
338
|
-
},
|
|
339
|
-
SingleFact() do |fact_type|
|
|
340
|
-
Readings(fact_type).size.should == 3
|
|
341
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
342
|
-
end
|
|
343
|
-
],
|
|
344
|
-
[ # Match with implicit trailing ignoring implicit leading adjective
|
|
345
|
-
%q{Girl is going out with at most one Boy-monster;},
|
|
346
|
-
%q{Girl is going out with ugly Boy monster,
|
|
347
|
-
ugly-Boy is going out with Girl;
|
|
348
|
-
},
|
|
349
|
-
SingleFact() do |fact_type|
|
|
350
|
-
Readings(fact_type).size.should == 3
|
|
351
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
352
|
-
end
|
|
353
|
-
],
|
|
354
|
-
]
|
|
355
|
-
|
|
356
|
-
EntityIdentificationTests = [
|
|
357
|
-
[
|
|
358
|
-
# REVISIT: At present, this doesn't add the minimum frequency constraint that a preferred identifier requires.
|
|
359
|
-
%q{Thong is written as String;},
|
|
360
|
-
%q{Thing is identified by Thong where Thing has one Thong;},
|
|
361
|
-
SingleFact() do |fact_type|
|
|
362
|
-
Readings(fact_type).size.should == 1
|
|
363
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
364
|
-
end,
|
|
365
|
-
Concept('Thong') do |concept|
|
|
366
|
-
concept.class.should == ActiveFacts::Metamodel::ValueType
|
|
367
|
-
# REVISIT: Figure out how WrittenAs can access the constellation.
|
|
368
|
-
WrittenAs('String')
|
|
369
|
-
end,
|
|
370
|
-
ConceptCount(2+BaseConcepts),
|
|
371
|
-
Concept('Thing'),
|
|
372
|
-
PreferredIdentifier(1),
|
|
373
|
-
PreferredIdentifierRolePlayedBy('Thong'),
|
|
374
|
-
],
|
|
375
|
-
|
|
376
|
-
[ # Auto-create Id and Thing Id:
|
|
377
|
-
%q{Thing is identified by its Id;},
|
|
378
|
-
SingleFact() do |fact_type|
|
|
379
|
-
Readings(fact_type).size.should == 2
|
|
380
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
381
|
-
end,
|
|
382
|
-
ConceptCount(3+BaseConcepts),
|
|
383
|
-
Concept('Thing'),
|
|
384
|
-
PreferredIdentifier(1),
|
|
385
|
-
PreferredIdentifierRolePlayedBy('Thing Id'),
|
|
386
|
-
],
|
|
387
|
-
|
|
388
|
-
[ # Auto-create Thing Id:
|
|
389
|
-
%q{Id is written as String;},
|
|
390
|
-
%q{Thing is identified by its Id;},
|
|
391
|
-
SingleFact() do |fact_type|
|
|
392
|
-
Readings(fact_type).size.should == 2
|
|
393
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
394
|
-
end,
|
|
395
|
-
ConceptCount(3+BaseConcepts),
|
|
396
|
-
Concept('Thing'),
|
|
397
|
-
PreferredIdentifier(1),
|
|
398
|
-
PreferredIdentifierRolePlayedBy('Thing Id'),
|
|
399
|
-
],
|
|
400
|
-
|
|
401
|
-
[ # Auto-create nothing (identifying value type exists already)
|
|
402
|
-
%q{Thing Id is written as String;},
|
|
403
|
-
%q{Thing is identified by its Id;},
|
|
404
|
-
SingleFact() do |fact_type|
|
|
405
|
-
Readings(fact_type).size.should == 2
|
|
406
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
407
|
-
end,
|
|
408
|
-
ConceptCount(2+BaseConcepts),
|
|
409
|
-
Concept('Thing'),
|
|
410
|
-
PreferredIdentifier(1),
|
|
411
|
-
PreferredIdentifierRolePlayedBy('Thing Id'),
|
|
412
|
-
],
|
|
413
|
-
|
|
414
|
-
[ # Auto-create nothing (identifying entity type exists already so don't create a VT)
|
|
415
|
-
%q{Id is written as Id;},
|
|
416
|
-
%q{Thing Id is identified by Id where Thing Id has one Id, Id is of one Thing Id;},
|
|
417
|
-
%q{Thing is identified by its Id;},
|
|
418
|
-
FactHavingPlayers("Thing", "Thing Id") do |fact_type|
|
|
419
|
-
Readings(fact_type).size.should == 2
|
|
420
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
421
|
-
end,
|
|
422
|
-
ConceptCount(3+BaseConcepts),
|
|
423
|
-
Concept('Thing'),
|
|
424
|
-
PreferredIdentifier(1),
|
|
425
|
-
PreferredIdentifierRolePlayedBy('Thing Id'),
|
|
426
|
-
],
|
|
427
|
-
|
|
428
|
-
[
|
|
429
|
-
%q{Thong is written as String;},
|
|
430
|
-
%q{Thing is identified by Thong where Thing has one Thong, Thong is of one Thing;},
|
|
431
|
-
SingleFact() do |fact_type|
|
|
432
|
-
Readings(fact_type).size.should == 2
|
|
433
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
434
|
-
end,
|
|
435
|
-
ConceptCount(2+BaseConcepts),
|
|
436
|
-
Concept('Thing'),
|
|
437
|
-
PreferredIdentifier(1),
|
|
438
|
-
PreferredIdentifierRolePlayedBy('Thong'),
|
|
439
|
-
],
|
|
440
|
-
|
|
441
|
-
[ # Objectified fact type with internal identification
|
|
442
|
-
%q{Relationship is where Boy relates to Girl;},
|
|
443
|
-
SingleFact() do |fact_type|
|
|
444
|
-
Readings(fact_type).size.should == 1
|
|
445
|
-
PresenceConstraints(fact_type).size.should == 1
|
|
446
|
-
end,
|
|
447
|
-
ConceptCount(1+BaseConcepts),
|
|
448
|
-
Concept('Relationship'),
|
|
449
|
-
PreferredIdentifier(2),
|
|
450
|
-
# PreferredIdentifierRolePlayedBy('Thong'),
|
|
451
|
-
],
|
|
452
|
-
|
|
453
|
-
[ # Objectified fact type with external identification
|
|
454
|
-
%q{Relationship is identified by its Id where Boy relates to Girl;},
|
|
455
|
-
ConceptCount(3+BaseConcepts),
|
|
456
|
-
Concept('Relationship'),
|
|
457
|
-
PreferredIdentifier(1), # 1 role in PI
|
|
458
|
-
PreferredIdentifierRolePlayedBy('Relationship Id'),
|
|
459
|
-
FactHavingPlayers('Relationship', 'Relationship Id') do |fact_type|
|
|
460
|
-
Readings(fact_type).size.should == 2
|
|
461
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
462
|
-
fact_type.all_reading.detect{|r| r.text == '{0} has {1}'}.should_not == nil
|
|
463
|
-
fact_type.all_reading.detect{|r| r.text == '{0} is of {1}'}.should_not == nil
|
|
464
|
-
end,
|
|
465
|
-
FactHavingPlayers('Boy', 'Girl') do |fact_type|
|
|
466
|
-
fact_type.entity_type.should == @concept
|
|
467
|
-
end,
|
|
468
|
-
],
|
|
469
|
-
|
|
470
|
-
[ # Objectified fact type with external identification and explicit reading
|
|
471
|
-
%q{Relationship is identified by its Id where Boy relates to Girl, Relationship is known by Relationship Id;},
|
|
472
|
-
ConceptCount(3+BaseConcepts),
|
|
473
|
-
Concept('Relationship'),
|
|
474
|
-
PreferredIdentifier(1),
|
|
475
|
-
PreferredIdentifierRolePlayedBy('Relationship Id'),
|
|
476
|
-
FactHavingPlayers('Relationship', 'Relationship Id') do |fact_type|
|
|
477
|
-
Readings(fact_type).size.should == 2
|
|
478
|
-
PresenceConstraints(fact_type).size.should == 2
|
|
479
|
-
fact_type.all_reading.detect{|r| r.text == '{0} is known by {1}'}.should_not == nil
|
|
480
|
-
fact_type.all_reading.detect{|r| r.text == '{0} is of {1}'}.should_not == nil
|
|
481
|
-
end,
|
|
482
|
-
FactHavingPlayers('Boy', 'Girl') do |fact_type|
|
|
483
|
-
fact_type.entity_type.should == @concept
|
|
484
|
-
end,
|
|
485
|
-
],
|
|
486
|
-
|
|
487
|
-
]
|
|
488
|
-
AllTests =
|
|
489
|
-
# SimpleBinaryFactTypeTests +
|
|
490
|
-
EntityIdentificationTests
|
|
491
|
-
|
|
492
|
-
before :each do
|
|
493
|
-
@compiler = ActiveFacts::CQL::Compiler.new('Test')
|
|
494
|
-
end
|
|
495
|
-
|
|
496
|
-
AllTests.each do |tests|
|
|
497
|
-
it "should process '#{(tests.select{|t| t.is_a?(String)}*' ').gsub(/\s+/m,' ')}' correctly" do
|
|
498
|
-
tests.each do |test|
|
|
499
|
-
case test
|
|
500
|
-
when String
|
|
501
|
-
result = @compiler.compile(MatchingPrefix+test)
|
|
502
|
-
puts @compiler.failure_reason unless result
|
|
503
|
-
result.should_not be_nil
|
|
504
|
-
when Proc
|
|
505
|
-
begin
|
|
506
|
-
test.call(@compiler.vocabulary.constellation)
|
|
507
|
-
rescue Spec::Example::ExamplePendingError
|
|
508
|
-
raise
|
|
509
|
-
rescue => e
|
|
510
|
-
puts "Failed on\n\t"+tests.select{|t| t.is_a?(String)}*" "
|
|
511
|
-
raise
|
|
512
|
-
end
|
|
513
|
-
end
|
|
514
|
-
end
|
|
515
|
-
end
|
|
516
|
-
end
|
|
517
|
-
end
|