activefacts 0.8.6 → 0.8.8
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +33 -2
- data/README.rdoc +30 -36
- data/Rakefile +16 -20
- data/bin/afgen +17 -11
- data/bin/cql +313 -36
- data/download.html +43 -19
- data/examples/CQL/Address.cql +15 -15
- data/examples/CQL/Blog.cql +8 -8
- data/examples/CQL/CompanyDirectorEmployee.cql +6 -5
- data/examples/CQL/Death.cql +3 -3
- data/examples/CQL/Diplomacy.cql +48 -0
- data/examples/CQL/Genealogy.cql +41 -41
- data/examples/CQL/Insurance.cql +311 -0
- data/examples/CQL/JoinEquality.cql +35 -0
- data/examples/CQL/Marriage.cql +1 -1
- data/examples/CQL/Metamodel.cql +290 -185
- data/examples/CQL/MetamodelNext.cql +420 -0
- data/examples/CQL/Monogamy.cql +24 -0
- data/examples/CQL/MonthInSeason.cql +27 -0
- data/examples/CQL/Moon.cql +23 -0
- data/examples/CQL/MultiInheritance.cql +4 -4
- data/examples/CQL/NonRoleId.cql +14 -0
- data/examples/CQL/OddIdentifier.cql +18 -0
- data/examples/CQL/OilSupply.cql +24 -24
- data/examples/CQL/OneToOnes.cql +17 -0
- data/examples/CQL/Orienteering.cql +55 -55
- data/examples/CQL/OrienteeringER.cql +58 -0
- data/examples/CQL/PersonPlaysGame.cql +2 -2
- data/examples/CQL/RedundantDependency.cql +34 -0
- data/examples/CQL/SchoolActivities.cql +5 -5
- data/examples/CQL/SeparateSubtype.cql +28 -0
- data/examples/CQL/ServiceDirector.cql +283 -0
- data/examples/CQL/SimplestUnary.cql +2 -2
- data/examples/CQL/SubtypePI.cql +11 -11
- data/examples/CQL/Supervision.cql +38 -0
- data/examples/CQL/Tests.Test5.Load.cql +38 -0
- data/examples/CQL/WaiterTips.cql +33 -0
- data/examples/CQL/Warehousing.cql +55 -53
- data/examples/CQL/WindowInRoomInBldg.cql +9 -9
- data/examples/CQL/unit.cql +433 -544
- data/examples/index.html +314 -170
- data/examples/intro.html +6 -176
- data/examples/local.css +8 -4
- data/index.html +40 -25
- data/lib/activefacts/api/concept.rb +2 -2
- data/lib/activefacts/api/constellation.rb +4 -4
- data/lib/activefacts/api/instance.rb +2 -2
- data/lib/activefacts/api/instance_index.rb +4 -0
- data/lib/activefacts/api/numeric.rb +3 -1
- data/lib/activefacts/api/role.rb +1 -1
- data/lib/activefacts/api/standard_types.rb +23 -16
- data/lib/activefacts/api/support.rb +3 -1
- data/lib/activefacts/api/vocabulary.rb +4 -0
- data/lib/activefacts/cql/CQLParser.treetop +87 -39
- data/lib/activefacts/cql/Concepts.treetop +95 -69
- data/lib/activefacts/cql/Context.treetop +11 -2
- data/lib/activefacts/cql/Expressions.treetop +23 -59
- data/lib/activefacts/cql/FactTypes.treetop +141 -95
- data/lib/activefacts/cql/Language/English.treetop +33 -21
- data/lib/activefacts/cql/LexicalRules.treetop +6 -1
- data/lib/activefacts/cql/Terms.treetop +75 -26
- data/lib/activefacts/cql/ValueTypes.treetop +52 -54
- data/lib/activefacts/cql/compiler.rb +46 -1691
- data/lib/activefacts/cql/compiler/constraint.rb +602 -0
- data/lib/activefacts/cql/compiler/entity_type.rb +425 -0
- data/lib/activefacts/cql/compiler/fact.rb +300 -0
- data/lib/activefacts/cql/compiler/fact_type.rb +230 -0
- data/lib/activefacts/cql/compiler/reading.rb +832 -0
- data/lib/activefacts/cql/compiler/shared.rb +109 -0
- data/lib/activefacts/cql/compiler/value_type.rb +104 -0
- data/lib/activefacts/cql/parser.rb +132 -81
- data/lib/activefacts/generate/cql.rb +397 -274
- data/lib/activefacts/generate/oo.rb +13 -12
- data/lib/activefacts/generate/ordered.rb +107 -117
- data/lib/activefacts/generate/ruby.rb +34 -38
- data/lib/activefacts/generate/sql/mysql.rb +62 -45
- data/lib/activefacts/generate/sql/server.rb +59 -42
- data/lib/activefacts/input/cql.rb +6 -3
- data/lib/activefacts/input/orm.rb +991 -557
- data/lib/activefacts/persistence/columns.rb +16 -12
- data/lib/activefacts/persistence/foreignkey.rb +7 -4
- data/lib/activefacts/persistence/index.rb +3 -4
- data/lib/activefacts/persistence/reference.rb +5 -2
- data/lib/activefacts/support.rb +20 -14
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary.rb +1 -0
- data/lib/activefacts/vocabulary/extensions.rb +328 -44
- data/lib/activefacts/vocabulary/metamodel.rb +145 -20
- data/lib/activefacts/vocabulary/verbaliser.rb +621 -0
- data/spec/absorption_spec.rb +4 -4
- data/spec/api/value_type.rb +1 -1
- data/spec/cql/context_spec.rb +45 -22
- data/spec/cql/deontic_spec.rb +88 -0
- data/spec/cql/matching_spec.rb +517 -0
- data/spec/cql/samples_spec.rb +88 -31
- data/spec/cql/unit_spec.rb +58 -37
- data/spec/cql_cql_spec.rb +12 -7
- data/spec/cql_mysql_spec.rb +3 -7
- data/spec/cql_parse_spec.rb +0 -4
- data/spec/cql_ruby_spec.rb +1 -4
- data/spec/cql_sql_spec.rb +5 -18
- data/spec/cql_symbol_tables_spec.rb +3 -0
- data/spec/cqldump_spec.rb +0 -2
- data/spec/helpers/array_matcher.rb +35 -0
- data/spec/helpers/ctrl_c_support.rb +52 -0
- data/spec/helpers/diff_matcher.rb +38 -0
- data/spec/helpers/file_matcher.rb +5 -3
- data/spec/helpers/string_matcher.rb +39 -0
- data/spec/helpers/test_parser.rb +13 -0
- data/spec/norma_cql_spec.rb +13 -5
- data/spec/norma_ruby_spec.rb +11 -3
- data/spec/{absorption_ruby_spec.rb → norma_ruby_sql_spec.rb} +37 -32
- data/spec/norma_sql_spec.rb +11 -5
- data/spec/norma_tables_spec.rb +33 -29
- data/spec/spec_helper.rb +4 -1
- data/status.html +92 -23
- metadata +102 -36
- data/lib/activefacts/generate/cql/html.rb +0 -403
data/spec/cql_mysql_spec.rb
CHANGED
@@ -10,15 +10,10 @@ require 'activefacts/support'
|
|
10
10
|
require 'activefacts/input/cql'
|
11
11
|
require 'activefacts/generate/sql/mysql'
|
12
12
|
|
13
|
-
include ActiveFacts
|
14
|
-
include ActiveFacts::Metamodel
|
15
|
-
|
16
13
|
describe "CQL Loader with SQL output" do
|
17
14
|
cql_failures = {
|
18
15
|
"Airline" => "Contains queries, unsupported",
|
19
16
|
"CompanyQuery" => "Contains queries, unsupported",
|
20
|
-
"OrienteeringER" => "Doesn't parse due to difficult fact type match",
|
21
|
-
"ServiceDirector" => "Doesn't parse some constraints due to mis-matched adjectives"
|
22
17
|
}
|
23
18
|
cql_mysql_failures = {
|
24
19
|
"Metamodel" => "An index to enforce uniqueness on the nesting fact type isn't emitted",
|
@@ -27,7 +22,7 @@ describe "CQL Loader with SQL output" do
|
|
27
22
|
# Generate and return the SQL for the given vocabulary
|
28
23
|
def sql(vocabulary)
|
29
24
|
output = StringIO.new
|
30
|
-
@dumper = ActiveFacts::Generate::SQL::MYSQL.new(vocabulary.constellation
|
25
|
+
@dumper = ActiveFacts::Generate::SQL::MYSQL.new(vocabulary.constellation)
|
31
26
|
@dumper.generate(output)
|
32
27
|
output.rewind
|
33
28
|
output.read
|
@@ -53,7 +48,8 @@ describe "CQL Loader with SQL output" do
|
|
53
48
|
sql_text = sql(vocabulary)
|
54
49
|
File.open(actual_file, "w") { |f| f.write sql_text }
|
55
50
|
|
56
|
-
|
51
|
+
next unless File.exists? expected_file
|
52
|
+
# ("expected output file #{expected_file} not found")
|
57
53
|
|
58
54
|
expected_text = File.open(expected_file) {|f| f.read }
|
59
55
|
broken = cql_mysql_failures[File.basename(actual_file, ".cql")]
|
data/spec/cql_parse_spec.rb
CHANGED
@@ -9,14 +9,10 @@ require 'activefacts/support'
|
|
9
9
|
require 'activefacts/input/cql'
|
10
10
|
require 'activefacts/generate/cql'
|
11
11
|
|
12
|
-
include ActiveFacts
|
13
|
-
|
14
12
|
describe "CQL Parser" do
|
15
13
|
cql_failures = {
|
16
14
|
"Airline" => "Contains queries, unsupported",
|
17
15
|
"CompanyQuery" => "Contains queries, unsupported",
|
18
|
-
"OrienteeringER" => "Contains a long fact type that can't be matched properly",
|
19
|
-
"ServiceDirector" => "Contains constraints with mismatched adjectives",
|
20
16
|
}
|
21
17
|
|
22
18
|
pattern = ENV["AFTESTS"] || "*"
|
data/spec/cql_ruby_spec.rb
CHANGED
@@ -10,8 +10,6 @@ require 'activefacts/support'
|
|
10
10
|
require 'activefacts/input/cql'
|
11
11
|
require 'activefacts/generate/ruby'
|
12
12
|
|
13
|
-
include ActiveFacts
|
14
|
-
|
15
13
|
class String
|
16
14
|
def strip_comments()
|
17
15
|
c_comment = %r{/\*((?!\*/).)*\*/}m
|
@@ -23,8 +21,7 @@ describe "CQL Loader with Ruby output" do
|
|
23
21
|
cql_failures = {
|
24
22
|
"Airline" => "Contains queries, not supported",
|
25
23
|
"CompanyQuery" => "Contains queries, not supported",
|
26
|
-
"OrienteeringER" => "
|
27
|
-
"ServiceDirector" => "Constraints contain adjectives that require looser matching",
|
24
|
+
# "OrienteeringER" => "Invalid model, it just works differently in CQL"
|
28
25
|
}
|
29
26
|
|
30
27
|
# Generate and return the Ruby for the given vocabulary
|
data/spec/cql_sql_spec.rb
CHANGED
@@ -10,35 +10,19 @@ require 'activefacts/support'
|
|
10
10
|
require 'activefacts/input/cql'
|
11
11
|
require 'activefacts/generate/sql/server'
|
12
12
|
|
13
|
-
include ActiveFacts
|
14
|
-
include ActiveFacts::Metamodel
|
15
|
-
|
16
13
|
describe "CQL Loader with SQL output" do
|
17
14
|
cql_failures = {
|
18
15
|
"Airline" => "Contains unsupported queries",
|
19
16
|
"CompanyQuery" => "Contains unsupported queries",
|
20
|
-
"OrienteeringER" => "Large fact type reading cannot be matched",
|
21
|
-
"ServiceDirector" => "Constraints contain adjectives that require looser matching",
|
22
17
|
}
|
23
18
|
cql_sql_failures = {
|
24
|
-
"
|
25
|
-
"CompanyDirectorEmployee" => "Names an index automatically from CQL, but explicitly from NORMA",
|
26
|
-
"Insurance" => "CQL doesn't have an option for subtype separation",
|
27
|
-
"Metamodel" =>
|
28
|
-
"Names an index automatically from CQL, but explicitly from NORMA" + " " +
|
29
|
-
"Drops uniqueness constraints",
|
30
|
-
"Orienteering" =>
|
31
|
-
"Names an index automatically from CQL, but explicitly from NORMA" + " " +
|
32
|
-
"Drops uniqueness constraints",
|
33
|
-
"RedundantDependency" => "Drops uniqueness constraints",
|
34
|
-
"SubtypePI" => "Names an index automatically from CQL, but explicitly from NORMA",
|
35
|
-
"Tests.Test5.Load" => "Names an index automatically from CQL, but explicitly from NORMA",
|
19
|
+
"OrienteeringER" => "Invalid model, it just works differently in CQL"
|
36
20
|
}
|
37
21
|
|
38
22
|
# Generate and return the SQL for the given vocabulary
|
39
23
|
def sql(vocabulary)
|
40
24
|
output = StringIO.new
|
41
|
-
@dumper = ActiveFacts::Generate::SQL::SERVER.new(vocabulary.constellation
|
25
|
+
@dumper = ActiveFacts::Generate::SQL::SERVER.new(vocabulary.constellation)
|
42
26
|
@dumper.generate(output)
|
43
27
|
output.rewind
|
44
28
|
output.read
|
@@ -73,6 +57,9 @@ describe "CQL Loader with SQL output" do
|
|
73
57
|
sql_text.should_not differ_from(expected_text)
|
74
58
|
}
|
75
59
|
else
|
60
|
+
# Discard index names:
|
61
|
+
sql_text.gsub!(/(CREATE .* INDEX )([^ ]* )ON /, '\1ON ')
|
62
|
+
expected_text.gsub!(/(CREATE .* INDEX )([^ ]* )ON /, '\1ON ')
|
76
63
|
sql_text.should_not differ_from(expected_text)
|
77
64
|
File.delete(actual_file) # It succeeded, we don't need the file.
|
78
65
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
4
|
#
|
5
5
|
|
6
|
+
=begin
|
7
|
+
|
6
8
|
require 'activefacts/support'
|
7
9
|
require 'activefacts/api/support'
|
8
10
|
require 'activefacts/input/cql'
|
@@ -256,3 +258,4 @@ describe "CQL Symbol table" do
|
|
256
258
|
end
|
257
259
|
|
258
260
|
end
|
261
|
+
=end
|
data/spec/cqldump_spec.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module ArrayMatcher
|
4
|
+
class BeDifferentArray
|
5
|
+
def initialize(expected)
|
6
|
+
@expected = expected
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches?(actual)
|
10
|
+
@extra = actual - @expected
|
11
|
+
@missing = @expected - actual
|
12
|
+
@extra + @missing != [] # Because the predicate is "be_different_array_from", the sense is inverted
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure_message
|
16
|
+
"expected a difference in the two lists, but got none"
|
17
|
+
end
|
18
|
+
|
19
|
+
def negative_failure_message
|
20
|
+
"expected no difference, but result #{
|
21
|
+
[ (@missing.empty? ? nil : 'lacks '+@missing.sort.inspect),
|
22
|
+
(@extra.empty? ? nil : 'has extra '+@extra.sort.inspect)
|
23
|
+
].compact * ' and '
|
24
|
+
}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def be_different_array_from(expected)
|
29
|
+
BeDifferentArray.new(expected)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Spec::Runner.configure do |config|
|
34
|
+
config.include(ArrayMatcher)
|
35
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Monkey patch in CTRL-C support for rspec from
|
2
|
+
# http://github.com/dchelimsky/rspec/commit/029f77c5063894cf52af05335b8e1c278411978b
|
3
|
+
# until it gets released
|
4
|
+
|
5
|
+
module Spec
|
6
|
+
module Example
|
7
|
+
module ExampleMethods
|
8
|
+
def execute(run_options, instance_variables) # :nodoc:
|
9
|
+
run_options.reporter.example_started(@_proxy)
|
10
|
+
set_instance_variables_from_hash(instance_variables)
|
11
|
+
|
12
|
+
execution_error = nil
|
13
|
+
Timeout.timeout(run_options.timeout) do
|
14
|
+
begin
|
15
|
+
before_each_example
|
16
|
+
instance_eval(&@_implementation)
|
17
|
+
rescue Interrupt
|
18
|
+
exit 1
|
19
|
+
rescue Exception => e
|
20
|
+
execution_error ||= e
|
21
|
+
end
|
22
|
+
begin
|
23
|
+
after_each_example
|
24
|
+
rescue Interrupt
|
25
|
+
exit 1
|
26
|
+
rescue Exception => e
|
27
|
+
execution_error ||= e
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
run_options.reporter.example_finished(@_proxy.update(description), execution_error)
|
32
|
+
success = execution_error.nil? || ExamplePendingError === execution_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Spec
|
39
|
+
module Runner
|
40
|
+
class ExampleGroupRunner
|
41
|
+
def run
|
42
|
+
prepare
|
43
|
+
success = true
|
44
|
+
example_groups.each do |example_group|
|
45
|
+
success = success & example_group.run(@options)
|
46
|
+
end
|
47
|
+
finish
|
48
|
+
success
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module DiffMatcher
|
4
|
+
class DifferFrom
|
5
|
+
def initialize(expected)
|
6
|
+
case expected
|
7
|
+
when Pathname
|
8
|
+
@matcher = FileMatcher::BeDifferentFile.new(expected)
|
9
|
+
when Array
|
10
|
+
@matcher = ArrayMatcher::BeDifferentArray.new(expected)
|
11
|
+
when String
|
12
|
+
@matcher = FileMatcher::BeDifferentFile.new(expected)
|
13
|
+
else
|
14
|
+
raise "DiffMatcher doesn't know how to match a #{expected.class}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def matches?(actual)
|
19
|
+
@matcher.matches?(actual)
|
20
|
+
end
|
21
|
+
|
22
|
+
def failure_message
|
23
|
+
@matcher.failure_message
|
24
|
+
end
|
25
|
+
|
26
|
+
def negative_failure_message
|
27
|
+
@matcher.negative_failure_message
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def differ_from(expected)
|
32
|
+
DifferFrom.new(expected)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Spec::Runner.configure do |config|
|
37
|
+
config.include(DiffMatcher)
|
38
|
+
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'diff/lcs'
|
2
2
|
|
3
3
|
module FileMatcher
|
4
|
-
class
|
4
|
+
class BeDifferentFile
|
5
5
|
def initialize(expected)
|
6
|
+
expected = File.open(expected).read if expected.is_a?(Pathname)
|
6
7
|
@expected = expected.scan(/[^\n]+/)
|
7
8
|
end
|
8
9
|
|
9
10
|
def matches?(actual)
|
11
|
+
actual = File.open(actual).read if actual.is_a?(Pathname)
|
10
12
|
actual_lines = actual.scan(/[^\n]+/)
|
11
13
|
differences = Diff::LCS::diff(@expected, actual_lines)
|
12
14
|
@diff = differences.map do |chunk|
|
@@ -29,8 +31,8 @@ module FileMatcher
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
33
|
-
|
34
|
+
def have_different_contents(expected)
|
35
|
+
BeDifferentFile.new(expected)
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'diff/lcs'
|
2
|
+
|
3
|
+
module StringMatcher
|
4
|
+
class BeDifferentString
|
5
|
+
def initialize(expected)
|
6
|
+
@expected = expected.scan(/[^\n]+/)
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches?(actual)
|
10
|
+
actual_lines = actual.scan(/[^\n]+/)
|
11
|
+
differences = Diff::LCS::diff(@expected, actual_lines)
|
12
|
+
@diff = differences.map do |chunk|
|
13
|
+
added_at = (add = chunk.detect{|d| d.action == '+'}) && add.position+1
|
14
|
+
removed_at = (remove = chunk.detect{|d| d.action == '-'}) && remove.position+1
|
15
|
+
"Line #{added_at}/#{removed_at}:\n"+
|
16
|
+
chunk.map do |change|
|
17
|
+
"#{change.action} #{change.element}"
|
18
|
+
end*"\n"
|
19
|
+
end*"\n"
|
20
|
+
@diff != ''
|
21
|
+
end
|
22
|
+
|
23
|
+
def failure_message
|
24
|
+
"expected a difference, but got none"
|
25
|
+
end
|
26
|
+
|
27
|
+
def negative_failure_message
|
28
|
+
"expected no difference, but got:\n#{@diff}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def have_different_contents(expected)
|
33
|
+
BeDifferentString.new(expected)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Spec::Runner.configure do |config|
|
38
|
+
config.include(StringMatcher)
|
39
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# The test parser regards any word starting with an upper-case letter as a pre-existing term
|
2
|
+
class TestParser < ActiveFacts::CQL::Parser
|
3
|
+
def context
|
4
|
+
@context ||= Context.new(self)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Context < ActiveFacts::CQL::Parser::Context
|
8
|
+
# Capitalised words that are otherwise undefined are treated as terms:
|
9
|
+
def system_term(t)
|
10
|
+
(first = t[0,1] and first.upcase == first) ? {t=>t} : false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/spec/norma_cql_spec.rb
CHANGED
@@ -10,11 +10,13 @@ require 'activefacts/support'
|
|
10
10
|
require 'activefacts/input/orm'
|
11
11
|
require 'activefacts/generate/cql'
|
12
12
|
|
13
|
-
include ActiveFacts
|
14
|
-
|
15
13
|
describe "Norma Loader" do
|
14
|
+
orm_failures = {
|
15
|
+
"SubtypePI" => "Has an illegal uniqueness join constraint",
|
16
|
+
}
|
16
17
|
orm_cql_failures = {
|
17
|
-
#
|
18
|
+
# "OddIdentifier" => "Strange identification pattern is incorrectly verbalised to CQL", # Fixed
|
19
|
+
"UnaryIdentification" => "No PI for VisitStatus",
|
18
20
|
}
|
19
21
|
# Generate and return the CQL for the given vocabulary
|
20
22
|
def cql(vocabulary)
|
@@ -29,9 +31,15 @@ describe "Norma Loader" do
|
|
29
31
|
Dir["examples/norma/#{pattern}.orm"].each do |orm_file|
|
30
32
|
expected_file = orm_file.sub(%r{/norma/(.*).orm\Z}, '/CQL/\1.cql')
|
31
33
|
actual_file = orm_file.sub(%r{examples/norma/(.*).orm\Z}, 'spec/actual/\1.cql')
|
34
|
+
base = File.basename(orm_file, ".orm")
|
32
35
|
|
33
36
|
it "should load #{orm_file} and dump CQL matching #{expected_file}" do
|
34
|
-
|
37
|
+
begin
|
38
|
+
vocabulary = ActiveFacts::Input::ORM.readfile(orm_file)
|
39
|
+
rescue => e
|
40
|
+
raise unless orm_failures.include?(base)
|
41
|
+
pending orm_failures[base]
|
42
|
+
end
|
35
43
|
|
36
44
|
cql_text = cql(vocabulary)
|
37
45
|
# Save the actual file:
|
@@ -41,7 +49,7 @@ describe "Norma Loader" do
|
|
41
49
|
|
42
50
|
expected_text = File.open(expected_file) {|f| f.read }
|
43
51
|
|
44
|
-
broken = orm_cql_failures[
|
52
|
+
broken = orm_cql_failures[base]
|
45
53
|
if broken
|
46
54
|
pending(broken) {
|
47
55
|
cql_text.should_not differ_from(expected_text)
|
data/spec/norma_ruby_spec.rb
CHANGED
@@ -10,8 +10,6 @@ require 'activefacts/support'
|
|
10
10
|
require 'activefacts/input/orm'
|
11
11
|
require 'activefacts/generate/ruby'
|
12
12
|
|
13
|
-
include ActiveFacts
|
14
|
-
|
15
13
|
class String
|
16
14
|
def strip_comments()
|
17
15
|
c_comment = %r{/\*((?!\*/).)*\*/}m
|
@@ -20,6 +18,10 @@ class String
|
|
20
18
|
end
|
21
19
|
|
22
20
|
describe "NORMA Loader with Ruby output" do
|
21
|
+
orm_failures = {
|
22
|
+
"SubtypePI" => "Has an illegal uniqueness join constraint",
|
23
|
+
}
|
24
|
+
|
23
25
|
# Generate and return the Ruby for the given vocabulary
|
24
26
|
def ruby(vocabulary)
|
25
27
|
output = StringIO.new
|
@@ -33,9 +35,15 @@ describe "NORMA Loader with Ruby output" do
|
|
33
35
|
Dir["examples/norma/#{pattern}.orm"].each do |orm_file|
|
34
36
|
expected_file = orm_file.sub(%r{examples/norma/(.*).orm\Z}, 'examples/ruby/\1.rb')
|
35
37
|
actual_file = orm_file.sub(%r{examples/norma/(.*).orm\Z}, 'spec/actual/\1.rb')
|
38
|
+
base = File.basename(orm_file, ".orm")
|
36
39
|
|
37
40
|
it "should load #{orm_file} and dump Ruby matching #{expected_file}" do
|
38
|
-
|
41
|
+
begin
|
42
|
+
vocabulary = ActiveFacts::Input::ORM.readfile(orm_file)
|
43
|
+
rescue => e
|
44
|
+
raise unless orm_failures.include?(base)
|
45
|
+
pending orm_failures[base]
|
46
|
+
end
|
39
47
|
|
40
48
|
# Build and save the actual file:
|
41
49
|
ruby_text = ruby(vocabulary)
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
4
|
#
|
5
5
|
|
6
|
+
require 'spec/spec_helper'
|
6
7
|
require 'stringio'
|
7
8
|
require 'activefacts/vocabulary'
|
8
9
|
require 'activefacts/support'
|
@@ -10,13 +11,14 @@ require 'activefacts/input/orm'
|
|
10
11
|
require 'activefacts/persistence'
|
11
12
|
require 'activefacts/generate/ruby'
|
12
13
|
|
13
|
-
include ActiveFacts
|
14
|
-
|
15
14
|
describe "Column lists from absorption compared with Ruby's" do
|
16
|
-
|
17
|
-
"
|
18
|
-
|
19
|
-
|
15
|
+
orm_failures = {
|
16
|
+
"SubtypePI" => "Has an illegal uniqueness join constraint",
|
17
|
+
}
|
18
|
+
norma_ruby_failures = {
|
19
|
+
"UnaryIdentification" => "No PI for VisitStatus",
|
20
|
+
"BPMN" => "Has duplicate column names",
|
21
|
+
"Diplomacy" => "Has duplicate column names",
|
20
22
|
}
|
21
23
|
|
22
24
|
# Generate and return the Ruby for the given vocabulary
|
@@ -32,29 +34,52 @@ describe "Column lists from absorption compared with Ruby's" do
|
|
32
34
|
Dir["examples/norma/#{pattern}.orm"].each do |orm_file|
|
33
35
|
expected_file = orm_file.sub(%r{examples/norma/(.*).orm\Z}, 'examples/ruby/\1.rb')
|
34
36
|
actual_file = orm_file.sub(%r{examples/norma/(.*).orm\Z}, 'spec/actual/\1.rb')
|
37
|
+
base = File.basename(orm_file, ".orm")
|
35
38
|
|
36
39
|
it "should load #{orm_file} and generate relational composition and Ruby with matching column names" do
|
37
|
-
|
40
|
+
begin
|
41
|
+
vocabulary = ActiveFacts::Input::ORM.readfile(orm_file)
|
42
|
+
rescue => e
|
43
|
+
raise unless orm_failures.include?(base)
|
44
|
+
pending orm_failures[base]
|
45
|
+
end
|
38
46
|
|
39
47
|
# Get the list of tables from the relational composition:
|
40
48
|
absorption_tables = vocabulary.tables.sort_by(&:name)
|
41
|
-
absorption_table_names = absorption_tables.map{|at| at.name}
|
49
|
+
absorption_table_names = absorption_tables.map{|at| at.name.gsub(/\s/,'')}
|
42
50
|
|
43
51
|
# Build the Ruby and eval it:
|
44
52
|
ruby_text = ruby(vocabulary)
|
45
53
|
File.open(actual_file, "w") { |f| f.write ruby_text }
|
46
54
|
|
47
|
-
broken =
|
48
|
-
eval_it = lambda {
|
55
|
+
broken = norma_ruby_failures[base]
|
56
|
+
eval_it = lambda {
|
57
|
+
Object.send :eval, ruby_text
|
58
|
+
}
|
59
|
+
exception = nil
|
49
60
|
if broken
|
50
61
|
pending(broken) {
|
51
62
|
lambda {
|
52
|
-
|
63
|
+
begin
|
64
|
+
eval_it.call
|
65
|
+
rescue => exception
|
66
|
+
if debug :exception
|
67
|
+
puts exception.to_s+": \n\t"+exception.backtrace*"\n\t"
|
68
|
+
end
|
69
|
+
raise
|
70
|
+
end
|
53
71
|
}.should_not raise_error
|
54
72
|
}
|
55
73
|
else
|
56
74
|
lambda {
|
75
|
+
begin
|
57
76
|
eval_it.call
|
77
|
+
rescue => exception
|
78
|
+
if debug :exception
|
79
|
+
puts exception.to_s+": \n\t"+exception.backtrace*"\n\t"
|
80
|
+
end
|
81
|
+
raise
|
82
|
+
end
|
58
83
|
}.should_not raise_error
|
59
84
|
end
|
60
85
|
|
@@ -69,27 +94,7 @@ describe "Column lists from absorption compared with Ruby's" do
|
|
69
94
|
ruby_table_names = ruby_tables.map{|c| c.basename}
|
70
95
|
|
71
96
|
# Assert that the list of tables is the same:
|
72
|
-
|
73
|
-
if broken
|
74
|
-
pending { tables.call }
|
75
|
-
else
|
76
|
-
tables.call
|
77
|
-
end
|
78
|
-
|
79
|
-
# So we get to see the full differences, figure them here and assert them to be empty:
|
80
|
-
diffs = {}
|
81
|
-
ruby_tables.each{|rt|
|
82
|
-
next unless rt.is_entity_type
|
83
|
-
absorption_table = absorption_tables.select{|at| at.name == rt.basename}[0]
|
84
|
-
absorption_columns = absorption_table.columns.map{|c| c.name("").downcase}.sort
|
85
|
-
ruby_columns = rt.columns.map{|c| c.gsub(/\./,'').downcase}.sort
|
86
|
-
missing = absorption_columns - ruby_columns
|
87
|
-
extra = ruby_columns - absorption_columns
|
88
|
-
unless missing.empty? and extra.empty?
|
89
|
-
diffs[rt.basename] = missing.map{|m| "-"+m} + extra.map{|e| '+'+e}
|
90
|
-
end
|
91
|
-
}
|
92
|
-
diffs.should == {}
|
97
|
+
ruby_table_names.should_not differ_from(absorption_table_names)
|
93
98
|
|
94
99
|
# Clean up:
|
95
100
|
Object.send :remove_const, vocabulary.name.to_sym
|