Module: ActiveFacts::API::ObjectType
- Included in:
- Instance::ClassMethods
- Defined in:
- lib/activefacts/api/object_type.rb
Overview
ObjectType contains methods that are added as class methods to all Value and Entity classes.
Constant Summary collapse
- SKIP_MUTUAL_PROPAGATION =
0x1
- CHECKED_IDENTIFYING_ROLE =
0x2
Instance Method Summary collapse
- #add_role(role) ⇒ Object
-
#all_role(role_name = nil) ⇒ Object
Each ObjectType maintains a list of the Roles it plays:.
- #all_role_transitive ⇒ Object
- #check_identifying_role_has_valid_cardinality(type, role) ⇒ Object
-
#has_one(role_name, options = {}) ⇒ Object
Define a binary fact type relating this object_type to another, with a uniqueness constraint only on this object_type’s role.
-
#maybe(role_name, options = {}) ⇒ Object
Define a unary fact type attached to this object_type; in essence, a boolean attribute.
-
#one_to_one(role_name, options = {}) ⇒ Object
Define a binary fact type joining this object_type to another, with uniqueness constraints in both directions, i.e.
-
#realise_role(role) ⇒ Object
Every new role added or inherited comes through here:.
- #subtypes ⇒ Object
- #subtypes_transitive ⇒ Object
-
#supertypes(*object_types) ⇒ Object
Access supertypes or add new supertypes; multiple inheritance.
-
#supertypes_transitive ⇒ Object
Return the array of all ObjectType supertypes, transitively.
-
#vocabulary ⇒ Object
What vocabulary (Ruby module) does this object_type belong to?.
Instance Method Details
#add_role(role) ⇒ Object
52 53 54 55 |
# File 'lib/activefacts/api/object_type.rb', line 52 def add_role(role) all_role[role.name] = role @all_role_transitive = nil # Undo the caching end |
#all_role(role_name = nil) ⇒ Object
Each ObjectType maintains a list of the Roles it plays:
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/activefacts/api/object_type.rb', line 23 def all_role(role_name = nil) unless instance_variable_defined?(@@all_role_name ||= "@all_role") # Avoid "instance variable not defined" warning from ||= @all_role = RoleCollection.new end case role_name when nil @all_role when Symbol, String # Search this class then all supertypes: unless role = @all_role[role_name.to_sym] role = nil supertypes.each do |supertype| begin role = supertype.all_role(role_name) rescue RoleNotDefinedException next end break end end unless role raise RoleNotDefinedException.new(self, role_name) end role else nil end end |
#all_role_transitive ⇒ Object
57 58 59 60 61 62 63 64 |
# File 'lib/activefacts/api/object_type.rb', line 57 def all_role_transitive return @all_role_transitive if @all_role_transitive @all_role_transitive = all_role.dup supertypes_transitive.each do |klass| @all_role_transitive.merge!(klass.all_role) end @all_role_transitive end |
#check_identifying_role_has_valid_cardinality(type, role) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/activefacts/api/object_type.rb', line 108 def (type, role) if is_entity_type && .include?(role) case type when :has_one if .size == 1 raise InvalidIdentificationException.new(self, role, true) end when :one_to_one if .size > 1 raise InvalidIdentificationException.new(self, role, false) end end end end |
#has_one(role_name, options = {}) ⇒ Object
Define a binary fact type relating this object_type to another, with a uniqueness constraint only on this object_type’s role. This method creates two accessor methods, one in this object_type and one in the other object_type.
-
role_name is a Symbol for the name of the role (this end of the relationship)
Options contain optional keys:
-
: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.
-
: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).
-
:counterpart - use if the role at the other end should have a name other than the default :all_<object_type> or :all_<object_type>_as_<role_name>
-
:reading - for verbalisation. Not used yet.
-
:restrict - a list of values or ranges which this role may take. Not used yet.
85 86 87 88 89 |
# File 'lib/activefacts/api/object_type.rb', line 85 def has_one(role_name, = {}) role_name, , mandatory, , restrict = extract_binary_params(role_name, false, ) (:has_one, role_name) define_binary_fact_type(false, role_name, , mandatory, , restrict) end |
#maybe(role_name, options = {}) ⇒ Object
Define a unary fact type attached to this object_type; in essence, a boolean attribute.
Example: maybe :is_ceo
69 70 71 72 73 |
# File 'lib/activefacts/api/object_type.rb', line 69 def maybe(role_name, = {}) raise UnrecognisedOptionsException.new("role", role_name, .keys) unless .empty? fact_type = FactType.new realise_role(Role.new(fact_type, self, role_name, false, true)) end |
#one_to_one(role_name, options = {}) ⇒ Object
Define a binary fact type joining this object_type to another, with uniqueness constraints in both directions, i.e. a one-to-one relationship This method creates two accessor methods, one in this object_type and one in the other object_type.
-
role_name is a Symbol for the name of the role (this end of the relationship)
Options contain optional keys:
-
: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.
-
: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).
-
:counterpart - use if the role at the other end should have a name other than the default :all_<object_type> or :all_<object_type>_as_<role_name>
-
:reading - for verbalisation. Not used yet.
-
:restrict - a list of values or ranges which this role may take. Not used yet.
101 102 103 104 105 106 |
# File 'lib/activefacts/api/object_type.rb', line 101 def one_to_one(role_name, = {}) role_name, , mandatory, , restrict = extract_binary_params(role_name, true, ) (:one_to_one, role_name) define_binary_fact_type(true, role_name, , mandatory, , restrict) end |
#realise_role(role) ⇒ Object
Every new role added or inherited comes through here:
183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/activefacts/api/object_type.rb', line 183 def realise_role(role) #:nodoc: if (role.unary?) # Unary role define_unary_role_accessor(role) elsif (role.unique) if role.counterpart.unique define_one_to_one_accessor(role) else define_one_to_many_accessor(role) end else define_many_to_one_accessor(role) end end |
#subtypes ⇒ Object
174 175 176 |
# File 'lib/activefacts/api/object_type.rb', line 174 def subtypes @subtypes ||= [] end |
#subtypes_transitive ⇒ Object
178 179 180 |
# File 'lib/activefacts/api/object_type.rb', line 178 def subtypes_transitive (subtypes+subtypes.map(&:subtypes_transitive)).flatten.uniq end |
#supertypes(*object_types) ⇒ Object
Access supertypes or add new supertypes; multiple inheritance. With parameters (Class objects), it adds new supertypes to this class. Instances of this class will then have role methods for any new superclasses (transitively). Superclasses must be Ruby classes which are existing ObjectTypes. Without parameters, it returns the array of ObjectType supertypes (one by Ruby inheritance, any others as defined using this method)
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/activefacts/api/object_type.rb', line 129 def supertypes(*object_types) @supertypes ||= [] all_supertypes = supertypes_transitive object_types.each do |object_type| next if all_supertypes.include? object_type supertype = case object_type when Class object_type when Symbol # No late binding here: (object_type = vocabulary.const_get(object_type.to_s.camelcase)) else raise InvalidSupertypeException.new("Illegal supertype #{object_type.inspect} for #{self.class.basename}") end unless supertype.respond_to?(:vocabulary) and supertype.vocabulary == self.vocabulary raise InvalidSupertypeException.new("#{supertype.name} must be an object type in #{vocabulary.name}") end if is_entity_type != supertype.is_entity_type raise InvalidSupertypeException.new("#{self} < #{supertype}: A value type may not be a supertype of an entity type, and vice versa") end TypeInheritanceFactType.new(supertype, self) @supertypes << supertype # Realise the roles (create accessors) of this supertype. realise_supertypes(object_type, all_supertypes) end [(superclass.respond_to?(:vocabulary) ? superclass : nil), *@supertypes].compact end |
#supertypes_transitive ⇒ Object
Return the array of all ObjectType supertypes, transitively.
162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/activefacts/api/object_type.rb', line 162 def supertypes_transitive supertypes = [] v = superclass.respond_to?(:vocabulary) ? superclass.vocabulary : nil supertypes << superclass if v.kind_of?(Module) supertypes += (@supertypes ||= []) sts = supertypes.inject([]) do |a, t| next if a.include?(t) a += [t] + t.supertypes_transitive end.uniq sts # The local variable unconfuses rcov end |
#vocabulary ⇒ Object
What vocabulary (Ruby module) does this object_type belong to?
18 19 20 |
# File 'lib/activefacts/api/object_type.rb', line 18 def vocabulary modspace # The module that contains this object_type. end |