rgen 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -74,3 +74,10 @@
74
74
  =0.4.5 (Nov 17th, 2008)
75
75
 
76
76
  * Updated XMI1.1 serializer to support explicit placement of elements on content level of the XMI file
77
+
78
+ =0.4.6 (Mar 1st, 2009)
79
+
80
+ * Bugfix: expand :foreach silently assumed current context if :foreach evalutated to nil
81
+ * Bugfix: fixed unit test for non-Windows plattforms (\r\n)
82
+ * Bugfix: depending on the Ruby version and/or platform constants used in templates could not be resolved
83
+ * Added automatic line ending detection (\n or \r\n) for template language +nl+ command
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007 Martin Thiede
1
+ Copyright (c) 2009 Martin Thiede
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -0,0 +1,45 @@
1
+ require 'rake/gempackagetask'
2
+ require 'rake/rdoctask'
3
+
4
+ RGenGemSpec = Gem::Specification.new do |s|
5
+ s.name = %q{rgen}
6
+ s.version = "0.4.6"
7
+ s.date = %q{2009-03-01}
8
+ s.summary = %q{Ruby Modelling and Generator Framework}
9
+ s.email = %q{martin dot thiede at gmx de}
10
+ s.homepage = %q{ruby-gen.org}
11
+ s.rubyforge_project = %q{rgen}
12
+ s.description = %q{RGen is a framework supporting Model Driven Software Development (MDSD). This means that it helps you build Metamodels, instantiate Models, modify and transform Models and finally generate arbitrary textual content from it.}
13
+ s.has_rdoc = true
14
+ s.authors = ["Martin Thiede"]
15
+ gemfiles = Rake::FileList.new
16
+ gemfiles.include("{lib,test,redist}/**/*")
17
+ gemfiles.include("README", "CHANGELOG", "MIT-LICENSE", "Rakefile")
18
+ gemfiles.exclude(/\b\.bak\b/)
19
+ s.files = gemfiles
20
+ s.rdoc_options = ["--main", "README", "-x", "redist", "-x", "test", "-x", "metamodels"]
21
+ s.extra_rdoc_files = ["README", "CHANGELOG", "MIT-LICENSE"]
22
+ end
23
+
24
+ Rake::RDocTask.new do |rd|
25
+ rd.main = "README"
26
+ rd.rdoc_files.include("README", "CHANGELOG", "MIT-LICENSE", "lib/**/*.rb")
27
+ rd.rdoc_files.exclude("lib/metamodels")
28
+ rd.rdoc_dir = "doc"
29
+ end
30
+
31
+ RGenPackageTask = Rake::GemPackageTask.new(RGenGemSpec) do |p|
32
+ p.need_zip = true
33
+ end
34
+
35
+ task :publish_doc do
36
+ sh %{pscp -r doc/* thiedem@rubyforge.org:/var/www/gforge-projects/rgen}
37
+ end
38
+
39
+ task :prepare_package_rdoc => :rdoc do
40
+ RGenPackageTask.package_files.include("doc/**/*")
41
+ end
42
+
43
+ task :release => [:prepare_package_rdoc, :package]
44
+
45
+ task :clobber => [:clobber_rdoc, :clobber_package]
@@ -19,11 +19,10 @@ class DirectoryTemplateContainer
19
19
  end
20
20
 
21
21
  def load(dir)
22
- #print "Loading templates in #{dir} ...\n"
23
22
  Dir.foreach(dir) { |f|
24
23
  qf = dir+"/"+f
25
24
  if !File.directory?(qf) && f =~ /^(.*)\.tpl$/
26
- (@containers[$1] = TemplateContainer.dup.new(@metamodel, @output_path, self,qf)).load
25
+ (@containers[$1] = TemplateContainer.new(@metamodel, @output_path, self,qf)).load
27
26
  elsif File.directory?(qf) && f != "." && f != ".."
28
27
  (@containers[f] = DirectoryTemplateContainer.new(@metamodel, @output_path, self)).load(qf)
29
28
  end
@@ -8,190 +8,208 @@ require 'rgen/template_language/template_helper'
8
8
 
9
9
  module RGen
10
10
 
11
- module TemplateLanguage
12
-
13
- class TemplateContainer
14
- include TemplateHelper
15
-
16
- def initialize(metamodels, output_path, parent, filename)
17
- @templates = {}
18
- @parent = parent
19
- @filename = filename
20
- @indent = 0
21
- @output_path = output_path
22
- raise StandardError.new("Can not set metamodel, dup class first") if self.class == TemplateContainer
23
- @@metamodels = metamodels
24
- @@metamodels = [ @@metamodels ] unless @@metamodels.is_a?(Array)
25
- end
26
-
27
- def load
28
- #print "Loading templates in #{@filename} ...\n"
29
- File.open(@filename) { |f|
30
- begin
31
- ERB.new(f.read,nil,nil,'@output').result(binding)
32
- rescue Exception => e
33
- processAndRaise(e)
34
- end
35
- }
36
- end
37
-
38
- # if this container can handle the call, the expansion result is returned
39
- # otherwise expand is called on the appropriate container and the result is added to @output
40
- def expand(template, *all_args)
41
- args, params = _splitArgsAndOptions(all_args)
42
- if params[:foreach].is_a? Enumerable
43
- _expand_foreach(template, args, params)
44
- else
45
- _expand(template, args, params)
46
- end
47
- end
48
-
49
- def this
50
- @context
51
- end
52
-
53
- def method_missing(name, *args)
54
- @context.send(name, *args)
55
- end
56
-
57
- def self.const_missing(name)
58
- super unless @@metamodels
59
- @@metamodels.each do |mm|
60
- return mm.const_get(name) rescue NameError
61
- end
62
- super
63
- end
64
-
65
- private
66
-
67
- def nonl
68
- @output.ignoreNextNL
69
- end
70
-
71
- def nows
72
- @output.ignoreNextWS
73
- end
74
-
75
- def nl
76
- _direct_concat("\n")
77
- end
78
-
79
- def ws
80
- _direct_concat(" ")
81
- end
82
-
83
- def iinc
84
- @indent += 1
85
- @output.indent = @indent
86
- end
87
-
88
- def idec
89
- @indent -= 1 if @indent > 0
90
- @output.indent = @indent
11
+ module TemplateLanguage
12
+
13
+ class TemplateContainer
14
+ include TemplateHelper
15
+
16
+ def initialize(metamodels, output_path, parent, filename)
17
+ @templates = {}
18
+ @parent = parent
19
+ @filename = filename
20
+ @indent = 0
21
+ @output_path = output_path
22
+ @metamodels = metamodels
23
+ @metamodels = [ @metamodels ] unless @metamodels.is_a?(Array)
24
+ end
25
+
26
+ def load
27
+ File.open(@filename,"rb") do |f|
28
+ begin
29
+ @@metamodels = @metamodels
30
+ fileContent = f.read
31
+ _detectNewLinePattern(fileContent)
32
+ ERB.new(fileContent,nil,nil,'@output').result(binding)
33
+ rescue Exception => e
34
+ processAndRaise(e)
91
35
  end
92
-
93
- def define(template, params={}, &block)
94
- @templates[template] ||= {}
95
- cls = params[:for] || Object
96
- @templates[template][cls] = block
36
+ end
37
+ end
38
+
39
+ # if this container can handle the call, the expansion result is returned
40
+ # otherwise expand is called on the appropriate container and the result is added to @output
41
+ def expand(template, *all_args)
42
+ args, params = _splitArgsAndOptions(all_args)
43
+ if params.has_key?(:foreach)
44
+ raise StandardError.new("expand :foreach argument is not enumerable") \
45
+ unless params[:foreach].is_a?(Enumerable)
46
+ _expand_foreach(template, args, params)
47
+ else
48
+ _expand(template, args, params)
49
+ end
50
+ end
51
+
52
+ def this
53
+ @context
54
+ end
55
+
56
+ def method_missing(name, *args)
57
+ @context.send(name, *args)
58
+ end
59
+
60
+ def self.const_missing(name)
61
+ super unless @@metamodels
62
+ @@metamodels.each do |mm|
63
+ return mm.const_get(name) rescue NameError
64
+ end
65
+ super
66
+ end
67
+
68
+ private
69
+
70
+ def nonl
71
+ @output.ignoreNextNL
72
+ end
73
+
74
+ def nows
75
+ @output.ignoreNextWS
76
+ end
77
+
78
+ def nl
79
+ _direct_concat(@newLinePattern)
80
+ end
81
+
82
+ def ws
83
+ _direct_concat(" ")
84
+ end
85
+
86
+ def iinc
87
+ @indent += 1
88
+ @output.indent = @indent
89
+ end
90
+
91
+ def idec
92
+ @indent -= 1 if @indent > 0
93
+ @output.indent = @indent
94
+ end
95
+
96
+ def define(template, params={}, &block)
97
+ @templates[template] ||= {}
98
+ cls = params[:for] || Object
99
+ @templates[template][cls] = block
100
+ end
101
+
102
+ def file(name, indentString=nil)
103
+ old_output, @output = @output, OutputHandler.new(@indent, indentString || @parent.indentString)
104
+ begin
105
+ yield
106
+ rescue Exception => e
107
+ processAndRaise(e)
108
+ end
109
+ path = ""
110
+ path += @output_path+"/" if @output_path
111
+ dirname = File.dirname(path+name)
112
+ FileUtils.makedirs(dirname) unless File.exist?(dirname)
113
+ File.open(path+name,"wb") { |f| f.write(@output) }
114
+ @output = old_output
115
+ end
116
+
117
+ # private private
118
+
119
+ def _expand_foreach(template, args, params)
120
+ sep = params[:separator]
121
+ params[:foreach].each_with_index {|e,i|
122
+ single_params = params.dup
123
+ single_params[:for] = e
124
+ _direct_concat(sep.to_s) if sep && i > 0
125
+ _expand(template, args, single_params)
126
+ }
127
+ end
128
+
129
+ LOCAL_TEMPLATE_REGEX = /^:*(\w+)$/
130
+
131
+ def _expand(template, args, params)
132
+ raise StandardError.new("expand :for argument evaluates to nil") if params.has_key?(:for) && params[:for].nil?
133
+ context = params[:for]
134
+ @indent = params[:indent] || @indent
135
+ # if this is the first call to expand within this container, @output is nil
136
+ noIndentNextLine = params[:noIndentNextLine]
137
+ noIndentNextLine = (@output.to_s.size > 0 && @output.to_s[-1] != "\n"[0]) if noIndentNextLine.nil?
138
+ old_context, @context = @context, context if context
139
+ local_output = nil
140
+ if template =~ LOCAL_TEMPLATE_REGEX
141
+ tplname = $1
142
+ raise StandardError.new("Template not found: #{$1}") unless @templates[tplname]
143
+ old_output, @output = @output, OutputHandler.new(@indent, @parent.indentString)
144
+ @output.noIndentNextLine if noIndentNextLine
145
+ _call_template(tplname, @context, args)
146
+ local_output, @output = @output, old_output
147
+ else
148
+ local_output = @parent.expand(template, *(args.dup << {:for => @context, :indent => @indent, :noIndentNextLine => noIndentNextLine}))
149
+ end
150
+ _direct_concat(local_output)
151
+ @context = old_context if old_context
152
+ local_output
153
+ end
154
+
155
+ def processAndRaise(e, tpl=nil)
156
+ bt = e.backtrace.dup
157
+ e.backtrace.each_with_index do |t,i|
158
+ if t =~ /\(erb\):(\d+):/
159
+ bt[i] = "#{@filename}:#{$1}"
160
+ bt[i] += ":in '#{tpl}'" if tpl
161
+ break
97
162
  end
98
-
99
- def file(name, indentString=nil)
100
- old_output, @output = @output, OutputHandler.new(@indent, indentString || @parent.indentString)
163
+ end
164
+ raise e, e.to_s, bt
165
+ end
166
+
167
+ def _call_template(tpl, context, args)
168
+ found = false
169
+ @templates[tpl].each_pair do |key, value|
170
+ if context.is_a?(key)
171
+ proc = @templates[tpl][key]
172
+ arity = proc.arity
173
+ arity = 0 if arity == -1 # if no args are given
174
+ raise StandardError.new("Wrong number of arguments calling template #{tpl}: #{args.size} for #{arity} "+
175
+ "(Beware: Hashes as last arguments are taken as options and are ignored)") \
176
+ if arity != args.size
101
177
  begin
102
- yield
178
+ @@metamodels = @metamodels
179
+ proc.call(*args)
103
180
  rescue Exception => e
104
- processAndRaise(e)
105
- end
106
- path = ""
107
- path += @output_path+"/" if @output_path
108
- dirname = File.dirname(path+name)
109
- FileUtils.makedirs(dirname) unless File.exist?(dirname)
110
- File.open(path+name,"w") { |f| f.write(@output) }
111
- @output = old_output
112
- end
113
-
114
- # private private
115
-
116
- def _expand_foreach(template, args, params)
117
- sep = params[:separator]
118
- params[:foreach].each_with_index {|e,i|
119
- single_params = params.dup
120
- single_params[:for] = e
121
- _direct_concat(sep.to_s) if sep && i > 0
122
- _expand(template, args, single_params)
123
- }
124
- end
125
-
126
- LOCAL_TEMPLATE_REGEX = /^:*(\w+)$/
127
-
128
- def _expand(template, args, params)
129
- raise StandardError.new("expand :for argument evaluates to nil") if params.has_key?(:for) && params[:for].nil?
130
- context = params[:for]
131
- @indent = params[:indent] || @indent
132
- # if this is the first call to expand within this container, @output is nil
133
- noIndentNextLine = params[:noIndentNextLine]
134
- noIndentNextLine = (@output.to_s.size > 0 && @output.to_s[-1] != "\n"[0]) if noIndentNextLine.nil?
135
- old_context, @context = @context, context if context
136
- local_output = nil
137
- if template =~ LOCAL_TEMPLATE_REGEX
138
- tplname = $1
139
- raise StandardError.new("Template not found: #{$1}") unless @templates[tplname]
140
- old_output, @output = @output, OutputHandler.new(@indent, @parent.indentString)
141
- @output.noIndentNextLine if noIndentNextLine
142
- _call_template(tplname, @context, args)
143
- local_output, @output = @output, old_output
144
- else
145
- local_output = @parent.expand(template, *(args.dup << {:for => @context, :indent => @indent, :noIndentNextLine => noIndentNextLine}))
146
- end
147
- _direct_concat(local_output)
148
- @context = old_context if old_context
149
- local_output
150
- end
151
-
152
- def processAndRaise(e, tpl=nil)
153
- bt = e.backtrace.dup
154
- e.backtrace.each_with_index do |t,i|
155
- if t =~ /\(erb\):(\d+):/
156
- bt[i] = "#{@filename}:#{$1}"
157
- bt[i] += ":in '#{tpl}'" if tpl
158
- break
159
- end
160
- end
161
- raise e, e.to_s, bt
162
- end
163
-
164
- def _call_template(tpl, context, args)
165
- found = false
166
- @templates[tpl].each_pair { |key, value|
167
- if context.is_a?(key)
168
- proc = @templates[tpl][key]
169
- arity = proc.arity
170
- arity = 0 if arity == -1 # if no args are given
171
- raise StandardError.new("Wrong number of arguments calling template #{tpl}: #{args.size} for #{arity} "+
172
- "(Beware: Hashes as last arguments are taken as options and are ignored)") \
173
- if arity != args.size
174
- begin
175
- proc.call(*args)
176
- rescue Exception => e
177
- processAndRaise(e, tpl)
178
- end
179
- found = true
180
- end
181
- }
182
- raise StandardError.new("Template class not matching: #{tpl} for #{context.class.name}") unless found
183
- end
184
-
185
- def _direct_concat(s)
186
- if @output.is_a? OutputHandler
187
- @output.direct_concat(s)
188
- else
189
- @output << s
190
- end
181
+ processAndRaise(e, tpl)
191
182
  end
192
-
183
+ found = true
193
184
  end
194
-
195
185
  end
196
-
197
- end
186
+ raise StandardError.new("Template class not matching: #{tpl} for #{context.class.name}") unless found
187
+ end
188
+
189
+ def _direct_concat(s)
190
+ if @output.is_a? OutputHandler
191
+ @output.direct_concat(s)
192
+ else
193
+ @output << s
194
+ end
195
+ end
196
+
197
+ def _detectNewLinePattern(text)
198
+ tests = 0
199
+ rnOccurances = 0
200
+ text.scan(/(\r?)\n/) do |groups|
201
+ tests += 1
202
+ rnOccurances += 1 if groups[0] == "\r"
203
+ break if tests >= 10
204
+ end
205
+ if rnOccurances > (tests / 2)
206
+ @newLinePattern = "\r\n"
207
+ else
208
+ @newLinePattern = "\n"
209
+ end
210
+ end
211
+ end
212
+
213
+ end
214
+
215
+ end