wortsammler 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,117 @@
1
+
2
+ #
3
+ # this mixin provides a convenient interface
4
+ # for the syntaxtree
5
+ #
6
+
7
+ class Treetop::Runtime::SyntaxNode
8
+
9
+ # this delivers a child node of the AST
10
+ def child
11
+ elements.select{|e| e.is_ast?} if ! elements.nil?
12
+ end
13
+
14
+ # returns an array of all descendants of the current node
15
+ # in the AST in document order
16
+ def descendant
17
+ child.map{|e| [e, e.descendant]}.flatten.compact if not child.nil?
18
+ end
19
+
20
+ # returns this and all descendant in document order
21
+ def thisdescendant
22
+ [self, descendant].flatten
23
+ end
24
+
25
+ # returns all nodes to up to the AST root
26
+ def ancestor
27
+ if ! parent.nil?
28
+ [parent, parent.ancestor].flatten
29
+ end
30
+ end
31
+
32
+ # indicates if the current treetop node is important enough
33
+ # to be in the intended AST
34
+ def is_ast?
35
+ true # nonterminal? # parent.nil? or extension_modules.include?(Xmine)
36
+ end
37
+
38
+ # indicates if a meaningful name for the node in the AST
39
+ # is available
40
+ def has_rule_name?
41
+ not (extension_modules.nil? or extension_modules.empty?)
42
+ end
43
+
44
+ # returns a meaning name for the node in the AST
45
+ def rule_name
46
+ if has_rule_name? then
47
+ extension_modules.first.name.split("::").last.gsub(/[0-9]/,"")
48
+ else
49
+ "###"
50
+ end
51
+ end
52
+
53
+ # another quick info for a node
54
+ def to_info
55
+ rule_name + ": "+ text_value
56
+ end
57
+
58
+ # exposes a node in the AST as xml
59
+ def to_xml
60
+ if child.nil? or child.empty?
61
+ "#>" +interval.to_s + ":"+ text_value + "<#"
62
+ else
63
+ [ xml_start_tag,
64
+ (child.nil? ? [] : child).map{|x| x.to_xml},
65
+ xml_end_tag
66
+ ].join
67
+ end
68
+ end
69
+
70
+ # get the XML start tag
71
+ def xml_start_tag
72
+ if has_rule_name? then
73
+ "<" + rule_name + ">"
74
+ end
75
+ end
76
+
77
+ # get the XML end tag
78
+ def xml_end_tag
79
+ if has_rule_name? then
80
+ "</" + rule_name + ">"
81
+ end
82
+ end
83
+
84
+ # clean the tree by removing garbage nodes
85
+ # which are not part of the intended AST
86
+ def clean_tree(root_node)
87
+ return if(root_node.elements.nil?)
88
+ root_node.elements.delete_if{|node| not node.is_ast? }
89
+ root_node.elements.each{|e| e.clean_tree(e)}
90
+ end
91
+ end
92
+
93
+
94
+ class Treetop::Runtime::SyntaxNode
95
+ def as_xml
96
+ [(["<", getLabel, ">" ].join if getLabel),
97
+ (if elements
98
+ elements.map { |e| e.as_xml }.join
99
+ else
100
+ text_value
101
+ end),
102
+ (["</", getLabel, ">" ].join if getLabel)
103
+ ].join
104
+ end
105
+
106
+ def wrap(tag,body)
107
+ "<#{tag}>#{body}</#{tag}>"
108
+ end
109
+
110
+ def getLabel
111
+ nil
112
+ end
113
+
114
+
115
+ end
116
+
117
+
@@ -0,0 +1,428 @@
1
+ require "optparse" # for option parser
2
+ require 'wortsammler/log_helper'
3
+ require 'wortsammler/class.proolib.rb'
4
+ require 'wortsammler/class.Traceable.rb'
5
+ require 'wortsammler/class.Traceable.md.rb'
6
+ require 'wortsammler/version.rb'
7
+
8
+
9
+ options = {}
10
+ config = nil
11
+
12
+ optparse = OptionParser.new do|opts|
13
+ # Set a banner, displayed at the top
14
+ # of the help screen.
15
+ opts.banner = ["This is Wortsammler #{Wortsammler::VERSION}",
16
+ "",
17
+ "Usage: Wortsammler [options]",
18
+ "",
19
+ "examples:",
20
+ "",
21
+ " wortsammler -cbpm mymanifest.yaml",
22
+ " -- beautify collect process files from mymanifest.yaml",
23
+ "",
24
+ " wortsammler -cbpi .",
25
+ " -- beautify collect process files in current folder"
26
+ ].join("\n")
27
+
28
+ ##
29
+ # Define the options, and what they do
30
+
31
+ opts.separator nil
32
+ opts.separator "options:"
33
+ opts.separator nil
34
+
35
+ # This displays the help screen, all programs are
36
+ # assumed to have this option.
37
+ opts.on( '-h', '--help', 'display this screen' ) do
38
+ puts opts
39
+ exit
40
+ end
41
+
42
+
43
+ options[:version] = false
44
+ opts.on( "-v", '--version', 'print Version info, then turn on verbose mode' ) do
45
+ options[:version] = true
46
+ options[:verbose] = true
47
+ end
48
+
49
+ opts.separator nil
50
+
51
+ options[:init] = false
52
+ opts.on( "-n", '--init DIR', 'create a project folder in DIR' ) do|file|
53
+ options[:init] = file
54
+ end
55
+
56
+
57
+ opts.separator nil
58
+
59
+ options[:input_path] = false
60
+ opts.on( '-i', '--input PATH', 'set input file/project folder for processing') do|path|
61
+ options[:input_path] = path
62
+ end
63
+
64
+ options[:manifest] = false
65
+ opts.on( '-m', '--manifest PATH', 'set mainfest file for processing' ) do|file|
66
+ options[:manifest] = file
67
+ end
68
+
69
+ opts.separator nil
70
+
71
+ options[:outputformats] = ['pdf']
72
+ opts.on( '-f', '--format formatList', 'set the outputformat to formatList' ) do|formatlist|
73
+ options[:outputformats] = formatlist.split(":")
74
+ end
75
+
76
+ options[:outputfolder] = false
77
+ opts.on( '-o', '--output PATH', 'set the output to PATH' ) do|path|
78
+ options[:outputfolder] = path
79
+ end
80
+
81
+
82
+ opts.separator nil
83
+
84
+ options[:collect] = false
85
+ opts.on( '-c', '--collect', 'collect traceables by manifest' ) do
86
+ options[:collect] = true
87
+ end
88
+
89
+ options[:process] = false
90
+ opts.on( '-p', '--process', 'process documents by manifest' ) do
91
+ options[:process] = true
92
+ end
93
+
94
+
95
+ options[:beautify] = false
96
+ opts.on( "-b", '--beautify', 'bautify markdownfiles' ) do
97
+ options[:beautify] = true
98
+ end
99
+
100
+ end
101
+
102
+ ##
103
+ # now parse the commandline
104
+ #
105
+ begin
106
+ optparse.parse!
107
+ rescue OptionParser::ParseError => option
108
+ $log.error "Invalid option #{option}"
109
+ exit false
110
+
111
+ rescue RegexpError => error
112
+ $log.error "#{error}"
113
+ exit
114
+ end
115
+
116
+
117
+ module Wortsammler
118
+ def self.wortsammler_execute(options)
119
+ ##
120
+ #
121
+ # print version info
122
+ #
123
+ if options[:version] then
124
+ puts "Wortsammler #{Wortsammler::VERSION}"
125
+
126
+ pandoc=`pandocx -v`.split("\n")[0] rescue pandoc="error running pandoc"
127
+ xetex=`xelatex -v`.split("\n")[0] rescue pandoc="error running xelatex"
128
+
129
+ puts "found #{pandoc}"
130
+ puts "found #{xetex}"
131
+
132
+ end
133
+
134
+ ##
135
+ # initialize a project
136
+ #
137
+ if project_folder=options[:init] then
138
+ if File.exists?(project_folder)
139
+ $log.error "directory already exists: '#{project_folder}'"
140
+ exit(false)
141
+ end
142
+ Wortsammler::init_folders(project_folder)
143
+ end
144
+
145
+
146
+ ##
147
+ #
148
+ # load the manifest
149
+ #
150
+ config=nil
151
+ if config_file=options[:manifest] then
152
+ config = ProoConfig.new(config_file)
153
+ end
154
+
155
+ ##
156
+ # process input path
157
+ #
158
+ #
159
+ input_files=nil
160
+ if input_path = options[:input_path]
161
+ unless File.exists? input_path then
162
+ $log.error "path does not exist path '#{input_path}'"
163
+ exit(false)
164
+ end
165
+ if File.file?(input_path) #(RS_Mdc)
166
+ input_files=[input_path]
167
+ elsif File.exists?(input_path)
168
+ input_files=Dir["#{input_path}/**/*.md", "#{input_path}/**/*.markdown"]
169
+ end
170
+ end
171
+
172
+ ##
173
+ #
174
+ # beautify markdown files
175
+ #
176
+ #
177
+ cleaner = PandocBeautifier.new($log)
178
+
179
+ if options[:beautify]
180
+
181
+
182
+ # process path
183
+
184
+ if input_files then
185
+ input_files.each{|f| cleaner.beautify(f)}
186
+ end
187
+
188
+ # process manifest
189
+
190
+ if config then
191
+ config.input.each{|f| cleaner.beautify(f)}
192
+ end
193
+
194
+ unless input_files or config
195
+ $log.error "no input specified. Please use -m or -i to specify input"
196
+ exit false
197
+ end
198
+ end
199
+
200
+ ##
201
+ # process collect in markdown files
202
+ #
203
+
204
+ if options[:collect]
205
+
206
+ # collect by path
207
+
208
+ if input_files then
209
+ $log.warn "collect from path not yet implemented"
210
+ end
211
+
212
+ # collect by manifest
213
+
214
+ if config then
215
+ Wortsammler.collect_traces(config)
216
+ end
217
+
218
+ unless input_files or config
219
+ $log.error "no input specified. Please use -m or -i to specify input"
220
+ exit false
221
+ end
222
+ end
223
+
224
+
225
+
226
+ ##
227
+ # process files
228
+ #
229
+ if options[:process]
230
+
231
+ if input_files then
232
+
233
+ if options[:outputformats] then
234
+ outputformats = options[:outputformats]
235
+ end
236
+
237
+ if options[:outputfolder] then
238
+ outputfolder = options[:outputfolder]
239
+ else
240
+ $log.error "no output folder specified"
241
+ exit false
242
+ end
243
+
244
+ unless File.exists?(outputfolder) then
245
+ $log.info "creating folder '#{outputfolder}'"
246
+ FileUtils.mkdir_p(outputfolder)
247
+ end
248
+
249
+ input_files.each{|f| cleaner.render_single_document(f, outputfolder, outputformats)}
250
+ end
251
+
252
+ # collect by manifest
253
+
254
+ if config then
255
+ cleaner.generateDocument(config.input,
256
+ config.outdir,
257
+ config.outname,
258
+ config.format,
259
+ config.vars,
260
+ config.editions,
261
+ config.snippets,
262
+ config)
263
+ end
264
+
265
+ unless input_files or config
266
+ $log.error "no input specified. Please use -m or -i to specify input"
267
+ exit false
268
+ end
269
+ end
270
+
271
+ end #execute
272
+
273
+
274
+ #
275
+ # This method can verify wortsammler options delivered by option parser
276
+ # @param options [Hash] Option hash delivered by option parser
277
+ #
278
+ # @return [Boolean] true if successful. otherwise exits the program
279
+ def self.verify_options(options)
280
+ if options[:input_path] or options[:manifest] then
281
+ unless options[:process] or options[:beautify] or options[:collect] then
282
+ $log.error "no procesing option (p, b, c) specified"
283
+ exit false
284
+ end
285
+ end
286
+
287
+ if options[:input_path] and options[:process] then
288
+ unless options[:outputfolder] then
289
+ $log.error "no output folder specified for input path"
290
+ exit false
291
+ end
292
+ end
293
+
294
+ true
295
+ end #verify_options
296
+
297
+
298
+
299
+ #
300
+ # Initialize a project directory. It creates a bunch of
301
+ # folders, a root document, a manifest and an intial rakefile
302
+ #
303
+ # @param root [String] [The path to the root folder of the sample project]
304
+ #
305
+ # @return [Boolean] [always true]
306
+ def self.init_folders(root)
307
+
308
+ folders=["ZSUPP_Manifests",
309
+ "ZGEN_Documents",
310
+ "ZSUPP_Tools",
311
+ "ZSUPP_Styles",
312
+ "ZGEN_RequirementsTracing",
313
+ "001_Main"
314
+ ]
315
+
316
+ folders.each{|folder|
317
+ FileUtils.mkdir_p("#{root}/#{folder}")
318
+ }
319
+
320
+ resourcedir=File.dirname(__FILE__)+"/../../resources"
321
+ Dir["#{resourcedir}/*.yaml"].each{|f|
322
+ FileUtils.cp(f, "#{root}/ZSUPP_Manifests")
323
+ }
324
+ FileUtils.cp("#{resourcedir}/main.md", "#{root}/001_Main")
325
+ FileUtils.cp("#{resourcedir}/rakefile.rb", "#{root}/ZSUPP_Tools")
326
+ FileUtils.cp("#{resourcedir}/default.latex", "#{root}/ZSUPP_Styles")
327
+ FileUtils.cp("#{resourcedir}/logo.jpg", "#{root}/ZSUPP_Styles")
328
+
329
+ true
330
+ end
331
+
332
+
333
+ #
334
+ # This collects the traces in a doucment specified by a manifest
335
+ # @param config [ProolibConfig] the manifest model
336
+ #
337
+ # @return [type] no specific return
338
+ def self.collect_traces(config)
339
+
340
+ files = config.input # get the input files
341
+ rootdir = config.rootdir # get the root directory
342
+
343
+ downstream_tracefile = config.downstream_tracefile # String to save downstram filenames
344
+ reqtracefile_base = config.reqtracefile_base # string to determine the requirements tracing results
345
+ upstream_tracefiles = config.upstream_tracefiles # String to read upstream tracefiles
346
+
347
+ traceable_set = TraceableSet.new
348
+
349
+ # collect all traceables in input
350
+ files.each{|f|
351
+ x=TraceableSet.processTracesInMdFile(f)
352
+ traceable_set.merge(x)
353
+ }
354
+
355
+ # collect all upstream traceables
356
+ #
357
+ upstream_traceable_set=TraceableSet.new
358
+ unless upstream_tracefiles.nil?
359
+ upstream_tracefiles.each{|f|
360
+ x=TraceableSet.processTracesInMdFile(f)
361
+ upstream_traceable_set.merge(x)
362
+ }
363
+ end
364
+
365
+ # check undefined traces
366
+ all_traceable_set=TraceableSet.new
367
+ all_traceable_set.merge(traceable_set)
368
+ all_traceable_set.merge(upstream_traceable_set)
369
+ undefineds=all_traceable_set.undefined_ids
370
+ $log.warn "undefined traces: #{undefineds.join(' ')}" unless undefineds.empty?
371
+
372
+
373
+ # check duplicates
374
+ duplicates=all_traceable_set.duplicate_traces
375
+ if duplicates.count > 0
376
+ $logger.warn "duplicated trace ids found:"
377
+ duplicates.each{|d| d.each{|t| $log.warn "#{t.id} in #{t.info}"}}
378
+ end
379
+
380
+ # write traceables to the intermediate Tracing file
381
+ outname="#{rootdir}/#{reqtracefile_base}.md"
382
+
383
+ # poke ths sort order for the traceables
384
+ all_traceable_set.sort_order=config.traceSortOrder if config.traceSortOrder
385
+ traceable_set.sort_order=config.traceSortOrder if config.traceSortOrder
386
+ # generate synopsis of traceableruby 1.8.7 garbage at end of file
387
+
388
+
389
+ tracelist=""
390
+ File.open(outname, "w"){|fx|
391
+ fx.puts ""
392
+ fx.puts "\\clearpage"
393
+ fx.puts ""
394
+ fx.puts "# Requirements Tracing"
395
+ fx.puts ""
396
+ tracelist=all_traceable_set.reqtraceSynopsis(:SPECIFICATION_ITEM)
397
+ fx.puts tracelist
398
+ }
399
+
400
+ # output the graphxml
401
+ # write traceables to the intermediate Tracing file
402
+ outname="#{rootdir}/#{reqtracefile_base}.graphml"
403
+ File.open(outname, "w") {|fx| fx.puts all_traceable_set.to_graphml}
404
+
405
+ outname="#{rootdir}/#{reqtracefile_base}Compare.txt"
406
+ File.open(outname, "w") {|fx| fx.puts traceable_set.to_compareEntries}
407
+
408
+ # write the downstream_trace file - to be included in downstream - speciifcations
409
+ outname="#{rootdir}/#{downstream_tracefile}"
410
+ File.open(outname, "w") {|fx|
411
+ fx.puts ""
412
+ fx.puts "\\clearpage"
413
+ fx.puts ""
414
+ fx.puts "# Upstream Requirements"
415
+ fx.puts ""
416
+ fx.puts traceable_set.to_downstream_tracefile(:SPECIFICATION_ITEM)
417
+ } unless downstream_tracefile.nil?
418
+
419
+
420
+ # now add the upstream traces to input
421
+ files.concat( upstream_tracefiles) unless upstream_tracefiles.nil?
422
+
423
+ nil
424
+ end
425
+ end # module
426
+
427
+ Wortsammler.verify_options(options)
428
+ Wortsammler.wortsammler_execute(options)
@@ -0,0 +1,8 @@
1
+ # setup the logger
2
+ require 'Logger'
3
+ $log = Logger.new(STDOUT)
4
+ $log.level = Logger::INFO
5
+ $log.datetime_format= "%Y-%m-%d %H:%M:%S"
6
+ $log.formatter = proc do |severity, datetime, progname, msg|
7
+ "[#{severity}] #{progname}: #{datetime.strftime($log.datetime_format)}: #{msg}\n"
8
+ end
@@ -0,0 +1,55 @@
1
+
2
+ grammar TraceInMarkdown
3
+
4
+ rule top
5
+ (document '' )
6
+ {def getLabel ; "top" ; end}
7
+ end
8
+
9
+ rule document
10
+ ( (noMarkupText / trace / markupAbort)* '')
11
+ {def getLabel ; "document" ; end}
12
+ end
13
+
14
+ rule noMarkupText
15
+ [^\[]+ { def as_xml; wrap('noMarkupText',super); end }
16
+ end
17
+
18
+ rule markupAbort
19
+ "["
20
+ end
21
+
22
+ rule trace
23
+ traceId s? traceHead s? traceBody uptraces:traceUpLink
24
+ {def getLabel ; "trace" ; end}
25
+ end
26
+
27
+ rule traceId
28
+ "[" payload:label "]"
29
+ end
30
+
31
+
32
+ rule label
33
+ [a-zA-Z]+ "_" [a-zA-Z]+ "_" [0-9]+
34
+ end
35
+
36
+ rule traceHead
37
+ '**' payload:(!'*' . / '\*')+ '**'
38
+ end
39
+
40
+ rule traceBody
41
+ "{" payload:(nestedBody / [^{}])+ "}"
42
+ end
43
+
44
+ rule nestedBody
45
+ "{" (nestedBody / [^{}])+ "}"
46
+ end
47
+
48
+ rule traceUpLink
49
+ "(" payload:(","? s? label)* ")"
50
+ end
51
+
52
+ rule s
53
+ [\s]+
54
+ end
55
+ end
@@ -0,0 +1,28 @@
1
+
2
+ ##
3
+ #
4
+ # (c) 2013 Bernhard Weichel
5
+ #
6
+ #
7
+
8
+
9
+ ##
10
+ # generate a task for each manifest file
11
+ #
12
+ Dir["../ZSUPP_Manifests/*.yaml"].each{|file|
13
+ taskdesc=File.basename(file, ".yaml")
14
+ taskname=taskdesc.split("_")[0]
15
+ desc "generate #{taskdesc}"
16
+ task taskname do
17
+ cmd="wortsammler -cbpm #{file}"
18
+ sh cmd
19
+ end
20
+ }
21
+
22
+ ##
23
+ # the default task
24
+
25
+ desc "print this help"
26
+ task :default do
27
+ system "rake -T"
28
+ end
@@ -0,0 +1,3 @@
1
+ module Wortsammler
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,5 @@
1
+ require "wortsammler/version"
2
+
3
+ module Wortsammler
4
+ # Your code goes here...
5
+ end
Binary file