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,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