activefacts 0.8.9 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. data/.gemtest +0 -0
  2. data/Manifest.txt +28 -33
  3. data/Rakefile +11 -12
  4. data/bin/cql +90 -46
  5. data/examples/CQL/Blog.cql +2 -1
  6. data/examples/CQL/CompanyDirectorEmployee.cql +2 -2
  7. data/examples/CQL/Death.cql +1 -1
  8. data/examples/CQL/Diplomacy.cql +9 -9
  9. data/examples/CQL/Genealogy.cql +3 -2
  10. data/examples/CQL/Insurance.cql +10 -7
  11. data/examples/CQL/JoinEquality.cql +2 -2
  12. data/examples/CQL/Marriage.cql +1 -1
  13. data/examples/CQL/Metamodel.cql +73 -53
  14. data/examples/CQL/MetamodelNext.cql +89 -67
  15. data/examples/CQL/OneToOnes.cql +2 -2
  16. data/examples/CQL/ServiceDirector.cql +10 -5
  17. data/examples/CQL/Supervision.cql +3 -3
  18. data/examples/CQL/Tests.Test5.Load.cql +1 -1
  19. data/examples/CQL/Warehousing.cql +4 -2
  20. data/lib/activefacts/cql/CQLParser.treetop +26 -60
  21. data/lib/activefacts/cql/Context.treetop +12 -2
  22. data/lib/activefacts/cql/Expressions.treetop +14 -30
  23. data/lib/activefacts/cql/FactTypes.treetop +165 -110
  24. data/lib/activefacts/cql/Language/English.treetop +167 -54
  25. data/lib/activefacts/cql/LexicalRules.treetop +16 -2
  26. data/lib/activefacts/cql/{Concepts.treetop → ObjectTypes.treetop} +36 -37
  27. data/lib/activefacts/cql/Terms.treetop +57 -27
  28. data/lib/activefacts/cql/ValueTypes.treetop +39 -13
  29. data/lib/activefacts/cql/compiler.rb +5 -3
  30. data/lib/activefacts/cql/compiler/{reading.rb → clause.rb} +407 -285
  31. data/lib/activefacts/cql/compiler/constraint.rb +178 -275
  32. data/lib/activefacts/cql/compiler/entity_type.rb +73 -64
  33. data/lib/activefacts/cql/compiler/expression.rb +418 -0
  34. data/lib/activefacts/cql/compiler/fact.rb +146 -145
  35. data/lib/activefacts/cql/compiler/fact_type.rb +197 -80
  36. data/lib/activefacts/cql/compiler/join.rb +159 -0
  37. data/lib/activefacts/cql/compiler/shared.rb +51 -23
  38. data/lib/activefacts/cql/compiler/value_type.rb +56 -2
  39. data/lib/activefacts/cql/parser.rb +15 -4
  40. data/lib/activefacts/generate/absorption.rb +7 -7
  41. data/lib/activefacts/generate/cql.rb +100 -37
  42. data/lib/activefacts/generate/oo.rb +28 -51
  43. data/lib/activefacts/generate/ordered.rb +60 -36
  44. data/lib/activefacts/generate/ruby.rb +6 -6
  45. data/lib/activefacts/generate/sql/server.rb +4 -4
  46. data/lib/activefacts/input/orm.rb +71 -53
  47. data/lib/activefacts/persistence.rb +1 -1
  48. data/lib/activefacts/persistence/columns.rb +27 -23
  49. data/lib/activefacts/persistence/foreignkey.rb +6 -6
  50. data/lib/activefacts/persistence/index.rb +17 -17
  51. data/lib/activefacts/persistence/{concept.rb → object_type.rb} +9 -9
  52. data/lib/activefacts/persistence/reference.rb +61 -36
  53. data/lib/activefacts/persistence/tables.rb +61 -59
  54. data/lib/activefacts/support.rb +54 -29
  55. data/lib/activefacts/version.rb +1 -1
  56. data/lib/activefacts/vocabulary/extensions.rb +99 -54
  57. data/lib/activefacts/vocabulary/metamodel.rb +43 -37
  58. data/lib/activefacts/vocabulary/verbaliser.rb +134 -109
  59. data/spec/absorption_spec.rb +8 -8
  60. data/spec/cql/comparison_spec.rb +91 -0
  61. data/spec/cql/contractions_spec.rb +251 -0
  62. data/spec/cql/entity_type_spec.rb +319 -0
  63. data/spec/cql/expressions_spec.rb +63 -0
  64. data/spec/cql/fact_type_matching_spec.rb +283 -0
  65. data/spec/cql/french_spec.rb +21 -0
  66. data/spec/cql/parser/bad_literals_spec.rb +86 -0
  67. data/spec/cql/parser/constraints_spec.rb +19 -0
  68. data/spec/cql/parser/entity_types_spec.rb +106 -0
  69. data/spec/cql/parser/expressions_spec.rb +179 -0
  70. data/spec/cql/parser/fact_types_spec.rb +41 -0
  71. data/spec/cql/parser/literals_spec.rb +312 -0
  72. data/spec/cql/parser/pragmas_spec.rb +89 -0
  73. data/spec/cql/parser/value_types_spec.rb +42 -0
  74. data/spec/cql/role_matching_spec.rb +147 -0
  75. data/spec/cql/samples_spec.rb +9 -9
  76. data/spec/cql_cql_spec.rb +1 -1
  77. data/spec/cql_dm_spec.rb +116 -0
  78. data/spec/cql_mysql_spec.rb +1 -1
  79. data/spec/cql_ruby_spec.rb +1 -1
  80. data/spec/cql_sql_spec.rb +3 -3
  81. data/spec/cql_symbol_tables_spec.rb +30 -30
  82. data/spec/cqldump_spec.rb +4 -4
  83. data/spec/helpers/array_matcher.rb +32 -27
  84. data/spec/helpers/diff_matcher.rb +6 -26
  85. data/spec/helpers/file_matcher.rb +41 -32
  86. data/spec/helpers/parse_to_ast_matcher.rb +76 -0
  87. data/spec/helpers/string_matcher.rb +32 -31
  88. data/spec/norma_cql_spec.rb +1 -1
  89. data/spec/norma_ruby_spec.rb +1 -1
  90. data/spec/norma_ruby_sql_spec.rb +1 -1
  91. data/spec/norma_sql_spec.rb +3 -1
  92. data/spec/norma_tables_spec.rb +1 -1
  93. data/spec/ruby_api_spec.rb +23 -0
  94. data/spec/spec_helper.rb +5 -4
  95. metadata +66 -66
  96. data/examples/CQL/OrienteeringER.cql +0 -58
  97. data/lib/activefacts/api.rb +0 -44
  98. data/lib/activefacts/api/concept.rb +0 -410
  99. data/lib/activefacts/api/constellation.rb +0 -128
  100. data/lib/activefacts/api/entity.rb +0 -256
  101. data/lib/activefacts/api/instance.rb +0 -60
  102. data/lib/activefacts/api/instance_index.rb +0 -80
  103. data/lib/activefacts/api/numeric.rb +0 -167
  104. data/lib/activefacts/api/role.rb +0 -80
  105. data/lib/activefacts/api/role_proxy.rb +0 -70
  106. data/lib/activefacts/api/role_values.rb +0 -117
  107. data/lib/activefacts/api/standard_types.rb +0 -87
  108. data/lib/activefacts/api/support.rb +0 -65
  109. data/lib/activefacts/api/value.rb +0 -135
  110. data/lib/activefacts/api/vocabulary.rb +0 -82
  111. data/spec/api/autocounter.rb +0 -82
  112. data/spec/api/constellation.rb +0 -130
  113. data/spec/api/entity_type.rb +0 -103
  114. data/spec/api/instance.rb +0 -461
  115. data/spec/api/roles.rb +0 -124
  116. data/spec/api/value_type.rb +0 -112
  117. data/spec/api_spec.rb +0 -13
  118. data/spec/cql/matching_spec.rb +0 -517
  119. data/spec/cql/unit_spec.rb +0 -394
  120. data/spec/spec.opts +0 -1
@@ -1,65 +0,0 @@
1
- #
2
- # ActiveFacts Runtime API.
3
- # Various additions or patches to Ruby built-in classes, and some global support methods
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
-
8
- class Symbol #:nodoc:
9
- def to_proc
10
- Proc.new{|*args| args.shift.__send__(self, *args)}
11
- end
12
- end
13
-
14
- class String #:nodoc:
15
- def camelcase(first=false, on='_\s')
16
- if first
17
- gsub(/(^|[#{on}]+)([A-Za-z])/){ $2.upcase }
18
- else
19
- gsub(/([#{on}]+)([A-Za-z])/){ $2.upcase }
20
- end
21
- end
22
-
23
- def snakecase
24
- gsub(/([a-z])([A-Z])/,'\1_\2').downcase
25
- end
26
-
27
- def camelwords
28
- gsub(/-([a-zA-Z])/){ $1.upcase }. # Break and upcase on hyphenated words
29
- gsub(/([a-z])([A-Z])/,'\1_\2').
30
- split(/[_\s]+/)
31
- end
32
- end
33
-
34
- class Module #:nodoc:
35
- def modspace
36
- space = name[ 0...(name.rindex( '::' ) || 0)]
37
- space == '' ? Object : eval(space)
38
- end
39
-
40
- def basename
41
- name.gsub(/.*::/, '')
42
- end
43
- end
44
-
45
- module ActiveFacts #:nodoc:
46
- # If the args array ends with a hash, remove it.
47
- # If the remaining args are fewer than the arg_names,
48
- # extract values from the hash and append them to args.
49
- # Return the new args array and the hash.
50
- # In any case leave the original args unmodified.
51
- def self.extract_hash_args(arg_names, args)
52
- if Hash === args[-1]
53
- arg_hash = args[-1] # Don't pop args, leave it unmodified
54
- args = args[0..-2]
55
- arg_hash = arg_hash.clone if (args.size < arg_names.size)
56
- while args.size < arg_names.size
57
- args << arg_hash[n = arg_names[args.size]]
58
- arg_hash.delete(n)
59
- end
60
- else
61
- arg_hash = {}
62
- end
63
- return args, arg_hash
64
- end
65
- end
@@ -1,135 +0,0 @@
1
- #
2
- # ActiveFacts Runtime API
3
- # Value module (mixins for ValueType classes and instances)
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- # The methods of this module are added to Value type classes.
8
- #
9
- module ActiveFacts
10
- module API
11
-
12
- # All Value instances include the methods defined here
13
- module Value
14
- include Instance
15
-
16
- # Value instance methods:
17
- def initialize(*args) #:nodoc:
18
- args[0] = args[0].__getobj__ if RoleProxy === args[0]
19
- super(args)
20
- end
21
-
22
- # verbalise this Value
23
- def verbalise(role_name = nil)
24
- "#{role_name || self.class.basename} '#{to_s}'"
25
- end
26
-
27
- # A value is its own key
28
- def identifying_role_values #:nodoc:
29
- self
30
- end
31
-
32
- # All ValueType classes include the methods defined here
33
- module ClassMethods
34
- include Instance::ClassMethods
35
-
36
- def initialise_value_type *args, &block #:nodoc:
37
- # REVISIT: args could be a hash, with keys :length, :scale, :unit, :allow
38
- #raise "value_type args unexpected" if args.size > 0
39
- end
40
-
41
- class_eval do
42
- define_method :length do |*args|
43
- @length = args[0] if args.length > 0
44
- @length
45
- end
46
- end
47
-
48
- class_eval do
49
- define_method :scale do |*args|
50
- @scale = args[0] if args.length > 0
51
- @scale
52
- end
53
- end
54
-
55
- class_eval do
56
- define_method :restrict do |*value_ranges|
57
- @value_ranges = *value_ranges
58
- end
59
- end
60
-
61
- # verbalise this ValueType
62
- def verbalise
63
- # REVISIT: Add length and scale here, if set
64
- # REVISIT: Set vocabulary name of superclass if not same as this
65
- "#{basename} = #{superclass.basename}();"
66
- end
67
-
68
- def identifying_role_values(*args) #:nodoc:
69
- # If the single arg is the correct class or a subclass, use it directly
70
- #puts "#{basename}.identifying_role_values#{args.inspect}"
71
- if (args.size == 1 and (arg = args[0]).is_a?(self.class)) # No secondary supertypes allowed for value types
72
- arg = arg.__getobj__ if RoleProxy === arg
73
- return arg
74
- end
75
- new(*args)
76
- end
77
-
78
- def assert_instance(constellation, args) #:nodoc:
79
- # Build the key for this instance from the args
80
- # The key of an instance is the value or array of keys of the identifying values.
81
- # The key values aren't necessarily present in the constellation, even after this.
82
- key = identifying_role_values(*args)
83
- #puts "#{klass} key is #{key.inspect}"
84
-
85
- # Find and return an existing instance matching this key
86
- instances = constellation.instances[self] # All instances of this class in this constellation
87
- instance = instances[key]
88
- # DEBUG: puts "assert #{self.basename} #{key.inspect} #{instance ? "exists" : "new"}"
89
- return instance, key if instance # A matching instance of this class
90
-
91
- instance = new(*args)
92
-
93
- instance.constellation = constellation
94
- return *index_instance(instance)
95
- end
96
-
97
- def index_instance(instance, key = nil) #:nodoc:
98
- instances = instance.constellation.instances[self]
99
- key = instance.identifying_role_values
100
- instances[key] = instance
101
- # DEBUG: puts "indexing value #{basename} using #{key.inspect} in #{constellation.object_id}"
102
-
103
- # Index the instance for each supertype:
104
- supertypes.each do |supertype|
105
- supertype.index_instance(instance, key)
106
- end
107
-
108
- return instance, key
109
- end
110
-
111
- def inherited(other) #:nodoc:
112
- #puts "REVISIT: ValueType #{self} < #{self.superclass} was inherited by #{other}; not implemented" #+"from #{caller*"\n\t"}"
113
- # Copy the type parameters here, etc?
114
- other.send :realise_supertypes, self
115
- vocabulary.__add_concept(other)
116
- super
117
- end
118
- end
119
-
120
- def self.included other #:nodoc:
121
- other.send :extend, ClassMethods
122
-
123
- #puts "ValueType included in #{other.basename} from #{caller*"\n\t"}"
124
-
125
- # Register ourselves with the parent module, which has become a Vocabulary:
126
- vocabulary = other.modspace
127
- # puts "ValueType.included(#{other.inspect})"
128
- unless vocabulary.respond_to? :concept # Extend module with Vocabulary if necessary
129
- vocabulary.send :extend, Vocabulary
130
- end
131
- vocabulary.__add_concept(other)
132
- end
133
- end
134
- end
135
- end
@@ -1,82 +0,0 @@
1
- #
2
- # ActiveFacts Runtime API
3
- # Vocabulary module (mixin for any Module that contains classes having Concept mixed in)
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- # The methods of this module are extended into any module that contains
8
- # a Concept class (Entity type or Value type).
9
- #
10
- module ActiveFacts
11
- module API
12
- # Vocabulary is a mixin that adds methods to any Module which has any Concept classes (ValueType or EntityType).
13
- # A Vocabulary knows all the Concept classes including forward-referenced ones,
14
- # and can resolve the forward references when the class is finally defined.
15
- # Construction of a Constellation requires a Vocabuary as argument.
16
- module Vocabulary
17
- # With a parameter, look up a concept class by name.
18
- # Without, return the hash (keyed by the class' basename) of all concepts in this vocabulary
19
- def concept(name = nil)
20
- @concept ||= {}
21
- return @concept unless name
22
-
23
- return name if name.is_a? Class
24
-
25
- # puts "Looking up concept #{name} in #{self.name}"
26
- camel = name.to_s.camelcase(true)
27
- if (c = @concept[camel])
28
- __bind(camel)
29
- return c
30
- end
31
- return (const_get("#{name}::#{camel}") rescue nil)
32
- end
33
-
34
- # Create a new constellation over this vocabulary
35
- def constellation
36
- Constellation.new(self)
37
- end
38
-
39
- def populate &b
40
- constellation.populate &b
41
- end
42
-
43
- def verbalise
44
- "Vocabulary #{name}:\n\t" +
45
- @concept.keys.sort.map{|concept|
46
- c = @concept[concept]
47
- __bind(c.basename)
48
- c.verbalise + "\n\t\t// Roles played: " + c.roles.verbalise
49
- }*"\n\t"
50
- end
51
-
52
- def __add_concept(klass) #:nodoc:
53
- name = klass.basename
54
- __bind(name)
55
- # puts "Adding concept #{name} to #{self.name}"
56
- @concept ||= {}
57
- @concept[klass.basename] = klass
58
- end
59
-
60
- def __delay(concept_name, args, &block) #:nodoc:
61
- # puts "Arranging for delayed binding on #{concept_name.inspect}"
62
- @delayed ||= Hash.new { |h,k| h[k] = [] }
63
- @delayed[concept_name] << [args, block]
64
- end
65
-
66
- # __bind raises an error if the named class doesn't exist yet.
67
- def __bind(concept_name) #:nodoc:
68
- concept = const_get(concept_name)
69
- # puts "#{name}.__bind #{concept_name} -> #{concept.name}" if concept
70
- if (@delayed && @delayed.include?(concept_name))
71
- # $stderr.puts "#{concept_name} was delayed, binding now"
72
- d = @delayed[concept_name]
73
- d.each{|(a,b)|
74
- b.call(concept, *a)
75
- }
76
- @delayed.delete(concept_name)
77
- end
78
- end
79
-
80
- end
81
- end
82
- end
@@ -1,82 +0,0 @@
1
- #
2
- # ActiveFacts tests: Value instances in the Runtime API
3
- # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
- #
5
- describe "AutoCounter Value Type instances" do
6
- before :each do
7
- Object.send :remove_const, :Mod if Object.const_defined?("Mod")
8
- module Mod
9
- class ThingId < AutoCounter
10
- value_type
11
- end
12
- class Thing
13
- identified_by :thing_id
14
- has_one :thing_id
15
- end
16
- class Ordinal < Int
17
- value_type
18
- end
19
- class ThingFacet
20
- identified_by :thing, :ordinal
21
- has_one :thing
22
- has_one :ordinal
23
- end
24
- end
25
- @constellation = ActiveFacts::API::Constellation.new(Mod)
26
- @thing = Mod::Thing.new(:new)
27
- @thing_id = Mod::ThingId.new
28
- end
29
-
30
- it "should respond to verbalise" do
31
- @thing_id.respond_to?(:verbalise).should be_true
32
- end
33
-
34
- it "should verbalise correctly" do
35
- @thing_id.verbalise.should =~ /ThingId 'new_[0-9]+'/
36
- end
37
-
38
- it "should respond to constellation" do
39
- @thing_id.respond_to?(:constellation).should be_true
40
- end
41
-
42
- it "should respond to its roles" do
43
- @thing_id.respond_to?(:all_thing).should be_true
44
- end
45
-
46
- it "should allow prevent invalid role assignment" do
47
- lambda {
48
- @thing.thing_id = "foo"
49
- }.should raise_error
50
- end
51
-
52
- it "should not allow its identifying roles to be assigned" do
53
- lambda {
54
- @thing.thing_id = @thing_id
55
- }.should raise_error
56
- end
57
-
58
- it "should allow an existing counter to be re-used" do
59
- @new_thing = Mod::Thing.new(@thing_id)
60
- @new_thing.thing_id.should == @thing_id
61
- end
62
-
63
- it "should return the ValueType in response to .class()" do
64
- @thing_id.class.vocabulary.should == Mod
65
- end
66
-
67
- it "should not allow a counter to be cloned" do
68
- lambda {
69
- @thing_id.clone
70
- }.should raise_error
71
- end
72
-
73
- it "should allow an existing counter-identified object to be re-used" do
74
- thing = @constellation.Thing(:new)
75
- facets = []
76
- facets << @constellation.ThingFacet(thing, 0)
77
- facets << @constellation.ThingFacet(thing, 1)
78
- facets[0].thing.object_id.should == facets[1].thing.object_id
79
- facets[0].thing.thing_id.object_id.should == facets[1].thing.thing_id.object_id
80
- end
81
-
82
- end
@@ -1,130 +0,0 @@
1
- #
2
- # ActiveFacts tests: Constellation instances in the Runtime API
3
- # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
- #
5
- require "ruby-debug"
6
-
7
- require 'activefacts/api'
8
-
9
- describe "A Constellation instance" do
10
- before :each do
11
- Object.send :remove_const, :Mod if Object.const_defined?("Mod")
12
- module Mod
13
- @base_types = [
14
- Int, Real, AutoCounter, String, Date, DateTime
15
- ]
16
-
17
- # Create a value type and a subtype of that value type for each base type:
18
- @base_types.each do |base_type|
19
- eval %Q{
20
- class #{base_type.name}Value < #{base_type.name}
21
- value_type
22
- end
23
-
24
- class #{base_type.name}SubValue < #{base_type.name}Value
25
- # Note no new "value_type" is required here, it comes through inheritance
26
- end
27
- }
28
- end
29
-
30
- class Name < StringValue
31
- value_type
32
- #has_one :attr, Name
33
- end
34
-
35
- class LegalEntity
36
- identified_by :name
37
- has_one :name
38
- end
39
-
40
- class SurrogateId
41
- identified_by :auto_counter_value
42
- has_one :auto_counter_value
43
- end
44
-
45
- class Company < LegalEntity
46
- supertypes SurrogateId
47
- end
48
-
49
- class Person < LegalEntity
50
- identified_by :name, :family_name # REVISIT: want a way to role_alias :name, :given_name
51
- supertypes SurrogateId
52
-
53
- has_one :family_name, :class => Name
54
- end
55
- end
56
- @constellation = ActiveFacts::API::Constellation.new(Mod)
57
- end
58
-
59
- it "should support fetching its vocabulary" do
60
- @constellation.vocabulary.should == Mod
61
- end
62
-
63
- # it "should support fetching its query" do
64
- # pending
65
- # @constellation.query.should == Mod
66
- # end
67
-
68
- it "should support methods to construct instances of any concept" do
69
- name = foo = acme = fred_fly = nil
70
- lambda {
71
- name = @constellation.Name("foo")
72
- foo = @constellation.LegalEntity("foo")
73
- acme = @constellation.Company("Acme, Inc")
74
- fred_fly = @constellation.Person("fred", "fly")
75
- }.should_not raise_error
76
- name.class.should == Mod::Name
77
- name.constellation.should == @constellation
78
- foo.class.should == Mod::LegalEntity
79
- foo.constellation.should == @constellation
80
- acme.class.should == Mod::Company
81
- acme.constellation.should == @constellation
82
- fred_fly.class.should == Mod::Person
83
- fred_fly.constellation.should == @constellation
84
- end
85
-
86
- it "should re-use instances constructed the same way" do
87
- name1 = @constellation.Name("foo")
88
- foo1 = @constellation.LegalEntity("foo")
89
- acme1 = @constellation.Company("Acme, Inc")
90
- fred_fly1 = @constellation.Person("fred", "fly")
91
-
92
- name2 = @constellation.Name("foo")
93
- foo2 = @constellation.LegalEntity("foo")
94
- acme2 = @constellation.Company("Acme, Inc")
95
- fred_fly2 = @constellation.Person("fred", "fly")
96
-
97
- name1.object_id.should == name2.object_id
98
- foo1.object_id.should == foo2.object_id
99
- acme1.object_id.should == acme2.object_id
100
- fred_fly1.object_id.should == fred_fly2.object_id
101
- end
102
-
103
- it "should index value instances, including by its superclasses" do
104
- baz = @constellation.Name("baz")
105
- @constellation.Name.keys.sort.should == ["baz"]
106
-
107
- @constellation.StringValue.keys.sort.should == ["baz"]
108
- end
109
-
110
- it "should index entity instances, including by its superclass and secondary supertypes" do
111
- name = "Acme, Inc"
112
- fred = "Fred"
113
- fly = "Fly"
114
- acme = @constellation.Company name, :auto_counter_value => :new
115
- fred_fly = @constellation.Person fred, fly, :auto_counter_value => :new
116
-
117
- # REVISIT: This should be illegal:
118
- #fred_fly.auto_counter_value = :new
119
-
120
- @constellation.Person.keys.sort.should == [[fred, fly]]
121
- @constellation.Company.keys.sort.should == [[name]]
122
-
123
- @constellation.LegalEntity.keys.sort.should be_include([name])
124
- @constellation.LegalEntity.keys.sort.should be_include([fred])
125
-
126
- @constellation.SurrogateId.values.should be_include(acme)
127
- @constellation.SurrogateId.values.should be_include(fred_fly)
128
- end
129
-
130
- end