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
@@ -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, "norma")
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
- pending("expected output file #{expected_file} not found") unless File.exists? expected_file
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")]
@@ -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"] || "*"
@@ -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" => "Large fact type reading cannot be matched",
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
- "Blog" => "Drops uniqueness constraints",
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, "norma")
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
@@ -8,8 +8,6 @@ require 'activefacts/support'
8
8
  require 'activefacts/vocabulary'
9
9
  require 'activefacts/generate/cql'
10
10
 
11
- include ActiveFacts
12
-
13
11
  describe "CQL Dumper" do
14
12
  def self.hide(*a,&b)
15
13
  end
@@ -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 BeDifferent
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 differ_from(expected)
33
- BeDifferent.new(expected)
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
@@ -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
- # "OddIdentifier" => "Strange identification pattern is incorrectly verbalised to CQL", # Fixed
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
- vocabulary = ActiveFacts::Input::ORM.readfile(orm_file)
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[File.basename(orm_file, ".orm")]
52
+ broken = orm_cql_failures[base]
45
53
  if broken
46
54
  pending(broken) {
47
55
  cql_text.should_not differ_from(expected_text)
@@ -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
- vocabulary = ActiveFacts::Input::ORM.readfile(orm_file)
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
- ABSORPTION_RUBY_FAILURES = {
17
- "Metamodel" => "Overlaps with ActiveFacts Metamodel",
18
- "MetamodelNext" => "Overlaps with ActiveFacts Metamodel",
19
- "ServiceDirector" => "Lacks standard AutoTimestamp class"
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
- vocabulary = ActiveFacts::Input::ORM.readfile(orm_file)
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 = ABSORPTION_RUBY_FAILURES[File.basename(orm_file, ".orm")]
48
- eval_it = lambda { Object.send :eval, ruby_text }
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
- eval_it.call
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
- tables = lambda { ruby_table_names.should == absorption_table_names }
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