activefacts 0.7.3 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +19 -0
- data/Manifest.txt +24 -2
- data/Rakefile +25 -3
- data/bin/afgen +1 -1
- data/bin/cql +13 -2
- data/css/offline.css +3 -0
- data/css/orm2.css +24 -0
- data/css/print.css +8 -0
- data/css/style-print.css +357 -0
- data/css/style.css +387 -0
- data/download.html +85 -0
- data/examples/CQL/Address.cql +3 -3
- data/examples/CQL/Blog.cql +13 -14
- data/examples/CQL/CompanyDirectorEmployee.cql +4 -4
- data/examples/CQL/Death.cql +3 -2
- data/examples/CQL/Genealogy.cql +13 -11
- data/examples/CQL/Marriage.cql +2 -2
- data/examples/CQL/Metamodel.cql +136 -93
- data/examples/CQL/MultiInheritance.cql +2 -2
- data/examples/CQL/OilSupply.cql +14 -10
- data/examples/CQL/Orienteering.cql +22 -19
- data/examples/CQL/PersonPlaysGame.cql +3 -2
- data/examples/CQL/SchoolActivities.cql +4 -2
- data/examples/CQL/SimplestUnary.cql +1 -1
- data/examples/CQL/SubtypePI.cql +6 -7
- data/examples/CQL/Warehousing.cql +16 -19
- data/examples/CQL/unit.cql +584 -0
- data/examples/index.html +276 -0
- data/examples/intro.html +497 -0
- data/examples/local.css +20 -0
- data/index.html +96 -0
- data/lib/activefacts/api/concept.rb +48 -46
- data/lib/activefacts/api/constellation.rb +43 -23
- data/lib/activefacts/api/entity.rb +2 -2
- data/lib/activefacts/api/instance.rb +6 -2
- data/lib/activefacts/api/instance_index.rb +5 -0
- data/lib/activefacts/api/value.rb +8 -2
- data/lib/activefacts/api/vocabulary.rb +15 -10
- data/lib/activefacts/cql/CQLParser.treetop +109 -88
- data/lib/activefacts/cql/Concepts.treetop +32 -10
- data/lib/activefacts/cql/Context.treetop +34 -0
- data/lib/activefacts/cql/Expressions.treetop +9 -9
- data/lib/activefacts/cql/FactTypes.treetop +30 -31
- data/lib/activefacts/cql/Language/English.treetop +50 -0
- data/lib/activefacts/cql/LexicalRules.treetop +2 -1
- data/lib/activefacts/cql/Terms.treetop +117 -0
- data/lib/activefacts/cql/ValueTypes.treetop +152 -0
- data/lib/activefacts/cql/compiler.rb +1718 -0
- data/lib/activefacts/cql/parser.rb +124 -57
- data/lib/activefacts/generate/absorption.rb +1 -1
- data/lib/activefacts/generate/cql.rb +111 -100
- data/lib/activefacts/generate/cql/html.rb +5 -5
- data/lib/activefacts/generate/oo.rb +3 -3
- data/lib/activefacts/generate/ordered.rb +51 -19
- data/lib/activefacts/generate/ruby.rb +10 -8
- data/lib/activefacts/generate/sql/mysql.rb +14 -10
- data/lib/activefacts/generate/sql/server.rb +29 -24
- data/lib/activefacts/input/cql.rb +9 -1264
- data/lib/activefacts/input/orm.rb +213 -200
- data/lib/activefacts/persistence/columns.rb +11 -10
- data/lib/activefacts/persistence/index.rb +15 -18
- data/lib/activefacts/persistence/reference.rb +17 -17
- data/lib/activefacts/persistence/tables.rb +50 -51
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/extensions.rb +79 -8
- data/lib/activefacts/vocabulary/metamodel.rb +183 -114
- data/spec/absorption_ruby_spec.rb +99 -0
- data/spec/absorption_spec.rb +3 -4
- data/spec/api/constellation.rb +1 -1
- data/spec/api/entity_type.rb +3 -1
- data/spec/api/instance.rb +4 -2
- data/spec/api/roles.rb +8 -6
- data/spec/api_spec.rb +1 -2
- data/spec/cql/context_spec.rb +71 -0
- data/spec/cql/samples_spec.rb +154 -0
- data/spec/cql/unit_spec.rb +375 -0
- data/spec/cql_cql_spec.rb +31 -21
- data/spec/cql_mysql_spec.rb +70 -0
- data/spec/cql_parse_spec.rb +15 -9
- data/spec/cql_ruby_spec.rb +27 -13
- data/spec/cql_sql_spec.rb +42 -16
- data/spec/cql_symbol_tables_spec.rb +2 -3
- data/spec/cqldump_spec.rb +7 -7
- data/spec/helpers/file_matcher.rb +39 -0
- data/spec/norma_cql_spec.rb +20 -12
- data/spec/norma_ruby_spec.rb +6 -3
- data/spec/norma_sql_spec.rb +6 -3
- data/spec/norma_tables_spec.rb +6 -4
- data/spec/spec_helper.rb +27 -8
- data/status.html +69 -0
- data/why.html +60 -0
- metadata +34 -11
- data/lib/activefacts/cql/DataTypes.treetop +0 -81
- data/spec/cql_unit_spec.rb +0 -330
data/examples/local.css
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
@charset "utf-8";
|
2
|
+
|
3
|
+
.offline {
|
4
|
+
display: none;
|
5
|
+
}
|
6
|
+
|
7
|
+
.localnav {
|
8
|
+
position:fixed;
|
9
|
+
left:25px;
|
10
|
+
top:210px;
|
11
|
+
}
|
12
|
+
|
13
|
+
.hangleft {
|
14
|
+
margin-left: -220px;
|
15
|
+
}
|
16
|
+
|
17
|
+
.examples td {
|
18
|
+
vertical-align: top;
|
19
|
+
padding: 3px 5px 3px 5px;
|
20
|
+
}
|
data/index.html
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
<!--#include virtual="/header.html" -->
|
2
|
+
<!--#include virtual="navbar.html" -->
|
3
|
+
|
4
|
+
<link rel="stylesheet" href="css/offline.css" media="screen" type="text/css" />
|
5
|
+
<link rel="stylesheet" href="css/print.css" media="print" type="text/css" />
|
6
|
+
|
7
|
+
<!-- Things to show only in the online version -->
|
8
|
+
<div id="sidebar" class="online">
|
9
|
+
<h3>Quotes</h3>
|
10
|
+
<!--p><em>“epic, a masterwork”</em></p>
|
11
|
+
<p align="right">Who</p-->
|
12
|
+
|
13
|
+
<p><em>“I've long believed there must be a way to do this, but could never
|
14
|
+
work out how to start.”</em></p>
|
15
|
+
<p align="right">OSDC conference attendee</p>
|
16
|
+
|
17
|
+
<!--p><em>“Six months ago I quit my job and sold my house to fund a related
|
18
|
+
project that now seems trivial and unnecessary in comparison”</em></p>
|
19
|
+
<p align="right">OSDC conference attendee</p>
|
20
|
+
|
21
|
+
<p><em>“Epic, a major achievement. Your approach is so far ahead of the
|
22
|
+
industry it's hard to believe it possible.”</em></p>
|
23
|
+
<p align="right">Who</p-->
|
24
|
+
|
25
|
+
<p><em>“Inspirational!”</em></p>
|
26
|
+
<p align="right">Sven Dowideit</p>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<div id="top" class="content">
|
30
|
+
<h2>ActiveFacts</h2>
|
31
|
+
|
32
|
+
<!-- Things to show only in the offline version -->
|
33
|
+
<div class="localnav offline noprint">
|
34
|
+
<ul>
|
35
|
+
<li><a href="http://dataconstellation.com" title="Data Constellation Home">Data Constellation</a></li>
|
36
|
+
<li><a href="http://dataconstellation.com/ActiveFacts" title="ActiveFacts Home Page">ActiveFacts Home</a></li>
|
37
|
+
<li><a href="examples/index.html" title="Example Models">Example Models</a></li>
|
38
|
+
<li><a href="examples/intro.html" title="Introduction to ORM2">Introduction to ORM2</a></li>
|
39
|
+
<li><a href="http://dataconstellation.com/ActiveFacts/CQLIntroduction.html" title="The Constellation Query Language">Constellation Query Language</a></li>
|
40
|
+
<li><a href="status.html" title="Project Status">Project Status</a></li>
|
41
|
+
<li><a href="download.html" title="Download">Download</a></li>
|
42
|
+
<!--li><a href="resources.html" title="Resources">Resources</a></li-->
|
43
|
+
</ul>
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<p>
|
47
|
+
ActiveFacts is a <strong>semantic modeling toolkit</strong> that
|
48
|
+
revolutionises the processes of software <strong>specification</strong>,
|
49
|
+
<strong>design</strong>, and <strong>implementation</strong>. It
|
50
|
+
incorporates the Constellation Query Language (CQL) and the Constellation
|
51
|
+
API, which together enable your data to be designed, expressed and
|
52
|
+
queried in a completely natural form for the first time. The language
|
53
|
+
is so easy to learn and use because of the way it incorporates natural
|
54
|
+
language expressions into a formal framework. This allows the business
|
55
|
+
user (in conjunction with the programmer and database experts) to use
|
56
|
+
the language to express the rules and behaviour of the business domain,
|
57
|
+
in the process formulating efficient database designs without needing
|
58
|
+
specialist database skills.
|
59
|
+
|
60
|
+
<h3> Constellation Query Language </h3>
|
61
|
+
|
62
|
+
<p> CQL combines the power of a formal language with the intuitive feel
|
63
|
+
of natural language. It can be used both to define and query semantic
|
64
|
+
models. You can write CQL models directly, use APRIMO, or import ORM2
|
65
|
+
models from <a href="http://www.ormfoundation.org/files/">NORMA</a>.
|
66
|
+
</p>
|
67
|
+
|
68
|
+
<h3> Constellation API </h3>
|
69
|
+
<p> The Constellation API introduces a new way to code
|
70
|
+
transactional applications. Each user action results
|
71
|
+
in a single query, which can span deeply into and
|
72
|
+
across the whole database, returning only the data
|
73
|
+
required to respond to that action. Any required
|
74
|
+
changes are made to the result Constellation, and
|
75
|
+
a single <em>save</em> operation pushes all the
|
76
|
+
changes resulting from the user's action back into
|
77
|
+
the database in a single atomic action.
|
78
|
+
</p>
|
79
|
+
|
80
|
+
<h3> Code generators </h3>
|
81
|
+
<p> The ActiveFacts code generation framework reads CQL
|
82
|
+
and emits extensible and effective object models for
|
83
|
+
use with the Constellation API, and efficient SQL
|
84
|
+
for whatever relational database product you're using.
|
85
|
+
</p>
|
86
|
+
|
87
|
+
<h3> APRIMO </h3>
|
88
|
+
<p> APRIMO is a semantic model development environment,
|
89
|
+
incorporating a Flash-based graphical designer that
|
90
|
+
implements ORM2 diagrams, with direct CQL entry and
|
91
|
+
even reverse engineering tools for existing databases.
|
92
|
+
APRIMO is not yet publicly available.
|
93
|
+
|
94
|
+
</div>
|
95
|
+
|
96
|
+
<!--#include virtual="/footer.html" -->
|
@@ -54,27 +54,31 @@ module ActiveFacts
|
|
54
54
|
# Define a binary fact type relating this concept to another,
|
55
55
|
# with a uniqueness constraint only on this concept's role.
|
56
56
|
# This method creates two accessor methods, one in this concept and one in the other concept.
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# *
|
60
|
-
# * :mandatory - if this role may not be NULL in a valid fact population. Mandatory constraints are only enforced during validation (e.g. before saving).
|
61
|
-
# * :
|
62
|
-
|
63
|
-
|
57
|
+
# * role_name is a Symbol for the name of the role (this end of the relationship)
|
58
|
+
# Options contain optional keys:
|
59
|
+
# * :class - A class name, Symbol or String naming a class, required if it doesn't match the role_name. Use a symbol or string if the class isn't defined yet, and the methods will be created later, when the class is first defined.
|
60
|
+
# * :mandatory - if this role may not be NULL in a valid fact population, say :mandatory => true. Mandatory constraints are only enforced during validation (e.g. before saving).
|
61
|
+
# * :counterpart - use if the role at the other end should have a name other than the default :all_<concept> or :all_<concept>\_as_<role_name>
|
62
|
+
# * :reading - for verbalisation. Not used yet.
|
63
|
+
# * :restrict - a list of values or ranges which this role may take. Not used yet.
|
64
|
+
def has_one(role_name, options = {})
|
65
|
+
role_name, related, mandatory, related_role_name = extract_binary_params(false, role_name, options)
|
64
66
|
define_binary_fact_type(false, role_name, related, mandatory, related_role_name)
|
65
67
|
end
|
66
68
|
|
67
69
|
# Define a binary fact type joining this concept to another,
|
68
70
|
# with uniqueness constraints in both directions, i.e. a one-to-one relationship
|
69
71
|
# This method creates two accessor methods, one in this concept and one in the other concept.
|
70
|
-
#
|
71
|
-
#
|
72
|
-
# *
|
73
|
-
# * :mandatory - if this role may not be NULL in a valid fact population. Mandatory constraints are only enforced during validation (e.g. before saving)
|
74
|
-
# * :
|
75
|
-
|
72
|
+
# * role_name is a Symbol for the name of the role (this end of the relationship)
|
73
|
+
# Options contain optional keys:
|
74
|
+
# * :class - A class name, Symbol or String naming a class, required if it doesn't match the role_name. Use a symbol or string if the class isn't defined yet, and the methods will be created later, when the class is first defined.
|
75
|
+
# * :mandatory - if this role may not be NULL in a valid fact population, say :mandatory => true. Mandatory constraints are only enforced during validation (e.g. before saving).
|
76
|
+
# * :counterpart - use if the role at the other end should have a name other than the default :all_<concept> or :all_<concept>\_as_<role_name>
|
77
|
+
# * :reading - for verbalisation. Not used yet.
|
78
|
+
# * :restrict - a list of values or ranges which this role may take. Not used yet.
|
79
|
+
def one_to_one(role_name, options = {})
|
76
80
|
role_name, related, mandatory, related_role_name =
|
77
|
-
extract_binary_params(true,
|
81
|
+
extract_binary_params(true, role_name, options)
|
78
82
|
define_binary_fact_type(true, role_name, related, mandatory, related_role_name)
|
79
83
|
end
|
80
84
|
|
@@ -291,6 +295,16 @@ module ActiveFacts
|
|
291
295
|
|
292
296
|
# Extract the parameters to a role definition and massage them into the right shape.
|
293
297
|
#
|
298
|
+
# The first parameter, role_name, is mandatory. It may be a Symbol, a String or a Class.
|
299
|
+
# New proposed input options:
|
300
|
+
# :class => the related class (Class object or Symbol). Not allowed if role_name was a class.
|
301
|
+
# :mandatory => true. There must be a related object for this object to be valid.
|
302
|
+
# :counterpart => Symbol/String. The name of the counterpart role. Will be to_s.snakecase'd and maybe augmented with "all_" and/or "_as_<role_name>"
|
303
|
+
# :reading => "forward/reverse". Forward and reverse readings. Must include MARKERS for the player names. May include adjectives. REVISIT: define MARKERS!
|
304
|
+
# LATER:
|
305
|
+
# :order => :local_role OR lambda{} (for sort_by)
|
306
|
+
# :restriction => Range or Array of Range/value or respond_to?(include?)
|
307
|
+
#
|
294
308
|
# This function returns an array:
|
295
309
|
# [ role_name,
|
296
310
|
# related,
|
@@ -307,46 +321,34 @@ module ActiveFacts
|
|
307
321
|
# Role counterpart_concept name (not role name)
|
308
322
|
# Trailing Adjective
|
309
323
|
# "_as_<other_role_name>" if other_role_name != this role counterpart_concept's name, and not other_player_this_player
|
310
|
-
def extract_binary_params(one_to_one,
|
311
|
-
#
|
312
|
-
# role_name (Symbol)
|
324
|
+
def extract_binary_params(one_to_one, role_name, options)
|
325
|
+
# Options:
|
313
326
|
# other counterpart_concept (Symbol or Class)
|
314
327
|
# mandatory (:mandatory)
|
315
328
|
# other end role name if any (Symbol),
|
316
|
-
role_name = nil
|
317
329
|
related = nil
|
318
330
|
mandatory = false
|
319
331
|
related_role_name = nil
|
320
332
|
role_player = self.basename.snakecase
|
321
333
|
|
322
|
-
|
323
|
-
|
324
|
-
when Symbol, String
|
325
|
-
role_name = a.to_sym
|
326
|
-
when Class
|
327
|
-
role_name = a.name.snakecase.to_sym
|
328
|
-
puts "#{a.name.snakecase} -> #{role_name}"
|
329
|
-
else
|
330
|
-
raise "Illegal first parameter to role: #{a.inspect}"
|
331
|
-
end
|
332
|
-
# puts "role_name = #{role_name.inspect}"
|
334
|
+
role_name = a.name.snakecase.to_sym if Class === role_name
|
335
|
+
role_name = role_name.to_sym
|
333
336
|
|
334
337
|
# The related class might be forward-referenced, so handle a Symbol/String instead of a Class.
|
335
|
-
|
338
|
+
related_name = options.delete(:class)
|
339
|
+
case related_name
|
340
|
+
when nil
|
341
|
+
related = role_name # No :class provided, assume it matches the role_name
|
342
|
+
related_name ||= role_name.to_s
|
336
343
|
when Class
|
337
|
-
related =
|
338
|
-
related_name =
|
339
|
-
when :mandatory, Numeric
|
340
|
-
args.unshift(a) # Oops, undo.
|
341
|
-
related_name =
|
342
|
-
related = role_name
|
344
|
+
related = related_name
|
345
|
+
related_name = related_name.basename.to_s.snakecase
|
343
346
|
when Symbol, String
|
344
|
-
related =
|
347
|
+
related = related_name
|
348
|
+
related_name = related_name.to_s.snakecase
|
345
349
|
else
|
346
|
-
|
350
|
+
raise "Invalid type for :class option on :#{role_name}"
|
347
351
|
end
|
348
|
-
related_name ||= role_name
|
349
|
-
related_name = related_name.to_s.snakecase
|
350
352
|
|
351
353
|
# resolve the Symbol to a Class now if possible:
|
352
354
|
resolved = vocabulary.concept(related) rescue nil
|
@@ -354,16 +356,16 @@ module ActiveFacts
|
|
354
356
|
related = resolved if resolved
|
355
357
|
# puts "related = #{related.inspect}"
|
356
358
|
|
357
|
-
if
|
359
|
+
if options.delete(:mandatory) == true
|
358
360
|
mandatory = true
|
359
|
-
args.shift
|
360
361
|
end
|
361
362
|
|
362
|
-
if
|
363
|
-
|
364
|
-
|
363
|
+
related_role_name = related_role_name.to_s if related_role_name = options.delete(:counterpart)
|
364
|
+
|
365
|
+
reading = options.delete(:reading) # REVISIT: Implement verbalisation
|
366
|
+
restriction = options.delete(:restrict) # REVISIT: Implement role value restrictions
|
365
367
|
|
366
|
-
|
368
|
+
raise "Unrecognised options on #{role_name}: #{options.keys.inspect}" unless options.empty?
|
367
369
|
|
368
370
|
# Avoid a confusing mismatch:
|
369
371
|
# Note that if you have a role "supervisor" and a sub-class "Supervisor", this'll bitch.
|
@@ -20,10 +20,11 @@ module ActiveFacts
|
|
20
20
|
# As a result, you cannot "create" an object in a constellation - you merely _assert_
|
21
21
|
# its existence. This is done using method_missing; @constellation.Thing(3) creates
|
22
22
|
# an instance (or returns the existing instance) of Thing identified by the value 3.
|
23
|
+
# You can also use the populate() method to apply a block of assertions.
|
23
24
|
#
|
24
|
-
# You can ##
|
25
|
-
# it from the database when the constellation is saved), and nullifies any
|
26
|
-
# to it.
|
25
|
+
# You can instance##deny any instance, and that removes it from the constellation (will
|
26
|
+
# delete it from the database when the constellation is saved), and nullifies any
|
27
|
+
# references to it.
|
27
28
|
#
|
28
29
|
# A Constellation may or not be valid according to the vocabulary's constraints,
|
29
30
|
# but it may also represent a portion of a larger population (a database) with
|
@@ -39,34 +40,26 @@ module ActiveFacts
|
|
39
40
|
# Create a new empty Constellation over the given Vocabulary
|
40
41
|
def initialize(vocabulary)
|
41
42
|
@vocabulary = vocabulary
|
42
|
-
@instances = Hash.new
|
43
|
+
@instances = Hash.new do |h,k|
|
44
|
+
raise "A constellation over #{@vocabulary.name} can only index instances of concepts in that vocabulary, not #{k.inspect}" unless k.is_a?(Class) and k.modspace == vocabulary
|
45
|
+
h[k] = InstanceIndex.new
|
46
|
+
end
|
43
47
|
end
|
44
48
|
|
45
49
|
def inspect #:nodoc:
|
46
50
|
"Constellation:#{object_id}"
|
47
51
|
end
|
48
52
|
|
49
|
-
#
|
50
|
-
def
|
51
|
-
# REVISIT:
|
52
|
-
(
|
53
|
-
@instances[klass].delete_if{|k,v| v == instance }
|
54
|
-
end
|
53
|
+
# Evaluate assertions against the population of this Constellation
|
54
|
+
def populate *args, &block
|
55
|
+
# REVISIT: Use args for something? Like options to enable/disable validation?
|
56
|
+
instance_eval(&block)
|
55
57
|
end
|
56
58
|
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
if args.size == 0
|
62
|
-
# Return the collection of all instances of this class in the constellation:
|
63
|
-
@instances[klass]
|
64
|
-
else
|
65
|
-
# Assert a new ground fact (concept instance) of the specified class, identified by args:
|
66
|
-
# REVISIT: create a constructor method here instead?
|
67
|
-
instance, key = klass.assert_instance(self, args)
|
68
|
-
instance
|
69
|
-
end
|
59
|
+
# Delete instances from the constellation, nullifying (or cascading) the roles each plays
|
60
|
+
def deny(*instances)
|
61
|
+
Array(instances).each do |i|
|
62
|
+
i.deny
|
70
63
|
end
|
71
64
|
end
|
72
65
|
|
@@ -103,6 +96,33 @@ module ActiveFacts
|
|
103
96
|
} * "\n"
|
104
97
|
}.compact*"\n"
|
105
98
|
end
|
99
|
+
|
100
|
+
# This method removes the given instance from this constellation's indexes
|
101
|
+
# It must be called before the identifying roles get deleted or nullified.
|
102
|
+
def __deny(instance) #:nodoc:
|
103
|
+
# REVISIT: Need to search, as key values are gone already. Is there a faster way?
|
104
|
+
([instance.class]+instance.class.supertypes_transitive).each do |klass|
|
105
|
+
@instances[klass].delete_if{|k,v| v == instance }
|
106
|
+
end
|
107
|
+
# REVISIT: Need to nullify all the roles this object plays.
|
108
|
+
# If mandatory on the counterpart side, this may/must propagate the delete (without mutual recursion!)
|
109
|
+
end
|
110
|
+
|
111
|
+
# With parameters, assert an instance of the concept whose name is the missing method, identified by the values passed as *args*.
|
112
|
+
# With no parameters, return the collection of all instances of that concept.
|
113
|
+
def method_missing(m, *args)
|
114
|
+
if klass = @vocabulary.const_get(m)
|
115
|
+
if args.size == 0
|
116
|
+
# Return the collection of all instances of this class in the constellation:
|
117
|
+
@instances[klass]
|
118
|
+
else
|
119
|
+
# Assert a new ground fact (concept instance) of the specified class, identified by args:
|
120
|
+
# REVISIT: create a constructor method here instead?
|
121
|
+
instance, key = klass.assert_instance(self, args)
|
122
|
+
instance
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
106
126
|
end
|
107
127
|
end
|
108
128
|
end
|
@@ -231,7 +231,7 @@ module ActiveFacts
|
|
231
231
|
other.identified_by *identifying_role_names
|
232
232
|
subtypes << other unless subtypes.include? other
|
233
233
|
#puts "#{self.name} inherited by #{other.name}"
|
234
|
-
vocabulary.
|
234
|
+
vocabulary.__add_concept(other)
|
235
235
|
end
|
236
236
|
|
237
237
|
# verbalise this concept
|
@@ -249,7 +249,7 @@ module ActiveFacts
|
|
249
249
|
unless vocabulary.respond_to? :concept # Extend module with Vocabulary if necessary
|
250
250
|
vocabulary.send :extend, Vocabulary
|
251
251
|
end
|
252
|
-
vocabulary.
|
252
|
+
vocabulary.__add_concept(other)
|
253
253
|
end
|
254
254
|
end
|
255
255
|
end
|
@@ -28,9 +28,9 @@ module ActiveFacts
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# De-assign all functional roles and remove from constellation, if any.
|
31
|
-
def
|
31
|
+
def deny
|
32
32
|
# Delete from the constellation first, so it can remember our identifying role values
|
33
|
-
@constellation.
|
33
|
+
@constellation.__deny(self) if @constellation
|
34
34
|
|
35
35
|
# Now, for all roles (from this class and all supertypes), assign nil to all functional roles
|
36
36
|
# The counterpart roles get cleared automatically.
|
@@ -38,6 +38,10 @@ module ActiveFacts
|
|
38
38
|
klass.roles.each do |role_name, role|
|
39
39
|
next if role.unary?
|
40
40
|
next if !role.unique
|
41
|
+
|
42
|
+
counterpart = role.counterpart
|
43
|
+
puts "Nullifying mandatory role #{role.name} of #{role.owner.name}" if counterpart.mandatory
|
44
|
+
|
41
45
|
send "#{role.name}=", nil
|
42
46
|
end
|
43
47
|
end
|
@@ -52,6 +52,12 @@ module ActiveFacts
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
class_eval do
|
56
|
+
define_method :restrict do |*value_ranges|
|
57
|
+
@value_ranges = *value_ranges
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
55
61
|
# verbalise this ValueType
|
56
62
|
def verbalise
|
57
63
|
# REVISIT: Add length and scale here, if set
|
@@ -106,7 +112,7 @@ module ActiveFacts
|
|
106
112
|
#puts "REVISIT: ValueType #{self} < #{self.superclass} was inherited by #{other}; not implemented" #+"from #{caller*"\n\t"}"
|
107
113
|
# Copy the type parameters here, etc?
|
108
114
|
other.send :realise_supertypes, self
|
109
|
-
vocabulary.
|
115
|
+
vocabulary.__add_concept(other)
|
110
116
|
super
|
111
117
|
end
|
112
118
|
end
|
@@ -122,7 +128,7 @@ module ActiveFacts
|
|
122
128
|
unless vocabulary.respond_to? :concept # Extend module with Vocabulary if necessary
|
123
129
|
vocabulary.send :extend, Vocabulary
|
124
130
|
end
|
125
|
-
vocabulary.
|
131
|
+
vocabulary.__add_concept(other)
|
126
132
|
end
|
127
133
|
end
|
128
134
|
end
|
@@ -31,7 +31,21 @@ module ActiveFacts
|
|
31
31
|
return (const_get("#{name}::#{camel}") rescue nil)
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
# Create a new constellation over this vocabulary
|
35
|
+
def constellation
|
36
|
+
Constellation.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def verbalise
|
40
|
+
"Vocabulary #{name}:\n\t" +
|
41
|
+
@concept.keys.sort.map{|concept|
|
42
|
+
c = @concept[concept]
|
43
|
+
__bind(c.basename)
|
44
|
+
c.verbalise + "\n\t\t// Roles played: " + c.roles.verbalise
|
45
|
+
}*"\n\t"
|
46
|
+
end
|
47
|
+
|
48
|
+
def __add_concept(klass) #:nodoc:
|
35
49
|
name = klass.basename
|
36
50
|
__bind(name)
|
37
51
|
# puts "Adding concept #{name} to #{self.name}"
|
@@ -59,15 +73,6 @@ module ActiveFacts
|
|
59
73
|
end
|
60
74
|
end
|
61
75
|
|
62
|
-
def verbalise
|
63
|
-
"Vocabulary #{name}:\n\t" +
|
64
|
-
@concept.keys.sort.map{|concept|
|
65
|
-
c = @concept[concept]
|
66
|
-
__bind(c.basename)
|
67
|
-
c.verbalise + "\n\t\t// Roles played: " + c.roles.verbalise
|
68
|
-
}*"\n\t"
|
69
|
-
end
|
70
|
-
|
71
76
|
end
|
72
77
|
end
|
73
78
|
end
|