wortsammler 0.0.2

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.
@@ -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