rgen 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
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