activefacts 0.8.9 → 0.8.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -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
|
data/spec/api/autocounter.rb
DELETED
@@ -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
|
data/spec/api/constellation.rb
DELETED
@@ -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
|