activefacts-api 0.8.12 → 0.9.1

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.
Files changed (36) hide show
  1. data/.rspec +1 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +14 -0
  4. data/Rakefile +21 -9
  5. data/VERSION +1 -1
  6. data/activefacts-api.gemspec +31 -12
  7. data/lib/activefacts/api.rb +1 -0
  8. data/lib/activefacts/api/constellation.rb +3 -1
  9. data/lib/activefacts/api/entity.rb +74 -29
  10. data/lib/activefacts/api/exceptions.rb +17 -0
  11. data/lib/activefacts/api/instance.rb +96 -1
  12. data/lib/activefacts/api/instance_index.rb +35 -37
  13. data/lib/activefacts/api/numeric.rb +62 -56
  14. data/lib/activefacts/api/object_type.rb +49 -23
  15. data/lib/activefacts/api/role.rb +8 -2
  16. data/lib/activefacts/api/role_values.rb +8 -26
  17. data/lib/activefacts/api/standard_types.rb +2 -17
  18. data/lib/activefacts/api/vocabulary.rb +1 -1
  19. data/lib/activefacts/tracer.rb +13 -1
  20. data/spec/{constellation_spec.rb → constellation/constellation_spec.rb} +127 -56
  21. data/spec/constellation/instance_index_spec.rb +90 -0
  22. data/spec/{instance_spec.rb → constellation/instance_spec.rb} +48 -42
  23. data/spec/{role_values_spec.rb → fact_type/role_values_spec.rb} +28 -19
  24. data/spec/{roles_spec.rb → fact_type/roles_spec.rb} +55 -21
  25. data/spec/fixtures/tax.rb +45 -0
  26. data/spec/{identification_spec.rb → identification_scheme/identification_spec.rb} +88 -74
  27. data/spec/identification_scheme/identity_change_spec.rb +118 -0
  28. data/spec/identification_scheme/identity_supertype_change_spec.rb +63 -0
  29. data/spec/{entity_type_spec.rb → object_type/entity_type/entity_type_spec.rb} +2 -4
  30. data/spec/object_type/entity_type/multipart_identification_spec.rb +77 -0
  31. data/spec/{autocounter_spec.rb → object_type/value_type/autocounter_spec.rb} +2 -4
  32. data/spec/object_type/value_type/numeric_spec.rb +63 -0
  33. data/spec/{value_type_spec.rb → object_type/value_type/value_type_spec.rb} +10 -14
  34. data/spec/simplecov_helper.rb +8 -0
  35. data/spec/spec_helper.rb +1 -1
  36. metadata +100 -19
@@ -2,8 +2,6 @@
2
2
  # ActiveFacts tests: Value instances in the Runtime API
3
3
  # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
4
  #
5
- require 'rspec'
6
- require 'activefacts/api'
7
5
 
8
6
  describe "An instance of every type of ObjectType" do
9
7
  before :each do
@@ -19,20 +17,20 @@ describe "An instance of every type of ObjectType" do
19
17
  t.name.snakecase
20
18
  end
21
19
  @role_names = @base_type_roles.inject([]) {|a, t|
22
- a << :"#{t}_value"
20
+ a << :"#{t}_val"
23
21
  } +
24
22
  @base_type_roles.inject([]) {|a, t|
25
- a << :"#{t}_sub_value"
23
+ a << :"#{t}_sub_val"
26
24
  }
27
25
 
28
26
  # Create a value type and a subtype of that value type for each base type:
29
27
  @base_types.each do |base_type|
30
- eval <<-END
31
- class #{base_type.name}Value < #{base_type.name}
28
+ Mod.module_eval <<-END
29
+ class #{base_type.name}Val < #{base_type.name}
32
30
  value_type
33
31
  end
34
32
 
35
- class #{base_type.name}SubValue < #{base_type.name}Value
33
+ class #{base_type.name}SubVal < #{base_type.name}Val
36
34
  # Note no new "value_type" is required here, it comes through inheritance
37
35
  end
38
36
  END
@@ -44,11 +42,11 @@ describe "An instance of every type of ObjectType" do
44
42
  @base_types.each do |base_type|
45
43
  code = <<-END
46
44
  class TestBy#{base_type.name}
47
- identified_by :#{base_type.name.snakecase}_value#{
45
+ identified_by :#{base_type.name.snakecase}_val#{
48
46
  @role_names.map do |role_name|
49
47
  %Q{
50
- has_one :#{role_name}#{
51
- mandatory = (role_name == (base_type.name.snakecase+'_value').to_sym ? ', :mandatory => true' : '')
48
+ #{
49
+ (role_name == (base_type.name.snakecase+'_val').to_sym ? "one_to_one :#{role_name}, :mandatory => true" : "has_one :#{role_name}")
52
50
  }
53
51
  one_to_one :one_#{role_name}, :class => #{role_name.to_s.camelcase}}
54
52
  end*""
@@ -56,10 +54,12 @@ describe "An instance of every type of ObjectType" do
56
54
  end
57
55
 
58
56
  class TestBy#{base_type.name}Sub
59
- identified_by :#{base_type.name.snakecase}_sub_value#{
57
+ identified_by :#{base_type.name.snakecase}_sub_val#{
60
58
  @role_names.map do |role_name|
61
59
  %Q{
62
- has_one :#{role_name}
60
+ #{
61
+ (role_name == (base_type.name.snakecase+'_sub_val').to_sym ? "one_to_one :#{role_name}" : "has_one :#{role_name}")
62
+ }
63
63
  one_to_one :one_#{role_name}, :class => #{role_name.to_s.camelcase}}
64
64
  end*""
65
65
  }
@@ -74,7 +74,7 @@ describe "An instance of every type of ObjectType" do
74
74
  one_to_one :test_by_#{base_type.name.snakecase}
75
75
  end
76
76
  END
77
- eval code
77
+ Mod.module_eval code
78
78
  end
79
79
  end
80
80
 
@@ -89,29 +89,29 @@ describe "An instance of every type of ObjectType" do
89
89
  @decimal = BigDecimal.new('98765432109876543210')
90
90
 
91
91
  # Value Type instances
92
- @int_value = Mod::IntValue.new(1)
93
- @real_value = Mod::RealValue.new(1.0)
94
- @auto_counter_value = Mod::AutoCounterValue.new(1)
95
- @new_auto_counter_value = Mod::AutoCounterValue.new(:new)
96
- @string_value = Mod::StringValue.new("one")
97
- @date_value = Mod::DateValue.new(2008, 04, 20)
92
+ @int_value = Mod::IntVal.new(1)
93
+ @real_value = Mod::RealVal.new(1.0)
94
+ @auto_counter_value = Mod::AutoCounterVal.new(1)
95
+ @new_auto_counter_value = Mod::AutoCounterVal.new(:new)
96
+ @string_value = Mod::StringVal.new("one")
97
+ @date_value = Mod::DateVal.new(2008, 04, 20)
98
98
  # Parse the date:
99
- @date_value = Mod::DateValue.new '2nd Nov 2001'
99
+ @date_value = Mod::DateVal.new '2nd Nov 2001'
100
100
  d = ::Date.civil(2008, 04, 20)
101
- @date_time_value = Mod::DateTimeValue.new d # 2008, 04, 20, 10, 28, 14
101
+ @date_time_value = Mod::DateTimeVal.new d # 2008, 04, 20, 10, 28, 14
102
102
  # This next isn't in the same pattern; it makes a Decimal from a BigDecimal rather than a String (coverage reasons)
103
- @decimal_value = Mod::DecimalValue.new(BigDecimal.new('98765432109876543210'))
103
+ @decimal_value = Mod::DecimalVal.new(BigDecimal.new('98765432109876543210'))
104
104
 
105
105
  # Value SubType instances
106
- @int_sub_value = Mod::IntSubValue.new(4)
107
- @real_sub_value = Mod::RealSubValue.new(4.0)
108
- @auto_counter_sub_value = Mod::AutoCounterSubValue.new(4)
109
- @auto_counter_sub_value_new = Mod::AutoCounterSubValue.new(:new)
110
- @string_sub_value = Mod::StringSubValue.new("five")
111
- @date_sub_value = Mod::DateSubValue.new(2008, 04, 25)
112
- @date_time_sub_value = Mod::DateTimeSubValue.new(::DateTime.civil(2008, 04, 26, 10, 28, 14))
106
+ @int_sub_value = Mod::IntSubVal.new(4)
107
+ @real_sub_value = Mod::RealSubVal.new(4.0)
108
+ @auto_counter_sub_value = Mod::AutoCounterSubVal.new(4)
109
+ @auto_counter_sub_value_new = Mod::AutoCounterSubVal.new(:new)
110
+ @string_sub_value = Mod::StringSubVal.new("five")
111
+ @date_sub_value = Mod::DateSubVal.new(2008, 04, 25)
112
+ @date_time_sub_value = Mod::DateTimeSubVal.new(::DateTime.civil(2008, 04, 26, 10, 28, 14))
113
113
  # This next isn't in the same pattern; it makes a Decimal from a BigNum rather than a String (coverage reasons)
114
- @decimal_sub_value = Mod::DecimalSubValue.new(98765432109876543210)
114
+ @decimal_sub_value = Mod::DecimalSubVal.new(98765432109876543210)
115
115
 
116
116
  # Entities identified by Value Type, SubType and Entity-by-value-type instances
117
117
  @test_by_int = Mod::TestByInt.new(2)
@@ -164,10 +164,10 @@ describe "An instance of every type of ObjectType" do
164
164
  String, Date, DateTime, Decimal
165
165
  ]
166
166
  @value_types = [
167
- Mod::IntValue, Mod::RealValue, Mod::AutoCounterValue, Mod::AutoCounterValue,
168
- Mod::StringValue, Mod::DateValue, Mod::DateTimeValue, Mod::DecimalValue,
169
- Mod::IntSubValue, Mod::RealSubValue, Mod::AutoCounterSubValue, Mod::AutoCounterSubValue,
170
- Mod::StringSubValue, Mod::DateSubValue, Mod::DateTimeSubValue, Mod::DecimalSubValue,
167
+ Mod::IntVal, Mod::RealVal, Mod::AutoCounterVal, Mod::AutoCounterVal,
168
+ Mod::StringVal, Mod::DateVal, Mod::DateTimeVal, Mod::DecimalVal,
169
+ Mod::IntSubVal, Mod::RealSubVal, Mod::AutoCounterSubVal, Mod::AutoCounterSubVal,
170
+ Mod::StringSubVal, Mod::DateSubVal, Mod::DateTimeSubVal, Mod::DecimalSubVal,
171
171
  ]
172
172
  @value_instances = [
173
173
  @int_value, @real_value, @auto_counter_value, @new_auto_counter_value,
@@ -226,11 +226,11 @@ describe "An instance of every type of ObjectType" do
226
226
  '98765432109876543211'
227
227
  ]
228
228
  @subtype_role_instances = [
229
- Mod::IntSubValue.new(6), Mod::RealSubValue.new(6.0),
230
- Mod::AutoCounterSubValue.new(:new), Mod::AutoCounterSubValue.new(8),
231
- Mod::StringSubValue.new("seven"),
232
- Mod::DateSubValue.new(2008,4,29), Mod::DateTimeSubValue.new(2008,4,30,10,28,16),
233
- Mod::DecimalSubValue.new('98765432109876543210'),
229
+ Mod::IntSubVal.new(6), Mod::RealSubVal.new(6.0),
230
+ Mod::AutoCounterSubVal.new(:new), Mod::AutoCounterSubVal.new(8),
231
+ Mod::StringSubVal.new("seven"),
232
+ Mod::DateSubVal.new(2008,4,29), Mod::DateTimeSubVal.new(2008,4,30,10,28,16),
233
+ Mod::DecimalSubVal.new('98765432109876543210'),
234
234
  ]
235
235
  end
236
236
 
@@ -308,7 +308,7 @@ describe "An instance of every type of ObjectType" do
308
308
 
309
309
  it "should disallow treating an unresolved AutoCounter as an integer" do
310
310
  c = ActiveFacts::API::Constellation.new(Mod)
311
- a = c.AutoCounterValue(:new)
311
+ a = c.AutoCounterVal(:new)
312
312
  lambda {
313
313
  b = 2 + a
314
314
  }.should raise_error
@@ -322,7 +322,7 @@ describe "An instance of every type of ObjectType" do
322
322
  it "should complain when not enough identifying values are provided for an entity" do
323
323
  c = ActiveFacts::API::Constellation.new(Mod)
324
324
  lambda {
325
- c.TestByInt(:int_value => nil)
325
+ c.TestByInt(:int_val => nil)
326
326
  }.should raise_error
327
327
  end
328
328
 
@@ -333,6 +333,13 @@ describe "An instance of every type of ObjectType" do
333
333
  }.should raise_error
334
334
  end
335
335
 
336
+ it "should complain when wrong type is used for an entity" do
337
+ c = ActiveFacts::API::Constellation.new(Mod)
338
+ lambda {
339
+ c.TestByInt("Not an Int")
340
+ }.should raise_error
341
+ end
342
+
336
343
  it "should handle a non-mandatory missing identifying role" do
337
344
  module Mod2
338
345
  class Word
@@ -380,5 +387,4 @@ describe "An instance of every type of ObjectType" do
380
387
  f.is_ok.should == false
381
388
  s.is_ok.should == true
382
389
  end
383
-
384
390
  end
@@ -2,8 +2,6 @@
2
2
  # ActiveFacts tests: Value instances in the Runtime API
3
3
  # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
4
  #
5
- require 'rspec'
6
- require 'activefacts/api'
7
5
 
8
6
  VALUE_TYPES = Int, Real, AutoCounter, String, Date, DateTime, Decimal
9
7
  RAW_VALUES = [2, 3.0, 4, "5", Date.new(2008, 04, 20), DateTime.new(2008, 04, 20, 10, 28, 14)]
@@ -22,20 +20,20 @@ module TestValueTypesModule
22
20
  value_type
23
21
  end
24
22
  BASE_VALUE_TYPE_ROLE_NAMES = VALUE_TYPES.map { |base_type| base_type.name.snakecase }
25
- VALUE_TYPE_ROLE_NAMES = BASE_VALUE_TYPE_ROLE_NAMES.map { |n| [ :"#{n}_value", :"#{n}_sub_value" ] }.flatten
23
+ VALUE_TYPE_ROLE_NAMES = BASE_VALUE_TYPE_ROLE_NAMES.map { |n| [ :"#{n}_val", :"#{n}_sub_val" ] }.flatten
26
24
  VALUE_TYPES.map do |value_type|
27
25
  code = <<-END
28
- class #{value_type.name}Value < #{value_type.name}
26
+ class #{value_type.name}Val < #{value_type.name}
29
27
  value_type
30
28
  end
31
29
 
32
- class #{value_type.name}ValueSub < #{value_type.name}Value
30
+ class #{value_type.name}ValSub < #{value_type.name}Val
33
31
  # Note no new "value_type" is required here, it comes through inheritance
34
32
  end
35
33
 
36
34
  class #{value_type.name}Entity
37
- identified_by :#{identifying_role_name = "id_#{value_type.name.snakecase}_value"}
38
- has_one :#{identifying_role_name}, :class => #{value_type.name}Value
35
+ identified_by :#{identifying_role_name = "id_#{value_type.name.snakecase}_val"}
36
+ one_to_one :#{identifying_role_name}, :class => #{value_type.name}Val
39
37
  end
40
38
 
41
39
  class #{value_type.name}EntitySub < #{value_type.name}Entity
@@ -43,13 +41,13 @@ module TestValueTypesModule
43
41
 
44
42
  class #{value_type.name}EntitySubCtr < #{value_type.name}Entity
45
43
  identified_by :counter
46
- has_one :counter, :class => "ESCID"
44
+ one_to_one :counter, :class => "ESCID"
47
45
  end
48
46
 
49
- VALUE_SUB_FOR_VALUE[#{value_type.name}Value] = #{value_type.name}ValueSub
47
+ VALUE_SUB_FOR_VALUE[#{value_type.name}Val] = #{value_type.name}ValSub
50
48
  classes = [
51
- #{value_type.name}Value,
52
- #{value_type.name}ValueSub,
49
+ #{value_type.name}Val,
50
+ #{value_type.name}ValSub,
53
51
  #{value_type.name}Entity,
54
52
  #{value_type.name}EntitySub,
55
53
  #{value_type.name}EntitySubCtr,
@@ -57,13 +55,13 @@ module TestValueTypesModule
57
55
  OBJECT_TYPES.concat(classes)
58
56
  classes.each { |klass| VALUE_TYPE_FOR_OBJECT_TYPE[klass] = value_type }
59
57
  END
60
- eval code
58
+ TestValueTypesModule.module_eval code
61
59
  end
62
60
  OBJECT_TYPE_NAMES = OBJECT_TYPES.map{|object_type| object_type.basename}
63
61
 
64
62
  class Octopus
65
63
  identified_by :zero
66
- has_one :zero, :class => IntValue
64
+ one_to_one :zero, :class => IntVal
67
65
  maybe :has_a_unary
68
66
  OBJECT_TYPE_NAMES.each do |object_type_name|
69
67
  has_one object_type_name.snakecase.to_sym
@@ -94,7 +92,7 @@ end
94
92
  describe "Object type role values" do
95
93
  def object_identifying_parameters object_type_name, value
96
94
  if object_type_name =~ /^(.*)EntitySubCtr$/
97
- [{ :"id_#{$1.snakecase}_value" => value, :counter => :new}]
95
+ [{ :"id_#{$1.snakecase}_val" => value, :counter => :new}]
98
96
  else
99
97
  [value]
100
98
  end
@@ -110,7 +108,7 @@ describe "Object type role values" do
110
108
  it "should allow instantiation of a bare #{object_type_name}" do
111
109
  object_identifying_parameters =
112
110
  if object_type_name =~ /^(.*)EntitySubCtr$/
113
- [{ :"id_#{$1.snakecase}_value" => values[0], :counter => :new}]
111
+ [{ :"id_#{$1.snakecase}_val" => values[0], :counter => :new}]
114
112
  else
115
113
  [values[0]]
116
114
  end
@@ -275,7 +273,7 @@ describe "Object type role values" do
275
273
  reflection = assigned.send(role.counterpart.name)
276
274
  reflection.should_not be_empty
277
275
  reflection.size.should == 1
278
- reflection.should be_include(@object)
276
+ reflection.should include @object
279
277
  end
280
278
 
281
279
  # Update the role to the second value:
@@ -299,7 +297,7 @@ describe "Object type role values" do
299
297
  # The counterpart should include us in its RoleValues
300
298
  reflection2 = assigned2.send(role.counterpart.name)
301
299
  reflection2.size.should == 1
302
- reflection2.should be_include(@object)
300
+ reflection2.should include @object
303
301
  end
304
302
 
305
303
  # Nullify the role
@@ -388,12 +386,23 @@ describe "Object type role values" do
388
386
 
389
387
  it "should support each" do
390
388
  count = 0
391
- @role_values.each { |rv| count += 1 }
389
+ @role_values.each do |v, *a|
390
+ a.size.should == 0
391
+ v.should_not be_nil
392
+ count += 1
393
+ end
392
394
  count.should == 1
393
395
  end
394
396
 
395
397
  it "should support detect" do
396
- @role_values.detect { |rv| true }.should be_true
398
+ count = 0
399
+ @role_values.detect do |v, *a|
400
+ a.size.should == 0
401
+ v.should_not be_nil
402
+ count += 1
403
+ false
404
+ end
405
+ count.should == 1
397
406
  end
398
407
 
399
408
  it "should verbalise" do
@@ -2,19 +2,21 @@
2
2
  # ActiveFacts tests: Roles of object_type classes in the Runtime API
3
3
  # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
4
  #
5
- require 'rspec'
6
- require 'activefacts/api'
7
5
 
8
6
  describe "Roles" do
9
7
  before :each do
10
8
  Object.send :remove_const, :Mod if Object.const_defined?("Mod")
11
9
  module Mod
12
10
  class Name < String
13
- value_type :length => 40, :scale => 0, :restrict => /^[A-Z][a-z]*/
11
+ value_type :length => 40, :scale => 0, :restrict => /^[A-Z][a-z0-9]*/
12
+ end
13
+ class Identifier
14
+ identified_by :name
15
+ one_to_one :name
14
16
  end
15
17
  class LegalEntity
16
18
  identified_by :name
17
- has_one :name
19
+ one_to_one :name
18
20
  end
19
21
  class Contract
20
22
  identified_by :first, :second
@@ -30,6 +32,11 @@ describe "Roles" do
30
32
  alias :given= :name=
31
33
  has_one :related_to, :class => LegalEntity
32
34
  end
35
+ class Employee
36
+ identified_by :name
37
+ one_to_one :identifier
38
+ one_to_one :name
39
+ end
33
40
  end
34
41
  # print "object_type: "; p Mod.object_type
35
42
  end
@@ -116,10 +123,10 @@ describe "Roles" do
116
123
  le = Mod::LegalEntity.new(foo)
117
124
  le.respond_to?(:name).should be_true
118
125
  name = le.name
119
- name.respond_to?(:all_legal_entity).should be_true
126
+ name.respond_to?(:legal_entity).should be_true
120
127
 
121
128
  #pending
122
- Array(name.all_legal_entity).should === [le]
129
+ [name.legal_entity].should === [le]
123
130
  end
124
131
 
125
132
  it "should instantiate subclasses sensibly" do
@@ -127,7 +134,7 @@ describe "Roles" do
127
134
  bloggs = c.LegalEntity("Bloggs & Co")
128
135
  p = c.Person("Fred", "Bloggs")
129
136
  p.related_to = "Bloggs & Co"
130
- p.related_to.should be_is_a(Mod::LegalEntity)
137
+ p.related_to.should be_an_instance_of Mod::LegalEntity
131
138
  p.related_to.should == bloggs
132
139
 
133
140
  # REVISIT: The raw instance doesn't override == to compare itself to a RoleProxy unfortunately...
@@ -136,28 +143,55 @@ describe "Roles" do
136
143
  end
137
144
 
138
145
  it "should forward missing methods on the role proxies" do
146
+ c = ActiveFacts::API::Constellation.new(Mod)
147
+ p = c.Person("Fred", "Bloggs")
148
+ lambda {p.family.foo}.should raise_error(NoMethodError)
149
+ end
150
+
151
+ it "should forward re-raise exceptions from missing methods on the role proxies" do
139
152
  c = ActiveFacts::API::Constellation.new(Mod)
140
153
  p = c.Person("Fred", "Bloggs")
154
+ class String
155
+ def foo
156
+ raise "Yawning"
157
+ end
158
+ end
141
159
 
142
- # Make sure that RoleProxy's method_missing delegates, then forwards the send
143
- lambda {
144
- p.family.foo
145
- }.should raise_error(NoMethodError)
160
+ lambda {p.family.foo}.should raise_error(RuntimeError)
146
161
  end
147
162
 
148
- it "should forward re-raise exceptions from missing methods on the role proxies" do
163
+ it "should keep a trace of the overwritten class when changing identification" do
164
+ pending
149
165
  c = ActiveFacts::API::Constellation.new(Mod)
150
- p = c.Person("Fred", "Bloggs")
166
+ e = c.Employee(:identifier => "Project2501")
167
+ e.overrides_identification_of.is_a?(Mod::LegalEntity).should be_true
168
+ end
151
169
 
152
- # x = p.family.__getobj__
153
- #def x.barf
154
- # raise "Yawning..."
155
- #end
156
- lambda {
157
- p.family.barf
158
- #}.should raise_error(RuntimeError)
159
- }.should raise_error(NoMethodError)
170
+ it "should be able to import an entity from another constellation" do
171
+ c1 = ActiveFacts::API::Constellation.new(Mod)
172
+ c2 = ActiveFacts::API::Constellation.new(Mod)
160
173
 
174
+ e = c1.Employee("PuppetMaster")
175
+ identifier = c2.Identifier("Project2501", :employee => e)
176
+ identifier.employee.name.should == "PuppetMaster"
161
177
  end
162
178
 
179
+ it "should be able to import an entity from another constellation which subclass another entity" do
180
+ pending "fails because identify_role_values get only the current class identifying roles" do
181
+ # in this example, it returns :identifier, but not :name from LegalEntity
182
+ module Mod
183
+ class Person2 < LegalEntity
184
+ identified_by :identifier
185
+ one_to_one :identifier
186
+ end
187
+ end
188
+
189
+ c1 = ActiveFacts::API::Constellation.new(Mod)
190
+ c2 = ActiveFacts::API::Constellation.new(Mod)
191
+
192
+ p = c1.Person2("Person2Name", :identifier => "Project2501")
193
+ identifier = c2.Identifier("Project2501", :person2 => p)
194
+ identifier.person2.name.should == "Person2Name"
195
+ end
196
+ end
163
197
  end
@@ -0,0 +1,45 @@
1
+ require 'activefacts/api'
2
+
3
+ module Tax
4
+
5
+ class Name < String
6
+ value_type
7
+ end
8
+
9
+ class Person
10
+ identified_by :name
11
+ one_to_one :name
12
+ end
13
+
14
+ class Australian < Person
15
+ end
16
+
17
+ class TaxPayer < Person
18
+ end
19
+
20
+ class TFN < Int
21
+ value_type
22
+ end
23
+
24
+ class AustralianTaxPayer < Australian
25
+ supertypes TaxPayer
26
+ identified_by :tfn
27
+ one_to_one :tfn, :class => TFN # Capitalisation rules!
28
+ end
29
+
30
+ class YearNr < Int
31
+ value_type
32
+ end
33
+
34
+ class Year
35
+ identified_by :year_nr
36
+ one_to_one :year_nr
37
+ end
38
+
39
+ class AustralianTaxReturn
40
+ identified_by :australian_tax_payer, :year
41
+ has_one :australian_tax_payer
42
+ has_one :year
43
+ end
44
+
45
+ end