module MetaRuby::ModelAsModule
Extend in modules that are used as models
@example
module MyBaseModel extend MetaRuby::ModelAsModule end
Alternatively, one can create a module to describe the metamodel for our base model and then include it in the actual root model
@example
module MyBaseMetamodel include MetaRuby::ModelAsModule end module MyBaseModel extend MyBaseMetamodel end
Attributes
The call trace at the point of definition. It is usually used to report to the user in which file this model got defined
@return [Array] a list of (file,line,method)
tuples as returned by #call_stack (from the facet gem)
Set or get the root model
Public Class Methods
Common method that can be used to create and register a submodel-as-a-module on a provided namespace
It is usually used to create specific DSL-like methods that allow to create these models
@param [Module,Class] namespace @param [String] name the model name, it must be valid for a Ruby
constant name
@param [Module] base_model the base model, which should include
{ModelAsModule} itself
@param [Array] args additional arguments to pass to base_model's
#setup_submodel
@param [#call] block block passed to base_model's setup_submodel
@return [Module] the new model
# File lib/metaruby/model_as_module.rb, line 58 def self.create_and_register_submodel(namespace, name, base_model, *args, &block) ModelAsModule.validate_constant_name(name) if namespace.const_defined?(name, false) model = namespace.const_get(name) base_model.setup_submodel(model, *args, &block) else namespace.const_set(name, model = base_model.new_submodel(*args, &block)) model.permanent_model = if !namespace.respond_to?(:permanent_model?) Registration.accessible_by_name?(namespace) else namespace.permanent_model? end end model end
# File lib/metaruby/model_as_module.rb, line 106 def self.extend_object(obj) obj.instance_variable_set :@name, nil super end
Validate that a string can be used as a constant name
@param [String] name the name to validate @raise [ArgumentError] if the name cannot be used as a constant name
# File lib/metaruby/model_as_module.rb, line 37 def self.validate_constant_name(name) if name !~ /^[A-Z]\w+$/ raise ArgumentError, "#{name} is not a valid model name" end end
Public Instance Methods
Called to apply a model definition block on this model
The definition class-eval's it
@return [void]
# File lib/metaruby/model_as_module.rb, line 163 def apply_block(&block) class_eval(&block) end
In the case of model-as-modules, we always deregister (regardless of the fact that self
is permanent or not). The reason for this is that the model-as-module hierarchy is much more dynamic than model-as-class. Who provides what can be changed after a clear_model
call.
MetaRuby::Registration#clear_model
# File lib/metaruby/model_as_module.rb, line 149 def clear_model super if supermodel supermodel.deregister_submodels([self]) end @supermodel = nil parent_models.clear end
# File lib/metaruby/model_as_module.rb, line 100 def name if @name then @name else super end end
@!attribute [rw] name
Sets a name on this model
Only use this on 'anonymous models', i.e. on models that are not meant to be assigned on a Ruby constant
@return [String] the assigned name
# File lib/metaruby/model_as_module.rb, line 96 def name=(name) @name = name end
Creates a new DataServiceModel that is a submodel of self
@param [String] name the submodel name. Use this option
only for "anonymous" models, i.e. models that won't be registered on a Ruby constant
@param [Class] type (self.class) the type of the submodel
# File lib/metaruby/model_as_module.rb, line 121 def new_submodel(name: nil, type: self.class, **submodel_options, &block) model = type.new model.extend ModelAsModule model.name = name.dup if name model.definition_location = if MetaRuby.keep_definition_location? caller_locations else Array.new end setup_submodel(model, submodel_options, &block) model end
Declares that this model also provides this other given model
# File lib/metaruby/model_as_module.rb, line 175 def provides(model) include model model_root = if model.root? then model else model.supermodel end if !supermodel self.supermodel = model_root self.supermodel.register_submodel(self) elsif supermodel != model_root if model_root.provides?(supermodel) self.supermodel = model_root elsif !supermodel.provides?(model_root) raise ArgumentError, "#{model}'s root is #{model_root} while #{self} is #{supermodel}, which are unrelated" end self.supermodel.register_submodel(self) end self.parent_models.merge(model.parent_models) self.parent_models << model end
Tests whether self provides the given model
@param [Module] model
# File lib/metaruby/model_as_module.rb, line 170 def provides?(model) self <= model end
Called when a new submodel has been created, on the newly created submodel
# File lib/metaruby/model_as_module.rb, line 136 def setup_submodel(submodel, options = Hash.new, &block) submodel.provides self if block_given? submodel.apply_block(&block) end end