rgen-0.7.0/ 0000755 0000041 0000041 00000000000 12352210062 012472 5 ustar www-data www-data rgen-0.7.0/Rakefile 0000644 0000041 0000041 00000003061 12352210062 014137 0 ustar www-data www-data require 'rubygems/package_task'
require 'rdoc/task'
RGenGemSpec = Gem::Specification.new do |s|
s.name = %q{rgen}
s.version = "0.7.0"
s.date = Time.now.strftime("%Y-%m-%d")
s.summary = %q{Ruby Modelling and Generator Framework}
s.email = %q{martin dot thiede at gmx de}
s.homepage = %q{http://ruby-gen.org}
s.rubyforge_project = %q{rgen}
s.description = %q{RGen is a framework for Model Driven Software Development (MDSD) in Ruby. This means that it helps you build Metamodels, instantiate Models, modify and transform Models and finally generate arbitrary textual content from it.}
s.authors = ["Martin Thiede"]
gemfiles = Rake::FileList.new
gemfiles.include("{lib,test}/**/*")
gemfiles.include("README.rdoc", "CHANGELOG", "MIT-LICENSE", "Rakefile")
gemfiles.exclude(/\b\.bak\b/)
s.files = gemfiles
s.rdoc_options = ["--main", "README.rdoc", "-x", "test", "-x", "metamodels", "-x", "ea_support/uml13*"]
s.extra_rdoc_files = ["README.rdoc", "CHANGELOG", "MIT-LICENSE"]
end
RDoc::Task.new do |rd|
rd.main = "README.rdoc"
rd.rdoc_files.include("README.rdoc", "CHANGELOG", "MIT-LICENSE", "lib/**/*.rb")
rd.rdoc_files.exclude("lib/metamodels/*")
rd.rdoc_files.exclude("lib/ea_support/uml13*")
rd.rdoc_dir = "doc"
end
RGenPackageTask = Gem::PackageTask.new(RGenGemSpec) do |p|
p.need_zip = false
end
task :prepare_package_rdoc => :rdoc do
RGenPackageTask.package_files.include("doc/**/*")
end
task :release => [:prepare_package_rdoc, :package]
task :clobber => [:clobber_rdoc, :clobber_package]
rgen-0.7.0/CHANGELOG 0000644 0000041 0000041 00000021222 12352210062 013703 0 ustar www-data www-data =0.1.0 (August 3rd, 2006)
* First public release
=0.2.0 (September 3rd, 2006)
* Added model transformation language (Transformer)
* Now RGen is distributed as a gem
* More complete documentation
=0.3.0 (October 9th, 2006)
* Improved XML Instantiator (Namespaces, Resolver, Customization)
* Added many_to_one builder method
* Added attribute reflection to MMBase (one_attributes, many_attributes)
* Added +copy+ method to Transformer
* Added simple model dumper module
* Fixed mmgen/mmgen.rb
=0.4.0 (Aug 8th, 2007)
* Added ECore metamodel and use it as the core metametamodel
* Revised and extended MetamodelBuilder language
* There is an ECore instance describing each metamodel built using MetamodelBuilder now
* Metamodel generator is now ECore based
* Added Ruby implementation of Boolean and Enum types
* Switched XML Instantiator to xmlscan for performance reasons
* Cleaned up instantiator file structure
* Renamed RGen::XMLInstantiator into RGen::Instantiator::DefaultXMLInstantiator
* Included xmlscan as a redistributed module
* Added support for chardata within XML tags
* Added (Enterprise Architect) XMI to ECore instantiator
* Some minor fixes in NameHelper
* Some fixes to template language
* Added UML1.3 Metamodel
* Added tranformation from UML1.3 to ECore
=0.4.1 (Nov 25th, 2007)
* Template language performance improvement
* Bugfix: use true/false instead of symbols for boolean attribute default values in metamodel classes
* Minor fixes on metamodel generator and ecore primitive type handling
* Made transformer implementation non-recursive to prevent "stack level too deep" exception for large models
* Minor fixes on EAInstantiator
* Made transformer search for matching rules for superclasses
* Bugfix: Enums are now added to EPackages created using the "ecore" method on a module
* Bugfix: Metamodel generator now writes enum names
* Performance improvement: don't require ecore transformer every time someone calls "ecore"
* Major performance improvement of template engine (no Regexps to check \n at end of line)
* Major performance improvement: AbstractXMLInstantiator optionally controls the garbage collector
* Major performance improvement: ERB templates are reused in metamodel_builder
* Added delete method to Environment
=0.4.2 (Mar 2nd, 2008)
* Performance improvement: collection feature of array extension uses hashes now to speed up array union
* Performance improvement: find on environment hashes elements by class
* Extended Transformer to allow sharing of result maps between several Transformer instances
* Bugfix: User defined upper bound values are no longer overwritten by -1 in all "many" metamodel builder methods
=0.4.3 (Aug 12th, 2008)
* Performance improvement: significant speed up of metamodel reverse registration
* Bugfix: Use object identity for metamodel to-many add/remove methods
* Bugfix: If expand's :for expression evaluates to nil an error is generated (silently used current context before)
* Template language indentation string can be set on DirectoryTemplateContainer and with the "file" command
=0.4.4 (Sep 10th, 2008)
* Added "abstract" metamodel DSL command
* Added ecore_ext.rb with convenience methods
* Added XMI1.1 serializer, revised XMLSerializer super class
=0.4.5 (Nov 17th, 2008)
* Updated XMI1.1 serializer to support explicit placement of elements on content level of the XMI file
=0.4.6 (Mar 1st, 2009)
* Bugfix: expand :foreach silently assumed current context if :foreach evalutated to nil
* Bugfix: fixed unit test for non-Windows plattforms (\r\n)
* Bugfix: depending on the Ruby version and/or platform constants used in templates could not be resolved
* Added automatic line ending detection (\n or \r\n) for template language +nl+ command
=0.5.0 (Jun 8th, 2009)
* Added ModelBuilder and ModelSerializer
* Added template language "define_local" command
* Added template language "evaluate" command
* Fixed template language bug: indentation problem when expand continues a non-empty line
* Fixed template language bug: template content expands several times when a template container is called recursively
* Fixed template language bug: template resolution problem if a template file has the same name as a template directory
* Cleaned up EA support
* Added method to clear ecore metamodel reflection cache
* Improved overriding of metamodel features in reopened classes
=0.5.1 (Nov 10th, 2009)
* Fixed metamodel builder bug: _register at one-side did not unregister from the element referenced by the old value
* Added helper class for building simple model comparators
=0.5.2 (Jun 13th, 2010)
* Added has_many_attr to metamodel builder, support for "many" attributes
* Added JSON support (json instantiator and serializer)
* Added QualifiedNameResolver instantiation helper
* Added reference proxy support
* Added more generic access methods on metaclasses
* Added ReferenceResolver resolver mixin
* Fixed ecore xml instantiator and serializer to handle references to builtin datatypes correctly
* Fixed bug in ecore xml serializer to not output references which are opposites of containment references
=0.5.3 (Aug 13th, 2010)
* Fixed string escaping in JSON instantiator and serializer
* Fixed order of eClassifiers and eSubpackages within an EPackage created by reflection on a RGen module
=0.5.4
* Fixed undeterministic order of child elements in ModelSerializer
* Fixed undeterministic order of attributes in XMI serializers
* Fixed ModelSerializer to always serialize the to-one part of bidirectional 1:N references
* Fixed ModelSerializer to add :as => in case of ambiguous child roles
* Made JsonInstantiator search subpackages for unqualified class names
=0.6.0
* Added exception when trying to instantiate abstract class
* Replaced xmlscan by dependency to nokogiri
* Made RGen work with Ruby 1.9
* Cleaned up intermediate attribute and reference description, improvement of metamodel load time
* Added optional data property for MMProxy
* Added ECoreToRuby which can create Ruby classes and modules from ECore models in memory (without metamodel generator)
* Refactored out QualifiedNameProvider and OppositeReferenceFilter
* Added model fragment/fragmented models support
* Extended Instantiator::ReferenceResolver and changed it into a class
* Moved utilities into util folder/module
* Added FileCacheMap
* Fixed template language bug: indenting not correct after callback into same template container and iinc/idec
* Added support for fragmented models
* Added FileChangeDetector utility
* Added CachedGlob utility
* Added index parameter to model element add methods
* Added MMGeneric
* Modified has_many_attr to allow the same value in the same attribute multiple times
* Made Environment#delete faster on large models
* Added type check of ecore defaultValueLiteral content in MetamodelBuilder
* Many-feature setters can work with an Enumerable instead of an Array
* Added pattern matcher utility
* Fixed problem of Ruby hanging when exceptions occur
* Fixed metamodel generator to quote illegal enum literal symbols
* Imporved UML to ECore transformer and EA support
=0.6.1
* Fixed metamodel builder to not overwrite a model element's 'class' method
* Added enum type transformation to ECoreToUML13 transformer, primitive type mapping based on instanceClassName
* Fixed default value appearing on read after setting a feature value to nil
* Added eIsSet and eUnset methods
* Added eContainer and eContainingFeature methods
* Fixed ModelFragment#elements not containing root elements
* Added optional output of invalidation reason to FileCacheMap#load_data
=0.6.2
* Made qualified name provider work with unidirectional containment references
* Fixed array_extension breaking the Hash[] method
=0.6.3
* Added BigDecimal support
=0.6.4
* Made FileChangeDetector and FileCacheMap robust against missing files
=0.6.5
* Fixed missing default argument of FragmentedModel#resolve
* Added to_str to methods which aren't forwarded by array extension on empty arrays
=0.6.6
* Added ModelFragment#mark_resolved and ResolutionHelper
* Added ReferenceResolver option to output failed resolutions
* Major performance improvement of FragmentedModel#resolve
* Fixed a Ruby 2.0 related warning
=0.7.0
* Enforce unique container rule by automatically disconnecting elements from other containers
* Added support for long typed values (ELong), thanks to Thomas Hallgren;
Note that this is merely an EMF compatibility thing, RGen could already handle big integers before
* Added eContents and eAllContents methods
* Added setNilOrRemoveGeneric and setNilOrRemoveAllGeneric methods
* Added disconnectContainer method
rgen-0.7.0/MIT-LICENSE 0000644 0000041 0000041 00000002041 12352210062 014123 0 ustar www-data www-data Copyright (c) 2013 Martin Thiede
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
rgen-0.7.0/README.rdoc 0000644 0000041 0000041 00000004067 12352210062 014307 0 ustar www-data www-data = RGen - Ruby Modelling and Generator Framework
RGen is a framework for Model Driven Software Development (MDSD)in Ruby.
This means that it helps you build Metamodels, instantiate Models, modify
and transform Models and finally generate arbitrary textual content from it.
RGen features include:
* Supporting Ruby 1.8.6, 1.8.7 and 1.9.x
* Metamodel definition language (internal Ruby DSL)
* ECore Meta-metamodel with an ECore instance available for every Metamodel
* Generator creating the Ruby metamodel definition from an ECore instance
* Transformer creating Ruby metamodel classes/modules from an ECore instance
* Instantiation of Metamodels, i.e. creation of Models (e.g. from XML)
* Model builder, internal Ruby DSL
* Model fragmentation over several several files and per-fragment caching
* Model Transformation language (internal Ruby DSL)
* Powerful template based generator language (internal Ruby DSL inside of ERB)
* UML 1.3 metamodel and XMI 1.1 instantiator included
* ECore XML support (XMI 2.0)
* UML-to-ECore and ECore-to-UML transformation (UML class models)
* Enterprise Architect support (UML1.3/XMI1.1)
== Download
Get the latest release from Github: https://github.com/mthiede/rgen
== Installation
Install RGen as a Ruby gem:
gem install rgen
== Running the Tests
Change to the 'test' folder and run the test suite:
cd test
ruby rgen_test.rb
== Documentation
RDoc documentation is available at Github: http://mthiede.github.com/rgen/
Find the main documentation parts for:
* RGen::MetamodelBuilder
* RGen::Transformer
* RGen::TemplateLanguage
* RGen::Fragment::FragmentedModel
== Examples
There are several examples of using RGen within the framework itself.
Metamodel Definition:
lib/rgen/ecore/ecore.rb
lib/metamodels/uml13_metamodel.rb
Instantiation:
lib/rgen/instantiator/xmi11_instantiator.rb
lib/rgen/instantiator/ecore_xml_instantiator.rb
Transformations:
lib/rgen/ecore/ruby_to_ecore.rb
lib/transformers/uml13_to_ecore.rb
Generators:
lib/mmgen/metamodel_generator.rb
== License
RGen is released under the MIT license.
rgen-0.7.0/lib/ 0000755 0000041 0000041 00000000000 12352210062 013240 5 ustar www-data www-data rgen-0.7.0/lib/ea_support/ 0000755 0000041 0000041 00000000000 12352210062 015421 5 ustar www-data www-data rgen-0.7.0/lib/ea_support/uml13_ea_metamodel_generator.rb 0000644 0000041 0000041 00000003623 12352210062 023455 0 ustar www-data www-data require 'metamodels/uml13_metamodel'
require 'mmgen/metamodel_generator'
require 'rgen/transformer'
require 'rgen/environment'
require 'rgen/ecore/ecore'
include MMGen::MetamodelGenerator
class ECoreCopyTransformer < RGen::Transformer
copy_all RGen::ECore
end
eaMMRoot = ECoreCopyTransformer.new.trans(UML13.ecore)
eaMMRoot.name = "UML13EA"
eaMMRoot.eClassifiers.find{|c| c.name == "ActivityGraph"}.name = "ActivityModel"
eaMMRoot.eClassifiers.find{|c| c.name == "Pseudostate"}.name = "PseudoState"
compositeState = eaMMRoot.eClassifiers.find{|c| c.name == "CompositeState"}
compositeState.eReferences.find{|r| r.name == "subvertex"}.name = "substate"
generalization = eaMMRoot.eClassifiers.find{|c| c.name == "Generalization"}
generalization.eReferences.find{|r| r.name == "parent"}.name = "supertype"
generalization.eReferences.find{|r| r.name == "child"}.name = "subtype"
assocEnd = eaMMRoot.eClassifiers.find{|c| c.name == "AssociationEnd"}
assocEnd.eAttributes.find{|r| r.name == "ordering"}.name = "isOrdered"
assocEnd.eAttributes.find{|r| r.name == "changeability"}.name = "changeable"
assocEnd.eAttributes.find{|r| r.name == "isOrdered"}.eType = RGen::ECore::EBoolean
assocEnd.eAttributes.find{|r| r.name == "changeable"}.eType.eLiterals.find{|l| l.name == "frozen"}.name = "none"
multRef = assocEnd.eStructuralFeatures.find{|f| f.name == "multiplicity"}
multRef.eType = nil
assocEnd.removeEStructuralFeatures(multRef)
assocEnd.addEStructuralFeatures(RGen::ECore::EAttribute.new(:name => "multiplicity", :eType => RGen::ECore::EString))
xmiIdProvider = RGen::ECore::EClass.new(:name => "XmiIdProvider", :ePackage => eaMMRoot)
eaMMRoot.eClassifiers.each do |c|
if %w(Package Class Generalization Association AssociationEnd StateVertex).include?(c.name)
c.addESuperTypes(xmiIdProvider)
end
end
generateMetamodel(eaMMRoot, File.dirname(__FILE__)+"/uml13_ea_metamodel.rb")
rgen-0.7.0/lib/ea_support/id_store.rb 0000644 0000041 0000041 00000001176 12352210062 017563 0 ustar www-data www-data require 'yaml'
class IdStore
def initialize(fileName=nil)
if fileName
raise "Base directory does not exist: #{File.dirname(fileName)}" \
unless File.exist?(File.dirname(fileName))
@idsFileName = fileName
end
@idHash = nil
end
def idHash
load unless @idHash
@idHash
end
def load
if @idsFileName && File.exist?(@idsFileName)
@idHash = YAML.load_file(@idsFileName) || {}
else
@idHash = {}
end
end
def store
return unless @idsFileName
File.open(@idsFileName,"w") do |f|
YAML.dump(@idHash, f)
end
end
end rgen-0.7.0/lib/ea_support/uml13_ea_metamodel_ext.rb 0000644 0000041 0000041 00000002203 12352210062 022260 0 ustar www-data www-data module UML13EA
class << self
attr_accessor :idStore
end
module ModelElement::ClassModule
def qualifiedName
_name = (respond_to?(:_name) ? self._name : name) || "unnamed"
_namespace = respond_to?(:_namespace) ? self._namespace : namespace
_namespace && _namespace.qualifiedName ? _namespace.qualifiedName+"::"+_name : _name
end
end
module XmiIdProvider::ClassModule
def _xmi_id
UML13EA.idStore.idHash[qualifiedName] ||= "EAID_"+object_id.to_s
end
end
module Package::ClassModule
def _xmi_id
UML13EA.idStore.idHash[qualifiedName] ||= "EAPK_"+object_id.to_s
end
end
module Generalization::ClassModule
def _name
"#{subtype.name}_#{supertype.name}"
end
end
module Association::ClassModule
def _name
connection.collect{|c| "#{c.getType.name}_#{c.name}"}.sort.join("_")
end
end
module AssociationEnd::ClassModule
def _name
"#{getType.name}_#{name}"
end
def _namespace
association
end
end
module StateVertex::ClassModule
def _namespace
container
end
end
end
rgen-0.7.0/lib/ea_support/uml13_ea_to_uml13.rb 0000644 0000041 0000041 00000006355 12352210062 021110 0 ustar www-data www-data require 'rgen/transformer'
require 'metamodels/uml13_metamodel'
require 'ea_support/uml13_ea_metamodel'
class UML13EAToUML13 < RGen::Transformer
include UML13EA
def transform
trans(:class => Package)
trans(:class => Class)
@env_out.find(:class => UML13::Attribute).each do |me|
# remove tagged vales internally used by EA which have been converted to UML
me.taggedValue = me.taggedValue.reject{|tv| ["lowerBound", "upperBound"].include?(tv.tag)}
end
end
def cleanModel
@env_out.find(:class => UML13::ModelElement).each do |me|
me.taggedValue = []
end
end
copy_all UML13EA, :to => UML13, :except => %w(
XmiIdProvider
AssociationEnd AssociationEndRole
StructuralFeature
Attribute
Generalization
ActivityModel
CompositeState
PseudoState
Dependency
)
transform AssociationEndRole, :to => UML13::AssociationEndRole do
copyAssociationEnd
end
transform AssociationEnd, :to => UML13::AssociationEnd do
copyAssociationEnd
end
def copyAssociationEnd
copy_features :except => [:isOrdered, :changeable] do
{:ordering => isOrdered ? :ordered : :unordered,
:changeability => {:none => :frozen}[changeable] || changeable,
:aggregation => {:shared => :aggregate}[aggregation] || aggregation,
:multiplicity => UML13::Multiplicity.new(
:range => [UML13::MultiplicityRange.new(
:lower => multiplicity && multiplicity.split("..").first,
:upper => multiplicity && multiplicity.split("..").last)])}
end
end
transform StructuralFeature, :to => UML13::StructuralFeature,
:if => lambda{|c| !@current_object.is_a?(UML13EA::Attribute)} do
copy_features :except => [:changeable] do
{:changeability => {:none => :frozen}[changeable] }
end
end
transform StructuralFeature, :to => UML13::Attribute,
:if => lambda{|c| @current_object.is_a?(UML13EA::Attribute)} do
_lowerBound = taggedValue.find{|tv| tv.tag == "lowerBound"}
_upperBound = taggedValue.find{|tv| tv.tag == "upperBound"}
if _lowerBound || _upperBound
_multiplicity = UML13::Multiplicity.new(
:range => [UML13::MultiplicityRange.new(
:lower => (_lowerBound && _lowerBound.value) || "0",
:upper => (_upperBound && _upperBound.value) || "1"
)])
end
copy_features :except => [:changeable] do
{:changeability => {:none => :frozen}[changeable],
:multiplicity => _multiplicity }
end
end
transform Generalization, :to => UML13::Generalization do
copy_features :except => [:subtype, :supertype] do
{ :child => trans(subtype),
:parent => trans(supertype) }
end
end
copy ActivityModel, :to => UML13::ActivityGraph
transform CompositeState, :to => UML13::CompositeState do
copy_features :except => [:substate] do
{ :subvertex => trans(substate) }
end
end
copy PseudoState, :to => UML13::Pseudostate
transform Dependency, :to => UML13::Dependency do
_name_tag = taggedValue.find{|tv| tv.tag == "dst_name"}
copy_features do
{ :name => (_name_tag && _name_tag.value) || "Anonymous" }
end
end
end
rgen-0.7.0/lib/ea_support/uml13_to_uml13_ea.rb 0000644 0000041 0000041 00000006057 12352210062 021107 0 ustar www-data www-data require 'rgen/transformer'
require 'metamodels/uml13_metamodel'
require 'ea_support/uml13_ea_metamodel'
require 'ea_support/uml13_ea_metamodel_ext'
class UML13ToUML13EA < RGen::Transformer
include UML13
def transform
trans(:class => Package)
trans(:class => Class)
end
copy_all UML13, :to => UML13EA, :except => %w(
ActivityGraph
CompositeState SimpleState
Class
Association AssociationEnd AssociationEndRole
Generalization
Pseudostate
Attribute
)
copy ActivityGraph, :to => UML13EA::ActivityModel
copy Pseudostate, :to => UML13EA::PseudoState
transform CompositeState, :to => UML13EA::CompositeState do
copy_features :except => [:subvertex] do
{ :substate => trans(subvertex) }
end
end
transform SimpleState, :to => UML13EA::SimpleState do
copy_features :except => [:container] do
{ :taggedValue => trans(taggedValue) +
[@env_out.new(UML13EA::TaggedValue, :tag => "ea_stype", :value => "State")] +
(container ? [ @env_out.new(UML13EA::TaggedValue, :tag => "owner", :value => trans(container)._xmi_id)] : []) }
end
end
transform Class, :to => UML13EA::Class do
copy_features do
{ :taggedValue => trans(taggedValue) + [@env_out.new(UML13EA::TaggedValue, :tag => "ea_stype", :value => "Class")]}
end
end
transform Association, :to => UML13EA::Association do
copy_features do
{ :connection => trans(connection[1].isNavigable ? [connection[0], connection[1]] : [connection[1], connection[0]]),
:taggedValue => trans(taggedValue) + [
@env_out.new(UML13EA::TaggedValue, :tag => "ea_type", :value => "Association"),
@env_out.new(UML13EA::TaggedValue, :tag => "direction", :value =>
connection.all?{|c| c.isNavigable} ? "Bi-Directional" : "Source -> Destination")] }
end
end
transform AssociationEnd, :to => UML13EA::AssociationEnd do
copyAssociationEnd
end
transform AssociationEndRole, :to => UML13EA::AssociationEndRole do
copyAssociationEnd
end
def copyAssociationEnd
_lower = multiplicity && multiplicity.range.first.lower
_upper = multiplicity && multiplicity.range.first.upper
copy_features :except => [:multiplicity, :ordering, :changeability] do
{ :multiplicity => _lower == _upper ? _lower : "#{_lower}..#{_upper}",
:isOrdered => ordering == :ordered,
:changeable => :none } #{:frozen => :none}[changeability] || changeability}
end
end
transform Attribute, :to => UML13EA::Attribute do
copy_features :except => [:changeability] do
{ :changeable => {:frozen => :none}[changeability] }
end
end
transform Generalization, :to => UML13EA::Generalization do
copy_features :except => [:child, :parent] do
{ :taggedValue => trans(taggedValue) + [@env_out.new(UML13EA::TaggedValue, :tag => "ea_type", :value => "Generalization")],
:subtype => trans(child),
:supertype => trans(parent)}
end
end
end
rgen-0.7.0/lib/ea_support/uml13_ea_metamodel.rb 0000644 0000041 0000041 00000052055 12352210062 021412 0 ustar www-data www-data require 'rgen/metamodel_builder'
module UML13EA
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
OperationDirectionKind = Enum.new(:name => 'OperationDirectionKind', :literals =>[ ])
MessageDirectionKind = Enum.new(:name => 'MessageDirectionKind', :literals =>[ ])
ChangeableKind = Enum.new(:name => 'ChangeableKind', :literals =>[ :changeable, :none, :addOnly ])
PseudostateKind = Enum.new(:name => 'PseudostateKind', :literals =>[ :initial, :deepHistory, :shallowHistory, :join, :fork, :branch, :junction, :final ])
ParameterDirectionKind = Enum.new(:name => 'ParameterDirectionKind', :literals =>[ :in, :inout, :out, :return ])
ScopeKind = Enum.new(:name => 'ScopeKind', :literals =>[ :instance, :classifier ])
OrderingKind = Enum.new(:name => 'OrderingKind', :literals =>[ :unordered, :ordered, :sorted ])
CallConcurrencyKind = Enum.new(:name => 'CallConcurrencyKind', :literals =>[ :sequential, :guarded, :concurrent ])
AggregationKind = Enum.new(:name => 'AggregationKind', :literals =>[ :none, :aggregate, :composite, :shared ])
VisibilityKind = Enum.new(:name => 'VisibilityKind', :literals =>[ :public, :protected, :private ])
end
class UML13EA::Expression < RGen::MetamodelBuilder::MMBase
has_attr 'language', String
has_attr 'body', String
end
class UML13EA::ActionExpression < UML13EA::Expression
end
class UML13EA::Element < RGen::MetamodelBuilder::MMBase
end
class UML13EA::ModelElement < UML13EA::Element
has_attr 'name', String
has_attr 'visibility', UML13EA::VisibilityKind, :defaultValueLiteral => "public"
has_attr 'isSpecification', Boolean
end
class UML13EA::Namespace < UML13EA::ModelElement
end
class UML13EA::GeneralizableElement < UML13EA::ModelElement
has_attr 'isRoot', Boolean
has_attr 'isLeaf', Boolean
has_attr 'isAbstract', Boolean
end
class UML13EA::Classifier < RGen::MetamodelBuilder::MMMultiple(UML13EA::GeneralizableElement, UML13EA::Namespace)
end
class UML13EA::ClassifierRole < UML13EA::Classifier
end
class UML13EA::PresentationElement < UML13EA::Element
end
class UML13EA::DiagramElement < UML13EA::PresentationElement
has_attr 'geometry', String
has_attr 'style', String
end
class UML13EA::Feature < UML13EA::ModelElement
has_attr 'ownerScope', UML13EA::ScopeKind, :defaultValueLiteral => "instance"
end
class UML13EA::BehavioralFeature < UML13EA::Feature
has_attr 'isQuery', Boolean
end
class UML13EA::Method < UML13EA::BehavioralFeature
end
class UML13EA::Actor < UML13EA::Classifier
end
class UML13EA::DataType < UML13EA::Classifier
end
class UML13EA::Primitive < UML13EA::DataType
end
class UML13EA::Action < UML13EA::ModelElement
has_attr 'isAsynchronous', Boolean
end
class UML13EA::SendAction < UML13EA::Action
end
class UML13EA::Interface < UML13EA::Classifier
end
class UML13EA::Event < UML13EA::ModelElement
end
class UML13EA::ChangeEvent < UML13EA::Event
end
class UML13EA::Partition < UML13EA::ModelElement
end
class UML13EA::Comment < UML13EA::ModelElement
has_attr 'body', String
end
class UML13EA::ProgrammingLanguageType < UML13EA::DataType
end
class UML13EA::StateMachine < UML13EA::ModelElement
end
class UML13EA::Call < RGen::MetamodelBuilder::MMBase
end
class UML13EA::Operation < UML13EA::BehavioralFeature
has_attr 'concurrency', UML13EA::CallConcurrencyKind, :defaultValueLiteral => "sequential"
has_attr 'isRoot', Boolean
has_attr 'isLeaf', Boolean
has_attr 'isAbstract', Boolean
end
class UML13EA::XmiIdProvider < RGen::MetamodelBuilder::MMBase
end
class UML13EA::StateVertex < RGen::MetamodelBuilder::MMMultiple(UML13EA::ModelElement, UML13EA::XmiIdProvider)
end
class UML13EA::SynchState < UML13EA::StateVertex
has_attr 'bound', Integer
end
class UML13EA::ClassifierInState < UML13EA::Classifier
end
class UML13EA::Link < UML13EA::ModelElement
end
class UML13EA::ProcedureExpression < UML13EA::Expression
end
class UML13EA::CallEvent < UML13EA::Event
end
class UML13EA::AssignmentAction < UML13EA::Action
end
class UML13EA::Relationship < UML13EA::ModelElement
end
class UML13EA::Association < RGen::MetamodelBuilder::MMMultiple(UML13EA::GeneralizableElement, UML13EA::Relationship, UML13EA::XmiIdProvider)
end
class UML13EA::AssociationRole < UML13EA::Association
end
class UML13EA::Diagram < UML13EA::PresentationElement
has_attr 'name', String
has_attr 'toolName', String
has_attr 'diagramType', String
has_attr 'style', String
end
class UML13EA::MultiplicityRange < RGen::MetamodelBuilder::MMBase
has_attr 'lower', String
has_attr 'upper', String
end
class UML13EA::ActionSequence < UML13EA::Action
end
class UML13EA::Constraint < UML13EA::ModelElement
end
class UML13EA::Instance < UML13EA::ModelElement
end
class UML13EA::UseCaseInstance < UML13EA::Instance
end
class UML13EA::State < UML13EA::StateVertex
end
class UML13EA::CompositeState < UML13EA::State
has_attr 'isConcurrent', Boolean
end
class UML13EA::SubmachineState < UML13EA::CompositeState
end
class UML13EA::SubactivityState < UML13EA::SubmachineState
has_attr 'isDynamic', Boolean
end
class UML13EA::StructuralFeature < UML13EA::Feature
has_attr 'changeable', UML13EA::ChangeableKind, :defaultValueLiteral => "changeable"
has_attr 'targetScope', UML13EA::ScopeKind, :defaultValueLiteral => "instance"
end
class UML13EA::Attribute < UML13EA::StructuralFeature
end
class UML13EA::Flow < UML13EA::Relationship
end
class UML13EA::Class < RGen::MetamodelBuilder::MMMultiple(UML13EA::Classifier, UML13EA::XmiIdProvider)
has_attr 'isActive', Boolean
end
class UML13EA::Guard < UML13EA::ModelElement
end
class UML13EA::CreateAction < UML13EA::Action
end
class UML13EA::IterationExpression < UML13EA::Expression
end
class UML13EA::ReturnAction < UML13EA::Action
end
class UML13EA::Parameter < UML13EA::ModelElement
has_attr 'kind', UML13EA::ParameterDirectionKind, :defaultValueLiteral => "inout"
end
class UML13EA::Dependency < UML13EA::Relationship
end
class UML13EA::Binding < UML13EA::Dependency
end
class UML13EA::Package < RGen::MetamodelBuilder::MMMultiple(UML13EA::Namespace, UML13EA::GeneralizableElement, UML13EA::XmiIdProvider)
end
class UML13EA::ObjectSetExpression < UML13EA::Expression
end
class UML13EA::StubState < UML13EA::StateVertex
has_attr 'referenceState', String
end
class UML13EA::Stereotype < UML13EA::GeneralizableElement
has_attr 'icon', String
has_attr 'baseClass', String
end
class UML13EA::Object < UML13EA::Instance
end
class UML13EA::LinkObject < RGen::MetamodelBuilder::MMMultiple(UML13EA::Link, UML13EA::Object)
end
class UML13EA::ComponentInstance < UML13EA::Instance
end
class UML13EA::Usage < UML13EA::Dependency
end
class UML13EA::SignalEvent < UML13EA::Event
end
class UML13EA::Structure < UML13EA::DataType
end
class UML13EA::AssociationEnd < RGen::MetamodelBuilder::MMMultiple(UML13EA::ModelElement, UML13EA::XmiIdProvider)
has_attr 'isNavigable', Boolean, :defaultValueLiteral => "false"
has_attr 'isOrdered', Boolean, :defaultValueLiteral => "false"
has_attr 'aggregation', UML13EA::AggregationKind, :defaultValueLiteral => "none"
has_attr 'targetScope', UML13EA::ScopeKind, :defaultValueLiteral => "instance"
has_attr 'changeable', UML13EA::ChangeableKind, :defaultValueLiteral => "changeable"
has_attr 'multiplicity', String
end
class UML13EA::AssociationEndRole < UML13EA::AssociationEnd
end
class UML13EA::Signal < UML13EA::Classifier
end
class UML13EA::Exception < UML13EA::Signal
end
class UML13EA::Extend < UML13EA::Relationship
end
class UML13EA::Argument < UML13EA::ModelElement
end
class UML13EA::TemplateParameter < RGen::MetamodelBuilder::MMBase
end
class UML13EA::PseudoState < UML13EA::StateVertex
has_attr 'kind', UML13EA::PseudostateKind, :defaultValueLiteral => "initial"
end
class UML13EA::SimpleState < UML13EA::State
end
class UML13EA::ActionState < UML13EA::SimpleState
has_attr 'isDynamic', Boolean
end
class UML13EA::TypeExpression < UML13EA::Expression
end
class UML13EA::DestroyAction < UML13EA::Action
end
class UML13EA::TerminateAction < UML13EA::Action
end
class UML13EA::Generalization < RGen::MetamodelBuilder::MMMultiple(UML13EA::Relationship, UML13EA::XmiIdProvider)
has_attr 'discriminator', String
end
class UML13EA::FinalState < UML13EA::State
end
class UML13EA::Subsystem < RGen::MetamodelBuilder::MMMultiple(UML13EA::Package, UML13EA::Classifier)
has_attr 'isInstantiable', Boolean
end
class UML13EA::TimeExpression < UML13EA::Expression
end
class UML13EA::TaggedValue < UML13EA::Element
has_attr 'tag', String
has_attr 'value', String
end
class UML13EA::DataValue < UML13EA::Instance
end
class UML13EA::Transition < UML13EA::ModelElement
end
class UML13EA::NodeInstance < UML13EA::Instance
end
class UML13EA::Component < UML13EA::Classifier
end
class UML13EA::Message < UML13EA::ModelElement
end
class UML13EA::Enumeration < UML13EA::DataType
end
class UML13EA::Reception < UML13EA::BehavioralFeature
has_attr 'isPolymorphic', Boolean
has_attr 'specification', String
end
class UML13EA::Include < UML13EA::Relationship
end
class UML13EA::CallState < UML13EA::ActionState
end
class UML13EA::ElementResidence < RGen::MetamodelBuilder::MMBase
has_attr 'visibility', UML13EA::VisibilityKind, :defaultValueLiteral => "public"
end
class UML13EA::UninterpretedAction < UML13EA::Action
end
class UML13EA::ArgListsExpression < UML13EA::Expression
end
class UML13EA::Stimulus < UML13EA::ModelElement
end
class UML13EA::AssociationClass < RGen::MetamodelBuilder::MMMultiple(UML13EA::Class, UML13EA::Association)
end
class UML13EA::Node < UML13EA::Classifier
end
class UML13EA::ElementImport < RGen::MetamodelBuilder::MMBase
has_attr 'visibility', UML13EA::VisibilityKind, :defaultValueLiteral => "public"
has_attr 'alias', String
end
class UML13EA::BooleanExpression < UML13EA::Expression
end
class UML13EA::Collaboration < RGen::MetamodelBuilder::MMMultiple(UML13EA::GeneralizableElement, UML13EA::Namespace)
end
class UML13EA::CallAction < UML13EA::Action
end
class UML13EA::UseCase < UML13EA::Classifier
end
class UML13EA::ActivityModel < UML13EA::StateMachine
end
class UML13EA::Permission < UML13EA::Dependency
end
class UML13EA::Interaction < UML13EA::ModelElement
end
class UML13EA::EnumerationLiteral < RGen::MetamodelBuilder::MMBase
has_attr 'name', String
end
class UML13EA::Model < UML13EA::Package
end
class UML13EA::LinkEnd < UML13EA::ModelElement
end
class UML13EA::ExtensionPoint < UML13EA::ModelElement
has_attr 'location', String
end
class UML13EA::Multiplicity < RGen::MetamodelBuilder::MMBase
end
class UML13EA::ObjectFlowState < UML13EA::SimpleState
has_attr 'isSynch', Boolean
end
class UML13EA::AttributeLink < UML13EA::ModelElement
end
class UML13EA::MappingExpression < UML13EA::Expression
end
class UML13EA::TimeEvent < UML13EA::Event
end
class UML13EA::Abstraction < UML13EA::Dependency
end
class UML13EA::ActionInstance < RGen::MetamodelBuilder::MMBase
end
UML13EA::ClassifierRole.contains_one_uni 'multiplicity', UML13EA::Multiplicity
UML13EA::ClassifierRole.has_many 'availableContents', UML13EA::ModelElement
UML13EA::ClassifierRole.has_many 'availableFeature', UML13EA::Feature
UML13EA::ClassifierRole.has_one 'base', UML13EA::Classifier, :lowerBound => 1
UML13EA::Diagram.contains_many 'element', UML13EA::DiagramElement, 'diagram'
UML13EA::Method.many_to_one 'specification', UML13EA::Operation, 'method'
UML13EA::Method.contains_one_uni 'body', UML13EA::ProcedureExpression
UML13EA::SendAction.has_one 'signal', UML13EA::Signal, :lowerBound => 1
UML13EA::ChangeEvent.contains_one_uni 'changeExpression', UML13EA::BooleanExpression
UML13EA::Partition.has_many 'contents', UML13EA::ModelElement
UML13EA::Comment.many_to_many 'annotatedElement', UML13EA::ModelElement, 'comment'
UML13EA::ProgrammingLanguageType.contains_one_uni 'type', UML13EA::TypeExpression
UML13EA::Action.contains_one_uni 'recurrence', UML13EA::IterationExpression
UML13EA::Action.contains_one_uni 'target', UML13EA::ObjectSetExpression
UML13EA::Action.contains_one_uni 'script', UML13EA::ActionExpression
UML13EA::Action.contains_many_uni 'actualArgument', UML13EA::Argument
UML13EA::StateMachine.many_to_one 'context', UML13EA::ModelElement, 'behavior'
UML13EA::StateMachine.contains_many_uni 'transitions', UML13EA::Transition
UML13EA::StateMachine.contains_one_uni 'top', UML13EA::State, :lowerBound => 1
UML13EA::Operation.one_to_many 'occurrence', UML13EA::CallEvent, 'operation'
UML13EA::ClassifierInState.has_one 'type', UML13EA::Classifier, :lowerBound => 1
UML13EA::ClassifierInState.has_many 'inState', UML13EA::State
UML13EA::Link.contains_many_uni 'connection', UML13EA::LinkEnd, :lowerBound => 2
UML13EA::Link.has_one 'association', UML13EA::Association, :lowerBound => 1
UML13EA::PresentationElement.many_to_many 'subject', UML13EA::ModelElement, 'presentation'
UML13EA::AssociationRole.contains_one_uni 'multiplicity', UML13EA::Multiplicity
UML13EA::AssociationRole.has_one 'base', UML13EA::Association
UML13EA::Diagram.has_one 'owner', UML13EA::ModelElement, :lowerBound => 1
UML13EA::ActionSequence.contains_many_uni 'action', UML13EA::Action
UML13EA::Constraint.contains_one_uni 'body', UML13EA::BooleanExpression
UML13EA::Constraint.many_to_many 'constrainedElement', UML13EA::ModelElement, 'constraint', :lowerBound => 1
UML13EA::SubactivityState.contains_one_uni 'dynamicArguments', UML13EA::ArgListsExpression
UML13EA::AssociationEnd.contains_many 'qualifier', UML13EA::Attribute, 'associationEnd'
UML13EA::Attribute.contains_one_uni 'initialValue', UML13EA::Expression
UML13EA::Flow.many_to_many 'source', UML13EA::ModelElement, 'sourceFlow'
UML13EA::Flow.many_to_many 'target', UML13EA::ModelElement, 'targetFlow'
UML13EA::Guard.contains_one_uni 'expression', UML13EA::BooleanExpression
UML13EA::CreateAction.has_one 'instantiation', UML13EA::Classifier, :lowerBound => 1
UML13EA::Namespace.contains_many 'ownedElement', UML13EA::ModelElement, 'namespace'
UML13EA::Parameter.contains_one_uni 'defaultValue', UML13EA::Expression
UML13EA::Parameter.many_to_many 'state', UML13EA::ObjectFlowState, 'parameter'
UML13EA::Parameter.has_one 'type', UML13EA::Classifier, :lowerBound => 1
UML13EA::Binding.has_many 'argument', UML13EA::ModelElement, :lowerBound => 1
UML13EA::Event.contains_many_uni 'parameters', UML13EA::Parameter
UML13EA::Dependency.many_to_many 'supplier', UML13EA::ModelElement, 'supplierDependency', :opposite_lowerBound => 1
UML13EA::Dependency.many_to_many 'client', UML13EA::ModelElement, 'clientDependency', :opposite_lowerBound => 1
UML13EA::Package.contains_many 'importedElement', UML13EA::ElementImport, 'package'
UML13EA::Classifier.contains_many 'feature', UML13EA::Feature, 'owner'
UML13EA::Stereotype.one_to_many 'extendedElement', UML13EA::ModelElement, 'stereotype'
UML13EA::Stereotype.has_many 'requiredTag', UML13EA::TaggedValue
UML13EA::ComponentInstance.has_many 'resident', UML13EA::Instance
UML13EA::SignalEvent.many_to_one 'signal', UML13EA::Signal, 'occurrence', :lowerBound => 1
UML13EA::Instance.contains_many_uni 'slot', UML13EA::AttributeLink
UML13EA::Instance.one_to_many 'linkEnd', UML13EA::LinkEnd, 'instance'
UML13EA::Instance.has_many 'classifier', UML13EA::Classifier, :lowerBound => 1
UML13EA::AssociationEndRole.has_many 'availableQualifier', UML13EA::Attribute
UML13EA::AssociationEndRole.has_one 'base', UML13EA::AssociationEnd
UML13EA::Extend.many_to_one 'extension', UML13EA::UseCase, 'extend'
UML13EA::Extend.contains_one_uni 'condition', UML13EA::BooleanExpression
UML13EA::Extend.has_many 'extensionPoint', UML13EA::ExtensionPoint, :lowerBound => 1
UML13EA::Extend.has_one 'base', UML13EA::UseCase, :lowerBound => 1
UML13EA::Argument.contains_one_uni 'value', UML13EA::Expression
UML13EA::TemplateParameter.has_one 'modelElement', UML13EA::ModelElement
UML13EA::TemplateParameter.has_one 'defaultElement', UML13EA::ModelElement
UML13EA::ActionState.contains_one_uni 'dynamicArguments', UML13EA::ArgListsExpression
UML13EA::GeneralizableElement.one_to_many 'specialization', UML13EA::Generalization, 'supertype'
UML13EA::GeneralizableElement.one_to_many 'generalization', UML13EA::Generalization, 'subtype'
UML13EA::StateVertex.one_to_many 'incoming', UML13EA::Transition, 'target', :opposite_lowerBound => 1
UML13EA::StateVertex.one_to_many 'outgoing', UML13EA::Transition, 'source', :opposite_lowerBound => 1
UML13EA::CompositeState.contains_many 'substate', UML13EA::StateVertex, 'container', :lowerBound => 1
UML13EA::ModelElement.contains_many 'taggedValue', UML13EA::TaggedValue, 'modelElement'
UML13EA::StructuralFeature.contains_one_uni 'multiplicity', UML13EA::Multiplicity
UML13EA::StructuralFeature.has_one 'type', UML13EA::Classifier, :lowerBound => 1
UML13EA::Transition.has_one 'trigger', UML13EA::Event
UML13EA::Transition.contains_one_uni 'effect', UML13EA::Action
UML13EA::Transition.contains_one_uni 'guard', UML13EA::Guard
UML13EA::NodeInstance.has_many 'resident', UML13EA::ComponentInstance
UML13EA::Component.contains_many 'residentElement', UML13EA::ElementResidence, 'implementationLocation'
UML13EA::Component.many_to_many 'deploymentLocation', UML13EA::Node, 'resident'
UML13EA::Message.has_one 'action', UML13EA::Action, :lowerBound => 1
UML13EA::Message.has_one 'communicationConnection', UML13EA::AssociationRole
UML13EA::Message.has_many 'predecessor', UML13EA::Message
UML13EA::Message.has_one 'receiver', UML13EA::ClassifierRole, :lowerBound => 1
UML13EA::Message.has_one 'sender', UML13EA::ClassifierRole, :lowerBound => 1
UML13EA::Message.has_one 'activator', UML13EA::Message
UML13EA::Interaction.contains_many 'message', UML13EA::Message, 'interaction', :lowerBound => 1
UML13EA::ModelElement.one_to_many 'elementResidence', UML13EA::ElementResidence, 'resident'
UML13EA::ModelElement.contains_many_uni 'templateParameter', UML13EA::TemplateParameter
UML13EA::ModelElement.one_to_many 'elementImport', UML13EA::ElementImport, 'modelElement'
UML13EA::Enumeration.contains_many_uni 'literal', UML13EA::EnumerationLiteral, :lowerBound => 1
UML13EA::Reception.many_to_one 'signal', UML13EA::Signal, 'reception'
UML13EA::Association.contains_many 'connection', UML13EA::AssociationEnd, 'association', :lowerBound => 2
UML13EA::Include.many_to_one 'base', UML13EA::UseCase, 'include'
UML13EA::Include.has_one 'addition', UML13EA::UseCase, :lowerBound => 1
UML13EA::Classifier.many_to_many 'participant', UML13EA::AssociationEnd, 'specification'
UML13EA::Classifier.one_to_many 'associationEnd', UML13EA::AssociationEnd, 'type'
UML13EA::Stimulus.has_one 'dispatchAction', UML13EA::Action, :lowerBound => 1
UML13EA::Stimulus.has_one 'communicationLink', UML13EA::Link
UML13EA::Stimulus.has_one 'receiver', UML13EA::Instance, :lowerBound => 1
UML13EA::Stimulus.has_one 'sender', UML13EA::Instance, :lowerBound => 1
UML13EA::Stimulus.has_many 'argument', UML13EA::Instance
UML13EA::State.contains_one_uni 'doActivity', UML13EA::Action
UML13EA::State.contains_many_uni 'internalTransition', UML13EA::Transition
UML13EA::State.has_many 'deferrableEvent', UML13EA::Event
UML13EA::State.contains_one_uni 'exit', UML13EA::Action
UML13EA::State.contains_one_uni 'entry', UML13EA::Action
UML13EA::Collaboration.has_one 'representedOperation', UML13EA::Operation
UML13EA::Collaboration.has_one 'representedClassifier', UML13EA::Classifier
UML13EA::Collaboration.has_many 'constrainingElement', UML13EA::ModelElement
UML13EA::Collaboration.contains_many 'interaction', UML13EA::Interaction, 'context'
UML13EA::CallAction.has_one 'operation', UML13EA::Operation, :lowerBound => 1
UML13EA::UseCase.has_many 'extensionPoint', UML13EA::ExtensionPoint
UML13EA::ActivityModel.contains_many_uni 'partition', UML13EA::Partition
UML13EA::Interaction.contains_many_uni 'link', UML13EA::Link
UML13EA::LinkEnd.has_one 'associationEnd', UML13EA::AssociationEnd, :lowerBound => 1
UML13EA::LinkEnd.has_one 'participant', UML13EA::Instance, :lowerBound => 1
UML13EA::BehavioralFeature.many_to_many 'raisedSignal', UML13EA::Signal, 'context'
UML13EA::BehavioralFeature.contains_many_uni 'parameter', UML13EA::Parameter
UML13EA::SubmachineState.has_one 'submachine', UML13EA::StateMachine, :lowerBound => 1
UML13EA::Multiplicity.contains_many_uni 'range', UML13EA::MultiplicityRange, :lowerBound => 1
UML13EA::ObjectFlowState.has_one 'type', UML13EA::Classifier, :lowerBound => 1
UML13EA::ObjectFlowState.has_one 'available', UML13EA::Parameter, :lowerBound => 1
UML13EA::AttributeLink.has_one 'value', UML13EA::Instance, :lowerBound => 1
UML13EA::AttributeLink.has_one 'attribute', UML13EA::Attribute, :lowerBound => 1
UML13EA::TimeEvent.contains_one_uni 'when', UML13EA::TimeExpression
UML13EA::Abstraction.contains_one_uni 'mapping', UML13EA::MappingExpression
rgen-0.7.0/lib/ea_support/ea_support.rb 0000644 0000041 0000041 00000003324 12352210062 020131 0 ustar www-data www-data require 'ea_support/uml13_ea_metamodel'
require 'ea_support/uml13_ea_metamodel_ext'
require 'ea_support/uml13_to_uml13_ea'
require 'ea_support/uml13_ea_to_uml13'
require 'ea_support/id_store'
require 'rgen/serializer/xmi11_serializer'
require 'rgen/instantiator/xmi11_instantiator'
require 'rgen/environment'
module EASupport
FIXMAP = {
:tags => {
"EAStub" => proc { |tag, attr|
UML13EA::Class.new(:name => attr["name"]) if attr["UMLType"] == "Class"
}
}
}
INFO = XMI11Instantiator::INFO
WARN = XMI11Instantiator::WARN
ERROR = XMI11Instantiator::ERROR
def self.instantiateUML13FromXMI11(envUML, fileName, options={})
envUMLEA = RGen::Environment.new
xmiInst = XMI11Instantiator.new(envUMLEA, FIXMAP, options[:loglevel] || ERROR)
xmiInst.add_metamodel("omg.org/UML1.3", UML13EA)
File.open(fileName) do |f|
xmiInst.instantiate(f.read)
end
trans = UML13EAToUML13.new(envUMLEA, envUML)
trans.transform
trans.cleanModel if options[:clean_model]
end
def self.serializeUML13ToXMI11(envUML, fileName, options={})
envUMLEA = RGen::Environment.new
UML13EA.idStore = options[:keep_ids] ?
IdStore.new(File.dirname(fileName)+"/"+File.basename(fileName)+".ids") : IdStore.new
UML13ToUML13EA.new(envUML, envUMLEA).transform
File.open(fileName, "w") do |f|
xmiSer = RGen::Serializer::XMI11Serializer.new(f)
xmiSer.setNamespace("UML","omg.org/UML1.3")
xmiSer.serialize(envUMLEA.find(:class => UML13EA::Model).first,
{:documentation => {:exporter => "Enterprise Architect", :exporterVersion => "2.5"}})
end
UML13EA.idStore.store
end
end rgen-0.7.0/lib/transformers/ 0000755 0000041 0000041 00000000000 12352210062 015765 5 ustar www-data www-data rgen-0.7.0/lib/transformers/ecore_to_uml13.rb 0000644 0000041 0000041 00000005216 12352210062 021136 0 ustar www-data www-data require 'rgen/transformer'
require 'rgen/ecore/ecore'
require 'metamodels/uml13_metamodel'
class ECoreToUML13 < RGen::Transformer
include RGen::ECore
def transform
trans(:class => EPackage)
trans(:class => EClass)
trans(:class => EEnum)
end
transform EPackage, :to => UML13::Package do
{:name => name,
:namespace => trans(eSuperPackage) || model,
:ownedElement => trans(eClassifiers.select{|c| c.is_a?(EClass)} + eSubpackages)
}
end
transform EClass, :to => UML13::Class do
{:name => name,
:namespace => trans(ePackage),
:feature => trans(eStructuralFeatures.select{|f| f.is_a?(EAttribute)} + eOperations),
:associationEnd => trans(eStructuralFeatures.select{|f| f.is_a?(EReference)}),
:generalization => eSuperTypes.collect { |st|
@env_out.new(UML13::Generalization, :parent => trans(st), :namespace => trans(ePackage) || model)
}
}
end
transform EEnum, :to => UML13::Class do
{:name => name,
:namespace => trans(ePackage),
:feature => trans(eLiterals)
}
end
transform EEnumLiteral, :to => UML13::Attribute do
{:name => name }
end
transform EAttribute, :to => UML13::Attribute do
_typemap = {"String" => "string", "Boolean" => "boolean", "Integer" => "int", "Float" => "float"}
{:name => name,
:taggedValue => [@env_out.new(UML13::TaggedValue, :tag => "type",
:value => _typemap[eType.instanceClassName] || eType.name)]
}
end
transform EReference, :to => UML13::AssociationEnd do
_otherAssocEnd = eOpposite ? trans(eOpposite) :
@env_out.new(UML13::AssociationEnd,
:type => trans(eType), :name => name, :multiplicity => createMultiplicity(@current_object),
:aggregation => :none, :isNavigable => true)
{ :association => trans(@current_object).association || @env_out.new(UML13::Association,
:connection => [_otherAssocEnd], :namespace => trans(eContainingClass.ePackage) || model),
:name => eOpposite && eOpposite.name,
:multiplicity => eOpposite && createMultiplicity(eOpposite),
:aggregation => containment ? :composite : :none,
:isNavigable => !eOpposite.nil?
}
end
transform EOperation, :to => UML13::Operation do
{:name => name}
end
def createMultiplicity(ref)
@env_out.new(UML13::Multiplicity, :range => [
@env_out.new(UML13::MultiplicityRange,
:lower => ref.lowerBound.to_s.sub("-1","*"), :upper => ref.upperBound.to_s.sub("-1","*"))])
end
def model
@model ||= @env_out.new(UML13::Model, :name => "Model")
end
end
rgen-0.7.0/lib/transformers/uml13_to_ecore.rb 0000644 0000041 0000041 00000010705 12352210062 021135 0 ustar www-data www-data require 'metamodels/uml13_metamodel'
require 'rgen/transformer'
require 'rgen/ecore/ecore'
require 'rgen/array_extensions'
class UML13ToECore < RGen::Transformer
include RGen::ECore
# Options:
#
# :reference_filter:
# a proc which receives an AssociationEnd or a Dependency and should return
# true or false, depending on if a referece should be created for it or not
#
def initialize(*args)
options = {}
if args.last.is_a?(Hash)
options = args.pop
end
@reference_filter = options[:reference_filter] || proc do |e|
if e.is_a?(UML13::AssociationEnd)
otherEnd = e.association.connection.find{|ae| ae != e}
otherEnd.name && otherEnd.name.size > 0
else
false
end
end
super(*args)
end
def transform
trans(:class => UML13::Class)
end
transform UML13::Model, :to => EPackage do
trans(ownedClassOrPackage)
{ :name => name && name.strip }
end
transform UML13::Package, :to => EPackage do
trans(ownedClassOrPackage)
{ :name => name && name.strip,
:eSuperPackage => trans(namespace.is_a?(UML13::Package) ? namespace : nil) }
end
method :ownedClassOrPackage do
ownedElement.select{|e| e.is_a?(UML13::Package) || e.is_a?(UML13::Class)}
end
transform UML13::Class, :to => EClass do
{ :name => name && name.strip,
:abstract => isAbstract,
:ePackage => trans(namespace.is_a?(UML13::Package) ? namespace : nil),
:eStructuralFeatures => trans(feature.select{|f| f.is_a?(UML13::Attribute)} +
associationEnd + clientDependency),
:eOperations => trans(feature.select{|f| f.is_a?(UML13::Operation)}),
:eSuperTypes => trans(generalization.parent + clientDependency.select{|d| d.stereotype && d.stereotype.name == "implements"}.supplier),
:eAnnotations => createAnnotations(taggedValue) }
end
transform UML13::Interface, :to => EClass do
{ :name => name && name.strip,
:abstract => isAbstract,
:ePackage => trans(namespace.is_a?(UML13::Package) ? namespace : nil),
:eStructuralFeatures => trans(feature.select{|f| f.is_a?(UML13::Attribute)} + associationEnd),
:eOperations => trans(feature.select{|f| f.is_a?(UML13::Operation)}),
:eSuperTypes => trans(generalization.parent)}
end
transform UML13::Attribute, :to => EAttribute do
{ :name => name && name.strip, :eType => trans(getType),
:lowerBound => (multiplicity && multiplicity.range.first.lower &&
multiplicity.range.first.lower.to_i) || 0,
:upperBound => (multiplicity && multiplicity.range.first.upper &&
multiplicity.range.first.upper.gsub('*','-1').to_i) || 1,
:eAnnotations => createAnnotations(taggedValue) }
end
transform UML13::DataType, :to => EDataType do
{ :name => name && name.strip,
:ePackage => trans(namespace.is_a?(UML13::Package) ? namespace : nil),
:eAnnotations => createAnnotations(taggedValue) }
end
transform UML13::Operation, :to => EOperation do
{ :name => name && name.strip }
end
transform UML13::AssociationEnd, :to => EReference, :if => :isReference do
otherEnd = association.connection.find{|ae| ae != @current_object}
{ :eType => trans(otherEnd.type),
:name => otherEnd.name && otherEnd.name.strip,
:eOpposite => trans(otherEnd),
:lowerBound => (otherEnd.multiplicity && otherEnd.multiplicity.range.first.lower &&
otherEnd.multiplicity.range.first.lower.to_i) || 0,
:upperBound => (otherEnd.multiplicity && otherEnd.multiplicity.range.first.upper &&
otherEnd.multiplicity.range.first.upper.gsub('*','-1').to_i) || 1,
:containment => (aggregation == :composite),
:eAnnotations => createAnnotations(association.taggedValue) }
end
transform UML13::Dependency, :to => EReference, :if => :isReference do
{ :eType => trans(supplier.first),
:name => name,
:lowerBound => 0,
:upperBound => 1,
:containment => false,
:eAnnotations => createAnnotations(taggedValue)
}
end
method :isReference do
@reference_filter.call(@current_object)
end
def createAnnotations(taggedValues)
if taggedValues.size > 0
[ EAnnotation.new(:details => trans(taggedValues)) ]
else
[]
end
end
transform UML13::TaggedValue, :to => EStringToStringMapEntry do
{ :key => tag, :value => value}
end
end
rgen-0.7.0/lib/rgen/ 0000755 0000041 0000041 00000000000 12352210062 014173 5 ustar www-data www-data rgen-0.7.0/lib/rgen/template_language.rb 0000644 0000041 0000041 00000027735 12352210062 020214 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
require 'rgen/template_language/directory_template_container'
require 'rgen/template_language/template_container'
module RGen
# The RGen template language has been designed to build complex generators.
# It is very similar to the EXPAND language of the Java based
# OpenArchitectureWare framework.
#
# =Templates
#
# The basic idea is to allow "templates" not only being template files
# but smaller parts. Those parts can be expanded from other parts very
# much like Ruby methods are called from other methods.
# Thus the term "template" refers to such a part within a "template file".
#
# Template files used by the RGen template language should have a
# filename with the postfix ".tpl". Those files can reside within (nested)
# template file directories.
#
# As an example a template directory could look like the following:
#
# templates/root.tpl
# templates/dbaccess/dbaccess.tpl
# templates/dbaccess/schema.tpl
# templates/headers/generic_headers.tpl
# templates/headers/specific/component.tpl
#
# A template is always called for a context object. The context object
# serves as the receiver of methods called within the template. Details are given
# below.
#
#
# =Defining Templates
#
# One or more templates can be defined in a template file using the +define+
# keyword as in the following example:
#
# <% define 'GenerateDBAdapter', :for => DBDescription do |dbtype| %>
# Content to be generated; use ERB syntax here
# <% end %>
#
# The template definition takes three kinds of parameters:
# 1. The name of the template within the template file as a String or Symbol
# 2. An optional class object describing the class of context objects for which
# this template is valid.
# 3. An arbitrary number of template parameters
# See RGen::TemplateLanguage::TemplateContainer for details about the syntax of +define+.
#
# Within a template, regular ERB syntax can be used. This is
# * <%
and %>
are used to embed Ruby code
# * <%=
and %>
are used to embed Ruby expressions with
# the expression result being written to the template output
# * <%#
and %>
are used for comments
# All content not within these tags is written to the template output verbatim.
# See below for details about output files and output formatting.
#
# All methods which are called from within the template are sent to the context
# object.
#
# Experience shows that one easily forgets the +do+ at the end of the first
# line of a template definition. This will result in an ERB parse error.
#
#
# =Expanding Templates
#
# Templates are normally expanded from within other templates. The only
# exception is the root template, which is expanded from the surrounding code.
#
# Template names can be specified in the following ways:
# * Non qualified name: use the template with the given name in the current template file
# * Relative qualified name: use the template within the template file specified by the relative path
# * Absolute qualified name: use the template within the template file specified by the absolute path
#
# The +expand+ keyword is used to expand templates.
#
# Here are some examples:
#
# <% expand 'GenerateDBAdapter', dbtype, :for => dbDesc %>
#
# Non qualified. Must be called within the file where 'GenerateDBAdapter' is defined.
# There is one template parameter passed in via variable +dbtype+.
# The context object is provided in variable +dbDesc+.
#
# <% expand 'dbaccess::ExampleSQL' %>
#
# Qualified with filename. Must be called from a file in the same directory as 'dbaccess.tpl'
# There are no parameters. The current context object will be used as the context
# object for this template expansion.
#
# <% expand '../headers/generic_headers::CHeader', :foreach => modules %>
#
# Relatively qualified. Must be called from a location from which the file
# 'generic_headers.tpl' is accessible via the relative path '../headers'.
# The template is expanded for each module in +modules+ (which has to be an Array).
# Each element of +modules+ will be the context object in turn.
#
# <% expand '/headers/generic_headers::CHeader', :foreach => modules %>
#
# Absolutely qualified: The same behaviour as before but with an absolute path from
# the template directory root (which in this example is 'templates', see above)
#
# Sometimes it is neccessary to generate some text (e.g. a ',') in between the single
# template expansion results from a :foreach
expansion. This can be achieved by
# using the :separator
keyword:
#
# <% expand 'ColumnName', :foreach => column, :separator => ', ' %>
#
# Note that the separator may also contain newline characters (\n). See below for
# details about formatting.
#
#
# =Formatting
#
# For many generator tools a formatting postprocess (e.g. using a pretty printer) is
# required in order to make the output readable. However, depending on the kind of
# generated output, such a tool might not be available.
#
# The RGen template language has been design for generators which do not need a
# postprocessing step. The basic idea is to eliminate all whitespace at the beginning
# of template lines (the indentation that makes the _template_ readable) and output
# newlines only after at least on character has been generated in the corresponding
# line. This way there are no empty lines in the output and each line will start with
# a non-whitspace character.
#
# Starting from this point one can add indentation and newlines as required by using
# explicit formatting commands:
# * <%nl%>
(newline) starts a new line
# * <%iinc%>
(indentation increment) increases the current indentation
# * <%idec%>
(indentation decrement) decreases the current indentation
# * <%nonl%>
(no newline) ignore next newline
# * <%nows%>
(no whitespace) ignore next whitespace
#
# Indentation takes place for every new line in the output unless it is 0.
# The initial indentation can be specified with a root +expand+ command by using
# the :indent
keyword.
#
# Here is an example:
#
# expand 'GenerateDBAdapter', dbtype, :for => dbDesc, :indent => 1
#
# Initial indentation defaults to 0. Normally <%iinc%>
and
# <%idec%>
are used to change the indentation.
# The current indentation is kept for expansion of subtemplates.
#
# The string which is used to realize one indentation step can be set using
# DirectoryTemplateContainer#indentString or with the template language +file+ command.
# The default is " " (3 spaces), the indentation string given at a +file+ command
# overwrites the container's default which in turn overwrites the overall default.
#
# Note that commands to ignore whitespace and newlines are still useful if output
# generated from multiple template lines should show up in one single output line.
#
# Here is an example of a template generating a C program:
#
# #include
# <%nl%>
# int main() {<%iinc%>
# printf("Hello World\n");
# return 0;<%idec>
# }
#
# The result is:
#
# #include
#
# int main() {
# printf("Hello World\n");
# return 0;
# }
#
# Note that without the explicit formatting commands, the output generated from the
# example above would not have any empty lines or whitespace in the beginning of lines.
# This may seem like unneccessary extra work for the example above which could also
# have been generated by passing the template to the output verbatimly.
# However in most cases templates will contain more template specific indentation and
# newlines which should be eliminated than formatting that should be visible in the
# output.
#
# Here is a more realistic example for generating C function prototypes:
#
# <% define 'Prototype', :for => CFunction do %>
# <%= getType.name %> <%= name %>(<%nows%>
# <% expand 'Signature', :foreach => argument, :separator => ', ' %>);
# <% end %>
#
# <% define 'Signature', :for => CFunctionArgument do %>
# <%= getType.name %> <%= name%><%nows%>
# <% end %>
#
# The result could look something like:
#
# void somefunc(int a, float b, int c);
# int otherfunc(short x);
#
# In this example a separator is used to join the single arguments of the C functions.
# Note that the template generating the argument type and name needs to contain
# a <%nows%>
if the result should consist of a single line.
#
# Here is one more example for generating C array initializations:
#
# <% define 'Array', :for => CArray do %>
# <%= getType.name %> <%= name %>[<%= size %>] = {<%iinc%>
# <% expand 'InitValue', :foreach => initvalue, :separator => ",\n" %><%nl%><%idec%>
# };
# <% end %>
#
# <% define 'InitValue', :for => PrimitiveInitValue do %>
# <%= value %><%nows%>
# <% end %>
#
# The result could look something like:
#
# int myArray[3] = {
# 1,
# 2,
# 3
# };
#
# Note that in this example, the separator contains a newline. The current increment
# will be applied to each single expansion result since it starts in a new line.
#
#
# =Output Files
#
# Normally the generated content is to be written into one or more output files.
# The RGen template language facilitates this by means of the +file+ keyword.
#
# When the +file+ keyword is used to define a block, all output generated
# from template code within this block will be written to the specified file.
# This includes output generated from template expansions.
# Thus all output from templates expanded within this block is written to
# the same file as long as those templates do not use the +file+ keyword to
# define a new file context.
#
# Here is an example:
#
# <% file 'dbadapter/'+adapter.name+'.c' do %>
# all content within this block will be written to the specified file
# <% end %>
#
# Note that the filename itself can be calculated dynamically by an arbitrary
# Ruby expression.
#
# The absolute position where the output file is created depends on the output
# root directory passed to DirectoryTemplateContainer as described below.
#
# As a second argument, the +file+ command can take the indentation string which is
# used to indent output lines (see Formatting).
#
# =Setting up the Generator
#
# Setting up the generator consists of 3 steps:
# * Instantiate DirectoryTemplateContainer passing one or more metamodel(s) and the output
# directory to the constructor.
# * Load the templates into the template container
# * Expand the root template to start generation
#
# Here is an example:
#
# module MyMM
# # metaclasses are defined here, e.g. using RGen::MetamodelBuilder
# end
#
# OUTPUT_DIR = File.dirname(__FILE__)+"/output"
# TEMPLATES_DIR = File.dirname(__FILE__)+"/templates"
#
# tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new(MyMM, OUTPUT_DIR)
# tc.load(TEMPLATES_DIR)
# # testModel should hold an instance of the metamodel class expected by the root template
# # the following line starts generation
# tc.expand('root::Root', :for => testModel, :indent => 1)
#
# The metamodel is the Ruby module which contains the metaclasses.
# This information is required for the template container in order to resolve the
# metamodel classes used within the template file.
# If several metamodels shall be used, an array of modules can be passed instead
# of a single module.
#
# The output path is prepended to the relative paths provided to the +file+
# definitions in the template files.
#
# The template directory should contain template files as described above.
#
# Finally the generation process is started by calling +expand+ in the same way as it
# is used from within templates.
#
# Also see the unit tests for more examples.
#
module TemplateLanguage
end
end rgen-0.7.0/lib/rgen/fragment/ 0000755 0000041 0000041 00000000000 12352210062 015776 5 ustar www-data www-data rgen-0.7.0/lib/rgen/fragment/fragmented_model.rb 0000644 0000041 0000041 00000010345 12352210062 021622 0 ustar www-data www-data require 'rgen/instantiator/reference_resolver'
module RGen
module Fragment
# A FragmentedModel represents a model which consists of fragments (ModelFragment).
#
# The main purpose of this class is to resolve references across fragments and
# to keep the references consistent while fragments are added or removed.
# This way it also plays an important role in keeping the model fragments consistent
# and thus ModelFragment objects should only be accessed via this interface.
# Overall unresolved references after the resolution step are also maintained.
#
# A FragmentedModel can also keep an RGen::Environment object up to date while fragments
# are added or removed. The environment must be registered with the constructor.
#
# Reference resolution is based on arbitrary identifiers. The identifiers must be
# provided in the fragments' indices. The FragmentedModel takes care to maintain
# the overall index.
#
class FragmentedModel
attr_reader :fragments
attr_reader :environment
# Creates a fragmented model. Options:
#
# :env
# environment which will be updated as model elements are added and removed
#
def initialize(options={})
@environment = options[:env]
@fragments = []
@index = nil
@fragment_change_listeners = []
@fragment_index = {}
end
# Adds a proc which is called when a fragment is added or removed
# The proc receives the fragment and one of :added, :removed
#
def add_fragment_change_listener(listener)
@fragment_change_listeners << listener
end
def remove_fragment_change_listener(listener)
@fragment_change_listeners.delete(listener)
end
# Add a fragment.
#
def add_fragment(fragment)
invalidate_cache
@fragments << fragment
fragment.elements.each{|e| @environment << e} if @environment
@fragment_change_listeners.each{|l| l.call(fragment, :added)}
end
# Removes the fragment. The fragment will be unresolved using unresolve_fragment.
#
def remove_fragment(fragment)
raise "fragment not part of model" unless @fragments.include?(fragment)
invalidate_cache
@fragments.delete(fragment)
@fragment_index.delete(fragment)
unresolve_fragment(fragment)
fragment.elements.each{|e| @environment.delete(e)} if @environment
@fragment_change_listeners.each{|l| l.call(fragment, :removed)}
end
# Resolve references between fragments.
# It is assumed that references within fragments have already been resolved.
# This method can be called several times. It will update the overall unresolved references.
#
# Options:
#
# :fragment_provider:
# Only if a +fragment_provider+ is given, the resolve step can be reverted later on
# by a call to unresolve_fragment. The fragment provider is a proc which receives a model
# element and must return the fragment in which the element is contained.
#
# :use_target_type:
# reference resolver uses the expected target type to narrow the set of possible targets
#
def resolve(options={})
local_index = index
@fragments.each do |f|
f.resolve_external(local_index, options)
end
end
# Remove all references between this fragment and all other fragments.
# The references will be replaced with unresolved references (MMProxy objects).
#
def unresolve_fragment(fragment)
fragment.unresolve_external
@fragments.each do |f|
if f != fragment
f.unresolve_external_fragment(fragment)
end
end
end
# Returns the overall unresolved references.
#
def unresolved_refs
@fragments.collect{|f| f.unresolved_refs}.flatten
end
# Returns the overall index.
# This is a Hash mapping identifiers to model elements accessible via the identifier.
#
def index
fragments.each do |f|
if !@fragment_index[f] || (@fragment_index[f].object_id != f.index.object_id)
@fragment_index[f] = f.index
invalidate_cache
end
end
return @index if @index
@index = {}
fragments.each do |f|
f.index.each do |i|
(@index[i[0]] ||= []) << i[1]
end
end
@index
end
private
def invalidate_cache
@index = nil
end
end
end
end
rgen-0.7.0/lib/rgen/fragment/model_fragment.rb 0000644 0000041 0000041 00000023310 12352210062 021305 0 ustar www-data www-data require 'rgen/instantiator/reference_resolver'
module RGen
module Fragment
# A model fragment is a list of root model elements associated with a location (e.g. a file).
# It also stores a list of unresolved references as well as a list of unresolved references
# which have been resolved. Using the latter, a fragment can undo reference resolution.
#
# Optionally, an arbitrary data object may be associated with the fragment. The data object
# will also be stored in the cache.
#
# If an element within the fragment changes this must be indicated to the fragment by calling
# +mark_changed+.
#
# Note: the fragment knows how to resolve references (+resolve_local+, +resolve_external+).
# However considering a fragment a data structure, this functionality might be removed in the
# future. Instead the fragment should be told about each resolution taking place. Use
# method +mark_resolved+ for this purpose.
#
class ModelFragment
attr_reader :root_elements
attr_accessor :location, :fragment_ref, :data
# A FragmentRef serves as a single target object for elements which need to reference the
# fragment they are contained in. The FragmentRef references the fragment it is contained in.
# The FragmentRef is separate from the fragment itself to allow storing it in a marshal dump
# independently of the fragment.
#
class FragmentRef
attr_accessor :fragment
end
# A ResolvedReference wraps an unresolved reference after it has been resolved.
# It also holds the target element to which it has been resolved, i.e. with which the proxy
# object has been replaced.
#
class ResolvedReference
attr_reader :uref, :target
def initialize(uref, target)
@uref, @target = uref, target
end
end
# Create a model fragment
#
# :data
# data object associated with this fragment
#
# :identifier_provider
# identifier provider to be used when resolving references
# it must be a proc which receives a model element and must return
# that element's identifier or nil if the element has no identifier
#
def initialize(location, options={})
@location = location
@fragment_ref = FragmentRef.new
@fragment_ref.fragment = self
@data = options[:data]
@resolved_refs = nil
@changed = false
@identifier_provider = options[:identifier_provider]
end
# Set the root elements, normally done by an instantiator.
#
# For optimization reasons the instantiator of the fragment may provide data explicitly which
# is normally derived by the fragment itself. In this case it is essential that this
# data is consistent with the fragment.
#
def set_root_elements(root_elements, options={})
@root_elements = root_elements
@elements = options[:elements]
@index = options[:index]
@unresolved_refs = options[:unresolved_refs]
@resolved_refs = nil
# new unresolved refs, reset removed_urefs
@removed_urefs = nil
@changed = false
end
# Must be called when any of the elements in this fragment has been changed
#
def mark_changed
@changed = true
@elements = nil
@index = nil
@unresolved_refs = nil
# unresolved refs will be recalculated, no need to keep removed_urefs
@removed_urefs = nil
@resolved_refs = :dirty
end
# Can be used to reset the change status to unchanged.
#
def mark_unchanged
@changed = false
end
# Indicates whether the fragment has been changed or not
#
def changed?
@changed
end
# Returns all elements within this fragment
#
def elements
return @elements if @elements
@elements = []
@root_elements.each do |e|
@elements << e
@elements.concat(e.eAllContents)
end
@elements
end
# Returns the index of the element contained in this fragment.
#
def index
build_index unless @index
@index
end
# Returns all unresolved references within this fragment, i.e. references to MMProxy objects
#
def unresolved_refs
@unresolved_refs ||= collect_unresolved_refs
if @removed_urefs
@unresolved_refs -= @removed_urefs
@removed_urefs = nil
end
@unresolved_refs
end
# Builds the index of all elements within this fragment having an identifier
# the index is an array of 2-element arrays holding the identifier and the element
#
def build_index
raise "cannot build index without an identifier provider" unless @identifier_provider
@index = elements.collect { |e|
ident = @identifier_provider.call(e, nil)
ident && !ident.empty? ? [ident, e] : nil
}.compact
end
# Resolves local references (within this fragment) as far as possible
#
# Options:
#
# :use_target_type:
# reference resolver uses the expected target type to narrow the set of possible targets
#
def resolve_local(options={})
resolver = RGen::Instantiator::ReferenceResolver.new
index.each do |i|
resolver.add_identifier(i[0], i[1])
end
@unresolved_refs = resolver.resolve(unresolved_refs, :use_target_type => options[:use_target_type])
end
# Resolves references to external fragments using the external_index provided.
# The external index must be a Hash mapping identifiers uniquely to model elements.
#
# Options:
#
# :fragment_provider:
# If a +fragment_provider+ is given, the resolve step can be reverted later on
# by a call to unresolve_external or unresolve_external_fragment. The fragment provider
# is a proc which receives a model element and must return the fragment in which it is
# contained.
#
# :use_target_type:
# reference resolver uses the expected target type to narrow the set of possible targets
#
#
def resolve_external(external_index, options)
fragment_provider = options[:fragment_provider]
resolver = RGen::Instantiator::ReferenceResolver.new(
:identifier_resolver => proc {|ident| external_index[ident] })
if fragment_provider
@resolved_refs = {} if @resolved_refs.nil? || @resolved_refs == :dirty
on_resolve = proc { |ur, target|
target_fragment = fragment_provider.call(target)
target_fragment ||= :unknown
raise "can not resolve local reference in resolve_external, call resolve_local first" \
if target_fragment == self
@resolved_refs[target_fragment] ||= []
@resolved_refs[target_fragment] << ResolvedReference.new(ur, target)
}
@unresolved_refs = resolver.resolve(unresolved_refs, :on_resolve => on_resolve, :use_target_type => options[:use_target_type])
else
@unresolved_refs = resolver.resolve(unresolved_refs, :use_target_type => options[:use_target_type])
end
end
# Marks a particular unresolved reference +uref+ as resolved to +target+ in +target_fragment+.
#
def mark_resolved(uref, target_fragment, target)
@resolved_refs = {} if @resolved_refs.nil? || @resolved_refs == :dirty
target_fragment ||= :unknown
if target_fragment != self
@resolved_refs[target_fragment] ||= []
@resolved_refs[target_fragment] << ResolvedReference.new(uref, target)
end
@removed_urefs ||= []
@removed_urefs << uref
end
# Unresolve outgoing references to all external fragments, i.e. references which used to
# be represented by an unresolved reference from within this fragment.
# Note, that there may be more references to external fragments due to references which
# were represented by unresolved references from within other fragments.
#
def unresolve_external
return if @resolved_refs.nil?
raise "can not unresolve, missing fragment information" if @resolved_refs == :dirty || @resolved_refs[:unknown]
rrefs = @resolved_refs.values.flatten
@resolved_refs = {}
unresolve_refs(rrefs)
end
# Like unresolve_external but only unresolve references to external fragment +fragment+
#
def unresolve_external_fragment(fragment)
return if @resolved_refs.nil?
raise "can not unresolve, missing fragment information" if @resolved_refs == :dirty || @resolved_refs[:unknown]
rrefs = @resolved_refs[fragment]
@resolved_refs.delete(fragment)
unresolve_refs(rrefs) if rrefs
end
private
# Turns resolved references +rrefs+ back into unresolved references
#
def unresolve_refs(rrefs)
# make sure any removed_urefs have been removed,
# otherwise they will be removed later even if this method actually re-added them
unresolved_refs
rrefs.each do |rr|
ur = rr.uref
refs = ur.element.getGeneric(ur.feature_name)
if refs.is_a?(Array)
index = refs.index(rr.target)
ur.element.removeGeneric(ur.feature_name, rr.target)
ur.element.addGeneric(ur.feature_name, ur.proxy, index)
else
ur.element.setGeneric(ur.feature_name, ur.proxy)
end
@unresolved_refs << ur
end
end
def collect_unresolved_refs
unresolved_refs = []
elements.each do |e|
each_reference_target(e) do |r, t|
if t.is_a?(RGen::MetamodelBuilder::MMProxy)
unresolved_refs <<
RGen::Instantiator::ReferenceResolver::UnresolvedReference.new(e, r.name, t)
end
end
end
unresolved_refs
end
def each_reference_target(element)
non_containment_references(element.class).each do |r|
element.getGenericAsArray(r.name).each do |t|
yield(r, t)
end
end
end
def non_containment_references(clazz)
@@non_containment_references_cache ||= {}
@@non_containment_references_cache[clazz] ||=
clazz.ecore.eAllReferences.select{|r| !r.containment}
end
end
end
end
rgen-0.7.0/lib/rgen/fragment/dump_file_cache.rb 0000644 0000041 0000041 00000003555 12352210062 021422 0 ustar www-data www-data module RGen
module Fragment
# Caches model fragments in Ruby dump files.
#
# Dump files are created per each fragment file.
#
# The main goal is to support fast loading and joining of fragments. Therefore the cache
# stores additional information which makes the joining process faster (adding to
# environment, resolving references)
#
class DumpFileCache
# +cache_map+ must be an object responding to +load_data+ and +store_data+
# for loading or storing data associated with a file;
# this can be an instance of Util::FileCacheMap
def initialize(cache_map)
@cache_map = cache_map
end
# Note that the fragment must not be connected to other fragments by resolved references
# unresolve the fragment if necessary
def store(fragment)
fref = fragment.fragment_ref
# temporarily remove the reference to the fragment to avoid dumping the fragment
fref.fragment = nil
@cache_map.store_data(fragment.location,
Marshal.dump({
:root_elements => fragment.root_elements,
:elements => fragment.elements,
:index => fragment.index,
:unresolved_refs => fragment.unresolved_refs,
:fragment_ref => fref,
:data => fragment.data
}))
fref.fragment = fragment
end
def load(fragment)
dump = @cache_map.load_data(fragment.location)
return :invalid if dump == :invalid
header = Marshal.load(dump)
fragment.set_root_elements(header[:root_elements],
:elements => header[:elements],
:index => header[:index],
:unresolved_refs => header[:unresolved_refs])
fragment.data = header[:data]
if header[:fragment_ref]
fragment.fragment_ref = header[:fragment_ref]
fragment.fragment_ref.fragment = fragment
else
raise "no fragment_ref in fragment loaded from cache"
end
end
end
end
end
rgen-0.7.0/lib/rgen/metamodel_builder.rb 0000644 0000041 0000041 00000017125 12352210062 020203 0 ustar www-data www-data # 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) references only,
#
# 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
rgen-0.7.0/lib/rgen/model_builder.rb 0000644 0000041 0000041 00000001746 12352210062 017336 0 ustar www-data www-data require 'rgen/model_builder/builder_context'
require 'rgen/util/method_delegation'
#require 'ruby-prof'
module RGen
module ModelBuilder
def self.build(package, env=nil, builderMethodsModule=nil, &block)
resolver = ReferenceResolver.new
bc = BuilderContext.new(package, builderMethodsModule, resolver, env)
contextModule = eval("Module.nesting", block.binding).first
Util::MethodDelegation.registerDelegate(bc, contextModule, "const_missing")
BuilderContext.currentBuilderContext = bc
begin
#RubyProf.start
bc.instance_eval(&block)
#prof = RubyProf.stop
#File.open("profile_flat.txt","w+") do |f|
# RubyProf::FlatPrinter.new(prof).print(f, 0)
# end
ensure
BuilderContext.currentBuilderContext = nil
end
Util::MethodDelegation.unregisterDelegate(bc, contextModule, "const_missing")
#puts "Resolving..."
resolver.resolve(bc.toplevelElements)
bc.toplevelElements
end
end
end
rgen-0.7.0/lib/rgen/template_language/ 0000755 0000041 0000041 00000000000 12352210062 017651 5 ustar www-data www-data rgen-0.7.0/lib/rgen/template_language/template_container.rb 0000644 0000041 0000041 00000016545 12352210062 024066 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
require 'erb'
require 'fileutils'
require 'rgen/template_language/output_handler'
require 'rgen/template_language/template_helper'
module RGen
module TemplateLanguage
class TemplateContainer
include TemplateHelper
def initialize(metamodels, output_path, parent, filename)
@templates = {}
@parent = parent
@filename = filename
@indent = 0
@output_path = output_path
@metamodels = metamodels
@metamodels = [ @metamodels ] unless @metamodels.is_a?(Array)
end
def load
File.open(@filename,"rb") do |f|
begin
@@metamodels = @metamodels
fileContent = f.read
_detectNewLinePattern(fileContent)
ERB.new(fileContent,nil,nil,'@output').result(binding)
rescue Exception => e
processAndRaise(e)
end
end
end
def expand(template, *all_args)
args, params = _splitArgsAndOptions(all_args)
if params.has_key?(:foreach)
raise StandardError.new("expand :foreach argument is not enumerable") \
unless params[:foreach].is_a?(Enumerable)
_expand_foreach(template, args, params)
else
_expand(template, args, params)
end
end
def evaluate(template, *all_args)
args, params = _splitArgsAndOptions(all_args)
raise StandardError.new(":foreach can not be used with evaluate") if params[:foreach]
_expand(template, args, params.merge({:_evalOnly => true}))
end
def this
@context
end
def method_missing(name, *args)
@context.send(name, *args)
end
def self.const_missing(name)
super unless @@metamodels
@@metamodels.each do |mm|
return mm.const_get(name) rescue NameError
end
super
end
private
def nonl
@output.ignoreNextNL
end
def nows
@output.ignoreNextWS
end
def nl
_direct_concat(@newLinePattern)
end
def ws
_direct_concat(" ")
end
def iinc
@indent += 1
@output.indent = @indent
end
def idec
@indent -= 1 if @indent > 0
@output.indent = @indent
end
TemplateDesc = Struct.new(:block, :local)
def define(template, params={}, &block)
_define(template, params, &block)
end
def define_local(template, params={}, &block)
_define(template, params.merge({:local => true}), &block)
end
def file(name, indentString=nil)
old_output, @output = @output, OutputHandler.new(@indent, indentString || @parent.indentString)
begin
yield
rescue Exception => e
processAndRaise(e)
end
path = ""
path += @output_path+"/" if @output_path
dirname = File.dirname(path+name)
FileUtils.makedirs(dirname) unless File.exist?(dirname)
File.open(path+name,"wb") { |f| f.write(@output) }
@output = old_output
end
# private private
def _define(template, params={}, &block)
@templates[template] ||= {}
cls = params[:for] || Object
@templates[template][cls] = TemplateDesc.new(block, params[:local])
end
def _expand_foreach(template, args, params)
sep = params[:separator]
params[:foreach].each_with_index {|e,i|
_direct_concat(sep.to_s) if sep && i > 0
output = _expand(template, args, params.merge({:for => e}))
}
end
LOCAL_TEMPLATE_REGEX = /^:*(\w+)$/
def _expand(template, args, params)
raise StandardError.new("expand :for argument evaluates to nil") if params.has_key?(:for) && params[:for].nil?
context = params[:for]
old_indent = @indent
@indent = params[:indent] || @indent
noIndentNextLine = params[:_noIndentNextLine] ||
(@output.is_a?(OutputHandler) && @output.noIndentNextLine) ||
(@output.to_s.size > 0 && @output.to_s[-1] != "\n"[0])
caller = params[:_caller] || self
old_context, @context = @context, context if context
local_output = nil
if template =~ LOCAL_TEMPLATE_REGEX
tplname = $1
raise StandardError.new("Template not found: #{$1}") unless @templates[tplname]
old_output, @output = @output, OutputHandler.new(@indent, @parent.indentString)
@output.noIndentNextLine = noIndentNextLine
_call_template(tplname, @context, args, caller == self)
old_output.noIndentNextLine = false if old_output.is_a?(OutputHandler) && !old_output.noIndentNextLine
local_output, @output = @output, old_output
else
local_output = @parent.expand(template, *(args.dup << {:for => @context, :indent => @indent, :_noIndentNextLine => noIndentNextLine, :_evalOnly => true, :_caller => caller}))
end
_direct_concat(local_output) unless params[:_evalOnly]
@context = old_context if old_context
@indent = old_indent
local_output.to_s
end
def processAndRaise(e, tpl=nil)
bt = e.backtrace.dup
e.backtrace.each_with_index do |t,i|
if t =~ /\(erb\):(\d+):/
bt[i] = "#{@filename}:#{$1}"
bt[i] += ":in '#{tpl}'" if tpl
break
end
end
raise e, e.to_s, bt
end
def _call_template(tpl, context, args, localCall)
found = false
@templates[tpl].each_pair do |key, value|
if context.is_a?(key)
templateDesc = @templates[tpl][key]
proc = templateDesc.block
arity = proc.arity
arity = 0 if arity == -1 # if no args are given
raise StandardError.new("Wrong number of arguments calling template #{tpl}: #{args.size} for #{arity} "+
"(Beware: Hashes as last arguments are taken as options and are ignored)") \
if arity != args.size
raise StandardError.new("Template can only be called locally: #{tpl}") \
if templateDesc.local && !localCall
begin
@@metamodels = @metamodels
proc.call(*args)
rescue Exception => e
processAndRaise(e, tpl)
end
found = true
end
end
raise StandardError.new("Template class not matching: #{tpl} for #{context.class.name}") unless found
end
def _direct_concat(s)
if @output.is_a? OutputHandler
@output.direct_concat(s)
else
@output << s
end
end
def _detectNewLinePattern(text)
tests = 0
rnOccurances = 0
text.scan(/(\r?)\n/) do |groups|
tests += 1
rnOccurances += 1 if groups[0] == "\r"
break if tests >= 10
end
if rnOccurances > (tests / 2)
@newLinePattern = "\r\n"
else
@newLinePattern = "\n"
end
end
end
end
end
rgen-0.7.0/lib/rgen/template_language/output_handler.rb 0000644 0000041 0000041 00000004434 12352210062 023240 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
module RGen
module TemplateLanguage
class OutputHandler
attr_writer :indent
attr_accessor :noIndentNextLine
def initialize(indent=0, indentString=" ", mode=:explicit)
self.mode = mode
@indent = indent
@indentString = indentString
@state = :wait_for_nonws
@output = ""
end
# ERB will call this method for every string s which is part of the
# template file in between %> and <%. If s contains a newline, it will
# call this method for every part of s which is terminated by a \n
#
def concat(s)
return @output.concat(s) if s.is_a? OutputHandler
#puts [object_id, noIndentNextLine, @state, @output.to_s, s].inspect
s = s.to_str.gsub(/^[\t ]*\r?\n/,'') if @ignoreNextNL
s = s.to_str.gsub(/^\s+/,'') if @ignoreNextWS
@ignoreNextNL = @ignoreNextWS = false if s =~ /\S/
if @mode == :direct
@output.concat(s)
elsif @mode == :explicit
while s.size > 0
if @state == :wait_for_nl
if s =~ /\A([^\r\n]*\r?\n)(.*)/m
rest = $2
@output.concat($1.gsub(/[\t ]+(?=\r|\n)/,''))
s = rest || ""
@state = :wait_for_nonws
else
@output.concat(s)
s = ""
end
elsif @state == :wait_for_nonws
if s =~ /\A\s*(\S+.*)/m
s = $1 || ""
if !@noIndentNextLine && !(@output.to_s.size > 0 && @output.to_s[-1] != "\n"[0])
@output.concat(@indentString * @indent)
else
@noIndentNextLine = false
end
@state = :wait_for_nl
else
s = ""
end
end
end
end
end
alias << concat
def to_str
@output
end
alias to_s to_str
def direct_concat(s)
@output.concat(s)
end
def ignoreNextNL
@ignoreNextNL = true
end
def ignoreNextWS
@ignoreNextWS = true
end
def mode=(m)
raise StandardError.new("Unknown mode: #{m}") unless [:direct, :explicit].include?(m)
@mode = m
end
end
end
end rgen-0.7.0/lib/rgen/template_language/template_helper.rb 0000644 0000041 0000041 00000000523 12352210062 023350 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
module RGen
module TemplateLanguage
module TemplateHelper
private
def _splitArgsAndOptions(all)
if all[-1] and all[-1].is_a? Hash
args = all[0..-2] || []
options = all[-1]
else
args = all
options = {}
end
return args, options
end
end
end
end rgen-0.7.0/lib/rgen/template_language/directory_template_container.rb 0000644 0000041 0000041 00000004161 12352210062 026141 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
require 'rgen/template_language/template_container'
require 'rgen/template_language/template_helper'
module RGen
module TemplateLanguage
class DirectoryTemplateContainer
include TemplateHelper
def initialize(metamodel=nil, output_path=nil, parent=nil)
@containers = {}
@directoryContainers = {}
@parent = parent
@metamodel = metamodel
@output_path = output_path
end
def load(dir)
Dir.foreach(dir) { |f|
qf = dir+"/"+f
if !File.directory?(qf) && f =~ /^(.*)\.tpl$/
(@containers[$1] = TemplateContainer.new(@metamodel, @output_path, self,qf)).load
elsif File.directory?(qf) && f != "." && f != ".."
(@directoryContainers[f] = DirectoryTemplateContainer.new(@metamodel, @output_path, self)).load(qf)
end
}
end
def expand(template, *all_args)
if template =~ /^\//
if @parent
# pass to parent
@parent.expand(template, *all_args)
else
# this is root
_expand(template, *all_args)
end
elsif template =~ /^\.\.\/(.*)/
if @parent
# pass to parent
@parent.expand($1, *all_args)
else
raise "No parent directory for root"
end
else
_expand(template, *all_args)
end
end
# Set indentation string.
# Every generated line will be prependend with n times this string at an indentation level of n.
# Defaults to " " (3 spaces)
def indentString=(str)
@indentString = str
end
def indentString
@indentString || (@parent && @parent.indentString) || " "
end
private
def _expand(template, *all_args)
if template =~ /^\/?(\w+)::(\w.*)/
raise "Template not found: #{$1}" unless @containers[$1]
@containers[$1].expand($2, *all_args)
elsif template =~ /^\/?(\w+)\/(\w.*)/
raise "Template not found: #{$1}" unless @directoryContainers[$1]
@directoryContainers[$1].expand($2, *all_args)
else
raise "Invalid template name: #{template}"
end
end
end
end
end rgen-0.7.0/lib/rgen/ecore/ 0000755 0000041 0000041 00000000000 12352210062 015270 5 ustar www-data www-data rgen-0.7.0/lib/rgen/ecore/ecore_interface.rb 0000644 0000041 0000041 00000002403 12352210062 020731 0 ustar www-data www-data module RGen
module ECore
# Mixin to provide access to the ECore model describing a Ruby class or module
# built using MetamodelBuilder.
# The module should be used to +extend+ a class or module, i.e. to make its
# methods class methods.
#
module ECoreInterface
# This method will lazily build to ECore model element belonging to the calling
# class or module using RubyToECore.
# Alternatively, the ECore model element can be provided up front. This is used
# when the Ruby metamodel classes and modules are created from ECore.
#
def ecore
if defined?(@ecore)
@ecore
else
unless defined?(@@transformer)
require 'rgen/ecore/ruby_to_ecore'
@@transformer = RubyToECore.new
end
@@transformer.trans(self)
end
end
# This method can be used to clear the ecore cache after the metamodel classes
# or modules have been changed; the ecore model will be recreated on next access
# to the +ecore+ method
# Beware, the ecore cache is global, i.e. for all metamodels.
#
def self.clear_ecore_cache
require 'rgen/ecore/ruby_to_ecore'
@@transformer = RubyToECore.new
end
def _set_ecore_internal(ecore) # :nodoc:
@ecore = ecore
end
end
end
end
rgen-0.7.0/lib/rgen/ecore/ecore.rb 0000644 0000041 0000041 00000020610 12352210062 016711 0 ustar www-data www-data require 'rgen/metamodel_builder'
module RGen
extend RGen::MetamodelBuilder::ModuleExtension
# This is the ECore metamodel described using the RGen::MetamodelBuilder language.
#
# Known differences to the Java/EMF implementation are:
# * Attributes can not be "many"
#
module ECore
extend RGen::MetamodelBuilder::ModuleExtension
class EObject < RGen::MetamodelBuilder::MMBase
end
class EModelElement < RGen::MetamodelBuilder::MMBase
end
class EAnnotation < RGen::MetamodelBuilder::MMMultiple(EModelElement, EObject)
has_attr 'source', String
end
class ENamedElement < EModelElement
has_attr 'name', String
end
class ETypedElement < ENamedElement
has_attr 'lowerBound', Integer, :defaultValueLiteral => "0"
has_attr 'ordered', Boolean, :defaultValueLiteral => "true"
has_attr 'unique', Boolean, :defaultValueLiteral => "true"
has_attr 'upperBound', Integer, :defaultValueLiteral => "1"
has_attr 'many', Boolean, :derived=>true
has_attr 'required', Boolean, :derived=>true
module ClassModule
def many_derived
upperBound > 1 || upperBound == -1
end
def required_derived
lowerBound > 0
end
end
end
class EStructuralFeature < ETypedElement
has_attr 'changeable', Boolean, :defaultValueLiteral => "true"
has_attr 'defaultValue', Object, :derived=>true
has_attr 'defaultValueLiteral', String
has_attr 'derived', Boolean, :defaultValueLiteral => "false"
has_attr 'transient', Boolean, :defaultValueLiteral => "false"
has_attr 'unsettable', Boolean, :defaultValueLiteral => "false"
has_attr 'volatile', Boolean, :defaultValueLiteral => "false"
module ClassModule
def defaultValue_derived
return nil if defaultValueLiteral.nil?
case eType
when EInt, ELong
defaultValueLiteral.to_i
when EFloat
defaultValueLiteral.to_f
when EEnum
defaultValueLiteral.to_sym
when EBoolean
defaultValueLiteral == "true"
when EString
defaultValueLiteral
else
raise "Unhandled type"
end
end
end
end
class EAttribute < EStructuralFeature
has_attr 'iD', Boolean, :defaultValueLiteral => "false"
end
class EClassifier < ENamedElement
has_attr 'defaultValue', Object, :derived=>true
has_attr 'instanceClass', Object, :derived=>true
has_attr 'instanceClassName', String
module ClassModule
def instanceClass_derived
map = {"java.lang.string" => "String",
"boolean" => "RGen::MetamodelBuilder::DataTypes::Boolean",
"int" => "Integer",
"long" => "RGen::MetamodelBuilder::DataTypes::Long"}
icn = instanceClassName
icn = "NilClass" if icn.nil?
icn = map[icn.downcase] if map[icn.downcase]
eval(icn)
end
end
end
class EDataType < EClassifier
has_attr 'serializable', Boolean
end
class EGenericType < EDataType
has_one 'eClassifier', EDataType
end
class ETypeArgument < EModelElement
has_one 'eClassifier', EDataType
end
class EEnum < EDataType
end
class EEnumLiteral < ENamedElement
# instance may point to a "singleton object" (e.g. a Symbol) representing the literal
# has_attr 'instance', Object, :eType=>:EEnumerator, :transient=>true
has_attr 'literal', String
has_attr 'value', Integer
end
# TODO: check if required
class EFactory < EModelElement
end
class EOperation < ETypedElement
end
class EPackage < ENamedElement
has_attr 'nsPrefix', String
has_attr 'nsURI', String
end
class EParameter < ETypedElement
end
class EReference < EStructuralFeature
has_attr 'container', Boolean, :derived=>true
has_attr 'containment', Boolean, :defaultValueLiteral => "false"
has_attr 'resolveProxies', Boolean, :defaultValueLiteral => "true"
end
class EStringToStringMapEntry < RGen::MetamodelBuilder::MMBase
has_attr 'key', String
has_attr 'value', String
end
class EClass < EClassifier
has_attr 'abstract', Boolean
has_attr 'interface', Boolean
has_one 'eIDAttribute', ECore::EAttribute, :derived=>true, :resolveProxies=>false
has_many 'eAllAttributes', ECore::EAttribute, :derived=>true
has_many 'eAllContainments', ECore::EReference, :derived=>true
has_many 'eAllOperations', ECore::EOperation, :derived=>true
has_many 'eAllReferences', ECore::EReference, :derived=>true
has_many 'eAllStructuralFeatures', ECore::EStructuralFeature, :derived=>true
has_many 'eAllSuperTypes', ECore::EClass, :derived=>true
has_many 'eAttributes', ECore::EAttribute, :derived=>true
has_many 'eReferences', ECore::EReference, :derived=>true
module ClassModule
def eAllAttributes_derived
eAttributes + eSuperTypes.eAllAttributes
end
def eAllContainments_derived
eReferences.select{|r| r.containment} + eSuperTypes.eAllContainments
end
def eAllReferences_derived
eReferences + eSuperTypes.eAllReferences
end
def eAllStructuralFeatures_derived
eStructuralFeatures + eSuperTypes.eAllStructuralFeatures
end
def eAllSuperTypes_derived
eSuperTypes + eSuperTypes.eAllSuperTypes
end
def eAttributes_derived
eStructuralFeatures.select{|f| f.is_a?(EAttribute)}
end
def eReferences_derived
eStructuralFeatures.select{|f| f.is_a?(EReference)}
end
end
end
# predefined datatypes
EString = EDataType.new(:name => "EString", :instanceClassName => "String")
EInt = EDataType.new(:name => "EInt", :instanceClassName => "Integer")
ELong = EDataType.new(:name => "ELong", :instanceClassName => "Long")
EBoolean = EDataType.new(:name => "EBoolean", :instanceClassName => "Boolean")
EFloat = EDataType.new(:name => "EFloat", :instanceClassName => "Float")
ERubyObject = EDataType.new(:name => "ERubyObject", :instanceClassName => "Object")
EJavaObject = EDataType.new(:name => "EJavaObject")
ERubyClass = EDataType.new(:name => "ERubyClass", :instanceClassName => "Class")
EJavaClass = EDataType.new(:name => "EJavaClass")
end
ECore::EModelElement.contains_many 'eAnnotations', ECore::EAnnotation, 'eModelElement', :resolveProxies=>false
ECore::EAnnotation.contains_many_uni 'details', ECore::EStringToStringMapEntry, :resolveProxies=>false
ECore::EAnnotation.contains_many_uni 'contents', ECore::EObject, :resolveProxies=>false
ECore::EAnnotation.has_many 'references', ECore::EObject
ECore::EPackage.contains_many 'eClassifiers', ECore::EClassifier, 'ePackage'
ECore::EPackage.contains_many 'eSubpackages', ECore::EPackage, 'eSuperPackage'
ECore::ETypedElement.has_one 'eType', ECore::EClassifier
ECore::EClass.contains_many 'eOperations', ECore::EOperation, 'eContainingClass', :resolveProxies=>false
ECore::EClass.contains_many 'eStructuralFeatures', ECore::EStructuralFeature, 'eContainingClass', :resolveProxies=>false
ECore::EClass.has_many 'eSuperTypes', ECore::EClass
ECore::EEnum.contains_many 'eLiterals', ECore::EEnumLiteral, 'eEnum', :resolveProxies=>false
ECore::EFactory.one_to_one 'ePackage', ECore::EPackage, 'eFactoryInstance', :lowerBound=>1, :transient=>true, :resolveProxies=>false
ECore::EOperation.contains_many 'eParameters', ECore::EParameter, 'eOperation', :resolveProxies=>false
ECore::EOperation.has_many 'eExceptions', ECore::EClassifier
ECore::EReference.has_one 'eOpposite', ECore::EReference
ECore::EAttribute.has_one 'eAttributeType', ECore::EDataType, :lowerBound=>1, :derived=>true
ECore::EReference.has_one 'eReferenceType', ECore::EClass, :lowerBound=>1, :derived=>true
ECore::EParameter.contains_one 'eGenericType', ECore::EGenericType, 'eParameter'
ECore::EGenericType.contains_many 'eTypeArguments', ECore::ETypeArgument, 'eGenericType'
end
rgen-0.7.0/lib/rgen/ecore/ecore_ext.rb 0000644 0000041 0000041 00000002667 12352210062 017605 0 ustar www-data www-data require 'rgen/array_extensions'
require 'rgen/ecore/ecore'
module RGen
module ECore
# make super type reference bidirectional
EClass.many_to_many 'eSuperTypes', ECore::EClass, 'eSubTypes'
module EModelElement::ClassModule
def annotationValue(source, tag)
detail = eAnnotations.select{ |a| a.source == source }.details.find{ |d| d.key == tag }
detail && detail.value
end
end
module EPackage::ClassModule
def qualifiedName
if eSuperPackage
eSuperPackage.qualifiedName+"::"+name
else
name
end
end
def eAllClassifiers
eClassifiers + eSubpackages.eAllClassifiers
end
def eAllSubpackages
eSubpackages + eSubpackages.eAllSubpackages
end
def eClasses
eClassifiers.select{|c| c.is_a?(ECore::EClass)}
end
def eAllClasses
eClasses + eSubpackages.eAllClasses
end
def eDataTypes
eClassifiers.select{|c| c.is_a?(ECore::EDataType)}
end
def eAllDataTypes
eDataTypes + eSubpackages.eAllDataTypes
end
end
module EClass::ClassModule
def qualifiedName
if ePackage
ePackage.qualifiedName+"::"+name
else
name
end
end
def eAllSubTypes
eSubTypes + eSubTypes.eAllSubTypes
end
end
end
end
rgen-0.7.0/lib/rgen/ecore/ecore_to_ruby.rb 0000644 0000041 0000041 00000010060 12352210062 020452 0 ustar www-data www-data require 'rgen/ecore/ecore'
module RGen
module ECore
class ECoreToRuby
def initialize
@modules = {}
@classifiers = {}
@features_added = {}
@in_create_module = false
end
def create_module(epackage)
return @modules[epackage] if @modules[epackage]
top = (@in_create_module == false)
@in_create_module = true
m = Module.new do
extend RGen::MetamodelBuilder::ModuleExtension
end
@modules[epackage] = m
epackage.eSubpackages.each{|p| create_module(p)}
m._set_ecore_internal(epackage)
create_module(epackage.eSuperPackage).const_set(epackage.name, m) if epackage.eSuperPackage
# create classes only after all modules have been created
# otherwise classes may be created multiple times
if top
epackage.eAllClassifiers.each do |c|
if c.is_a?(RGen::ECore::EClass)
create_class(c)
elsif c.is_a?(RGen::ECore::EEnum)
create_enum(c)
end
end
@in_create_module = false
end
m
end
def create_class(eclass)
return @classifiers[eclass] if @classifiers[eclass]
c = Class.new(super_class(eclass)) do
abstract if eclass.abstract
class << self
attr_accessor :_ecore_to_ruby
end
end
class << eclass
attr_accessor :instanceClass
def instanceClassName
instanceClass.to_s
end
end
eclass.instanceClass = c
c::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] = c
c._set_ecore_internal(eclass)
c._ecore_to_ruby = self
create_module(eclass.ePackage).const_set(eclass.name, c)
c
end
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
create_module(eenum.ePackage).const_set(eenum.name, e)
e
end
class FeatureWrapper
def initialize(efeature, classifiers)
@efeature = efeature
@classifiers = classifiers
end
def value(prop)
return false if prop == :containment && @efeature.is_a?(RGen::ECore::EAttribute)
@efeature.send(prop)
end
def many?
@efeature.many
end
def reference?
@efeature.is_a?(RGen::ECore::EReference)
end
def opposite
@efeature.eOpposite
end
def impl_type
etype = @efeature.eType
if etype.is_a?(RGen::ECore::EClass) || etype.is_a?(RGen::ECore::EEnum)
@classifiers[etype]
else
ic = etype.instanceClass
if ic
ic
else
raise "unknown type: #{etype.name}"
end
end
end
end
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
def super_class(eclass)
super_types = eclass.eSuperTypes
case super_types.size
when 0
RGen::MetamodelBuilder::MMBase
when 1
create_class(super_types.first)
else
RGen::MetamodelBuilder::MMMultiple(*super_types.collect{|t| create_class(t)})
end
end
end
end
end
rgen-0.7.0/lib/rgen/ecore/ecore_builder_methods.rb 0000644 0000041 0000041 00000005452 12352210062 022151 0 ustar www-data www-data module RGen
module ECore
module ECoreBuilderMethods
def eAttr(name, type, argHash={}, &block)
eAttribute(name, {:eType => type}.merge(argHash), &block)
end
def eRef(name, type, argHash={}, &block)
eReference(name, {:eType => type}.merge(argHash), &block)
end
# create bidirectional reference at once
def eBiRef(name, type, oppositeName, argHash={})
raise BuilderError.new("eOpposite attribute not allowed for bidirectional references") \
if argHash[:eOpposite] || argHash[:opposite_eOpposite]
eReference(name, {:eType => type}.merge(argHash.reject{|k,v| k.to_s =~ /^opposite_/})) do
eReference oppositeName, {:eContainingClass => type, :eType => _context(2),
:as => :eOpposite, :eOpposite => _context(1)}.
merge(Hash[*(argHash.select{|k,v| k.to_s =~ /^opposite_/}.
collect{|p| [p[0].to_s.sub(/^opposite_/,"").to_sym, p[1]]}.flatten)])
end
end
# reference shortcuts
alias references_1 eRef
alias references_one eRef
def references_N(name, type, argHash={})
eRef(name, type, {:upperBound => -1}.merge(argHash))
end
alias references_many references_N
def references_1to1(name, type, oppositeName, argHash={})
eBiRef(name, type, oppositeName, {:upperBound => 1, :opposite_upperBound => 1}.merge(argHash))
end
alias references_one_to_one references_1to1
def references_1toN(name, type, oppositeName, argHash={})
eBiRef(name, type, oppositeName, {:upperBound => -1, :opposite_upperBound => 1}.merge(argHash))
end
alias references_one_to_many references_1toN
def references_Nto1(name, type, oppositeName, argHash={})
eBiRef(name, type, oppositeName, {:upperBound => 1, :opposite_upperBound => -1}.merge(argHash))
end
alias references_many_to_one references_Nto1
def references_MtoN(name, type, oppositeName, argHash={})
eBiRef(name, type, oppositeName, {:upperBound => -1, :opposite_upperBound => -1}.merge(argHash))
end
alias references_many_to_many references_MtoN
# containment reference shortcuts
def contains_1(name, type, argHash={})
references_1(name, type, {:containment => true}.merge(argHash))
end
alias contains_one contains_1
def contains_N(name, type, argHash={})
references_N(name, type, {:containment => true}.merge(argHash))
end
alias contains_many contains_N
def contains_1to1(name, type, oppositeName, argHash={})
references_1to1(name, type, oppositeName, {:containment => true}.merge(argHash))
end
alias contains_one_to_one contains_1to1
def contains_1toN(name, type, oppositeName, argHash={})
references_1toN(name, type, oppositeName, {:containment => true}.merge(argHash))
end
alias contains_one_to_many contains_1toN
end
end
end rgen-0.7.0/lib/rgen/ecore/ruby_to_ecore.rb 0000644 0000041 0000041 00000006132 12352210062 020457 0 ustar www-data www-data require 'rgen/transformer'
require 'rgen/ecore/ecore'
module RGen
module ECore
# This transformer creates an ECore model from Ruby classes built
# by RGen::MetamodelBuilder.
#
class RubyToECore < Transformer
transform Class, :to => EClass, :if => :convert? do
{ :name => name.gsub(/.*::(\w+)$/,'\1'),
:abstract => _abstract_class,
:interface => false,
:eStructuralFeatures => trans(_metamodel_description),
:ePackage => trans(name =~ /(.*)::\w+$/ ? eval($1) : nil),
:eSuperTypes => trans(superclasses),
:instanceClassName => name,
:eAnnotations => trans(_annotations)
}
end
method :superclasses do
if superclass.respond_to?(:multiple_superclasses) && superclass.multiple_superclasses
superclass.multiple_superclasses
else
[ superclass ]
end
end
transform Module, :to => EPackage, :if => :convert? do
@enumParentModule ||= {}
_constants = _constantOrder + (constants - _constantOrder)
_constants.select {|c| const_get(c).is_a?(MetamodelBuilder::DataTypes::Enum)}.
each {|c| @enumParentModule[const_get(c)] = @current_object}
{ :name => name.gsub(/.*::(\w+)$/,'\1'),
:eClassifiers => trans(_constants.collect{|c| const_get(c)}.select{|c| c.is_a?(Class) ||
(c.is_a?(MetamodelBuilder::DataTypes::Enum) && c != MetamodelBuilder::DataTypes::Boolean) }),
:eSuperPackage => trans(name =~ /(.*)::\w+$/ ? eval($1) : nil),
:eSubpackages => trans(_constants.collect{|c| const_get(c)}.select{|c| c.is_a?(Module) && !c.is_a?(Class)}),
:eAnnotations => trans(_annotations)
}
end
method :convert? do
@current_object.respond_to?(:ecore) && @current_object != RGen::MetamodelBuilder::MMBase
end
transform MetamodelBuilder::Intermediate::Attribute, :to => EAttribute do
Hash[*MetamodelBuilder::Intermediate::Attribute.properties.collect{|p| [p, value(p)]}.flatten].merge({
:eType => (etype == :EEnumerable ? trans(impl_type) : RGen::ECore.const_get(etype)),
:eAnnotations => trans(annotations)
})
end
transform MetamodelBuilder::Intermediate::Reference, :to => EReference do
Hash[*MetamodelBuilder::Intermediate::Reference.properties.collect{|p| [p, value(p)]}.flatten].merge({
:eType => trans(impl_type),
:eOpposite => trans(opposite),
:eAnnotations => trans(annotations)
})
end
transform MetamodelBuilder::Intermediate::Annotation, :to => EAnnotation do
{ :source => source,
:details => details.keys.collect do |k|
e = RGen::ECore::EStringToStringMapEntry.new
e.key = k
e.value = details[k]
e
end
}
end
transform MetamodelBuilder::DataTypes::Enum, :to => EEnum do
{ :name => name,
:instanceClassName => @enumParentModule && @enumParentModule[@current_object] && @enumParentModule[@current_object].name+"::"+name,
:eLiterals => literals.collect do |l|
lit = RGen::ECore::EEnumLiteral.new
lit.name = l.to_s
lit
end }
end
end
end
end
rgen-0.7.0/lib/rgen/metamodel_builder/ 0000755 0000041 0000041 00000000000 12352210062 017650 5 ustar www-data www-data rgen-0.7.0/lib/rgen/metamodel_builder/builder_runtime.rb 0000644 0000041 0000041 00000011001 12352210062 023357 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
require 'rgen/util/name_helper'
module RGen
module MetamodelBuilder
# This module is mixed into MetamodelBuilder::MMBase.
# The methods provided by this module are used by the methods generated
# by the class methods of MetamodelBuilder::BuilderExtensions
module BuilderRuntime
include Util::NameHelper
def is_a?(c)
return super unless c.const_defined?(:ClassModule)
kind_of?(c::ClassModule)
end
def addGeneric(role, value, index=-1)
send("add#{firstToUpper(role.to_s)}",value, index)
end
def removeGeneric(role, value)
send("remove#{firstToUpper(role.to_s)}",value)
end
def setGeneric(role, value)
send("set#{firstToUpper(role.to_s)}",value)
end
def hasManyMethods(role)
respond_to?("add#{firstToUpper(role.to_s)}")
end
def setOrAddGeneric(role, value)
if hasManyMethods(role)
addGeneric(role, value)
else
setGeneric(role, value)
end
end
def setNilOrRemoveGeneric(role, value)
if hasManyMethods(role)
removeGeneric(role, value)
else
setGeneric(role, nil)
end
end
def setNilOrRemoveAllGeneric(role)
if hasManyMethods(role)
setGeneric(role, [])
else
setGeneric(role, nil)
end
end
def getGeneric(role)
send("get#{firstToUpper(role.to_s)}")
end
def getGenericAsArray(role)
result = getGeneric(role)
result = [result].compact unless result.is_a?(Array)
result
end
def eIsSet(role)
eval("defined? @#{role}") != nil
end
def eUnset(role)
if respond_to?("add#{firstToUpper(role.to_s)}")
setGeneric(role, [])
else
setGeneric(role, nil)
end
remove_instance_variable("@#{role}")
end
def eContainer
@_container
end
def eContainingFeature
@_containing_feature_name
end
# returns the contained elements in no particular order
def eContents
if @_contained_elements
@_contained_elements.dup
else
[]
end
end
# if a block is given, calls the block on every contained element in depth first order.
# if the block returns :prune, recursion will stop at this point.
#
# if no block is given builds and returns a list of all contained elements.
#
def eAllContents(&block)
if block
if @_contained_elements
@_contained_elements.each do |e|
res = block.call(e)
e.eAllContents(&block) if res != :prune
end
end
nil
else
result = []
if @_contained_elements
@_contained_elements.each do |e|
result << e
result.concat(e.eAllContents)
end
end
result
end
end
def disconnectContainer
eContainer.setNilOrRemoveGeneric(eContainingFeature, self) if eContainer
end
def _set_container(container, containing_feature_name)
# if a new container is set, make sure to disconnect from the old one.
# note that _set_container will never be called for the container and the role
# which are currently set because the accessor methods in BuilderExtensions
# block setting/adding a value which is already present.
# (it may be called for the same container with a different role, a different container
# with the same role and a different container with a different role, though)
# this ensures, that disconnecting for the current container doesn't break
# a new connection which has just been set up in the accessor methods.
disconnectContainer if container
@_container._remove_contained_element(self) if @_container
container._add_contained_element(self) if container
@_container = container
@_containing_feature_name = containing_feature_name
end
def _add_contained_element(element)
@_contained_elements ||= []
@_contained_elements << element
end
def _remove_contained_element(element)
@_contained_elements.delete(element) if @_contained_elements
end
def _assignmentTypeError(target, value, expected)
text = ""
if target
targetId = target.class.name
targetId += "(" + target.name + ")" if target.respond_to?(:name) and target.name
text += "In #{targetId} : "
end
valueId = value.class.name
valueId += "(" + value.name + ")" if value.respond_to?(:name) and value.name
valueId += "(:" + value.to_s + ")" if value.is_a?(Symbol)
text += "Can not use a #{valueId} where a #{expected} is expected"
StandardError.new(text)
end
end
end
end
rgen-0.7.0/lib/rgen/metamodel_builder/intermediate/ 0000755 0000041 0000041 00000000000 12352210062 022322 5 ustar www-data www-data rgen-0.7.0/lib/rgen/metamodel_builder/intermediate/feature.rb 0000644 0000041 0000041 00000006710 12352210062 024306 0 ustar www-data www-data require 'rgen/metamodel_builder/data_types'
module RGen
module MetamodelBuilder
module Intermediate
class Feature
attr_reader :etype, :impl_type
def value(prop)
@props[prop]
end
def annotations
@annotations ||= []
end
def many?
value(:upperBound) > 1 || value(:upperBound) == -1
end
def reference?
is_a?(Reference)
end
protected
def check(props)
@props.keys.each do |p|
kind = props[p]
raise StandardError.new("invalid property #{p}") unless kind
raise StandardError.new("property '#{p}' not set") if value(p).nil? && kind == :required
end
end
end
class Attribute < Feature
Properties = {
:name => :required,
:ordered => :required,
:unique => :required,
:changeable => :required,
:volatile => :required,
:transient => :required,
:unsettable => :required,
:derived => :required,
:lowerBound => :required,
:upperBound => :required,
:defaultValueLiteral => :optional
}
Defaults = {
:ordered => true,
:unique => true,
:changeable => true,
:volatile => false,
:transient => false,
:unsettable => false,
:derived => false,
:lowerBound => 0
}
Types = {
String => :EString,
Integer => :EInt,
RGen::MetamodelBuilder::DataTypes::Long => :ELong,
Float => :EFloat,
RGen::MetamodelBuilder::DataTypes::Boolean => :EBoolean,
Object => :ERubyObject,
Class => :ERubyClass
}
def self.default_value(prop)
Defaults[prop]
end
def self.properties
Properties.keys.sort{|a,b| a.to_s <=> b.to_s}
end
def initialize(type, props)
@props = Defaults.merge(props)
type ||= String
@etype = Types[type]
if @etype
@impl_type = type
elsif type.is_a?(RGen::MetamodelBuilder::DataTypes::Enum)
@etype = :EEnumerable
@impl_type = type
else
raise ArgumentError.new("invalid type '#{type}'")
end
if @props[:derived]
@props[:changeable] = false
@props[:volatile] = true
@props[:transient] = true
end
check(Properties)
end
end
class Reference < Feature
attr_accessor :opposite
Properties = {
:name => :required,
:ordered => :required,
:unique => :required,
:changeable => :required,
:volatile => :required,
:transient => :required,
:unsettable => :required,
:derived => :required,
:lowerBound => :required,
:upperBound => :required,
:resolveProxies => :required,
:containment => :required
}
Defaults = {
:ordered => true,
:unique => true,
:changeable => true,
:volatile => false,
:transient => false,
:unsettable => false,
:derived => false,
:lowerBound => 0,
:resolveProxies => true
}
def self.default_value(prop)
Defaults[prop]
end
def self.properties
Properties.keys.sort{|a,b| a.to_s <=> b.to_s}
end
def initialize(type, props)
@props = Defaults.merge(props)
if type.respond_to?(:_metamodel_description)
@etype = nil
@impl_type = type
else
raise ArgumentError.new("'#{type}' (#{type.class}) is not a MMBase in reference #{props[:name]}")
end
if @props[:derived]
@props[:changeable] = false
@props[:volatile] = true
@props[:transient] = true
end
check(Properties)
end
end
end
end
end
rgen-0.7.0/lib/rgen/metamodel_builder/intermediate/annotation.rb 0000644 0000041 0000041 00000001270 12352210062 025021 0 ustar www-data www-data module RGen
module MetamodelBuilder
module Intermediate
class Annotation
attr_reader :details, :source
def initialize(hash)
if hash[:source] || hash[:details]
restKeys = hash.keys - [:source, :details]
raise "Hash key #{restKeys.first} not allowed." unless restKeys.empty?
raise "Details not provided, key :details is missing" unless hash[:details]
raise "Details must be provided as a hash" unless hash[:details].is_a?(Hash)
@details = hash[:details]
@source = hash[:source]
else
raise "Details must be provided as a hash" unless hash.is_a?(Hash)
@details = hash
end
end
end
end
end
end
rgen-0.7.0/lib/rgen/metamodel_builder/module_extension.rb 0000644 0000041 0000041 00000001466 12352210062 023565 0 ustar www-data www-data require 'rgen/ecore/ecore_interface'
require 'rgen/metamodel_builder/intermediate/annotation'
module RGen
module MetamodelBuilder
# This module is used to extend modules which should be
# part of RGen metamodels
module ModuleExtension
include RGen::ECore::ECoreInterface
def annotation(hash)
_annotations << Intermediate::Annotation.new(hash)
end
def _annotations
@_annotations ||= []
end
def _constantOrder
@_constantOrder ||= []
end
def final_method(m)
@final_methods ||= []
@final_methods << m
end
def method_added(m)
raise "Method #{m} can not be redefined" if @final_methods && @final_methods.include?(m)
end
def self.extended(m)
MetamodelBuilder::ConstantOrderHelper.moduleCreated(m)
end
end
end
end
rgen-0.7.0/lib/rgen/metamodel_builder/data_types.rb 0000644 0000041 0000041 00000004442 12352210062 022336 0 ustar www-data www-data module RGen
module MetamodelBuilder
module DataTypes
# An enum object is used to describe possible attribute values within a
# MetamodelBuilder attribute definition. An attribute defined this way can only
# take the values specified when creating the Enum object.
# Literal values can only be symbols or true or false.
# Optionally a name may be specified for the enum object.
#
# Examples:
#
# Enum.new(:name => "AnimalEnum", :literals => [:cat, :dog])
# Enum.new(:literals => [:cat, :dog])
# Enum.new([:cat, :dog])
#
class Enum
attr_reader :name, :literals
# Creates a new named enum type object consisting of the elements passed as arguments.
def initialize(params)
MetamodelBuilder::ConstantOrderHelper.enumCreated(self)
if params.is_a?(Array)
@literals = params
@name = "anonymous"
elsif params.is_a?(Hash)
raise StandardError.new("Hash entry :literals is missing") unless params[:literals]
@literals = params[:literals]
@name = params[:name] || "anonymous"
else
raise StandardError.new("Pass an Array or a Hash")
end
end
# This method can be used to check if an object can be used as value for
# variables having this enum object as type.
def validLiteral?(l)
literals.include?(l)
end
def literals_as_strings
literals.collect do |l|
if l.is_a?(Symbol)
if l.to_s =~ /^\d|\W/
":'"+l.to_s+"'"
else
":"+l.to_s
end
elsif l.is_a?(TrueClass) || l.is_a?(FalseClass)
l.to_s
else
raise StandardError.new("Literal values can only be symbols or true/false")
end
end
end
def to_s # :nodoc:
name
end
end
# Boolean is a predefined enum object having Ruby's true and false singletons
# as possible values.
Boolean = Enum.new(:name => "Boolean", :literals => [true, false])
# Long represents a 64-bit Integer
# This constant is merely a marker for keeping this information in the Ruby version of the metamodel,
# values of this type will always be instances of Integer or Bignum;
# Setting it to a string value ensures that it responds to "to_s" which is used in the metamodel generator
Long = "Long"
end
end
end
rgen-0.7.0/lib/rgen/metamodel_builder/constant_order_helper.rb 0000644 0000041 0000041 00000006641 12352210062 024567 0 ustar www-data www-data module RGen
module MetamodelBuilder
# The purpose of the ConstantOrderHelper is to capture the definition order of RGen metamodel builder
# classes, modules and enums. The problem is that Ruby doesn't seem to track the order of
# constants being created in a module. However the order is important because it defines the order
# of eClassifiers and eSubpackages in a EPackage.
#
# It would be helpful here if Ruby provided a +const_added+ callback, but this is not the case up to now.
#
# The idea for capturing is that all events of creating a RGen class, module or enum are reported to the
# ConstantOrderHelper singleton.
# For classes and modules it tries to add their names to the parent's +_constantOrder+ array.
# The parent module is derived from the class's or module's name. However, the new name is only added
# if the respective parent module has a new constant (which is not yet in +_constantOrder+) which
# points to the new class or module.
# For enums it is a bit more complicated, because at the time the enum is created, the parent
# module does not yet contain the constant to which the enum is assigned. Therefor, the enum is remembered
# and it is tried to be stored on the next event (class, module or enum) within the module which was
# created last (which was last extended with ModuleExtension). If it can not be found in that module,
# all parent modules of the last module are searched. This way it should also be correctly entered in
# case it was defined outside of the last created module.
# Note that an enum is not stored to the constant order array unless another event occurs. That's why
# it is possible that one enum is missing at the enum. This needs to be taken care of by the ECore transformer.
#
# This way of capturing should be sufficient for the regular use cases of the RGen metamodel builder language.
# However, it is possible to write code which messes this up, see unit tests for details.
# In the worst case, the new classes, modules or enums will just not be found in a parent module and thus be ignored.
#
ConstantOrderHelper = Class.new do
def initialize
@currentModule = nil
@pendingEnum = nil
end
def classCreated(c)
handlePendingEnum
cont = containerModule(c)
name = (c.name || "").split("::").last
return unless cont.respond_to?(:_constantOrder) && !cont._constantOrder.include?(name)
cont._constantOrder << name
end
def moduleCreated(m)
handlePendingEnum
cont = containerModule(m)
name = (m.name || "").split("::").last
return unless cont.respond_to?(:_constantOrder) && !cont._constantOrder.include?(name)
cont._constantOrder << name
@currentModule = m
end
def enumCreated(e)
handlePendingEnum
@pendingEnum = e
end
private
def containerModule(m)
containerName = (m.name || "").split("::")[0..-2].join("::")
containerName.empty? ? nil : eval(containerName, TOPLEVEL_BINDING)
end
def handlePendingEnum
return unless @pendingEnum
m = @currentModule
while m
if m.respond_to?(:_constantOrder)
newConstants = m.constants - m._constantOrder
const = newConstants.find{|c| m.const_get(c).object_id == @pendingEnum.object_id}
if const
m._constantOrder << const.to_s
break
end
end
m = containerModule(m)
end
@pendingEnum = nil
end
end.new
end
end
rgen-0.7.0/lib/rgen/metamodel_builder/mm_multiple.rb 0000644 0000041 0000041 00000000650 12352210062 022522 0 ustar www-data www-data
module RGen
module MetamodelBuilder
def self.MMMultiple(*superclasses)
c = Class.new(MMBase)
class << c
attr_reader :multiple_superclasses
end
c.instance_variable_set(:@multiple_superclasses, superclasses)
superclasses.collect{|sc| sc.ancestors}.flatten.
reject{|m| m.is_a?(Class)}.each do |arg|
c.instance_eval do
include arg
end
end
return c
end
end
end rgen-0.7.0/lib/rgen/metamodel_builder/builder_extensions.rb 0000644 0000041 0000041 00000053566 12352210062 024121 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
require 'erb'
require 'rgen/metamodel_builder/intermediate/feature'
module RGen
module MetamodelBuilder
# This module provides methods which can be used to setup a metamodel element.
# The module is used to +extend+ MetamodelBuilder::MMBase, i.e. add the module's
# methods as class methods.
#
# MetamodelBuilder::MMBase should be used as a start for new metamodel elements.
# See MetamodelBuilder for an example.
#
module BuilderExtensions
include Util::NameHelper
class FeatureBlockEvaluator
def self.eval(block, props1, props2=nil)
return unless block
e = self.new(props1, props2)
e.instance_eval(&block)
end
def initialize(props1, props2)
@props1, @props2 = props1, props2
end
def annotation(hash)
@props1.annotations << Intermediate::Annotation.new(hash)
end
def opposite_annotation(hash)
raise "No opposite available" unless @props2
@props2.annotations << Intermediate::Annotation.new(hash)
end
end
# Add an attribute which can hold a single value.
# 'role' specifies the name which is used to access the attribute.
# 'target_class' specifies the type of objects which can be held by this attribute.
# If no target class is given, String will be default.
#
# This class method adds the following instance methods, where 'role' is to be
# replaced by the given role name:
# class#role # getter
# class#role=(value) # setter
def has_attr(role, target_class=nil, raw_props={}, &block)
props = Intermediate::Attribute.new(target_class, _ownProps(raw_props).merge({
:name=>role, :upperBound=>1}))
raise "No opposite available" unless _oppositeProps(raw_props).empty?
FeatureBlockEvaluator.eval(block, props)
_build_internal(props)
end
# Add an attribute which can hold multiple values.
# 'role' specifies the name which is used to access the attribute.
# 'target_class' specifies the type of objects which can be held by this attribute.
# If no target class is given, String will be default.
#
# This class method adds the following instance methods, where 'role' is to be
# replaced by the given role name:
# class#addRole(value, index=-1)
# class#removeRole(value)
# class#role # getter, returns an array
# class#role= # setter, sets multiple values at once
# Note that the first letter of the role name is turned into an uppercase
# for the add and remove methods.
def has_many_attr(role, target_class=nil, raw_props={}, &block)
props = Intermediate::Attribute.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
:name=>role})))
raise "No opposite available" unless _oppositeProps(raw_props).empty?
FeatureBlockEvaluator.eval(block, props)
_build_internal(props)
end
# Add a single unidirectional association.
# 'role' specifies the name which is used to access the association.
# 'target_class' specifies the type of objects which can be held by this association.
#
# This class method adds the following instance methods, where 'role' is to be
# replaced by the given role name:
# class#role # getter
# class#role=(value) # setter
#
def has_one(role, target_class=nil, raw_props={}, &block)
props = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
:name=>role, :upperBound=>1, :containment=>false}))
raise "No opposite available" unless _oppositeProps(raw_props).empty?
FeatureBlockEvaluator.eval(block, props)
_build_internal(props)
end
# Add an unidirectional _many_ association.
# 'role' specifies the name which is used to access the attribute.
# 'target_class' is optional and can be used to fix the type of objects which
# can be referenced by this association.
#
# This class method adds the following instance methods, where 'role' is to be
# replaced by the given role name:
# class#addRole(value, index=-1)
# class#removeRole(value)
# class#role # getter, returns an array
# Note that the first letter of the role name is turned into an uppercase
# for the add and remove methods.
#
def has_many(role, target_class=nil, raw_props={}, &block)
props = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
:name=>role, :containment=>false})))
raise "No opposite available" unless _oppositeProps(raw_props).empty?
FeatureBlockEvaluator.eval(block, props)
_build_internal(props)
end
def contains_one_uni(role, target_class=nil, raw_props={}, &block)
props = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
:name=>role, :upperBound=>1, :containment=>true}))
raise "No opposite available" unless _oppositeProps(raw_props).empty?
FeatureBlockEvaluator.eval(block, props)
_build_internal(props)
end
def contains_many_uni(role, target_class=nil, raw_props={}, &block)
props = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
:name=>role, :containment=>true})))
raise "No opposite available" unless _oppositeProps(raw_props).empty?
FeatureBlockEvaluator.eval(block, props)
_build_internal(props)
end
# Add a bidirectional one-to-many association between two classes.
# The class this method is called on is refered to as _own_class_ in
# the following.
#
# Instances of own_class can use 'own_role' to access _many_ associated instances
# of type 'target_class'. Instances of 'target_class' can use 'target_role' to
# access _one_ associated instance of own_class.
#
# This class method adds the following instance methods where 'ownRole' and
# 'targetRole' are to be replaced by the given role names:
# own_class#addOwnRole(value, index=-1)
# own_class#removeOwnRole(value)
# own_class#ownRole
# target_class#targetRole
# target_class#targetRole=(value)
# Note that the first letter of the role name is turned into an uppercase
# for the add and remove methods.
#
# When an element is added/set on either side, this element also receives the element
# is is added to as a new element.
#
def one_to_many(target_role, target_class, own_role, raw_props={}, &block)
props1 = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
:name=>target_role, :containment=>false})))
props2 = Intermediate::Reference.new(self, _oppositeProps(raw_props).merge({
:name=>own_role, :upperBound=>1, :containment=>false}))
FeatureBlockEvaluator.eval(block, props1, props2)
_build_internal(props1, props2)
end
def contains_many(target_role, target_class, own_role, raw_props={}, &block)
props1 = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
:name=>target_role, :containment=>true})))
props2 = Intermediate::Reference.new(self, _oppositeProps(raw_props).merge({
:name=>own_role, :upperBound=>1, :containment=>false}))
FeatureBlockEvaluator.eval(block, props1, props2)
_build_internal(props1, props2)
end
# This is the inverse of one_to_many provided for convenience.
def many_to_one(target_role, target_class, own_role, raw_props={}, &block)
props1 = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
:name=>target_role, :upperBound=>1, :containment=>false}))
props2 = Intermediate::Reference.new(self, _setManyUpperBound(_oppositeProps(raw_props).merge({
:name=>own_role, :containment=>false})))
FeatureBlockEvaluator.eval(block, props1, props2)
_build_internal(props1, props2)
end
# Add a bidirectional many-to-many association between two classes.
# The class this method is called on is refered to as _own_class_ in
# the following.
#
# Instances of own_class can use 'own_role' to access _many_ associated instances
# of type 'target_class'. Instances of 'target_class' can use 'target_role' to
# access _many_ associated instances of own_class.
#
# This class method adds the following instance methods where 'ownRole' and
# 'targetRole' are to be replaced by the given role names:
# own_class#addOwnRole(value, index=-1)
# own_class#removeOwnRole(value)
# own_class#ownRole
# target_class#addTargetRole
# target_class#removeTargetRole=(value)
# target_class#targetRole
# Note that the first letter of the role name is turned into an uppercase
# for the add and remove methods.
#
# When an element is added on either side, this element also receives the element
# is is added to as a new element.
#
def many_to_many(target_role, target_class, own_role, raw_props={}, &block)
props1 = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
:name=>target_role, :containment=>false})))
props2 = Intermediate::Reference.new(self, _setManyUpperBound(_oppositeProps(raw_props).merge({
:name=>own_role, :containment=>false})))
FeatureBlockEvaluator.eval(block, props1, props2)
_build_internal(props1, props2)
end
# Add a bidirectional one-to-one association between two classes.
# The class this method is called on is refered to as _own_class_ in
# the following.
#
# Instances of own_class can use 'own_role' to access _one_ associated instance
# of type 'target_class'. Instances of 'target_class' can use 'target_role' to
# access _one_ associated instance of own_class.
#
# This class method adds the following instance methods where 'ownRole' and
# 'targetRole' are to be replaced by the given role names:
# own_class#ownRole
# own_class#ownRole=(value)
# target_class#targetRole
# target_class#targetRole=(value)
#
# When an element is set on either side, this element also receives the element
# is is added to as the new element.
#
def one_to_one(target_role, target_class, own_role, raw_props={}, &block)
props1 = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
:name=>target_role, :upperBound=>1, :containment=>false}))
props2 = Intermediate::Reference.new(self, _oppositeProps(raw_props).merge({
:name=>own_role, :upperBound=>1, :containment=>false}))
FeatureBlockEvaluator.eval(block, props1, props2)
_build_internal(props1, props2)
end
def contains_one(target_role, target_class, own_role, raw_props={}, &block)
props1 = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
:name=>target_role, :upperBound=>1, :containment=>true}))
props2 = Intermediate::Reference.new(self, _oppositeProps(raw_props).merge({
:name=>own_role, :upperBound=>1, :containment=>false}))
FeatureBlockEvaluator.eval(block, props1, props2)
_build_internal(props1, props2)
end
def _metamodel_description # :nodoc:
@metamodel_description ||= []
end
def _add_metamodel_description(desc) # :nodoc
@metamodel_description ||= []
@metamodelDescriptionByName ||= {}
@metamodel_description.delete(@metamodelDescriptionByName[desc.value(:name)])
@metamodel_description << desc
@metamodelDescriptionByName[desc.value(:name)] = desc
end
def abstract
@abstract = true
end
def _abstract_class
@abstract || false
end
def inherited(c)
c.send(:include, c.const_set(:ClassModule, Module.new))
MetamodelBuilder::ConstantOrderHelper.classCreated(c)
end
protected
# Central builder method
#
def _build_internal(props1, props2=nil)
_add_metamodel_description(props1)
if props1.many?
_build_many_methods(props1, props2)
else
_build_one_methods(props1, props2)
end
if props2
# this is a bidirectional reference
props1.opposite, props2.opposite = props2, props1
other_class = props1.impl_type
other_class._add_metamodel_description(props2)
raise "Internal error: second description must be a reference description" \
unless props2.reference?
if props2.many?
other_class._build_many_methods(props2, props1)
else
other_class._build_one_methods(props2, props1)
end
end
end
# To-One association methods
#
def _build_one_methods(props, other_props=nil)
name = props.value(:name)
other_role = other_props && other_props.value(:name)
if props.value(:derived)
build_derived_method(name, props, :one)
else
@@one_read_builder ||= ERB.new <<-CODE
def get<%= firstToUpper(name) %>
<% if !props.reference? && props.value(:defaultValueLiteral) %>
<% defVal = props.value(:defaultValueLiteral) %>
<% check_default_value_literal(defVal, props) %>
<% defVal = '"'+defVal+'"' if props.impl_type == String %>
<% defVal = ':'+defVal if props.impl_type.is_a?(DataTypes::Enum) && props.impl_type != DataTypes::Boolean %>
(defined? @<%= name %>) ? @<%= name %> : <%= defVal %>
<% else %>
@<%= name %>
<% end %>
end
<% if name != "class" %>
alias <%= name %> get<%= firstToUpper(name) %>
<% end %>
CODE
self::ClassModule.module_eval(@@one_read_builder.result(binding))
end
if props.value(:changeable)
@@one_write_builder ||= ERB.new <<-CODE
def set<%= firstToUpper(name) %>(val)
return if (defined? @<%= name %>) && val == @<%= name %>
<%= type_check_code("val", props) %>
oldval = @<%= name %>
@<%= name %> = val
<% if other_role %>
oldval._unregister<%= firstToUpper(other_role) %>(self) unless oldval.nil? || oldval.is_a?(MMGeneric)
val._register<%= firstToUpper(other_role) %>(self) unless val.nil? || val.is_a?(MMGeneric)
<% end %>
<% if props.reference? && props.value(:containment) %>
val._set_container(self, :<%= name %>) unless val.nil?
oldval._set_container(nil, nil) unless oldval.nil?
<% end %>
end
alias <%= name %>= set<%= firstToUpper(name) %>
def _register<%= firstToUpper(name) %>(val)
<% if other_role %>
@<%= name %>._unregister<%= firstToUpper(other_role) %>(self) unless @<%= name %>.nil? || @<%= name %>.is_a?(MMGeneric)
<% end %>
<% if props.reference? && props.value(:containment) %>
@<%= name %>._set_container(nil, nil) unless @<%= name %>.nil?
val._set_container(self, :<%= name %>) unless val.nil?
<% end %>
@<%= name %> = val
end
def _unregister<%= firstToUpper(name) %>(val)
<% if props.reference? && props.value(:containment) %>
@<%= name %>._set_container(nil, nil) unless @<%= name %>.nil?
<% end %>
@<%= name %> = nil
end
CODE
self::ClassModule.module_eval(@@one_write_builder.result(binding))
end
end
# To-Many association methods
#
def _build_many_methods(props, other_props=nil)
name = props.value(:name)
other_role = other_props && other_props.value(:name)
if props.value(:derived)
build_derived_method(name, props, :many)
else
@@many_read_builder ||= ERB.new <<-CODE
def get<%= firstToUpper(name) %>
( @<%= name %> ? @<%= name %>.dup : [] )
end
<% if name != "class" %>
alias <%= name %> get<%= firstToUpper(name) %>
<% end %>
CODE
self::ClassModule.module_eval(@@many_read_builder.result(binding))
end
if props.value(:changeable)
@@many_write_builder ||= ERB.new <<-CODE
def add<%= firstToUpper(name) %>(val, index=-1)
@<%= name %> = [] unless @<%= name %>
return if val.nil? || (@<%= name %>.any?{|e| e.object_id == val.object_id} && (val.is_a?(MMBase) || val.is_a?(MMGeneric)))
<%= type_check_code("val", props) %>
@<%= name %>.insert(index, val)
<% if other_role %>
val._register<%= firstToUpper(other_role) %>(self) unless val.is_a?(MMGeneric)
<% end %>
<% if props.reference? && props.value(:containment) %>
val._set_container(self, :<%= name %>)
<% end %>
end
def remove<%= firstToUpper(name) %>(val)
@<%= name %> = [] unless @<%= name %>
@<%= name %>.each_with_index do |e,i|
if e.object_id == val.object_id
@<%= name %>.delete_at(i)
<% if props.reference? && props.value(:containment) %>
val._set_container(nil, nil)
<% end %>
<% if other_role %>
val._unregister<%= firstToUpper(other_role) %>(self) unless val.is_a?(MMGeneric)
<% end %>
return
end
end
end
def set<%= firstToUpper(name) %>(val)
return if val.nil?
raise _assignmentTypeError(self, val, Enumerable) unless val.is_a? Enumerable
get<%= firstToUpper(name) %>.each {|e|
remove<%= firstToUpper(name) %>(e)
}
val.each {|v|
add<%= firstToUpper(name) %>(v)
}
end
alias <%= name %>= set<%= firstToUpper(name) %>
def _register<%= firstToUpper(name) %>(val)
@<%= name %> = [] unless @<%= name %>
@<%= name %>.push val
<% if props.reference? && props.value(:containment) %>
val._set_container(self, :<%= name %>)
<% end %>
end
def _unregister<%= firstToUpper(name) %>(val)
@<%= name %>.delete val
<% if props.reference? && props.value(:containment) %>
val._set_container(nil, nil)
<% end %>
end
CODE
self::ClassModule.module_eval(@@many_write_builder.result(binding))
end
end
private
def build_derived_method(name, props, kind)
raise "Implement method #{name}_derived instead of method #{name}" \
if (public_instance_methods+protected_instance_methods+private_instance_methods).include?(name)
@@derived_builder ||= ERB.new <<-CODE
def get<%= firstToUpper(name) %>
raise "Derived feature requires public implementation of method <%= name %>_derived" \
unless respond_to?(:<%= name+"_derived" %>)
val = <%= name %>_derived
<% if kind == :many %>
raise _assignmentTypeError(self,val,Enumerable) unless val && val.is_a?(Enumerable)
val.each do |v|
<%= type_check_code("v", props) %>
end
<% else %>
<%= type_check_code("val", props) %>
<% end %>
val
end
<% if name != "class" %>
alias <%= name %> get<%= firstToUpper(name) %>
<% end %>
#TODO final_method :<%= name %>
CODE
self::ClassModule.module_eval(@@derived_builder.result(binding))
end
def check_default_value_literal(literal, props)
return if literal.nil? || props.impl_type == String
if props.impl_type == Integer || props.impl_type == RGen::MetamodelBuilder::DataTypes::Long
unless literal =~ /^\d+$/
raise StandardError.new("Property #{props.value(:name)} can not take value #{literal}, expected an Integer")
end
elsif props.impl_type == Float
unless literal =~ /^\d+\.\d+$/
raise StandardError.new("Property #{props.value(:name)} can not take value #{literal}, expected a Float")
end
elsif props.impl_type == RGen::MetamodelBuilder::DataTypes::Boolean
unless ["true", "false"].include?(literal)
raise StandardError.new("Property #{props.value(:name)} can not take value #{literal}, expected true or false")
end
elsif props.impl_type.is_a?(RGen::MetamodelBuilder::DataTypes::Enum)
unless props.impl_type.literals.include?(literal.to_sym)
raise StandardError.new("Property #{props.value(:name)} can not take value #{literal}, expected one of #{props.impl_type.literals_as_strings.join(', ')}")
end
else
raise StandardError.new("Unkown type "+props.impl_type.to_s)
end
end
def type_check_code(varname, props)
code = ""
if props.impl_type == RGen::MetamodelBuilder::DataTypes::Long
code << "unless #{varname}.nil? || #{varname}.is_a?(Integer) || #{varname}.is_a?(MMGeneric)"
code << "\n"
expected = "Integer"
elsif props.impl_type.is_a?(Class)
code << "unless #{varname}.nil? || #{varname}.is_a?(#{props.impl_type}) || #{varname}.is_a?(MMGeneric)"
code << " || #{varname}.is_a?(BigDecimal)" if props.impl_type == Float && defined?(BigDecimal)
code << "\n"
expected = props.impl_type.to_s
elsif props.impl_type.is_a?(RGen::MetamodelBuilder::DataTypes::Enum)
code << "unless #{varname}.nil? || [#{props.impl_type.literals_as_strings.join(',')}].include?(#{varname}) || #{varname}.is_a?(MMGeneric)\n"
expected = "["+props.impl_type.literals_as_strings.join(',')+"]"
else
raise StandardError.new("Unkown type "+props.impl_type.to_s)
end
code << "raise _assignmentTypeError(self,#{varname},\"#{expected}\")\n"
code << "end"
code
end
def _ownProps(props)
Hash[*(props.select{|k,v| !(k.to_s =~ /^opposite_/)}.flatten)]
end
def _oppositeProps(props)
r = {}
props.each_pair do |k,v|
if k.to_s =~ /^opposite_(.*)$/
r[$1.to_sym] = v
end
end
r
end
def _setManyUpperBound(props)
props[:upperBound] = -1 unless props[:upperBound].is_a?(Integer) && props[:upperBound] > 1
props
end
end
end
end
rgen-0.7.0/lib/rgen/environment.rb 0000644 0000041 0000041 00000005632 12352210062 017072 0 ustar www-data www-data module RGen
# An Environment is used to hold model elements.
#
class Environment
def initialize
@elements = {}
@subClasses = {}
@subClassesUpdated = {}
@deleted = {}
@deletedClasses = {}
end
# Add a model element. Returns the environment so <<
can be chained.
#
def <<(el)
clazz = el.class
@elements[clazz] ||= []
@elements[clazz] << el
updateSubClasses(clazz)
self
end
# Removes model element from environment.
def delete(el)
@deleted[el] = true
@deletedClasses[el.class] = true
end
# Iterates each element
#
def each(&b)
removeDeleted
@elements.values.flatten.each(&b)
end
# Return the elements of the environment as an array
#
def elements
removeDeleted
@elements.values.flatten
end
# This method can be used to instantiate a class and automatically put it into
# the environment. The new instance is returned.
#
def new(clazz, *args)
obj = clazz.new(*args)
self << obj
obj
end
# Finds and returns model elements in the environment.
#
# The search description argument must be a hash specifying attribute/value pairs.
# Only model elements are returned which respond to the specified attribute methods
# and return the specified values as result of these attribute methods.
#
# As a special hash key :class can be used to look for model elements of a specific
# class. In this case an array of possible classes can optionally be given.
#
def find(desc)
removeDeleted
result = []
classes = desc[:class] if desc[:class] and desc[:class].is_a?(Array)
classes = [ desc[:class] ] if !classes and desc[:class]
if classes
hashKeys = classesWithSubClasses(classes)
else
hashKeys = @elements.keys
end
hashKeys.each do |clazz|
next unless @elements[clazz]
@elements[clazz].each do |e|
failed = false
desc.each_pair { |k,v|
failed = true if k != :class and ( !e.respond_to?(k) or e.send(k) != v )
}
result << e unless failed
end
end
result
end
private
def removeDeleted
@deletedClasses.keys.each do |c|
@elements[c].reject!{|e| @deleted[e]}
end
@deletedClasses.clear
@deleted.clear
end
def updateSubClasses(clazz)
return if @subClassesUpdated[clazz]
if clazz.respond_to?( :ecore )
superClasses = clazz.ecore.eAllSuperTypes.collect{|c| c.instanceClass}
else
superClasses = superclasses(clazz)
end
superClasses.each do |c|
next if c == Object
@subClasses[c] ||= []
@subClasses[c] << clazz
end
@subClassesUpdated[clazz] = true
end
def classesWithSubClasses(classes)
result = classes
classes.each do |c|
result += @subClasses[c] if @subClasses[c]
end
result.uniq
end
def superclasses(clazz)
if clazz == Object
[]
else
superclasses(clazz.superclass) << clazz.superclass
end
end
end
end rgen-0.7.0/lib/rgen/util/ 0000755 0000041 0000041 00000000000 12352210062 015150 5 ustar www-data www-data rgen-0.7.0/lib/rgen/util/name_helper.rb 0000644 0000041 0000041 00000001244 12352210062 017755 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
module RGen
module Util
module NameHelper
def normalize(name)
name.gsub(/\W/,'_')
end
def className(object)
object.class.name =~ /::(\w+)$/; $1
end
def firstToUpper(str)
str[0..0].upcase + ( str[1..-1] || "" )
end
def firstToLower(str)
str[0..0].downcase + ( str[1..-1] || "" )
end
def saneClassName(str)
firstToUpper(normalize(str)).sub(/^Class$/, 'Clazz')
end
def saneMethodName(str)
firstToLower(normalize(str)).sub(/^class$/, 'clazz')
end
def camelize(str)
str.split(/[\W_]/).collect{|s| firstToUpper(s.downcase)}.join
end
end
end
end
rgen-0.7.0/lib/rgen/util/auto_class_creator.rb 0000644 0000041 0000041 00000001762 12352210062 021357 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
require 'rgen/metamodel_builder'
module RGen
module Util
class Base
extend MetamodelBuilder
def initialize(env=nil)
env << self if env
end
end
class AutoCreatedClass < Base
def method_missing(m,*args)
return super unless self.class.parent.accEnabled
if m.to_s =~ /(.*)=$/
self.class.has_one($1)
send(m,args[0])
elsif args.size == 0
self.class.has_many(m)
send(m)
end
end
end
# will be "extended" to the auto created class
module ParentAccess
def parent=(p)
@parent = p
end
def parent
@parent
end
end
module AutoClassCreator
attr_reader :accEnabled
def const_missing(className)
return super unless @accEnabled
module_eval("class "+className.to_s+" < RGen::AutoCreatedClass; end")
c = const_get(className)
c.extend(ParentAccess)
c.parent = self
c
end
def enableACC
@accEnabled = true
end
def disableACC
@accEnabled = false
end
end
end
end
rgen-0.7.0/lib/rgen/util/file_change_detector.rb 0000644 0000041 0000041 00000004555 12352210062 021623 0 ustar www-data www-data require 'digest'
module RGen
module Util
# The FileChangeDetector detects changes in a set of files.
# Changes are detected between successive calls to check_files with a give set of files.
# Changes include files being added, removed or having changed their content.
#
class FileChangeDetector
FileInfo = Struct.new(:timestamp, :digest)
# Create a FileChangeDetector, options include:
#
# :file_added
# a proc which is called when a file is added, receives the filename
#
# :file_removed
# a proc which is called when a file is removed, receives the filename
#
# :file_changed
# a proc which is called when a file is changed, receives the filename
#
def initialize(options={})
@file_added = options[:file_added]
@file_removed = options[:file_removed]
@file_changed = options[:file_changed]
@file_info = {}
end
# Checks if any of the files has changed compared to the last call of check_files.
# When called for the first time on a new object, all files will be reported as being added.
#
def check_files(files)
files_before = @file_info.keys
used_files = {}
files.each do |file|
begin
if @file_info[file]
if @file_info[file].timestamp != File.mtime(file)
@file_info[file].timestamp = File.mtime(file)
digest = calc_digest(file)
if @file_info[file].digest != digest
@file_info[file].digest = digest
@file_changed && @file_changed.call(file)
end
end
else
@file_info[file] = FileInfo.new
@file_info[file].timestamp = File.mtime(file)
@file_info[file].digest = calc_digest(file)
@file_added && @file_added.call(file)
end
used_files[file] = true
# protect against missing files
rescue Errno::ENOENT
# used_files is not set and @file_info will be removed below
# notification hook hasn't been called yet since it comes after file accesses
end
end
files_before.each do |file|
if !used_files[file]
@file_info.delete(file)
@file_removed && @file_removed.call(file)
end
end
end
private
def calc_digest(file)
sha1 = Digest::SHA1.new
sha1.file(file)
sha1.hexdigest
end
end
end
end
rgen-0.7.0/lib/rgen/util/model_comparator_base.rb 0000644 0000041 0000041 00000006632 12352210062 022025 0 ustar www-data www-data require 'andand'
module RGen
module Util
class ModelComparatorBase
CompareSpec = Struct.new(:identifier, :recurse, :filter, :ignore_features, :display_name, :sort)
INDENT = " "
class << self
attr_reader :compareSpecs
def compare_spec(clazz, hash)
@compareSpecs ||= {}
raise "Compare spec already defined for #{clazz}" if @compareSpecs[clazz]
spec = CompareSpec.new
hash.each_pair do |k,v|
spec.send("#{k}=",v)
end
@compareSpecs[clazz] = spec
end
end
# compares two sets of elements
def compare(as, bs, recursive=true)
result = []
aById = as.select{|e| useElement?(e)}.inject({}){|r, e| r[elementIdentifier(e)] = e; r}
bById = bs.select{|e| useElement?(e)}.inject({}){|r, e| r[elementIdentifier(e)] = e; r}
onlyA = sortElements((aById.keys - bById.keys).collect{|id| aById[id]})
onlyB = sortElements((bById.keys - aById.keys).collect{|id| bById[id]})
aAndB = sortElementPairs((aById.keys & bById.keys).collect{|id| [aById[id], bById[id]]})
onlyA.each do |e|
result << "- #{elementDisplayName(e)}"
end
onlyB.each do |e|
result << "+ #{elementDisplayName(e)}"
end
if recursive
aAndB.each do |ab|
a, b = *ab
r = compareElements(a, b)
if r.size > 0
result << "#{elementDisplayName(a)}"
result += r.collect{|l| INDENT+l}
end
end
end
result
end
def sortElementPairs(pairs)
pairs.sort do |x,y|
a, b = x[0], y[0]
r = a.class.name <=> b.class.name
r = compareSpec(a).sort.call(a,b) if r == 0 && compareSpec(a) && compareSpec(a).sort
r
end
end
def sortElements(elements)
elements.sort do |a,b|
r = a.class.name <=> b.class.name
r = compareSpec(a).sort.call(a,b) if r == 0 && compareSpec(a) && compareSpec(a).sort
r
end
end
def elementDisplayName(e)
if compareSpec(e) && compareSpec(e).display_name
compareSpec(e).display_name.call(e)
else
elementIdentifier(e)
end
end
def compareElements(a, b)
result = []
if a.class != b.class
result << "Class: #{a.class} -> #{b.class}"
else
a.class.ecore.eAllStructuralFeatures.reject{|f| f.derived || compareSpec(a).andand.ignore_features.andand.include?(f.name.to_sym)}.each do |f|
va, vb = a.getGeneric(f.name), b.getGeneric(f.name)
if f.is_a?(RGen::ECore::EAttribute)
r = compareValues(f.name, va, vb)
result << r if r
else
va, vb = [va].compact, [vb].compact unless f.many
r = compare(va, vb, f.containment || compareSpec(a).andand.recurse.andand.include?(f.name.to_sym))
if r.size > 0
result << "[#{f.name}]"
result += r.collect{|l| INDENT+l}
end
end
end
end
result
end
def compareValues(name, val1, val2)
result = nil
result = "[#{name}] #{val1} -> #{val2}" if val1 != val2
result
end
def elementIdentifier(element)
cs = compareSpec(element)
if cs && cs.identifier
if cs.identifier.is_a?(Proc)
cs.identifier.call(element)
else
cs.identifier
end
else
if element.respond_to?(:name)
element.name
else
element.object_id
end
end
end
def useElement?(element)
cs = compareSpec(element)
!(cs && cs.filter) || cs.filter.call(element)
end
def compareSpec(element)
@compareSpec ||= {}
return @compareSpec[element.class] if @compareSpec[element.class]
return nil unless self.class.compareSpecs
key = self.class.compareSpecs.keys.find{|k| element.is_a?(k)}
@compareSpec[element.class] = self.class.compareSpecs[key]
end
end
end
end
rgen-0.7.0/lib/rgen/util/model_dumper.rb 0000644 0000041 0000041 00000001047 12352210062 020153 0 ustar www-data www-data module RGen
module Util
module ModelDumper
def dump(obj=nil)
obj ||= self
if obj.is_a?(Array)
obj.collect {|o| dump(o)}.join("\n\n")
elsif obj.class.respond_to?(:ecore)
([obj.to_s] +
obj.class.ecore.eAllStructuralFeatures.select{|f| !f.many}.collect { |a|
" #{a} => #{obj.getGeneric(a.name)}"
} +
obj.class.ecore.eAllStructuralFeatures.select{|f| f.many}.collect { |a|
" #{a} => [ #{obj.getGeneric(a.name).join(', ')} ]"
}).join("\n")
else
obj.to_s
end
end
end
end
end
rgen-0.7.0/lib/rgen/util/file_cache_map.rb 0000644 0000041 0000041 00000007056 12352210062 020404 0 ustar www-data www-data require 'digest'
require 'fileutils'
module RGen
module Util
# Implements a cache for storing and loading data associated with arbitrary files.
# The data is stored in cache files within a subfolder of the folder where
# the associated files exists.
# The cache files are protected with a checksum and loaded data will be
# invalid in case either the associated file are the cache file has changed.
#
class FileCacheMap
# optional program version info to be associated with the cache files
# if the program version changes, cached data will also be invalid
attr_accessor :version_info
# +cache_dir+ is the name of the subfolder where cache files are created
# +postfix+ is an extension appended to the original file name for
# creating the name of the cache file
def initialize(cache_dir, postfix)
@postfix = postfix
@cache_dir = cache_dir
end
# load data associated with file +key_path+
# returns :invalid in case either the associated file or the cache file has changed
#
# options:
# :invalidation_reasons:
# an array which will receive symbols indicating why the cache is invalid:
# :no_cachefile, :cachefile_corrupted, :keyfile_changed
#
def load_data(key_path, options={})
reasons = options[:invalidation_reasons] || []
cf = cache_file(key_path)
result = nil
begin
File.open(cf, "rb") do |f|
header = f.read(41)
if !header
reasons << :cachefile_corrupted
return :invalid
end
checksum = header[0..39]
data = f.read
if calc_sha1(data) == checksum
if calc_sha1_keydata(key_path) == data[0..39]
result = data[41..-1]
else
reasons << :keyfile_changed
result = :invalid
end
else
reasons << :cachefile_corrupted
result = :invalid
end
end
rescue Errno::ENOENT
reasons << :no_cachefile
result = :invalid
end
result
end
# store data +value_data+ associated with file +key_path+
def store_data(key_path, value_data)
data = calc_sha1_keydata(key_path) + "\n" + value_data
data = calc_sha1(data) + "\n" + data
cf = cache_file(key_path)
FileUtils.mkdir(File.dirname(cf)) rescue Errno::EEXIST
File.open(cf, "wb") do |f|
f.write(data)
end
end
# remove cache files which are not associated with any file in +key_paths+
# will only remove files within +root_path+
def clean_unused(root_path, key_paths)
raise "key paths must be within root path" unless key_paths.all?{|p| p.index(root_path) == 0}
used_files = key_paths.collect{|p| cache_file(p)}
files = Dir[root_path+"/**/"+@cache_dir+"/*"+@postfix]
files.each do |f|
FileUtils.rm(f) unless used_files.include?(f)
end
end
private
def cache_file(path)
File.dirname(path) + "/"+@cache_dir+"/" + File.basename(path) + @postfix
end
def calc_sha1(data)
sha1 = Digest::SHA1.new
sha1.update(data)
sha1.hexdigest
end
def keyData(path)
File.read(path)+@version_info.to_s
end
# this method is much faster than calling +keyData+ and putting the result in +calc_sha1+
# reason is probably that there are not so many big strings being created
def calc_sha1_keydata(path)
begin
sha1 = Digest::SHA1.new
sha1.file(path)
sha1.update(@version_info.to_s)
sha1.hexdigest
rescue Errno::ENOENT
""
end
end
end
end
end
rgen-0.7.0/lib/rgen/util/model_comparator.rb 0000644 0000041 0000041 00000004001 12352210062 021017 0 ustar www-data www-data require 'rgen/ecore/ecore'
module RGen
module Util
module ModelComparator
# This method compares to models regarding equality
# For this the identity of a model element is defined based on identity
# of all attributes and referenced elements.
# Arrays are sorted before comparison if possible (if <=> is provided).
#
def modelEqual?(a, b, featureIgnoreList=[])
@modelEqual_visited = {}
_modelEqual_internal(a, b, featureIgnoreList, [])
end
def _modelEqual_internal(a, b, featureIgnoreList, path)
return true if @modelEqual_visited[[a,b]]
@modelEqual_visited[[a,b]] = true
return true if a.nil? && b.nil?
unless a.class == b.class
puts "#{path.inspect}\n Classes differ: #{a} vs. #{b}"
return false
end
if a.is_a?(Array)
unless a.size == b.size
puts "#{path.inspect}\n Array size differs: #{a.size} vs. #{b.size}"
return false
end
begin
# in Ruby 1.9 every object has the <=> operator but the default one returns
# nil and thus sorting won't work (ArgumentError)
as = a.sort
rescue ArgumentError, NoMethodError
as = a
end
begin
bs = b.sort
rescue ArgumentError, NoMethodError
bs = b
end
a.each_index do |i|
return false unless _modelEqual_internal(as[i], bs[i], featureIgnoreList, path+[i])
end
else
a.class.ecore.eAllStructuralFeatures.reject{|f| f.derived}.each do |feat|
next if featureIgnoreList.include?(feat.name)
if feat.eType.is_a?(RGen::ECore::EDataType)
unless a.getGeneric(feat.name) == b.getGeneric(feat.name)
puts "#{path.inspect}\n Value '#{feat.name}' differs: #{a.getGeneric(feat.name)} vs. #{b.getGeneric(feat.name)}"
return false
end
else
return false unless _modelEqual_internal(a.getGeneric(feat.name), b.getGeneric(feat.name), featureIgnoreList, path+["#{a.respond_to?(:name) && a.name}:#{feat.name}"])
end
end
end
return true
end
end
end
end
rgen-0.7.0/lib/rgen/util/cached_glob.rb 0000644 0000041 0000041 00000003443 12352210062 017713 0 ustar www-data www-data module RGen
module Util
# WARNING: the mechanism of taking timestamps of directories in order to find out if the
# content has changed doesn't work reliably across all kinds of filesystems
#
class CachedGlob
def initialize(dir_glob, file_glob)
@dir_glob = dir_glob
@file_glob = file_glob
@root_dirs = []
@dirs = {}
@files = {}
@timestamps = {}
end
# returns all files contained in directories matched by +dir_glob+ which match +file_glob+.
# +file_glob+ must be relative to +dir_glob+.
# dir_glob "*/a" with file_glob "**/*.txt" is basically equivalent with Dir.glob("*/a/**/*.txt")
# the idea is that the file glob will only be re-eavluated when the content of one of the
# directories matched by dir_glob has changed.
# this will only be faster than a normal Dir.glob if the number of dirs matched by dir_glob is
# relatively large and changes in files affect only a few of them at a time.
def glob
root_dirs = Dir.glob(@dir_glob)
(@root_dirs - root_dirs).each do |d|
remove_root_dir(d)
end
(@root_dirs & root_dirs).each do |d|
update_root_dir(d) if dir_changed?(d)
end
(root_dirs - @root_dirs).each do |d|
update_root_dir(d)
end
@root_dirs = root_dirs
@root_dirs.sort.collect{|d| @files[d]}.flatten
end
private
def dir_changed?(dir)
@dirs[dir].any?{|d| File.mtime(d) != @timestamps[dir][d]}
end
def update_root_dir(dir)
@dirs[dir] = Dir.glob(dir+"/**/")
@files[dir] = Dir.glob(dir+"/"+@file_glob)
@timestamps[dir] = {}
@dirs[dir].each do |d|
@timestamps[dir][d] = File.mtime(d)
end
end
def remove_root_dir(dir)
@dirs.delete(dir)
@files.delete(dir)
@timestamps.delete(dir)
end
end
end
end
rgen-0.7.0/lib/rgen/util/method_delegation.rb 0000644 0000041 0000041 00000005376 12352210062 021163 0 ustar www-data www-data module RGen
module Util
module MethodDelegation
class << self
def registerDelegate(delegate, object, method)
method = method.to_sym
createDelegateStore(object)
if object._methodDelegates[method]
object._methodDelegates[method] << delegate
else
object._methodDelegates[method] = [delegate]
createDelegatingMethod(object, method)
end
end
def unregisterDelegate(delegate, object, method)
method = method.to_sym
return unless object.respond_to?(:_methodDelegates)
return unless object._methodDelegates[method]
object._methodDelegates[method].delete(delegate)
if object._methodDelegates[method].empty?
object._methodDelegates[method] = nil
removeDelegatingMethod(object, method)
removeDelegateStore(object)
end
end
private
def createDelegateStore(object)
return if object.respond_to?(:_methodDelegates)
class << object
def _methodDelegates
@_methodDelegates ||= {}
end
end
end
def removeDelegateStore(object)
return unless object.respond_to?(:_methodDelegates)
class << object
remove_method(:_methodDelegates)
end
end
def createDelegatingMethod(object, method)
if hasMethod(object, method)
object.instance_eval <<-END
class << self
alias #{aliasMethodName(method)} #{method}
end
END
end
# define the delegating method
object.instance_eval <<-END
class << self
def #{method}(*args, &block)
@_methodDelegates[:#{method}].each do |d|
catch(:continue) do
return d.#{method}_delegated(self, *args, &block)
end
end
# if aliased method does not exist, we want an exception
#{aliasMethodName(method)}(*args, &block)
end
end
END
end
def removeDelegatingMethod(object, method)
if hasMethod(object, aliasMethodName(method))
# there is an aliased original, restore it
object.instance_eval <<-END
class << self
alias #{method} #{aliasMethodName(method)}
remove_method(:#{aliasMethodName(method)})
end
END
else
# just delete the delegating method
object.instance_eval <<-END
class << self
remove_method(:#{method})
end
END
end
end
def hasMethod(object, method)
# in Ruby 1.9, #methods returns symbols
if object.methods.first.is_a?(Symbol)
method = method.to_sym
else
method = method.to_s
end
object.methods.include?(method)
end
def aliasMethodName(method)
"#{method}_delegate_original"
end
end
end
end
end
rgen-0.7.0/lib/rgen/util/pattern_matcher.rb 0000644 0000041 0000041 00000023410 12352210062 020655 0 ustar www-data www-data module RGen
module Util
# A PatternMatcher can be used to find, insert and remove patterns on a given model.
#
# A pattern is specified by means of a block passed to the add_pattern method.
# The block must take an Environment as first parameter and at least one model element
# as connection point as further parameter. The pattern matches if it can be found
# in a given environment and connected to the given connection point elements.
#
class PatternMatcher
Match = Struct.new(:root, :elements, :bound_values)
attr_accessor :debug
def initialize
@patterns = {}
@insert_mode = false
@debug = false
end
def add_pattern(name, &block)
raise "a pattern needs at least 2 block parameters: " +
"an RGen environment and a model element as connection point" \
unless block.arity >= 2
@patterns[name] = block
end
def find_pattern(env, name, *connection_points)
match = find_pattern_internal(env, name, *connection_points)
end
def insert_pattern(env, name, *connection_points)
@insert_mode = true
root = evaluate_pattern(name, env, connection_points)
@insert_mode = false
root
end
def remove_pattern(env, name, *connection_points)
match = find_pattern_internal(env, name, *connection_points)
if match
match.elements.each do |e|
disconnect_element(e)
env.delete(e)
end
match
else
nil
end
end
def lazy(&block)
if @insert_mode
block.call
else
Lazy.new(&block)
end
end
class Lazy < RGen::MetamodelBuilder::MMGeneric
def initialize(&block)
@block = block
end
def _eval
@block.call
end
end
private
class Proxy < RGen::MetamodelBuilder::MMProxy
attr_reader :_target
def initialize(target)
@_target = target
end
def method_missing(m, *args)
result = @_target.send(m, *args)
if result.is_a?(Array)
result.collect do |e|
if e.is_a?(RGen::MetamodelBuilder::MMBase)
Proxy.new(e)
else
e
end
end
else
if result.is_a?(RGen::MetamodelBuilder::MMBase)
Proxy.new(result)
else
result
end
end
end
end
class Bindable < RGen::MetamodelBuilder::MMGeneric
# by being an Enumerable, Bindables can be used for many-features as well
include Enumerable
def initialize
@bound = false
@value = nil
@many = false
end
def _bound?
@bound
end
def _many?
@many
end
def _bind(value)
@value = value
@bound = true
end
def _value
@value
end
def to_s
@value.to_s
end
# pretend this is an enumerable which contains itself, so the bindable can be
# inserted into many-features, when this is done the bindable is marked as a many-bindable
def each
@many = true
yield(self)
end
def method_missing(m, *args)
raise "bindable not bound" unless _bound?
@value.send(m, *args)
end
end
TempEnv = RGen::Environment.new
class << TempEnv
def <<(el); end
end
def find_pattern_internal(env, name, *connection_points)
proxied_args = connection_points.collect{|a|
a.is_a?(RGen::MetamodelBuilder::MMBase) ? Proxy.new(a) : a }
bindables = create_bindables(name, connection_points)
pattern_root = evaluate_pattern(name, TempEnv, proxied_args+bindables)
candidates = candidates_via_connection_points(pattern_root, connection_points)
candidates ||= env.find(:class => pattern_root.class)
candidates.each do |e|
# create new bindables for every try, otherwise they can could be bound to old values
bindables = create_bindables(name, connection_points)
pattern_root = evaluate_pattern(name, TempEnv, proxied_args+bindables)
matched = match(pattern_root, e)
return Match.new(e, matched, bindables.collect{|b| b._value}) if matched
end
nil
end
def create_bindables(pattern_name, connection_points)
(1..(num_pattern_variables(pattern_name) - connection_points.size)).collect{|i| Bindable.new}
end
def candidates_via_connection_points(pattern_root, connection_points)
@candidates_via_connection_points_refs ||= {}
refs = (@candidates_via_connection_points_refs[pattern_root.class] ||=
pattern_root.class.ecore.eAllReferences.reject{|r| r.derived || r.many || !r.eOpposite})
candidates = nil
refs.each do |r|
t = pattern_root.getGeneric(r.name)
cp = t.is_a?(Proxy) && connection_points.find{|cp| cp.object_id == t._target.object_id}
if cp
elements = cp.getGenericAsArray(r.eOpposite.name)
candidates = elements if candidates.nil? || elements.size < candidates.size
end
end
candidates
end
def match(pat_element, test_element)
visited = {}
check_later = []
return false unless match_internal(pat_element, test_element, visited, check_later)
while cl = check_later.shift
pv, tv = cl.lazy._eval, cl.value
if cl.feature.is_a?(RGen::ECore::EAttribute)
unless pv == tv
match_failed(cl.feature, "wrong attribute value (lazy): #{pv} vs. #{tv}")
return false
end
else
if pv.is_a?(Proxy)
unless pv._target.object_id == tv.object_id
match_failed(f, "wrong target object")
return false
end
else
unless (pv.nil? && tv.nil?) || (!pv.nil? && !tv.nil? && match_internal(pv, tv, visited, check_later))
return false
end
end
end
end
visited.keys
end
CheckLater = Struct.new(:feature, :lazy, :value)
def match_internal(pat_element, test_element, visited, check_later)
return true if visited[test_element]
visited[test_element] = true
unless pat_element.class == test_element.class
match_failed(nil, "wrong class: #{pat_element.class} vs #{test_element.class}")
return false
end
all_structural_features(pat_element).each do |f|
pat_values = pat_element.getGeneric(f.name)
# nil values must be kept to support size check with Bindables
pat_values = [ pat_values ] unless pat_values.is_a?(Array)
test_values = test_element.getGeneric(f.name)
test_values = [ test_values] unless test_values.is_a?(Array)
if pat_values.size == 1 && pat_values.first.is_a?(Bindable) && pat_values.first._many?
unless match_many_bindable(pat_values.first, test_values)
return false
end
else
unless pat_values.size == test_values.size
match_failed(f, "wrong size #{pat_values.size} vs. #{test_values.size}")
return false
end
pat_values.each_with_index do |pv,i|
tv = test_values[i]
if pv.is_a?(Lazy)
check_later << CheckLater.new(f, pv, tv)
elsif pv.is_a?(Bindable)
if pv._bound?
unless pv._value == tv
match_failed(f, "value does not match bound value #{pv._value.class}:#{pv._value.object_id} vs. #{tv.class}:#{tv.object_id}")
return false
end
else
pv._bind(tv)
end
else
if f.is_a?(RGen::ECore::EAttribute)
unless pv == tv
match_failed(f, "wrong attribute value")
return false
end
else
if pv.is_a?(Proxy)
unless pv._target.object_id == tv.object_id
match_failed(f, "wrong target object")
return false
end
else
unless both_nil_or_match(pv, tv, visited, check_later)
return false
end
end
end
end
end
end
end
true
end
def match_many_bindable(bindable, test_values)
if bindable._bound?
bindable._value.each_with_index do |pv,i|
tv = test_values[i]
if f.is_a?(RGen::ECore::EAttribute)
unless pv == tv
match_failed(f, "wrong attribute value")
return false
end
else
unless both_nil_or_match(pv, tv, visited, check_later)
return false
end
end
end
else
bindable._bind(test_values.dup)
end
true
end
def both_nil_or_match(pv, tv, visited, check_later)
(pv.nil? && tv.nil?) || (!pv.nil? && !tv.nil? && match_internal(pv, tv, visited, check_later))
end
def match_failed(f, msg)
puts "match failed #{f&&f.eContainingClass.name}##{f&&f.name}: #{msg}" if @debug
end
def num_pattern_variables(name)
prok = @patterns[name]
prok.arity - 1
end
def evaluate_pattern(name, env, connection_points)
prok = @patterns[name]
raise "unknown pattern #{name}" unless prok
raise "wrong number of arguments, expected #{prok.arity-1} connection points)" \
unless connection_points.size == prok.arity-1
prok.call(env, *connection_points)
end
def disconnect_element(element)
return if element.nil?
all_structural_features(element).each do |f|
if f.many
element.setGeneric(f.name, [])
else
element.setGeneric(f.name, nil)
end
end
end
def all_structural_features(element)
@all_structural_features ||= {}
return @all_structural_features[element.class] if @all_structural_features[element.class]
@all_structural_features[element.class] =
element.class.ecore.eAllStructuralFeatures.reject{|f| f.derived}
end
end
end
end
rgen-0.7.0/lib/rgen/serializer/ 0000755 0000041 0000041 00000000000 12352210062 016344 5 ustar www-data www-data rgen-0.7.0/lib/rgen/serializer/qualified_name_provider.rb 0000644 0000041 0000041 00000002656 12352210062 023557 0 ustar www-data www-data module RGen
module Serializer
# simple identifier calculation based on qualified names.
# as a prerequisit, elements must have a local name stored in single attribute +attribute_name+.
# there may be classes without the name attribute though and there may be elements without a
# local name. in both cases the element will have the same qualified name as its container.
#
class QualifiedNameProvider
def initialize(options={})
@qualified_name_cache = {}
@attribute_name = options[:attribute_name] || "name"
@separator = options[:separator] || "/"
@leading_separator = options.has_key?(:leading_separator) ? options[:leading_separator] : true
end
def identifier(element)
if element.is_a?(RGen::MetamodelBuilder::MMProxy)
element.targetIdentifier
else
qualified_name(element)
end
end
def qualified_name(element)
return @qualified_name_cache[element] if @qualified_name_cache[element]
local_ident = ((element.respond_to?(@attribute_name) && element.getGeneric(@attribute_name)) || "").strip
parent = element.eContainer
if parent
if local_ident.size > 0
result = qualified_name(parent) + @separator + local_ident
else
result = qualified_name(parent)
end
else
result = (@leading_separator ? @separator : "") + local_ident
end
@qualified_name_cache[element] = result
end
end
end
end
rgen-0.7.0/lib/rgen/serializer/opposite_reference_filter.rb 0000644 0000041 0000041 00000001123 12352210062 024113 0 ustar www-data www-data module RGen
module Serializer
# Filters refereences with an eOpposite:
# 1. containment references are always preferred
# 2. at a 1-to-n reference the 1-reference is always preferred
# 3. otherwise the reference with the name in string sort order before the opposite's name is prefereed
#
OppositeReferenceFilter = proc do |features|
features.reject{|f| f.is_a?(RGen::ECore::EReference) && !f.containment && f.eOpposite &&
(f.eOpposite.containment || (f.many && !f.eOpposite.many) || (!(!f.many && f.eOpposite.many) && (f.name < f.eOpposite.name)))}
end
end
end
rgen-0.7.0/lib/rgen/serializer/json_serializer.rb 0000644 0000041 0000041 00000007203 12352210062 022075 0 ustar www-data www-data module RGen
module Serializer
class JsonSerializer
def initialize(writer, opts={})
@writer = writer
@elementIdentifiers = {}
@identAttrName = opts[:identAttrName] || "name"
@separator = opts[:separator] || "/"
@leadingSeparator = opts.has_key?(:leadingSeparator) ? opts[:leadingSeparator] : true
@featureFilter = opts[:featureFilter]
@identifierProvider = opts[:identifierProvider]
end
def elementIdentifier(element)
ident = @identifierProvider && @identifierProvider.call(element)
ident || (element.is_a?(RGen::MetamodelBuilder::MMProxy) && element.targetIdentifier) || qualifiedElementName(element)
end
# simple identifier calculation based on qualified names
# prerequisits:
# * containment relations must be bidirectionsl
# * local name stored in single attribute +@identAttrName+ for all classes
#
def qualifiedElementName(element)
return @elementIdentifiers[element] if @elementIdentifiers[element]
localIdent = ((element.respond_to?(@identAttrName) && element.getGeneric(@identAttrName)) || "").strip
parentRef = element.class.ecore.eAllReferences.select{|r| r.eOpposite && r.eOpposite.containment}.first
parent = parentRef && element.getGeneric(parentRef.name)
if parent
if localIdent.size > 0
parentIdent = qualifiedElementName(parent)
result = parentIdent + @separator + localIdent
else
result = qualifiedElementName(parent)
end
else
result = (@leadingSeparator ? @separator : "") + localIdent
end
@elementIdentifiers[element] = result
end
def serialize(elements)
if elements.is_a?(Array)
write("[ ")
elements.each_with_index do |e, i|
serializeElement(e)
write(",\n") unless i == elements.size-1
end
write("]")
else
serializeElement(elements)
end
end
def serializeElement(element, indent="")
write(indent + "{ \"_class\": \""+element.class.ecore.name+"\"")
element.class.ecore.eAllStructuralFeatures.each do |f|
next if f.derived
value = element.getGeneric(f.name)
unless value == [] || value.nil? ||
(f.is_a?(RGen::ECore::EReference) && f.eOpposite && f.eOpposite.containment) ||
(@featureFilter && !@featureFilter.call(f))
write(", ")
writeFeature(f, value, indent)
end
end
write(" }")
end
def writeFeature(feat, value, indent)
write("\""+feat.name+"\": ")
if feat.is_a?(RGen::ECore::EAttribute)
if value.is_a?(Array)
write("[ "+value.collect{|v| attributeValue(v, feat)}.join(", ")+" ]")
else
write(attributeValue(value, feat))
end
elsif !feat.containment
if value.is_a?(Array)
write("[ "+value.collect{|v| "\""+elementIdentifier(v)+"\""}.join(", ")+" ]")
else
write("\""+elementIdentifier(value)+"\"")
end
else
if value.is_a?(Array)
write("[ \n")
value.each_with_index do |v, i|
serializeElement(v, indent+" ")
write(",\n") unless i == value.size-1
end
write("]")
else
write("\n")
serializeElement(value, indent+" ")
end
end
end
def attributeValue(value, a)
if a.eType == RGen::ECore::EString || a.eType.is_a?(RGen::ECore::EEnum)
"\""+value.to_s.gsub('\\','\\\\\\\\').gsub('"','\\"').gsub("\n","\\n").gsub("\r","\\r").
gsub("\t","\\t").gsub("\f","\\f").gsub("\b","\\b")+"\""
else
value.to_s
end
end
private
def write(s)
@writer.write(s)
end
end
end
end
rgen-0.7.0/lib/rgen/serializer/xmi20_serializer.rb 0000644 0000041 0000041 00000004423 12352210062 022064 0 ustar www-data www-data require 'rgen/serializer/xml_serializer'
module RGen
module Serializer
class XMI20Serializer < XMLSerializer
def serialize(rootElement)
@referenceStrings = {}
buildReferenceStrings(rootElement, "#/")
addBuiltinReferenceStrings
attrs = attributeValues(rootElement)
attrs << ['xmi:version', "2.0"]
attrs << ['xmlns:xmi', "http://www.omg.org/XMI"]
attrs << ['xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"]
attrs << ['xmlns:ecore', "http://www.eclipse.org/emf/2002/Ecore" ]
tag = "ecore:"+rootElement.class.ecore.name
startTag(tag, attrs)
writeComposites(rootElement)
endTag(tag)
end
def writeComposites(element)
eachReferencedElement(element, containmentReferences(element)) do |r,te|
attrs = attributeValues(te)
attrs << ['xsi:type', "ecore:"+te.class.ecore.name]
tag = r.name
startTag(tag, attrs)
writeComposites(te)
endTag(tag)
end
end
def attributeValues(element)
result = []
eAllAttributes(element).select{|a| !a.derived}.each do |a|
val = element.getGeneric(a.name)
result << [a.name, val] unless val.nil? || val == ""
end
eAllReferences(element).select{|r| !r.containment && !(r.eOpposite && r.eOpposite.containment) && !r.derived}.each do |r|
targetElements = element.getGenericAsArray(r.name)
val = targetElements.collect{|te| @referenceStrings[te]}.compact.join(' ')
result << [r.name, val] unless val.nil? || val == ""
end
result
end
def buildReferenceStrings(element, string)
@referenceStrings[element] = string
eachReferencedElement(element, containmentReferences(element)) do |r,te|
buildReferenceStrings(te, string+"/"+te.name) if te.respond_to?(:name)
end
end
def addBuiltinReferenceStrings
pre = "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore"
@referenceStrings[RGen::ECore::EString] = pre+"#//EString"
@referenceStrings[RGen::ECore::EInt] = pre+"#//EInt"
@referenceStrings[RGen::ECore::ELong] = pre+"#//ELong"
@referenceStrings[RGen::ECore::EFloat] = pre+"#//EFloat"
@referenceStrings[RGen::ECore::EBoolean] = pre+"#//EBoolean"
@referenceStrings[RGen::ECore::EJavaObject] = pre+"#//EJavaObject"
@referenceStrings[RGen::ECore::EJavaClass] = pre+"#//EJavaClass"
end
end
end
end
rgen-0.7.0/lib/rgen/serializer/xml_serializer.rb 0000644 0000041 0000041 00000004345 12352210062 021730 0 ustar www-data www-data module RGen
module Serializer
class XMLSerializer
INDENT_SPACE = 2
def initialize(file)
@indent = 0
@lastStartTag = nil
@textContent = false
@file = file
end
def serialize(rootElement)
raise "Abstract class, overwrite method in subclass!"
end
def startTag(tag, attributes={})
@textContent = false
handleLastStartTag(false, true)
if attributes.is_a?(Hash)
attrString = attributes.keys.collect{|k| "#{k}=\"#{attributes[k]}\""}.join(" ")
else
attrString = attributes.collect{|pair| "#{pair[0]}=\"#{pair[1]}\""}.join(" ")
end
@lastStartTag = " "*@indent*INDENT_SPACE + "<#{tag} "+attrString
@indent += 1
end
def endTag(tag)
@indent -= 1
unless handleLastStartTag(true, true)
output " "*@indent*INDENT_SPACE unless @textContent
output "#{tag}>\n"
end
@textContent = false
end
def writeText(text)
handleLastStartTag(false, false)
output "#{text}"
@textContent = true
end
protected
def eAllReferences(element)
@eAllReferences ||= {}
@eAllReferences[element.class] ||= element.class.ecore.eAllReferences
end
def eAllAttributes(element)
@eAllAttributes ||= {}
@eAllAttributes[element.class] ||= element.class.ecore.eAllAttributes
end
def eAllStructuralFeatures(element)
@eAllStructuralFeatures ||= {}
@eAllStructuralFeatures[element.class] ||= element.class.ecore.eAllStructuralFeatures
end
def eachReferencedElement(element, refs, &block)
refs.each do |r|
targetElements = element.getGeneric(r.name)
targetElements = [targetElements] unless targetElements.is_a?(Array)
targetElements.each do |te|
yield(r,te)
end
end
end
def containmentReferences(element)
@containmentReferences ||= {}
@containmentReferences[element.class] ||= eAllReferences(element).select{|r| r.containment}
end
private
def handleLastStartTag(close, newline)
return false unless @lastStartTag
output @lastStartTag
output close ? "/>" : ">"
output "\n" if newline
@lastStartTag = nil
true
end
def output(text)
@file.write(text)
end
end
end
end
rgen-0.7.0/lib/rgen/serializer/xmi11_serializer.rb 0000644 0000041 0000041 00000005743 12352210062 022072 0 ustar www-data www-data require 'rgen/serializer/xml_serializer'
module RGen
module Serializer
class XMI11Serializer < XMLSerializer
def initialize(file)
super
@namespacePrefix = ""
@contentLevelElements = []
end
def setNamespace(shortcut, url)
@namespaceShortcut = shortcut
@namespaceUrl = url
@namespacePrefix = shortcut+":"
end
def serialize(rootElement, headerInfo=nil)
attrs = []
attrs << ['xmi.version', "1.1"]
attrs << ['xmlns:'+@namespaceShortcut, @namespaceUrl] if @namespaceUrl
attrs << ['timestamp', Time.now.to_s]
startTag("XMI", attrs)
if headerInfo
startTag("XMI.header")
writeHeaderInfo(headerInfo)
endTag("XMI.header")
end
startTag("XMI.content")
@contentLevelElements = []
writeElement(rootElement)
# write remaining toplevel elements, each of which could have
# more toplevel elements as childs
while @contentLevelElements.size > 0
writeElement(@contentLevelElements.shift)
end
endTag("XMI.content")
endTag("XMI")
end
def writeHeaderInfo(hash)
hash.each_pair do |k,v|
tag = "XMI." + k.to_s
startTag(tag)
if v.is_a?(Hash)
writeHeaderInfo(v)
else
writeText(v.to_s)
end
endTag(tag)
end
end
def writeElement(element)
tag = @namespacePrefix + element.class.ecore.name
attrs = attributeValues(element)
startTag(tag, attrs)
containmentReferences(element).each do |r|
roletag = @namespacePrefix + r.eContainingClass.name + "." + r.name
targets = element.getGeneric(r.name)
targets = [ targets ] unless targets.is_a?(Array)
targets.compact!
next if targets.empty?
startTag(roletag)
targets.each do |t|
if xmiLevel(t) == :content
@contentLevelElements << t
else
writeElement(t)
end
end
endTag(roletag)
end
endTag(tag)
end
def attributeValues(element)
result = [["xmi.id", xmiId(element)]]
eAllAttributes(element).select{|a| !a.derived}.each do |a|
val = element.getGeneric(a.name)
result << [a.name, val] unless val.nil? || val == ""
end
eAllReferences(element).each do |r|
next if r.derived
next if r.containment
next if r.eOpposite && r.eOpposite.containment && xmiLevel(element).nil?
next if r.eOpposite && r.many && !r.eOpposite.many
targetElements = element.getGenericAsArray(r.name)
targetElements.compact!
val = targetElements.collect{|te| xmiId(te)}.compact.join(' ')
result << [r.name, val] unless val == ""
end
result
end
def xmiId(element)
if element.respond_to?(:_xmi_id) && element._xmi_id
element._xmi_id.to_s
else
element.object_id.to_s
end
end
def xmiLevel(element)
return nil unless element.respond_to?(:_xmi_level)
element._xmi_level
end
end
end
end
rgen-0.7.0/lib/rgen/model_builder/ 0000755 0000041 0000041 00000000000 12352210062 017001 5 ustar www-data www-data rgen-0.7.0/lib/rgen/model_builder/builder_context.rb 0000644 0000041 0000041 00000025517 12352210062 022532 0 ustar www-data www-data require 'rgen/ecore/ecore_ext'
require 'rgen/model_builder/reference_resolver'
module RGen
module ModelBuilder
class BuilderContext
attr_reader :toplevelElements
def initialize(package, extensionsModule, resolver, env=nil)
package = package.ecore unless package.is_a?(RGen::ECore::EPackage)
raise "First argument must be a metamodel package" \
unless package.is_a?(RGen::ECore::EPackage)
@rootPackage, @env = package, env
@commandResolver = CommandResolver.new(package, extensionsModule, self)
@package = @rootPackage
@resolver = resolver
@contextStack = []
@toplevelElements = []
@helperNames = {}
end
def const_missing_delegated(delegator, const)
ConstPathElement.new(const, self)
end
# in Ruby 1.9.0 and 1.9.1 #instance_eval looks up constants in the calling scope
# that's why const_missing needs to be prepared in BuilderContext, too
class << self
def currentBuilderContext=(bc)
@@currentBuilderContext = bc
end
def const_missing(name)
if @@currentBuilderContext
ConstPathElement.new(name, @@currentBuilderContext)
else
super
end
end
end
class CommandResolver
def initialize(rootPackage, extensionsModule, builderContext)
@extensionFactory = ExtensionContainerFactory.new(rootPackage, extensionsModule, builderContext)
@packageResolver = PackageResolver.new(rootPackage, @extensionFactory)
@resolveCommand = {}
end
def resolveCommand(cmd, parentPackage)
return @resolveCommand[[parentPackage, cmd]] if @resolveCommand.has_key?([parentPackage, cmd])
package = @packageResolver.packageByCommand(parentPackage, cmd)
result = nil
if package
extensionContainer = @extensionFactory.extensionContainer(package)
if extensionContainer.respond_to?(cmd)
result = extensionContainer
else
className = cmd.to_s[0..0].upcase + cmd.to_s[1..-1]
result = package.eClasses.find{|c| c.name == className}
end
end
@resolveCommand[[parentPackage, cmd]] = [package, result]
end
end
def method_missing(m, *args, &block)
package, classOrContainer = @commandResolver.resolveCommand(m, @package)
return super if package.nil?
return classOrContainer.send(m, *args, &block) if classOrContainer.is_a?(ExtensionContainerFactory::ExtensionContainer)
eClass = classOrContainer
nameArg, argHash = self.class.processArguments(args)
internalName = nameArg || argHash[:name]
argHash[:name] ||= nameArg if nameArg && self.class.hasNameAttribute(eClass)
resolverJobs, asRole, helperName = self.class.filterArgHash(argHash, eClass)
element = eClass.instanceClass.new(argHash)
@resolver.setElementName(element, internalName)
@env << element if @env
contextElement = @contextStack.last
if contextElement
self.class.associateWithContextElement(element, contextElement, asRole)
else
@toplevelElements << element
end
resolverJobs.each do |job|
job.receiver = element
job.namespace = contextElement
@resolver.addJob(job)
end
# process block
if block
@contextStack.push(element)
@package, oldPackage = package, @package
instance_eval(&block)
@package = oldPackage
@contextStack.pop
end
element
end
def _using(constPathElement, &block)
@package, oldPackage =
self.class.resolvePackage(@package, @rootPackage, constPathElement.constPath), @package
instance_eval(&block)
@package = oldPackage
end
def _context(depth=1)
@contextStack[-depth]
end
class ExtensionContainerFactory
class ExtensionContainer
def initialize(builderContext)
@builderContext = builderContext
end
def method_missing(m, *args, &block)
@builderContext.send(m, *args, &block)
end
end
def initialize(rootPackage, extensionsModule, builderContext)
@rootPackage, @extensionsModule, @builderContext = rootPackage, extensionsModule, builderContext
@extensionContainer = {}
end
def moduleForPackage(package)
qName = package.qualifiedName
rqName = @rootPackage.qualifiedName
raise "Package #{qName} is not contained within #{rqName}" unless qName.index(rqName) == 0
path = qName.sub(rqName,'').split('::')
path.shift if path.first == ""
mod = @extensionsModule
path.each do |p|
if mod && mod.const_defined?(p)
mod = mod.const_get(p)
else
mod = nil
break
end
end
mod
end
def extensionContainer(package)
return @extensionContainer[package] if @extensionContainer[package]
container = ExtensionContainer.new(@builderContext)
extensionModule = moduleForPackage(package)
container.extend(extensionModule) if extensionModule
@extensionContainer[package] = container
end
end
class PackageResolver
def initialize(rootPackage, extensionFactory)
@rootPackage = rootPackage
@extensionFactory = extensionFactory
@packageByCommand = {}
end
def packageByCommand(contextPackage, name)
return @packageByCommand[[contextPackage, name]] if @packageByCommand.has_key?([contextPackage, name])
if @extensionFactory.extensionContainer(contextPackage).respond_to?(name)
result = contextPackage
else
className = name.to_s[0..0].upcase + name.to_s[1..-1]
eClass = contextPackage.eClasses.find{|c| c.name == className}
if eClass
result = contextPackage
elsif contextPackage != @rootPackage
result = packageByCommand(contextPackage.eSuperPackage, name)
else
result = nil
end
end
@packageByCommand[[contextPackage, name]] = result
end
end
class ConstPathElement < Module
def initialize(name, builderContext, parent=nil)
@name = name.to_s
@builderContext = builderContext
@parent = parent
end
def const_missing(const)
ConstPathElement.new(const, @builderContext, self)
end
def method_missing(m, *args, &block)
@builderContext._using(self) do
send(m, *args, &block)
end
end
def constPath
if @parent
@parent.constPath << @name
else
[@name]
end
end
end
# helper methods put in the class object to be out of the way of
# method evaluation in the builder context
class << self
class PackageNotFoundException < Exception
end
def resolvePackage(contextPackage, rootPackage, path)
begin
return resolvePackageDownwards(contextPackage, path)
rescue PackageNotFoundException
if contextPackage.eSuperPackage && contextPackage != rootPackage
return resolvePackage(contextPackage.eSuperPackage, rootPackage, path)
else
raise
end
end
end
def resolvePackageDownwards(contextPackage, path)
first, *rest = path
package = contextPackage.eSubpackages.find{|p| p.name == first}
raise PackageNotFoundException.new("Could not resolve package: #{first} is not a subpackage of #{contextPackage.name}") unless package
if rest.empty?
package
else
resolvePackageDownwards(package, rest)
end
end
def processArguments(args)
unless (args.size == 2 && args.first.is_a?(String) && args.last.is_a?(Hash)) ||
(args.size == 1 && (args.first.is_a?(String) || args.first.is_a?(Hash))) ||
args.size == 0
raise "Provide a Hash to set feature values, " +
"optionally the first argument may be a String specifying " +
"the value of the \"name\" attribute."
end
if args.last.is_a?(Hash)
argHash = args.last
else
argHash = {}
end
nameArg = args.first if args.first.is_a?(String)
[nameArg, argHash]
end
def filterArgHash(argHash, eClass)
resolverJobs = []
asRole, helperName = nil, nil
refByName = {}
eAllReferences(eClass).each {|r| refByName[r.name] = r}
argHash.each_pair do |k,v|
if k == :as
asRole = v
argHash.delete(k)
elsif k == :name && !hasNameAttribute(eClass)
helperName = v
argHash.delete(k)
elsif v.is_a?(String)
ref = refByName[k.to_s]#eAllReferences(eClass).find{|r| r.name == k.to_s}
if ref
argHash.delete(k)
resolverJobs << ReferenceResolver::ResolverJob.new(nil, ref, nil, v)
end
elsif v.is_a?(Array)
ref = refByName[k.to_s] #eAllReferences(eClass).find{|r| r.name == k.to_s}
ref && v.dup.each do |e|
if e.is_a?(String)
v.delete(e)
resolverJobs << ReferenceResolver::ResolverJob.new(nil, ref, nil, e)
end
end
end
end
[ resolverJobs, asRole, helperName ]
end
def hasNameAttribute(eClass)
@hasNameAttribute ||= {}
@hasNameAttribute[eClass] ||= eClass.eAllAttributes.any?{|a| a.name == "name"}
end
def eAllReferences(eClass)
@eAllReferences ||= {}
@eAllReferences[eClass] ||= eClass.eAllReferences
end
def containmentRefs(contextClass, eClass)
@containmentRefs ||= {}
@containmentRefs[[contextClass, eClass]] ||=
eAllReferences(contextClass).select do |r|
r.containment && (eClass.eAllSuperTypes << eClass).include?(r.eType)
end
end
def associateWithContextElement(element, contextElement, asRole)
return unless contextElement
contextClass = contextElement.class.ecore
if asRole
asRoleRef = eAllReferences(contextClass).find{|r| r.name == asRole.to_s}
raise "Context class #{contextClass.name} has no reference named #{asRole}" unless asRoleRef
ref = asRoleRef
else
possibleContainmentRefs = containmentRefs(contextClass, element.class.ecore)
if possibleContainmentRefs.size == 1
ref = possibleContainmentRefs.first
elsif possibleContainmentRefs.size == 0
raise "Context class #{contextClass.name} can not contain a #{element.class.ecore.name}"
else
raise "Context class #{contextClass.name} has several containment references to a #{element.class.ecore.name}." +
" Clearify using \":as => \""
end
end
if ref.many
contextElement.addGeneric(ref.name, element)
else
contextElement.setGeneric(ref.name, element)
end
end
end
end
end
end
rgen-0.7.0/lib/rgen/model_builder/model_serializer.rb 0000644 0000041 0000041 00000017306 12352210062 022666 0 ustar www-data www-data require 'rgen/array_extensions'
require 'rgen/ecore/ecore_ext'
module RGen
module ModelBuilder
class ModelSerializer
def initialize(writable, rootPackage)
@writable = writable
@currentPackage = rootPackage
@qualifiedElementName = {}
@internalElementName = {}
@relativeQualifiedElementName = {}
end
def serialize(elements)
calcQualifiedElementNames(elements)
unifyQualifiedElementNames
elements = [elements] unless elements.is_a?(Enumerable)
elements.each do |e|
serializeElement(e)
end
end
private
def serializeElement(element, viaRef=nil, namePath=[], indent=0)
className = element.class.ecore.name
cmd = className[0..0].downcase+className[1..-1]
args = ["\"#{@internalElementName[element]}\""]
namePath = namePath + [@internalElementName[element]]
childs = []
eAllStructuralFeatures(element).each do |f|
next if f.derived
if f.is_a?(RGen::ECore::EAttribute)
next if f.name == "name" && element.name == @internalElementName[element]
val = element.getGeneric(f.name)
#puts f.defaultValue.inspect if f.name == "isRoot"
args << ":#{f.name} => #{serializeAttribute(val)}" unless val == f.defaultValue || val.nil?
elsif !f.containment
next if f.eOpposite && f.eOpposite == viaRef
val = element.getGeneric(f.name)
refString = serializeReference(element, f, val)
args << ":#{f.name} => #{refString}" if refString
else
cs = element.getGeneric(f.name)
refString = nil
if cs.is_a?(Array)
cs.compact!
rcs = cs.select{|c| serializeChild?(c, namePath)}
childs << [f, rcs] unless rcs.empty?
refString = serializeReference(element, f, cs-rcs)
else
if cs && serializeChild?(cs, namePath)
childs << [f, [cs]]
else
refString = serializeReference(element, f, cs)
end
end
args << ":#{f.name} => #{refString}" if refString
end
end
args << ":as => :#{viaRef.name}" if viaRef && containmentRefs(viaRef.eContainingClass, element.class.ecore).size > 1
cmd = elementPackage(element)+"."+cmd if elementPackage(element).size > 0
@writable.write " " * indent + cmd + " " + args.join(", ")
if childs.size > 0
@writable.write " do\n"
oldPackage, @currentPackage = @currentPackage, element.class.ecore.ePackage
childs.each do |pair|
f, cs = pair
cs.each {|c| serializeElement(c, f, namePath, indent+1) }
end
@currentPackage = oldPackage
@writable.write " " * indent + "end\n"
else
@writable.write "\n"
end
end
def serializeChild?(child, namePath)
@qualifiedElementName[child][0..-2] == namePath
end
def serializeAttribute(value)
if value.is_a?(String)
"\"#{value.gsub("\"","\\\"")}\""
elsif value.is_a?(Symbol)
":#{value}"
elsif value.nil?
"nil"
else
value.to_s
end
end
def serializeReference(element, ref, value)
if value.is_a?(Array)
value = value.compact
value = value.select{|v| compareWithOppositeReference(ref, element, v) > 0} if ref.eOpposite
qualNames = value.collect do |v|
relativeQualifiedElementName(v, element).join(".")
end
!qualNames.empty? && ("[" + qualNames.collect { |v| "\"#{v}\"" }.join(", ") + "]")
elsif value && (!ref.eOpposite || compareWithOppositeReference(ref, element, value) > 0)
qualName = relativeQualifiedElementName(value, element).join(".")
("\"#{qualName}\"")
end
end
# descide which part of a bidirectional reference get serialized
def compareWithOppositeReference(ref, element, target)
result = 0
# first try to make the reference from the many side to the one side
result = -1 if ref.many && !ref.eOpposite.many
result = 1 if !ref.many && ref.eOpposite.many
return result if result != 0
# for 1:1 or many:many perfer, shorter references
result = relativeQualifiedElementName(element, target).size <=>
relativeQualifiedElementName(target, element).size
return result if result != 0
# there just needs to be a descision, use class name or object_id
result = element.class.name <=> target.class.name
return result if result != 0
element.object_id <=> target.object_id
end
def elementPackage(element)
@elementPackage ||= {}
return @elementPackage[element] if @elementPackage[element]
eNames = element.class.ecore.ePackage.qualifiedName.split("::")
rNames = @currentPackage.qualifiedName.split("::")
while eNames.first == rNames.first && !eNames.first.nil?
eNames.shift
rNames.shift
end
@elementPackage[element] = eNames.join("::")
end
def relativeQualifiedElementName(element, context)
return @relativeQualifiedElementName[[element, context]] if @relativeQualifiedElementName[[element, context]]
# elements which are not in the @qualifiedElementName Hash are not in the scope
# of this serialization and will be ignored
return [] if element.nil? || @qualifiedElementName[element].nil?
return [] if context.nil? || @qualifiedElementName[context].nil?
eNames = @qualifiedElementName[element].dup
cNames = @qualifiedElementName[context].dup
while eNames.first == cNames.first && eNames.size > 1
eNames.shift
cNames.shift
end
@relativeQualifiedElementName[[element, context]] = eNames
end
def calcQualifiedElementNames(elements, prefix=[], takenNames=[])
elements = [elements] unless elements.is_a?(Array)
elements.compact!
elements.each do |element|
qualifiedNamePath = prefix + [calcInternalElementName(element, takenNames)]
@qualifiedElementName[element] ||= []
@qualifiedElementName[element] << qualifiedNamePath
takenChildNames = []
eAllStructuralFeatures(element).each do |f|
if f.is_a?(RGen::ECore::EReference) && f.containment
childs = element.getGeneric(f.name)
calcQualifiedElementNames(childs, qualifiedNamePath, takenChildNames)
end
end
end
end
def unifyQualifiedElementNames
@qualifiedElementName.keys.each do |k|
@qualifiedElementName[k] = @qualifiedElementName[k].sort{|a,b| a.size <=> b.size}.first
end
end
def calcInternalElementName(element, takenNames)
return @internalElementName[element] if @internalElementName[element]
name = if element.respond_to?(:name) && element.name && !element.name.empty?
element.name
else
nextElementHelperName(element)
end
while takenNames.include?(name)
name = nextElementHelperName(element)
end
takenNames << name
@internalElementName[element] = name
end
def nextElementHelperName(element)
eClass = element.class.ecore
@nextElementNameId ||= {}
@nextElementNameId[eClass] ||= 1
result = "_#{eClass.name}#{@nextElementNameId[eClass]}"
@nextElementNameId[eClass] += 1
result
end
def eAllStructuralFeatures(element)
@eAllStructuralFeatures ||= {}
@eAllStructuralFeatures[element.class] ||= element.class.ecore.eAllStructuralFeatures
end
def eAllReferences(eClass)
@eAllReferences ||= {}
@eAllReferences[eClass] ||= eClass.eAllReferences
end
def containmentRefs(contextClass, eClass)
@containmentRefs ||= {}
@containmentRefs[[contextClass, eClass]] ||=
eAllReferences(contextClass).select do |r|
r.containment && (eClass.eAllSuperTypes << eClass).include?(r.eType)
end
end
end
end
end
rgen-0.7.0/lib/rgen/model_builder/reference_resolver.rb 0000644 0000041 0000041 00000010503 12352210062 023204 0 ustar www-data www-data require 'rgen/array_extensions'
module RGen
module ModelBuilder
class ReferenceResolver
ResolverJob = Struct.new(:receiver, :reference, :namespace, :string)
class ResolverException < Exception
end
class ToplevelNamespace
def initialize(ns)
raise "Namespace must be an Enumerable" unless ns.is_a?(Enumerable)
@ns = ns
end
def elements
@ns
end
end
def initialize
@jobs = []
@elementName = {}
end
def addJob(job)
@jobs << job
end
def setElementName(element, name)
@elementName[element] = name
end
def resolve(ns=[])
@toplevelNamespace = ToplevelNamespace.new(ns)
(@jobs || []).each_with_index do |job, i|
target = resolveReference(job.namespace || @toplevelNamespace, job.string.split("."))
raise ResolverException.new("Can not resolve reference #{job.string}") unless target
if job.reference.many
job.receiver.addGeneric(job.reference.name, target)
else
job.receiver.setGeneric(job.reference.name, target)
end
end
end
private
# TODO: if a reference can not be fully resolved, but a prefix can be found,
# the exception reported is that its first path element can not be found on
# toplevel
def resolveReference(namespace, nameParts)
element = resolveReferenceDownwards(namespace, nameParts)
if element.nil? && parentNamespace(namespace)
element = resolveReference(parentNamespace(namespace), nameParts)
end
element
end
def resolveReferenceDownwards(namespace, nameParts)
firstPart, *restParts = nameParts
element = namespaceElementByName(namespace, firstPart)
return nil unless element
if restParts.size > 0
resolveReferenceDownwards(element, restParts)
else
element
end
end
def namespaceElementByName(namespace, name)
@namespaceElementsByName ||= {}
return @namespaceElementsByName[namespace][name] if @namespaceElementsByName[namespace]
hash = {}
namespaceElements(namespace).each do |e|
raise ResolverException.new("Multiple elements named #{elementName(e)} found in #{nsToS(namespace)}") if hash[elementName(e)]
hash[elementName(e)] = e if elementName(e)
end
@namespaceElementsByName[namespace] = hash
hash[name]
end
def parentNamespace(namespace)
if namespace.class.respond_to?(:ecore)
parents = elementParents(namespace)
raise ResolverException.new("Element #{nsToS(namespace)} has multiple parents") \
if parents.size > 1
parents.first || @toplevelNamespace
else
nil
end
end
def namespaceElements(namespace)
if namespace.is_a?(ToplevelNamespace)
namespace.elements
elsif namespace.class.respond_to?(:ecore)
elementChildren(namespace)
else
raise ResolverException.new("Element #{nsToS(namespace)} can not be used as a namespace")
end
end
def nsToS(namespace)
if namespace.is_a?(ToplevelNamespace)
"toplevel namespace"
else
result = namespace.class.name
result += ":\"#{elementName(namespace)}\"" if elementName(namespace)
result
end
end
def elementName(element)
@elementName[element]
end
def elementChildren(element)
@elementChildren ||= {}
return @elementChildren[element] if @elementChildren[element]
children = containmentRefs(element).collect do |r|
element.getGeneric(r.name)
end.flatten.compact
@elementChildren[element] = children
end
def elementParents(element)
@elementParents ||= {}
return @elementParents[element] if @elementParents[element]
parents = parentRefs(element).collect do |r|
element.getGeneric(r.name)
end.flatten.compact
@elementParents[element] = parents
end
def containmentRefs(element)
@containmentRefs ||= {}
@containmentRefs[element.class] ||= eAllReferences(element).select{|r| r.containment}
end
def parentRefs(element)
@parentRefs ||= {}
@parentRefs[element.class] ||= eAllReferences(element).select{|r| r.eOpposite && r.eOpposite.containment}
end
def eAllReferences(element)
@eAllReferences ||= {}
@eAllReferences[element.class] ||= element.class.ecore.eAllReferences
end
end
end
end rgen-0.7.0/lib/rgen/instantiator/ 0000755 0000041 0000041 00000000000 12352210062 016712 5 ustar www-data www-data rgen-0.7.0/lib/rgen/instantiator/ecore_xml_instantiator.rb 0000644 0000041 0000041 00000012125 12352210062 024014 0 ustar www-data www-data require 'rgen/ecore/ecore'
require 'rgen/instantiator/abstract_xml_instantiator'
require 'rgen/array_extensions'
class ECoreXMLInstantiator < AbstractXMLInstantiator
include RGen::ECore
INFO = 0
WARN = 1
ERROR = 2
def initialize(env, loglevel=ERROR)
@env = env
@rolestack = []
@elementstack = []
@element_by_id = {}
@loglevel = loglevel
end
def start_tag(prefix, tag, namespaces, attributes)
eRef = nil
if @elementstack.last
eRef = eAllReferences(@elementstack.last).find{|r|r.name == tag}
if eRef
if attributes["xsi:type"] && attributes["xsi:type"] =~ /ecore:(\w+)/
class_name = $1
attributes.delete("xsi:type")
else
class_name = eRef.eType.name
end
else
raise "Reference not found: #{tag} on #{@elementstack.last}"
end
else
class_name = tag
end
eClass = RGen::ECore.ecore.eClassifiers.find{|c| c.name == class_name}
if eClass
obj = RGen::ECore.const_get(class_name).new
if attributes["xmi:id"]
@element_by_id[attributes["xmi:id"]] = obj
attributes.delete("xmi:id")
end
if eRef
if eRef.many
@elementstack.last.addGeneric(eRef.name, obj)
else
@elementstack.last.setGeneric(eRef.name, obj)
end
end
@env << obj
@elementstack.push obj
else
log WARN, "Class not found: #{class_name}"
@elementstack.push nil
end
attributes.each_pair do |attr, value|
set_attribute_internal(attr, value)
end
end
def end_tag(prefix, tag)
@elementstack.pop
end
ResolverDescription = Struct.new(:object, :attribute, :value)
def set_attribute(attr, value)
# do nothing, already handled by start_tag/set_attribute_internal
end
def set_attribute_internal(attr, value)
return unless @elementstack.last
eFeat = eAllStructuralFeatures(@elementstack.last).find{|a| a.name == attr}
if eFeat.is_a?(EReference)
rd = ResolverDescription.new
rd.object = @elementstack.last
rd.attribute = attr
rd.value = value
@resolver_descs << rd
elsif eFeat
value = true if value == "true" && eFeat.eType == EBoolean
value = false if value == "false" && eFeat.eType == EBoolean
value = value.to_i if eFeat.eType == EInt || eFeat.eType == ELong
@elementstack.last.setGeneric(attr, value)
else
log WARN, "Feature not found: #{attr} on #{@elementstack.last}"
end
end
def instantiate(str)
@resolver_descs = []
# puts "Instantiating ..."
super(str, 1000)
rootpackage = @env.find(:class => EPackage).first
# puts "Resolving ..."
@resolver_descs.each do |rd|
refed = find_referenced(rootpackage, rd.value)
feature = eAllStructuralFeatures(rd.object).find{|f| f.name == rd.attribute}
raise StandardError.new("StructuralFeature not found: #{rd.attribute}") unless feature
if feature.many
rd.object.setGeneric(feature.name, refed)
else
rd.object.setGeneric(feature.name, refed.first)
end
end
end
def eAllReferences(element)
@eAllReferences ||= {}
@eAllReferences[element.class] ||= element.class.ecore.eAllReferences
end
def eAllAttributes(element)
@eAllAttributes ||= {}
@eAllAttributes[element.class] ||= element.class.ecore.eAllAttributes
end
def eAllStructuralFeatures(element)
@eAllStructuralFeatures ||= {}
@eAllStructuralFeatures[element.class] ||= element.class.ecore.eAllStructuralFeatures
end
def find_referenced(context, desc)
desc.split(/\s+/).collect do |r|
if r =~ /^#([^\/]+)$/
@element_by_id[$1]
elsif r =~ /^#\/\d*\/([\w\/]+)/
find_in_context(context, $1.split('/'))
elsif r =~ /#\/\/(\w+)$/
case $1
when "EString"; RGen::ECore::EString
when "EInt"; RGen::ECore::EInt
when "ELong"; RGen::ECore::ELong
when "EBoolean"; RGen::ECore::EBoolean
when "EFloat"; RGen::ECore::EFloat
when "EJavaObject"; RGen::ECore::EJavaObject
when "EJavaClass"; RGen::ECore::EJavaClass
end
end
end.compact
end
def find_in_context(context, desc_elements)
if context.is_a?(EPackage)
r = (context.eClassifiers + context.eSubpackages).find{|c| c.name == desc_elements.first}
elsif context.is_a?(EClass)
r = context.eStructuralFeatures.find{|s| s.name == desc_elements.first}
else
raise StandardError.new("Don't know how to find #{desc_elements.join('/')} in context #{context}")
end
if r
if desc_elements.size > 1
find_in_context(r, desc_elements[1..-1])
else
r
end
else
log WARN, "Can not follow path, element #{desc_elements.first} not found within #{context}(#{context.name})"
end
end
def log(level, msg)
puts %w(INFO WARN ERROR)[level] + ": " + msg if level >= @loglevel
end
end
rgen-0.7.0/lib/rgen/instantiator/abstract_xml_instantiator.rb 0000644 0000041 0000041 00000003760 12352210062 024527 0 ustar www-data www-data require 'nokogiri'
class AbstractXMLInstantiator
class Visitor < Nokogiri::XML::SAX::Document
def initialize(inst, gcSuspendCount)
@instantiator = inst
@gcSuspendCount = gcSuspendCount
@namespaces = {}
end
def start_element_namespace(tag, attributes, prefix, uri, ns)
controlGC
ns.each{|n| @namespaces[n[0]] = n[1]}
attrs = attributes.collect{|a| [a.prefix ? a.prefix+":"+a.localname : a.localname, a.value]}
@instantiator.start_tag(prefix, tag, @namespaces, Hash[*(attrs.flatten)])
attrs.each { |pair| @instantiator.set_attribute(pair[0], pair[1]) }
end
def end_element_namespace(tag, prefix, uri)
@instantiator.end_tag(prefix, tag)
end
def characters(str)
@instantiator.text(str)
end
def controlGC
return unless @gcSuspendCount > 0
@gcCounter ||= 0
@gcCounter += 1
if @gcCounter == @gcSuspendCount
@gcCounter = 0
GC.enable
ObjectSpace.garbage_collect
GC.disable
end
end
end
# Parses str and calls start_tag, end_tag, set_attribute and text methods of a subclass.
#
# If gcSuspendCount is specified, the garbage collector will be disabled for that
# number of start or end tags. After that period it will clean up and then be disabled again.
# A value of about 1000 can significantly improve overall performance.
# The memory usage normally does not increase.
# Depending on the work done for every xml tag the value might have to be adjusted.
#
def instantiate(str, gcSuspendCount=0)
gcDisabledBefore = GC.disable
gcSuspendCount = 0 if gcDisabledBefore
begin
visitor = Visitor.new(self, gcSuspendCount)
parser = Nokogiri::XML::SAX::Parser.new(visitor)
parser.parse(str) do |ctx|
@parserContext = ctx
end
ensure
GC.enable unless gcDisabledBefore
end
end
def text(str)
end
end
rgen-0.7.0/lib/rgen/instantiator/qualified_name_resolver.rb 0000644 0000041 0000041 00000005545 12352210062 024134 0 ustar www-data www-data require 'rgen/instantiator/reference_resolver'
module RGen
module Instantiator
# This is a resolver resolving element identifiers which are qualified names.
class QualifiedNameResolver
attr_reader :nameAttribute
attr_reader :separator
attr_reader :leadingSeparator
def initialize(rootElements, options={})
@rootElements = rootElements
@nameAttribute = options[:nameAttribute] || "name"
@separator = options[:separator] || "/"
@leadingSeparator = options.has_key?(:leadingSeparator) ? options[:leadingSeparator] : true
@elementByQName = {}
@visitedQName = {}
@childReferences = {}
@resolverDelegate = ReferenceResolver.new(:identifier_resolver => method(:resolveIdentifier))
end
def resolveIdentifier(qualifiedName)
return @elementByQName[qualifiedName] if @elementByQName.has_key?(qualifiedName)
path = qualifiedName.split(separator).reject{|s| s == ""}
if path.size > 1
parentQName = (leadingSeparator ? separator : "") + path[0..-2].join(separator)
parents = resolveIdentifier(parentQName)
parents = [parents].compact unless parents.is_a?(Array)
children = parents.collect{|p| allNamedChildren(p)}.flatten
elsif path.size == 1
parentQName = ""
children = allRootNamedChildren
else
return @elementByQName[qualifiedName] = nil
end
# if the parent was already visited all matching elements are the hash
if !@visitedQName[parentQName]
children.each do |c|
name = c.send(nameAttribute)
if name
qname = parentQName + ((parentQName != "" || leadingSeparator) ? separator : "") + name
existing = @elementByQName[qname]
if existing
@elementByQName[qname] = [existing] unless existing.is_a?(Array)
@elementByQName[qname] << c
else
@elementByQName[qname] = c
end
end
end
# all named children of praent have been checked and hashed
@visitedQName[parentQName] = true
end
@elementByQName[qualifiedName] ||= nil
end
def resolveReferences(unresolvedReferences, problems=[])
@resolverDelegate.resolve(unresolvedReferences, :problems => problems)
end
private
def allNamedChildren(element)
childReferences(element.class).collect do |r|
element.getGenericAsArray(r.name).collect do |c|
if c.respond_to?(nameAttribute)
c
else
allNamedChildren(c)
end
end
end.flatten
end
def allRootNamedChildren
@rootElements.collect do |e|
if e.respond_to?(nameAttribute)
e
else
allNamedChildren(e)
end
end.flatten
end
def childReferences(clazz)
@childReferences[clazz] ||= clazz.ecore.eAllReferences.select{|r| r.containment}
end
end
end
end
rgen-0.7.0/lib/rgen/instantiator/default_xml_instantiator.rb 0000644 0000041 0000041 00000005630 12352210062 024346 0 ustar www-data www-data require 'rgen/instantiator/nodebased_xml_instantiator'
module RGen
module Instantiator
# A default XML instantiator.
# Derive your own instantiator from this class or use it as is.
#
class DefaultXMLInstantiator < NodebasedXMLInstantiator
include Util::NameHelper
NamespaceDescriptor = Struct.new(:prefix, :target)
class << self
def map_tag_ns(from, to, prefix="")
tag_ns_map[from] = NamespaceDescriptor.new(prefix, to)
end
def tag_ns_map # :nodoc:
@tag_ns_map ||={}
@tag_ns_map
end
end
def initialize(env, default_module, create_mm=false)
super(env)
@default_module = default_module
@create_mm = create_mm
end
def on_descent(node)
obj = new_object(node)
@env << obj unless obj.nil?
node.object = obj
node.attributes.each_pair { |k,v| set_attribute(node, k, v) }
end
def on_ascent(node)
node.children.each { |c| assoc_p2c(node, c) }
node.object.class.has_attr 'chardata', Object unless node.object.respond_to?(:chardata)
set_attribute(node, "chardata", node.chardata)
end
def class_name(str)
saneClassName(str)
end
def new_object(node)
ns_desc = self.class.tag_ns_map[node.namespace]
class_name = class_name(ns_desc.nil? ? node.qtag : ns_desc.prefix+node.tag)
mod = (ns_desc && ns_desc.target) || @default_module
build_on_error(NameError, :build_class, class_name, mod) do
mod.const_get(class_name).new
end
end
def build_class(name, mod)
mod.const_set(name, Class.new(RGen::MetamodelBuilder::MMBase))
end
def method_name(str)
saneMethodName(str)
end
def assoc_p2c(parent, child)
return unless parent.object && child.object
method_name = method_name(className(child.object))
build_on_error(NoMethodError, :build_p2c_assoc, parent, child, method_name) do
parent.object.addGeneric(method_name, child.object)
child.object.setGeneric("parent", parent.object)
end
end
def build_p2c_assoc(parent, child, method_name)
parent.object.class.has_many(method_name, child.object.class)
child.object.class.has_one("parent", RGen::MetamodelBuilder::MMBase)
end
def set_attribute(node, attr, value)
return unless node.object
build_on_error(NoMethodError, :build_attribute, node, attr, value) do
node.object.setGeneric(method_name(attr), value)
end
end
def build_attribute(node, attr, value)
node.object.class.has_attr(method_name(attr))
end
protected
# Helper method for implementing classes.
# This method yields the given block.
# If the metamodel should be create automatically (see constructor)
# rescues +error+ and calls +builder_method+ with +args+, then
# yields the block again.
def build_on_error(error, builder_method, *args)
begin
yield
rescue error
if @create_mm
send(builder_method, *args)
yield
else
raise
end
end
end
end
end
end
rgen-0.7.0/lib/rgen/instantiator/json_instantiator.rb 0000644 0000041 0000041 00000010154 12352210062 023010 0 ustar www-data www-data require 'rgen/instantiator/qualified_name_resolver'
require 'rgen/instantiator/json_parser'
module RGen
module Instantiator
# JsonInstantiator is used to create RGen models from JSON.
#
# Each JSON object needs to have an attribute "_class" which is used to find
# the metamodel class to instantiate. The value of "_class" should be the
# the relative qualified class name within the root package as a string.
#
# If the option "short_class_names" is set to true, unqualified class names can be used.
# In this case, metamodel classes are searched in the metamodel root package first.
# If this search is not successful, all subpackages will be searched for the class name.
#
class JsonInstantiator
# Model elements will be created in evironment +env+,
# classes are looked for in metamodel package module +mm+,
# +options+ include:
# short_class_names: if true subpackages will be searched for unqualifed class names (default: true)
# ignore_keys: an array of json object key names which are to be ignored (default: none)
#
# The options are also passed to the underlying QualifiedNameResolver.
#
def initialize(env, mm, options={})
@env = env
@mm = mm
@options = options
@short_class_names = !@options.has_key?(:short_class_names) || @options[:short_class_names]
@ignore_keys = @options[:ignore_keys] || []
@unresolvedReferences = []
@classes = {}
@classes_flat = {}
mm.ecore.eAllClasses.each do |c|
@classes[c.instanceClass.name.sub(mm.name+"::","")] = c
@classes_flat[c.name] = c
end
@parser = JsonParser.new(self)
end
# Creates the elements described by the json string +str+.
# Returns an array of ReferenceResolver::UnresolvedReference
# describing the references which could not be resolved
#
# Options:
# :root_elements: if an array is provided, it will be filled with the root elements
#
def instantiate(str, options={})
root = @parser.parse(str)
if options[:root_elements].is_a?(Array)
options[:root_elements].clear
root.each{|r| options[:root_elements] << r}
end
resolver = QualifiedNameResolver.new(root, @options)
resolver.resolveReferences(@unresolvedReferences)
end
def createObject(hash)
className = hash["_class"]
# hashes without a _class key are returned as is
return hash unless className
if @classes[className]
clazz = @classes[className].instanceClass
elsif @short_class_names && @classes_flat[className]
clazz = @classes_flat[className].instanceClass
else
raise "class not found: #{className}"
end
hash.delete("_class")
@ignore_keys.each do |k|
hash.delete(k)
end
urefs = []
hash.keys.each do |k|
f = eFeature(k, clazz)
hash[k] = [hash[k]] if f.many && !hash[k].is_a?(Array)
if f.is_a?(RGen::ECore::EReference) && !f.containment
if f.many
idents = hash[k]
hash[k] = idents.collect do |i|
proxy = RGen::MetamodelBuilder::MMProxy.new(i)
urefs << ReferenceResolver::UnresolvedReference.new(nil, k, proxy)
proxy
end
else
ident = hash[k]
ident = ident.first if ident.is_a?(Array)
proxy = RGen::MetamodelBuilder::MMProxy.new(ident)
hash[k] = proxy
urefs << ReferenceResolver::UnresolvedReference.new(nil, k, proxy)
end
elsif f.eType.is_a?(RGen::ECore::EEnum)
hash[k] = hash[k].to_sym
elsif f.eType.instanceClassName == "Float"
hash[k] = hash[k].to_f
end
end
obj = @env.new(clazz, hash)
urefs.each do |r|
r.element = obj
@unresolvedReferences << r
end
obj
end
private
def eFeature(name, clazz)
@eFeature ||= {}
@eFeature[clazz] ||= {}
unless @eFeature[clazz][name]
feature = clazz.ecore.eAllStructuralFeatures.find{|f| f.name == name}
raise "feature '#{name}' not found in class '#{clazz}'" unless feature
end
@eFeature[clazz][name] ||= feature
end
end
end
end
rgen-0.7.0/lib/rgen/instantiator/nodebased_xml_instantiator.rb 0000644 0000041 0000041 00000006762 12352210062 024655 0 ustar www-data www-data require 'rgen/metamodel_builder'
require 'rgen/instantiator/abstract_instantiator'
require 'nokogiri'
module RGen
module Instantiator
class NodebasedXMLInstantiator < AbstractInstantiator
class << self
# The prune level is the number of parent/children associations which
# is kept when the instantiator ascents the XML tree.
# If the level is 2, information for the node's children and the childrens'
# children will be available as an XMLNodeDescriptor object.
# If the level is 0 no pruning will take place, i.e. the whole information
# is kept until the end of the instantiation process. 0 is default.
def set_prune_level(level)
@prune_level = level
end
def prune_level # :nodoc:
@prune_level ||= 0
end
end
class XMLNodeDescriptor
attr_reader :namespace, :qtag, :prefix, :tag, :parent, :attributes, :chardata
attr_accessor :object, :children
def initialize(ns, qtag, prefix, tag, parent, children, attributes)
@namespace, @qtag, @prefix, @tag, @parent, @children, @attributes =
ns, qtag, prefix, tag, parent, children, attributes
@parent.children << self if @parent
@chardata = []
end
end
class Visitor < Nokogiri::XML::SAX::Document
attr_reader :namespaces
def initialize(inst)
@instantiator = inst
@namespaces = {}
end
def start_element_namespace(tag, attributes, prefix, uri, ns)
ns.each{|n| @namespaces[n[0]] = n[1]}
attrs = {}
attributes.each{|a| attrs[a.prefix ? a.prefix+":"+a.localname : a.localname] = a.value}
qname = prefix ? prefix+":"+tag : tag
@instantiator.start_element(uri, qname, prefix, tag, attrs)
end
def end_element(name)
@instantiator.end_element
end
def characters(str)
@instantiator.on_chardata(str)
end
end
def initialize(env)
super
@env = env
@stack = []
end
def instantiate_file(file)
File.open(file) { |f| parse(f.read)}
resolve
end
def instantiate(text)
parse(text)
resolve
end
def parse(src)
@visitor = Visitor.new(self)
parser = Nokogiri::XML::SAX::Parser.new(@visitor)
parser.parse(src)
@visitor = nil
end
def start_element(ns, qtag, prefix, tag, attributes)
node = XMLNodeDescriptor.new(ns, qtag, prefix, tag, @stack[-1], [], attributes)
@stack.push node
on_descent(node)
end
def end_element
node = @stack.pop
on_ascent(node)
prune_children(node, self.class.prune_level - 1) if self.class.prune_level > 0
end
def on_chardata(str)
node = @stack.last
node.chardata << str
end
# This method is called when the XML parser goes down the tree.
# An XMLNodeDescriptor +node+ describes the current node.
# Implementing classes must overwrite this method.
def on_descent(node)
raise "Overwrite this method !"
end
# This method is called when the XML parser goes up the tree.
# An XMLNodeDescriptor +node+ describes the current node.
# Implementing classes must overwrite this method.
def on_ascent(node)
raise "Overwrite this method !"
end
def namespaces
@visitor.namespaces if @visitor
end
private
def prune_children(node, level)
if level == 0
node.children = nil
else
node.children.each { |c| prune_children(c, level-1) }
end
end
end
end
end
rgen-0.7.0/lib/rgen/instantiator/json_parser.rb 0000644 0000041 0000041 00000015625 12352210062 021575 0 ustar www-data www-data #
# DO NOT MODIFY!!!!
# This file is automatically generated by racc 1.4.5
# from racc grammer file "json_parser.y".
#
require 'racc/parser'
module RGen
module Instantiator
class JsonParser < Racc::Parser
module_eval <<'..end json_parser.y modeval..id3d5fb611e2', 'json_parser.y', 38
ParserToken = Struct.new(:line, :file, :value)
def initialize(instantiator)
@instantiator = instantiator
end
def parse(str, file=nil)
@q = []
line = 1
until str.empty?
case str
when /\A\n/
str = $'
line +=1
when /\A\s+/
str = $'
when /\A([-+]?\d+\.\d+)/
str = $'
@q << [:FLOAT, ParserToken.new(line, file, $1)]
when /\A([-+]?\d+)/
str = $'
@q << [:INTEGER, ParserToken.new(line, file, $1)]
when /\A"((?:[^"\\]|\\"|\\\\|\\[^"\\])*)"/
str = $'
sval = $1
sval.gsub!('\\\\','\\')
sval.gsub!('\\"','"')
sval.gsub!('\\n',"\n")
sval.gsub!('\\r',"\r")
sval.gsub!('\\t',"\t")
sval.gsub!('\\f',"\f")
sval.gsub!('\\b',"\b")
@q << [:STRING, ParserToken.new(line, file, sval)]
when /\A(\{|\}|\[|\]|,|:|true|false)/
str = $'
@q << [$1, ParserToken.new(line, file, $1)]
else
raise "parse error in line #{line} on "+str[0..20].inspect+"..."
end
end
@q.push [false, ParserToken.new(line, file, '$end')]
do_parse
end
def next_token
r = @q.shift
r
end
..end json_parser.y modeval..id3d5fb611e2
##### racc 1.4.5 generates ###
racc_reduce_table = [
0, 0, :racc_error,
1, 14, :_reduce_1,
3, 16, :_reduce_2,
2, 16, :_reduce_3,
1, 17, :_reduce_4,
3, 17, :_reduce_5,
3, 18, :_reduce_6,
2, 18, :_reduce_7,
1, 19, :_reduce_8,
3, 19, :_reduce_9,
3, 20, :_reduce_10,
1, 15, :_reduce_11,
1, 15, :_reduce_12,
1, 15, :_reduce_13,
1, 15, :_reduce_14,
1, 15, :_reduce_15,
1, 15, :_reduce_16,
1, 15, :_reduce_17 ]
racc_reduce_n = 18
racc_shift_n = 29
racc_action_table = [
3, 16, 17, 7, 22, 8, 21, 10, 11, 1,
2, 3, 12, 23, 7, 24, 8, 25, 10, 11,
1, 2, 3, 20, 15, 7, 17, 8, nil, 10,
11, 1, 2, 3, nil, nil, 7, nil, 8, nil,
10, 11, 1, 2 ]
racc_action_check = [
0, 7, 7, 0, 15, 0, 14, 0, 0, 0,
0, 3, 3, 17, 3, 18, 3, 19, 3, 3,
3, 3, 20, 13, 4, 20, 25, 20, nil, 20,
20, 20, 20, 23, nil, nil, 23, nil, 23, nil,
23, 23, 23, 23 ]
racc_action_pointer = [
-2, nil, nil, 9, 24, nil, nil, -5, nil, nil,
nil, nil, nil, 19, 3, 4, nil, 5, 9, 13,
20, nil, nil, 31, nil, 19, nil, nil, nil ]
racc_action_default = [
-18, -16, -17, -18, -18, -1, -11, -18, -13, -12,
-14, -15, -3, -4, -18, -18, -7, -18, -18, -8,
-18, -2, 29, -18, -6, -18, -5, -10, -9 ]
racc_goto_table = [
5, 18, 4, 14, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, 28,
26, nil, nil, 27 ]
racc_goto_check = [
2, 6, 1, 4, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, 6,
4, nil, nil, 2 ]
racc_goto_pointer = [
nil, 2, 0, nil, 0, nil, -6, nil ]
racc_goto_default = [
nil, nil, 13, 6, nil, 9, nil, 19 ]
racc_token_table = {
false => 0,
Object.new => 1,
"[" => 2,
"]" => 3,
"," => 4,
"{" => 5,
"}" => 6,
:STRING => 7,
":" => 8,
:INTEGER => 9,
:FLOAT => 10,
"true" => 11,
"false" => 12 }
racc_use_result_var = true
racc_nt_base = 13
Racc_arg = [
racc_action_table,
racc_action_check,
racc_action_default,
racc_action_pointer,
racc_goto_table,
racc_goto_check,
racc_goto_default,
racc_goto_pointer,
racc_nt_base,
racc_reduce_table,
racc_token_table,
racc_shift_n,
racc_reduce_n,
racc_use_result_var ]
Racc_token_to_s_table = [
'$end',
'error',
'"["',
'"]"',
'","',
'"{"',
'"}"',
'STRING',
'":"',
'INTEGER',
'FLOAT',
'"true"',
'"false"',
'$start',
'json',
'value',
'array',
'valueList',
'object',
'memberList',
'member']
Racc_debug_parser = false
##### racc system variables end #####
# reduce 0 omitted
module_eval <<'.,.,', 'json_parser.y', 4
def _reduce_1( val, _values, result )
result = val[0]
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 6
def _reduce_2( val, _values, result )
result = val[1]
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 7
def _reduce_3( val, _values, result )
result = []
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 9
def _reduce_4( val, _values, result )
result = [ val[0] ]
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 10
def _reduce_5( val, _values, result )
result = [ val[0] ] + val[2]
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 12
def _reduce_6( val, _values, result )
result = @instantiator.createObject(val[1])
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 13
def _reduce_7( val, _values, result )
result = nil
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 15
def _reduce_8( val, _values, result )
result = val[0]
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 16
def _reduce_9( val, _values, result )
result = val[0].merge(val[2])
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 18
def _reduce_10( val, _values, result )
result = {val[0].value => val[2]}
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 20
def _reduce_11( val, _values, result )
result = val[0]
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 21
def _reduce_12( val, _values, result )
result = val[0]
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 22
def _reduce_13( val, _values, result )
result = val[0].value
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 23
def _reduce_14( val, _values, result )
result = val[0].value.to_i
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 24
def _reduce_15( val, _values, result )
result = val[0].value.to_f
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 25
def _reduce_16( val, _values, result )
result = true
result
end
.,.,
module_eval <<'.,.,', 'json_parser.y', 26
def _reduce_17( val, _values, result )
result = false
result
end
.,.,
def _reduce_none( val, _values, result )
result
end
end # class JsonParser
end
end
rgen-0.7.0/lib/rgen/instantiator/json_parser.y 0000644 0000041 0000041 00000004113 12352210062 021430 0 ustar www-data www-data class JsonParser
rule
json: value { result = val[0] }
array: "[" valueList "]" { result = val[1] }
| "[" "]" { result = [] }
valueList: value { result = [ val[0] ] }
| value "," valueList { result = [ val[0] ] + val[2] }
object: "{" memberList "}" { result = @instantiator.createObject(val[1]) }
| "{" "}" { result = nil }
memberList: member { result = val[0] }
| member "," memberList { result = val[0].merge(val[2]) }
member: STRING ":" value { result = {val[0].value => val[2]} }
value: array { result = val[0] }
| object { result = val[0] }
| STRING { result = val[0].value }
| INTEGER { result = val[0].value.to_i }
| FLOAT { result = val[0].value.to_f }
| "true" { result = true }
| "false" { result = false }
end
---- header
module RGen
module Instantiator
---- inner
ParserToken = Struct.new(:line, :file, :value)
def initialize(instantiator)
@instantiator = instantiator
end
def parse(str, file=nil)
@q = []
line = 1
until str.empty?
case str
when /\A\n/
str = $'
line +=1
when /\A\s+/
str = $'
when /\A([-+]?\d+\.\d+)/
str = $'
@q << [:FLOAT, ParserToken.new(line, file, $1)]
when /\A([-+]?\d+)/
str = $'
@q << [:INTEGER, ParserToken.new(line, file, $1)]
when /\A"((?:[^"\\]|\\"|\\\\|\\[^"\\])*)"/
str = $'
sval = $1
sval.gsub!('\\\\','\\')
sval.gsub!('\\"','"')
sval.gsub!('\\n',"\n")
sval.gsub!('\\r',"\r")
sval.gsub!('\\t',"\t")
sval.gsub!('\\f',"\f")
sval.gsub!('\\b',"\b")
@q << [:STRING, ParserToken.new(line, file, sval)]
when /\A(\{|\}|\[|\]|,|:|true|false)/
str = $'
@q << [$1, ParserToken.new(line, file, $1)]
else
raise "parse error in line #{line} on "+str[0..20].inspect+"..."
end
end
@q.push [false, ParserToken.new(line, file, '$end')]
do_parse
end
def next_token
r = @q.shift
r
end
---- footer
end
end
rgen-0.7.0/lib/rgen/instantiator/reference_resolver.rb 0000644 0000041 0000041 00000011144 12352210062 023117 0 ustar www-data www-data require 'rgen/instantiator/resolution_helper'
module RGen
module Instantiator
# The ReferenceResolver can be used to resolve unresolved references, i.e. instances
# of class UnresolvedReference
#
# There are two ways how this can be used:
# 1. the identifiers and associated model elements are added upfront using +add_identifier+
# 2. register an :identifier_resolver with the constructor, which will be invoked
# for every unresolved identifier
#
class ReferenceResolver
# Instances of this class represent information about not yet resolved references.
# This consists of the +element+ and metamodel +feature_name+ which hold/is to hold the
# reference and the +proxy+ object which is the placeholder for the reference.
# If the reference could not be resolved because the target type does not match the
# feature type, the flag +target_type_error+ will be set.
#
class UnresolvedReference
attr_reader :feature_name, :proxy
attr_accessor :element, :target_type_error
def initialize(element, feature_name, proxy)
@element = element
@feature_name = feature_name
@proxy = proxy
end
end
# Create a reference resolver, options:
#
# :identifier_resolver:
# a proc which is called with an identifier and which should return the associated element
# in case the identifier is not uniq, the proc may return multiple values
# default: lookup element in internal map
#
def initialize(options={})
@identifier_resolver = options[:identifier_resolver]
@identifier_map = {}
end
# Add an +identifer+ / +element+ pair which will be used for looking up unresolved identifers
def add_identifier(ident, element)
map_entry = @identifier_map[ident]
if map_entry
if map_entry.is_a?(Array)
map_entry << element
else
@identifier_map[ident] = [map_entry, element]
end
else
@identifier_map[ident] = element
end
end
# Tries to resolve the given +unresolved_refs+. If resolution is successful, the proxy object
# will be removed, otherwise there will be an error description in the problems array.
# In case the resolved target element's type is not valid for the given feature, the
# +target_type_error+ flag will be set on the unresolved reference.
# Returns an array of the references which are still unresolved. Options:
#
# :problems
# an array to which problems will be appended
#
# :on_resolve
# a proc which will be called for every sucessful resolution, receives the unresolved
# reference as well as to new target element
#
# :use_target_type
# use the expected target type to narrow the set of possible targets
# (i.e. ignore targets with wrong type)
#
# :failed_resolutions
# a Hash which will receive an entry for each failed resolution for which at least one
# target element was found (wrong target type, or target not unique).
# hash key is the uref, hash value is the target element or the Array of target elements
#
def resolve(unresolved_refs, options={})
problems = options[:problems] || []
still_unresolved_refs = []
failed_resolutions = options[:failed_resolutions] || {}
unresolved_refs.each do |ur|
if @identifier_resolver
target = @identifier_resolver.call(ur.proxy.targetIdentifier)
else
target = @identifier_map[ur.proxy.targetIdentifier]
end
target = [target].compact unless target.is_a?(Array)
if options[:use_target_type]
feature = ur.element.class.ecore.eAllReferences.find{|r| r.name == ur.feature_name}
target = target.select{|e| e.is_a?(feature.eType.instanceClass)}
end
if target.size == 1
status = ResolutionHelper.set_uref_target(ur, target[0])
if status == :success
options[:on_resolve] && options[:on_resolve].call(ur, target[0])
elsif status == :type_error
ur.target_type_error = true
problems << type_error_message(target[0])
still_unresolved_refs << ur
failed_resolutions[ur] = target[0]
end
elsif target.size > 1
problems << "identifier #{ur.proxy.targetIdentifier} not uniq"
still_unresolved_refs << ur
failed_resolutions[ur] = target
else
problems << "identifier #{ur.proxy.targetIdentifier} not found"
still_unresolved_refs << ur
end
end
still_unresolved_refs
end
private
def type_error_message(target)
"invalid target type #{target.class}"
end
end
end
end
rgen-0.7.0/lib/rgen/instantiator/abstract_instantiator.rb 0000644 0000041 0000041 00000003275 12352210062 023650 0 ustar www-data www-data module RGen
module Instantiator
class AbstractInstantiator
ResolverDescription = Struct.new(:from, :attribute, :block) # :nodoc:
class << self
attr_accessor :resolver_descs
end
def initialize(env)
@env = env
end
# Specifies that +attribute+ should be resolved. If +:class+ is specified,
# resolve +attribute+ only for objects of type class.
# The block must return the value to which the attribute should be assigned.
# The object for which the attribute is to be resolved will be accessible
# in the current context within the block.
#
def self.resolve(attribute, desc=nil, &block)
from = (desc.is_a?(Hash) && desc[:class])
self.resolver_descs ||= []
self.resolver_descs << ResolverDescription.new(from, attribute, block)
end
# Resolves +attribute+ to a model element which has attribute +:id+ set to the
# value currently in attribute +:src+
#
def self.resolve_by_id(attribute, desc)
id_attr = (desc.is_a?(Hash) && desc[:id])
src_attr = (desc.is_a?(Hash) && desc[:src])
raise StandardError.new("No id attribute given.") unless id_attr
resolve(attribute) do
@env.find(id_attr => @current_object.send(src_attr)).first
end
end
private
def method_missing(m, *args) #:nodoc:
if @current_object
@current_object.send(m)
else
super
end
end
def resolve
self.class.resolver_descs ||= []
self.class.resolver_descs.each { |desc|
@env.find(:class => desc.from).each { |e|
old_object, @current_object = @current_object, e
e.send("#{desc.attribute}=", instance_eval(&desc.block)) if e.respond_to?("#{desc.attribute}=")
@current_object = old_object
}
}
end
end
end
end rgen-0.7.0/lib/rgen/instantiator/resolution_helper.rb 0000644 0000041 0000041 00000002073 12352210062 023003 0 ustar www-data www-data module RGen
module Instantiator
module ResolutionHelper
# sets the target of an unresolved reference in the model
# returns :type_error if the target is of wrong type, otherwise :success
#
def self.set_uref_target(uref, target)
refs = uref.element.getGeneric(uref.feature_name)
if refs.is_a?(Array)
index = refs.index(uref.proxy)
uref.element.removeGeneric(uref.feature_name, uref.proxy)
begin
uref.element.addGeneric(uref.feature_name, target, index)
rescue StandardError => e
if is_type_error?(e)
uref.element.addGeneric(uref.feature_name, uref.proxy, index)
return :type_error
else
raise
end
end
else
begin
# this will replace the proxy
uref.element.setGeneric(uref.feature_name, target)
rescue StandardError => e
if is_type_error?(e)
return :type_error
else
raise
end
end
end
:success
end
def self.is_type_error?(e)
e.message =~ /Can not use a .* where a .* is expected/
end
end
end
end
rgen-0.7.0/lib/rgen/instantiator/xmi11_instantiator.rb 0000644 0000041 0000041 00000011477 12352210062 023007 0 ustar www-data www-data require 'rgen/ecore/ecore'
require 'rgen/instantiator/abstract_xml_instantiator'
require 'rgen/array_extensions'
class XMI11Instantiator < AbstractXMLInstantiator
include RGen::ECore
ResolverDescription = Struct.new(:object, :attribute, :value, :many)
INFO = 0
WARN = 1
ERROR = 2
def initialize(env, fix_map={}, loglevel=ERROR)
@env = env
@fix_map = fix_map
@loglevel = loglevel
@rolestack = []
@elementstack = []
end
def add_metamodel(ns, mod)
@ns_module_map ||={}
@ns_module_map[ns] = mod
end
def instantiate(str)
@resolver_descs = []
@element_by_id = {}
super(str, 1000)
@resolver_descs.each do |rd|
if rd.many
newval = rd.value.split(" ").collect{|v| @element_by_id[v]}
else
newval = @element_by_id[rd.value]
end
log WARN, "Could not resolve reference #{rd.attribute} on #{rd.object}" unless newval
begin
rd.object.setGeneric(rd.attribute,newval)
rescue Exception
log WARN, "Could not set reference #{rd.attribute} on #{rd.object}"
end
end
end
def start_tag(prefix, tag, namespaces, attributes)
if tag =~ /\w+\.(\w+)/
# XMI role
role_name = map_feature_name($1) || $1
eRef = @elementstack.last && eAllReferences(@elementstack.last).find{|r|r.name == role_name}
log WARN, "No reference found for #{role_name} on #{@elementstack.last}" unless eRef
@rolestack.push eRef
elsif attributes["xmi.idref"]
# reference
rd = ResolverDescription.new
rd.object = @elementstack.last
rd.attribute = @rolestack.last.name
rd.value = attributes["xmi.idref"]
rd.many = @rolestack.last.many
@resolver_descs << rd
@elementstack.push nil
else
# model element
value = map_tag(tag, attributes) || tag
if value.is_a?(String)
mod = @ns_module_map[namespaces[prefix]]
unless mod
log WARN, "Ignoring tag #{tag}"
return
end
value = mod.const_get(value).new
end
@env << value
eRef = @rolestack.last
if eRef && eRef.many
@elementstack.last.addGeneric(eRef.name, value)
elsif eRef
@elementstack.last.setGeneric(eRef.name, value)
end
@elementstack.push value
end
end
def end_tag(prefix, tag)
if tag =~ /\w+\.(\w+)/
@rolestack.pop
else
@elementstack.pop
end
end
def set_attribute(attr, value)
return unless @elementstack.last
if attr == "xmi.id"
@element_by_id[value] = @elementstack.last
else
attr_name = map_feature_name(attr) || attr
eFeat = eAllStructuralFeatures(@elementstack.last).find{|a| a.name == attr_name}
unless eFeat
log WARN, "No structural feature found for #{attr_name} on #{@elementstack.last}"
return
end
if eFeat.is_a?(RGen::ECore::EReference)
if map_feature_value(attr_name, value).is_a?(eFeat.eType.instanceClass)
@elementstack.last.setGeneric(attr_name, map_feature_value(attr_name, value))
else
rd = ResolverDescription.new
rd.object = @elementstack.last
rd.attribute = attr_name
rd.value = value
rd.many = eFeat.many
@resolver_descs << rd
end
else
value = map_feature_value(attr_name, value) || value
value = true if value == "true" && eFeat.eType == EBoolean
value = false if value == "false" && eFeat.eType == EBoolean
value = value.to_i if eFeat.eType == EInt || eFeat.eType == ELong
value = value.to_f if eFeat.eType == EFloat
value = value.to_sym if eFeat.eType.is_a?(EEnum)
@elementstack.last.setGeneric(attr_name, value)
end
end
end
private
def map_tag(tag, attributes)
tag_map = @fix_map[:tags] || {}
value = tag_map[tag]
if value.is_a?(Proc)
value.call(tag, attributes)
else
value
end
end
def map_feature_name(name)
name_map = @fix_map[:feature_names] || {}
name_map[name]
end
def map_feature_value(attr_name, value)
value_map = @fix_map[:feature_values] || {}
map = value_map[attr_name]
if map.is_a?(Hash)
map[value]
elsif map.is_a?(Proc)
map.call(value)
end
end
def log(level, msg)
puts %w(INFO WARN ERROR)[level] + ": " + msg if level >= @loglevel
end
def eAllReferences(element)
@eAllReferences ||= {}
@eAllReferences[element.class] ||= element.class.ecore.eAllReferences
end
def eAllStructuralFeatures(element)
@eAllStructuralFeatures ||= {}
@eAllStructuralFeatures[element.class] ||= element.class.ecore.eAllStructuralFeatures
end
end
rgen-0.7.0/lib/rgen/array_extensions.rb 0000644 0000041 0000041 00000003024 12352210062 020114 0 ustar www-data www-data # RGen Framework
# (c) Martin Thiede, 2006
require 'rgen/metamodel_builder'
class Array
def >>(method)
compact.inject([]) { |r,e| r | ( (o=e.send(method)).is_a?(Array) ? o : [o] ) }
end
def method_missing(m, *args)
# This extensions has the side effect that it allows to call any method on any
# empty array with an empty array as the result. This behavior is required for
# navigating models.
#
# This is a problem for Hash[] called with an (empty) array of tupels.
# It will call to_hash expecting a Hash as the result. When it gets an array instead,
# it fails with an exception. Make sure it gets a NoMethodException as without this
# extension and it will catch that and return an empty hash as expected.
#
# Similar problems exist for other Ruby built-in methods which are expected to fail.
#
return super unless (size == 0 &&
m != :to_hash && m != :to_str) ||
compact.any?{|e| e.is_a? RGen::MetamodelBuilder::MMBase}
# use an array to build the result to achiev similar ordering
result = []
inResult = {}
compact.each do |e|
if e.is_a? RGen::MetamodelBuilder::MMBase
((o=e.send(m)).is_a?(Array) ? o : [o] ).each do |v|
next if inResult[v.object_id]
inResult[v.object_id] = true
result << v
end
else
raise StandardError.new("Trying to call a method on an array element not a RGen MMBase")
end
end
result.compact
end
end
rgen-0.7.0/lib/rgen/transformer.rb 0000644 0000041 0000041 00000050666 12352210062 017077 0 ustar www-data www-data require 'rgen/ecore/ecore'
require 'rgen/ecore/ecore_ext'
module RGen
# The Transformer class can be used to specify model transformations.
#
# Model transformations take place between a source model (located in the source
# environment being an instance of the source metamodel) and a target model (located
# in the target environment being an instance of the target metamodel).
# Normally a "model" consists of several model elements associated with each other.
#
# =Transformation Rules
#
# The transformation is specified within a subclass of Transformer.
# Within the subclass, the Transformer.transform class method can be used to specify transformation
# blocks for specific metamodel classes of the source metamodel.
#
# If there is no transformation rule for the current object's class, a rule for the superclass
# is used instead. If there's no rule for the superclass, the class hierarchy is searched
# this way until Object.
#
# Here is an example:
#
# class MyTransformer < RGen::Transformer
#
# transform InputClass, :to => OutputClass do
# { :name => name, :otherClass => trans(otherClass) }
# end
#
# transform OtherInputClass, :to => OtherOutputClass do
# { :name => name }
# end
# end
#
# In this example a transformation rule is specified for model elements of class InputClass
# as well as for elements of class OtherInputClass. The former is to be transformed into
# an instance of OutputClass, the latter into an instance of OtherOutputClass.
# Note that the Ruby class objects are used to specifiy the classes.
#
# =Transforming Attributes
#
# Besides the target class of a transformation, the attributes of the result object are
# specified in the above example. This is done by providing a Ruby block with the call of
# +transform+. Within this block arbitrary Ruby code may be placed, however the block
# must return a hash. This hash object specifies the attribute assignment of the
# result object using key/value pairs: The key must be a Symbol specifying the attribute
# which is to be assigned by name, the value is the value that will be assigned.
#
# For convenience, the transformation block will be evaluated in the context of the
# source model element which is currently being converted. This way it is possible to just
# write :name => name
in the example in order to assign the name of the source
# object to the name attribute of the target object.
#
# =Transforming References
#
# When attributes of elements are references to other elements, those referenced
# elements have to be transformed as well. As shown above, this can be done by calling
# the Transformer#trans method. This method initiates a transformation of the element
# or array of elements passed as parameter according to transformation rules specified
# using +transform+. In fact the +trans+ method is the only way to start the transformation
# at all.
#
# For convenience and performance reasons, the result of +trans+ is cached with respect
# to the parameter object. I.e. calling trans on the same source object a second time will
# return the same result object _without_ a second evaluation of the corresponding
# transformation rules.
#
# This way the +trans+ method can be used to lookup the target element for some source
# element without the need to locally store a reference to the target element. In addition
# this can be useful if it is not clear if certain element has already been transformed
# when it is required within some other transformation block. See example below.
#
# Special care has been taken to allow the transformation of elements which reference
# each other cyclically. The key issue here is that the target element of some transformation
# is created _before_ the transformation's block is evaluated, i.e before the elements
# attributes are set. Otherwise a call to +trans+ within the transformation's block
# could lead to a +trans+ of the element itself.
#
# Here is an example:
#
# transform ModelAIn, :to => ModelAOut do
# { :name => name, :modelB => trans(modelB) }
# end
#
# transform ModelBIn, :to => ModelBOut do
# { :name => name, :modelA => trans(modelA) }
# end
#
# Note that in this case it does not matter if the transformation is initiated by calling
# +trans+ with a ModelAIn element or ModelBIn element due to the caching feature described
# above.
#
# =Transformer Methods
#
# When code in transformer blocks becomes more complex it might be useful to refactor
# it into smaller methods. If regular Ruby methods within the Transformer subclass are
# used for this purpose, it is necessary to know the source element being transformed.
# This could be achieved by explicitly passing the +@current_object+ as parameter of the
# method (see Transformer#trans).
#
# A more convenient way however is to define a special kind of method using the
# Transformer.method class method. Those methods are evaluated within the context of the
# current source element being transformed just the same as transformer blocks are.
#
# Here is an example:
#
# transform ModelIn, :to => ModelOut do
# { :number => doubleNumber }
# end
#
# method :doubleNumber do
# number * 2;
# end
#
# In this example the transformation assigns the 'number' attribute of the source element
# multiplied by 2 to the target element. The multiplication is done in a dedicated method
# called 'doubleNumber'. Note that the 'number' attribute of the source element is
# accessed without an explicit reference to the source element as the method's body
# evaluates in the source element's context.
#
# =Conditional Transformations
#
# Using the transformations as described above, all elements of the same class are
# transformed the same way. Conditional transformations allow to transform elements of
# the same class into elements of different target classes as well as applying different
# transformations on the attributes.
#
# Conditional transformations are defined by specifying multiple transformer blocks for
# the same source class and providing a condition with each block. Since it is important
# to create the target object before evaluation of the transformation block (see above),
# the conditions must also be evaluated separately _before_ the transformer block.
#
# Conditions are specified using transformer methods as described above. If the return
# value is true, the corresponding block is used for transformation. If more than one
# conditions are true, only the first transformer block will be evaluated.
#
# If there is no rule with a condition evaluating to true, rules for superclasses will
# be checked as described above.
#
# Here is an example:
#
# transform ModelIn, :to => ModelOut, :if => :largeNumber do
# { :number => number * 2}
# end
#
# transform ModelIn, :to => ModelOut, :if => :smallNumber do
# { :number => number / 2 }
# end
#
# method :largeNumber do
# number > 1000
# end
#
# method :smallNumber do
# number < 500
# end
#
# In this case the transformation of an element of class ModelIn depends on the value
# of the element's 'number' attribute. If the value is greater than 1000, the first rule
# as taken and the number is doubled. If the value is smaller than 500, the second rule
# is taken and the number is divided by two.
#
# Note that it is up to the user to avoid cycles within the conditions. A cycle could
# occure if the condition are based on transformation target elements, i.e. if +trans+
# is used within the condition to lookup or transform other elements.
#
# = Copy Transformations
#
# In some cases, transformations should just copy a model, either in the same metamodel
# or in another metamodel with the same package/class structure. Sometimes, a transformation
# is not exactly a copy, but a copy with slight modifications. Also in this case most
# classes need to be copied verbatim.
#
# The class method Transformer.copy can be used to specify a copy rule for a single
# metamodel class. If no target class is specified using the :to named parameter, the
# target class will be the same as the source class (i.e. in the same metamodel).
#
# copy MM1::ClassA # copy within the same metamodel
# copy MM1::ClassA, :to => MM2::ClassA
#
# The class method Transfomer.copy_all can be used to specify copy rules for all classes
# of a particular metamodel package. Again with :to, the target metamodel package may
# be specified which must have the same package/class structure. If :to is omitted, the
# target metamodel is the same as the source metamodel. In case that for some classes
# specific transformation rules should be used instead of copy rules, exceptions may be
# specified using the :except named parameter. +copy_all+ also provides an easy way to
# copy (clone) a model within the same metamodel.
#
# copy_all MM1 # copy rules for the whole metamodel MM1,
# # used to clone models of MM1
#
# copy_all MM1, :to => MM2, :except => %w( # copy rules for all classes of MM1 to
# ClassA # equally named classes in MM2, except
# Sub1::ClassB # "ClassA" and "Sub1::ClassB"
# )
#
# If a specific class transformation is not an exact copy, the Transformer.transform method
# should be used to actually specify the transformation. If this transformation is also
# mostly a copy, the helper method Transformer#copy_features can be used to create the
# transformation Hash required by the transform method. Any changes to this hash may be done
# in a hash returned by a block given to +copy_features+. This hash will extend or overwrite
# the default copy hash. In case a particular feature should not be part of the copy hash
# (e.g. because it does not exist in the target metamodel), exceptions can be specified using
# the :except named parameter. Here is an example:
#
# transform ClassA, :to => ClassAx do
# copy_features :except => [:featA] do
# { :featB => featA }
# end
# end
#
# In this example, ClassAx is a copy of ClassA except, that feature "featA" in ClassA is renamed
# into "featB" in ClassAx. Using +copy_features+ all features are copied except "featA". Then
# "featB" of the target class is assigned the value of "featA" of the source class.
#
class Transformer
TransformationDescription = Struct.new(:block, :target) # :nodoc:
@@methods = {}
@@transformer_blocks = {}
def self._transformer_blocks # :nodoc:
@@transformer_blocks[self] ||= {}
end
def self._methods # :nodoc:
@@methods[self] ||= {}
end
# This class method is used to specify a transformation rule.
#
# The first argument specifies the class of elements for which this rule applies.
# The second argument must be a hash including the target class
# (as value of key ':to') and an optional condition (as value of key ':if').
#
# The target class is specified by passing the actual Ruby class object.
# The condition is either the name of a transformer method (see Transfomer.method) as
# a symbol or a proc object. In either case the block is evaluated at transformation
# time and its result value determines if the rule applies.
#
def self.transform(from, desc=nil, &block)
to = (desc && desc.is_a?(Hash) && desc[:to])
condition = (desc && desc.is_a?(Hash) && desc[:if])
raise StandardError.new("No transformation target specified.") unless to
block_desc = TransformationDescription.new(block, to)
if condition
_transformer_blocks[from] ||= {}
raise StandardError.new("Multiple (non-conditional) transformations for class #{from.name}.") unless _transformer_blocks[from].is_a?(Hash)
_transformer_blocks[from][condition] = block_desc
else
raise StandardError.new("Multiple (non-conditional) transformations for class #{from.name}.") unless _transformer_blocks[from].nil?
_transformer_blocks[from] = block_desc
end
end
# This class method specifies that all objects of class +from+ are to be copied
# into an object of class +to+. If +to+ is omitted, +from+ is used as target class.
# The target class may also be specified using the :to => hash notation.
# During copy, all attributes and references of the target object
# are set to their transformed counterparts of the source object.
#
def self.copy(from, to=nil)
raise StandardError.new("Specify target class either directly as second parameter or using :to => ") \
unless to.nil? || to.is_a?(Class) || (to.is_a?(Hash) && to[:to].is_a?(Class))
to = to[:to] if to.is_a?(Hash)
transform(from, :to => to || from) do
copy_features
end
end
# Create copy rules for all classes of metamodel package (module) +from+ and its subpackages.
# The target classes are the classes with the same name in the metamodel package
# specified using named parameter :to. If no target metamodel is specified, source
# and target classes will be the same.
# The named parameter :except can be used to specify classes by qualified name for which
# no copy rules should be created. Qualified names are relative to the metamodel package
# specified.
#
def self.copy_all(from, hash={})
to = hash[:to] || from
except = hash[:except]
fromDepth = from.ecore.qualifiedName.split("::").size
from.ecore.eAllClasses.each do |c|
path = c.qualifiedName.split("::")[fromDepth..-1]
next if except && except.include?(path.join("::"))
copy c.instanceClass, :to => path.inject(to){|m,c| m.const_get(c)}
end
end
# Define a transformer method for the current transformer class.
# In contrast to regular Ruby methods, a method defined this way executes in the
# context of the object currently being transformed.
#
def self.method(name, &block)
_methods[name.to_s] = block
end
# Creates a new transformer
# Optionally an input and output Environment can be specified.
# If an elementMap is provided (normally a Hash) this map will be used to lookup
# and store transformation results. This way results can be predefined
# and it is possible to have several transformers work on the same result map.
#
def initialize(env_in=nil, env_out=nil, elementMap=nil)
@env_in = env_in
@env_out = env_out
@transformer_results = elementMap || {}
@transformer_jobs = []
end
# Transforms a given model element according to the rules specified by means of
# the Transformer.transform class method.
#
# The transformation result element is created in the output environment and returned.
# In addition, the result is cached, i.e. a second invocation with the same parameter
# object will return the same result object without any further evaluation of the
# transformation rules. Nil will be transformed into nil. Ruby "singleton" objects
# +true+, +false+, numerics and symbols will be returned without any change. Ruby strings
# will be duplicated with the result being cached.
#
# The transformation input can be given as:
# * a single object
# * an array each element of which is transformed in turn
# * a hash used as input to Environment#find with the result being transformed
#
def trans(obj)
if obj.is_a?(Hash)
raise StandardError.new("No input environment available to find model element.") unless @env_in
obj = @env_in.find(obj)
end
return nil if obj.nil?
return obj if obj.is_a?(TrueClass) or obj.is_a?(FalseClass) or obj.is_a?(Numeric) or obj.is_a?(Symbol)
return @transformer_results[obj] if @transformer_results[obj]
return @transformer_results[obj] = obj.dup if obj.is_a?(String)
return obj.collect{|o| trans(o)}.compact if obj.is_a? Array
raise StandardError.new("No transformer for class #{obj.class.name}") unless _transformerBlock(obj.class)
block_desc = _evaluateCondition(obj)
return nil unless block_desc
@transformer_results[obj] = _instantiateTargetClass(obj, block_desc.target)
# we will transform the properties later
@transformer_jobs << TransformerJob.new(self, obj, block_desc)
# if there have been jobs in the queue before, don't process them in this call
# this way calls to trans are not nested; a recursive implementation
# may cause a "Stack level too deep" exception for large models
return @transformer_results[obj] if @transformer_jobs.size > 1
# otherwise this is the first call of trans, process all jobs here
# more jobs will be added during job execution
while @transformer_jobs.size > 0
@transformer_jobs.first.execute
@transformer_jobs.shift
end
@transformer_results[obj]
end
# Create the hash required as return value of the block given to the Transformer.transform method.
# The hash will assign feature values of the source class to the features of the target class,
# assuming the features of both classes are the same. If the :except named parameter specifies
# an Array of symbols, the listed features are not copied by the hash. In order to easily manipulate
# the resulting hash, a block may be given which should also return a feature assignmet hash. This
# hash should be created manually and will extend/overwrite the automatically created hash.
#
def copy_features(options={})
hash = {}
@current_object.class.ecore.eAllStructuralFeatures.each do |f|
next if f.derived
next if options[:except] && options[:except].include?(f.name.to_sym)
hash[f.name.to_sym] = trans(@current_object.send(f.name))
end
hash.merge!(yield) if block_given?
hash
end
def _transformProperties(obj, block_desc) #:nodoc:
old_object, @current_object = @current_object, obj
block_result = instance_eval(&block_desc.block)
raise StandardError.new("Transformer must return a hash") unless block_result.is_a? Hash
@current_object = old_object
_attributesFromHash(@transformer_results[obj], block_result)
end
class TransformerJob #:nodoc:
def initialize(transformer, obj, block_desc)
@transformer, @obj, @block_desc = transformer, obj, block_desc
end
def execute
@transformer._transformProperties(@obj, @block_desc)
end
end
# Each call which is not handled by the transformer object is passed to the object
# currently being transformed.
# If that object also does not respond to the call, it is treated as a transformer
# method call (see Transformer.method).
#
def method_missing(m, *args) #:nodoc:
if @current_object.respond_to?(m)
@current_object.send(m, *args)
else
_invokeMethod(m, *args)
end
end
private
# returns _transformer_blocks content for clazz or one of its superclasses
def _transformerBlock(clazz) # :nodoc:
block = self.class._transformer_blocks[clazz]
block = _transformerBlock(clazz.superclass) if block.nil? && clazz != Object
block
end
# returns the first TransformationDescription for clazz or one of its superclasses
# for which condition is true
def _evaluateCondition(obj, clazz=obj.class) # :nodoc:
tb = self.class._transformer_blocks[clazz]
block_description = nil
if tb.is_a?(TransformationDescription)
# non-conditional
block_description = tb
elsif tb
old_object, @current_object = @current_object, obj
tb.each_pair {|condition, block|
if condition.is_a?(Proc)
result = instance_eval(&condition)
elsif condition.is_a?(Symbol)
result = _invokeMethod(condition)
else
result = condition
end
if result
block_description = block
break
end
}
@current_object = old_object
end
block_description = _evaluateCondition(obj, clazz.superclass) if block_description.nil? && clazz != Object
block_description
end
def _instantiateTargetClass(obj, target_desc) # :nodoc:
old_object, @current_object = @current_object, obj
if target_desc.is_a?(Proc)
target_class = instance_eval(&target_desc)
elsif target_desc.is_a?(Symbol)
target_class = _invokeMethod(target_desc)
else
target_class = target_desc
end
@current_object = old_object
result = target_class.new
@env_out << result if @env_out
result
end
def _invokeMethod(m) # :nodoc:
raise StandardError.new("Method not found: #{m}") unless self.class._methods[m.to_s]
instance_eval(&self.class._methods[m.to_s])
end
def _attributesFromHash(obj, hash) # :nodoc:
hash.delete(:class)
hash.each_pair{|k,v|
obj.send("#{k}=", v)
}
obj
end
end
end rgen-0.7.0/lib/metamodels/ 0000755 0000041 0000041 00000000000 12352210062 015372 5 ustar www-data www-data rgen-0.7.0/lib/metamodels/uml13_metamodel.rb 0000644 0000041 0000041 00000045451 12352210062 020720 0 ustar www-data www-data require 'rgen/metamodel_builder'
module UML13
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
AggregationKind = Enum.new(:name => "AggregationKind", :literals =>[ :none, :aggregate, :composite ])
ChangeableKind = Enum.new(:name => "ChangeableKind", :literals =>[ :changeable, :frozen, :addOnly ])
OperationDirectionKind = Enum.new(:name => "OperationDirectionKind", :literals =>[ ])
ParameterDirectionKind = Enum.new(:name => "ParameterDirectionKind", :literals =>[ :in, :inout, :out, :return ])
MessageDirectionKind = Enum.new(:name => "MessageDirectionKind", :literals =>[ ])
ScopeKind = Enum.new(:name => "ScopeKind", :literals =>[ :instance, :classifier ])
VisibilityKind = Enum.new(:name => "VisibilityKind", :literals =>[ :public, :protected, :private ])
PseudostateKind = Enum.new(:name => "PseudostateKind", :literals =>[ :initial, :deepHistory, :shallowHistory, :join, :fork, :branch, :junction, :final ])
CallConcurrencyKind = Enum.new(:name => "CallConcurrencyKind", :literals =>[ :sequential, :guarded, :concurrent ])
OrderingKind = Enum.new(:name => "OrderingKind", :literals =>[ :unordered, :ordered, :sorted ])
class Element < RGen::MetamodelBuilder::MMBase
end
class ModelElement < Element
has_attr 'name', String
has_attr 'visibility', UML13::VisibilityKind, :defaultValueLiteral => "public"
has_attr 'isSpecification', Boolean
end
class Namespace < ModelElement
end
class GeneralizableElement < ModelElement
has_attr 'isRoot', Boolean
has_attr 'isLeaf', Boolean
has_attr 'isAbstract', Boolean
end
class Classifier < RGen::MetamodelBuilder::MMMultiple(GeneralizableElement, Namespace)
end
class Class < Classifier
has_attr 'isActive', Boolean
end
class DataType < Classifier
end
class Feature < ModelElement
has_attr 'ownerScope', UML13::ScopeKind, :defaultValueLiteral => "instance"
end
class StructuralFeature < Feature
has_attr 'changeability', UML13::ChangeableKind, :defaultValueLiteral => "changeable"
has_attr 'targetScope', UML13::ScopeKind, :defaultValueLiteral => "instance"
end
class AssociationEnd < ModelElement
has_attr 'isNavigable', Boolean, :defaultValueLiteral => "false"
has_attr 'ordering', UML13::OrderingKind, :defaultValueLiteral => "unordered"
has_attr 'aggregation', UML13::AggregationKind, :defaultValueLiteral => "none"
has_attr 'targetScope', UML13::ScopeKind, :defaultValueLiteral => "instance"
has_attr 'changeability', UML13::ChangeableKind, :defaultValueLiteral => "changeable"
end
class Interface < Classifier
end
class Constraint < ModelElement
end
class Relationship < ModelElement
end
class Association < RGen::MetamodelBuilder::MMMultiple(GeneralizableElement, Relationship)
end
class Attribute < StructuralFeature
end
class BehavioralFeature < Feature
has_attr 'isQuery', Boolean
end
class Operation < BehavioralFeature
has_attr 'concurrency', UML13::CallConcurrencyKind, :defaultValueLiteral => "sequential"
has_attr 'isRoot', Boolean
has_attr 'isLeaf', Boolean
has_attr 'isAbstract', Boolean
end
class Parameter < ModelElement
has_attr 'kind', UML13::ParameterDirectionKind, :defaultValueLiteral => "inout"
end
class Method < BehavioralFeature
end
class Generalization < Relationship
has_attr 'discriminator', String
end
class AssociationClass < RGen::MetamodelBuilder::MMMultiple(Class, Association)
end
class Dependency < Relationship
end
class Abstraction < Dependency
end
class PresentationElement < Element
end
class Usage < Dependency
end
class Binding < Dependency
end
class Component < Classifier
end
class Node < Classifier
end
class Permission < Dependency
end
class Comment < ModelElement
has_attr 'body', String
end
class Flow < Relationship
end
class TemplateParameter < RGen::MetamodelBuilder::MMBase
end
class ElementResidence < RGen::MetamodelBuilder::MMBase
has_attr 'visibility', UML13::VisibilityKind, :defaultValueLiteral => "public"
end
class Multiplicity < RGen::MetamodelBuilder::MMBase
end
class Expression < RGen::MetamodelBuilder::MMBase
has_attr 'language', String
has_attr 'body', String
end
class ObjectSetExpression < Expression
end
class TimeExpression < Expression
end
class BooleanExpression < Expression
end
class ActionExpression < Expression
end
class MultiplicityRange < RGen::MetamodelBuilder::MMBase
has_attr 'lower', String
has_attr 'upper', String
end
class Structure < DataType
end
class Primitive < DataType
end
class Enumeration < DataType
end
class EnumerationLiteral < RGen::MetamodelBuilder::MMBase
has_attr 'name', String
end
class ProgrammingLanguageType < DataType
end
class IterationExpression < Expression
end
class TypeExpression < Expression
end
class ArgListsExpression < Expression
end
class MappingExpression < Expression
end
class ProcedureExpression < Expression
end
class Stereotype < GeneralizableElement
has_attr 'icon', String
has_attr 'baseClass', String
end
class TaggedValue < Element
has_attr 'tag', String
has_attr 'value', String
end
class UseCase < Classifier
end
class Actor < Classifier
end
class Instance < ModelElement
end
class UseCaseInstance < Instance
end
class Extend < Relationship
end
class Include < Relationship
end
class ExtensionPoint < ModelElement
has_attr 'location', String
end
class StateMachine < ModelElement
end
class Event < ModelElement
end
class StateVertex < ModelElement
end
class State < StateVertex
end
class TimeEvent < Event
end
class CallEvent < Event
end
class SignalEvent < Event
end
class Transition < ModelElement
end
class CompositeState < State
has_attr 'isConcurrent', Boolean
end
class ChangeEvent < Event
end
class Guard < ModelElement
end
class Pseudostate < StateVertex
has_attr 'kind', UML13::PseudostateKind, :defaultValueLiteral => "initial"
end
class SimpleState < State
end
class SubmachineState < CompositeState
end
class SynchState < StateVertex
has_attr 'bound', Integer
end
class StubState < StateVertex
has_attr 'referenceState', String
end
class FinalState < State
end
class Collaboration < RGen::MetamodelBuilder::MMMultiple(GeneralizableElement, Namespace)
end
class ClassifierRole < Classifier
end
class AssociationRole < Association
end
class AssociationEndRole < AssociationEnd
end
class Message < ModelElement
end
class Interaction < ModelElement
end
class Signal < Classifier
end
class Action < ModelElement
has_attr 'isAsynchronous', Boolean
end
class CreateAction < Action
end
class DestroyAction < Action
end
class UninterpretedAction < Action
end
class AttributeLink < ModelElement
end
class Object < Instance
end
class Link < ModelElement
end
class LinkObject < RGen::MetamodelBuilder::MMMultiple(Object, Link)
end
class DataValue < Instance
end
class CallAction < Action
end
class SendAction < Action
end
class ActionSequence < Action
end
class Argument < ModelElement
end
class Reception < BehavioralFeature
has_attr 'isPolymorphic', Boolean
has_attr 'specification', String
end
class LinkEnd < ModelElement
end
class Call < RGen::MetamodelBuilder::MMBase
end
class ReturnAction < Action
end
class TerminateAction < Action
end
class Stimulus < ModelElement
end
class ActionInstance < RGen::MetamodelBuilder::MMBase
end
class Exception < Signal
end
class AssignmentAction < Action
end
class ComponentInstance < Instance
end
class NodeInstance < Instance
end
class ActivityGraph < StateMachine
end
class Partition < ModelElement
end
class SubactivityState < SubmachineState
has_attr 'isDynamic', Boolean
end
class ActionState < SimpleState
has_attr 'isDynamic', Boolean
end
class CallState < ActionState
end
class ObjectFlowState < SimpleState
has_attr 'isSynch', Boolean
end
class ClassifierInState < Classifier
end
class Package < RGen::MetamodelBuilder::MMMultiple(GeneralizableElement, Namespace)
end
class Model < Package
end
class Subsystem < RGen::MetamodelBuilder::MMMultiple(Classifier, Package)
has_attr 'isInstantiable', Boolean
end
class ElementImport < RGen::MetamodelBuilder::MMBase
has_attr 'visibility', UML13::VisibilityKind, :defaultValueLiteral => "public"
has_attr 'alias', String
end
class DiagramElement < PresentationElement
has_attr 'geometry', String
has_attr 'style', String
end
class Diagram < PresentationElement
has_attr 'name', String
has_attr 'toolName', String
has_attr 'diagramType', String
has_attr 'style', String
end
end
UML13::Classifier.many_to_many 'participant', UML13::AssociationEnd, 'specification'
UML13::Classifier.one_to_many 'associationEnd', UML13::AssociationEnd, 'type'
UML13::Classifier.contains_many 'feature', UML13::Feature, 'owner'
UML13::StructuralFeature.contains_one_uni 'multiplicity', UML13::Multiplicity
UML13::StructuralFeature.has_one 'type', UML13::Classifier, :lowerBound => 1
UML13::Namespace.contains_many 'ownedElement', UML13::ModelElement, 'namespace'
UML13::AssociationEnd.contains_one_uni 'multiplicity', UML13::Multiplicity
UML13::AssociationEnd.contains_many 'qualifier', UML13::Attribute, 'associationEnd'
UML13::Association.contains_many 'connection', UML13::AssociationEnd, 'association', :lowerBound => 2
UML13::Constraint.contains_one_uni 'body', UML13::BooleanExpression
UML13::Constraint.many_to_many 'constrainedElement', UML13::ModelElement, 'constraint', :lowerBound => 1
UML13::GeneralizableElement.one_to_many 'specialization', UML13::Generalization, 'parent'
UML13::GeneralizableElement.one_to_many 'generalization', UML13::Generalization, 'child'
UML13::Attribute.contains_one_uni 'initialValue', UML13::Expression
UML13::Operation.one_to_many 'occurrence', UML13::CallEvent, 'operation'
UML13::Operation.one_to_many 'method', UML13::Method, 'specification'
UML13::Parameter.contains_one_uni 'defaultValue', UML13::Expression
UML13::Parameter.many_to_many 'state', UML13::ObjectFlowState, 'parameter'
UML13::Parameter.has_one 'type', UML13::Classifier, :lowerBound => 1
UML13::Method.contains_one_uni 'body', UML13::ProcedureExpression
UML13::BehavioralFeature.many_to_many 'raisedSignal', UML13::Signal, 'context'
UML13::BehavioralFeature.contains_many_uni 'parameter', UML13::Parameter
UML13::ModelElement.one_to_many 'behavior', UML13::StateMachine, 'context'
UML13::ModelElement.many_to_one 'stereotype', UML13::Stereotype, 'extendedElement'
UML13::ModelElement.one_to_many 'elementResidence', UML13::ElementResidence, 'resident'
UML13::ModelElement.many_to_many 'sourceFlow', UML13::Flow, 'source'
UML13::ModelElement.many_to_many 'targetFlow', UML13::Flow, 'target'
UML13::ModelElement.many_to_many 'presentation', UML13::PresentationElement, 'subject'
UML13::ModelElement.many_to_many 'supplierDependency', UML13::Dependency, 'supplier', :lowerBound => 1
UML13::ModelElement.contains_many 'taggedValue', UML13::TaggedValue, 'modelElement'
UML13::ModelElement.contains_many_uni 'templateParameter', UML13::TemplateParameter
UML13::ModelElement.many_to_many 'clientDependency', UML13::Dependency, 'client', :lowerBound => 1
UML13::ModelElement.many_to_many 'comment', UML13::Comment, 'annotatedElement'
UML13::ModelElement.one_to_many 'elementImport', UML13::ElementImport, 'modelElement'
UML13::Abstraction.contains_one_uni 'mapping', UML13::MappingExpression
UML13::Binding.has_many 'argument', UML13::ModelElement, :lowerBound => 1
UML13::Component.contains_many 'residentElement', UML13::ElementResidence, 'implementationLocation'
UML13::Component.many_to_many 'deploymentLocation', UML13::Node, 'resident'
UML13::TemplateParameter.has_one 'modelElement', UML13::ModelElement
UML13::TemplateParameter.has_one 'defaultElement', UML13::ModelElement
UML13::Multiplicity.contains_many_uni 'range', UML13::MultiplicityRange, :lowerBound => 1
UML13::Enumeration.contains_many_uni 'literal', UML13::EnumerationLiteral, :lowerBound => 1
UML13::ProgrammingLanguageType.contains_one_uni 'type', UML13::TypeExpression
UML13::Stereotype.has_many 'requiredTag', UML13::TaggedValue
UML13::UseCase.has_many 'extensionPoint', UML13::ExtensionPoint
UML13::UseCase.one_to_many 'include', UML13::Include, 'base'
UML13::UseCase.one_to_many 'extend', UML13::Extend, 'extension'
UML13::Extend.contains_one_uni 'condition', UML13::BooleanExpression
UML13::Extend.has_many 'extensionPoint', UML13::ExtensionPoint, :lowerBound => 1
UML13::Extend.has_one 'base', UML13::UseCase, :lowerBound => 1
UML13::Include.has_one 'addition', UML13::UseCase, :lowerBound => 1
UML13::StateMachine.contains_many_uni 'transitions', UML13::Transition
UML13::StateMachine.contains_one_uni 'top', UML13::State, :lowerBound => 1
UML13::Event.contains_many_uni 'parameters', UML13::Parameter
UML13::State.contains_one_uni 'doActivity', UML13::Action
UML13::State.contains_many_uni 'internalTransition', UML13::Transition
UML13::State.has_many 'deferrableEvent', UML13::Event
UML13::State.contains_one_uni 'exit', UML13::Action
UML13::State.contains_one_uni 'entry', UML13::Action
UML13::TimeEvent.contains_one_uni 'when', UML13::TimeExpression
UML13::SignalEvent.many_to_one 'signal', UML13::Signal, 'occurrence', :lowerBound => 1
UML13::Transition.many_to_one 'target', UML13::StateVertex, 'incoming', :lowerBound => 1
UML13::Transition.many_to_one 'source', UML13::StateVertex, 'outgoing', :lowerBound => 1
UML13::Transition.has_one 'trigger', UML13::Event
UML13::Transition.contains_one_uni 'effect', UML13::Action
UML13::Transition.contains_one_uni 'guard', UML13::Guard
UML13::CompositeState.contains_many 'subvertex', UML13::StateVertex, 'container', :lowerBound => 1
UML13::ChangeEvent.contains_one_uni 'changeExpression', UML13::BooleanExpression
UML13::Guard.contains_one_uni 'expression', UML13::BooleanExpression
UML13::SubmachineState.has_one 'submachine', UML13::StateMachine, :lowerBound => 1
UML13::Collaboration.has_one 'representedOperation', UML13::Operation
UML13::Collaboration.has_one 'representedClassifier', UML13::Classifier
UML13::Collaboration.has_many 'constrainingElement', UML13::ModelElement
UML13::Collaboration.contains_many 'interaction', UML13::Interaction, 'context'
UML13::ClassifierRole.contains_one_uni 'multiplicity', UML13::Multiplicity
UML13::ClassifierRole.has_many 'availableContents', UML13::ModelElement
UML13::ClassifierRole.has_many 'availableFeature', UML13::Feature
UML13::ClassifierRole.has_one 'base', UML13::Classifier, :lowerBound => 1
UML13::AssociationRole.contains_one_uni 'multiplicity', UML13::Multiplicity
UML13::AssociationRole.has_one 'base', UML13::Association
UML13::AssociationEndRole.has_many 'availableQualifier', UML13::Attribute
UML13::AssociationEndRole.has_one 'base', UML13::AssociationEnd
UML13::Message.has_one 'action', UML13::Action, :lowerBound => 1
UML13::Message.has_one 'communicationConnection', UML13::AssociationRole
UML13::Message.has_many 'predecessor', UML13::Message
UML13::Message.has_one 'receiver', UML13::ClassifierRole, :lowerBound => 1
UML13::Message.has_one 'sender', UML13::ClassifierRole, :lowerBound => 1
UML13::Message.has_one 'activator', UML13::Message
UML13::Interaction.contains_many 'message', UML13::Message, 'interaction', :lowerBound => 1
UML13::Interaction.contains_many_uni 'link', UML13::Link
UML13::Instance.contains_many_uni 'slot', UML13::AttributeLink
UML13::Instance.one_to_many 'linkEnd', UML13::LinkEnd, 'instance'
UML13::Instance.has_many 'classifier', UML13::Classifier, :lowerBound => 1
UML13::Signal.one_to_many 'reception', UML13::Reception, 'signal'
UML13::CreateAction.has_one 'instantiation', UML13::Classifier, :lowerBound => 1
UML13::Action.contains_one_uni 'recurrence', UML13::IterationExpression
UML13::Action.contains_one_uni 'target', UML13::ObjectSetExpression
UML13::Action.contains_one_uni 'script', UML13::ActionExpression
UML13::Action.contains_many_uni 'actualArgument', UML13::Argument
UML13::AttributeLink.has_one 'value', UML13::Instance, :lowerBound => 1
UML13::AttributeLink.has_one 'attribute', UML13::Attribute, :lowerBound => 1
UML13::CallAction.has_one 'operation', UML13::Operation, :lowerBound => 1
UML13::SendAction.has_one 'signal', UML13::Signal, :lowerBound => 1
UML13::ActionSequence.contains_many_uni 'action', UML13::Action
UML13::Argument.contains_one_uni 'value', UML13::Expression
UML13::Link.contains_many_uni 'connection', UML13::LinkEnd, :lowerBound => 2
UML13::Link.has_one 'association', UML13::Association, :lowerBound => 1
UML13::LinkEnd.has_one 'associationEnd', UML13::AssociationEnd, :lowerBound => 1
UML13::LinkEnd.has_one 'participant', UML13::Instance, :lowerBound => 1
UML13::Stimulus.has_one 'dispatchAction', UML13::Action, :lowerBound => 1
UML13::Stimulus.has_one 'communicationLink', UML13::Link
UML13::Stimulus.has_one 'receiver', UML13::Instance, :lowerBound => 1
UML13::Stimulus.has_one 'sender', UML13::Instance, :lowerBound => 1
UML13::Stimulus.has_many 'argument', UML13::Instance
UML13::ComponentInstance.has_many 'resident', UML13::Instance
UML13::NodeInstance.has_many 'resident', UML13::ComponentInstance
UML13::ActivityGraph.contains_many_uni 'partition', UML13::Partition
UML13::Partition.has_many 'contents', UML13::ModelElement
UML13::SubactivityState.contains_one_uni 'dynamicArguments', UML13::ArgListsExpression
UML13::ObjectFlowState.has_one 'type', UML13::Classifier, :lowerBound => 1
UML13::ObjectFlowState.has_one 'available', UML13::Parameter, :lowerBound => 1
UML13::ClassifierInState.has_one 'type', UML13::Classifier, :lowerBound => 1
UML13::ClassifierInState.has_many 'inState', UML13::State
UML13::ActionState.contains_one_uni 'dynamicArguments', UML13::ArgListsExpression
UML13::Package.contains_many 'importedElement', UML13::ElementImport, 'package'
UML13::Diagram.contains_many 'element', UML13::DiagramElement, 'diagram'
UML13::Diagram.has_one 'owner', UML13::ModelElement, :lowerBound => 1
rgen-0.7.0/lib/metamodels/uml13_metamodel_ext.rb 0000644 0000041 0000041 00000001164 12352210062 021571 0 ustar www-data www-data # Some handy extensions to the UML13 metamodel
#
module UML13
module AssociationEnd::ClassModule
def otherEnd
association.connection.find{|c| c != self}
end
end
module Classifier::ClassModule
def localCompositeEnd
associationEnd.select{|e| e.aggregation == :composite}
end
def remoteCompositeEnd
associationEnd.otherEnd.select{|e| e.aggregation == :composite}
end
def localNavigableEnd
associationEnd.select{|e| e.isNavigable}
end
def remoteNavigableEnd
associationEnd.otherEnd.select{|e| e.isNavigable}
end
end
end
rgen-0.7.0/lib/mmgen/ 0000755 0000041 0000041 00000000000 12352210062 014343 5 ustar www-data www-data rgen-0.7.0/lib/mmgen/templates/ 0000755 0000041 0000041 00000000000 12352210062 016341 5 ustar www-data www-data rgen-0.7.0/lib/mmgen/templates/metamodel_generator.tpl 0000644 0000041 0000041 00000015461 12352210062 023106 0 ustar www-data www-data
<% define 'GenerateMetamodel', :for => EPackage do |filename| %>
<% file filename do %>
require 'rgen/metamodel_builder'
<%nl%>
<% if needClassReorder? %>
<% expand 'GeneratePackagesOnly' %>
<% expand 'GenerateClassesReordered' %>
<% else %>
<% expand 'GeneratePackage' %>
<% end %>
<%nl%>
<% expand 'GenerateAssocs' %>
<% end %>
<% end %>
<% define 'GeneratePackage', :for => EPackage do %>
module <%= moduleName %><% iinc %>
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
<% expand 'annotations::Annotations' %>
<%nl%>
<% expand 'EnumTypes' %>
<% for c in ownClasses %><%nl%>
<% expand 'ClassHeader', this, :for => c %><%iinc%>
<% if c.abstract %>abstract<% end %>
<% expand 'annotations::Annotations', :for => c %>
<% expand 'Attribute', this, :foreach => c.eAttributes %>
<%idec%>
end
<% end %><%nl%>
<% for p in eSubpackages %>
<%nl%><% expand 'GeneratePackage', :for => p %>
<% end %><%idec%>
end
<% end %>
<% define 'GenerateClassesReordered', :for => EPackage do %>
<% for c in allClassesSorted %><%nl%>
<% expand 'ClassHeaderFullyQualified', this, :for => c %><%iinc%>
<% if c.abstract %>abstract<% end %>
<% expand 'annotations::Annotations', :for => c %>
<% expand 'Attribute', this, :foreach => c.eAttributes %>
<%idec%>
end
<% end %><%nl%>
<% end %>
<% define 'GeneratePackagesOnly', :for => EPackage do %>
module <%= moduleName %><% iinc %>
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
<% expand 'annotations::Annotations' %>
<%nl%>
<% expand 'EnumTypes' %>
<% for p in eSubpackages %>
<%nl%><% expand 'GeneratePackagesOnly', :for => p %>
<% end %><%idec%>
end
<% end %>
<% define 'Attribute', :for => EAttribute do |rootp| %>
<% if upperBound == 1%>has_attr<% else %>has_many_attr<% end %> '<%= name %>', <%nows%>
<% if eType.is_a?(EEnum) %><%nows%>
<%= eType.qualifiedClassifierName(rootp) %><%nows%>
<% else %><%nows%>
<%= eType && eType.instanceClass.to_s %><%nows%>
<% end %><%nows%>
<% for p in RGen::MetamodelBuilder::Intermediate::Attribute.properties %>
<% unless p == :name || (p == :upperBound && (upperBound == 1 || upperBound == -1)) ||
RGen::MetamodelBuilder::Intermediate::Attribute.default_value(p) == getGeneric(p) %>
, :<%=p%> => <%nows%>
<% if getGeneric(p).is_a?(String) %>
"<%= getGeneric(p) %>"<%nows%>
<% elsif getGeneric(p).is_a?(Symbol) %>
:<%= getGeneric(p) %><%nows%>
<% else %>
<%= getGeneric(p) %><%nows%>
<% end %>
<% end %>
<% end %>
<%ws%><% expand 'annotations::Annotations' %><%nl%>
<% end %>
<% define 'EnumTypes', :for => EPackage do %>
<% for enum in eClassifiers.select{|c| c.is_a?(EEnum)} %>
<%= enum.name %> = Enum.new(:name => '<%= enum.name %>', :literals =>[ <%nows%>
<%= enum.eLiterals.collect { |lit| ":"+(lit.name =~ /^\d|\W/ ? "'"+lit.name+"'" : lit.name) }.join(', ') %> ])
<% end %>
<% end %>
<% define 'GenerateAssocs', :for => EPackage do %>
<% refDone = {} %>
<% for ref in eAllClassifiers.select{|c| c.is_a?(EClass)}.eReferences %>
<% if !refDone[ref] && ref.eOpposite %>
<% ref = ref.eOpposite if ref.eOpposite.containment %>
<% refDone[ref] = refDone[ref.eOpposite] = true %>
<% if !ref.many && !ref.eOpposite.many %>
<% if ref.containment %>
<% expand 'Reference', "contains_one", this, :for => ref %>
<% else %>
<% expand 'Reference', "one_to_one", this, :for => ref %>
<% end %>
<% elsif !ref.many && ref.eOpposite.many %>
<% expand 'Reference', "many_to_one", this, :for => ref %>
<% elsif ref.many && !ref.eOpposite.many %>
<% if ref.containment %>
<% expand 'Reference', "contains_many", this, :for => ref %>
<% else %>
<% expand 'Reference', "one_to_many", this, :for => ref %>
<% end %>
<% elsif ref.many && ref.eOpposite.many %>
<% expand 'Reference', "many_to_many", this, :for => ref %>
<% end %>
<% expand 'annotations::Annotations', :for => ref %><%nl%>
<% elsif !refDone[ref] %>
<% refDone[ref] = true %>
<% if !ref.many %>
<% if ref.containment %>
<% expand 'Reference', "contains_one_uni", this, :for => ref %>
<% else %>
<% expand 'Reference', "has_one", this, :for => ref %>
<% end %>
<% elsif ref.many %>
<% if ref.containment %>
<% expand 'Reference', "contains_many_uni", this, :for => ref %>
<% else %>
<% expand 'Reference', "has_many", this, :for => ref %>
<% end %>
<% end %>
<% expand 'annotations::Annotations', :for => ref %><%nl%>
<% end %>
<% end %>
<% end %>
<% define 'Reference', :for => EReference do |cmd, rootpackage| %>
<%= eContainingClass.qualifiedClassifierName(rootpackage) %>.<%= cmd %> '<%= name %>', <%= eType && eType.qualifiedClassifierName(rootpackage) %><%nows%>
<% if eOpposite %><%nows%>
, '<%= eOpposite.name%>'<%nows%>
<% end %><%nows%>
<% pset = RGen::MetamodelBuilder::Intermediate::Reference.properties.reject{|p| p == :name || p == :upperBound || p == :containment} %>
<% for p in pset.reject{|p| RGen::MetamodelBuilder::Intermediate::Reference.default_value(p) == getGeneric(p)} %>
, :<%=p%> => <%=getGeneric(p)%><%nows%>
<% end %>
<% if eOpposite %>
<% for p in pset.reject{|p| RGen::MetamodelBuilder::Intermediate::Reference.default_value(p) == eOpposite.getGeneric(p)} %>
, :opposite_<%=p%> => <%=eOpposite.getGeneric(p)%><%nows%>
<% end %>
<% end %><%ws%>
<% end %>
<% define 'ClassHeader', :for => EClass do |rootp| %>
class <%= classifierName %> < <% nows %>
<% if eSuperTypes.size > 1 %><% nows %>
RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedClassifierNameIfRequired(rootp)}.join(', ') %>)
<% elsif eSuperTypes.size > 0 %><% nows %>
<%= eSuperTypes.first.qualifiedClassifierNameIfRequired(rootp) %>
<% else %><% nows %>
RGen::MetamodelBuilder::MMBase
<% end %>
<% end %>
<% define 'ClassHeaderFullyQualified', :for => EClass do |rootp| %>
class <%= qualifiedClassifierName(rootp) %> < <% nows %>
<% if eSuperTypes.size > 1 %><% nows %>
RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedClassifierName(rootp)}.join(', ') %>)
<% elsif eSuperTypes.size > 0 %><% nows %>
<%= eSuperTypes.first.qualifiedClassifierName(rootp) %>
<% else %><% nows %>
RGen::MetamodelBuilder::MMBase
<% end %>
<% end %>
rgen-0.7.0/lib/mmgen/templates/annotations.tpl 0000644 0000041 0000041 00000002353 12352210062 021422 0 ustar www-data www-data <% define 'Annotations', :for => EPackage do %>
<% for a in eAnnotations %>
annotation <% expand 'AnnotationArgs', :for => a %>
<% end %>
<% end %>
<% define 'Annotations', :for => EClass do %>
<% for a in eAnnotations %>
annotation <% expand 'AnnotationArgs', :for => a %>
<% end %>
<% end %>
<% define 'Annotations', :for => EStructuralFeature do %>
<% oppositeAnnotations = (this.respond_to?(:eOpposite) && eOpposite && eOpposite.eAnnotations) || [] %>
<% if eAnnotations.size > 0 || oppositeAnnotations.size > 0 %>
do<%iinc%>
<% for a in eAnnotations %>
annotation <% expand 'AnnotationArgs', :for => a %>
<% end %>
<% for a in oppositeAnnotations %>
opposite_annotation <% expand 'AnnotationArgs', :for => a %>
<% end %><%idec%>
end<%nows%>
<% end %>
<% end %>
<% define 'AnnotationArgs', :for => EAnnotation do %>
<% if source.nil? %>
<% expand 'Details' %>
<% else %>
:source => "<%= source.to_s %>", :details => {<% expand 'Details' %>}<%nows%>
<% end %>
<% end %>
<% define 'Details', :for => EAnnotation do %>
<%= details.sort{|a,b| a.key<=>b.key}.collect{ |d| "\'" + d.key + "\' => \'"+ (d.value || "").gsub('\'','\\\'').to_s + "\'"}.join(', ') %><%nows%>
<% end %> rgen-0.7.0/lib/mmgen/mm_ext/ 0000755 0000041 0000041 00000000000 12352210062 015634 5 ustar www-data www-data rgen-0.7.0/lib/mmgen/mm_ext/ecore_mmgen_ext.rb 0000644 0000041 0000041 00000004733 12352210062 021330 0 ustar www-data www-data require 'rgen/util/name_helper'
module RGen
module ECore
module EPackage::ClassModule
include RGen::Util::NameHelper
def moduleName
firstToUpper(name)
end
def qualifiedModuleName(rootPackage)
return moduleName unless eSuperPackage and self != rootPackage
eSuperPackage.qualifiedModuleName(rootPackage) + "::" + moduleName
end
def ancestorPackages
return [] unless eSuperPackage
[eSuperPackage] + eSuperPackage.ancestorPackages
end
def ownClasses
eClassifiers.select{|c| c.is_a?(EClass)}
end
def classesInGenerationOrdering
ownClasses + eSubpackages.collect{|s| s.classesInGenerationOrdering}.flatten
end
def needClassReorder?
classesInGenerationOrdering != inheritanceOrderClasses(classesInGenerationOrdering)
end
def allClassesSorted
inheritanceOrderClasses(classesInGenerationOrdering)
end
def inheritanceOrderClasses(cls)
sortArray = cls.dup
i1 = 0
while i1 < sortArray.size-1
again = false
for i2 in i1+1..sortArray.size-1
e2 = sortArray[i2]
if sortArray[i1].eSuperTypes.include?(e2)
sortArray.delete(e2)
sortArray.insert(i1,e2)
again = true
break
end
end
i1 += 1 unless again
end
sortArray
end
end
module EClassifier::ClassModule
include RGen::Util::NameHelper
def classifierName
firstToUpper(name)
end
def qualifiedClassifierName(rootPackage)
(ePackage ? ePackage.qualifiedModuleName(rootPackage) + "::" : "") + classifierName
end
def ancestorPackages
return [] unless ePackage
[ePackage] + ePackage.ancestorPackages
end
def qualifiedClassifierNameIfRequired(package)
if ePackage != package
commonSuper = (package.ancestorPackages & ancestorPackages).first
qualifiedClassifierName(commonSuper)
else
classifierName
end
end
end
module EAttribute::ClassModule
def RubyType
typeMap = {'float' => 'Float', 'int' => 'Integer'}
(self.getType && typeMap[self.getType.downcase]) || 'String'
end
end
end
end
rgen-0.7.0/lib/mmgen/metamodel_generator.rb 0000644 0000041 0000041 00000001044 12352210062 020704 0 ustar www-data www-data require 'rgen/environment'
require 'rgen/template_language'
require 'rgen/ecore/ecore'
require 'rgen/ecore/ecore_ext'
require 'mmgen/mm_ext/ecore_mmgen_ext'
module MMGen
module MetamodelGenerator
def generateMetamodel(rootPackage, out_file)
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new(RGen::ECore, File.dirname(out_file))
tpl_path = File.dirname(__FILE__) + '/templates'
tc.load(tpl_path)
tc.expand('metamodel_generator::GenerateMetamodel', File.basename(out_file), :for => rootPackage)
end
end
end rgen-0.7.0/lib/mmgen/mmgen.rb 0000644 0000041 0000041 00000001346 12352210062 015777 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..")
require 'ea/xmi_ecore_instantiator'
require 'mmgen/metamodel_generator'
include MMGen::MetamodelGenerator
unless ARGV.length >= 2
puts "Usage: mmgen.rb ()*"
exit
else
file_name = ARGV.shift
root_package_name = ARGV.shift
modules = ARGV
out_file = file_name.gsub(/\.\w+$/,'.rb')
puts out_file
end
env = RGen::Environment.new
File.open(file_name) { |f|
puts "instantiating ..."
XMIECoreInstantiator.new.instantiateECoreModel(env, f.read)
}
rootPackage = env.find(:class => RGen::ECore::EPackage, :name => root_package_name).first
puts "generating ..."
generateMetamodel(rootPackage, out_file, modules)
rgen-0.7.0/metadata.yml 0000644 0000041 0000041 00000017753 12352210062 015012 0 ustar www-data www-data --- !ruby/object:Gem::Specification
name: rgen
version: !ruby/object:Gem::Version
version: 0.7.0
platform: ruby
authors:
- Martin Thiede
autorequire:
bindir: bin
cert_chain: []
date: 2014-04-01 00:00:00.000000000 Z
dependencies: []
description: RGen is a framework for Model Driven Software Development (MDSD) in Ruby.
This means that it helps you build Metamodels, instantiate Models, modify and transform
Models and finally generate arbitrary textual content from it.
email: martin dot thiede at gmx de
executables: []
extensions: []
extra_rdoc_files:
- README.rdoc
- CHANGELOG
- MIT-LICENSE
files:
- lib/ea_support/ea_support.rb
- lib/ea_support/id_store.rb
- lib/ea_support/uml13_ea_metamodel.rb
- lib/ea_support/uml13_ea_metamodel_ext.rb
- lib/ea_support/uml13_ea_metamodel_generator.rb
- lib/ea_support/uml13_ea_to_uml13.rb
- lib/ea_support/uml13_to_uml13_ea.rb
- lib/metamodels/uml13_metamodel.rb
- lib/metamodels/uml13_metamodel_ext.rb
- lib/mmgen/metamodel_generator.rb
- lib/mmgen/mm_ext/ecore_mmgen_ext.rb
- lib/mmgen/mmgen.rb
- lib/mmgen/templates/annotations.tpl
- lib/mmgen/templates/metamodel_generator.tpl
- lib/rgen/array_extensions.rb
- lib/rgen/ecore/ecore.rb
- lib/rgen/ecore/ecore_builder_methods.rb
- lib/rgen/ecore/ecore_ext.rb
- lib/rgen/ecore/ecore_interface.rb
- lib/rgen/ecore/ecore_to_ruby.rb
- lib/rgen/ecore/ruby_to_ecore.rb
- lib/rgen/environment.rb
- lib/rgen/fragment/dump_file_cache.rb
- lib/rgen/fragment/fragmented_model.rb
- lib/rgen/fragment/model_fragment.rb
- lib/rgen/instantiator/abstract_instantiator.rb
- lib/rgen/instantiator/abstract_xml_instantiator.rb
- lib/rgen/instantiator/default_xml_instantiator.rb
- lib/rgen/instantiator/ecore_xml_instantiator.rb
- lib/rgen/instantiator/json_instantiator.rb
- lib/rgen/instantiator/json_parser.rb
- lib/rgen/instantiator/json_parser.y
- lib/rgen/instantiator/nodebased_xml_instantiator.rb
- lib/rgen/instantiator/qualified_name_resolver.rb
- lib/rgen/instantiator/reference_resolver.rb
- lib/rgen/instantiator/resolution_helper.rb
- lib/rgen/instantiator/xmi11_instantiator.rb
- lib/rgen/metamodel_builder.rb
- lib/rgen/metamodel_builder/builder_extensions.rb
- lib/rgen/metamodel_builder/builder_runtime.rb
- lib/rgen/metamodel_builder/constant_order_helper.rb
- lib/rgen/metamodel_builder/data_types.rb
- lib/rgen/metamodel_builder/intermediate/annotation.rb
- lib/rgen/metamodel_builder/intermediate/feature.rb
- lib/rgen/metamodel_builder/mm_multiple.rb
- lib/rgen/metamodel_builder/module_extension.rb
- lib/rgen/model_builder.rb
- lib/rgen/model_builder/builder_context.rb
- lib/rgen/model_builder/model_serializer.rb
- lib/rgen/model_builder/reference_resolver.rb
- lib/rgen/serializer/json_serializer.rb
- lib/rgen/serializer/opposite_reference_filter.rb
- lib/rgen/serializer/qualified_name_provider.rb
- lib/rgen/serializer/xmi11_serializer.rb
- lib/rgen/serializer/xmi20_serializer.rb
- lib/rgen/serializer/xml_serializer.rb
- lib/rgen/template_language.rb
- lib/rgen/template_language/directory_template_container.rb
- lib/rgen/template_language/output_handler.rb
- lib/rgen/template_language/template_container.rb
- lib/rgen/template_language/template_helper.rb
- lib/rgen/transformer.rb
- lib/rgen/util/auto_class_creator.rb
- lib/rgen/util/cached_glob.rb
- lib/rgen/util/file_cache_map.rb
- lib/rgen/util/file_change_detector.rb
- lib/rgen/util/method_delegation.rb
- lib/rgen/util/model_comparator.rb
- lib/rgen/util/model_comparator_base.rb
- lib/rgen/util/model_dumper.rb
- lib/rgen/util/name_helper.rb
- lib/rgen/util/pattern_matcher.rb
- lib/transformers/ecore_to_uml13.rb
- lib/transformers/uml13_to_ecore.rb
- test/array_extensions_test.rb
- test/ea_instantiator_test.rb
- test/ea_serializer_test.rb
- test/ecore_self_test.rb
- test/environment_test.rb
- test/json_test.rb
- test/metamodel_builder_test.rb
- test/metamodel_from_ecore_test.rb
- test/metamodel_order_test.rb
- test/metamodel_roundtrip_test.rb
- test/metamodel_roundtrip_test/TestModel.rb
- test/metamodel_roundtrip_test/TestModel_Regenerated.rb
- test/metamodel_roundtrip_test/houseMetamodel.ecore
- test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore
- test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb
- test/metamodel_roundtrip_test/using_builtin_types.ecore
- test/metamodel_roundtrip_test/using_builtin_types_serialized.ecore
- test/method_delegation_test.rb
- test/model_builder/builder_context_test.rb
- test/model_builder/builder_test.rb
- test/model_builder/ecore_internal.rb
- test/model_builder/ecore_original.rb
- test/model_builder/ecore_original_regenerated.rb
- test/model_builder/reference_resolver_test.rb
- test/model_builder/serializer_test.rb
- test/model_builder/statemachine_metamodel.rb
- test/model_builder/test_model/statemachine1.rb
- test/model_builder_test.rb
- test/model_fragment_test.rb
- test/output_handler_test.rb
- test/qualified_name_provider_test.rb
- test/qualified_name_resolver_test.rb
- test/reference_resolver_test.rb
- test/rgen_test.rb
- test/template_language_test.rb
- test/template_language_test/expected_result1.txt
- test/template_language_test/expected_result2.txt
- test/template_language_test/expected_result3.txt
- test/template_language_test/indentStringTestDefaultIndent.out
- test/template_language_test/indentStringTestTabIndent.out
- test/template_language_test/templates/callback_indent_test/a.tpl
- test/template_language_test/templates/callback_indent_test/b.tpl
- test/template_language_test/templates/code/array.tpl
- test/template_language_test/templates/content/author.tpl
- test/template_language_test/templates/content/chapter.tpl
- test/template_language_test/templates/define_local_test/local.tpl
- test/template_language_test/templates/define_local_test/test.tpl
- test/template_language_test/templates/evaluate_test/test.tpl
- test/template_language_test/templates/indent_string_test.tpl
- test/template_language_test/templates/index/c/cmod.tpl
- test/template_language_test/templates/index/chapter.tpl
- test/template_language_test/templates/no_backslash_r_test.tpl
- test/template_language_test/templates/no_indent_test/no_indent.tpl
- test/template_language_test/templates/no_indent_test/sub1/no_indent.tpl
- test/template_language_test/templates/no_indent_test/test.tpl
- test/template_language_test/templates/no_indent_test/test2.tpl
- test/template_language_test/templates/no_indent_test/test3.tpl
- test/template_language_test/templates/null_context_test.tpl
- test/template_language_test/templates/root.tpl
- test/template_language_test/templates/template_resolution_test/sub1.tpl
- test/template_language_test/templates/template_resolution_test/sub1/sub1.tpl
- test/template_language_test/templates/template_resolution_test/test.tpl
- test/template_language_test/testout.txt
- test/testmodel/class_model_checker.rb
- test/testmodel/ea_testmodel.eap
- test/testmodel/ea_testmodel.xml
- test/testmodel/ea_testmodel_partial.xml
- test/testmodel/ea_testmodel_regenerated.xml
- test/testmodel/ecore_model_checker.rb
- test/testmodel/manual_testmodel.xml
- test/testmodel/object_model_checker.rb
- test/transformer_test.rb
- test/util/file_cache_map_test.rb
- test/util/file_cache_map_test/testdir/fileA
- test/util/pattern_matcher_test.rb
- test/util_test.rb
- test/xml_instantiator_test.rb
- test/xml_instantiator_test/simple_ecore_model_checker.rb
- test/xml_instantiator_test/simple_xmi_ecore_instantiator.rb
- test/xml_instantiator_test/simple_xmi_metamodel.rb
- test/xml_instantiator_test/simple_xmi_to_ecore.rb
- README.rdoc
- CHANGELOG
- MIT-LICENSE
- Rakefile
homepage: http://ruby-gen.org
licenses: []
metadata: {}
post_install_message:
rdoc_options:
- --main
- README.rdoc
- -x
- test
- -x
- metamodels
- -x
- ea_support/uml13*
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - '>='
- !ruby/object:Gem::Version
version: '0'
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - '>='
- !ruby/object:Gem::Version
version: '0'
requirements: []
rubyforge_project: rgen
rubygems_version: 2.0.3
signing_key:
specification_version: 4
summary: Ruby Modelling and Generator Framework
test_files: []
rgen-0.7.0/test/ 0000755 0000041 0000041 00000000000 12352210062 013451 5 ustar www-data www-data rgen-0.7.0/test/reference_resolver_test.rb 0000644 0000041 0000041 00000010224 12352210062 020713 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/metamodel_builder'
require 'rgen/instantiator/reference_resolver'
class ReferenceResolverTest < Test::Unit::TestCase
class TestNode < RGen::MetamodelBuilder::MMBase
has_attr 'name', String
has_one 'other', TestNode
has_many 'others', TestNode
end
class TestNode2 < RGen::MetamodelBuilder::MMBase
has_attr 'name', String
end
def test_identifier_resolver
nodeA, nodeB, nodeC, unresolved_refs = create_model
resolver = RGen::Instantiator::ReferenceResolver.new(
:identifier_resolver => proc do |ident|
{:a => nodeA, :b => nodeB, :c => nodeC}[ident]
end)
urefs = resolver.resolve(unresolved_refs)
check_model(nodeA, nodeB, nodeC)
assert urefs.empty?
end
def test_add_identifier
nodeA, nodeB, nodeC, unresolved_refs = create_model
resolver = RGen::Instantiator::ReferenceResolver.new
resolver.add_identifier(:a, nodeA)
resolver.add_identifier(:b, nodeB)
resolver.add_identifier(:c, nodeC)
urefs = resolver.resolve(unresolved_refs)
check_model(nodeA, nodeB, nodeC)
assert urefs.empty?
end
def test_problems
nodeA, nodeB, nodeC, unresolved_refs = create_model
resolver = RGen::Instantiator::ReferenceResolver.new(
:identifier_resolver => proc do |ident|
{:a => [nodeA, nodeB], :c => nodeC}[ident]
end)
problems = []
urefs = resolver.resolve(unresolved_refs, :problems => problems)
assert_equal ["identifier b not found", "identifier a not uniq"], problems
assert_equal 2, urefs.size
assert urefs.all?{|ur| !ur.target_type_error}
end
def test_on_resolve_proc
nodeA, nodeB, nodeC, unresolved_refs = create_model
resolver = RGen::Instantiator::ReferenceResolver.new
resolver.add_identifier(:a, nodeA)
resolver.add_identifier(:b, nodeB)
resolver.add_identifier(:c, nodeC)
data = []
resolver.resolve(unresolved_refs,
:on_resolve => proc {|ur, e| data << [ ur, e ]})
assert data[0][0].is_a?(RGen::Instantiator::ReferenceResolver::UnresolvedReference)
assert_equal nodeA, data[0][0].element
assert_equal "other", data[0][0].feature_name
assert_equal :b, data[0][0].proxy.targetIdentifier
assert_equal nodeB, data[0][1]
end
def test_target_type_error
nodeA, nodeB, nodeC, unresolved_refs = create_model
resolver = RGen::Instantiator::ReferenceResolver.new(
:identifier_resolver => proc do |ident|
{:a => TestNode2.new, :b => TestNode2.new, :c => nodeC}[ident]
end)
problems = []
urefs = resolver.resolve(unresolved_refs, :problems => problems)
assert_equal 2, problems.size
assert problems[0] =~ /invalid target type .*TestNode2/
assert problems[1] =~ /invalid target type .*TestNode2/
assert_equal 2, urefs.uniq.size
assert urefs[0].target_type_error
assert urefs[1].target_type_error
assert urefs.any?{|ur| ur.proxy.object_id == nodeA.other.object_id}
assert urefs.any?{|ur| ur.proxy.object_id == nodeB.others[0].object_id}
end
private
def create_model
nodeA = TestNode.new(:name => "NodeA")
nodeB = TestNode.new(:name => "NodeB")
nodeC = TestNode.new(:name => "NodeC")
bProxy = RGen::MetamodelBuilder::MMProxy.new(:b)
nodeA.other = bProxy
aProxy = RGen::MetamodelBuilder::MMProxy.new(:a)
cProxy = RGen::MetamodelBuilder::MMProxy.new(:c)
nodeB.others = [aProxy, cProxy]
unresolved_refs = [
RGen::Instantiator::ReferenceResolver::UnresolvedReference.new(nodeA, "other", bProxy),
RGen::Instantiator::ReferenceResolver::UnresolvedReference.new(nodeB, "others", aProxy),
RGen::Instantiator::ReferenceResolver::UnresolvedReference.new(nodeB, "others", cProxy)
]
return nodeA, nodeB, nodeC, unresolved_refs
end
def check_model(nodeA, nodeB, nodeC)
assert_equal nodeB, nodeA.other
assert_equal [], nodeA.others
assert_equal nil, nodeB.other
assert_equal [nodeA, nodeC], nodeB.others
assert_equal nil, nodeC.other
assert_equal [], nodeC.others
end
end
rgen-0.7.0/test/template_language_test.rb 0000644 0000041 0000041 00000014335 12352210062 020521 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/template_language'
require 'rgen/metamodel_builder'
class TemplateContainerTest < Test::Unit::TestCase
TEMPLATES_DIR = File.dirname(__FILE__)+"/template_language_test/templates"
OUTPUT_DIR = File.dirname(__FILE__)+"/template_language_test"
module MyMM
class Chapter
attr_reader :title
def initialize(title)
@title = title
end
end
class Document
attr_reader :title, :authors, :chapters
attr_accessor :sampleArray
def initialize(title)
@title = title
@chapters = []
@authors = []
end
end
class Author
attr_reader :name, :email
def initialize(name, email)
@name, @email = name, email
end
end
end
module CCodeMM
class CArray < RGen::MetamodelBuilder::MMBase
has_attr 'name'
has_attr 'size', Integer
has_attr 'type'
end
class PrimitiveInitValue < RGen::MetamodelBuilder::MMBase
has_attr 'value', Integer
end
CArray.has_many 'initvalue', PrimitiveInitValue
end
TEST_MODEL = MyMM::Document.new("SomeDocument")
TEST_MODEL.authors << MyMM::Author.new("Martin", "martin@somewhe.re")
TEST_MODEL.authors << MyMM::Author.new("Otherguy", "other@somewhereel.se")
TEST_MODEL.chapters << MyMM::Chapter.new("Intro")
TEST_MODEL.chapters << MyMM::Chapter.new("MainPart")
TEST_MODEL.chapters << MyMM::Chapter.new("Summary")
TEST_MODEL.sampleArray = CCodeMM::CArray.new(:name => "myArray", :type => "int", :size => 5,
:initvalue => (1..5).collect { |v| CCodeMM::PrimitiveInitValue.new(:value => v) })
def test_with_model
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
File.delete(OUTPUT_DIR+"/testout.txt") if File.exists? OUTPUT_DIR+"/testout.txt"
tc.expand('root::Root', :for => TEST_MODEL, :indent => 1)
result = expected = ""
File.open(OUTPUT_DIR+"/testout.txt") {|f| result = f.read}
File.open(OUTPUT_DIR+"/expected_result1.txt") {|f| expected = f.read}
assert_equal expected, result
end
def test_immediate_result
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
expected = ""
File.open(OUTPUT_DIR+"/expected_result2.txt","rb") {|f| expected = f.read}
assert_equal expected, tc.expand('code/array::ArrayDefinition', :for => TEST_MODEL.sampleArray).to_s
end
def test_indent_string
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
tc.indentString = " " # 2 spaces instead of 3 (default)
tc.expand('indent_string_test::IndentStringTest', :for => :dummy)
File.open(OUTPUT_DIR+"/indentStringTestDefaultIndent.out","rb") do |f|
assert_equal " <- your default here\r\n", f.read
end
File.open(OUTPUT_DIR+"/indentStringTestTabIndent.out","rb") do |f|
assert_equal "\t<- tab\r\n", f.read
end
end
def test_null_context
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
assert_raise StandardError do
# the template must raise an exception because it calls expand :for => nil
tc.expand('null_context_test::NullContextTestBad', :for => :dummy)
end
assert_raise StandardError do
# the template must raise an exception because it calls expand :foreach => nil
tc.expand('null_context_test::NullContextTestBad2', :for => :dummy)
end
assert_nothing_raised do
tc.expand('null_context_test::NullContextTestOk', :for => :dummy)
end
end
def test_no_indent
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
assert_equal " xxx<---\r\n xxx<---\r\n xxx<---\r\n xxx<---\r\n", tc.expand('no_indent_test/test::Test', :for => :dummy)
end
def test_no_indent2
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
assert_equal " return xxxx;\r\n", tc.expand("no_indent_test/test2::Test", :for => :dummy)
end
def test_no_indent3
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
assert_equal " l1<---\r\n l2\r\n\r\n", tc.expand("no_indent_test/test3::Test", :for => :dummy)
end
def test_template_resolution
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
assert_equal "Sub1\r\nSub1 in sub1\r\n", tc.expand('template_resolution_test/test::Test', :for => :dummy)
assert_equal "Sub1\r\nSub1\r\nSub1 in sub1\r\n", tc.expand('template_resolution_test/sub1::Test', :for => :dummy)
end
def test_evaluate
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
assert_equal "xx1xxxx2xxxx3xxxx4xx\r\n", tc.expand('evaluate_test/test::Test', :for => :dummy)
end
def test_define_local
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
assert_equal "Local1\r\n", tc.expand('define_local_test/test::Test', :for => :dummy)
assert_raise StandardError do
tc.expand('define_local_test/test::TestForbidden', :for => :dummy)
end
end
def test_no_backslash_r
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
expected = ""
File.open(OUTPUT_DIR+"/expected_result3.txt") {|f| expected = f.read}
assert_equal expected, tc.expand('no_backslash_r_test::Test', :for => :dummy).to_s
end
def test_callback_indent
tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new([MyMM, CCodeMM], OUTPUT_DIR)
tc.load(TEMPLATES_DIR)
assert_equal("|before callback\r\n |in callback\r\n|after callback\r\n |after iinc\r\n",
tc.expand('callback_indent_test/a::caller', :for => :dummy))
end
end
rgen-0.7.0/test/transformer_test.rb 0000644 0000041 0000041 00000016407 12352210062 017407 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
$:.unshift File.join(File.dirname(__FILE__),"..","test")
require 'test/unit'
require 'rgen/transformer'
require 'rgen/environment'
require 'rgen/util/model_comparator'
require 'metamodels/uml13_metamodel'
require 'testmodel/class_model_checker'
class TransformerTest < Test::Unit::TestCase
class ModelIn
attr_accessor :name
end
class ModelInSub < ModelIn
end
class ModelAIn
attr_accessor :name
attr_accessor :modelB
end
class ModelBIn
attr_accessor :name
attr_accessor :modelA
end
class ModelCIn
attr_accessor :number
end
class ModelOut
attr_accessor :name
end
class ModelAOut
attr_accessor :name
attr_accessor :modelB
end
class ModelBOut
attr_accessor :name
attr_accessor :modelA
end
class ModelCOut
attr_accessor :number
end
class MyTransformer < RGen::Transformer
attr_reader :modelInTrans_count
attr_reader :modelAInTrans_count
attr_reader :modelBInTrans_count
transform ModelIn, :to => ModelOut do
# aribitrary ruby code may be placed before the hash creating the output element
@modelInTrans_count ||= 0; @modelInTrans_count += 1
{ :name => name }
end
transform ModelAIn, :to => ModelAOut do
@modelAInTrans_count ||= 0; @modelAInTrans_count += 1
{ :name => name, :modelB => trans(modelB) }
end
transform ModelBIn, :to => ModelBOut do
@modelBInTrans_count ||= 0; @modelBInTrans_count += 1
{ :name => name, :modelA => trans(modelA) }
end
transform ModelCIn, :to => ModelCOut, :if => :largeNumber do
# a method can be called anywhere in a transformer block
{ :number => duplicateNumber }
end
transform ModelCIn, :to => ModelCOut, :if => :smallNumber do
{ :number => number / 2 }
end
method :largeNumber do
number > 1000
end
method :smallNumber do
number < 500
end
method :duplicateNumber do
number * 2;
end
end
class MyTransformer2 < RGen::Transformer
# check that subclasses are independent (i.e. do not share the rules)
transform ModelIn, :to => ModelOut do
{ :name => name }
end
end
def test_transformer
from = ModelIn.new
from.name = "TestName"
env_out = RGen::Environment.new
t = MyTransformer.new(:env_in, env_out)
assert t.trans(from).is_a?(ModelOut)
assert_equal "TestName", t.trans(from).name
assert_equal 1, env_out.elements.size
assert_equal env_out.elements.first, t.trans(from)
assert_equal 1, t.modelInTrans_count
end
def test_transformer_chain
from = ModelIn.new
from.name = "Test1"
from2 = ModelIn.new
from2.name = "Test2"
from3 = ModelIn.new
from3.name = "Test3"
env_out = RGen::Environment.new
elementMap = {}
t1 = MyTransformer.new(:env_in, env_out, elementMap)
assert t1.trans(from).is_a?(ModelOut)
assert_equal "Test1", t1.trans(from).name
assert_equal 1, t1.modelInTrans_count
# modifying the element map means that following calls of +trans+ will be affected
assert_equal( {from => t1.trans(from)}, elementMap )
elementMap.merge!({from2 => :dummy})
assert_equal :dummy, t1.trans(from2)
# second transformer based on the element map of the first
t2 = MyTransformer.new(:env_in, env_out, elementMap)
# second transformer returns same objects
assert_equal t1.trans(from).object_id, t2.trans(from).object_id
assert_equal :dummy, t2.trans(from2)
# and no transformer rule is evaluated at this point
assert_equal nil, t2.modelInTrans_count
# now transform a new object in second transformer
assert t2.trans(from3).is_a?(ModelOut)
assert_equal "Test3", t2.trans(from3).name
assert_equal 1, t2.modelInTrans_count
# the first transformer returns the same object without evaluation of a transformer rule
assert_equal t1.trans(from3).object_id, t2.trans(from3).object_id
assert_equal 1, t1.modelInTrans_count
end
def test_transformer_subclass
from = ModelInSub.new
from.name = "TestName"
t = MyTransformer.new
assert t.trans(from).is_a?(ModelOut)
assert_equal "TestName", t.trans(from).name
assert_equal 1, t.modelInTrans_count
end
def test_transformer_array
froms = [ModelIn.new, ModelIn.new]
froms[0].name = "M1"
froms[1].name = "M2"
env_out = RGen::Environment.new
t = MyTransformer.new(:env_in, env_out)
assert t.trans(froms).is_a?(Array)
assert t.trans(froms)[0].is_a?(ModelOut)
assert_equal "M1", t.trans(froms)[0].name
assert t.trans(froms)[1].is_a?(ModelOut)
assert_equal "M2", t.trans(froms)[1].name
assert_equal 2, env_out.elements.size
assert (t.trans(froms)-env_out.elements).empty?
assert_equal 2, t.modelInTrans_count
end
def test_transformer_cyclic
# setup a cyclic dependency between fromA and fromB
fromA = ModelAIn.new
fromB = ModelBIn.new
fromA.modelB = fromB
fromA.name = "ModelA"
fromB.modelA = fromA
fromB.name = "ModelB"
env_out = RGen::Environment.new
t = MyTransformer.new(:env_in, env_out)
# check that trans resolves the cycle correctly (no endless loop)
# both elements, fromA and fromB will be transformed with the transformation
# of the first element, either fromA or fromB
assert t.trans(fromA).is_a?(ModelAOut)
assert_equal "ModelA", t.trans(fromA).name
assert t.trans(fromA).modelB.is_a?(ModelBOut)
assert_equal "ModelB", t.trans(fromA).modelB.name
assert_equal t.trans(fromA), t.trans(fromA).modelB.modelA
assert_equal t.trans(fromB), t.trans(fromA).modelB
assert_equal 2, env_out.elements.size
assert (env_out.elements - [t.trans(fromA), t.trans(fromB)]).empty?
assert_equal 1, t.modelAInTrans_count
assert_equal 1, t.modelBInTrans_count
end
def test_transformer_conditional
froms = [ModelCIn.new, ModelCIn.new, ModelCIn.new]
froms[0].number = 100
froms[1].number = 1000
froms[2].number = 2000
env_out = RGen::Environment.new
t = MyTransformer.new(:env_in, env_out)
assert t.trans(froms).is_a?(Array)
assert_equal 2, t.trans(froms).size
# this one matched the smallNumber rule
assert t.trans(froms[0]).is_a?(ModelCOut)
assert_equal 50, t.trans(froms[0]).number
# this one did not match any rule
assert t.trans(froms[1]).nil?
# this one matched the largeNumber rule
assert t.trans(froms[2]).is_a?(ModelCOut)
assert_equal 4000, t.trans(froms[2]).number
# elements in environment are the same as the ones returned
assert_equal 2, env_out.elements.size
assert (t.trans(froms)-env_out.elements).empty?
end
class CopyTransformer < RGen::Transformer
include UML13
def transform
trans(:class => UML13::Package)
end
UML13.ecore.eClassifiers.each do |c|
copy c.instanceClass
end
end
MODEL_DIR = File.join(File.dirname(__FILE__),"testmodel")
include Testmodel::ClassModelChecker
include RGen::Util::ModelComparator
def test_copyTransformer
envIn = RGen::Environment.new
envOut = RGen::Environment.new
EASupport.instantiateUML13FromXMI11(envIn, MODEL_DIR+"/ea_testmodel.xml")
CopyTransformer.new(envIn, envOut).transform
checkClassModel(envOut)
assert modelEqual?(
envIn.find(:class => UML13::Model).first,
envOut.find(:class => UML13::Model).first)
end
end
rgen-0.7.0/test/util_test.rb 0000644 0000041 0000041 00000000160 12352210062 016007 0 ustar www-data www-data $:.unshift File.dirname(__FILE__)
require 'util/file_cache_map_test'
require 'util/pattern_matcher_test'
rgen-0.7.0/test/template_language_test/ 0000755 0000041 0000041 00000000000 12352210062 020166 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/expected_result3.txt 0000644 0000041 0000041 00000000230 12352210062 024204 0 ustar www-data www-data This file was created on Linux and does not contain \r before \n
The next blank line is done by the "nl" command which shall only add a \n, no \r:
END
rgen-0.7.0/test/template_language_test/indentStringTestTabIndent.out 0000644 0000041 0000041 00000000011 12352210062 026010 0 ustar www-data www-data <- tab
rgen-0.7.0/test/template_language_test/expected_result2.txt 0000644 0000041 0000041 00000000132 12352210062 024204 0 ustar www-data www-data int myArray[5] = {
1,
2,
3,
4,
5
};
Text from Root
Text from Root
rgen-0.7.0/test/template_language_test/indentStringTestDefaultIndent.out 0000644 0000041 0000041 00000000030 12352210062 026667 0 ustar www-data www-data <- your default here
rgen-0.7.0/test/template_language_test/templates/ 0000755 0000041 0000041 00000000000 12352210062 022164 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/root.tpl 0000644 0000041 0000041 00000001524 12352210062 023672 0 ustar www-data www-data <% define 'Root' do %>
<% file 'testout.txt' do %>
Document: <%= title %>
<%nl%>
<%iinc%>
by <% expand 'content/author::Author', :foreach => authors, :separator => ' and ' %>
<%idec%>
<%nl%>
Index:<%iinc%>
<% for c in chapters %>
<% nr = (nr || 0); nr += 1 %>
<% expand 'index/chapter::Root', nr, this, :for => c %>
<% end %><%idec%>
<%nl%>
----------------
<%nl%>
Chapters in one line:
<% expand 'content/chapter::Root', :foreach => chapters, :separator => ", " %><%nl%>
<%nl%>
Chapters each in one line:
<% expand 'content/chapter::Root', :foreach => chapters, :separator => ",\r\n" %><%nl%>
<%nl%>
Here are some code examples:
<% expand 'code/array::ArrayDefinition', :for => sampleArray %>
<% end %>
<% end %>
<% define 'TextFromRoot' do %>
Text from Root
<% end %>
rgen-0.7.0/test/template_language_test/templates/indent_string_test.tpl 0000644 0000041 0000041 00000000421 12352210062 026610 0 ustar www-data www-data <% define 'IndentStringTest', :for => Object do %>
<% file 'indentStringTestDefaultIndent.out' do %>
<%iinc%>
<- your default here
<%idec%>
<% end %>
<% file 'indentStringTestTabIndent.out', "\t" do %>
<%iinc%>
<- tab
<%idec%>
<% end %>
<% end %> rgen-0.7.0/test/template_language_test/templates/no_indent_test/ 0000755 0000041 0000041 00000000000 12352210062 025200 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/no_indent_test/sub1/ 0000755 0000041 0000041 00000000000 12352210062 026052 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/no_indent_test/sub1/no_indent.tpl 0000644 0000041 0000041 00000000106 12352210062 030545 0 ustar www-data www-data <% define 'NoIndent', :for => Object do %>
<---<%nows%>
<% end %>
rgen-0.7.0/test/template_language_test/templates/no_indent_test/test.tpl 0000644 0000041 0000041 00000001042 12352210062 026675 0 ustar www-data www-data <% define 'Test', :for => Object do %>
<%iinc%>
xxx<% expand 'NoIndent1' %>
xxx<% expand 'NoIndent2' %>
xxx<% expand 'NoIndent3' %>
xxx<% expand 'NoIndent4' %>
<%idec%>
<% end %>
<% define 'NoIndent1', :for => Object do %>
<---<%nows%>
<% end %>
<% define 'NoIndent2', :for => Object do %>
<% expand 'NoIndent1' %>
<% end %>
<% define 'NoIndent3', :for => Object do %>
<% expand 'no_indent::NoIndent' %>
<% end %>
<% define 'NoIndent4', :for => Object do %>
<% expand 'sub1/no_indent::NoIndent' %>
<% end %>
rgen-0.7.0/test/template_language_test/templates/no_indent_test/test3.tpl 0000644 0000041 0000041 00000000242 12352210062 026761 0 ustar www-data www-data <% define 'Test', :for => Object do %>
<%iinc%>
l1<% expand 'Call1' %>
<%idec%>
<% end %>
<% define 'Call1', :for => Object do %>
<---
l2
<% end %>
rgen-0.7.0/test/template_language_test/templates/no_indent_test/no_indent.tpl 0000644 0000041 0000041 00000000106 12352210062 027673 0 ustar www-data www-data <% define 'NoIndent', :for => Object do %>
<---<%nows%>
<% end %>
rgen-0.7.0/test/template_language_test/templates/no_indent_test/test2.tpl 0000644 0000041 0000041 00000000415 12352210062 026762 0 ustar www-data www-data <% define 'Test', :for => Object do %>
<%iinc%><%iinc%>
return <% expand 'Call1' %>;
<%idec%><%idec%>
<% end %>
<% define 'Call1', :for => Object do %>
x<% expand 'Call2' %><%nows%>
<% end %>
<% define 'Call2', :for => Object do %>
xxx<%nows%>
<% end %> rgen-0.7.0/test/template_language_test/templates/no_backslash_r_test.tpl 0000644 0000041 0000041 00000000315 12352210062 026713 0 ustar www-data www-data <% define 'Test', :for => Object do %>
This file was created on Linux and does not contain \r before \n
The next blank line is done by the "nl" command which shall only add a \n, no \r:
<%nl%>END
<% end %> rgen-0.7.0/test/template_language_test/templates/index/ 0000755 0000041 0000041 00000000000 12352210062 023273 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/index/c/ 0000755 0000041 0000041 00000000000 12352210062 023515 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/index/c/cmod.tpl 0000644 0000041 0000041 00000000064 12352210062 025160 0 ustar www-data www-data <% define 'cmod' do %>Module C is special !<% end %> rgen-0.7.0/test/template_language_test/templates/index/chapter.tpl 0000644 0000041 0000041 00000000131 12352210062 025435 0 ustar www-data www-data <% define 'Root' do |idx, doc| %>
<%= idx%> <%= title %> in <%= doc.title %>
<% end %> rgen-0.7.0/test/template_language_test/templates/define_local_test/ 0000755 0000041 0000041 00000000000 12352210062 025627 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/define_local_test/local.tpl 0000644 0000041 0000041 00000000231 12352210062 027436 0 ustar www-data www-data <% define 'CallLocal1', :for => Object do %>
<% expand 'Local1' %>
<% end %>
<% define_local 'Local1', :for => Object do %>
Local1
<% end %>
rgen-0.7.0/test/template_language_test/templates/define_local_test/test.tpl 0000644 0000041 0000041 00000000264 12352210062 027331 0 ustar www-data www-data <% define 'Test', :for => Object do %>
<% expand 'local::CallLocal1' %>
<% end %>
<% define 'TestForbidden', :for => Object do %>
<% expand 'local::Local1' %>
<% end %>
rgen-0.7.0/test/template_language_test/templates/template_resolution_test/ 0000755 0000041 0000041 00000000000 12352210062 027321 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/template_resolution_test/sub1.tpl 0000644 0000041 0000041 00000000302 12352210062 030707 0 ustar www-data www-data <% define 'Sub1', :for => Object do %>
Sub1
<% end %>
<% define 'Test', :for => Object do %>
<% expand 'Sub1' %>
<% expand 'sub1::Sub1' %>
<% expand 'sub1/sub1::Sub1' %>
<% end %>
rgen-0.7.0/test/template_language_test/templates/template_resolution_test/sub1/ 0000755 0000041 0000041 00000000000 12352210062 030173 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/template_resolution_test/sub1/sub1.tpl 0000644 0000041 0000041 00000000100 12352210062 031555 0 ustar www-data www-data <% define 'Sub1', :for => Object do %>
Sub1 in sub1
<% end %> rgen-0.7.0/test/template_language_test/templates/template_resolution_test/test.tpl 0000644 0000041 0000041 00000000156 12352210062 031023 0 ustar www-data www-data <% define 'Test', :for => Object do %>
<% expand 'sub1::Sub1' %>
<% expand 'sub1/sub1::Sub1' %>
<% end %> rgen-0.7.0/test/template_language_test/templates/code/ 0000755 0000041 0000041 00000000000 12352210062 023076 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/code/array.tpl 0000644 0000041 0000041 00000000601 12352210062 024732 0 ustar www-data www-data <% define 'ArrayDefinition', :for => CArray do %>
<%= getType %> <%= name %>[<%= size %>] = {<%iinc%>
<% expand 'InitValue', :foreach => initvalue, :separator => ",\r\n" %><%nl%><%idec%>
};
<% expand '../root::TextFromRoot' %>
<% expand '/root::TextFromRoot' %>
<% end %>
<% define 'InitValue', :for => PrimitiveInitValue do %>
<%= value %><%nows%>
<% end %>
rgen-0.7.0/test/template_language_test/templates/content/ 0000755 0000041 0000041 00000000000 12352210062 023636 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/content/chapter.tpl 0000644 0000041 0000041 00000000126 12352210062 026004 0 ustar www-data www-data <% define 'Root', :for => Chapter do %>
*** <%= title %> ***<%nows%>
<% end %> rgen-0.7.0/test/template_language_test/templates/content/author.tpl 0000644 0000041 0000041 00000000305 12352210062 025657 0 ustar www-data www-data <% define 'Author', :for => Author do %>
<% expand 'SubAuthor' %>
<% end %>
<% define 'SubAuthor', :for => Author do %>
<%= name %>, EMail: <%= email.sub('@','(at)') %><%nows%>
<% end %>
rgen-0.7.0/test/template_language_test/templates/null_context_test.tpl 0000644 0000041 0000041 00000000712 12352210062 026462 0 ustar www-data www-data <% define 'NullContextTestBad', :for => Object do %>
<%# this must raise an exception %>
<% expand 'Callee', :for => nil %>
<% end %>
<% define 'NullContextTestBad2', :for => Object do %>
<%# this must raise an exception %>
<% expand 'Callee', :foreach => nil %>
<% end %>
<% define 'NullContextTestOk', :for => Object do %>
<%# however this is ok %>
<% expand 'Callee' %>
<% end %>
<% define 'Callee', :for => Object do %>
<% end %> rgen-0.7.0/test/template_language_test/templates/evaluate_test/ 0000755 0000041 0000041 00000000000 12352210062 025031 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/evaluate_test/test.tpl 0000644 0000041 0000041 00000000302 12352210062 026524 0 ustar www-data www-data <% define 'Test', :for => Object do %>
<%= [1,2,3,4].collect{|n| evaluate 'Eval', :for => n}.join %>
<% end %>
<% define 'Eval', :for => Object do %>
xx<%= this %>xx<%nows%>
<% end %>
rgen-0.7.0/test/template_language_test/templates/callback_indent_test/ 0000755 0000041 0000041 00000000000 12352210062 026320 5 ustar www-data www-data rgen-0.7.0/test/template_language_test/templates/callback_indent_test/a.tpl 0000644 0000041 0000041 00000000343 12352210062 027261 0 ustar www-data www-data <% define 'caller', :for => Object do %>
|before callback
<% expand 'b::do_callback' %>
|after callback
<%iinc%>
|after iinc
<% end %>
<% define 'callback', :for => Object do %>
|in callback
<% end %>
rgen-0.7.0/test/template_language_test/templates/callback_indent_test/b.tpl 0000644 0000041 0000041 00000000161 12352210062 027260 0 ustar www-data www-data <% define 'do_callback', :for => Object do %>
<%iinc%>
<% expand 'a::callback' %>
<%idec%>
<% end %>
rgen-0.7.0/test/template_language_test/testout.txt 0000644 0000041 0000041 00000001105 12352210062 022433 0 ustar www-data www-data Document: SomeDocument
by Martin, EMail: martin(at)somewhe.re and Otherguy, EMail: other(at)somewhereel.se
Index:
1 Intro in SomeDocument
2 MainPart in SomeDocument
3 Summary in SomeDocument
----------------
Chapters in one line:
*** Intro ***, *** MainPart ***, *** Summary ***
Chapters each in one line:
*** Intro ***,
*** MainPart ***,
*** Summary ***
Here are some code examples:
int myArray[5] = {
1,
2,
3,
4,
5
};
Text from Root
Text from Root
rgen-0.7.0/test/template_language_test/expected_result1.txt 0000644 0000041 0000041 00000001105 12352210062 024204 0 ustar www-data www-data Document: SomeDocument
by Martin, EMail: martin(at)somewhe.re and Otherguy, EMail: other(at)somewhereel.se
Index:
1 Intro in SomeDocument
2 MainPart in SomeDocument
3 Summary in SomeDocument
----------------
Chapters in one line:
*** Intro ***, *** MainPart ***, *** Summary ***
Chapters each in one line:
*** Intro ***,
*** MainPart ***,
*** Summary ***
Here are some code examples:
int myArray[5] = {
1,
2,
3,
4,
5
};
Text from Root
Text from Root
rgen-0.7.0/test/rgen_test.rb 0000644 0000041 0000041 00000001331 12352210062 015766 0 ustar www-data www-data $:.unshift File.dirname(__FILE__)
require 'test/unit'
require 'array_extensions_test'
require 'ea_instantiator_test'
require 'ecore_self_test'
require 'environment_test'
require 'metamodel_builder_test'
require 'metamodel_roundtrip_test'
require 'output_handler_test'
require 'template_language_test'
require 'transformer_test'
require 'xml_instantiator_test'
require 'ea_serializer_test'
require 'model_builder_test'
require 'method_delegation_test'
require 'json_test'
require 'reference_resolver_test'
require 'qualified_name_resolver_test'
require 'metamodel_order_test'
require 'metamodel_from_ecore_test'
require 'util_test'
require 'model_fragment_test'
require 'qualified_name_provider_test'
rgen-0.7.0/test/model_builder_test.rb 0000644 0000041 0000041 00000000337 12352210062 017646 0 ustar www-data www-data $:.unshift File.dirname(__FILE__) + "/../lib"
require 'model_builder/builder_test'
require 'model_builder/serializer_test'
require 'model_builder/builder_context_test'
require 'model_builder/reference_resolver_test'
rgen-0.7.0/test/metamodel_roundtrip_test.rb 0000644 0000041 0000041 00000006706 12352210062 021123 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/array_extensions'
require 'rgen/util/model_comparator'
require 'mmgen/metamodel_generator'
require 'rgen/instantiator/ecore_xml_instantiator'
require 'rgen/serializer/xmi20_serializer'
class MetamodelRoundtripTest < Test::Unit::TestCase
TEST_DIR = File.dirname(__FILE__)+"/metamodel_roundtrip_test"
include MMGen::MetamodelGenerator
include RGen::Util::ModelComparator
module Regenerated
Inside = binding
end
def test_generator
require TEST_DIR+"/TestModel.rb"
outfile = TEST_DIR+"/TestModel_Regenerated.rb"
generateMetamodel(HouseMetamodel.ecore, outfile)
File.open(outfile) do |f|
eval(f.read, Regenerated::Inside)
end
assert modelEqual?(HouseMetamodel.ecore, Regenerated::HouseMetamodel.ecore, ["instanceClassName"])
end
module UMLRegenerated
Inside = binding
end
def test_generate_from_ecore
outfile = TEST_DIR+"/houseMetamodel_from_ecore.rb"
env = RGen::Environment.new
File.open(TEST_DIR+"/houseMetamodel.ecore") { |f|
ECoreXMLInstantiator.new(env).instantiate(f.read)
}
rootpackage = env.find(:class => RGen::ECore::EPackage).first
rootpackage.name = "HouseMetamodel"
generateMetamodel(rootpackage, outfile)
File.open(outfile) do |f|
eval(f.read, UMLRegenerated::Inside, "test_eval", 0)
end
end
def test_ecore_serializer
require TEST_DIR+"/TestModel.rb"
File.open(TEST_DIR+"/houseMetamodel_Regenerated.ecore","w") do |f|
ser = RGen::Serializer::XMI20Serializer.new(f)
ser.serialize(HouseMetamodel.ecore)
end
end
BuiltinTypesTestEcore = TEST_DIR+"/using_builtin_types.ecore"
def test_ecore_serializer_builtin_types
mm = RGen::ECore::EPackage.new(:name => "P1", :eClassifiers => [
RGen::ECore::EClass.new(:name => "C1", :eStructuralFeatures => [
RGen::ECore::EAttribute.new(:name => "a1", :eType => RGen::ECore::EString),
RGen::ECore::EAttribute.new(:name => "a2", :eType => RGen::ECore::EInt),
RGen::ECore::EAttribute.new(:name => "a3", :eType => RGen::ECore::ELong),
RGen::ECore::EAttribute.new(:name => "a4", :eType => RGen::ECore::EFloat),
RGen::ECore::EAttribute.new(:name => "a5", :eType => RGen::ECore::EBoolean)
])
])
outfile = TEST_DIR+"/using_builtin_types_serialized.ecore"
File.open(outfile, "w") do |f|
ser = RGen::Serializer::XMI20Serializer.new(f)
ser.serialize(mm)
end
assert_equal(File.read(BuiltinTypesTestEcore), File.read(outfile))
end
def test_ecore_instantiator_builtin_types
env = RGen::Environment.new
File.open(BuiltinTypesTestEcore) { |f|
ECoreXMLInstantiator.new(env).instantiate(f.read)
}
a1 = env.find(:class => RGen::ECore::EAttribute, :name => "a1").first
assert_equal(RGen::ECore::EString, a1.eType)
a2 = env.find(:class => RGen::ECore::EAttribute, :name => "a2").first
assert_equal(RGen::ECore::EInt, a2.eType)
a3 = env.find(:class => RGen::ECore::EAttribute, :name => "a3").first
assert_equal(RGen::ECore::ELong, a3.eType)
a4 = env.find(:class => RGen::ECore::EAttribute, :name => "a4").first
assert_equal(RGen::ECore::EFloat, a4.eType)
a5 = env.find(:class => RGen::ECore::EAttribute, :name => "a5").first
assert_equal(RGen::ECore::EBoolean, a5.eType)
end
end
rgen-0.7.0/test/metamodel_roundtrip_test/ 0000755 0000041 0000041 00000000000 12352210062 020565 5 ustar www-data www-data rgen-0.7.0/test/metamodel_roundtrip_test/houseMetamodel.ecore 0000644 0000041 0000041 00000004564 12352210062 024570 0 ustar www-data www-data
rgen-0.7.0/test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb 0000644 0000041 0000041 00000002514 12352210062 026267 0 ustar www-data www-data require 'rgen/metamodel_builder'
module HouseMetamodel
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
SexEnum = Enum.new(:name => 'SexEnum', :literals =>[ :male, :female ])
class House < RGen::MetamodelBuilder::MMBase
annotation :source => "bla", :details => {'a' => 'b'}
has_attr 'address', String, :changeable => false
end
class MeetingPlace < RGen::MetamodelBuilder::MMBase
end
class Person < RGen::MetamodelBuilder::MMBase
has_attr 'sex', HouseMetamodel::SexEnum
has_attr 'id', Long
has_many_attr 'nicknames', String
end
module Rooms
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
class Room < RGen::MetamodelBuilder::MMBase
end
class Bathroom < Room
end
class Kitchen < RGen::MetamodelBuilder::MMMultiple(Room, HouseMetamodel::MeetingPlace)
end
end
end
HouseMetamodel::House.has_one 'bathroom', HouseMetamodel::Rooms::Bathroom, :lowerBound => 1
HouseMetamodel::House.one_to_one 'kitchen', HouseMetamodel::Rooms::Kitchen, 'house', :lowerBound => 1
HouseMetamodel::House.contains_many 'room', HouseMetamodel::Rooms::Room, 'house'
HouseMetamodel::Person.has_many 'house', HouseMetamodel::House
rgen-0.7.0/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore 0000644 0000041 0000041 00000037753 12352210062 027103 0 ustar www-data www-data
rgen-0.7.0/test/metamodel_roundtrip_test/TestModel.rb 0000644 0000041 0000041 00000012157 12352210062 023020 0 ustar www-data www-data require 'rgen/metamodel_builder'
module HouseMetamodel
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
SexEnum = Enum.new(:name => "SexEnum", :literals => [ :male, :female ])
# TODO: Datatypes
# AggregationKind = Enum.new([ :none, :aggregate, :composite ])
class MeetingPlace < RGen::MetamodelBuilder::MMBase
annotation :source => "testmodel", :details => { 'complexity' => '1', 'date_created' => '2006-07-12 08:40:46', 'date_modified' => '2006-07-12 08:44:02', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_A1B83D59_CAE1_422c_BA5F_D3624D7156AD', 'package_name' => 'HouseMetamodel', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0' }
end
class Person < RGen::MetamodelBuilder::MMBase
annotation 'complexity' => '1', 'date_created' => '2006-06-27 08:34:23', 'date_modified' => '2006-06-27 08:34:26', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_A1B83D59_CAE1_422c_BA5F_D3624D7156AD', 'package_name' => 'HouseMetamodel', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
has_attr 'sex', SexEnum
has_attr 'id', Long
has_many_attr 'nicknames', String
end
class House < RGen::MetamodelBuilder::MMBase
annotation 'complexity' => '1', 'date_created' => '2005-09-16 19:52:18', 'date_modified' => '2006-02-28 08:29:19', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_A1B83D59_CAE1_422c_BA5F_D3624D7156AD', 'package_name' => 'HouseMetamodel', 'phase' => '1.0', 'status' => 'Proposed', 'stereotype' => 'dummy', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
has_attr 'size', Integer
has_attr 'module'
has_attr 'address', String, :changeable => false do
annotation 'collection' => 'false', 'containment' => 'Not Specified', 'derived' => '0', 'duplicates' => '0', 'ea_guid' => '{A8DF581B-9AC6-4f75-AB48-8FAEDFC6E068}', 'lowerBound' => '1', 'ordered' => '0', 'position' => '0', 'styleex' => 'volatile=0;', 'type' => 'String', 'upperBound' => '1'
end
end
module Rooms
extend RGen::MetamodelBuilder::ModuleExtension
class Room < RGen::MetamodelBuilder::MMBase
abstract
annotation 'complexity' => '1', 'date_created' => '2005-09-16 19:52:28', 'date_modified' => '2006-06-22 21:15:25', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_F9D8C6E3_4DAD_4aa2_AD47_D0ABA4E93E08', 'package_name' => 'Rooms', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
end
class Bathroom < Room
annotation 'complexity' => '1', 'date_created' => '2006-06-27 08:32:25', 'date_modified' => '2006-06-27 08:34:23', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_F9D8C6E3_4DAD_4aa2_AD47_D0ABA4E93E08', 'package_name' => 'Rooms', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
end
class Kitchen < RGen::MetamodelBuilder::MMMultiple(HouseMetamodel::MeetingPlace, Room)
annotation 'complexity' => '1', 'date_created' => '2005-11-30 19:26:13', 'date_modified' => '2006-06-22 21:15:34', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_F9D8C6E3_4DAD_4aa2_AD47_D0ABA4E93E08', 'package_name' => 'Rooms', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
end
end
module DependingOnRooms
extend RGen::MetamodelBuilder::ModuleExtension
class RoomSub < Rooms::Room
end
end
end
HouseMetamodel::Person.has_many 'home', HouseMetamodel::House do
annotation 'containment' => 'Unspecified'
end
HouseMetamodel::House.has_one 'bathroom', HouseMetamodel::Rooms::Bathroom, :lowerBound => 1, :transient => true
HouseMetamodel::House.one_to_one 'kitchen', HouseMetamodel::Rooms::Kitchen, 'house', :lowerBound => 1, :opposite_lowerBound => 1 do
annotation 'containment' => 'Unspecified'
opposite_annotation 'containment' => 'Unspecified'
end
HouseMetamodel::House.contains_many 'room', HouseMetamodel::Rooms::Room, 'house', :lowerBound => 1 do
# only an opposite annotation
opposite_annotation 'containment' => 'Unspecified'
end
rgen-0.7.0/test/metamodel_roundtrip_test/using_builtin_types.ecore 0000644 0000041 0000041 00000003317 12352210062 025707 0 ustar www-data www-data
rgen-0.7.0/test/metamodel_roundtrip_test/TestModel_Regenerated.rb 0000644 0000041 0000041 00000012147 12352210062 025324 0 ustar www-data www-data require 'rgen/metamodel_builder'
module HouseMetamodel
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
SexEnum = Enum.new(:name => 'SexEnum', :literals =>[ :male, :female ])
class MeetingPlace < RGen::MetamodelBuilder::MMBase
annotation :source => "testmodel", :details => {'complexity' => '1', 'date_created' => '2006-07-12 08:40:46', 'date_modified' => '2006-07-12 08:44:02', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_A1B83D59_CAE1_422c_BA5F_D3624D7156AD', 'package_name' => 'HouseMetamodel', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'}
end
class Person < RGen::MetamodelBuilder::MMBase
annotation 'complexity' => '1', 'date_created' => '2006-06-27 08:34:23', 'date_modified' => '2006-06-27 08:34:26', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_A1B83D59_CAE1_422c_BA5F_D3624D7156AD', 'package_name' => 'HouseMetamodel', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
has_attr 'sex', HouseMetamodel::SexEnum
has_attr 'id', Long
has_many_attr 'nicknames', String
end
class House < RGen::MetamodelBuilder::MMBase
annotation 'complexity' => '1', 'date_created' => '2005-09-16 19:52:18', 'date_modified' => '2006-02-28 08:29:19', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_A1B83D59_CAE1_422c_BA5F_D3624D7156AD', 'package_name' => 'HouseMetamodel', 'phase' => '1.0', 'status' => 'Proposed', 'stereotype' => 'dummy', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
has_attr 'size', Integer
has_attr 'module', String
has_attr 'address', String, :changeable => false do
annotation 'collection' => 'false', 'containment' => 'Not Specified', 'derived' => '0', 'duplicates' => '0', 'ea_guid' => '{A8DF581B-9AC6-4f75-AB48-8FAEDFC6E068}', 'lowerBound' => '1', 'ordered' => '0', 'position' => '0', 'styleex' => 'volatile=0;', 'type' => 'String', 'upperBound' => '1'
end
end
module Rooms
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
class Room < RGen::MetamodelBuilder::MMBase
abstract
annotation 'complexity' => '1', 'date_created' => '2005-09-16 19:52:28', 'date_modified' => '2006-06-22 21:15:25', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_F9D8C6E3_4DAD_4aa2_AD47_D0ABA4E93E08', 'package_name' => 'Rooms', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
end
class Bathroom < Room
annotation 'complexity' => '1', 'date_created' => '2006-06-27 08:32:25', 'date_modified' => '2006-06-27 08:34:23', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_F9D8C6E3_4DAD_4aa2_AD47_D0ABA4E93E08', 'package_name' => 'Rooms', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
end
class Kitchen < RGen::MetamodelBuilder::MMMultiple(HouseMetamodel::MeetingPlace, Room)
annotation 'complexity' => '1', 'date_created' => '2005-11-30 19:26:13', 'date_modified' => '2006-06-22 21:15:34', 'ea_ntype' => '0', 'ea_stype' => 'Class', 'gentype' => 'Java', 'isSpecification' => 'false', 'package' => 'EAPK_F9D8C6E3_4DAD_4aa2_AD47_D0ABA4E93E08', 'package_name' => 'Rooms', 'phase' => '1.0', 'status' => 'Proposed', 'style' => 'BackColor=-1;BorderColor=-1;BorderWidth=-1;FontColor=-1;VSwimLanes=0;HSwimLanes=0;BorderStyle=0;', 'tagged' => '0', 'version' => '1.0'
end
end
module DependingOnRooms
extend RGen::MetamodelBuilder::ModuleExtension
include RGen::MetamodelBuilder::DataTypes
class RoomSub < HouseMetamodel::Rooms::Room
end
end
end
HouseMetamodel::Person.has_many 'home', HouseMetamodel::House do
annotation 'containment' => 'Unspecified'
end
HouseMetamodel::House.has_one 'bathroom', HouseMetamodel::Rooms::Bathroom, :lowerBound => 1, :transient => true
HouseMetamodel::House.one_to_one 'kitchen', HouseMetamodel::Rooms::Kitchen, 'house', :lowerBound => 1, :opposite_lowerBound => 1 do
annotation 'containment' => 'Unspecified'
opposite_annotation 'containment' => 'Unspecified'
end
HouseMetamodel::House.contains_many 'room', HouseMetamodel::Rooms::Room, 'house', :lowerBound => 1 do
opposite_annotation 'containment' => 'Unspecified'
end
rgen-0.7.0/test/metamodel_roundtrip_test/using_builtin_types_serialized.ecore 0000644 0000041 0000041 00000003330 12352210062 030115 0 ustar www-data www-data
rgen-0.7.0/test/method_delegation_test.rb 0000644 0000041 0000041 00000013170 12352210062 020512 0 ustar www-data www-data $:.unshift File.dirname(__FILE__) + "/../lib"
require 'test/unit'
require 'rgen/util/method_delegation'
class MethodDelegationTest < Test::Unit::TestCase
include RGen
class TestDelegate
attr_accessor :mode, :callcount
def common_delegated(delegator)
@callcount ||= 0
@callcount += 1
case @mode
when :continue
throw :continue
when :delegatorId
delegator.object_id
when :return7
7
end
end
alias to_s_delegated common_delegated
alias methodInSingleton_delegated common_delegated
alias class_delegated common_delegated
alias artificialMethod_delegated common_delegated
end
class ConstPathElement < Module
def self.const_missing_delegated(delegator, const)
ConstPathElement.new(const)
end
def initialize(name, parent=nil)
@name = name.to_s
@parent = parent
end
def const_missing(const)
ConstPathElement.new(const, self)
end
def to_s
if @parent
@parent.to_s+"::"+@name
else
@name
end
end
end
# missing: check with multiple params and block param
def test_method_defined_in_singleton
# delegator is an Array
delegator = []
# delegating method is a method defined in the singleton class
class << delegator
def methodInSingleton
"result from method in singleton"
end
end
checkDelegation(delegator, "methodInSingleton", "result from method in singleton")
end
def test_method_defined_in_class
# delegator is a String
delegator = "Delegator1"
checkDelegation(delegator, "to_s", "Delegator1")
end
def test_method_defined_in_superclass
# delegator is an instance of a new anonymous class
delegator = Class.new.new
# delegating method is +object_id+ which is defined in the superclass
checkDelegation(delegator, "class", delegator.class)
end
def test_new_method
# delegator is an String
delegator = "Delegator2"
# delegating method is a new method which does not exist on String
checkDelegation(delegator, "artificialMethod", delegator.object_id, true)
end
def test_const_missing
surroundingModule = Module.nesting.first
Util::MethodDelegation.registerDelegate(ConstPathElement, surroundingModule, "const_missing")
assert_equal "SomeArbitraryConst", SomeArbitraryConst.to_s
assert_equal "AnotherConst::A::B::C", AnotherConst::A::B::C.to_s
Util::MethodDelegation.unregisterDelegate(ConstPathElement, surroundingModule, "const_missing")
assert_raise NameError do
SomeArbitraryConst
end
end
def checkDelegation(delegator, method, originalResult, newMethod=false)
delegate1 = TestDelegate.new
delegate2 = TestDelegate.new
Util::MethodDelegation.registerDelegate(delegate1, delegator, method)
Util::MethodDelegation.registerDelegate(delegate2, delegator, method)
assert delegator.respond_to?(:_methodDelegates)
if newMethod
assert !delegator.respond_to?("#{method}_delegate_original".to_sym)
else
assert delegator.respond_to?("#{method}_delegate_original".to_sym)
end
# check delegator parameter
delegate1.mode = :delegatorId
assert_equal delegator.object_id, delegator.send(method)
delegate1.callcount = 0
delegate2.callcount = 0
delegate1.mode = :return7
# delegate1 returns a value
assert_equal 7, delegator.send(method)
assert_equal 1, delegate1.callcount
# delegate2 is not called
assert_equal 0, delegate2.callcount
delegate1.mode = :nothing
# delegate1 just exits and thus returns nil
assert_equal nil, delegator.send(method)
assert_equal 2, delegate1.callcount
# delegate2 is not called
assert_equal 0, delegate2.callcount
delegate1.mode = :continue
delegate2.mode = :return7
# delegate1 is called but continues
# delegate2 returns a value
assert_equal 7, delegator.send(method)
assert_equal 3, delegate1.callcount
assert_equal 1, delegate2.callcount
delegate1.mode = :continue
delegate2.mode = :continue
# both delegates continue, the original method returns its value
checkCallOriginal(delegator, method, originalResult, newMethod)
# both delegates are called though
assert_equal 4, delegate1.callcount
assert_equal 2, delegate2.callcount
# calling unregister with a non existing method has no effect
Util::MethodDelegation.unregisterDelegate(delegate1, delegator, "xxx")
Util::MethodDelegation.unregisterDelegate(delegate1, delegator, method)
checkCallOriginal(delegator, method, originalResult, newMethod)
# delegate1 not called any more
assert_equal 4, delegate1.callcount
# delegate2 is still called
assert_equal 3, delegate2.callcount
Util::MethodDelegation.unregisterDelegate(delegate2, delegator, method)
checkCallOriginal(delegator, method, originalResult, newMethod)
# both delegates not called any more
assert_equal 4, delegate1.callcount
assert_equal 3, delegate2.callcount
# after all delegates were unregistered, singleton class should be clean
assert !delegator.respond_to?(:_methodDelegates)
end
def checkCallOriginal(delegator, method, originalResult, newMethod)
if newMethod
assert_raise NoMethodError do
result = delegator.send(method)
end
else
result = delegator.send(method)
assert_equal originalResult, result
end
end
end
rgen-0.7.0/test/xml_instantiator_test/ 0000755 0000041 0000041 00000000000 12352210062 020107 5 ustar www-data www-data rgen-0.7.0/test/xml_instantiator_test/simple_xmi_ecore_instantiator.rb 0000644 0000041 0000041 00000003320 12352210062 026554 0 ustar www-data www-data require 'rgen/instantiator/default_xml_instantiator'
require 'rgen/environment'
require 'rgen/ecore/ecore'
require 'xml_instantiator_test/simple_xmi_metamodel'
# SimpleXMIECoreInstantiator demonstrates the usage of the DefaultXMLInstantiator.
# It can be used to instantiate an ECore model from an XMI description
# produced by Enterprise Architect.
#
# Note however, that this is *not* the recommended way to read an EA model.
# See EAInstantiatorTest for the clean way to do this.
#
# This example shows how arbitrary XML content can be used to instantiate
# an implicit metamodel. The resulting model is transformed into a simple
# ECore model.
#
# See XMLInstantiatorTest for an example of how to use this class.
#
class SimpleXMIECoreInstantiator < RGen::Instantiator::DefaultXMLInstantiator
map_tag_ns "omg.org/UML1.3", SimpleXMIMetaModel::UML
resolve_by_id :typeClass, :src => :type, :id => :xmi_id
resolve_by_id :subtypeClass, :src => :subtype, :id => :xmi_id
resolve_by_id :supertypeClass, :src => :supertype, :id => :xmi_id
def initialize
@envXMI = RGen::Environment.new
super(@envXMI, SimpleXMIMetaModel, true)
end
def new_object(node)
if node.tag == "EAStub"
class_name = saneClassName(node.attributes["UMLType"])
mod = XMIMetaModel::UML
build_on_error(NameError, :build_class, class_name, mod) do
mod.const_get(class_name).new
end
else
super
end
end
# This method does the actual work.
def instantiateECoreModel(envOut, str)
instantiate(str)
require 'xml_instantiator_test/simple_xmi_to_ecore'
SimpleXmiToECore.new(@envXMI,envOut).transform
end
end
rgen-0.7.0/test/xml_instantiator_test/simple_xmi_to_ecore.rb 0000644 0000041 0000041 00000005673 12352210062 024474 0 ustar www-data www-data require 'rgen/transformer'
require 'rgen/ecore/ecore'
require 'rgen/array_extensions'
require 'xml_instantiator_test/simple_xmi_metamodel'
class SimpleXmiToECore < RGen::Transformer
include RGen::ECore
class MapHelper
def initialize(keyMethod,valueMethod,elements)
@keyMethod, @valueMethod, @elements = keyMethod, valueMethod, elements
end
def [](key)
return @elements.select{|e| e.send(@keyMethod) == key}.first.send(@valueMethod) rescue NoMethodError
nil
end
end
class TaggedValueHelper < MapHelper
def initialize(element)
super('tag','value',element.modelElement_taggedValue.taggedValue)
end
end
# Do the actual transformation.
# Input and output environment have to be provided to the transformer constructor.
def transform
trans(:class => SimpleXMIMetaModel::UML::Clazz)
end
transform SimpleXMIMetaModel::UML::Package, :to => EPackage do
{ :name => name,
:eSuperPackage => trans(parent.parent.is_a?(SimpleXMIMetaModel::UML::Package) ? parent.parent : nil) }
end
transform SimpleXMIMetaModel::UML::Clazz, :to => EClass do
{ :name => name,
:ePackage => trans(parent.parent.is_a?(SimpleXMIMetaModel::UML::Package) ? parent.parent : nil),
:eStructuralFeatures => trans(classifier_feature.attribute + associationEnds),
:eOperations => trans(classifier_feature.operation),
:eSuperTypes => trans(generalizationsAsSubtype.supertypeClass),
:eAnnotations => [ EAnnotation.new(:details => trans(modelElement_taggedValue.taggedValue)) ] }
end
transform SimpleXMIMetaModel::UML::TaggedValue, :to => EStringToStringMapEntry do
{ :key => tag, :value => value}
end
transform SimpleXMIMetaModel::UML::Attribute, :to => EAttribute do
typemap = { "String" => EString, "boolean" => EBoolean, "int" => EInt, "long" => ELong, "float" => EFloat }
tv = TaggedValueHelper.new(@current_object)
{ :name => name, :eType => typemap[tv['type']],
:eAnnotations => [ EAnnotation.new(:details => trans(modelElement_taggedValue.taggedValue)) ] }
end
transform SimpleXMIMetaModel::UML::Operation, :to => EOperation do
{ :name => name }
end
transform SimpleXMIMetaModel::UML::AssociationEnd, :to => EReference, :if => :isReference do
{ :eType => trans(otherEnd.typeClass),
:name => otherEnd.name,
:eOpposite => trans(otherEnd),
:lowerBound => (otherEnd.multiplicity || '0').split('..').first.to_i,
:upperBound => (otherEnd.multiplicity || '1').split('..').last.gsub('*','-1').to_i,
:containment => (aggregation == 'composite'),
:eAnnotations => [ EAnnotation.new(:details => trans(modelElement_taggedValue.taggedValue)) ] }
end
method :isReference do
otherEnd.isNavigable == 'true' ||
# composite assocations are bidirectional
aggregation == 'composite' || otherEnd.aggregation == 'composite'
end
end
rgen-0.7.0/test/xml_instantiator_test/simple_ecore_model_checker.rb 0000644 0000041 0000041 00000010114 12352210062 025743 0 ustar www-data www-data require 'rgen/ecore/ecore'
# This "light" version of the ECore model checker is used to check the
# model produced by the XMLInstantiatorTest only.
#
module SimpleECoreModelChecker
include RGen::ECore
def checkECoreModel(env)
# check main package
mainPackage = env.elements.select {|e| e.is_a? EPackage and e.name == "HouseMetamodel"}.first
assert_not_nil mainPackage
# check Rooms package
assert mainPackage.eSubpackages.is_a?(Array)
assert_equal 1, mainPackage.eSubpackages.size
assert mainPackage.eSubpackages[0].is_a?(EPackage)
roomsPackage = mainPackage.eSubpackages[0]
assert_equal "Rooms", roomsPackage.name
# check main package classes
assert mainPackage.eClassifiers.is_a?(Array)
assert_equal 3, mainPackage.eClassifiers.size
assert mainPackage.eClassifiers.all?{|c| c.is_a?(EClass)}
houseClass = mainPackage.eClassifiers.select{|c| c.name == "House"}.first
personClass = mainPackage.eClassifiers.select{|c| c.name == "Person"}.first
meetingPlaceClass = mainPackage.eClassifiers.select{|c| c.name == "MeetingPlace"}.first
assert_not_nil houseClass
assert_not_nil personClass
assert_not_nil meetingPlaceClass
# check Rooms package classes
assert roomsPackage.eClassifiers.is_a?(Array)
assert_equal 3, roomsPackage.eClassifiers.size
assert roomsPackage.eClassifiers.all?{|c| c.is_a?(EClass)}
roomClass = roomsPackage.eClassifiers.select{|c| c.name == "Room"}.first
kitchenClass = roomsPackage.eClassifiers.select{|c| c.name == "Kitchen"}.first
bathroomClass = roomsPackage.eClassifiers.select{|c| c.name == "Bathroom"}.first
assert_not_nil roomClass
assert_not_nil kitchenClass
assert_not_nil bathroomClass
# check Room inheritance
assert kitchenClass.eSuperTypes.is_a?(Array)
assert_equal 2, kitchenClass.eSuperTypes.size
assert_equal roomClass.object_id, kitchenClass.eSuperTypes.select{|c| c.name == "Room"}.first.object_id
assert_equal meetingPlaceClass.object_id, kitchenClass.eSuperTypes.select{|c| c.name == "MeetingPlace"}.first.object_id
assert bathroomClass.eSuperTypes.is_a?(Array)
assert_equal 1, bathroomClass.eSuperTypes.size
assert_equal roomClass.object_id, bathroomClass.eSuperTypes[0].object_id
# check House-Room "part of" association
assert houseClass.eAllContainments.eType.is_a?(Array)
assert_equal 1, houseClass.eAllContainments.eType.size
roomRef = houseClass.eAllContainments.first
assert_equal roomClass.object_id, roomRef.eType.object_id
assert_equal "room", roomRef.name
assert_equal 1, roomRef.lowerBound
assert_equal(-1, roomRef.upperBound)
assert_not_nil roomRef.eOpposite
assert_equal houseClass.object_id, roomRef.eOpposite.eType.object_id
partOfRefs = roomClass.eReferences.select{|r| r.eOpposite && r.eOpposite.containment}
assert_equal 1, partOfRefs.size
assert_equal houseClass.object_id, partOfRefs.first.eType.object_id
assert_equal "house", partOfRefs.first.name
assert_equal roomRef.object_id, partOfRefs.first.eOpposite.object_id
# check House OUT associations
assert houseClass.eReferences.is_a?(Array)
assert_equal 3, houseClass.eReferences.size
bathRef = houseClass.eReferences.find {|e| e.name == "bathroom"}
kitchenRef = houseClass.eReferences.find {|e| e.name == "kitchen"}
roomRef = houseClass.eReferences.find {|e| e.name == "room"}
assert_not_nil bathRef
assert_nil bathRef.eOpposite
assert_not_nil kitchenRef
assert_not_nil roomRef
assert_equal 1, kitchenRef.lowerBound
assert_equal 1, kitchenRef.upperBound
assert_equal 1, roomRef.lowerBound
assert_equal(-1, roomRef.upperBound)
# check House IN associations
houseInRefs = env.find(:class => EReference, :eType => houseClass)
assert_equal 3, houseInRefs.size
homeEnd = houseInRefs.find{|e| e.name == "home"}
assert_not_nil homeEnd
assert_equal 0, homeEnd.lowerBound
assert_equal(-1, homeEnd.upperBound)
end
end
rgen-0.7.0/test/xml_instantiator_test/simple_xmi_metamodel.rb 0000644 0000041 0000041 00000002164 12352210062 024634 0 ustar www-data www-data # This is an extension of the implicit metamodel created by the
# DefaultXMLInstantiator when it reads an Enterprise Architect
# XMI file.
#
module SimpleXMIMetaModel
module UML
include RGen::MetamodelBuilder
class Classifier_feature < MMBase
end
class ClassifierRole < MMBase
end
class Clazz < ClassifierRole
end
class Interface < ClassifierRole
end
class Operation < MMBase
end
class Generalization < MMBase
end
class ModelElement_stereotype < MMBase
end
class AssociationEnd < MMBase
module ClassModule
def otherEnd
parent.associationEnd.find{|ae| ae != self}
end
end
end
class AssociationEndRole < MMBase
end
ClassifierRole.one_to_many 'associationEnds', AssociationEnd, 'typeClass'
ClassifierRole.one_to_many 'associationEndRoles', AssociationEndRole, 'typeClass'
Clazz.one_to_many 'generalizationsAsSubtype', Generalization, 'subtypeClass'
Clazz.one_to_many 'generalizationsAsSupertype', Generalization, 'supertypeClass'
end
end
rgen-0.7.0/test/json_test.rb 0000644 0000041 0000041 00000014522 12352210062 016012 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/environment'
require 'rgen/metamodel_builder'
require 'rgen/serializer/json_serializer'
require 'rgen/instantiator/json_instantiator'
class JsonTest < Test::Unit::TestCase
module TestMM
extend RGen::MetamodelBuilder::ModuleExtension
class TestNode < RGen::MetamodelBuilder::MMBase
has_attr 'text', String
has_attr 'integer', Integer
has_attr 'float', Float
has_one 'other', TestNode
contains_many 'childs', TestNode, 'parent'
end
end
module TestMMData
extend RGen::MetamodelBuilder::ModuleExtension
# class "Data" exists in the standard Ruby namespace
class Data < RGen::MetamodelBuilder::MMBase
has_attr 'notTheBuiltin', String
end
end
module TestMMSubpackage
extend RGen::MetamodelBuilder::ModuleExtension
module SubPackage
extend RGen::MetamodelBuilder::ModuleExtension
class Data < RGen::MetamodelBuilder::MMBase
has_attr 'notTheBuiltin', String
end
class Data2 < RGen::MetamodelBuilder::MMBase
has_attr 'data2', String
end
end
end
class StringWriter < String
alias write concat
end
def test_json_serializer
testModel = TestMM::TestNode.new(:text => "some text", :childs => [
TestMM::TestNode.new(:text => "child")])
output = StringWriter.new
ser = RGen::Serializer::JsonSerializer.new(output)
assert_equal %q({ "_class": "TestNode", "text": "some text", "childs": [
{ "_class": "TestNode", "text": "child" }] }), ser.serialize(testModel)
end
def test_json_instantiator
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMM)
inst.instantiate(%q({ "_class": "TestNode", "text": "some text", "childs": [
{ "_class": "TestNode", "text": "child" }] }))
root = env.find(:class => TestMM::TestNode, :text => "some text").first
assert_not_nil root
assert_equal 1, root.childs.size
assert_equal TestMM::TestNode, root.childs.first.class
assert_equal "child", root.childs.first.text
end
def test_json_serializer_escapes
testModel = TestMM::TestNode.new(:text => %Q(some " \\ \\" text \r xx \n xx \r\n xx \t xx \b xx \f))
output = StringWriter.new
ser = RGen::Serializer::JsonSerializer.new(output)
assert_equal %q({ "_class": "TestNode", "text": "some \" \\\\ \\\\\" text \r xx \n xx \r\n xx \t xx \b xx \f" }),
ser.serialize(testModel)
end
def test_json_instantiator_escapes
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMM)
inst.instantiate(%q({ "_class": "TestNode", "text": "some \" \\\\ \\\\\" text \r xx \n xx \r\n xx \t xx \b xx \f" }))
assert_equal %Q(some " \\ \\" text \r xx \n xx \r\n xx \t xx \b xx \f), env.elements.first.text
end
def test_json_instantiator_escape_single_backslash
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMM)
inst.instantiate(%q({ "_class": "TestNode", "text": "a single \\ will be just itself" }))
assert_equal %q(a single \\ will be just itself), env.elements.first.text
end
def test_json_serializer_integer
testModel = TestMM::TestNode.new(:integer => 7)
output = StringWriter.new
ser = RGen::Serializer::JsonSerializer.new(output)
assert_equal %q({ "_class": "TestNode", "integer": 7 }), ser.serialize(testModel)
end
def test_json_instantiator_integer
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMM)
inst.instantiate(%q({ "_class": "TestNode", "integer": 7 }))
assert_equal 7, env.elements.first.integer
end
def test_json_serializer_float
testModel = TestMM::TestNode.new(:float => 1.23)
output = StringWriter.new
ser = RGen::Serializer::JsonSerializer.new(output)
assert_equal %q({ "_class": "TestNode", "float": 1.23 }), ser.serialize(testModel)
end
def test_json_instantiator_float
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMM)
inst.instantiate(%q({ "_class": "TestNode", "float": 1.23 }))
assert_equal 1.23, env.elements.first.float
end
def test_json_instantiator_conflict_builtin
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMMData)
inst.instantiate(%q({ "_class": "Data", "notTheBuiltin": "for sure" }))
assert_equal "for sure", env.elements.first.notTheBuiltin
end
def test_json_serializer_subpacakge
testModel = TestMMSubpackage::SubPackage::Data2.new(:data2 => "xxx")
output = StringWriter.new
ser = RGen::Serializer::JsonSerializer.new(output)
assert_equal %q({ "_class": "Data2", "data2": "xxx" }), ser.serialize(testModel)
end
def test_json_instantiator_builtin_in_subpackage
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMMSubpackage)
inst.instantiate(%q({ "_class": "Data", "notTheBuiltin": "for sure" }))
assert_equal "for sure", env.elements.first.notTheBuiltin
end
def test_json_instantiator_subpackage
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMMSubpackage)
inst.instantiate(%q({ "_class": "Data2", "data2": "something" }))
assert_equal "something", env.elements.first.data2
end
def test_json_instantiator_subpackage_no_shortname_opt
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMMSubpackage, :short_class_names => false)
assert_raise RuntimeError do
inst.instantiate(%q({ "_class": "Data2", "data2": "something" }))
end
end
def test_json_instantiator_references
env = RGen::Environment.new
inst = RGen::Instantiator::JsonInstantiator.new(env, TestMM, :nameAttribute => "text")
inst.instantiate(%q([
{ "_class": "TestNode", "text": "A", "childs": [
{ "_class": "TestNode", "text": "B" } ]},
{ "_class": "TestNode", "text": "C", "other": "/A/B"}]
))
nodeA = env.find(:class => TestMM::TestNode, :text => "A").first
nodeC = env.find(:class => TestMM::TestNode, :text => "C").first
assert_equal 1, nodeA.childs.size
assert_equal nodeA.childs[0], nodeC.other
end
end
rgen-0.7.0/test/output_handler_test.rb 0000644 0000041 0000041 00000003002 12352210062 020065 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/template_language/output_handler'
class MetamodelBuilderTest < Test::Unit::TestCase
def test_direct_nl
h = RGen::TemplateLanguage::OutputHandler.new
h.mode = :direct
h << "Test"
h.ignoreNextNL
h << "\nContent"
assert_equal "TestContent", h.to_s
end
def test_direct_ws
h = RGen::TemplateLanguage::OutputHandler.new
h.mode = :direct
h << "Test"
h.ignoreNextWS
h << " \n Content"
assert_equal "TestContent", h.to_s
end
def test_explicit_indent
h = RGen::TemplateLanguage::OutputHandler.new
h.mode = :explicit
h.indent = 1
h << "Start"
h << " \n "
h << "Test"
h << " \n \n Content"
assert_equal " Start\n Test\n Content", h.to_s
end
def test_explicit_endswithws
h = RGen::TemplateLanguage::OutputHandler.new
h.mode = :explicit
h.indent = 1
h << "Start \n\n"
assert_equal " Start\n", h.to_s
end
def test_performance
h = RGen::TemplateLanguage::OutputHandler.new
h.mode = :explicit
h.indent = 1
line = (1..50).collect{|w| "someword"}.join(" ")+"\n"
# repeat more often to make performance differences visible
20.times do
h << line
end
end
def test_indent_string
h = RGen::TemplateLanguage::OutputHandler.new(1, "\t", :explicit)
h << "Start"
h << " \n "
h << "Test"
h << " \n \n Content"
assert_equal "\tStart\n\tTest\n\tContent", h.to_s
end
end rgen-0.7.0/test/ea_serializer_test.rb 0000644 0000041 0000041 00000001335 12352210062 017655 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/environment'
require 'metamodels/uml13_metamodel'
require 'ea_support/ea_support'
require 'rgen/serializer/xmi11_serializer'
class EASerializerTest < Test::Unit::TestCase
MODEL_DIR = File.join(File.dirname(__FILE__),"testmodel")
TEST_DIR = File.join(File.dirname(__FILE__),"ea_serializer_test")
def test_serializer
envUML = RGen::Environment.new
EASupport.instantiateUML13FromXMI11(envUML, MODEL_DIR+"/ea_testmodel.xml")
models = envUML.find(:class => UML13::Model)
assert_equal 1, models.size
EASupport.serializeUML13ToXMI11(envUML, MODEL_DIR+"/ea_testmodel_regenerated.xml")
end
end rgen-0.7.0/test/array_extensions_test.rb 0000644 0000041 0000041 00000003100 12352210062 020424 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/array_extensions'
class ArrayExtensionsTest < Test::Unit::TestCase
def test_element_methods
c = Struct.new("SomeClass",:name,:age)
a = []
a << c.new('MyName',33)
a << c.new('YourName',22)
assert_equal ["MyName", "YourName"], a >> :name
assert_raise NoMethodError do
a.name
end
assert_equal [33, 22], a>>:age
assert_raise NoMethodError do
a.age
end
# unfortunately, any method can be called on an empty array
assert_equal [], [].age
end
class MMBaseClass < RGen::MetamodelBuilder::MMBase
has_attr 'name'
has_attr 'age', Integer
end
def test_with_mmbase
e1 = MMBaseClass.new
e1.name = "MyName"
e1.age = 33
e2 = MMBaseClass.new
e2.name = "YourName"
e2.age = 22
a = [e1, e2]
assert_equal ["MyName", "YourName"], a >> :name
assert_equal ["MyName", "YourName"], a.name
assert_equal [33, 22], a>>:age
assert_equal [33, 22], a.age
# put something into the array that is not an MMBase
a << "not a MMBase"
# the dot operator will tell that there is something not a MMBase
assert_raise StandardError do
a.age
end
# the >> operator will try to call the method anyway
assert_raise NoMethodError do
a >> :age
end
end
def test_hash_square
assert_equal({}, Hash[[]])
end
def test_to_str_on_empty_array
assert_raise NoMethodError do
[].to_str
end
end
end
rgen-0.7.0/test/qualified_name_provider_test.rb 0000644 0000041 0000041 00000002475 12352210062 021722 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/metamodel_builder'
require 'rgen/serializer/qualified_name_provider'
class QualifiedNameProviderTest < Test::Unit::TestCase
class AbstractTestNode < RGen::MetamodelBuilder::MMBase
contains_many 'children', AbstractTestNode, "parent"
end
class NamedNode < AbstractTestNode
has_attr 'n', String
end
class UnnamedNode < AbstractTestNode
end
def test_simple
root = NamedNode.new(:n => "root", :children => [
NamedNode.new(:n => "a", :children => [
NamedNode.new(:n => "a1")
]),
UnnamedNode.new(:children => [
NamedNode.new(:n => "b1")
])
])
qnp = RGen::Serializer::QualifiedNameProvider.new(:attribute_name => "n")
assert_equal "/root", qnp.identifier(root)
assert_equal "/root/a", qnp.identifier(root.children[0])
assert_equal "/root/a/a1", qnp.identifier(root.children[0].children[0])
assert_equal "/root", qnp.identifier(root.children[1])
assert_equal "/root/b1", qnp.identifier(root.children[1].children[0])
end
def test_unnamed_root
root = UnnamedNode.new
qnp = RGen::Serializer::QualifiedNameProvider.new(:attribute_name => "n")
assert_equal "/", qnp.identifier(root)
end
end
rgen-0.7.0/test/metamodel_builder_test.rb 0000644 0000041 0000041 00000135615 12352210062 020525 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/metamodel_builder'
require 'rgen/array_extensions'
require 'bigdecimal'
class MetamodelBuilderTest < Test::Unit::TestCase
module TestMetamodel
extend RGen::MetamodelBuilder::ModuleExtension
class SimpleClass < RGen::MetamodelBuilder::MMBase
KindType = RGen::MetamodelBuilder::DataTypes::Enum.new([:simple, :extended])
has_attr 'name' # default is String
has_attr 'stringWithDefault', String, :defaultValueLiteral => "xtest"
has_attr 'integerWithDefault', Integer, :defaultValueLiteral => "123"
has_attr 'longWithDefault', Long, :defaultValueLiteral => "1234567890"
has_attr 'floatWithDefault', Float, :defaultValueLiteral => "0.123"
has_attr 'boolWithDefault', Boolean, :defaultValueLiteral => "true"
has_attr 'anything', Object
has_attr 'allowed', RGen::MetamodelBuilder::DataTypes::Boolean
has_attr 'kind', KindType
has_attr 'kindWithDefault', KindType, :defaultValueLiteral => "extended"
end
class ManyAttrClass < RGen::MetamodelBuilder::MMBase
has_many_attr 'literals', String
has_many_attr 'bools', Boolean
has_many_attr 'integers', Integer
has_many_attr 'enums', RGen::MetamodelBuilder::DataTypes::Enum.new([:a, :b, :c])
has_many_attr 'limitTest', Integer, :upperBound => 2
end
class ClassA < RGen::MetamodelBuilder::MMBase
# metamodel accessors must work independent of the ==() method
module ClassModule
def ==(o)
o.is_a?(ClassA)
end
end
end
class ClassB < RGen::MetamodelBuilder::MMBase
end
class ClassC < RGen::MetamodelBuilder::MMBase
end
class HasOneTestClass < RGen::MetamodelBuilder::MMBase
has_one 'classA', ClassA
has_one 'classB', ClassB
end
class HasManyTestClass < RGen::MetamodelBuilder::MMBase
has_many 'classA', ClassA
end
class OneClass < RGen::MetamodelBuilder::MMBase
end
class ManyClass < RGen::MetamodelBuilder::MMBase
end
OneClass.one_to_many 'manyClasses', ManyClass, 'oneClass', :upperBound => 5
class AClassMM < RGen::MetamodelBuilder::MMBase
end
class BClassMM < RGen::MetamodelBuilder::MMBase
end
AClassMM.many_to_many 'bClasses', BClassMM, 'aClasses'
module SomePackage
extend RGen::MetamodelBuilder::ModuleExtension
class ClassA < RGen::MetamodelBuilder::MMBase
end
module SubPackage
extend RGen::MetamodelBuilder::ModuleExtension
class ClassB < RGen::MetamodelBuilder::MMBase
end
end
end
class OneClass2 < RGen::MetamodelBuilder::MMBase
end
class ManyClass2 < RGen::MetamodelBuilder::MMBase
end
ManyClass2.many_to_one 'oneClass', OneClass2, 'manyClasses'
class AClassOO < RGen::MetamodelBuilder::MMBase
end
class BClassOO < RGen::MetamodelBuilder::MMBase
end
AClassOO.one_to_one 'bClass', BClassOO, 'aClass'
class SomeSuperClass < RGen::MetamodelBuilder::MMBase
has_attr "name"
has_many "classAs", ClassA
end
class SomeSubClass < SomeSuperClass
has_attr "subname"
has_many "classBs", ClassB
end
class OtherSubClass < SomeSuperClass
has_attr "othersubname"
has_many "classCs", ClassC
end
class SubSubClass < RGen::MetamodelBuilder::MMMultiple(SomeSubClass, OtherSubClass)
has_attr "subsubname"
end
module AnnotatedModule
extend RGen::MetamodelBuilder::ModuleExtension
annotation "moduletag" => "modulevalue"
class AnnotatedClass < RGen::MetamodelBuilder::MMBase
annotation "sometag" => "somevalue", "othertag" => "othervalue"
annotation :source => "rgen/test", :details => {"thirdtag" => "thirdvalue"}
has_attr "boolAttr", Boolean do
annotation "attrtag" => "attrval"
annotation :source => "rgen/test2", :details => {"attrtag2" => "attrvalue2", "attrtag3" => "attrvalue3"}
end
has_many "others", AnnotatedClass do
annotation "reftag" => "refval"
annotation :source => "rgen/test3", :details => {"reftag2" => "refvalue2", "reftag3" => "refvalue3"}
end
many_to_many "m2m", AnnotatedClass, "m2mback" do
annotation "m2mtag" => "m2mval"
opposite_annotation "opposite_m2mtag" => "opposite_m2mval"
end
end
end
class AbstractClass < RGen::MetamodelBuilder::MMBase
abstract
end
class ContainedClass < RGen::MetamodelBuilder::MMBase
end
class ContainerClass < RGen::MetamodelBuilder::MMBase
contains_one_uni 'oneChildUni', ContainedClass
contains_one_uni 'oneChildUni2', ContainedClass
contains_one 'oneChild', ContainedClass, 'parentOne'
contains_one 'oneChild2', ContainedClass, 'parentOne2'
contains_many_uni 'manyChildUni', ContainedClass
contains_many_uni 'manyChildUni2', ContainedClass
contains_many 'manyChild', ContainedClass, 'parentMany'
contains_many 'manyChild2', ContainedClass, 'parentMany2'
end
class NestedContainerClass < ContainedClass
contains_one_uni 'oneChildUni', ContainedClass
end
class OppositeRefAssocA < RGen::MetamodelBuilder::MMBase
end
class OppositeRefAssocB < RGen::MetamodelBuilder::MMBase
end
OppositeRefAssocA.one_to_one 'bClass', OppositeRefAssocB, 'aClass'
end
def mm
TestMetamodel
end
def test_has_attr
sc = mm::SimpleClass.new
assert_respond_to sc, :name
assert_respond_to sc, :name=
sc.name = "TestName"
assert_equal "TestName", sc.name
sc.name = nil
assert_equal nil, sc.name
err = assert_raise StandardError do
sc.name = 5
end
assert_match /In (\w+::)+SimpleClass : Can not use a Fixnum where a String is expected/, err.message
assert_equal "EString", mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="name"}.eType.name
assert_equal "xtest", sc.stringWithDefault
assert_equal :extended, sc.kindWithDefault
assert_equal 123, sc.integerWithDefault
assert_equal 1234567890, sc.longWithDefault
assert_equal 0.123, sc.floatWithDefault
assert_equal true, sc.boolWithDefault
# setting nil should not make the default value appear on next read
sc.stringWithDefault = nil
assert_nil sc.stringWithDefault
sc.anything = :asymbol
assert_equal :asymbol, sc.anything
sc.anything = self # a class
assert_equal self, sc.anything
assert_respond_to sc, :allowed
assert_respond_to sc, :allowed=
sc.allowed = true
assert_equal true, sc.allowed
sc.allowed = false
assert_equal false, sc.allowed
sc.allowed = nil
assert_equal nil, sc.allowed
err = assert_raise StandardError do
sc.allowed = :someSymbol
end
assert_match /In (\w+::)+SimpleClass : Can not use a Symbol\(:someSymbol\) where a \[true,false\] is expected/, err.message
err = assert_raise StandardError do
sc.allowed = "a string"
end
assert_match /In (\w+::)+SimpleClass : Can not use a String where a \[true,false\] is expected/, err.message
assert_equal "EBoolean", mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="allowed"}.eType.name
assert_respond_to sc, :kind
assert_respond_to sc, :kind=
sc.kind = :simple
assert_equal :simple, sc.kind
sc.kind = :extended
assert_equal :extended, sc.kind
sc.kind = nil
assert_equal nil, sc.kind
err = assert_raise StandardError do
sc.kind = :false
end
assert_match /In (\w+::)+SimpleClass : Can not use a Symbol\(:false\) where a \[:simple,:extended\] is expected/, err.message
err = assert_raise StandardError do
sc.kind = "a string"
end
assert_match /In (\w+::)+SimpleClass : Can not use a String where a \[:simple,:extended\] is expected/, err.message
enum = mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="kind"}.eType
assert_equal ["extended", "simple"], enum.eLiterals.name.sort
end
def test_float
sc = mm::SimpleClass.new
sc.floatWithDefault = 7.89
assert_equal 7.89, sc.floatWithDefault
if BigDecimal.double_fig == 16
sc.floatWithDefault = 123456789012345678.0
# loss of precision
assert_equal "123456789012345680.0", sprintf("%.1f", sc.floatWithDefault)
end
sc.floatWithDefault = nil
sc.floatWithDefault = BigDecimal.new("123456789012345678.0")
assert sc.floatWithDefault.is_a?(BigDecimal)
assert_equal "123456789012345678.0", sc.floatWithDefault.to_s("F")
dump = Marshal.dump(sc)
sc2 = Marshal.load(dump)
assert sc2.floatWithDefault.is_a?(BigDecimal)
assert_equal "123456789012345678.0", sc2.floatWithDefault.to_s("F")
end
def test_long
sc = mm::SimpleClass.new
sc.longWithDefault = 5
assert_equal 5, sc.longWithDefault
sc.longWithDefault = 1234567890
assert_equal 1234567890, sc.longWithDefault
assert sc.longWithDefault.is_a?(Bignum)
assert sc.longWithDefault.is_a?(Integer)
err = assert_raise StandardError do
sc.longWithDefault = "a string"
end
assert_match /In (\w+::)+SimpleClass : Can not use a String where a Integer is expected/, err.message
end
def test_many_attr
o = mm::ManyAttrClass.new
assert_respond_to o, :literals
assert_respond_to o, :addLiterals
assert_respond_to o, :removeLiterals
err = assert_raise(StandardError) do
o.addLiterals(1)
end
assert_match /In (\w+::)+ManyAttrClass : Can not use a Fixnum where a String is expected/, err.message
assert_equal [], o.literals
o.addLiterals("a")
assert_equal ["a"], o.literals
o.addLiterals("b")
assert_equal ["a", "b"], o.literals
o.addLiterals("b")
assert_equal ["a", "b", "b"], o.literals
# attributes allow the same object several times
o.addLiterals(o.literals.first)
assert_equal ["a", "b", "b", "a"], o.literals
assert o.literals[0].object_id == o.literals[3].object_id
# removing works by object identity, so providing a new string won't delete an existing one
o.removeLiterals("a")
assert_equal ["a", "b", "b", "a"], o.literals
theA = o.literals.first
# each remove command removes only one element: remove first "a"
o.removeLiterals(theA)
assert_equal ["b", "b", "a"], o.literals
# remove second "a" (same object)
o.removeLiterals(theA)
assert_equal ["b", "b"], o.literals
o.removeLiterals(o.literals.first)
assert_equal ["b"], o.literals
o.removeLiterals(o.literals.first)
assert_equal [], o.literals
# setting multiple elements at a time
o.literals = ["a", "b", "c"]
assert_equal ["a", "b", "c"], o.literals
# can only take enumerables
err = assert_raise(StandardError) do
o.literals = 1
end
assert_match /In (\w+::)+ManyAttrClass : Can not use a Fixnum where a Enumerable is expected/, err.message
o.bools = [true, false, true, false]
assert_equal [true, false, true, false], o.bools
o.integers = [1, 2, 2, 3, 3]
assert_equal [1, 2, 2, 3, 3], o.integers
o.enums = [:a, :a, :b, :c, :c]
assert_equal [:a, :a, :b, :c, :c], o.enums
lit = mm::ManyAttrClass.ecore.eAttributes.find{|a| a.name == "literals"}
assert lit.is_a?(RGen::ECore::EAttribute)
assert lit.many
lim = mm::ManyAttrClass.ecore.eAttributes.find{|a| a.name == "limitTest"}
assert lit.many
assert_equal 2, lim.upperBound
end
def test_many_attr_insert
o = mm::ManyAttrClass.new
o.addLiterals("a")
o.addLiterals("b", 0)
o.addLiterals("c", 1)
assert_equal ["b", "c", "a"], o.literals
end
def test_has_one
sc = mm::HasOneTestClass.new
assert_respond_to sc, :classA
assert_respond_to sc, :classA=
ca = mm::ClassA.new
sc.classA = ca
assert_equal ca, sc.classA
sc.classA = nil
assert_equal nil, sc.classA
assert_respond_to sc, :classB
assert_respond_to sc, :classB=
cb = mm::ClassB.new
sc.classB = cb
assert_equal cb, sc.classB
err = assert_raise StandardError do
sc.classB = ca
end
assert_match /In (\w+::)+HasOneTestClass : Can not use a (\w+::)+ClassA where a (\w+::)+ClassB is expected/, err.message
assert_equal [], mm::ClassA.ecore.eReferences
assert_equal [], mm::ClassB.ecore.eReferences
assert_equal ["classA", "classB"].sort, mm::HasOneTestClass.ecore.eReferences.name.sort
assert_equal [], mm::HasOneTestClass.ecore.eReferences.select { |a| a.many == true }
assert_equal [], mm::HasOneTestClass.ecore.eAttributes
end
def test_has_many
o = mm::HasManyTestClass.new
ca1 = mm::ClassA.new
ca2 = mm::ClassA.new
ca3 = mm::ClassA.new
o.addClassA(ca1)
o.addClassA(ca2)
assert_equal [ca1, ca2], o.classA
# make sure we get a copy
o.classA.clear
assert_equal [ca1, ca2], o.classA
o.removeClassA(ca3)
assert_equal [ca1, ca2], o.classA
o.removeClassA(ca2)
assert_equal [ca1], o.classA
err = assert_raise StandardError do
o.addClassA(mm::ClassB.new)
end
assert_match /In (\w+::)+HasManyTestClass : Can not use a (\w+::)+ClassB where a (\w+::)+ClassA is expected/, err.message
assert_equal [], mm::HasManyTestClass.ecore.eReferences.select{|r| r.many == false}
assert_equal ["classA"], mm::HasManyTestClass.ecore.eReferences.select{|r| r.many == true}.name
end
def test_has_many_insert
o = mm::HasManyTestClass.new
ca1 = mm::ClassA.new
ca2 = mm::ClassA.new
ca3 = mm::ClassA.new
ca4 = mm::ClassA.new
ca5 = mm::ClassA.new
o.addClassA(ca1)
o.addClassA(ca2)
o.addClassA(ca3,0)
o.addClassA(ca4,1)
o.addGeneric("classA",ca5,2)
assert_equal [ca3, ca4, ca5, ca1, ca2], o.classA
end
def test_one_to_many
oc = mm::OneClass.new
assert_respond_to oc, :manyClasses
assert oc.manyClasses.empty?
mc = mm::ManyClass.new
assert_respond_to mc, :oneClass
assert_respond_to mc, :oneClass=
assert_nil mc.oneClass
# put the OneClass into the ManyClass
mc.oneClass = oc
assert_equal oc, mc.oneClass
assert oc.manyClasses.include?(mc)
# remove the OneClass from the ManyClass
mc.oneClass = nil
assert_equal nil, mc.oneClass
assert !oc.manyClasses.include?(mc)
# put the ManyClass into the OneClass
oc.addManyClasses mc
assert oc.manyClasses.include?(mc)
assert_equal oc, mc.oneClass
# remove the ManyClass from the OneClass
oc.removeManyClasses mc
assert !oc.manyClasses.include?(mc)
assert_equal nil, mc.oneClass
assert_equal [], mm::OneClass.ecore.eReferences.select{|r| r.many == false}
assert_equal ["manyClasses"], mm::OneClass.ecore.eReferences.select{|r| r.many == true}.name
assert_equal 5, mm::OneClass.ecore.eReferences.find{|r| r.many == true}.upperBound
assert_equal ["oneClass"], mm::ManyClass.ecore.eReferences.select{|r| r.many == false}.name
assert_equal [], mm::ManyClass.ecore.eReferences.select{|r| r.many == true}
end
def test_one_to_many_replace1
oc1 = mm::OneClass.new
oc2 = mm::OneClass.new
mc = mm::ManyClass.new
oc1.manyClasses = [mc]
assert_equal [mc], oc1.manyClasses
assert_equal [], oc2.manyClasses
assert_equal oc1, mc.oneClass
oc2.manyClasses = [mc]
assert_equal [mc], oc2.manyClasses
assert_equal [], oc1.manyClasses
assert_equal oc2, mc.oneClass
end
def test_one_to_many_replace2
oc = mm::OneClass.new
mc1 = mm::ManyClass.new
mc2 = mm::ManyClass.new
mc1.oneClass = oc
assert_equal [mc1], oc.manyClasses
assert_equal oc, mc1.oneClass
assert_equal nil, mc2.oneClass
mc2.oneClass = oc
assert_equal [mc1, mc2], oc.manyClasses
assert_equal oc, mc1.oneClass
assert_equal oc, mc2.oneClass
end
def test_one_to_many_insert
oc = mm::OneClass.new
mc1 = mm::ManyClass.new
mc2 = mm::ManyClass.new
oc.addManyClasses(mc1, 0)
oc.addManyClasses(mc2, 0)
assert_equal [mc2, mc1], oc.manyClasses
assert_equal oc, mc1.oneClass
assert_equal oc, mc2.oneClass
end
def test_one_to_many2
oc = mm::OneClass2.new
assert_respond_to oc, :manyClasses
assert oc.manyClasses.empty?
mc = mm::ManyClass2.new
assert_respond_to mc, :oneClass
assert_respond_to mc, :oneClass=
assert_nil mc.oneClass
# put the OneClass into the ManyClass
mc.oneClass = oc
assert_equal oc, mc.oneClass
assert oc.manyClasses.include?(mc)
# remove the OneClass from the ManyClass
mc.oneClass = nil
assert_equal nil, mc.oneClass
assert !oc.manyClasses.include?(mc)
# put the ManyClass into the OneClass
oc.addManyClasses mc
assert oc.manyClasses.include?(mc)
assert_equal oc, mc.oneClass
# remove the ManyClass from the OneClass
oc.removeManyClasses mc
assert !oc.manyClasses.include?(mc)
assert_equal nil, mc.oneClass
assert_equal [], mm::OneClass2.ecore.eReferences.select{|r| r.many == false}
assert_equal ["manyClasses"], mm::OneClass2.ecore.eReferences.select{|r| r.many == true}.name
assert_equal ["oneClass"], mm::ManyClass2.ecore.eReferences.select{|r| r.many == false}.name
assert_equal [], mm::ManyClass2.ecore.eReferences.select{|r| r.many == true}
end
def test_one_to_one
ac = mm::AClassOO.new
assert_respond_to ac, :bClass
assert_respond_to ac, :bClass=
assert_nil ac.bClass
bc = mm::BClassOO.new
assert_respond_to bc, :aClass
assert_respond_to bc, :aClass=
assert_nil bc.aClass
# put the AClass into the BClass
bc.aClass = ac
assert_equal ac, bc.aClass
assert_equal bc, ac.bClass
# remove the AClass from the BClass
bc.aClass = nil
assert_equal nil, bc.aClass
assert_equal nil, ac.bClass
# put the BClass into the AClass
ac.bClass = bc
assert_equal bc, ac.bClass
assert_equal ac, bc.aClass
# remove the BClass from the AClass
ac.bClass = nil
assert_equal nil, ac.bClass
assert_equal nil, bc.aClass
assert_equal ["bClass"], mm::AClassOO.ecore.eReferences.select{|r| r.many == false}.name
assert_equal [], mm::AClassOO.ecore.eReferences.select{|r| r.many == true}
assert_equal ["aClass"], mm::BClassOO.ecore.eReferences.select{|r| r.many == false}.name
assert_equal [], mm::BClassOO.ecore.eReferences.select{|r| r.many == true}
end
def test_one_to_one_replace
a = mm::AClassOO.new
b1 = mm::BClassOO.new
b2 = mm::BClassOO.new
a.bClass = b1
assert_equal b1, a.bClass
assert_equal a, b1.aClass
assert_equal nil, b2.aClass
a.bClass = b2
assert_equal b2, a.bClass
assert_equal nil, b1.aClass
assert_equal a, b2.aClass
end
def test_many_to_many
ac = mm::AClassMM.new
assert_respond_to ac, :bClasses
assert ac.bClasses.empty?
bc = mm::BClassMM.new
assert_respond_to bc, :aClasses
assert bc.aClasses.empty?
# put the AClass into the BClass
bc.addAClasses ac
assert bc.aClasses.include?(ac)
assert ac.bClasses.include?(bc)
# put something else into the BClass
err = assert_raise StandardError do
bc.addAClasses :notaaclass
end
assert_match /In (\w+::)+BClassMM : Can not use a Symbol\(:notaaclass\) where a (\w+::)+AClassMM is expected/, err.message
# remove the AClass from the BClass
bc.removeAClasses ac
assert !bc.aClasses.include?(ac)
assert !ac.bClasses.include?(bc)
# put the BClass into the AClass
ac.addBClasses bc
assert ac.bClasses.include?(bc)
assert bc.aClasses.include?(ac)
# put something else into the AClass
err = assert_raise StandardError do
ac.addBClasses :notabclass
end
assert_match /In (\w+::)+AClassMM : Can not use a Symbol\(:notabclass\) where a (\w+::)+BClassMM is expected/, err.message
# remove the BClass from the AClass
ac.removeBClasses bc
assert !ac.bClasses.include?(bc)
assert !bc.aClasses.include?(ac)
assert_equal [], mm::AClassMM.ecore.eReferences.select{|r| r.many == false}
assert_equal ["bClasses"], mm::AClassMM.ecore.eReferences.select{|r| r.many == true}.name
assert_equal [], mm::BClassMM.ecore.eReferences.select{|r| r.many == false}
assert_equal ["aClasses"], mm::BClassMM.ecore.eReferences.select{|r| r.many == true}.name
end
def test_many_to_many_insert
ac1 = mm::AClassMM.new
ac2 = mm::AClassMM.new
bc1= mm::BClassMM.new
bc2= mm::BClassMM.new
ac1.addBClasses(bc1)
ac1.addBClasses(bc2, 0)
ac2.addBClasses(bc1)
ac2.addBClasses(bc2, 0)
assert_equal [bc2, bc1], ac1.bClasses
assert_equal [bc2, bc1], ac2.bClasses
assert_equal [ac1, ac2], bc1.aClasses
assert_equal [ac1, ac2], bc2.aClasses
end
def test_inheritance
assert_equal ["name"], mm::SomeSuperClass.ecore.eAllAttributes.name
assert_equal ["classAs"], mm::SomeSuperClass.ecore.eAllReferences.name
assert_equal ["name", "subname"], mm::SomeSubClass.ecore.eAllAttributes.name.sort
assert_equal ["classAs", "classBs"], mm::SomeSubClass.ecore.eAllReferences.name.sort
assert_equal ["name", "othersubname"], mm::OtherSubClass.ecore.eAllAttributes.name.sort
assert_equal ["classAs", "classCs"], mm::OtherSubClass.ecore.eAllReferences.name.sort
assert mm::SomeSubClass.new.is_a?(mm::SomeSuperClass)
assert_equal ["name", "othersubname", "subname", "subsubname"], mm::SubSubClass.ecore.eAllAttributes.name.sort
assert_equal ["classAs", "classBs", "classCs"], mm::SubSubClass.ecore.eAllReferences.name.sort
assert mm::SubSubClass.new.is_a?(mm::SomeSuperClass)
assert mm::SubSubClass.new.is_a?(mm::SomeSubClass)
assert mm::SubSubClass.new.is_a?(mm::OtherSubClass)
end
def test_annotations
assert_equal 1, mm::AnnotatedModule.ecore.eAnnotations.size
anno = mm::AnnotatedModule.ecore.eAnnotations.first
checkAnnotation(anno, nil, {"moduletag" => "modulevalue"})
eClass = mm::AnnotatedModule::AnnotatedClass.ecore
assert_equal 2, eClass.eAnnotations.size
anno = eClass.eAnnotations.find{|a| a.source == "rgen/test"}
checkAnnotation(anno, "rgen/test", {"thirdtag" => "thirdvalue"})
anno = eClass.eAnnotations.find{|a| a.source == nil}
checkAnnotation(anno, nil, {"sometag" => "somevalue", "othertag" => "othervalue"})
eAttr = eClass.eAttributes.first
assert_equal 2, eAttr.eAnnotations.size
anno = eAttr.eAnnotations.find{|a| a.source == "rgen/test2"}
checkAnnotation(anno, "rgen/test2", {"attrtag2" => "attrvalue2", "attrtag3" => "attrvalue3"})
anno = eAttr.eAnnotations.find{|a| a.source == nil}
checkAnnotation(anno, nil, {"attrtag" => "attrval"})
eRef = eClass.eReferences.find{|r| !r.eOpposite}
assert_equal 2, eRef.eAnnotations.size
anno = eRef.eAnnotations.find{|a| a.source == "rgen/test3"}
checkAnnotation(anno, "rgen/test3", {"reftag2" => "refvalue2", "reftag3" => "refvalue3"})
anno = eRef.eAnnotations.find{|a| a.source == nil}
checkAnnotation(anno, nil, {"reftag" => "refval"})
eRef = eClass.eReferences.find{|r| r.eOpposite}
assert_equal 1, eRef.eAnnotations.size
anno = eRef.eAnnotations.first
checkAnnotation(anno, nil, {"m2mtag" => "m2mval"})
eRef = eRef.eOpposite
assert_equal 1, eRef.eAnnotations.size
anno = eRef.eAnnotations.first
checkAnnotation(anno, nil, {"opposite_m2mtag" => "opposite_m2mval"})
end
def checkAnnotation(anno, source, hash)
assert anno.is_a?(RGen::ECore::EAnnotation)
assert_equal source, anno.source
assert_equal hash.size, anno.details.size
hash.each_pair do |k, v|
detail = anno.details.find{|d| d.key == k}
assert detail.is_a?(RGen::ECore::EStringToStringMapEntry)
assert_equal v, detail.value
end
end
def test_ecore_identity
subPackage = mm::SomePackage::SubPackage.ecore
assert_equal subPackage.eClassifiers.first.object_id, mm::SomePackage::SubPackage::ClassB.ecore.object_id
somePackage = mm::SomePackage.ecore
assert_equal somePackage.eSubpackages.first.object_id, subPackage.object_id
end
def test_proxy
p = RGen::MetamodelBuilder::MMProxy.new("test")
assert_equal "test", p.targetIdentifier
p.targetIdentifier = 123
assert_equal 123, p.targetIdentifier
p.data = "additional info"
assert_equal "additional info", p.data
q = RGen::MetamodelBuilder::MMProxy.new("ident", "data")
assert_equal "data", q.data
end
def test_proxies_has_one
e = mm::HasOneTestClass.new
proxy = RGen::MetamodelBuilder::MMProxy.new
e.classA = proxy
assert_equal proxy, e.classA
a = mm::ClassA.new
# displace proxy
e.classA = a
assert_equal a, e.classA
# displace by proxy
e.classA = proxy
assert_equal proxy, e.classA
end
def test_proxies_has_many
e = mm::HasManyTestClass.new
proxy = RGen::MetamodelBuilder::MMProxy.new
e.addClassA(proxy)
assert_equal [proxy], e.classA
# again
e.addClassA(proxy)
assert_equal [proxy], e.classA
proxy2 = RGen::MetamodelBuilder::MMProxy.new
e.addClassA(proxy2)
assert_equal [proxy, proxy2], e.classA
e.removeClassA(proxy)
assert_equal [proxy2], e.classA
# again
e.removeClassA(proxy)
assert_equal [proxy2], e.classA
e.removeClassA(proxy2)
assert_equal [], e.classA
end
def test_proxies_one_to_one
ea = mm::AClassOO.new
eb = mm::BClassOO.new
proxy1 = RGen::MetamodelBuilder::MMProxy.new
proxy2 = RGen::MetamodelBuilder::MMProxy.new
ea.bClass = proxy1
eb.aClass = proxy2
assert_equal proxy1, ea.bClass
assert_equal proxy2, eb.aClass
# displace proxies
ea.bClass = eb
assert_equal eb, ea.bClass
assert_equal ea, eb.aClass
# displace by proxy
ea.bClass = proxy1
assert_equal proxy1, ea.bClass
assert_nil eb.aClass
end
def test_proxies_one_to_many
eo = mm::OneClass.new
em = mm::ManyClass.new
proxy1 = RGen::MetamodelBuilder::MMProxy.new
proxy2 = RGen::MetamodelBuilder::MMProxy.new
eo.addManyClasses(proxy1)
assert_equal [proxy1], eo.manyClasses
em.oneClass = proxy2
assert_equal proxy2, em.oneClass
# displace proxies at many side
# adding em will set em.oneClass to eo and displace the proxy from em.oneClass
eo.addManyClasses(em)
assert_equal [proxy1, em], eo.manyClasses
assert_equal eo, em.oneClass
eo.removeManyClasses(proxy1)
assert_equal [em], eo.manyClasses
assert_equal eo, em.oneClass
# displace by proxy
em.oneClass = proxy2
assert_equal [], eo.manyClasses
assert_equal proxy2, em.oneClass
# displace proxies at one side
em.oneClass = eo
assert_equal [em], eo.manyClasses
assert_equal eo, em.oneClass
end
def test_proxies_many_to_many
e1 = mm::AClassMM.new
e2 = mm::BClassMM.new
proxy1 = RGen::MetamodelBuilder::MMProxy.new
proxy2 = RGen::MetamodelBuilder::MMProxy.new
e1.addBClasses(proxy1)
e2.addAClasses(proxy2)
assert_equal [proxy1], e1.bClasses
assert_equal [proxy2], e2.aClasses
e1.addBClasses(e2)
assert_equal [proxy1, e2], e1.bClasses
assert_equal [proxy2, e1], e2.aClasses
e1.removeBClasses(proxy1)
e2.removeAClasses(proxy2)
assert_equal [e2], e1.bClasses
assert_equal [e1], e2.aClasses
end
# Multiplicity agnostic convenience methods
def test_genericAccess
e1 = mm::OneClass.new
e2 = mm::ManyClass.new
e3 = mm::OneClass.new
e4 = mm::ManyClass.new
# use on "many" feature
e1.setOrAddGeneric("manyClasses", e2)
assert_equal [e2], e1.manyClasses
assert_equal [e2], e1.getGeneric("manyClasses")
assert_equal [e2], e1.getGenericAsArray("manyClasses")
# use on "one" feature
e2.setOrAddGeneric("oneClass", e3)
assert_equal e3, e2.oneClass
assert_equal e3, e2.getGeneric("oneClass")
assert_equal [e3], e2.getGenericAsArray("oneClass")
assert_nil e4.getGeneric("oneClass")
assert_equal [], e4.getGenericAsArray("oneClass")
end
def test_setNilOrRemoveGeneric
e1 = mm::OneClass.new
e2 = mm::ManyClass.new
e3 = mm::OneClass.new
# use on "many" feature
e1.addManyClasses(e2)
assert_equal [e2], e1.manyClasses
e1.setNilOrRemoveGeneric("manyClasses", e2)
assert_equal [], e1.manyClasses
# use on "one" feature
e2.oneClass = e3
assert_equal e3, e2.oneClass
e2.setNilOrRemoveGeneric("oneClass", e3)
assert_nil e2.oneClass
end
def test_setNilOrRemoveAllGeneric
e1 = mm::OneClass.new
e2 = mm::ManyClass.new
e3 = mm::OneClass.new
e4 = mm::ManyClass.new
# use on "many" feature
e1.addManyClasses(e2)
e1.addManyClasses(e4)
assert_equal [e2, e4], e1.manyClasses
e1.setNilOrRemoveAllGeneric("manyClasses")
assert_equal [], e1.manyClasses
# use on "one" feature
e2.oneClass = e3
assert_equal e3, e2.oneClass
e2.setNilOrRemoveAllGeneric("oneClass")
assert_nil e2.oneClass
end
def test_abstract
err = assert_raise StandardError do
mm::AbstractClass.new
end
assert_match /Class (\w+::)+AbstractClass is abstract/, err.message
end
module BadDefaultValueLiteralContainer
Test1 = proc do
class BadClass < RGen::MetamodelBuilder::MMBase
has_attr 'integerWithDefault', Integer, :defaultValueLiteral => "1.1"
end
end
Test2 = proc do
class BadClass < RGen::MetamodelBuilder::MMBase
has_attr 'integerWithDefault', Integer, :defaultValueLiteral => "x"
end
end
Test3 = proc do
class BadClass < RGen::MetamodelBuilder::MMBase
has_attr 'boolWithDefault', Boolean, :defaultValueLiteral => "1"
end
end
Test4 = proc do
class BadClass < RGen::MetamodelBuilder::MMBase
has_attr 'floatWithDefault', Float, :defaultValueLiteral => "1"
end
end
Test5 = proc do
class BadClass < RGen::MetamodelBuilder::MMBase
has_attr 'floatWithDefault', Float, :defaultValueLiteral => "true"
end
end
Test6 = proc do
class BadClass < RGen::MetamodelBuilder::MMBase
kindType = RGen::MetamodelBuilder::DataTypes::Enum.new([:simple, :extended])
has_attr 'enumWithDefault', kindType, :defaultValueLiteral => "xxx"
end
end
Test7 = proc do
class BadClass < RGen::MetamodelBuilder::MMBase
kindType = RGen::MetamodelBuilder::DataTypes::Enum.new([:simple, :extended])
has_attr 'enumWithDefault', kindType, :defaultValueLiteral => "7"
end
end
Test8 = proc do
class BadClass < RGen::MetamodelBuilder::MMBase
has_attr 'longWithDefault', Integer, :defaultValueLiteral => "1.1"
end
end
end
def test_bad_default_value_literal
err = assert_raise StandardError do
BadDefaultValueLiteralContainer::Test1.call
end
assert_equal "Property integerWithDefault can not take value 1.1, expected an Integer", err.message
err = assert_raise StandardError do
BadDefaultValueLiteralContainer::Test2.call
end
assert_equal "Property integerWithDefault can not take value x, expected an Integer", err.message
err = assert_raise StandardError do
BadDefaultValueLiteralContainer::Test3.call
end
assert_equal "Property boolWithDefault can not take value 1, expected true or false", err.message
err = assert_raise StandardError do
BadDefaultValueLiteralContainer::Test4.call
end
assert_equal "Property floatWithDefault can not take value 1, expected a Float", err.message
err = assert_raise StandardError do
BadDefaultValueLiteralContainer::Test5.call
end
assert_equal "Property floatWithDefault can not take value true, expected a Float", err.message
err = assert_raise StandardError do
BadDefaultValueLiteralContainer::Test6.call
end
assert_equal "Property enumWithDefault can not take value xxx, expected one of :simple, :extended", err.message
err = assert_raise StandardError do
BadDefaultValueLiteralContainer::Test7.call
end
assert_equal "Property enumWithDefault can not take value 7, expected one of :simple, :extended", err.message
err = assert_raise StandardError do
BadDefaultValueLiteralContainer::Test8.call
end
assert_equal "Property longWithDefault can not take value 1.1, expected an Integer", err.message
end
def test_isset_set_to_nil
e = mm::SimpleClass.new
assert_respond_to e, :name
assert !e.eIsSet(:name)
assert !e.eIsSet("name")
e.name = nil
assert e.eIsSet(:name)
end
def test_isset_set_to_default
e = mm::SimpleClass.new
assert !e.eIsSet(:stringWithDefault)
# set the default value
e.name = "xtest"
assert e.eIsSet(:name)
end
def test_isset_many_add
e = mm::ManyAttrClass.new
assert_equal [], e.literals
assert !e.eIsSet(:literals)
e.addLiterals("x")
assert e.eIsSet(:literals)
end
def test_isset_many_remove
e = mm::ManyAttrClass.new
assert_equal [], e.literals
assert !e.eIsSet(:literals)
# removing a value which is not there
e.removeLiterals("x")
assert e.eIsSet(:literals)
end
def test_isset_ref
ac = mm::AClassOO.new
bc = mm::BClassOO.new
assert !bc.eIsSet(:aClass)
assert !ac.eIsSet(:bClass)
bc.aClass = ac
assert bc.eIsSet(:aClass)
assert ac.eIsSet(:bClass)
end
def test_isset_ref_many
ac = mm::AClassMM.new
bc = mm::BClassMM.new
assert !bc.eIsSet(:aClasses)
assert !ac.eIsSet(:bClasses)
bc.aClasses = [ac]
assert bc.eIsSet(:aClasses)
assert ac.eIsSet(:bClasses)
end
def test_unset_nil
e = mm::SimpleClass.new
e.name = nil
assert e.eIsSet(:name)
e.eUnset(:name)
assert !e.eIsSet(:name)
end
def test_unset_string
e = mm::SimpleClass.new
e.name = "someone"
assert e.eIsSet(:name)
e.eUnset(:name)
assert !e.eIsSet(:name)
end
def test_unset_ref
ac = mm::AClassOO.new
bc = mm::BClassOO.new
bc.aClass = ac
assert bc.eIsSet(:aClass)
assert ac.eIsSet(:bClass)
assert_equal bc, ac.bClass
bc.eUnset(:aClass)
assert_nil bc.aClass
assert_nil ac.bClass
assert !bc.eIsSet(:aClass)
# opposite ref is nil but still "set"
assert ac.eIsSet(:bClass)
end
def test_unset_ref_many
ac = mm::AClassMM.new
bc = mm::BClassMM.new
bc.aClasses = [ac]
assert bc.eIsSet(:aClasses)
assert ac.eIsSet(:bClasses)
assert_equal [bc], ac.bClasses
bc.eUnset(:aClasses)
assert_equal [], bc.aClasses
assert_equal [], ac.bClasses
assert !bc.eIsSet(:aClasses)
# opposite ref is empty but still "set"
assert ac.eIsSet(:bClasses)
end
def test_unset_marshal
e = mm::SimpleClass.new
e.name = "someone"
e.eUnset(:name)
e2 = Marshal.load(Marshal.dump(e))
assert e.object_id != e2.object_id
assert !e2.eIsSet(:name)
end
def test_conainer_one_uni
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainedClass.new
assert_equal [], a.eContents
assert_equal [], a.eAllContents
assert_nil b.eContainer
assert_nil b.eContainingFeature
a.oneChildUni = b
assert_equal a, b.eContainer
assert_equal :oneChildUni, b.eContainingFeature
assert_equal [b], a.eContents
assert_equal [b], a.eAllContents
a.oneChildUni = c
assert_nil b.eContainer
assert_nil b.eContainingFeature
assert_equal a, c.eContainer
assert_equal :oneChildUni, c.eContainingFeature
assert_equal [c], a.eContents
assert_equal [c], a.eAllContents
a.oneChildUni = nil
assert_nil c.eContainer
assert_nil c.eContainingFeature
assert_equal [], a.eContents
assert_equal [], a.eAllContents
end
def test_container_many_uni
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainedClass.new
assert_equal [], a.eContents
assert_equal [], a.eAllContents
a.addManyChildUni(b)
assert_equal a, b.eContainer
assert_equal :manyChildUni, b.eContainingFeature
assert_equal [b], a.eContents
assert_equal [b], a.eAllContents
a.addManyChildUni(c)
assert_equal a, c.eContainer
assert_equal :manyChildUni, c.eContainingFeature
assert_equal [b, c], a.eContents
assert_equal [b, c], a.eAllContents
a.removeManyChildUni(b)
assert_nil b.eContainer
assert_nil b.eContainingFeature
assert_equal a, c.eContainer
assert_equal :manyChildUni, c.eContainingFeature
assert_equal [c], a.eContents
assert_equal [c], a.eAllContents
a.removeManyChildUni(c)
assert_nil c.eContainer
assert_nil c.eContainingFeature
assert_equal [], a.eContents
assert_equal [], a.eAllContents
end
def test_conainer_one_bi
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainerClass.new
d = mm::ContainedClass.new
a.oneChild = b
assert_equal a, b.eContainer
assert_equal :oneChild, b.eContainingFeature
assert_equal [b], a.eContents
assert_equal [b], a.eAllContents
c.oneChild = d
assert_equal c, d.eContainer
assert_equal :oneChild, d.eContainingFeature
assert_equal [d], c.eContents
assert_equal [d], c.eAllContents
a.oneChild = d
assert_nil b.eContainer
assert_nil b.eContainingFeature
assert_equal a, d.eContainer
assert_equal :oneChild, d.eContainingFeature
assert_equal [d], a.eContents
assert_equal [d], a.eAllContents
assert_equal [], c.eContents
assert_equal [], c.eAllContents
end
def test_conainer_one_bi_rev
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainerClass.new
d = mm::ContainedClass.new
a.oneChild = b
assert_equal a, b.eContainer
assert_equal :oneChild, b.eContainingFeature
assert_equal [b], a.eContents
assert_equal [b], a.eAllContents
c.oneChild = d
assert_equal c, d.eContainer
assert_equal :oneChild, d.eContainingFeature
assert_equal [d], c.eContents
assert_equal [d], c.eAllContents
d.parentOne = a
assert_nil b.eContainer
assert_nil b.eContainingFeature
assert_equal a, d.eContainer
assert_equal :oneChild, d.eContainingFeature
assert_equal [d], a.eContents
assert_equal [d], a.eAllContents
assert_equal [], c.eContents
assert_equal [], c.eAllContents
end
def test_conainer_one_bi_nil
a = mm::ContainerClass.new
b = mm::ContainedClass.new
a.oneChild = b
assert_equal a, b.eContainer
assert_equal :oneChild, b.eContainingFeature
assert_equal [b], a.eContents
assert_equal [b], a.eAllContents
a.oneChild = nil
assert_nil b.eContainer
assert_nil b.eContainingFeature
assert_equal [], a.eContents
assert_equal [], a.eAllContents
end
def test_conainer_one_bi_nil_rev
a = mm::ContainerClass.new
b = mm::ContainedClass.new
a.oneChild = b
assert_equal a, b.eContainer
assert_equal :oneChild, b.eContainingFeature
assert_equal [b], a.eContents
assert_equal [b], a.eAllContents
b.parentOne = nil
assert_nil b.eContainer
assert_nil b.eContainingFeature
assert_equal [], a.eContents
assert_equal [], a.eAllContents
end
def test_container_many_bi
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainedClass.new
a.addManyChild(b)
a.addManyChild(c)
assert_equal a, b.eContainer
assert_equal :manyChild, b.eContainingFeature
assert_equal a, c.eContainer
assert_equal :manyChild, c.eContainingFeature
assert_equal [b, c], a.eContents
assert_equal [b, c], a.eAllContents
a.removeManyChild(b)
assert_nil b.eContainer
assert_nil b.eContainingFeature
assert_equal [c], a.eContents
assert_equal [c], a.eAllContents
end
def test_conainer_many_bi_steal
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainedClass.new
d = mm::ContainerClass.new
a.addManyChild(b)
a.addManyChild(c)
assert_equal a, b.eContainer
assert_equal :manyChild, b.eContainingFeature
assert_equal a, c.eContainer
assert_equal :manyChild, c.eContainingFeature
assert_equal [b, c], a.eContents
assert_equal [b, c], a.eAllContents
d.addManyChild(b)
assert_equal d, b.eContainer
assert_equal :manyChild, b.eContainingFeature
assert_equal [c], a.eContents
assert_equal [c], a.eAllContents
assert_equal [b], d.eContents
assert_equal [b], d.eAllContents
end
def test_conainer_many_bi_steal_rev
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainedClass.new
d = mm::ContainerClass.new
a.addManyChild(b)
a.addManyChild(c)
assert_equal a, b.eContainer
assert_equal :manyChild, b.eContainingFeature
assert_equal a, c.eContainer
assert_equal :manyChild, c.eContainingFeature
assert_equal [b, c], a.eContents
assert_equal [b, c], a.eAllContents
b.parentMany = d
assert_equal d, b.eContainer
assert_equal :manyChild, b.eContainingFeature
assert_equal [c], a.eContents
assert_equal [c], a.eAllContents
assert_equal [b], d.eContents
assert_equal [b], d.eAllContents
end
def test_all_contents
a = mm::ContainerClass.new
b = mm::NestedContainerClass.new
c = mm::ContainedClass.new
a.oneChildUni = b
b.oneChildUni = c
assert_equal [b, c], a.eAllContents
end
def test_all_contents_with_block
a = mm::ContainerClass.new
b = mm::NestedContainerClass.new
c = mm::ContainedClass.new
a.oneChildUni = b
b.oneChildUni = c
yielded = []
a.eAllContents do |e|
yielded << e
end
assert_equal [b, c], yielded
end
def test_all_contents_prune
a = mm::ContainerClass.new
b = mm::NestedContainerClass.new
c = mm::ContainedClass.new
a.oneChildUni = b
b.oneChildUni = c
yielded = []
a.eAllContents do |e|
yielded << e
:prune
end
assert_equal [b], yielded
end
def test_container_generic
a = mm::ContainerClass.new
assert_nothing_raised do
a.oneChild = RGen::MetamodelBuilder::MMGeneric.new
end
end
def test_opposite_assoc_on_first_write
ac = mm::OppositeRefAssocA.new
bc = mm::OppositeRefAssocB.new
# no access to 'aClass' or 'bClass' methods before
# test if on-demand metamodel building creates opposite ref association on first write
bc.aClass = ac
assert_equal ac, bc.aClass
assert_equal bc, ac.bClass
end
def test_clear_by_array_assignment
oc1 = mm::OneClass.new
mc1 = mm::ManyClass.new
mc2 = mm::ManyClass.new
mc3 = mm::ManyClass.new
oc1.manyClasses = [mc1, mc2]
assert_equal [mc1, mc2], oc1.manyClasses
oc1.manyClasses = []
assert_equal [], oc1.manyClasses
end
def test_clear_by_array_assignment_uni
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainedClass.new
a.manyChildUni = [b, c]
assert_equal [b, c], a.manyChildUni
a.manyChildUni = []
assert_equal [], a.manyChildUni
end
def test_disconnectContainer_one_uni
a = mm::ContainerClass.new
b = mm::ContainedClass.new
a.oneChildUni = b
b.disconnectContainer
assert_nil a.oneChildUni
end
def test_disconnectContainer_one
a = mm::ContainerClass.new
b = mm::ContainedClass.new
a.oneChild = b
b.disconnectContainer
assert_nil a.oneChild
assert_nil b.parentOne
end
def test_disconnectContainer_many_uni
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainedClass.new
a.addManyChildUni(b)
a.addManyChildUni(c)
b.disconnectContainer
assert_equal [c], a.manyChildUni
end
def test_disconnectContainer_many
a = mm::ContainerClass.new
b = mm::ContainedClass.new
c = mm::ContainedClass.new
a.addManyChild(b)
a.addManyChild(c)
b.disconnectContainer
assert_nil b.parentMany
assert_equal [c], a.manyChild
end
# Duplicate Containment Tests
#
# Testing that no element is contained in two different containers at a time.
# This must also work for uni-directional containments as well as
# for containments via different roles.
# here the bi-dir reference disconnects from the previous container
def test_duplicate_containment_bidir_samerole_one
a1 = mm::ContainerClass.new
a2 = mm::ContainerClass.new
b = mm::ContainedClass.new
a1.oneChild = b
a2.oneChild = b
assert_nil a1.oneChild
end
# here the bi-dir reference disconnects from the previous container
def test_duplicate_containment_bidir_samerole_many
a1 = mm::ContainerClass.new
a2 = mm::ContainerClass.new
b = mm::ContainedClass.new
a1.addManyChild(b)
a2.addManyChild(b)
assert_equal [], a1.manyChild
end
def test_duplicate_containment_unidir_samerole_one
a1 = mm::ContainerClass.new
a2 = mm::ContainerClass.new
b = mm::ContainedClass.new
a1.oneChildUni = b
a2.oneChildUni = b
assert_nil a1.oneChildUni
end
def test_duplicate_containment_unidir_samerole_many
a1 = mm::ContainerClass.new
a2 = mm::ContainerClass.new
b = mm::ContainedClass.new
a1.addManyChildUni(b)
a2.addManyChildUni(b)
assert_equal [], a1.manyChildUni
end
def test_duplicate_containment_bidir_otherrole_one
a1 = mm::ContainerClass.new
a2 = mm::ContainerClass.new
b = mm::ContainedClass.new
a1.oneChild = b
a2.oneChild2 = b
assert_nil a1.oneChild
end
def test_duplicate_containment_bidir_otherrole_many
a1 = mm::ContainerClass.new
a2 = mm::ContainerClass.new
b = mm::ContainedClass.new
a1.addManyChild(b)
a2.addManyChild2(b)
assert_equal [], a1.manyChild
end
def test_duplicate_containment_unidir_otherrole_one
a1 = mm::ContainerClass.new
a2 = mm::ContainerClass.new
b = mm::ContainedClass.new
a1.oneChildUni = b
a2.oneChildUni2 = b
assert_nil a1.oneChildUni
end
def test_duplicate_containment_unidir_otherrole_many
a1 = mm::ContainerClass.new
a2 = mm::ContainerClass.new
b = mm::ContainedClass.new
a1.addManyChildUni(b)
a2.addManyChildUni2(b)
assert_equal [], a1.manyChildUni
end
end
rgen-0.7.0/test/metamodel_from_ecore_test.rb 0000644 0000041 0000041 00000004234 12352210062 021207 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","test")
require 'metamodel_builder_test'
require 'rgen/ecore/ecore_to_ruby'
# this test suite runs all the tests of MetamodelBuilderTest with the TestMetamodel
# replaced by the result of feeding its ecore model through ECoreToRuby
#
class MetamodelFromEcoreTest < MetamodelBuilderTest
# clone the ecore model, because it will be modified below
test_ecore = Marshal.load(Marshal.dump(TestMetamodel.ecore))
# some EEnum types are not hooked into the EPackage because they do not
# appear with a constant assignment in TestMetamodel
# fix this by explicitly assigning the ePackage
# also fix the name of anonymous enums
test_ecore.eClassifiers.find{|c| c.name == "SimpleClass"}.
eAttributes.select{|a| a.name == "kind" || a.name == "kindWithDefault"}.each{|a|
a.eType.name = "KindType"
a.eType.ePackage = test_ecore}
test_ecore.eClassifiers.find{|c| c.name == "ManyAttrClass"}.
eAttributes.select{|a| a.name == "enums"}.each{|a|
a.eType.name = "ABCEnum"
a.eType.ePackage = test_ecore}
MetamodelFromEcore = RGen::ECore::ECoreToRuby.new.create_module(test_ecore)
def mm
MetamodelFromEcore
end
# alternative implementation for dynamic variant
def test_bad_default_value_literal
package = RGen::ECore::EPackage.new(:name => "Package1", :eClassifiers => [
RGen::ECore::EClass.new(:name => "Class1", :eStructuralFeatures => [
RGen::ECore::EAttribute.new(:name => "value", :eType => RGen::ECore::EInt, :defaultValueLiteral => "x")])])
mod = RGen::ECore::ECoreToRuby.new.create_module(package)
obj = mod::Class1.new
# the error is raised only when the feature is lazily constructed
assert_raise StandardError do
obj.value
end
end
# define all the test methods explicitly in the subclass
# otherwise minitest is smart enough to run the tests only in the superclass context
MetamodelBuilderTest.instance_methods.select{|m| m.to_s =~ /^test_/}.each do |m|
next if instance_methods(false).include?(m)
module_eval <<-END
def #{m}
super
end
END
end
end
rgen-0.7.0/test/ea_instantiator_test.rb 0000644 0000041 0000041 00000002117 12352210062 020222 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/environment'
require 'metamodels/uml13_metamodel'
require 'ea_support/ea_support'
require 'transformers/uml13_to_ecore'
require 'testmodel/class_model_checker'
require 'testmodel/object_model_checker'
require 'testmodel/ecore_model_checker'
class EAInstantiatorTest < Test::Unit::TestCase
include Testmodel::ClassModelChecker
include Testmodel::ObjectModelChecker
include Testmodel::ECoreModelChecker
MODEL_DIR = File.join(File.dirname(__FILE__),"testmodel")
def test_instantiator
envUML = RGen::Environment.new
EASupport.instantiateUML13FromXMI11(envUML, MODEL_DIR+"/ea_testmodel.xml")
checkClassModel(envUML)
checkObjectModel(envUML)
envECore = RGen::Environment.new
UML13ToECore.new(envUML, envECore).transform
checkECoreModel(envECore)
end
def test_partial
envUML = RGen::Environment.new
EASupport.instantiateUML13FromXMI11(envUML, MODEL_DIR+"/ea_testmodel_partial.xml")
checkClassModelPartial(envUML)
end
end rgen-0.7.0/test/util/ 0000755 0000041 0000041 00000000000 12352210062 014426 5 ustar www-data www-data rgen-0.7.0/test/util/pattern_matcher_test.rb 0000644 0000041 0000041 00000004776 12352210062 021210 0 ustar www-data www-data $:.unshift(File.dirname(__FILE__)+"/../../lib")
require 'test/unit'
require 'rgen/environment'
require 'rgen/metamodel_builder'
require 'rgen/model_builder'
require 'rgen/util/pattern_matcher'
class PatternMatcherTest < Test::Unit::TestCase
module TestMM
extend RGen::MetamodelBuilder::ModuleExtension
class Node < RGen::MetamodelBuilder::MMBase
has_attr 'name', String
contains_many 'children', Node, 'parent'
end
end
def modelA
env = RGen::Environment.new
RGen::ModelBuilder.build(TestMM, env) do
node "A" do
node "AA"
end
node "B" do
node "B1"
node "B2"
node "B3"
end
node "C" do
node "C1"
node "C2"
end
node "D" do
node "DD"
end
end
env
end
def test_simple
matcher = RGen::Util::PatternMatcher.new
matcher.add_pattern("simple") do |env, c|
TestMM::Node.new(:name => "A", :children => [
TestMM::Node.new(:name => "AA")])
end
matcher.add_pattern("bad") do |env, c|
TestMM::Node.new(:name => "X")
end
env = modelA
match = matcher.find_pattern(env, "simple")
assert_not_nil match
assert_equal "A", match.root.name
assert_equal env.find(:class => TestMM::Node, :name => "A").first.object_id, match.root.object_id
assert_equal 2, match.elements.size
assert_equal [nil], match.bound_values
assert_nil matcher.find_pattern(env, "bad")
end
def test_value_binding
matcher = RGen::Util::PatternMatcher.new
matcher.add_pattern("single_child") do |env, name, child|
TestMM::Node.new(:name => name, :children => [ child ])
end
matcher.add_pattern("double_child") do |env, name, child1, child2|
TestMM::Node.new(:name => name, :children => [ child1, child2 ])
end
matcher.add_pattern("child_pattern") do |env, child_name|
TestMM::Node.new(:name => "A", :children => [
TestMM::Node.new(:name => child_name)])
end
env = modelA
match = matcher.find_pattern(env, "single_child")
assert_not_nil match
assert_equal "A", match.root.name
assert_equal "AA", match.bound_values[1].name
match = matcher.find_pattern(env, "single_child", "D")
assert_not_nil match
assert_equal "D", match.root.name
assert_equal "DD", match.bound_values[0].name
match = matcher.find_pattern(env, "double_child")
assert_not_nil match
assert_equal "C", match.root.name
match = matcher.find_pattern(env, "child_pattern")
assert_not_nil match
assert_equal ["AA"], match.bound_values
end
end
rgen-0.7.0/test/util/file_cache_map_test/ 0000755 0000041 0000041 00000000000 12352210062 020364 5 ustar www-data www-data rgen-0.7.0/test/util/file_cache_map_test/testdir/ 0000755 0000041 0000041 00000000000 12352210062 022042 5 ustar www-data www-data rgen-0.7.0/test/util/file_cache_map_test/testdir/fileA 0000644 0000041 0000041 00000000010 12352210062 022774 0 ustar www-data www-data somedata rgen-0.7.0/test/util/file_cache_map_test.rb 0000644 0000041 0000041 00000006270 12352210062 020716 0 ustar www-data www-data $:.unshift(File.dirname(__FILE__)+"/../../lib")
require 'test/unit'
require 'fileutils'
require 'rgen/util/file_cache_map'
class FileCacheMapTest < Test::Unit::TestCase
TestDir = File.dirname(__FILE__)+"/file_cache_map_test/testdir"
def setup
FileUtils.rm_r(Dir[TestDir+"/*"])
# * doesn't include dot files
FileUtils.rm_r(Dir[TestDir+"/.cache"])
@cm = RGen::Util::FileCacheMap.new(".cache", ".test")
end
def test_nocache
reasons = []
assert_equal(:invalid, @cm.load_data(TestDir+"/fileA", :invalidation_reasons => reasons))
assert_equal [:no_cachefile], reasons
end
def test_storeload
keyFile = TestDir+"/fileA"
File.open(keyFile, "w") {|f| f.write("somedata")}
@cm.store_data(keyFile, "valuedata")
assert(File.exist?(TestDir+"/.cache/fileA.test"))
assert_equal("valuedata", @cm.load_data(keyFile))
end
def test_storeload_subdir
keyFile = TestDir+"/subdir/fileA"
FileUtils.mkdir(TestDir+"/subdir")
File.open(keyFile, "w") {|f| f.write("somedata")}
@cm.store_data(keyFile, "valuedata")
assert(File.exist?(TestDir+"/subdir/.cache/fileA.test"))
assert_equal("valuedata", @cm.load_data(keyFile))
end
def test_storeload_postfix
keyFile = TestDir+"/fileB.txt"
File.open(keyFile, "w") {|f| f.write("somedata")}
@cm.store_data(keyFile, "valuedata")
assert(File.exist?(TestDir+"/.cache/fileB.txt.test"))
assert_equal("valuedata", @cm.load_data(keyFile))
end
def test_storeload_empty
keyFile = TestDir+"/fileA"
File.open(keyFile, "w") {|f| f.write("")}
@cm.store_data(keyFile, "valuedata")
assert(File.exist?(TestDir+"/.cache/fileA.test"))
assert_equal("valuedata", @cm.load_data(keyFile))
end
def test_corruptcache
keyFile = TestDir+"/fileA"
File.open(keyFile, "w") {|f| f.write("somedata")}
@cm.store_data(keyFile, "valuedata")
File.open(TestDir+"/.cache/fileA.test","a") {|f| f.write("more data")}
reasons = []
assert_equal(:invalid, @cm.load_data(keyFile, :invalidation_reasons => reasons))
assert_equal [:cachefile_corrupted], reasons
end
def test_changedcontent
keyFile = TestDir+"/fileA"
File.open(keyFile, "w") {|f| f.write("somedata")}
@cm.store_data(keyFile, "valuedata")
File.open(keyFile, "a") {|f| f.write("more data")}
reasons = []
assert_equal(:invalid, @cm.load_data(keyFile, :invalidation_reasons => reasons))
assert_equal [:keyfile_changed], reasons
end
def test_versioninfo
keyFile = TestDir+"/fileA"
File.open(keyFile, "w") {|f| f.write("somedata")}
@cm.version_info = "123"
@cm.store_data(keyFile, "valuedata")
assert(File.exist?(TestDir+"/.cache/fileA.test"))
assert_equal("valuedata", @cm.load_data(keyFile))
end
def test_changed_version
keyFile = TestDir+"/fileA"
File.open(keyFile, "w") {|f| f.write("somedata")}
@cm.version_info = "123"
@cm.store_data(keyFile, "valuedata")
@cm.version_info = "456"
reasons = []
assert_equal(:invalid, @cm.load_data(keyFile, :invalidation_reasons => reasons))
assert_equal [:keyfile_changed], reasons
end
end
rgen-0.7.0/test/xml_instantiator_test.rb 0000644 0000041 0000041 00000011354 12352210062 020440 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/instantiator/default_xml_instantiator'
require 'rgen/environment'
require 'rgen/util/model_dumper'
require 'xml_instantiator_test/simple_xmi_ecore_instantiator'
require 'xml_instantiator_test/simple_ecore_model_checker'
module EmptyMM
end
module DefaultMM
module MNS
class Room < RGen::MetamodelBuilder::MMBase; end
end
class Person < RGen::MetamodelBuilder::MMBase; end
Person.one_to_one 'personalRoom', MNS::Room, 'inhabitant'
end
class XMLInstantiatorTest < Test::Unit::TestCase
XML_DIR = File.join(File.dirname(__FILE__),"testmodel")
include RGen::Util::ModelDumper
class MyInstantiator < RGen::Instantiator::DefaultXMLInstantiator
map_tag_ns "testmodel.org/myNamespace", DefaultMM::MNS
def class_name(str)
camelize(str)
end
# resolve :type do
# @env.find(:xmi_id => getType).first
# end
resolve_by_id :personalRoom, :id => :getId, :src => :room
end
class PruneTestInstantiator < RGen::Instantiator::NodebasedXMLInstantiator
attr_reader :max_depth
set_prune_level 2
def initialize(env)
super(env)
@max_depth = 0
end
def on_descent(node)
end
def on_ascent(node)
calc_max_depth(node, 0)
end
def calc_max_depth(node, offset)
if node.children.nil? || node.children.size == 0
@max_depth = offset if offset > @max_depth
else
node.children.each do |c|
calc_max_depth(c, offset+1)
end
end
end
end
module PruneTestMM
end
def test_pruning
env = RGen::Environment.new
# prune level 2 is set in the class body
inst = PruneTestInstantiator.new(env)
inst.instantiate_file(File.join(XML_DIR,"manual_testmodel.xml"))
assert_equal 2, inst.max_depth
PruneTestInstantiator.set_prune_level(0)
inst = PruneTestInstantiator.new(env)
inst.instantiate_file(File.join(XML_DIR,"manual_testmodel.xml"))
assert_equal 5, inst.max_depth
PruneTestInstantiator.set_prune_level(1)
inst = PruneTestInstantiator.new(env)
inst.instantiate_file(File.join(XML_DIR,"manual_testmodel.xml"))
assert_equal 1, inst.max_depth
end
def test_custom
env = RGen::Environment.new
inst = MyInstantiator.new(env, DefaultMM, true)
inst.instantiate_file(File.join(XML_DIR,"manual_testmodel.xml"))
house = env.find(:class => DefaultMM::MNS::House).first
assert_not_nil house
assert_equal 2, house.room.size
rooms = env.find(:class => DefaultMM::MNS::Room)
assert_equal 2, rooms.size
assert_equal 0, (house.room - rooms).size
rooms.each {|r| assert r.parent == house}
tomsRoom = rooms.select{|r| r.name == "TomsRoom"}.first
assert_not_nil tomsRoom
persons = env.find(:class => DefaultMM::Person)
assert_equal 4, persons.size
tom = persons.select{|p| p.name == "Tom"}.first
assert_not_nil tom
assert tom.personalRoom == tomsRoom
mpns = env.find(:class => DefaultMM::MultiPartName)
assert mpns.first.respond_to?("insideMultiPart")
end
def test_default
env = RGen::Environment.new
inst = RGen::Instantiator::DefaultXMLInstantiator.new(env, EmptyMM, true)
inst.instantiate_file(File.join(XML_DIR,"manual_testmodel.xml"))
house = env.find(:class => EmptyMM::MNS_House).first
assert_not_nil house
assert_equal 2, house.mNS_Room.size
assert_equal "before kitchen", remove_whitespace_elements(house.chardata)[0].strip
assert_equal "after kitchen", remove_whitespace_elements(house.chardata)[1].strip
assert_equal "after toms room", remove_whitespace_elements(house.chardata)[2].strip
rooms = env.find(:class => EmptyMM::MNS_Room)
assert_equal 2, rooms.size
assert_equal 0, (house.mNS_Room - rooms).size
rooms.each {|r| assert r.parent == house}
tomsRoom = rooms.select{|r| r.name == "TomsRoom"}.first
assert_not_nil tomsRoom
assert_equal "within toms room", remove_whitespace_elements(tomsRoom.chardata)[0]
persons = env.find(:class => EmptyMM::Person)
assert_equal 4, persons.size
tom = persons.select{|p| p.name == "Tom"}.first
assert_not_nil tom
end
def remove_whitespace_elements(elements)
elements.reject{|e| e.strip == ""}
end
include SimpleECoreModelChecker
def test_simle_xmi_ecore_instantiator
envECore = RGen::Environment.new
File.open(XML_DIR+"/ea_testmodel.xml") { |f|
SimpleXMIECoreInstantiator.new.instantiateECoreModel(envECore, f.read)
}
checkECoreModel(envECore)
end
end
rgen-0.7.0/test/qualified_name_resolver_test.rb 0000644 0000041 0000041 00000007372 12352210062 021732 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/metamodel_builder'
require 'rgen/instantiator/qualified_name_resolver'
class QualifiedNameResolverTest < Test::Unit::TestCase
class TestNode < RGen::MetamodelBuilder::MMBase
has_attr 'name', String
has_one 'nextSibling', TestNode
contains_many 'children', TestNode, "parent"
end
class TestNode2 < RGen::MetamodelBuilder::MMBase
has_attr 'cname', String
has_one 'nextSibling', TestNode2
contains_many 'children', TestNode2, "parent"
end
class TestNode3 < RGen::MetamodelBuilder::MMBase
has_attr 'name', String
contains_one 'child', TestNode3, "parent"
end
def testModel
[TestNode.new(:name => "Root1", :children => [
TestNode.new(:name => "Sub11"),
TestNode.new(:name => "Sub12", :children => [
TestNode.new(:name => "Sub121")])]),
TestNode.new(:name => "Root2", :children => [
TestNode.new(:name => "Sub21", :children => [
TestNode.new(:name => "Sub211")])]),
TestNode.new(:name => "Root3"),
TestNode.new(:name => "Root3")
]
end
def testModel2
[TestNode2.new(:cname => "Root1", :children => [
TestNode2.new(:cname => "Sub11")])]
end
def testModel3
[TestNode3.new(:name => "Root1", :child =>
TestNode3.new(:name => "Sub11", :child =>
TestNode3.new(:name => "Sub111")))]
end
def test_customNameAttribute
model = testModel2
res = RGen::Instantiator::QualifiedNameResolver.new(model, :nameAttribute => "cname")
assert_equal model[0], res.resolveIdentifier("/Root1")
assert_equal model[0].children[0], res.resolveIdentifier("/Root1/Sub11")
end
def test_customSeparator
model = testModel
res = RGen::Instantiator::QualifiedNameResolver.new(model, :separator => "|")
assert_equal model[0], res.resolveIdentifier("|Root1")
assert_nil res.resolveIdentifier("/Root1")
assert_equal model[0].children[0], res.resolveIdentifier("|Root1|Sub11")
end
def test_noLeadingSeparator
model = testModel
res = RGen::Instantiator::QualifiedNameResolver.new(model, :leadingSeparator => false)
assert_equal model[0], res.resolveIdentifier("Root1")
assert_nil res.resolveIdentifier("/Root1")
assert_equal model[0].children[0], res.resolveIdentifier("Root1/Sub11")
end
def test_resolve
model = testModel
res = RGen::Instantiator::QualifiedNameResolver.new(model)
assert_equal model[0], res.resolveIdentifier("/Root1")
# again
assert_equal model[0], res.resolveIdentifier("/Root1")
assert_equal model[0].children[0], res.resolveIdentifier("/Root1/Sub11")
# again
assert_equal model[0].children[0], res.resolveIdentifier("/Root1/Sub11")
assert_equal model[0].children[1], res.resolveIdentifier("/Root1/Sub12")
assert_equal model[0].children[1].children[0], res.resolveIdentifier("/Root1/Sub12/Sub121")
assert_equal model[1], res.resolveIdentifier("/Root2")
assert_equal model[1].children[0], res.resolveIdentifier("/Root2/Sub21")
assert_equal model[1].children[0].children[0], res.resolveIdentifier("/Root2/Sub21/Sub211")
# duplicate name yields two result elements
assert_equal [model[2], model[3]], res.resolveIdentifier("/Root3")
assert_equal nil, res.resolveIdentifier("/RootX")
assert_equal nil, res.resolveIdentifier("/Root1/SubX")
end
def test_oneChild
model = testModel3
res = RGen::Instantiator::QualifiedNameResolver.new(model)
assert_equal model[0], res.resolveIdentifier("/Root1")
assert_equal model[0].child, res.resolveIdentifier("/Root1/Sub11")
assert_equal model[0].child.child, res.resolveIdentifier("/Root1/Sub11/Sub111")
end
end
rgen-0.7.0/test/model_fragment_test.rb 0000644 0000041 0000041 00000001331 12352210062 020016 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/metamodel_builder'
require 'rgen/fragment/model_fragment'
class ModelFragmentTest < Test::Unit::TestCase
module TestMetamodel
extend RGen::MetamodelBuilder::ModuleExtension
class SimpleClass < RGen::MetamodelBuilder::MMBase
has_attr 'name', String
contains_many 'subclass', SimpleClass, 'parent'
end
end
def test_elements
root = TestMetamodel::SimpleClass.new(:name => "parent",
:subclass => [TestMetamodel::SimpleClass.new(:name => "child")])
frag = RGen::Fragment::ModelFragment.new("location")
frag.set_root_elements([root])
assert_equal 2, frag.elements.size
end
end
rgen-0.7.0/test/ecore_self_test.rb 0000644 0000041 0000041 00000003744 12352210062 017153 0 ustar www-data www-data $:.unshift File.join(File.dirname(__FILE__),"..","lib")
require 'test/unit'
require 'rgen/ecore/ecore'
require 'rgen/array_extensions'
class ECoreSelfTest < Test::Unit::TestCase
include RGen::ECore
def test_simple
assert_equal \
%w(lowerBound ordered unique upperBound many required eType).sort,
ETypedElement.ecore.eStructuralFeatures.name.sort
assert_equal \
EClassifier.ecore,
ETypedElement.ecore.eStructuralFeatures.find{|f| f.name=="eType"}.eType
assert_equal %w(ENamedElement), ETypedElement.ecore.eSuperTypes.name
assert_equal \
EModelElement.ecore,
EModelElement.ecore.eStructuralFeatures.find{|f| f.name=="eAnnotations"}.eOpposite.eType
assert_equal \
%w(eType),
ETypedElement.ecore.eReferences.name
assert_equal \
%w(lowerBound ordered unique upperBound many required).sort,
ETypedElement.ecore.eAttributes.name.sort
assert RGen::ECore.ecore.is_a?(EPackage)
assert_equal "ECore", RGen::ECore.ecore.name
assert_equal "RGen", RGen::ECore.ecore.eSuperPackage.name
assert_equal %w(ECore), RGen.ecore.eSubpackages.name
assert_equal\
%w(EObject EModelElement EAnnotation ENamedElement ETypedElement
EStructuralFeature EAttribute EClassifier EDataType EEnum EEnumLiteral EFactory
EOperation EPackage EParameter EReference EStringToStringMapEntry EClass
ETypeArgument EGenericType).sort,
RGen::ECore.ecore.eClassifiers.name.sort
assert_equal "false", EAttribute.ecore.eAllAttributes.
find{|a|a.name == "derived"}.defaultValueLiteral
assert_equal false, EAttribute.ecore.eAllAttributes.
find{|a|a.name == "derived"}.defaultValue
assert_nil EAttribute.ecore.eAllAttributes.
find{|a|a.name == "defaultValueLiteral"}.defaultValueLiteral
assert_nil EAttribute.ecore.eAllAttributes.
find{|a|a.name == "defaultValueLiteral"}.defaultValue
end
end
rgen-0.7.0/test/model_builder/ 0000755 0000041 0000041 00000000000 12352210062 016257 5 ustar www-data www-data rgen-0.7.0/test/model_builder/reference_resolver_test.rb 0000644 0000041 0000041 00000012011 12352210062 023515 0 ustar www-data www-data $:.unshift File.dirname(__FILE__)+"/../lib"
require 'test/unit'
require 'rgen/metamodel_builder'
require 'rgen/model_builder/reference_resolver'
class ReferenceResolverTest < Test::Unit::TestCase
class ClassA < RGen::MetamodelBuilder::MMBase
has_attr "name"
end
class ClassB < RGen::MetamodelBuilder::MMBase
has_attr "name"
end
class ClassC < RGen::MetamodelBuilder::MMBase
has_attr "name"
end
ClassA.contains_many 'childB', ClassB, 'parentA'
ClassB.contains_many 'childC', ClassC, 'parentB'
ClassA.has_one 'refC', ClassC
ClassB.has_one 'refC', ClassC
ClassC.has_many 'refCs', ClassC
ClassC.has_one 'refA', ClassA
ClassC.has_one 'refB', ClassB
def testModel
a1 = ClassA.new(:name => "a1")
a2 = ClassA.new(:name => "a2")
b1 = ClassB.new(:name => "b1", :parentA => a1)
b2 = ClassB.new(:name => "b2", :parentA => a1)
c1 = ClassC.new(:name => "c1", :parentB => b1)
c2 = ClassC.new(:name => "c2", :parentB => b1)
c3 = ClassC.new(:name => "c3", :parentB => b1)
[a1, a2, b1, b2, c1, c2, c3]
end
def setElementNames(resolver, elements)
elements.each do |e|
resolver.setElementName(e, e.name)
end
end
def createJob(hash)
raise "Invalid arguments" unless \
hash.is_a?(Hash) && (hash.keys & [:receiver, :reference, :namespace, :string]).size == 4
RGen::ModelBuilder::ReferenceResolver::ResolverJob.new(
hash[:receiver], hash[:reference], hash[:namespace], hash[:string])
end
def test_resolve_same_namespace
a1, a2, b1, b2, c1, c2, c3 = testModel
toplevelNamespace = [a1, a2]
resolver = RGen::ModelBuilder::ReferenceResolver.new
setElementNames(resolver, [a1, a2, b1, b2, c1, c2, c3])
resolver.addJob(createJob(
:receiver => c2,
:reference => ClassC.ecore.eReferences.find{|r| r.name == "refCs"},
:namespace => b1,
:string => "c1"))
resolver.addJob(createJob(
:receiver => b2,
:reference => ClassB.ecore.eReferences.find{|r| r.name == "refC"},
:namespace => a1,
:string => "b1.c1"))
resolver.addJob(createJob(
:receiver => a2,
:reference => ClassA.ecore.eReferences.find{|r| r.name == "refC"},
:namespace => nil,
:string => "a1.b1.c1"))
resolver.resolve(toplevelNamespace)
assert_equal [c1], c2.refCs
assert_equal c1, b2.refC
assert_equal c1, a2.refC
end
def test_resolve_parent_namespace
a1, a2, b1, b2, c1, c2, c3 = testModel
toplevelNamespace = [a1, a2]
resolver = RGen::ModelBuilder::ReferenceResolver.new
setElementNames(resolver, [a1, a2, b1, b2, c1, c2, c3])
resolver.addJob(createJob(
:receiver => c2,
:reference => ClassC.ecore.eReferences.find{|r| r.name == "refA"},
:namespace => b1,
:string => "a1"))
resolver.addJob(createJob(
:receiver => c2,
:reference => ClassC.ecore.eReferences.find{|r| r.name == "refB"},
:namespace => b1,
:string => "b1"))
resolver.addJob(createJob(
:receiver => c2,
:reference => ClassC.ecore.eReferences.find{|r| r.name == "refCs"},
:namespace => b1,
:string => "b1.c1"))
resolver.addJob(createJob(
:receiver => c2,
:reference => ClassC.ecore.eReferences.find{|r| r.name == "refCs"},
:namespace => b1,
:string => "a1.b1.c3"))
resolver.resolve(toplevelNamespace)
assert_equal a1, c2.refA
assert_equal b1, c2.refB
assert_equal [c1, c3], c2.refCs
end
def test_resolve_faulty
a1, a2, b1, b2, c1, c2, c3 = testModel
toplevelNamespace = [a1, a2]
resolver = RGen::ModelBuilder::ReferenceResolver.new
setElementNames(resolver, [a1, a2, b1, b2, c1, c2, c3])
resolver.addJob(createJob(
:receiver => c2,
:reference => ClassC.ecore.eReferences.find{|r| r.name == "refCs"},
:namespace => b1,
:string => "b1.c5"))
assert_raise RGen::ModelBuilder::ReferenceResolver::ResolverException do
resolver.resolve(toplevelNamespace)
end
end
def test_ambiguous_prefix
a = ClassA.new(:name => "name1")
b1 = ClassB.new(:name => "name1", :parentA => a)
b2 = ClassB.new(:name => "target", :parentA => a)
c1 = ClassC.new(:name => "name21", :parentB => b1)
c2 = ClassC.new(:name => "name22", :parentB => b1)
toplevelNamespace = [a]
resolver = RGen::ModelBuilder::ReferenceResolver.new
setElementNames(resolver, [a, b1, b2, c1, c2])
resolver.addJob(createJob(
:receiver => c2,
:reference => ClassC.ecore.eReferences.find{|r| r.name == "refCs"},
:namespace => b1,
:string => "name1.name1.name21"))
resolver.addJob(createJob(
:receiver => c2,
:reference => ClassC.ecore.eReferences.find{|r| r.name == "refB"},
:namespace => b1,
:string => "name1.target"))
resolver.resolve(toplevelNamespace)
assert_equal [c1], c2.refCs
assert_equal b2, c2.refB
end
end rgen-0.7.0/test/model_builder/builder_test.rb 0000644 0000041 0000041 00000020502 12352210062 021270 0 ustar www-data www-data $:.unshift File.dirname(__FILE__) + "/../lib"
require 'test/unit'
require 'rgen/ecore/ecore'
require 'rgen/ecore/ecore_builder_methods'
require 'rgen/environment'
require 'rgen/model_builder'
require 'model_builder/statemachine_metamodel'
class ModelBuilderTest < Test::Unit::TestCase
def test_statemachine
result = RGen::ModelBuilder.build(StatemachineMetamodel) do
statemachine "Airconditioner" do
state "Off", :kind => :START
compositeState "On" do
state "Heating" do
transition :as => :outgoingTransition, :targetState => "Cooling",
:statemachine => "Airconditioner"
end
state "Cooling" do
end
end
transition :sourceState => "On.Cooling", :targetState => "On.Heating" do
_using Condition::TimeCondition do
timeCondition :as => :condition, :timeout => 100
end
Condition::TimeCondition.timeCondition :as => :condition, :timeout => 10
end
end
_using Condition do
statemachine "AirconExtension" do
s = state "StartState"
transition :sourceState => s, :targetState => "Airconditioner.Off"
end
end
end
assert result.is_a?(Array)
assert_equal 2, result.size
sm1 = result[0]
assert sm1.is_a?(StatemachineMetamodel::Statemachine)
assert_equal "Airconditioner", sm1.name
assert_equal 2, sm1.state.size
offState = sm1.state[0]
assert offState.is_a?(StatemachineMetamodel::State)
assert_equal "Off", offState.name
assert_equal :START, offState.kind
onState = sm1.state[1]
assert onState.is_a?(StatemachineMetamodel::CompositeState)
assert_equal "On", onState.name
assert_equal 2, onState.state.size
hState = onState.state[0]
assert hState.is_a?(StatemachineMetamodel::State)
assert_equal "Heating", hState.name
cState = onState.state[1]
assert cState.is_a?(StatemachineMetamodel::State)
assert_equal "Cooling", cState.name
assert_equal 1, hState.outgoingTransition.size
hOutTrans = hState.outgoingTransition[0]
assert hOutTrans.is_a?(StatemachineMetamodel::Transition)
assert_equal cState, hOutTrans.targetState
assert_equal sm1, hOutTrans.statemachine
assert_equal 1, hState.incomingTransition.size
hInTrans = hState.incomingTransition[0]
assert hInTrans.is_a?(StatemachineMetamodel::Transition)
assert_equal cState, hInTrans.sourceState
assert_equal sm1, hInTrans.statemachine
assert_equal 2, hInTrans.condition.size
assert hInTrans.condition[0].is_a?(StatemachineMetamodel::Condition::TimeCondition::TimeCondition)
assert_equal 100, hInTrans.condition[0].timeout
assert hInTrans.condition[1].is_a?(StatemachineMetamodel::Condition::TimeCondition::TimeCondition)
assert_equal 10, hInTrans.condition[1].timeout
sm2 = result[1]
assert sm2.is_a?(StatemachineMetamodel::Statemachine)
assert_equal "AirconExtension", sm2.name
assert_equal 1, sm2.state.size
sState = sm2.state[0]
assert sState.is_a?(StatemachineMetamodel::State)
assert_equal "StartState", sState.name
assert_equal 1, sState.outgoingTransition.size
assert sState.outgoingTransition[0].is_a?(StatemachineMetamodel::Transition)
assert_equal offState, sState.outgoingTransition[0].targetState
assert_equal sm2, sState.outgoingTransition[0].statemachine
end
def test_dynamic
numStates = 5
env = RGen::Environment.new
result = RGen::ModelBuilder.build(StatemachineMetamodel, env) do
sm = statemachine "SM#{numStates}" do
(1..numStates).each do |i|
state "State#{i}" do
transition :as => :outgoingTransition, :targetState => "State#{i < numStates ? i+1 : 1}",
:statemachine => sm
end
end
end
end
assert_equal 11, env.elements.size
assert_equal "SM5", result[0].name
state = result[0].state.first
assert_equal "State1", state.name
state = state.outgoingTransition.first.targetState
assert_equal "State2", state.name
state = state.outgoingTransition.first.targetState
assert_equal "State3", state.name
state = state.outgoingTransition.first.targetState
assert_equal "State4", state.name
state = state.outgoingTransition.first.targetState
assert_equal "State5", state.name
assert_equal result[0].state[0], state.outgoingTransition.first.targetState
end
def test_multiref
result = RGen::ModelBuilder.build(StatemachineMetamodel) do
a = transition
transition "b"
transition "c"
state :outgoingTransition => [a, "b", "c"]
end
assert result[0].is_a?(StatemachineMetamodel::Transition)
assert result[1].is_a?(StatemachineMetamodel::Transition)
assert !result[1].respond_to?(:name)
assert result[2].is_a?(StatemachineMetamodel::Transition)
assert !result[2].respond_to?(:name)
state = result[3]
assert state.is_a?(StatemachineMetamodel::State)
assert_equal result[0], state.outgoingTransition[0]
assert_equal result[1], state.outgoingTransition[1]
assert_equal result[2], state.outgoingTransition[2]
end
module TestMetamodel
extend RGen::MetamodelBuilder::ModuleExtension
# these classes have no name
class TestA < RGen::MetamodelBuilder::MMBase
end
class TestB < RGen::MetamodelBuilder::MMBase
end
class TestC < RGen::MetamodelBuilder::MMBase
end
TestA.contains_many 'testB', TestB, 'testA'
TestC.has_one 'testB', TestB
end
def test_helper_names
result = RGen::ModelBuilder.build(TestMetamodel) do
testA "_a" do
testB "_b"
end
testC :testB => "_a._b"
end
assert result[0].is_a?(TestMetamodel::TestA)
assert result[1].is_a?(TestMetamodel::TestC)
assert_equal result[0].testB[0], result[1].testB
end
def test_ecore
result = RGen::ModelBuilder.build(RGen::ECore, nil, RGen::ECore::ECoreBuilderMethods) do
ePackage "TestPackage1" do
eClass "TestClass1" do
eAttribute "attr1", :eType => RGen::ECore::EString
eAttr "attr2", RGen::ECore::EInt
eBiRef "biRef1", "TestClass2", "testClass1"
contains_1toN 'testClass2', "TestClass2", "tc1Parent"
end
eClass "TestClass2" do
eRef "ref1", "TestClass1"
end
end
end
assert result.is_a?(Array)
assert_equal 1, result.size
p1 = result.first
assert p1.is_a?(RGen::ECore::EPackage)
assert_equal "TestPackage1", p1.name
# TestClass1
class1 = p1.eClassifiers.find{|c| c.name == "TestClass1"}
assert_not_nil class1
assert class1.is_a?(RGen::ECore::EClass)
# TestClass1.attr1
attr1 = class1.eAllAttributes.find{|a| a.name == "attr1"}
assert_not_nil attr1
assert_equal RGen::ECore::EString, attr1.eType
# TestClass1.attr2
attr2 = class1.eAllAttributes.find{|a| a.name == "attr2"}
assert_not_nil attr2
assert_equal RGen::ECore::EInt, attr2.eType
# TestClass2
class2 = p1.eClassifiers.find{|c| c.name == "TestClass2"}
assert_not_nil class2
assert class2.is_a?(RGen::ECore::EClass)
# TestClass2.ref1
ref1 = class2.eAllReferences.find{|a| a.name == "ref1"}
assert_not_nil ref1
assert_equal class1, ref1.eType
# TestClass1.biRef1
biRef1 = class1.eAllReferences.find{|r| r.name == "biRef1"}
assert_not_nil biRef1
assert_equal class2, biRef1.eType
biRef1Opp = class2.eAllReferences.find {|r| r.name == "testClass1"}
assert_not_nil biRef1Opp
assert_equal class1, biRef1Opp.eType
assert_equal biRef1Opp, biRef1.eOpposite
assert_equal biRef1, biRef1Opp.eOpposite
# TestClass1.testClass2
tc2Ref = class1.eAllReferences.find{|r| r.name == "testClass2"}
assert_not_nil tc2Ref
assert_equal class2, tc2Ref.eType
assert tc2Ref.containment
assert_equal -1, tc2Ref.upperBound
tc2RefOpp = class2.eAllReferences.find{|r| r.name == "tc1Parent"}
assert_not_nil tc2RefOpp
assert_equal class1, tc2RefOpp.eType
assert !tc2RefOpp.containment
assert_equal 1, tc2RefOpp.upperBound
end
end rgen-0.7.0/test/model_builder/ecore_internal.rb 0000644 0000041 0000041 00000023427 12352210062 021605 0 ustar www-data www-data ePackage "ECore", :eSuperPackage => "" do
eClass "EObject", :abstract => false, :interface => false, :eSubTypes => ["EAnnotation"], :instanceClassName => "RGen::ECore::EObject"
eClass "EModelElement", :abstract => false, :interface => false, :eSubTypes => ["EAnnotation", "ENamedElement", "ETypeArgument", "EFactory"], :instanceClassName => "RGen::ECore::EModelElement" do
eReference "eAnnotations", :containment => true, :resolveProxies => false, :eOpposite => "EAnnotation.eModelElement", :upperBound => -1, :eType => "EAnnotation"
end
eClass "EAnnotation", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EAnnotation" do
eAttribute "source", :eType => ""
eReference "eModelElement", :eOpposite => "EModelElement.eAnnotations", :eType => "EModelElement"
eReference "details", :containment => true, :resolveProxies => false, :upperBound => -1, :eType => "EStringToStringMapEntry"
eReference "contents", :containment => true, :resolveProxies => false, :upperBound => -1, :eType => "EObject"
eReference "references", :upperBound => -1, :eType => "EObject"
end
eClass "ENamedElement", :abstract => false, :interface => false, :eSubTypes => ["ETypedElement", "EClassifier", "EEnumLiteral", "EPackage"], :instanceClassName => "RGen::ECore::ENamedElement" do
eAttribute "name", :eType => ""
end
eClass "ETypedElement", :abstract => false, :interface => false, :eSubTypes => ["EStructuralFeature", "EOperation", "EParameter"], :instanceClassName => "RGen::ECore::ETypedElement" do
eAttribute "lowerBound", :defaultValueLiteral => "0", :eType => ""
eAttribute "ordered", :defaultValueLiteral => "true", :eType => ""
eAttribute "unique", :defaultValueLiteral => "true", :eType => ""
eAttribute "upperBound", :defaultValueLiteral => "1", :eType => ""
eAttribute "many", :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => ""
eAttribute "required", :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => ""
eReference "eType", :eType => "EClassifier"
end
eClass "EStructuralFeature", :abstract => false, :interface => false, :eSubTypes => ["EAttribute", "EReference"], :instanceClassName => "RGen::ECore::EStructuralFeature" do
eAttribute "changeable", :defaultValueLiteral => "true", :eType => ""
eAttribute "defaultValue", :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => ""
eAttribute "defaultValueLiteral", :eType => ""
eAttribute "derived", :defaultValueLiteral => "false", :eType => ""
eAttribute "transient", :defaultValueLiteral => "false", :eType => ""
eAttribute "unsettable", :defaultValueLiteral => "false", :eType => ""
eAttribute "volatile", :defaultValueLiteral => "false", :eType => ""
eReference "eContainingClass", :eOpposite => "EClass.eStructuralFeatures", :eType => "EClass"
end
eClass "EAttribute", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EAttribute" do
eAttribute "iD", :defaultValueLiteral => "false", :eType => ""
eReference "eAttributeType", :changeable => false, :derived => true, :transient => true, :volatile => true, :lowerBound => 1, :eType => "EDataType"
end
eClass "EClassifier", :abstract => false, :interface => false, :eSubTypes => ["EDataType", "EClass"], :instanceClassName => "RGen::ECore::EClassifier" do
eAttribute "defaultValue", :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => ""
eAttribute "instanceClass", :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => ""
eAttribute "instanceClassName", :eType => ""
eReference "ePackage", :eOpposite => "EPackage.eClassifiers", :eType => "EPackage"
end
eClass "EDataType", :abstract => false, :interface => false, :eSubTypes => ["EGenericType", "EEnum"], :instanceClassName => "RGen::ECore::EDataType" do
eAttribute "serializable", :eType => ""
end
eClass "EGenericType", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EGenericType" do
eReference "eClassifier", :eType => "EDataType"
eReference "eParameter", :eOpposite => "EParameter.eGenericType", :eType => "EParameter"
eReference "eTypeArguments", :containment => true, :eOpposite => "ETypeArgument.eGenericType", :upperBound => -1, :eType => "ETypeArgument"
end
eClass "ETypeArgument", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::ETypeArgument" do
eReference "eClassifier", :eType => "EDataType"
eReference "eGenericType", :eOpposite => "EGenericType.eTypeArguments", :eType => "EGenericType"
end
eClass "EEnum", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EEnum" do
eReference "eLiterals", :containment => true, :resolveProxies => false, :eOpposite => "EEnumLiteral.eEnum", :upperBound => -1, :eType => "EEnumLiteral"
end
eClass "EEnumLiteral", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EEnumLiteral" do
eAttribute "literal", :eType => ""
eAttribute "value", :eType => ""
eReference "eEnum", :eOpposite => "EEnum.eLiterals", :eType => "EEnum"
end
eClass "EFactory", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EFactory" do
eReference "ePackage", :resolveProxies => false, :eOpposite => "EPackage.eFactoryInstance", :transient => true, :lowerBound => 1, :eType => "EPackage"
end
eClass "EOperation", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EOperation" do
eReference "eContainingClass", :eOpposite => "EClass.eOperations", :eType => "EClass"
eReference "eParameters", :containment => true, :resolveProxies => false, :eOpposite => "EParameter.eOperation", :upperBound => -1, :eType => "EParameter"
eReference "eExceptions", :upperBound => -1, :eType => "EClassifier"
end
eClass "EPackage", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EPackage" do
eAttribute "nsPrefix", :eType => ""
eAttribute "nsURI", :eType => ""
eReference "eClassifiers", :containment => true, :eOpposite => "EClassifier.ePackage", :upperBound => -1, :eType => "EClassifier"
eReference "eSubpackages", :containment => true, :eOpposite => "eSuperPackage", :upperBound => -1, :eType => "EPackage"
eReference "eSuperPackage", :eOpposite => "eSubpackages", :eType => "EPackage"
eReference "eFactoryInstance", :eOpposite => "EFactory.ePackage", :eType => "EFactory"
end
eClass "EParameter", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EParameter" do
eReference "eOperation", :eOpposite => "EOperation.eParameters", :eType => "EOperation"
eReference "eGenericType", :containment => true, :eOpposite => "EGenericType.eParameter", :eType => "EGenericType"
end
eClass "EReference", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EReference" do
eAttribute "container", :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => ""
eAttribute "containment", :defaultValueLiteral => "false", :eType => ""
eAttribute "resolveProxies", :defaultValueLiteral => "true", :eType => ""
eReference "eOpposite", :eType => "EReference"
eReference "eReferenceType", :changeable => false, :derived => true, :transient => true, :volatile => true, :lowerBound => 1, :eType => "EClass"
end
eClass "EStringToStringMapEntry", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EStringToStringMapEntry" do
eAttribute "key", :eType => ""
eAttribute "value", :eType => ""
end
eClass "EClass", :abstract => false, :interface => false, :instanceClassName => "RGen::ECore::EClass" do
eAttribute "abstract", :eType => ""
eAttribute "interface", :eType => ""
eReference "eIDAttribute", :resolveProxies => false, :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => "EAttribute"
eReference "eAllAttributes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EAttribute"
eReference "eAllContainments", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EReference"
eReference "eAllOperations", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EOperation"
eReference "eAllReferences", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EReference"
eReference "eAllStructuralFeatures", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EStructuralFeature"
eReference "eAllSuperTypes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EClass"
eReference "eAttributes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EAttribute"
eReference "eReferences", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EReference"
eReference "eOperations", :containment => true, :resolveProxies => false, :eOpposite => "EOperation.eContainingClass", :upperBound => -1, :eType => "EOperation"
eReference "eStructuralFeatures", :containment => true, :resolveProxies => false, :eOpposite => "EStructuralFeature.eContainingClass", :upperBound => -1, :eType => "EStructuralFeature"
eReference "eSuperTypes", :eOpposite => "eSubTypes", :upperBound => -1, :eType => "EClass"
eReference "eSubTypes", :eOpposite => "eSuperTypes", :upperBound => -1, :eType => "EClass"
end
end
rgen-0.7.0/test/model_builder/test_model/ 0000755 0000041 0000041 00000000000 12352210062 020416 5 ustar www-data www-data rgen-0.7.0/test/model_builder/test_model/statemachine1.rb 0000644 0000041 0000041 00000001322 12352210062 023467 0 ustar www-data www-data statemachine "Airconditioner" do
state "Off", :kind => :START
compositeState "On" do
state "Heating" do
transition :as => :outgoingTransition, :targetState => "Cooling",
:statemachine => "Airconditioner"
end
state "Cooling" do
end
end
transition :sourceState => "On.Cooling", :targetState => "On.Heating" do
_using Condition::TimeCondition do
timeCondition :as => :condition, :timeout => 100
end
Condition::TimeCondition.timeCondition :as => :condition, :timeout => 10
end
end
_using Condition do
statemachine "AirconExtension" do
s = state "StartState"
transition :sourceState => s, :targetState => "Airconditioner.Off"
end
end
rgen-0.7.0/test/model_builder/ecore_original_regenerated.rb 0000644 0000041 0000041 00000023144 12352210062 024136 0 ustar www-data www-data ePackage "ecore", :nsPrefix => "ecore", :nsURI => "http://www.eclipse.org/emf/2002/Ecore" do
eClass "EAttribute" do
eAttribute "iD"
eReference "eAttributeType", :changeable => false, :derived => true, :transient => true, :volatile => true, :lowerBound => 1
end
eClass "EAnnotation" do
eAttribute "source"
eReference "details", :containment => true, :resolveProxies => false, :upperBound => -1
eReference "eModelElement", :resolveProxies => false, :transient => true
eReference "contents", :containment => true, :resolveProxies => false, :upperBound => -1
eReference "references", :upperBound => -1
end
eClass "EClass" do
eAttribute "abstract"
eAttribute "interface"
eReference "eSuperTypes", :unsettable => true, :upperBound => -1
eReference "eOperations", :containment => true, :resolveProxies => false, :upperBound => -1
eReference "eAllAttributes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
eReference "eAllReferences", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
eReference "eReferences", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
eReference "eAttributes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
eReference "eAllContainments", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
eReference "eAllOperations", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
eReference "eAllStructuralFeatures", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
eReference "eAllSuperTypes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
eReference "eIDAttribute", :resolveProxies => false, :changeable => false, :derived => true, :transient => true, :volatile => true
eReference "eStructuralFeatures", :containment => true, :resolveProxies => false, :upperBound => -1
eReference "eGenericSuperTypes", :containment => true, :resolveProxies => false, :unsettable => true, :upperBound => -1
eReference "eAllGenericSuperTypes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1
end
eClass "EClassifier", :abstract => true do
eAttribute "instanceClassName", :unsettable => true, :volatile => true
eAttribute "instanceClass", :changeable => false, :derived => true, :transient => true, :volatile => true
eAttribute "defaultValue", :changeable => false, :derived => true, :transient => true, :volatile => true
eAttribute "instanceTypeName", :unsettable => true, :volatile => true
eReference "ePackage", :changeable => false, :transient => true
eReference "eTypeParameters", :containment => true, :upperBound => -1
end
eClass "EDataType" do
eAttribute "serializable", :defaultValueLiteral => "true"
end
eClass "EEnum" do
eReference "eLiterals", :containment => true, :resolveProxies => false, :upperBound => -1
end
eClass "EEnumLiteral" do
eAttribute "value"
eAttribute "instance", :transient => true
eAttribute "literal"
eReference "eEnum", :resolveProxies => false, :changeable => false, :transient => true
end
eClass "EFactory" do
eReference "ePackage", :resolveProxies => false, :transient => true, :lowerBound => 1
end
eClass "EModelElement", :abstract => true do
eReference "eAnnotations", :containment => true, :resolveProxies => false, :upperBound => -1
end
eClass "ENamedElement", :abstract => true do
eAttribute "name"
end
eClass "EObject"
eClass "EOperation" do
eReference "eContainingClass", :resolveProxies => false, :changeable => false, :transient => true
eReference "eTypeParameters", :containment => true, :upperBound => -1
eReference "eParameters", :containment => true, :resolveProxies => false, :upperBound => -1
eReference "eExceptions", :unsettable => true, :upperBound => -1
eReference "eGenericExceptions", :containment => true, :resolveProxies => false, :unsettable => true, :upperBound => -1
end
eClass "EPackage" do
eAttribute "nsURI"
eAttribute "nsPrefix"
eReference "eFactoryInstance", :resolveProxies => false, :transient => true, :lowerBound => 1
eReference "eClassifiers", :containment => true, :upperBound => -1
eReference "eSubpackages", :containment => true, :upperBound => -1
eReference "eSuperPackage", :changeable => false, :transient => true
end
eClass "EParameter" do
eReference "eOperation", :resolveProxies => false, :changeable => false, :transient => true
end
eClass "EReference" do
eAttribute "containment"
eAttribute "container", :changeable => false, :derived => true, :transient => true, :volatile => true
eAttribute "resolveProxies", :defaultValueLiteral => "true"
eReference "eOpposite"
eReference "eReferenceType", :changeable => false, :derived => true, :transient => true, :volatile => true, :lowerBound => 1
eReference "eKeys", :upperBound => -1
end
eClass "EStructuralFeature", :abstract => true do
eAttribute "changeable", :defaultValueLiteral => "true"
eAttribute "volatile"
eAttribute "transient"
eAttribute "defaultValueLiteral"
eAttribute "defaultValue", :changeable => false, :derived => true, :transient => true, :volatile => true
eAttribute "unsettable"
eAttribute "derived"
eReference "eContainingClass", :resolveProxies => false, :changeable => false, :transient => true
end
eClass "ETypedElement", :abstract => true do
eAttribute "ordered", :defaultValueLiteral => "true"
eAttribute "unique", :defaultValueLiteral => "true"
eAttribute "lowerBound"
eAttribute "upperBound", :defaultValueLiteral => "1"
eAttribute "many", :changeable => false, :derived => true, :transient => true, :volatile => true
eAttribute "required", :changeable => false, :derived => true, :transient => true, :volatile => true
eReference "eType", :unsettable => true, :volatile => true
eReference "eGenericType", :containment => true, :resolveProxies => false, :unsettable => true, :volatile => true
end
eDataType "EBigDecimal", :instanceClassName => "java.math.BigDecimal"
eDataType "EBigInteger", :instanceClassName => "java.math.BigInteger"
eDataType "EBoolean", :instanceClassName => "boolean"
eDataType "EBooleanObject", :instanceClassName => "java.lang.Boolean"
eDataType "EByte", :instanceClassName => "byte"
eDataType "EByteArray", :instanceClassName => "byte[]"
eDataType "EByteObject", :instanceClassName => "java.lang.Byte"
eDataType "EChar", :instanceClassName => "char"
eDataType "ECharacterObject", :instanceClassName => "java.lang.Character"
eDataType "EDate", :instanceClassName => "java.util.Date"
eDataType "EDiagnosticChain", :serializable => false, :instanceClassName => "org.eclipse.emf.common.util.DiagnosticChain"
eDataType "EDouble", :instanceClassName => "double"
eDataType "EDoubleObject", :instanceClassName => "java.lang.Double"
eDataType "EEList", :serializable => false, :instanceClassName => "org.eclipse.emf.common.util.EList" do
eTypeParameter "E"
end
eDataType "EEnumerator", :serializable => false, :instanceClassName => "org.eclipse.emf.common.util.Enumerator"
eDataType "EFeatureMap", :serializable => false, :instanceClassName => "org.eclipse.emf.ecore.util.FeatureMap"
eDataType "EFeatureMapEntry", :serializable => false, :instanceClassName => "org.eclipse.emf.ecore.util.FeatureMap$Entry"
eDataType "EFloat", :instanceClassName => "float"
eDataType "EFloatObject", :instanceClassName => "java.lang.Float"
eDataType "EInt", :instanceClassName => "int"
eDataType "EIntegerObject", :instanceClassName => "java.lang.Integer"
eDataType "EJavaClass", :instanceClassName => "java.lang.Class" do
eTypeParameter "T"
end
eDataType "EJavaObject", :instanceClassName => "java.lang.Object"
eDataType "ELong", :instanceClassName => "long"
eDataType "ELongObject", :instanceClassName => "java.lang.Long"
eDataType "EMap", :serializable => false, :instanceClassName => "java.util.Map" do
eTypeParameter "K"
eTypeParameter "V"
end
eDataType "EResource", :serializable => false, :instanceClassName => "org.eclipse.emf.ecore.resource.Resource"
eDataType "EResourceSet", :serializable => false, :instanceClassName => "org.eclipse.emf.ecore.resource.ResourceSet"
eDataType "EShort", :instanceClassName => "short"
eDataType "EShortObject", :instanceClassName => "java.lang.Short"
eDataType "EString", :instanceClassName => "java.lang.String"
eClass "EStringToStringMapEntry", :instanceClassName => "java.util.Map$Entry" do
eAttribute "key"
eAttribute "value"
end
eDataType "ETreeIterator", :serializable => false, :instanceClassName => "org.eclipse.emf.common.util.TreeIterator" do
eTypeParameter "E"
end
eClass "EGenericType" do
eReference "eUpperBound", :containment => true, :resolveProxies => false
eReference "eTypeArguments", :containment => true, :resolveProxies => false, :upperBound => -1
eReference "eRawType", :changeable => false, :derived => true, :transient => true, :lowerBound => 1
eReference "eLowerBound", :containment => true, :resolveProxies => false
eReference "eTypeParameter", :resolveProxies => false
eReference "eClassifier"
end
eClass "ETypeParameter" do
eReference "eBounds", :containment => true, :resolveProxies => false, :upperBound => -1
end
end
rgen-0.7.0/test/model_builder/builder_context_test.rb 0000644 0000041 0000041 00000003626 12352210062 023044 0 ustar www-data www-data $:.unshift File.dirname(__FILE__)+"/../lib"
require 'test/unit'
require 'rgen/ecore/ecore'
require 'rgen/model_builder/builder_context'
class BuilderContextTest < Test::Unit::TestCase
module BuilderExtension1
module PackageA
def inPackAExt
3
end
module PackageB
def inPackBExt
5
end
end
end
end
class BuilderContext
def inBuilderContext
7
end
end
def test_extensionContainerFactory
aboveRoot = RGen::ECore::EPackage.new(:name => "AboveRoot")
root = RGen::ECore::EPackage.new(:name => "Root", :eSuperPackage => aboveRoot)
packageA = RGen::ECore::EPackage.new(:name => "PackageA", :eSuperPackage => root)
packageB = RGen::ECore::EPackage.new(:name => "PackageB", :eSuperPackage => packageA)
packageC = RGen::ECore::EPackage.new(:name => "PackageBC", :eSuperPackage => packageA)
factory = RGen::ModelBuilder::BuilderContext::ExtensionContainerFactory.new(root, BuilderExtension1, BuilderContext.new)
assert_equal BuilderExtension1::PackageA, factory.moduleForPackage(packageA)
packAExt = factory.extensionContainer(packageA)
assert packAExt.respond_to?(:inPackAExt)
assert !packAExt.respond_to?(:inPackBExt)
assert_equal 3, packAExt.inPackAExt
assert_equal 7, packAExt.inBuilderContext
assert_equal BuilderExtension1::PackageA::PackageB, factory.moduleForPackage(packageB)
packBExt = factory.extensionContainer(packageB)
assert !packBExt.respond_to?(:inPackAExt)
assert packBExt.respond_to?(:inPackBExt)
assert_equal 5, packBExt.inPackBExt
assert_equal 7, packBExt.inBuilderContext
assert_raise RuntimeError do
# aboveRoot is not contained within root
assert_nil factory.moduleForPackage(aboveRoot)
end
assert_nil factory.moduleForPackage(packageC)
end
end rgen-0.7.0/test/model_builder/statemachine_metamodel.rb 0000644 0000041 0000041 00000002252 12352210062 023301 0 ustar www-data www-data # a test metamodel used by the following tests
module StatemachineMetamodel
extend RGen::MetamodelBuilder::ModuleExtension
module Condition
extend RGen::MetamodelBuilder::ModuleExtension
class Condition < RGen::MetamodelBuilder::MMBase
end
module TimeCondition
extend RGen::MetamodelBuilder::ModuleExtension
class TimeCondition < Condition
has_attr 'timeout', Integer
end
end
end
class Statemachine < RGen::MetamodelBuilder::MMBase
has_attr 'name'
end
class State < RGen::MetamodelBuilder::MMBase
has_attr 'name'
has_attr 'kind', RGen::MetamodelBuilder::DataTypes::Enum.new([:START])
end
class CompositeState < State
has_attr 'name'
contains_many 'state', State, 'compositeState'
end
class Transition < RGen::MetamodelBuilder::MMBase
many_to_one 'sourceState', State, 'outgoingTransition'
many_to_one 'targetState', State, 'incomingTransition'
has_many 'condition', Condition::Condition
end
Statemachine.contains_many 'state', State, 'statemachine'
Statemachine.contains_many 'transition', Transition, 'statemachine'
end
rgen-0.7.0/test/model_builder/serializer_test.rb 0000644 0000041 0000041 00000004554 12352210062 022024 0 ustar www-data www-data $:.unshift File.dirname(__FILE__) + "/../lib"
require 'test/unit'
require 'rgen/ecore/ecore'
# The following would also influence other tests...
#
#module RGen::ECore
# class EGenericType < EObject
# contains_many_uni 'eTypeArguments', EGenericType
# end
# class ETypeParameter < ENamedElement
# end
# class EClassifier
# contains_many_uni 'eTypeParameters', ETypeParameter
# end
# class ETypedElement
# has_one 'eGenericType', EGenericType
# end
#end
#
#RGen::ECore::ECoreInterface.clear_ecore_cache
#RGen::ECore::EString.ePackage = RGen::ECore.ecore
require 'rgen/environment'
require 'rgen/model_builder/model_serializer'
require 'rgen/instantiator/ecore_xml_instantiator'
require 'rgen/model_builder'
require 'model_builder/statemachine_metamodel'
class ModelSerializerTest < Test::Unit::TestCase
def test_ecore_internal
File.open(File.dirname(__FILE__)+"/ecore_internal.rb","w") do |f|
serializer = RGen::ModelBuilder::ModelSerializer.new(f, RGen::ECore.ecore)
serializer.serialize(RGen::ECore.ecore)
end
end
def test_roundtrip
model = %{\
statemachine "Airconditioner" do
state "Off", :kind => :START
compositeState "On" do
state "Heating"
state "Cooling"
state "Dumm"
end
transition "_Transition1", :sourceState => "On.Cooling", :targetState => "On.Heating"
transition "_Transition2", :sourceState => "On.Heating", :targetState => "On.Cooling"
end
}
check_roundtrip(StatemachineMetamodel, model)
end
module AmbiguousRoleMM
extend RGen::MetamodelBuilder::ModuleExtension
class A < RGen::MetamodelBuilder::MMBase
end
class B < RGen::MetamodelBuilder::MMBase
end
class C < B
end
A.contains_many 'role1', B, 'back1'
A.contains_many 'role2', B, 'back2'
end
def test_roundtrip_ambiguous_role
model = %{\
a "_A1" do
b "_B1", :as => :role1
b "_B2", :as => :role2
c "_C1", :as => :role2
end
}
check_roundtrip(AmbiguousRoleMM, model)
end
private
def build_model(mm, model)
RGen::ModelBuilder.build(mm) do
eval(model)
end
end
def check_roundtrip(mm, model)
sm = build_model(mm, model)
f = StringIO.new
serializer = RGen::ModelBuilder::ModelSerializer.new(f, mm.ecore)
serializer.serialize(sm)
assert_equal model, f.string
end
end
rgen-0.7.0/test/model_builder/ecore_original.rb 0000644 0000041 0000041 00000030643 12352210062 021573 0 ustar www-data www-data ePackage "ecore", :nsPrefix => "ecore", :nsURI => "http://www.eclipse.org/emf/2002/Ecore" do
eClass "EAttribute", :eSuperTypes => ["EStructuralFeature"] do
eAttribute "iD"
eReference "eAttributeType", :changeable => false, :derived => true, :transient => true, :volatile => true, :lowerBound => 1, :eType => "EDataType"
end
eClass "EAnnotation", :eSuperTypes => ["EModelElement"] do
eAttribute "source"
eReference "details", :containment => true, :resolveProxies => false, :upperBound => -1, :eType => "EStringToStringMapEntry"
eReference "eModelElement", :resolveProxies => false, :eOpposite => "EModelElement.eAnnotations", :transient => true, :eType => "EModelElement"
eReference "contents", :containment => true, :resolveProxies => false, :upperBound => -1, :eType => "EObject"
eReference "references", :upperBound => -1, :eType => "EObject"
end
eClass "EClass", :eSuperTypes => ["EClassifier"] do
eAttribute "abstract"
eAttribute "interface"
eReference "eSuperTypes", :unsettable => true, :upperBound => -1, :eType => "EClass"
eReference "eOperations", :containment => true, :resolveProxies => false, :eOpposite => "EOperation.eContainingClass", :upperBound => -1, :eType => "EOperation"
eReference "eAllAttributes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EAttribute"
eReference "eAllReferences", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EReference"
eReference "eReferences", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EReference"
eReference "eAttributes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EAttribute"
eReference "eAllContainments", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EReference"
eReference "eAllOperations", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EOperation"
eReference "eAllStructuralFeatures", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EStructuralFeature"
eReference "eAllSuperTypes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EClass"
eReference "eIDAttribute", :resolveProxies => false, :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => "EAttribute"
eReference "eStructuralFeatures", :containment => true, :resolveProxies => false, :eOpposite => "EStructuralFeature.eContainingClass", :upperBound => -1, :eType => "EStructuralFeature"
eReference "eGenericSuperTypes", :containment => true, :resolveProxies => false, :unsettable => true, :upperBound => -1, :eType => "EGenericType"
eReference "eAllGenericSuperTypes", :changeable => false, :derived => true, :transient => true, :volatile => true, :upperBound => -1, :eType => "EGenericType"
end
eClass "EClassifier", :abstract => true, :eSuperTypes => ["ENamedElement"], :eSubTypes => ["EClass", "EDataType"] do
eAttribute "instanceClassName", :unsettable => true, :volatile => true
eAttribute "instanceClass", :changeable => false, :derived => true, :transient => true, :volatile => true
eAttribute "defaultValue", :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => "EJavaObject"
eAttribute "instanceTypeName", :unsettable => true, :volatile => true
eReference "ePackage", :eOpposite => "EPackage.eClassifiers", :changeable => false, :transient => true, :eType => "EPackage"
eReference "eTypeParameters", :containment => true, :upperBound => -1, :eType => "ETypeParameter"
end
eClass "EDataType", :eSuperTypes => ["EClassifier"], :eSubTypes => ["EEnum"] do
eAttribute "serializable", :defaultValueLiteral => "true"
end
eClass "EEnum", :eSuperTypes => ["EDataType"] do
eReference "eLiterals", :containment => true, :resolveProxies => false, :eOpposite => "EEnumLiteral.eEnum", :upperBound => -1, :eType => "EEnumLiteral"
end
eClass "EEnumLiteral", :eSuperTypes => ["ENamedElement"] do
eAttribute "value"
eAttribute "instance", :transient => true, :eType => "EEnumerator"
eAttribute "literal"
eReference "eEnum", :resolveProxies => false, :eOpposite => "EEnum.eLiterals", :changeable => false, :transient => true, :eType => "EEnum"
end
eClass "EFactory", :eSuperTypes => ["EModelElement"] do
eReference "ePackage", :resolveProxies => false, :eOpposite => "EPackage.eFactoryInstance", :transient => true, :lowerBound => 1, :eType => "EPackage"
end
eClass "EModelElement", :abstract => true, :eSuperTypes => ["EObject"], :eSubTypes => ["EAnnotation", "EFactory", "ENamedElement"] do
eReference "eAnnotations", :containment => true, :resolveProxies => false, :eOpposite => "EAnnotation.eModelElement", :upperBound => -1, :eType => "EAnnotation"
end
eClass "ENamedElement", :abstract => true, :eSuperTypes => ["EModelElement"], :eSubTypes => ["EClassifier", "EEnumLiteral", "EPackage", "ETypedElement", "ETypeParameter"] do
eAttribute "name"
end
eClass "EObject", :eSubTypes => ["EModelElement", "EGenericType"]
eClass "EOperation", :eSuperTypes => ["ETypedElement"] do
eReference "eContainingClass", :resolveProxies => false, :eOpposite => "EClass.eOperations", :changeable => false, :transient => true, :eType => "EClass"
eReference "eTypeParameters", :containment => true, :upperBound => -1, :eType => "ETypeParameter"
eReference "eParameters", :containment => true, :resolveProxies => false, :eOpposite => "EParameter.eOperation", :upperBound => -1, :eType => "EParameter"
eReference "eExceptions", :unsettable => true, :upperBound => -1, :eType => "EClassifier"
eReference "eGenericExceptions", :containment => true, :resolveProxies => false, :unsettable => true, :upperBound => -1, :eType => "EGenericType"
end
eClass "EPackage", :eSuperTypes => ["ENamedElement"] do
eAttribute "nsURI"
eAttribute "nsPrefix"
eReference "eFactoryInstance", :resolveProxies => false, :eOpposite => "EFactory.ePackage", :transient => true, :lowerBound => 1, :eType => "EFactory"
eReference "eClassifiers", :containment => true, :eOpposite => "EClassifier.ePackage", :upperBound => -1, :eType => "EClassifier"
eReference "eSubpackages", :containment => true, :eOpposite => "eSuperPackage", :upperBound => -1, :eType => "EPackage"
eReference "eSuperPackage", :eOpposite => "eSubpackages", :changeable => false, :transient => true, :eType => "EPackage"
end
eClass "EParameter", :eSuperTypes => ["ETypedElement"] do
eReference "eOperation", :resolveProxies => false, :eOpposite => "EOperation.eParameters", :changeable => false, :transient => true, :eType => "EOperation"
end
eClass "EReference", :eSuperTypes => ["EStructuralFeature"] do
eAttribute "containment"
eAttribute "container", :changeable => false, :derived => true, :transient => true, :volatile => true
eAttribute "resolveProxies", :defaultValueLiteral => "true"
eReference "eOpposite", :eType => "EReference"
eReference "eReferenceType", :changeable => false, :derived => true, :transient => true, :volatile => true, :lowerBound => 1, :eType => "EClass"
eReference "eKeys", :upperBound => -1, :eType => "EAttribute"
end
eClass "EStructuralFeature", :abstract => true, :eSuperTypes => ["ETypedElement"], :eSubTypes => ["EAttribute", "EReference"] do
eAttribute "changeable", :defaultValueLiteral => "true"
eAttribute "volatile"
eAttribute "transient"
eAttribute "defaultValueLiteral"
eAttribute "defaultValue", :changeable => false, :derived => true, :transient => true, :volatile => true, :eType => "EJavaObject"
eAttribute "unsettable"
eAttribute "derived"
eReference "eContainingClass", :resolveProxies => false, :eOpposite => "EClass.eStructuralFeatures", :changeable => false, :transient => true, :eType => "EClass"
end
eClass "ETypedElement", :abstract => true, :eSuperTypes => ["ENamedElement"], :eSubTypes => ["EOperation", "EParameter", "EStructuralFeature"] do
eAttribute "ordered", :defaultValueLiteral => "true"
eAttribute "unique", :defaultValueLiteral => "true"
eAttribute "lowerBound"
eAttribute "upperBound", :defaultValueLiteral => "1"
eAttribute "many", :changeable => false, :derived => true, :transient => true, :volatile => true
eAttribute "required", :changeable => false, :derived => true, :transient => true, :volatile => true
eReference "eType", :unsettable => true, :volatile => true, :eType => "EClassifier"
eReference "eGenericType", :containment => true, :resolveProxies => false, :unsettable => true, :volatile => true, :eType => "EGenericType"
end
eDataType "EBigDecimal", :instanceClassName => "java.math.BigDecimal"
eDataType "EBigInteger", :instanceClassName => "java.math.BigInteger"
eDataType "EBoolean", :instanceClassName => "boolean"
eDataType "EBooleanObject", :instanceClassName => "java.lang.Boolean"
eDataType "EByte", :instanceClassName => "byte"
eDataType "EByteArray", :instanceClassName => "byte[]"
eDataType "EByteObject", :instanceClassName => "java.lang.Byte"
eDataType "EChar", :instanceClassName => "char"
eDataType "ECharacterObject", :instanceClassName => "java.lang.Character"
eDataType "EDate", :instanceClassName => "java.util.Date"
eDataType "EDiagnosticChain", :serializable => false, :instanceClassName => "org.eclipse.emf.common.util.DiagnosticChain"
eDataType "EDouble", :instanceClassName => "double"
eDataType "EDoubleObject", :instanceClassName => "java.lang.Double"
eDataType "EEList", :serializable => false, :instanceClassName => "org.eclipse.emf.common.util.EList" do
eTypeParameter "E"
end
eDataType "EEnumerator", :serializable => false, :instanceClassName => "org.eclipse.emf.common.util.Enumerator"
eDataType "EFeatureMap", :serializable => false, :instanceClassName => "org.eclipse.emf.ecore.util.FeatureMap"
eDataType "EFeatureMapEntry", :serializable => false, :instanceClassName => "org.eclipse.emf.ecore.util.FeatureMap$Entry"
eDataType "EFloat", :instanceClassName => "float"
eDataType "EFloatObject", :instanceClassName => "java.lang.Float"
eDataType "EInt", :instanceClassName => "int"
eDataType "EIntegerObject", :instanceClassName => "java.lang.Integer"
eDataType "EJavaClass", :instanceClassName => "java.lang.Class" do
eTypeParameter "T"
end
eDataType "EJavaObject", :instanceClassName => "java.lang.Object"
eDataType "ELong", :instanceClassName => "long"
eDataType "ELongObject", :instanceClassName => "java.lang.Long"
eDataType "EMap", :serializable => false, :instanceClassName => "java.util.Map" do
eTypeParameter "K"
eTypeParameter "V"
end
eDataType "EResource", :serializable => false, :instanceClassName => "org.eclipse.emf.ecore.resource.Resource"
eDataType "EResourceSet", :serializable => false, :instanceClassName => "org.eclipse.emf.ecore.resource.ResourceSet"
eDataType "EShort", :instanceClassName => "short"
eDataType "EShortObject", :instanceClassName => "java.lang.Short"
eDataType "EString", :instanceClassName => "java.lang.String"
eClass "EStringToStringMapEntry", :instanceClassName => "java.util.Map$Entry" do
eAttribute "key"
eAttribute "value"
end
eDataType "ETreeIterator", :serializable => false, :instanceClassName => "org.eclipse.emf.common.util.TreeIterator" do
eTypeParameter "E"
end
eClass "EGenericType", :eSuperTypes => ["EObject"] do
eReference "eUpperBound", :containment => true, :resolveProxies => false, :eType => "EGenericType"
eReference "eTypeArguments", :containment => true, :resolveProxies => false, :upperBound => -1, :eType => "EGenericType"
eReference "eRawType", :changeable => false, :derived => true, :transient => true, :lowerBound => 1, :eType => "EClassifier"
eReference "eLowerBound", :containment => true, :resolveProxies => false, :eType => "EGenericType"
eReference "eTypeParameter", :resolveProxies => false, :eType => "ETypeParameter"
eReference "eClassifier", :eType => "EClassifier"
end
eClass "ETypeParameter", :eSuperTypes => ["ENamedElement"] do
eReference "eBounds", :containment => true, :resolveProxies => false, :upperBound => -1, :eType => "EGenericType"
end
end
rgen-0.7.0/test/testmodel/ 0000755 0000041 0000041 00000000000 12352210062 015451 5 ustar www-data www-data rgen-0.7.0/test/testmodel/manual_testmodel.xml 0000644 0000041 0000041 00000001003 12352210062 021522 0 ustar www-data www-data
before kitchen
after kitchen
within toms room
after toms room
rgen-0.7.0/test/testmodel/ea_testmodel.eap 0000644 0000041 0000041 00004614000 12352210062 020612 0 ustar www-data www-data Standard Jet DB nb` Ugr@? ~1y0̝cǟFN7]D^(`T{6߱wCϯ34ay[|*|OJl>`&_Љ$g'DeFx- { %
&