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.
Instance Method Summary collapse
- #all_roles ⇒ 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:.
-
#roles(role_name = nil) ⇒ Object
Each ObjectType maintains a list of the Roles it plays:.
- #subtypes ⇒ 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
#all_roles ⇒ Object
49 50 51 52 53 54 55 56 |
# File 'lib/activefacts/api/object_type.rb', line 49 def all_roles return @all_roles if @all_roles @all_roles = roles.dup supertypes_transitive.each do |klass| @all_roles.merge!(klass.roles) end @all_roles end |
#check_identifying_role_has_valid_cardinality(type, role) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/activefacts/api/object_type.rb', line 99 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.
76 77 78 79 80 |
# File 'lib/activefacts/api/object_type.rb', line 76 def has_one(role_name, = {}) role_name, , mandatory, = extract_binary_params(false, role_name, ) (:has_one, role_name) define_binary_fact_type(false, role_name, , mandatory, ) 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
61 62 63 64 |
# File 'lib/activefacts/api/object_type.rb', line 61 def maybe(role_name, = {}) raise UnrecognisedOptionsException.new("role", role_name, .keys) unless .empty? realise_role(roles[role_name] = Role.new(self, TrueClass, role_name)) 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.
92 93 94 95 96 97 |
# File 'lib/activefacts/api/object_type.rb', line 92 def one_to_one(role_name, = {}) role_name, , mandatory, = extract_binary_params(true, role_name, ) (:one_to_one, role_name) define_binary_fact_type(true, role_name, , mandatory, ) end |
#realise_role(role) ⇒ Object
Every new role added or inherited comes through here:
171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/activefacts/api/object_type.rb', line 171 def realise_role(role) #:nodoc: if (role.is_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 |
#roles(role_name = nil) ⇒ Object
Each ObjectType maintains a list of the Roles it plays:
20 21 22 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 |
# File 'lib/activefacts/api/object_type.rb', line 20 def roles(role_name = nil) unless instance_variable_defined?(@@roles_name ||= "@roles") # Avoid "instance variable not defined" warning from ||= @roles = RoleCollection.new end case role_name when nil @roles when Symbol, String # Search this class then all supertypes: unless role = @roles[role_name.to_sym] role = nil supertypes.each do |supertype| begin role = supertype.roles(role_name) rescue RoleNotDefinedException next end break end end unless role raise RoleNotDefinedException.new(self, role_name) end role else nil end end |
#subtypes ⇒ Object
166 167 168 |
# File 'lib/activefacts/api/object_type.rb', line 166 def subtypes @subtypes ||= [] 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)
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/activefacts/api/object_type.rb', line 120 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 @supertypes << supertype # Realise the roles (create accessors) of this supertype. # REVISIT: The existing accessors at the other end will need to allow this class as role counterpart # REVISIT: Need to check all superclass roles recursively, unless we hit a common 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.
154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/activefacts/api/object_type.rb', line 154 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?
15 16 17 |
# File 'lib/activefacts/api/object_type.rb', line 15 def vocabulary modspace # The module that contains this object_type. end |