wortsammler 0.0.2

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