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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +131 -0
- data/README.pdf +0 -0
- data/Rakefile +34 -0
- data/bin/wortsammler +4 -0
- data/lib/wortsammler/class.Traceable.md.rb +104 -0
- data/lib/wortsammler/class.Traceable.rb +387 -0
- data/lib/wortsammler/class.proolib.rb +747 -0
- data/lib/wortsammler/class.treetopHelper.rb +117 -0
- data/lib/wortsammler/exe.wortsammler.rb +428 -0
- data/lib/wortsammler/log_helper.rb +8 -0
- data/lib/wortsammler/mdTraceParser.treetop +55 -0
- data/lib/wortsammler/rake_helper.rb +28 -0
- data/lib/wortsammler/version.rb +3 -0
- data/lib/wortsammler.rb +5 -0
- data/pkg/wortsammler-0.0.1.gem +0 -0
- data/resources/default.latex +225 -0
- data/resources/logo.jpg +0 -0
- data/resources/main.md +268 -0
- data/resources/rakefile.rb +5 -0
- data/resources/requirementsSynopsis.graphml +17 -0
- data/resources/sample_the-sample-document.yaml +51 -0
- data/spec/test.graphml +74 -0
- data/spec/traceable_spec.rb +299 -0
- data/spec/wortsammler_spec.rb +168 -0
- data/testresults/wortsammler_testresults.html +408 -0
- data/testresults/wortsammler_testresults.log +59 -0
- data/wortsammler.gemspec +53 -0
- metadata +282 -0
@@ -0,0 +1,387 @@
|
|
1
|
+
#
|
2
|
+
# These class represents the management of Traceable object
|
3
|
+
#
|
4
|
+
# TraceableSet
|
5
|
+
# Traceable
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'nokogiri'
|
10
|
+
#require 'amatch'
|
11
|
+
require 'diffy'
|
12
|
+
#require 'ruby-debug'
|
13
|
+
|
14
|
+
# this class represents a set of traceables
|
15
|
+
class TraceableSet
|
16
|
+
|
17
|
+
|
18
|
+
public
|
19
|
+
|
20
|
+
#
|
21
|
+
# Initialize the traceable set
|
22
|
+
#
|
23
|
+
# @return [type] [description]
|
24
|
+
def initialize()
|
25
|
+
# the traces
|
26
|
+
@traces={}
|
27
|
+
|
28
|
+
# the list of supporters
|
29
|
+
# supporters for foo 0 @@supported_by["foo"]
|
30
|
+
@supported_by={}
|
31
|
+
|
32
|
+
|
33
|
+
# define the sort order policy
|
34
|
+
# it is the same for all slots
|
35
|
+
@sortOrder=[]
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# [add add a traceable to the Traceable set]
|
41
|
+
# @param traceable [Traceable] The traceable which shall be added
|
42
|
+
# * first
|
43
|
+
# * second
|
44
|
+
#
|
45
|
+
# @return [type] [description]
|
46
|
+
def add(traceable)
|
47
|
+
#TOOD: check traceable
|
48
|
+
#TODO: check if append can be optimized
|
49
|
+
|
50
|
+
@traces[traceable.id] = [@traces[traceable.id], traceable].flatten.compact
|
51
|
+
|
52
|
+
traceable.contributes_to.each do |t|
|
53
|
+
@supported_by[t] = [@supported_by[t], traceable.id].flatten.compact
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
#
|
59
|
+
# expose added traceables found as a result of comparing two TraceableSets
|
60
|
+
# @param reference_set [TraceableSet] The set of traceables used as reference
|
61
|
+
# @param category [Symbol] Restrict the comparison to a particlar category
|
62
|
+
#
|
63
|
+
# @return [Array] the ids of the added traces (list of trace_id which are not in @referece_set)
|
64
|
+
def added_trace_ids(reference_set, category=nil)
|
65
|
+
self.all_trace_ids(category) - reference_set.all_trace_ids(category)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
#
|
70
|
+
# expose changed traceables
|
71
|
+
# @param reference_set [TraceableSet] the set of traceables used as reference
|
72
|
+
# @param category [Symbol] Restrict the operation to traceables of this category.
|
73
|
+
#
|
74
|
+
# @return [Array] List of trace_id which changed not in reference_set
|
75
|
+
def changed_trace_ids(reference_set, category=nil)
|
76
|
+
candidates=self.all_trace_ids(category) & reference_set.all_trace_ids(category)
|
77
|
+
candidates.map{|candidate|
|
78
|
+
self[candidate].get_diff(reference_set[candidate])
|
79
|
+
}.compact
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# expose *unchanged* traceables
|
84
|
+
# @param reference_set [TraceableSet] the set of traceables used as reference
|
85
|
+
# @param category [Symbol] Restrict the operation to traceables of this category.
|
86
|
+
#
|
87
|
+
# @return [Array] List of trace_id which unchanged
|
88
|
+
def unchanged_trace_ids(reference_set, category=nil)
|
89
|
+
candidates=self.all_trace_ids(category) & reference_set.all_trace_ids(category)
|
90
|
+
candidates.select{|candidate|
|
91
|
+
self[candidate].get_diff(reference_set[candidate]).nil?
|
92
|
+
}.compact
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
#
|
97
|
+
# expose *deleted* traceables
|
98
|
+
# @param reference_set [TraceableSet] the set of traceables used as reference
|
99
|
+
# @param category [Symbol] Restrict the operation to traceables of this category.
|
100
|
+
#
|
101
|
+
# @return [Array] List of trace_id which are deleted (not in current set)
|
102
|
+
def deleted_trace_ids(reference_set, category=nil)
|
103
|
+
reference_set.all_trace_ids(category) - self.all_trace_ids(category)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# export the trace as graphml for yed
|
108
|
+
# @return - the requirements tree in graphml
|
109
|
+
def to_graphml
|
110
|
+
f = File.open("#{File.dirname(__FILE__)}/../../resources/requirementsSynopsis.graphml")
|
111
|
+
doc = Nokogiri::XML(f)
|
112
|
+
f.close
|
113
|
+
|
114
|
+
graph=doc.xpath("//xmlns:graph").first
|
115
|
+
|
116
|
+
# generate all nodes
|
117
|
+
self.all_traces(nil).each{|theTrace|
|
118
|
+
n_node = Nokogiri::XML::Node.new "node", doc
|
119
|
+
n_node["id"] = theTrace.id
|
120
|
+
n_data = Nokogiri::XML::Node.new "data", doc
|
121
|
+
n_data["key"]= "d6"
|
122
|
+
n_ShapeNode = Nokogiri::XML::Node.new "y:ShapeNode", doc
|
123
|
+
n_NodeLabel = Nokogiri::XML::Node.new "y:NodeLabel", doc
|
124
|
+
n_NodeLabel.content = "[#{theTrace.id}] #{theTrace.header_orig}"
|
125
|
+
n_ShapeNode << n_NodeLabel
|
126
|
+
n_data << n_ShapeNode
|
127
|
+
n_node << n_data
|
128
|
+
graph << n_node
|
129
|
+
|
130
|
+
theTrace.contributes_to.each{|up|
|
131
|
+
n_edge=Nokogiri::XML::Node.new "edge", doc
|
132
|
+
n_edge["source" ] = theTrace.id
|
133
|
+
n_edge["target" ] = up
|
134
|
+
n_edge["id" ] = "#{up}_#{theTrace.id}"
|
135
|
+
graph << n_edge
|
136
|
+
}
|
137
|
+
}
|
138
|
+
xp(doc).to_xml
|
139
|
+
end
|
140
|
+
|
141
|
+
# this delivers an array ids of all Traceables
|
142
|
+
# @param [Symbol] selected_category the category of the deisred Traceables
|
143
|
+
# if nil is given, then all Traceables are returned
|
144
|
+
# @return [Array of String] an array of the registered Traceables
|
145
|
+
# of the selectedCategory
|
146
|
+
def all_trace_ids(selected_category = nil)
|
147
|
+
@traces.keys.select{|x|
|
148
|
+
y = @traces[x].first
|
149
|
+
selected_category.nil? or y.category == selected_category
|
150
|
+
}.sort
|
151
|
+
end
|
152
|
+
|
153
|
+
#this delivers an array of all traces
|
154
|
+
|
155
|
+
|
156
|
+
#
|
157
|
+
# return an array of all traces of a given category
|
158
|
+
# @param selected_category [Symbol] the category of traceables to return
|
159
|
+
#
|
160
|
+
# @return [Array of Traceable] The array of traceables
|
161
|
+
def all_traces(selected_category = nil)
|
162
|
+
all_trace_ids(selected_category).map{|t| @traces[t].first}
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
#
|
167
|
+
# return an array of all traces
|
168
|
+
#
|
169
|
+
# @return [Array of Traceable] array of all traces
|
170
|
+
def all_traces_as_arrays
|
171
|
+
@traces
|
172
|
+
end
|
173
|
+
|
174
|
+
# this returns a particular trace
|
175
|
+
# in case of duplicates, it delivers the first one
|
176
|
+
# @param id [String] the id of the requested traceable
|
177
|
+
def [] (id)
|
178
|
+
if @traces.has_key?(id)
|
179
|
+
@traces[id].first
|
180
|
+
else
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# this lists duplicate traces
|
186
|
+
# @return [Array of String] the list of the id of duplicate Traces
|
187
|
+
def duplicate_ids()
|
188
|
+
@traces.select{|id, traceables| traceables.length > 1}.map{|id, traceable| id}.sort
|
189
|
+
end
|
190
|
+
|
191
|
+
# this lists duplicate traces
|
192
|
+
# @return [Array of Traceable] the list duplicate Traces.
|
193
|
+
def duplicate_traces()
|
194
|
+
@traces.select{|id, traceables| traceables.length > 1}.map{|id, traceable| traceable}.sort
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
# this serializes a particular slot for caching
|
199
|
+
# @param file [String] name of the cachefile
|
200
|
+
def dump_to_marshal(file)
|
201
|
+
File.open(file, "wb"){|f|
|
202
|
+
Marshal.dump(self, f)
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
# this loads cached information into a particular slot
|
207
|
+
# @param file [String] name of the cachefile
|
208
|
+
def self.load_from_marshal(file)
|
209
|
+
a=nil
|
210
|
+
File.open(file, "rb"){|f| a=Marshal.load(f)}
|
211
|
+
a
|
212
|
+
end
|
213
|
+
|
214
|
+
# this merges a TraceableSet
|
215
|
+
# @return [Treaceable] the current traceable set
|
216
|
+
def merge(set)
|
217
|
+
set.all_traces_as_arrays.values.flatten.each{|t| self.add(t)}
|
218
|
+
end
|
219
|
+
|
220
|
+
# this retunrs traces marked as supported but not being defined
|
221
|
+
# @return [Array of String] the list of the id of undefined Traces
|
222
|
+
# traces which are marked as uptraces but do not exist.
|
223
|
+
def undefined_ids
|
224
|
+
@supported_by.keys.select{|t| not @traces.has_key?(t)}.sort
|
225
|
+
end
|
226
|
+
|
227
|
+
#
|
228
|
+
# returns the list of all uptraces in the current TraceableSet. Note that
|
229
|
+
# this is a hash of strings.
|
230
|
+
#
|
231
|
+
# myset.uptrace_ids[rs_foo_001] # yield id of traces referring to rs_foo_001
|
232
|
+
#
|
233
|
+
# @return [Hash of Array of String] the Hash of the uptrace ids.
|
234
|
+
def uptrace_ids
|
235
|
+
@supported_by
|
236
|
+
end
|
237
|
+
|
238
|
+
# this adjusts the sortOrder
|
239
|
+
# @param sort_order [Array of String ] is an array of strings
|
240
|
+
# if a traceId starts with such a string
|
241
|
+
# it is placed according to the sequence
|
242
|
+
# in the array. Otherwise it is sorted at the end
|
243
|
+
def sort_order= (sort_order)
|
244
|
+
@sort_order=sort_order
|
245
|
+
end
|
246
|
+
|
247
|
+
# this determines the sort order index of a trace
|
248
|
+
# required behavior needs to be set in advance by the method sortOrder=
|
249
|
+
# @param trace_id [String] the id of a Traceable for which
|
250
|
+
# the sort order index shall be coumputed.
|
251
|
+
# @return [String] the sort key of the given id.
|
252
|
+
def trace_order_index(trace_id)
|
253
|
+
global=@sort_order.index{|x| trace_id.start_with? x} ||
|
254
|
+
(@sort_order.length+1)
|
255
|
+
|
256
|
+
# add the {index} of the trace to
|
257
|
+
orderId = [global.to_s.rjust(5,"0"),trace_id].join("_")
|
258
|
+
orderId
|
259
|
+
end
|
260
|
+
|
261
|
+
# this delivers a string of traceables which can be used to compare
|
262
|
+
# traces with a
|
263
|
+
#
|
264
|
+
|
265
|
+
|
266
|
+
#
|
267
|
+
# return a string all traces sorted which can be saved as a file
|
268
|
+
# and subsequently be used by a textual diff to determine changed
|
269
|
+
# traces.
|
270
|
+
#
|
271
|
+
# @return [type] [description]
|
272
|
+
def to_compareEntries
|
273
|
+
all_traces.sort.map{|t| "\n\n[#{t.id}]\n#{t.as_oneline}" }.join("\n")
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
|
278
|
+
#############################
|
279
|
+
|
280
|
+
private
|
281
|
+
|
282
|
+
#
|
283
|
+
# this is used to beautify an nokigiri document
|
284
|
+
# @param [Nokogiri::XML::Document] doc - the document
|
285
|
+
# @return [Nokogiri::XML::Document] the beautified document
|
286
|
+
def xp(doc)
|
287
|
+
xsl =<<XSL
|
288
|
+
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
289
|
+
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
|
290
|
+
<xsl:strip-space elements="*"/>
|
291
|
+
<xsl:template match="/">
|
292
|
+
<xsl:copy-of select="."/>
|
293
|
+
</xsl:template>
|
294
|
+
</xsl:stylesheet>
|
295
|
+
XSL
|
296
|
+
|
297
|
+
|
298
|
+
xslt = Nokogiri::XSLT(xsl)
|
299
|
+
out = xslt.transform(doc)
|
300
|
+
|
301
|
+
out
|
302
|
+
end
|
303
|
+
|
304
|
+
|
305
|
+
end
|
306
|
+
|
307
|
+
|
308
|
+
|
309
|
+
|
310
|
+
class Traceable
|
311
|
+
include Comparable
|
312
|
+
|
313
|
+
|
314
|
+
# String: The trace-Id
|
315
|
+
attr_accessor :id
|
316
|
+
# string: the alternative Id, used e.g. for the constraint number
|
317
|
+
attr_accessor :alternative_id
|
318
|
+
# String: The header in plain text
|
319
|
+
attr_accessor :header_plain
|
320
|
+
# String: The header in original format
|
321
|
+
attr_accessor :header_orig
|
322
|
+
# String: The body in plain text
|
323
|
+
attr_accessor :body_plain
|
324
|
+
# String: he body in original format
|
325
|
+
attr_accessor :body_orig
|
326
|
+
# Array of Strings: The uplink as an array of Trace-ids
|
327
|
+
attr_accessor :contributes_to
|
328
|
+
# String: the Traceable in its original format
|
329
|
+
attr_accessor :trace_orig
|
330
|
+
# String: origin of the entry
|
331
|
+
attr_accessor :origin
|
332
|
+
# String: category of the entry
|
333
|
+
attr_accessor :category
|
334
|
+
# String: info on the entry
|
335
|
+
attr_accessor :info
|
336
|
+
|
337
|
+
|
338
|
+
def initialize()
|
339
|
+
@id = ""
|
340
|
+
@alternative_id = ""
|
341
|
+
@header_orig = ""
|
342
|
+
@body_plain = ""
|
343
|
+
@body_orig = ""
|
344
|
+
@contributes_to = []
|
345
|
+
@trace_orig = ""
|
346
|
+
@category = ""
|
347
|
+
@info = ""
|
348
|
+
end
|
349
|
+
|
350
|
+
# define the comparison to makeit really comaprable
|
351
|
+
# @param [Traceable] other the other traceable for comparison.
|
352
|
+
def <=> (other)
|
353
|
+
@id <=> other.id
|
354
|
+
end
|
355
|
+
|
356
|
+
def get_diff(other)
|
357
|
+
newval = self.get_comparison_string
|
358
|
+
oldval = other.get_comparison_string
|
359
|
+
|
360
|
+
#todo: get it back as soon as amatch is available
|
361
|
+
similarity = "n/a"
|
362
|
+
#similarity=newval.levenshtein_similar(oldval).to_s[0..6]
|
363
|
+
|
364
|
+
if newval == oldval
|
365
|
+
result = nil
|
366
|
+
else
|
367
|
+
diff_as_html= "<pre>#{other.trace_orig}</pre><hr/><pre>#{self.trace_orig}</pre>"#Diffy::Diff.new(other.trace_orig, self.trace_orig).to_s(:text)
|
368
|
+
rawDiff = Diffy::Diff.new(self.trace_orig, other.trace_orig)
|
369
|
+
diff_as_html=rawDiff.to_s(:html)
|
370
|
+
|
371
|
+
result = [self.id, similarity, diff_as_html]
|
372
|
+
diff_as_html=nil
|
373
|
+
end
|
374
|
+
result
|
375
|
+
end
|
376
|
+
|
377
|
+
|
378
|
+
def get_comparison_string
|
379
|
+
"#{header_orig};#{body_orig};#{contributes_to.sort}".gsub(/\s+/," ")
|
380
|
+
end
|
381
|
+
|
382
|
+
def as_oneline
|
383
|
+
trace_orig.gsub(/\s+/, " ")
|
384
|
+
end
|
385
|
+
|
386
|
+
|
387
|
+
end
|