Module: MetaRuby::Registration

Included in:
ModelAsClass, ModelAsModule
Defined in:
lib/metaruby/registration.rb

Overview

Handling of registration of model hierarchies

It depends on the mixed-in object to provide a #supermodel method that returns the model that is parent of self

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#definition_locationArray<Thread::Backtrace::Locations>

The place where this model got defined in the source code This is an array of Thread::Backtrace::Locations

Returns:

  • (Array<Thread::Backtrace::Locations>)


16
17
18
# File 'lib/metaruby/registration.rb', line 16

def definition_location
  @definition_location
end

Class Method Details

.accessible_by_name?(object) ⇒ Boolean

Returns true if the given object can be accessed by resolving its name as a constant.

Returns:

  • (Boolean)

    true if the given object can be accessed by resolving its name as a constant



54
55
56
57
58
59
60
61
# File 'lib/metaruby/registration.rb', line 54

def self.accessible_by_name?(object)
    return false if !object.respond_to?(:name) || !object.name
    begin
        constant("::#{object.name}") == object
    rescue NameError
        false
    end
end

.deregister_constant(obj) ⇒ Object

Removes the constant that stores the given object in the Ruby constant hierarchy

It assumes that calling #name on the object returns the place in the constant hierarchy where it is stored



133
134
135
# File 'lib/metaruby/registration.rb', line 133

def self.deregister_constant(obj)
    constant("::#{obj.spacename}").send(:remove_const, obj.basename)
end

Instance Method Details

#accessible_by_name?Boolean

Returns true if this object can be accessed by resolving its name as a constant.

Returns:

  • (Boolean)

    true if this object can be accessed by resolving its name as a constant



65
66
67
# File 'lib/metaruby/registration.rb', line 65

def accessible_by_name?
    Registration.accessible_by_name?(self)
end

#clear_modelObject

Clears this model

It deregisters sef if it is not a #permanent_model?, and clears the submodels

Model classes and modules should also clear their respective attributes (if there are any)



109
110
111
112
113
114
115
116
117
# File 'lib/metaruby/registration.rb', line 109

def clear_model
    if !permanent_model?
        if m = supermodel
            m.deregister_submodels([self])
        end
        clear_registration_as_constant
    end
    clear_submodels
end

#clear_registration_as_constantObject

Removes any constant this model is registered as



120
121
122
123
124
125
126
# File 'lib/metaruby/registration.rb', line 120

def clear_registration_as_constant
    # Deregister non-permanent models that are registered in the
    # constant hierarchy
    if Registration.accessible_by_name?(self)
        Registration.deregister_constant(self)
    end
end

#clear_submodelsObject

Recursively deregisters all non-permanent submodels



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/metaruby/registration.rb', line 138

def clear_submodels
    permanent, non_permanent = each_submodel.partition { |m| m.permanent_model? }
    if !non_permanent.empty?
        deregister_submodels(non_permanent)
    end

    non_permanent.each do |m|
        m.clear_registration_as_constant
    end

    # This contains the permanent submodels
    #
    # We can call #clear_submodels while iterating here as it is a
    # constraint that all models in #submodels are permanent (and
    # will therefore not be removed)
    permanent.each { |m| m.clear_submodels }
    # And this the non-permanent ones
    non_permanent.each { |m| m.clear_submodels }
    true
end

#deregister_submodels(set) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Deregisters a set of submodels on this model and all its supermodels

This is usually not called directly. Use #clear_submodels instead

Parameters:

  • set (Set)

    the set of submodels to remove



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/metaruby/registration.rb', line 167

def deregister_submodels(set)
    has_match = false
    submodels.delete_if do |m|
        begin
            m = m.__getobj__
            if set.include?(m)
                has_match = true
            end
        rescue WeakRef::RefError
            true
        end
    end

    if m = supermodel
        m.deregister_submodels(set)
    end
    has_match
end

#each_submodelObject

Enumerates all models that are submodels of this class



90
91
92
93
94
95
96
97
98
99
100
# File 'lib/metaruby/registration.rb', line 90

def each_submodel
    return enum_for(:each_submodel) if !block_given?
    submodels.delete_if do |obj|
        begin
            yield(obj.__getobj__)
            false
        rescue WeakRef::RefError
            true
        end
    end
end

#has_submodel?(model) ⇒ Boolean

Returns whether a model is a submodel of self

Returns:

  • (Boolean)


30
31
32
# File 'lib/metaruby/registration.rb', line 30

def has_submodel?(model)
    each_submodel.any? { |m| m == model }
end

#permanent_definition_context?Boolean

Returns true if the definition context (module, class) in which self is registered is permanent or not w.r.t. the model registration functionality of metaruby.

Returns:

  • (Boolean)

    true if the definition context (module, class) in which self is registered is permanent or not w.r.t. the model registration functionality of metaruby



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/metaruby/registration.rb', line 37

def permanent_definition_context?
    return false if !name
    definition_context_name = spacename
    if !definition_context_name.empty?
        begin
            enclosing_context = constant("::#{definition_context_name}")
            return !enclosing_context.respond_to?(:permanent_model?) || enclosing_context.permanent_model?
        rescue NameError
            false
        end
    else
        true
    end
end

#permanent_model?Boolean

Tells #clear_submodels whether this model should be removed from the model set or not. The default is false (it should be removed)

Returns:

  • (Boolean)


22
# File 'lib/metaruby/registration.rb', line 22

attr_predicate :permanent_model?, true

#register_submodel(klass) ⇒ Object

Call to register a model that is a submodel of self



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/metaruby/registration.rb', line 70

def register_submodel(klass)
    if klass.singleton_class?
        raise ArgumentError, "cannot register a singleton class"
    end

    if !klass.definition_location
        klass.definition_location = 
            if MetaRuby.keep_definition_location?
                caller_locations
            else Array.new
            end
    end

    submodels << WeakRef.new(klass)
    if m = supermodel
        m.register_submodel(klass)
    end
end

#submodelsArray<WeakRef>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the set of models that are children of this one.

Returns:

  • (Array<WeakRef>)

    the set of models that are children of this one



27
# File 'lib/metaruby/registration.rb', line 27

attribute(:submodels) { Array.new }