activefacts-api 0.8.12 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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