activefacts 0.6.0
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/History.txt +4 -0
- data/Manifest.txt +83 -0
- data/README.rdoc +81 -0
- data/Rakefile +41 -0
- data/bin/afgen +46 -0
- data/bin/cql +52 -0
- data/examples/CQL/Address.cql +46 -0
- data/examples/CQL/Blog.cql +54 -0
- data/examples/CQL/CompanyDirectorEmployee.cql +51 -0
- data/examples/CQL/Death.cql +16 -0
- data/examples/CQL/Genealogy.cql +95 -0
- data/examples/CQL/Marriage.cql +18 -0
- data/examples/CQL/Metamodel.cql +238 -0
- data/examples/CQL/MultiInheritance.cql +19 -0
- data/examples/CQL/OilSupply.cql +47 -0
- data/examples/CQL/Orienteering.cql +108 -0
- data/examples/CQL/PersonPlaysGame.cql +17 -0
- data/examples/CQL/SchoolActivities.cql +31 -0
- data/examples/CQL/SimplestUnary.cql +12 -0
- data/examples/CQL/SubtypePI.cql +32 -0
- data/examples/CQL/Warehousing.cql +99 -0
- data/examples/CQL/WindowInRoomInBldg.cql +22 -0
- data/lib/activefacts.rb +10 -0
- data/lib/activefacts/api.rb +25 -0
- data/lib/activefacts/api/concept.rb +384 -0
- data/lib/activefacts/api/constellation.rb +106 -0
- data/lib/activefacts/api/entity.rb +239 -0
- data/lib/activefacts/api/instance.rb +54 -0
- data/lib/activefacts/api/numeric.rb +158 -0
- data/lib/activefacts/api/role.rb +94 -0
- data/lib/activefacts/api/standard_types.rb +67 -0
- data/lib/activefacts/api/support.rb +59 -0
- data/lib/activefacts/api/value.rb +122 -0
- data/lib/activefacts/api/vocabulary.rb +120 -0
- data/lib/activefacts/cql.rb +31 -0
- data/lib/activefacts/cql/CQLParser.treetop +104 -0
- data/lib/activefacts/cql/Concepts.treetop +112 -0
- data/lib/activefacts/cql/DataTypes.treetop +66 -0
- data/lib/activefacts/cql/Expressions.treetop +113 -0
- data/lib/activefacts/cql/FactTypes.treetop +185 -0
- data/lib/activefacts/cql/Language/English.treetop +92 -0
- data/lib/activefacts/cql/LexicalRules.treetop +169 -0
- data/lib/activefacts/cql/Rakefile +6 -0
- data/lib/activefacts/cql/parser.rb +88 -0
- data/lib/activefacts/generate/absorption.rb +87 -0
- data/lib/activefacts/generate/cql.rb +441 -0
- data/lib/activefacts/generate/cql/html.rb +397 -0
- data/lib/activefacts/generate/null.rb +19 -0
- data/lib/activefacts/generate/ordered.rb +557 -0
- data/lib/activefacts/generate/ruby.rb +326 -0
- data/lib/activefacts/generate/sql/server.rb +164 -0
- data/lib/activefacts/generate/text.rb +21 -0
- data/lib/activefacts/input/cql.rb +1268 -0
- data/lib/activefacts/input/orm.rb +926 -0
- data/lib/activefacts/persistence.rb +1 -0
- data/lib/activefacts/persistence/composition.rb +653 -0
- data/lib/activefacts/support.rb +51 -0
- data/lib/activefacts/version.rb +3 -0
- data/lib/activefacts/vocabulary.rb +6 -0
- data/lib/activefacts/vocabulary/extensions.rb +343 -0
- data/lib/activefacts/vocabulary/metamodel.rb +303 -0
- data/script/txt2html +71 -0
- data/spec/absorption_spec.rb +95 -0
- data/spec/api/autocounter.rb +82 -0
- data/spec/api/constellation.rb +130 -0
- data/spec/api/entity_type.rb +101 -0
- data/spec/api/instance.rb +428 -0
- data/spec/api/roles.rb +122 -0
- data/spec/api/value_type.rb +112 -0
- data/spec/api_spec.rb +14 -0
- data/spec/cql_cql_spec.rb +58 -0
- data/spec/cql_parse_spec.rb +31 -0
- data/spec/cql_ruby_spec.rb +60 -0
- data/spec/cql_sql_spec.rb +54 -0
- data/spec/cql_symbol_tables_spec.rb +259 -0
- data/spec/cql_unit_spec.rb +336 -0
- data/spec/cqldump_spec.rb +169 -0
- data/spec/norma_cql_spec.rb +48 -0
- data/spec/norma_ruby_spec.rb +50 -0
- data/spec/norma_sql_spec.rb +45 -0
- data/spec/norma_tables_spec.rb +94 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +173 -0
data/script/txt2html
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
load File.dirname(__FILE__) + "/../Rakefile"
|
4
|
+
require 'rubyforge'
|
5
|
+
require 'redcloth'
|
6
|
+
require 'syntax/convertors/html'
|
7
|
+
require 'erb'
|
8
|
+
|
9
|
+
download = "http://rubyforge.org/projects/#{$hoe.rubyforge_name}"
|
10
|
+
version = $hoe.version
|
11
|
+
|
12
|
+
def rubyforge_project_id
|
13
|
+
RubyForge.new.configure.autoconfig["group_ids"][$hoe.rubyforge_name]
|
14
|
+
end
|
15
|
+
|
16
|
+
class Fixnum
|
17
|
+
def ordinal
|
18
|
+
# teens
|
19
|
+
return 'th' if (10..19).include?(self % 100)
|
20
|
+
# others
|
21
|
+
case self % 10
|
22
|
+
when 1: return 'st'
|
23
|
+
when 2: return 'nd'
|
24
|
+
when 3: return 'rd'
|
25
|
+
else return 'th'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Time
|
31
|
+
def pretty
|
32
|
+
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def convert_syntax(syntax, source)
|
37
|
+
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
38
|
+
end
|
39
|
+
|
40
|
+
if ARGV.length >= 1
|
41
|
+
src, template = ARGV
|
42
|
+
template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb')
|
43
|
+
else
|
44
|
+
puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html")
|
45
|
+
exit!
|
46
|
+
end
|
47
|
+
|
48
|
+
template = ERB.new(File.open(template).read)
|
49
|
+
|
50
|
+
title = nil
|
51
|
+
body = nil
|
52
|
+
File.open(src) do |fsrc|
|
53
|
+
title_text = fsrc.readline
|
54
|
+
body_text_template = fsrc.read
|
55
|
+
body_text = ERB.new(body_text_template).result(binding)
|
56
|
+
syntax_items = []
|
57
|
+
body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
|
58
|
+
ident = syntax_items.length
|
59
|
+
element, syntax, source = $1, $2, $3
|
60
|
+
syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
|
61
|
+
"syntax-temp-#{ident}"
|
62
|
+
}
|
63
|
+
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
64
|
+
body = RedCloth.new(body_text).to_html
|
65
|
+
body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
|
66
|
+
end
|
67
|
+
stat = File.stat(src)
|
68
|
+
created = stat.ctime
|
69
|
+
modified = stat.mtime
|
70
|
+
|
71
|
+
$stdout << template.result(binding)
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts tests: Test the relational absorption by compiling CQL fragments.
|
3
|
+
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
5
|
+
require 'rubygems'
|
6
|
+
require 'treetop'
|
7
|
+
require 'activefacts/support'
|
8
|
+
require 'activefacts/api/support'
|
9
|
+
require 'activefacts/input/cql'
|
10
|
+
require 'activefacts/persistence'
|
11
|
+
|
12
|
+
describe "Absorption" do
|
13
|
+
Prologue = %Q{
|
14
|
+
vocabulary Test;
|
15
|
+
DateTime is defined as DateAndTime();
|
16
|
+
Month is defined as VariableLengthText(3);
|
17
|
+
Season is defined as VariableLengthText(6);
|
18
|
+
PartyID is defined as AutoCounter();
|
19
|
+
ClaimID is defined as AutoCounter();
|
20
|
+
}
|
21
|
+
Claim = %Q{
|
22
|
+
Claim is identified by ClaimID where
|
23
|
+
Claim has exactly one ClaimID,
|
24
|
+
ClaimID is of at most one Claim;
|
25
|
+
}
|
26
|
+
Incident = %Q{
|
27
|
+
Incident is identified by Claim where
|
28
|
+
Claim concerns at most one Incident,
|
29
|
+
Incident is of exactly one Claim;
|
30
|
+
}
|
31
|
+
Party = %Q{
|
32
|
+
Party is identified by PartyID where
|
33
|
+
Party has exactly one PartyID,
|
34
|
+
PartyID is of at most one Party;
|
35
|
+
}
|
36
|
+
Person = %Q{
|
37
|
+
Person is a kind of Party;
|
38
|
+
}
|
39
|
+
|
40
|
+
Tests = [
|
41
|
+
{ :should => "inject a value column into the table for an independent ValueType",
|
42
|
+
:cql => %Q{
|
43
|
+
#{Prologue}
|
44
|
+
Month is in exactly one Season;
|
45
|
+
},
|
46
|
+
:tables => { "Month" => [ %w{Month Value}, "Season" ] }
|
47
|
+
},
|
48
|
+
|
49
|
+
{ :should => "absorb a one-to-one along the identification path",
|
50
|
+
:cql => %Q{
|
51
|
+
#{Prologue} #{Claim} #{Incident}
|
52
|
+
Incident relates to loss on exactly one DateTime;
|
53
|
+
},
|
54
|
+
:tables => { "Claim" => ["ClaimID", %w{Incident DateTime}]}
|
55
|
+
},
|
56
|
+
|
57
|
+
{ :should => "absorb an objectified binary with single-role UC",
|
58
|
+
:cql => %Q{
|
59
|
+
#{Prologue} #{Claim} #{Party} #{Person}
|
60
|
+
Lodgement is where
|
61
|
+
Claim was lodged by at most one Person;
|
62
|
+
Lodgement was made at at most one DateTime;
|
63
|
+
Person has exactly one birth-Date;
|
64
|
+
},
|
65
|
+
:tables => {
|
66
|
+
"Claim" => ["ClaimID", %w{Lodgement DateTime}, %w{Lodgement Person ID}],
|
67
|
+
"Party" => ["PartyID", %w{Person birth Date}]
|
68
|
+
}
|
69
|
+
},
|
70
|
+
|
71
|
+
]
|
72
|
+
|
73
|
+
setup do
|
74
|
+
end
|
75
|
+
|
76
|
+
Tests.each do |test|
|
77
|
+
should = test[:should]
|
78
|
+
cql = test[:cql]
|
79
|
+
expected_tables = test[:tables]
|
80
|
+
it "should #{should}" do
|
81
|
+
@compiler = ActiveFacts::Input::CQL.new(cql, should)
|
82
|
+
@vocabulary = @compiler.read
|
83
|
+
|
84
|
+
# Ensure that the same tables were generated:
|
85
|
+
tables = @vocabulary.tables
|
86
|
+
tables.map(&:name).sort.should == expected_tables.keys.sort
|
87
|
+
|
88
|
+
# Ensure that the same column descriptions were generated:
|
89
|
+
tables.sort_by(&:name).each do |table|
|
90
|
+
column_descriptions = table.absorbed_roles.all_role_ref.map{|rr| rr.column_name(nil) }.sort
|
91
|
+
column_descriptions.should == expected_tables[table.name].map{|c| Array(c) }.sort
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,82 @@
|
|
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
|
+
setup 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 allow its roles to be assigned" do
|
53
|
+
lambda {
|
54
|
+
@thing.thing_id = @thing_id
|
55
|
+
}.should_not 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
|
@@ -0,0 +1,130 @@
|
|
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
|
+
setup 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, :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
|
@@ -0,0 +1,101 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts tests: Entity classes in the Runtime API
|
3
|
+
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
5
|
+
describe "Entity Type class definitions" do
|
6
|
+
setup do
|
7
|
+
Object.send :remove_const, :Mod if Object.const_defined?("Mod")
|
8
|
+
module Mod
|
9
|
+
class Name < String
|
10
|
+
value_type
|
11
|
+
end
|
12
|
+
class LegalEntity
|
13
|
+
end
|
14
|
+
class Person < LegalEntity
|
15
|
+
identified_by :name
|
16
|
+
has_one :name, Name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should respond_to verbalise" do
|
22
|
+
Mod::Person.respond_to?(:verbalise).should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should not pollute the superclass" do
|
26
|
+
Mod::LegalEntity.respond_to?(:verbalise).should_not be_true
|
27
|
+
Class.respond_to?(:verbalise).should_not be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return a string from verbalise" do
|
31
|
+
v = Mod::Person.verbalise
|
32
|
+
v.should_not be_nil
|
33
|
+
v.should_not =~ /REVISIT/
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should respond_to vocabulary" do
|
37
|
+
Mod::Person.respond_to?(:vocabulary).should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return the parent module as the vocabulary" do
|
41
|
+
vocabulary = Mod::Person.vocabulary
|
42
|
+
vocabulary.should == Mod
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return a vocabulary that knows about this concept" do
|
46
|
+
vocabulary = Mod::Person.vocabulary
|
47
|
+
vocabulary.respond_to?(:concept).should be_true
|
48
|
+
vocabulary.concept.has_key?("Person").should be_true
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should respond to roles()" do
|
52
|
+
Mod::Person.respond_to?(:roles).should be_true
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should contain only the added role definition" do
|
56
|
+
Mod::Person.roles.size.should == 1
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should return the role definition" do
|
60
|
+
# Check the role definition may be accessed by passing an index:
|
61
|
+
Mod::Person.roles(0).should be_nil
|
62
|
+
|
63
|
+
role = Mod::Person.roles(:name)
|
64
|
+
role.should_not be_nil
|
65
|
+
|
66
|
+
role = Mod::Person.roles("name")
|
67
|
+
role.should_not be_nil
|
68
|
+
|
69
|
+
# Check the role definition may be accessed by indexing the returned hash:
|
70
|
+
role = Mod::Person.roles[:name]
|
71
|
+
role.should_not be_nil
|
72
|
+
|
73
|
+
# Check the role definition array by .include?
|
74
|
+
Mod::Person.roles.include?(:name).should be_true
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should fail on a ValueClass" do
|
78
|
+
lambda{
|
79
|
+
class SomeClass < String
|
80
|
+
identified_by
|
81
|
+
end
|
82
|
+
}.should raise_error
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return the identifying roles" do
|
86
|
+
Mod::Person.identifying_roles.should == [:name]
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should prevent a role name from matching a concept that exists unless that concept is the player" do
|
90
|
+
lambda {
|
91
|
+
module Mod
|
92
|
+
class LegalEntity
|
93
|
+
end
|
94
|
+
class Bad
|
95
|
+
identified_by :name
|
96
|
+
has_one :name, LegalEntity
|
97
|
+
end
|
98
|
+
end
|
99
|
+
}.should raise_error
|
100
|
+
end
|
101
|
+
end
|