class RGen::ECore::ECoreToRuby
ECoreToRuby can turn ECore models into their Ruby metamodel representations
Attributes
Public Class Methods
# File lib/rgen/ecore/ecore_to_ruby.rb, line 11 def initialize @modules = {} @classifiers = {} @features_added = {} @reserved = Set.new(Object.methods) end
Public Instance Methods
# File lib/rgen/ecore/ecore_to_ruby.rb, line 240 def add_features(eclass) return false if @features_added[eclass] c = @classifiers[eclass] eclass.eStructuralFeatures.each do |f| w1 = FeatureWrapper.new(f, @classifiers) w2 = FeatureWrapper.new(f.eOpposite, @classifiers) if f.is_a?(RGen::ECore::EReference) && f.eOpposite c.module_eval do if w1.many? _build_many_methods(w1, w2) else _build_one_methods(w1, w2) end end end @features_added[eclass] = true eclass.eSuperTypes.each do |t| add_features(t) end true end
Create a Ruby module representing epackage. This includes all nested modules/packages, classes and enums.
If a parent module is provided with the “under” parameter, the new module will be nested under the parent module.
If the parent module has a non-temporary name, (more precisely: a non-temporary classpath) i.e. if it is reachable via a path of constant names from the root, then the nested modules and classes will also have non-temporary names. In particular, this means that they will keep their names even if they are assigned to new constants.
If no parent module is provided or the parent module has a temporary name by itself, then the nested modules and classes will also have temporary names. This means that their name will stay 'volatile' until they are assigned to constants reachable from the root and the Module#name method is called for the first time.
While the second approach is more flexible, it can come with a major performance impact. The reason is that Ruby searches the space of all known non-temporary classes/modules every time the name of a class/module with a temporary name is queried.
# File lib/rgen/ecore/ecore_to_ruby.rb, line 42 def create_module(epackage, under=Module.new) with_empty_constant_order_helper do temp = under.to_s.start_with?("#") mod = create_module_internal(epackage, under, temp) epackage.eAllClassifiers.each do |c| if c.is_a?(RGen::ECore::EClass) create_class(c, temp) elsif c.is_a?(RGen::ECore::EEnum) create_enum(c) end end load_classes_with_reserved_keywords(epackage) mod end end
Private Instance Methods
# File lib/rgen/ecore/ecore_to_ruby.rb, line 96 def create_class(eclass, temp) return @classifiers[eclass] if @classifiers[eclass] mod = @modules[eclass.ePackage] if temp cls = Class.new(super_class(eclass, temp)) do abstract if eclass.abstract class << self attr_accessor :_ecore_to_ruby end end mod.const_set(eclass.name, cls) else mod.module_eval <<-END class #{eclass.name} < #{super_class(eclass, temp)} #{eclass.abstract ? 'abstract' : ''} class << self attr_accessor :_ecore_to_ruby end end END cls = mod.const_get(eclass.name) end class << eclass attr_accessor :instanceClass def instanceClassName instanceClass.to_s end end eclass.instanceClass = cls cls::ClassModule.module_eval do alias _method_missing method_missing def method_missing(m, *args) if self.class._ecore_to_ruby.add_features(self.class.ecore) send(m, *args) else _method_missing(m, *args) end end alias _respond_to respond_to? def respond_to?(m, include_all=false) self.class._ecore_to_ruby.add_features(self.class.ecore) _respond_to(m) end end @classifiers[eclass] = cls cls._set_ecore_internal(eclass) cls._ecore_to_ruby = self cls end
# File lib/rgen/ecore/ecore_to_ruby.rb, line 150 def create_enum(eenum) return @classifiers[eenum] if @classifiers[eenum] e = RGen::MetamodelBuilder::DataTypes::Enum.new(eenum.eLiterals.collect{|l| l.name.to_sym}) @classifiers[eenum] = e @modules[eenum.ePackage].const_set(eenum.name, e) e end
# File lib/rgen/ecore/ecore_to_ruby.rb, line 72 def create_module_internal(epackage, under, temp) return @modules[epackage] if @modules[epackage] if temp mod = Module.new do extend RGen::MetamodelBuilder::ModuleExtension end under.const_set(epackage.name, mod) else under.module_eval <<-END module #{epackage.name} extend RGen::MetamodelBuilder::ModuleExtension end END mod = under.const_get(epackage.name) end @modules[epackage] = mod epackage.eSubpackages.each{|p| create_module_internal(p, mod, temp)} mod._set_ecore_internal(epackage) mod end
# File lib/rgen/ecore/ecore_to_ruby.rb, line 62 def load_classes_with_reserved_keywords(epackage) epackage.eAllClassifiers.each do |eclass| # we early load classes which have ruby reserved keywords if eclass.is_a?(RGen::ECore::EClass) reserved_used = eclass.eStructuralFeatures.any? { |f| @reserved.include?(f.name.to_sym) } add_features(eclass) if reserved_used end end end
# File lib/rgen/ecore/ecore_to_ruby.rb, line 130 def method_missing(m, *args) if self.class._ecore_to_ruby.add_features(self.class.ecore) send(m, *args) else _method_missing(m, *args) end end
# File lib/rgen/ecore/ecore_to_ruby.rb, line 138 def respond_to?(m, include_all=false) self.class._ecore_to_ruby.add_features(self.class.ecore) _respond_to(m) end
# File lib/rgen/ecore/ecore_to_ruby.rb, line 193 def super_class(eclass, temp) super_types = eclass.eSuperTypes if temp case super_types.size when 0 RGen::MetamodelBuilder::MMBase when 1 create_class(super_types.first, temp) else RGen::MetamodelBuilder::MMMultiple(*super_types.collect{|t| create_class(t, temp)}) end else case super_types.size when 0 "RGen::MetamodelBuilder::MMBase" when 1 create_class(super_types.first, temp).name else "RGen::MetamodelBuilder::MMMultiple(" + super_types.collect{|t| create_class(t, temp).name}.join(",") + ")" end end end
# File lib/rgen/ecore/ecore_to_ruby.rb, line 223 def with_empty_constant_order_helper orig_coh = RGen::MetamodelBuilder::ConstantOrderHelper RGen::MetamodelBuilder.instance_eval { remove_const(:ConstantOrderHelper) } RGen::MetamodelBuilder.const_set(:ConstantOrderHelper, EmptyConstantOrderHelper.new) begin result = yield ensure RGen::MetamodelBuilder.instance_eval { remove_const(:ConstantOrderHelper) } RGen::MetamodelBuilder.const_set(:ConstantOrderHelper, orig_coh) end result end