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