rgen 0.7.0 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +23 -0
  3. data/README.rdoc +1 -1
  4. data/Rakefile +15 -25
  5. data/lib/rgen/ecore/ecore.rb +1 -1
  6. data/lib/rgen/ecore/ecore_ext.rb +9 -1
  7. data/lib/rgen/ecore/ecore_to_ruby.rb +133 -47
  8. data/lib/rgen/fragment/fragmented_model.rb +2 -0
  9. data/lib/rgen/fragment/model_fragment.rb +3 -0
  10. data/lib/rgen/instantiator/default_xml_instantiator.rb +93 -88
  11. data/lib/rgen/metamodel_builder/builder_extensions.rb +32 -8
  12. data/lib/rgen/metamodel_builder/builder_runtime.rb +12 -5
  13. data/lib/rgen/template_language/output_handler.rb +52 -19
  14. data/lib/rgen/template_language/template_container.rb +17 -7
  15. data/lib/rgen/template_language.rb +2 -1
  16. data/test/array_extensions_test.rb +7 -7
  17. data/test/ea_instantiator_test.rb +2 -2
  18. data/test/ea_serializer_test.rb +2 -2
  19. data/test/ecore_self_test.rb +2 -2
  20. data/test/ecore_to_ruby_test.rb +73 -0
  21. data/test/environment_test.rb +2 -2
  22. data/test/json_test.rb +4 -4
  23. data/test/metamodel_builder_test.rb +71 -44
  24. data/test/metamodel_from_ecore_test.rb +1 -1
  25. data/test/metamodel_order_test.rb +2 -2
  26. data/test/metamodel_roundtrip_test.rb +2 -2
  27. data/test/method_delegation_test.rb +5 -5
  28. data/test/model_builder/builder_context_test.rb +3 -3
  29. data/test/model_builder/builder_test.rb +11 -11
  30. data/test/model_builder/reference_resolver_test.rb +3 -3
  31. data/test/model_builder/serializer_test.rb +2 -2
  32. data/test/model_fragment_test.rb +2 -2
  33. data/test/output_handler_test.rb +2 -2
  34. data/test/qualified_name_provider_test.rb +2 -2
  35. data/test/qualified_name_resolver_test.rb +4 -4
  36. data/test/reference_resolver_test.rb +4 -4
  37. data/test/rgen_test.rb +2 -1
  38. data/test/template_language_test/templates/indent_nonl_at_eof_test/test.tpl +14 -0
  39. data/test/template_language_test/templates/indent_same_line_sub/test.tpl +16 -0
  40. data/test/template_language_test/templates/line_endings/mixed.tpl +6 -0
  41. data/test/template_language_test/templates/line_endings/unix.tpl +6 -0
  42. data/test/template_language_test/templates/line_endings/windows.tpl +6 -0
  43. data/test/template_language_test/templates/ws_test.tpl +21 -0
  44. data/test/template_language_test.rb +60 -9
  45. data/test/testmodel/class_model_checker.rb +17 -17
  46. data/test/testmodel/ecore_model_checker.rb +13 -13
  47. data/test/testmodel/object_model_checker.rb +6 -6
  48. data/test/transformer_test.rb +3 -3
  49. data/test/util/file_cache_map_test.rb +2 -2
  50. data/test/util/pattern_matcher_test.rb +7 -7
  51. data/test/xml_instantiator_test/simple_ecore_model_checker.rb +12 -12
  52. data/test/xml_instantiator_test.rb +8 -8
  53. metadata +61 -20
  54. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +0 -71
  55. data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +0 -162
  56. data/test/metamodel_roundtrip_test/using_builtin_types_serialized.ecore +0 -9
  57. data/test/model_builder/ecore_internal.rb +0 -113
  58. data/test/testmodel/ea_testmodel_regenerated.xml +0 -813
  59. data/test/util/file_cache_map_test/testdir/fileA +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe212a74ff9c45d6fcd848596acb527d6def24f5
4
- data.tar.gz: 3c99d2170dab24b922a30a5a5420f03aaa05779e
3
+ metadata.gz: d1c27a6cc15f063ebc9483cb56253ebd20721cd2
4
+ data.tar.gz: b30dfcf5b91d19a8d26b0cc66a5dec9d3c0471c9
5
5
  SHA512:
6
- metadata.gz: a70a59af207fcf7d3c35c0f8785a9bcceebb370b9a0f41e07a2103bc563256acd6e5160d256c1e8c786d52f48f9e540ed62e2105348b9b9a520a57f9d0a99c0b
7
- data.tar.gz: eae33d63df0964a0175917aa7efd711306e933a4ab56fa938976a5d28eb8fc53a3e7e18e984a4c89dd134d0421418f6d86ff02a60c1e7e011620a544a62b6edd
6
+ metadata.gz: 5b74eb0928f9e39911b25dddbff8c73b12a331d651d59fdb27672794c6f6477bcdf23b3e8ac17ca97c2b3138dc33a3788a48ae6100493a710ff06e5557093dc8
7
+ data.tar.gz: cfe2866c2692b7a408cd460205cdc105f2cf792262104adfb6a0f0aa55bf917c26193766abebf43ccfd2f218f74e78910f20b82fa17d585beaca5345301bf985
data/CHANGELOG CHANGED
@@ -195,3 +195,26 @@
195
195
  * Added setNilOrRemoveGeneric and setNilOrRemoveAllGeneric methods
196
196
  * Added disconnectContainer method
197
197
 
198
+ =0.8.0
199
+
200
+ * Fixed missing indentation when template file is not terminated by a newline
201
+ * Fixed missing indentation when expand in same line expands sub templates
202
+ * Fixed DefaultXMLInstantiator naming error with a tag named 'File' (issue #19, pull request #21 from jkugs)
203
+ * Simplified ECoreToRuby and optionally let it create modules with non-temporary names
204
+ * Improved performance of output handler
205
+ * Improved performance of setXXX and addXXX methods (pull request #22 from thallgren)
206
+ * Use a value larger than Fixnum max to test Bignum support (pull request #18 from graaff)
207
+
208
+ =0.8.1
209
+
210
+ * Improved performance of ECoreToRuby
211
+ * Fixed <%ws%> command to trigger indentation if starting a new line
212
+
213
+ =0.8.2
214
+
215
+ * Added helper methods
216
+
217
+ =0.8.3
218
+
219
+ * Performance improvement: getGeneric made a lot faster
220
+
data/README.rdoc CHANGED
@@ -5,7 +5,7 @@ This means that it helps you build Metamodels, instantiate Models, modify
5
5
  and transform Models and finally generate arbitrary textual content from it.
6
6
 
7
7
  RGen features include:
8
- * Supporting Ruby 1.8.6, 1.8.7 and 1.9.x
8
+ * Supporting Ruby 1.8.7, 1.9.x, 2.0, 2.1, 2.2
9
9
  * Metamodel definition language (internal Ruby DSL)
10
10
  * ECore Meta-metamodel with an ECore instance available for every Metamodel
11
11
  * Generator creating the Ruby metamodel definition from an ECore instance
data/Rakefile CHANGED
@@ -1,39 +1,29 @@
1
1
  require 'rubygems/package_task'
2
2
  require 'rdoc/task'
3
+ require 'bundler/setup'
4
+ require 'rake/testtask'
3
5
 
4
- RGenGemSpec = Gem::Specification.new do |s|
5
- s.name = %q{rgen}
6
- s.version = "0.7.0"
7
- s.date = Time.now.strftime("%Y-%m-%d")
8
- s.summary = %q{Ruby Modelling and Generator Framework}
9
- s.email = %q{martin dot thiede at gmx de}
10
- s.homepage = %q{http://ruby-gen.org}
11
- s.rubyforge_project = %q{rgen}
12
- 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.}
13
- s.authors = ["Martin Thiede"]
14
- gemfiles = Rake::FileList.new
15
- gemfiles.include("{lib,test}/**/*")
16
- gemfiles.include("README.rdoc", "CHANGELOG", "MIT-LICENSE", "Rakefile")
17
- gemfiles.exclude(/\b\.bak\b/)
18
- s.files = gemfiles
19
- s.rdoc_options = ["--main", "README.rdoc", "-x", "test", "-x", "metamodels", "-x", "ea_support/uml13*"]
20
- s.extra_rdoc_files = ["README.rdoc", "CHANGELOG", "MIT-LICENSE"]
21
- end
6
+ RGenGemSpec = eval(File.read('rgen.gemspec'))
22
7
 
23
8
  RDoc::Task.new do |rd|
24
- rd.main = "README.rdoc"
25
- rd.rdoc_files.include("README.rdoc", "CHANGELOG", "MIT-LICENSE", "lib/**/*.rb")
26
- rd.rdoc_files.exclude("lib/metamodels/*")
27
- rd.rdoc_files.exclude("lib/ea_support/uml13*")
28
- rd.rdoc_dir = "doc"
9
+ rd.main = 'README.rdoc'
10
+ rd.rdoc_files.include('README.rdoc', 'CHANGELOG', 'MIT-LICENSE', 'lib/**/*.rb')
11
+ rd.rdoc_files.exclude('lib/metamodels/*')
12
+ rd.rdoc_files.exclude('lib/ea_support/uml13*')
13
+ rd.rdoc_dir = 'doc'
29
14
  end
30
15
 
31
16
  RGenPackageTask = Gem::PackageTask.new(RGenGemSpec) do |p|
32
17
  p.need_zip = false
33
- end
18
+ end
19
+
20
+ ::Rake::TestTask.new(:test) do |t|
21
+ t.test_files = ['test/rgen_test.rb']
22
+ t.warning = false
23
+ end
34
24
 
35
25
  task :prepare_package_rdoc => :rdoc do
36
- RGenPackageTask.package_files.include("doc/**/*")
26
+ RGenPackageTask.package_files.include('doc/**/*')
37
27
  end
38
28
 
39
29
  task :release => [:prepare_package_rdoc, :package]
@@ -155,7 +155,7 @@ module RGen
155
155
  has_many 'eAttributes', ECore::EAttribute, :derived=>true
156
156
  has_many 'eReferences', ECore::EReference, :derived=>true
157
157
 
158
- module ClassModule
158
+ module ClassModule
159
159
  def eAllAttributes_derived
160
160
  eAttributes + eSuperTypes.eAllAttributes
161
161
  end
@@ -63,7 +63,15 @@ module RGen
63
63
  def eAllSubTypes
64
64
  eSubTypes + eSubTypes.eAllSubTypes
65
65
  end
66
+
67
+ def concrete
68
+ !(abstract || interface)
69
+ end
70
+
71
+ def isAssignableFrom(cls)
72
+ cls == self || cls.eAllSuperTypes.any? { |super_type| super_type == self }
73
+ end
66
74
 
67
- end
75
+ end
68
76
  end
69
77
  end
@@ -4,63 +4,115 @@ module RGen
4
4
 
5
5
  module ECore
6
6
 
7
+ # ECoreToRuby can turn ECore models into their Ruby metamodel representations
7
8
  class ECoreToRuby
8
9
 
9
10
  def initialize
10
11
  @modules = {}
11
12
  @classifiers = {}
12
13
  @features_added = {}
13
- @in_create_module = false
14
14
  end
15
15
 
16
- def create_module(epackage)
17
- return @modules[epackage] if @modules[epackage]
18
-
19
- top = (@in_create_module == false)
20
- @in_create_module = true
21
-
22
- m = Module.new do
23
- extend RGen::MetamodelBuilder::ModuleExtension
24
- end
25
- @modules[epackage] = m
26
-
27
- epackage.eSubpackages.each{|p| create_module(p)}
28
- m._set_ecore_internal(epackage)
29
-
30
- create_module(epackage.eSuperPackage).const_set(epackage.name, m) if epackage.eSuperPackage
16
+ # Create a Ruby module representing +epackage+.
17
+ # This includes all nested modules/packages, classes and enums.
18
+ #
19
+ # If a parent module is provided with the "under" parameter,
20
+ # the new module will be nested under the parent module.
21
+ #
22
+ # If the parent module has a non-temporary name,
23
+ # (more precisely: a non-temporary classpath) i.e. if it is reachable
24
+ # via a path of constant names from the root, then the nested
25
+ # modules and classes will also have non-temporary names.
26
+ # In particular, this means that they will keep their names even
27
+ # if they are assigned to new constants.
28
+ #
29
+ # If no parent module is provided or the parent module has a
30
+ # temporary name by itself, then the nested modules and classes will
31
+ # also have temporary names. This means that their name will stay
32
+ # 'volatile' until they are assigned to constants reachable from
33
+ # the root and the Module#name method is called for the first time.
34
+ #
35
+ # While the second approach is more flexible, it can come with a major
36
+ # performance impact. The reason is that Ruby searches the space of
37
+ # all known non-temporary classes/modules every time the name
38
+ # of a class/module with a temporary name is queried.
39
+ #
40
+ def create_module(epackage, under=Module.new)
41
+ with_empty_constant_order_helper do
42
+ temp = under.to_s.start_with?("#")
43
+ mod = create_module_internal(epackage, under, temp)
31
44
 
32
- # create classes only after all modules have been created
33
- # otherwise classes may be created multiple times
34
- if top
35
45
  epackage.eAllClassifiers.each do |c|
36
46
  if c.is_a?(RGen::ECore::EClass)
37
- create_class(c)
47
+ create_class(c, temp)
38
48
  elsif c.is_a?(RGen::ECore::EEnum)
39
49
  create_enum(c)
40
50
  end
41
51
  end
42
- @in_create_module = false
52
+
53
+ mod
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def create_module_internal(epackage, under, temp)
60
+ return @modules[epackage] if @modules[epackage]
61
+
62
+ if temp
63
+ mod = Module.new do
64
+ extend RGen::MetamodelBuilder::ModuleExtension
65
+ end
66
+ under.const_set(epackage.name, mod)
67
+ else
68
+ under.module_eval <<-END
69
+ module #{epackage.name}
70
+ extend RGen::MetamodelBuilder::ModuleExtension
71
+ end
72
+ END
73
+ mod = under.const_get(epackage.name)
43
74
  end
44
- m
75
+ @modules[epackage] = mod
76
+
77
+ epackage.eSubpackages.each{|p| create_module_internal(p, mod, temp)}
78
+ mod._set_ecore_internal(epackage)
79
+
80
+ mod
45
81
  end
46
82
 
47
- def create_class(eclass)
83
+ def create_class(eclass, temp)
48
84
  return @classifiers[eclass] if @classifiers[eclass]
49
85
 
50
- c = Class.new(super_class(eclass)) do
51
- abstract if eclass.abstract
52
- class << self
53
- attr_accessor :_ecore_to_ruby
86
+ mod = @modules[eclass.ePackage]
87
+ if temp
88
+ cls = Class.new(super_class(eclass, temp)) do
89
+ abstract if eclass.abstract
90
+ class << self
91
+ attr_accessor :_ecore_to_ruby
92
+ end
54
93
  end
94
+ mod.const_set(eclass.name, cls)
95
+ else
96
+ mod.module_eval <<-END
97
+ class #{eclass.name} < #{super_class(eclass, temp)}
98
+ #{eclass.abstract ? 'abstract' : ''}
99
+ class << self
100
+ attr_accessor :_ecore_to_ruby
101
+ end
102
+ end
103
+ END
104
+ cls = mod.const_get(eclass.name)
55
105
  end
106
+
56
107
  class << eclass
57
108
  attr_accessor :instanceClass
58
109
  def instanceClassName
59
110
  instanceClass.to_s
60
111
  end
61
112
  end
62
- eclass.instanceClass = c
63
- c::ClassModule.module_eval do
113
+ eclass.instanceClass = cls
114
+
115
+ cls::ClassModule.module_eval do
64
116
  alias _method_missing method_missing
65
117
  def method_missing(m, *args)
66
118
  if self.class._ecore_to_ruby.add_features(self.class.ecore)
@@ -75,12 +127,11 @@ class ECoreToRuby
75
127
  _respond_to(m)
76
128
  end
77
129
  end
78
- @classifiers[eclass] = c
79
- c._set_ecore_internal(eclass)
80
- c._ecore_to_ruby = self
130
+ @classifiers[eclass] = cls
131
+ cls._set_ecore_internal(eclass)
132
+ cls._ecore_to_ruby = self
81
133
 
82
- create_module(eclass.ePackage).const_set(eclass.name, c)
83
- c
134
+ cls
84
135
  end
85
136
 
86
137
  def create_enum(eenum)
@@ -89,7 +140,7 @@ class ECoreToRuby
89
140
  e = RGen::MetamodelBuilder::DataTypes::Enum.new(eenum.eLiterals.collect{|l| l.name.to_sym})
90
141
  @classifiers[eenum] = e
91
142
 
92
- create_module(eenum.ePackage).const_set(eenum.name, e)
143
+ @modules[eenum.ePackage].const_set(eenum.name, e)
93
144
  e
94
145
  end
95
146
 
@@ -126,6 +177,53 @@ class ECoreToRuby
126
177
  end
127
178
  end
128
179
 
180
+ def super_class(eclass, temp)
181
+ super_types = eclass.eSuperTypes
182
+ if temp
183
+ case super_types.size
184
+ when 0
185
+ RGen::MetamodelBuilder::MMBase
186
+ when 1
187
+ create_class(super_types.first, temp)
188
+ else
189
+ RGen::MetamodelBuilder::MMMultiple(*super_types.collect{|t| create_class(t, temp)})
190
+ end
191
+ else
192
+ case super_types.size
193
+ when 0
194
+ "RGen::MetamodelBuilder::MMBase"
195
+ when 1
196
+ create_class(super_types.first, temp).name
197
+ else
198
+ "RGen::MetamodelBuilder::MMMultiple(" +
199
+ super_types.collect{|t| create_class(t, temp).name}.join(",") + ")"
200
+ end
201
+ end
202
+ end
203
+
204
+ class EmptyConstantOrderHelper
205
+ def classCreated(c); end
206
+ def moduleCreated(m); end
207
+ def enumCreated(e); end
208
+ end
209
+
210
+ def with_empty_constant_order_helper
211
+ orig_coh = RGen::MetamodelBuilder::ConstantOrderHelper
212
+ RGen::MetamodelBuilder.instance_eval { remove_const(:ConstantOrderHelper) }
213
+ RGen::MetamodelBuilder.const_set(:ConstantOrderHelper, EmptyConstantOrderHelper.new)
214
+
215
+ begin
216
+ result = yield
217
+ ensure
218
+ RGen::MetamodelBuilder.instance_eval { remove_const(:ConstantOrderHelper) }
219
+ RGen::MetamodelBuilder.const_set(:ConstantOrderHelper, orig_coh)
220
+ end
221
+
222
+ result
223
+ end
224
+
225
+ public
226
+
129
227
  def add_features(eclass)
130
228
  return false if @features_added[eclass]
131
229
  c = @classifiers[eclass]
@@ -147,18 +245,6 @@ class ECoreToRuby
147
245
  true
148
246
  end
149
247
 
150
- def super_class(eclass)
151
- super_types = eclass.eSuperTypes
152
- case super_types.size
153
- when 0
154
- RGen::MetamodelBuilder::MMBase
155
- when 1
156
- create_class(super_types.first)
157
- else
158
- RGen::MetamodelBuilder::MMMultiple(*super_types.collect{|t| create_class(t)})
159
- end
160
- end
161
-
162
248
  end
163
249
 
164
250
  end
@@ -111,6 +111,8 @@ class FragmentedModel
111
111
  # This is a Hash mapping identifiers to model elements accessible via the identifier.
112
112
  #
113
113
  def index
114
+ # Invalidate the cache when any fragment's local index changes.
115
+ # Assumption: If the local index content changes, there is a new index object.
114
116
  fragments.each do |f|
115
117
  if !@fragment_index[f] || (@fragment_index[f].object_id != f.index.object_id)
116
118
  @fragment_index[f] = f.index
@@ -117,6 +117,9 @@ class ModelFragment
117
117
  end
118
118
 
119
119
  # Returns the index of the element contained in this fragment.
120
+ #
121
+ # FragmentedModel's index caching depends on the fact that any change
122
+ # of a fragment's index contents implies a new index object.
120
123
  #
121
124
  def index
122
125
  build_index unless @index
@@ -8,107 +8,112 @@ module Instantiator
8
8
  # Derive your own instantiator from this class or use it as is.
9
9
  #
10
10
  class DefaultXMLInstantiator < NodebasedXMLInstantiator
11
- include Util::NameHelper
11
+ include Util::NameHelper
12
12
 
13
- NamespaceDescriptor = Struct.new(:prefix, :target)
14
-
15
- class << self
16
-
17
- def map_tag_ns(from, to, prefix="")
18
- tag_ns_map[from] = NamespaceDescriptor.new(prefix, to)
19
- end
20
-
21
- def tag_ns_map # :nodoc:
22
- @tag_ns_map ||={}
23
- @tag_ns_map
24
- end
25
-
26
- end
27
-
28
- def initialize(env, default_module, create_mm=false)
29
- super(env)
30
- @default_module = default_module
31
- @create_mm = create_mm
32
- end
33
-
34
- def on_descent(node)
35
- obj = new_object(node)
36
- @env << obj unless obj.nil?
37
- node.object = obj
38
- node.attributes.each_pair { |k,v| set_attribute(node, k, v) }
39
- end
13
+ NamespaceDescriptor = Struct.new(:prefix, :target)
14
+
15
+ class << self
16
+
17
+ def map_tag_ns(from, to, prefix="")
18
+ tag_ns_map[from] = NamespaceDescriptor.new(prefix, to)
19
+ end
20
+
21
+ def tag_ns_map # :nodoc:
22
+ @tag_ns_map ||={}
23
+ @tag_ns_map
24
+ end
25
+
26
+ end
27
+
28
+ def initialize(env, default_module, create_mm=false)
29
+ super(env)
30
+ @default_module = default_module
31
+ @create_mm = create_mm
32
+ end
33
+
34
+ def on_descent(node)
35
+ obj = new_object(node)
36
+ @env << obj unless obj.nil?
37
+ node.object = obj
38
+ node.attributes.each_pair { |k,v| set_attribute(node, k, v) }
39
+ end
40
40
 
41
- def on_ascent(node)
42
- node.children.each { |c| assoc_p2c(node, c) }
43
- node.object.class.has_attr 'chardata', Object unless node.object.respond_to?(:chardata)
44
- set_attribute(node, "chardata", node.chardata)
45
- end
46
-
41
+ def on_ascent(node)
42
+ node.children.each { |c| assoc_p2c(node, c) }
43
+ node.object.class.has_attr 'chardata', Object unless node.object.respond_to?(:chardata)
44
+ set_attribute(node, "chardata", node.chardata)
45
+ end
46
+
47
47
  def class_name(str)
48
48
  saneClassName(str)
49
49
  end
50
50
 
51
- def new_object(node)
52
- ns_desc = self.class.tag_ns_map[node.namespace]
53
- class_name = class_name(ns_desc.nil? ? node.qtag : ns_desc.prefix+node.tag)
54
- mod = (ns_desc && ns_desc.target) || @default_module
55
- build_on_error(NameError, :build_class, class_name, mod) do
56
- mod.const_get(class_name).new
57
- end
58
- end
51
+ def new_object(node)
52
+ ns_desc = self.class.tag_ns_map[node.namespace]
53
+ class_name = class_name(ns_desc.nil? ? node.qtag : ns_desc.prefix+node.tag)
54
+ mod = (ns_desc && ns_desc.target) || @default_module
55
+ build_on_error(NameError, :build_class, class_name, mod) do
56
+ begin
57
+ mod.const_get(class_name, false).new
58
+ rescue ArgumentError
59
+ # Ruby 1.8
60
+ mod.const_get(class_name).new
61
+ end
62
+ end
63
+ end
59
64
 
60
- def build_class(name, mod)
61
- mod.const_set(name, Class.new(RGen::MetamodelBuilder::MMBase))
62
- end
65
+ def build_class(name, mod)
66
+ mod.const_set(name, Class.new(RGen::MetamodelBuilder::MMBase))
67
+ end
63
68
 
64
69
  def method_name(str)
65
70
  saneMethodName(str)
66
71
  end
67
72
 
68
- def assoc_p2c(parent, child)
69
- return unless parent.object && child.object
70
- method_name = method_name(className(child.object))
71
- build_on_error(NoMethodError, :build_p2c_assoc, parent, child, method_name) do
72
- parent.object.addGeneric(method_name, child.object)
73
- child.object.setGeneric("parent", parent.object)
74
- end
75
- end
76
-
77
- def build_p2c_assoc(parent, child, method_name)
78
- parent.object.class.has_many(method_name, child.object.class)
79
- child.object.class.has_one("parent", RGen::MetamodelBuilder::MMBase)
80
- end
81
-
82
- def set_attribute(node, attr, value)
83
- return unless node.object
84
- build_on_error(NoMethodError, :build_attribute, node, attr, value) do
85
- node.object.setGeneric(method_name(attr), value)
86
- end
87
- end
88
-
89
- def build_attribute(node, attr, value)
90
- node.object.class.has_attr(method_name(attr))
91
- end
73
+ def assoc_p2c(parent, child)
74
+ return unless parent.object && child.object
75
+ method_name = method_name(className(child.object))
76
+ build_on_error(NoMethodError, :build_p2c_assoc, parent, child, method_name) do
77
+ parent.object.addGeneric(method_name, child.object)
78
+ child.object.setGeneric("parent", parent.object)
79
+ end
80
+ end
81
+
82
+ def build_p2c_assoc(parent, child, method_name)
83
+ parent.object.class.has_many(method_name, child.object.class)
84
+ child.object.class.has_one("parent", RGen::MetamodelBuilder::MMBase)
85
+ end
86
+
87
+ def set_attribute(node, attr, value)
88
+ return unless node.object
89
+ build_on_error(NoMethodError, :build_attribute, node, attr, value) do
90
+ node.object.setGeneric(method_name(attr), value)
91
+ end
92
+ end
93
+
94
+ def build_attribute(node, attr, value)
95
+ node.object.class.has_attr(method_name(attr))
96
+ end
92
97
 
93
- protected
94
-
95
- # Helper method for implementing classes.
96
- # This method yields the given block.
97
- # If the metamodel should be create automatically (see constructor)
98
- # rescues +error+ and calls +builder_method+ with +args+, then
99
- # yields the block again.
100
- def build_on_error(error, builder_method, *args)
101
- begin
102
- yield
103
- rescue error
104
- if @create_mm
105
- send(builder_method, *args)
106
- yield
107
- else
108
- raise
109
- end
110
- end
111
- end
98
+ protected
99
+
100
+ # Helper method for implementing classes.
101
+ # This method yields the given block.
102
+ # If the metamodel should be create automatically (see constructor)
103
+ # rescues +error+ and calls +builder_method+ with +args+, then
104
+ # yields the block again.
105
+ def build_on_error(error, builder_method, *args)
106
+ begin
107
+ yield
108
+ rescue error
109
+ if @create_mm
110
+ send(builder_method, *args)
111
+ yield
112
+ else
113
+ raise
114
+ end
115
+ end
116
+ end
112
117
 
113
118
  end
114
119