testability-driver 0.9.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/lib/tdriver/base/behaviour/behaviours/object_behaviour_composition.rb +1 -1
  2. data/lib/tdriver/base/behaviour/behaviours/object_behaviour_description.rb +11 -7
  3. data/lib/tdriver/base/behaviour/behaviours/object_composition.rb +8 -0
  4. data/lib/tdriver/base/behaviour/factory.rb +229 -209
  5. data/lib/tdriver/base/errors.rb +3 -0
  6. data/lib/tdriver/base/state_object.rb +11 -20
  7. data/lib/tdriver/base/sut/controller.rb +4 -4
  8. data/lib/tdriver/base/sut/factory.rb +205 -170
  9. data/lib/tdriver/base/sut/generic/behaviours/application.rb +256 -174
  10. data/lib/tdriver/base/sut/generic/behaviours/find.rb +17 -11
  11. data/lib/tdriver/base/sut/generic/behaviours/flash_behaviour.rb +57 -66
  12. data/lib/tdriver/base/sut/generic/behaviours/sut.rb +578 -497
  13. data/lib/tdriver/base/sut/generic/behaviours/switchbox_behaviour.rb +41 -15
  14. data/lib/tdriver/base/sut/generic/behaviours/verification.rb +48 -19
  15. data/lib/tdriver/base/sut/generic/commands/fixture.rb +47 -0
  16. data/lib/tdriver/base/sut/generic/commands/key_sequence.rb +25 -13
  17. data/lib/tdriver/base/sut/generic/commands/screen_capture.rb +16 -10
  18. data/lib/tdriver/base/sut/generic/plugin.rb +9 -3
  19. data/lib/tdriver/base/sut/sut.rb +41 -33
  20. data/lib/tdriver/base/test_object/abstract.rb +26 -3
  21. data/lib/tdriver/base/test_object/adapter.rb +399 -0
  22. data/lib/tdriver/base/test_object/behaviours/syncronization.rb +56 -14
  23. data/lib/tdriver/base/test_object/behaviours/test_object.rb +663 -197
  24. data/lib/tdriver/base/test_object/cache.rb +132 -0
  25. data/lib/tdriver/base/test_object/factory.rb +677 -426
  26. data/lib/tdriver/base/test_object/factory_new.rb +202 -0
  27. data/lib/tdriver/base/test_object/identificator.rb +24 -17
  28. data/lib/tdriver/base/test_object/loader.rb +9 -3
  29. data/lib/tdriver/base/test_object/verification.rb +181 -0
  30. data/lib/tdriver/loader.rb +1 -1
  31. data/lib/tdriver/report/report.rb +2 -0
  32. data/lib/tdriver/report/report_api.rb +4 -4
  33. data/lib/tdriver/report/report_creator.rb +29 -3
  34. data/lib/tdriver/report/report_data_presentation.rb +7 -3
  35. data/lib/tdriver/report/report_execution_statistics.rb +80 -21
  36. data/lib/tdriver/report/report_javascript.rb +192 -0
  37. data/lib/tdriver/report/report_test_case_run.rb +22 -0
  38. data/lib/tdriver/report/report_test_run.rb +62 -55
  39. data/lib/tdriver/report/report_writer.rb +57 -56
  40. data/lib/tdriver/tdriver.rb +14 -41
  41. data/lib/tdriver/util/common/error.rb +1 -0
  42. data/lib/tdriver/util/common/exceptions.rb +12 -0
  43. data/lib/tdriver/util/common/file.rb +12 -6
  44. data/lib/tdriver/util/common/gem.rb +2 -1
  45. data/lib/tdriver/util/common/hash.rb +152 -0
  46. data/lib/tdriver/util/common/kernel.rb +49 -34
  47. data/lib/tdriver/util/common/loader.rb +21 -17
  48. data/lib/tdriver/util/common/numeric.rb +39 -0
  49. data/lib/tdriver/util/common/object.rb +115 -0
  50. data/lib/tdriver/util/common/string.rb +55 -2
  51. data/lib/tdriver/util/dbaccess/dbaccess.rb +194 -161
  52. data/lib/tdriver/util/dynamic_attribute_filter.rb +6 -0
  53. data/lib/tdriver/util/hooking.rb +2 -2
  54. data/lib/tdriver/util/loader.rb +2 -2
  55. data/lib/tdriver/util/localisation/localisation.rb +277 -18
  56. data/lib/tdriver/util/logger.rb +142 -13
  57. data/lib/tdriver/util/parameter/parameter_hash.rb +8 -5
  58. data/lib/tdriver/util/parameter/parameter_xml.rb +18 -2
  59. data/lib/tdriver/util/recorder.rb +17 -12
  60. data/lib/tdriver/util/user_data/user_data.rb +3 -2
  61. data/lib/tdriver/util/{video_rec.rb → video_utils.rb} +136 -16
  62. data/lib/tdriver/util/xml/abstraction.rb +7 -0
  63. data/lib/tdriver/util/xml/attribute.rb +32 -0
  64. data/lib/tdriver/util/xml/loader.rb +8 -2
  65. data/lib/tdriver/util/xml/nil_node.rb +95 -0
  66. data/lib/tdriver/util/xml/parsers/nokogiri/abstraction.rb +46 -7
  67. data/lib/tdriver/util/xml/parsers/nokogiri/attribute.rb +19 -9
  68. data/lib/tdriver/util/xml/parsers/nokogiri/document.rb +1 -1
  69. data/lib/tdriver/util/xml/parsers/nokogiri/element.rb +13 -1
  70. data/lib/tdriver/util/xml/parsers/nokogiri/loader.rb +6 -0
  71. data/lib/tdriver/util/xml/parsers/nokogiri/nodeset.rb +27 -15
  72. data/lib/tdriver/util/xml/parsers/nokogiri/text.rb +57 -0
  73. data/lib/tdriver/util/xml/text.rb +32 -0
  74. data/lib/tdriver/util/xml/xml.rb +35 -22
  75. data/lib/tdriver/version.rb +1 -1
  76. data/lib/tdriver-devtools/behaviour/xml/rdoc_behaviour_xml_generator.rb +41 -34
  77. data/lib/tdriver-devtools/doc/generate.rb +31 -6
  78. data/lib/tdriver-devtools/doc/xslt/template.xsl +46 -25
  79. data/lib/tdriver-devtools/tests/feature_tests/example/behaviour_example.rb +100 -0
  80. data/lib/tdriver-devtools/tests/feature_tests/update +1 -1
  81. data/lib/tdriver.rb +0 -3
  82. data/xml/behaviours/generic.xml +1 -1
  83. data/xml/defaults/generic.xml +4 -90
  84. data/xml/templates/generic.xml +33 -25
  85. metadata +21 -29
  86. data/lib/tdriver-devtools/behaviour/xml_generator/example/flick-example.rb +0 -245
  87. data/lib/tdriver-devtools/behaviour/xml_generator/example/sut.rb +0 -964
  88. data/lib/tdriver-devtools/behaviour/xml_generator/generate.rb +0 -68
  89. data/lib/tdriver-devtools/behaviour/xml_generator/lib/custom_rdoc_generator.rb +0 -1865
  90. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument.default.template +0 -1
  91. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument.template +0 -3
  92. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument_type.template +0 -4
  93. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.exception.template +0 -4
  94. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.arguments.template +0 -4
  95. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.deprecated.template +0 -3
  96. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.exceptions.template +0 -3
  97. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.info.template +0 -1
  98. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.returns.template +0 -3
  99. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.tables.template +0 -3
  100. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.template +0 -12
  101. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.returns.template +0 -5
  102. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.item.template +0 -1
  103. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.row.template +0 -2
  104. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.template +0 -7
  105. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.template +0 -14
  106. data/lib/tdriver-devtools/behaviour/xml_generator/update +0 -3
  107. data/lib/tdriver-devtools/tests/feature_tests/example/flick-example.rb +0 -233
  108. data/lib/tdriver-devtools/tests/feature_tests/example/impl.rb +0 -194
@@ -1,68 +0,0 @@
1
- #!/usr/bin/env ruby
2
- ############################################################################
3
- ##
4
- ## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
5
- ## All rights reserved.
6
- ## Contact: Nokia Corporation (testabilitydriver@nokia.com)
7
- ##
8
- ## This file is part of Testability Driver.
9
- ##
10
- ## If you have questions regarding the use of this file, please contact
11
- ## Nokia at testabilitydriver@nokia.com .
12
- ##
13
- ## This library is free software; you can redistribute it and/or
14
- ## modify it under the terms of the GNU Lesser General Public
15
- ## License version 2.1 as published by the Free Software Foundation
16
- ## and appearing in the file LICENSE.LGPL included in the packaging
17
- ## of this file.
18
- ##
19
- ############################################################################
20
- require 'rdoc/rdoc'
21
-
22
- module RDoc
23
-
24
- class RDoc
25
-
26
- # install custom generator to RDoc
27
- def install_generator( name, filename )
28
-
29
- GENERATORS[ name.to_s.downcase ] = Generator.new( filename, ( "%sFeatureTestGenerator" % [ name ] ).intern , name.to_s.downcase )
30
-
31
- end
32
-
33
- end
34
-
35
- end
36
-
37
- if ARGV.count < 2
38
-
39
- abort "\nUsage: #{ File.basename( $0 ) } plugin_or_gem_name filename.rb \n\n"
40
-
41
- else
42
-
43
- $output_results_name = ARGV.slice!(0)
44
-
45
- ARGV.each{ | filename |
46
-
47
- abort("\nUnable to create feature test due to implementation file %s not found\n\n" % [ filename ] ) unless File.exist?( File.expand_path( filename ) )
48
-
49
- }
50
-
51
- begin
52
-
53
- RDoc::RDoc.new.tap{ | rdoc |
54
-
55
- rdoc.install_generator( 'TDriver', File.expand_path( File.join( File.dirname( __FILE__ ), 'lib/custom_rdoc_generator.rb' ) ) )
56
-
57
- rdoc.document( ['--inline-source', '--op', 'behaviour_xml', '--fmt', 'tdriver'] + ARGV )
58
-
59
- }
60
-
61
- rescue RDoc::RDocError => e
62
-
63
- abort e.message
64
-
65
- end
66
-
67
- end
68
-
@@ -1,1865 +0,0 @@
1
- ############################################################################
2
- ##
3
- ## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4
- ## All rights reserved.
5
- ## Contact: Nokia Corporation (testabilitydriver@nokia.com)
6
- ##
7
- ## This file is part of Testability Driver.
8
- ##
9
- ## If you have questions regarding the use of this file, please contact
10
- ## Nokia at testabilitydriver@nokia.com .
11
- ##
12
- ## This library is free software; you can redistribute it and/or
13
- ## modify it under the terms of the GNU Lesser General Public
14
- ## License version 2.1 as published by the Free Software Foundation
15
- ## and appearing in the file LICENSE.LGPL included in the packaging
16
- ## of this file.
17
- ##
18
- ############################################################################
19
-
20
- module Generators
21
-
22
- abort("RDoc not available/loaded") unless defined?( RDoc )
23
-
24
- class TDriverFeatureTestGenerator
25
-
26
- def initialize( options )
27
-
28
- @templates = {}
29
-
30
- @found_modules_and_methods = {}
31
-
32
- load_templates
33
-
34
- @options = options
35
-
36
- @already_processed_files = []
37
-
38
- @current_module_tests = []
39
-
40
- @current_module = nil
41
-
42
- @output = { :files => [], :classes => [], :modules => [], :attributes => [], :methods => [], :aliases => [], :constants => [], :requires => [], :includes => []}
43
-
44
- @errors = []
45
-
46
- end
47
-
48
- def help( topic )
49
-
50
- case topic
51
-
52
- when 'description'
53
- <<-EXAMPLE
54
- # == description
55
- # This method returns "String" as return value
56
- def my_method( arguments )
57
- return "string"
58
- end
59
- EXAMPLE
60
-
61
- when 'returns'
62
- <<-EXAMPLE
63
- # == returns
64
- # String
65
- # description: example description
66
- # example: "string"
67
- #
68
- def my_method( arguments )
69
- return "string"
70
- end
71
- EXAMPLE
72
-
73
- when 'arguments'
74
- <<-EXAMPLE
75
- # == arguments
76
- # arg1
77
- # Integer
78
- # description: first argument can integer
79
- # example: 10
80
- # String
81
- # description: ... or string
82
- # example: "Hello"
83
- #
84
- # arg2
85
- # Array
86
- # description: MyArray
87
- # example: [1,2,3]
88
- # default: []
89
- #
90
- # *arg3
91
- # Array
92
- # description: MyMultipleArray
93
- # example: ['a','b','c']
94
- # default: []
95
- #
96
- # &block
97
- # Proc
98
- # description: MyMultipleArray
99
- # example: ['a','b','c']
100
- # default: []
101
- def my_method( arg1, arg2, *arg3, &block )
102
- # ...
103
- end
104
- EXAMPLE
105
-
106
- when 'attr_argument'
107
- <<-EXAMPLE
108
- # == arguments
109
- # value
110
- # Integer
111
- # description: first argument can integer
112
- # example: 10
113
- attr_writer :my_attribute
114
-
115
- or
116
-
117
- # == arguments
118
- # value
119
- # Integer
120
- # description: first argument can integer
121
- # example: 10
122
- # String
123
- # description: ... or string
124
- # example: "Hello"
125
- attr_writer :my_attribute # ... when input value can be either Integer or String
126
- EXAMPLE
127
-
128
-
129
- when 'exceptions'
130
- <<-EXAMPLE
131
- # == exceptions
132
- # RuntimeError
133
- # description: example exception #1
134
- #
135
- # ArgumentError
136
- # description: example exception #2
137
- def my_method
138
-
139
- # ...
140
-
141
- end
142
- EXAMPLE
143
-
144
- when 'behaviour_description'
145
- <<-EXAMPLE
146
- # == description
147
- # This module contains demonstration implementation containing tags for documentation generation using gesture as an example
148
- module MyBehaviour
149
-
150
- # ...
151
-
152
- end
153
- EXAMPLE
154
-
155
- when 'behaviour_name'
156
- <<-EXAMPLE
157
- # == behaviour
158
- # MyPlatformSpecificBehaviour
159
- module MyBehaviour
160
-
161
- # ...
162
-
163
- end
164
- EXAMPLE
165
-
166
- when 'behaviour_object_types'
167
- <<-EXAMPLE
168
- # == objects
169
- # *
170
- module MyBehaviour
171
-
172
- # apply behaviour to any test object, except SUT
173
-
174
- end
175
-
176
- or
177
-
178
- # == objects
179
- # sut
180
- module MyBehaviour
181
-
182
- # apply behaviour only to SUT object
183
-
184
- end
185
-
186
- # == objects
187
- # *;sut
188
- module MyBehaviour
189
-
190
- # apply behaviour to any test object, including SUT
191
-
192
- end
193
-
194
- or
195
-
196
- # == objects
197
- # MyObject
198
- module MyBehaviour
199
-
200
- # apply behaviour only to objects which type is 'MyObject'
201
-
202
- end
203
-
204
- or
205
-
206
- # == objects
207
- # MyObject;OtherObject
208
- module MyBehaviour
209
-
210
- # apply behaviour only to objects which type is 'MyObject' or 'OtherObject'
211
- # if more object types needed use ';' as separator.
212
-
213
- end
214
-
215
-
216
- EXAMPLE
217
-
218
- when 'behaviour_version'
219
- <<-EXAMPLE
220
- # == sut_version
221
- # *
222
- module MyBehaviour
223
-
224
- # any sut version
225
-
226
- end
227
-
228
- or
229
-
230
- # == sut_version
231
- # 1.0
232
- module MyBehaviour
233
-
234
- # apply behaviour only to sut with version 1.0
235
-
236
- end
237
- EXAMPLE
238
-
239
- when 'behaviour_input_type'
240
- <<-EXAMPLE
241
- # == input_type
242
- # *
243
- module MyBehaviour
244
-
245
- # any input type
246
-
247
- end
248
-
249
- or
250
-
251
- # == input_type
252
- # touch
253
- module MyBehaviour
254
-
255
- # apply behaviour only to sut which input type is 'touch'
256
-
257
- end
258
-
259
- or
260
-
261
- # == input_type
262
- # touch;key
263
- module MyBehaviour
264
-
265
- # apply behaviour only to sut which input type is 'touch' or 'key'
266
- # if more types needed use ';' as separator.
267
-
268
- end
269
-
270
- EXAMPLE
271
-
272
- when 'behaviour_sut_type'
273
- <<-EXAMPLE
274
- # == sut_type
275
- # *
276
- module MyBehaviour
277
-
278
- # any input type
279
-
280
- end
281
-
282
- or
283
-
284
- # == sut_type
285
- # XX
286
- module MyBehaviour
287
-
288
- # apply behaviour only to sut which sut type is 'XX'
289
-
290
- end
291
-
292
- or
293
-
294
- # == sut_type
295
- # XX;YY
296
- module MyBehaviour
297
-
298
- # apply behaviour only to sut which sut type is 'XX' or 'YY'
299
- # if more types needed use ';' as separator.
300
-
301
- end
302
- EXAMPLE
303
-
304
- when 'behaviour_requires'
305
- <<-EXAMPLE
306
- # == requires
307
- # *
308
- module MyBehaviour
309
-
310
- # when no plugins required (TDriver internal/generic SUT behaviour)
311
-
312
- end
313
-
314
- or
315
-
316
- # == requires
317
- # testability-driver-my-plugin
318
- module MyBehaviour
319
-
320
- # when plugin 'testability-driver-my-plugin' is required
321
-
322
- end
323
- EXAMPLE
324
-
325
- when 'table_format'
326
-
327
- <<-EXAMPLE
328
- # == tables
329
- # table_name
330
- # title: My table 1
331
- # |header1|header2|header3|
332
- # |1.1|1.2|1.3|
333
- # |2.1|2.2|2.3|
334
- # |3.1|3.2|3.3|
335
- #
336
- # another_table_name
337
- # title: My table 2
338
- # |id|value|
339
- # |0|true|
340
- # |1|false|
341
- def my_method
342
-
343
- # ...
344
-
345
- end
346
- EXAMPLE
347
-
348
- when 'default_argument_value_already_given'
349
- <<-EXAMPLE
350
- # == arguments
351
- # value
352
- # Integer
353
- # description: first argument can integer
354
- # example: 10
355
- # default: 1
356
- # String
357
- # description: ... or string
358
- # example: "Hello"
359
- # default: "a"
360
- def my_method( value = 1 )
361
-
362
- # ...
363
-
364
- end
365
- EXAMPLE
366
-
367
- when 'default_value_mandatory_argument'
368
-
369
- <<-EXAMPLE
370
- # == arguments
371
- # value
372
- # Integer
373
- # description: first argument can integer
374
- # example: 10
375
- # default: 1
376
- def my_method( value )
377
-
378
- # ...
379
-
380
- end
381
- EXAMPLE
382
-
383
-
384
- else
385
-
386
- 'Unknown help topic "%s"' % topic
387
-
388
- end
389
-
390
- end
391
-
392
- def self.for( options )
393
-
394
- new( options )
395
-
396
- end
397
-
398
- def load_templates
399
-
400
- Dir.glob( File.join( File.dirname( File.expand_path( __FILE__ ) ), '..', 'templates', '*.template' ) ).each{ | file |
401
-
402
- name = File.basename( file ).gsub( '.template', '' )
403
-
404
- @templates[ name ] = open( file, 'r' ).read
405
-
406
- }
407
-
408
- end
409
-
410
- def generate( files )
411
-
412
- # process files
413
- files.each{ | file |
414
-
415
- process_file( file ) unless @already_processed_files.include?( file.file_absolute_name )
416
-
417
-
418
- }
419
-
420
- # TODO: some other format for writing the hash to file...
421
- open("#{ $output_results_name }.hash", "w" ){ | file | file << @found_modules_and_methods.inspect }
422
-
423
- end
424
-
425
- def process_file( file )
426
-
427
- @module_path = []
428
-
429
- @current_file = file
430
-
431
- process_modules( file.modules )
432
-
433
- end
434
-
435
- def process_modules( modules )
436
-
437
- modules.each{ | _module |
438
-
439
- unless @already_processed_files.include?( _module.full_name )
440
-
441
- @module_path.push( _module.name )
442
-
443
- process_module( _module )
444
-
445
- @module_path.pop
446
-
447
- end
448
-
449
- }
450
-
451
- end
452
-
453
- def process_methods( methods )
454
-
455
- @processing = "method"
456
-
457
- results = []
458
-
459
- methods.each{ | method |
460
-
461
- results << process_method( method )
462
-
463
- }
464
-
465
- Hash[ results ]
466
-
467
- end
468
-
469
- def process_method_arguments_section( source, params_array )
470
-
471
- result = []
472
-
473
- current_argument = nil
474
-
475
- current_argument_type = nil
476
-
477
- current_section = nil
478
-
479
- argument_index = -1
480
-
481
- arguments_found = 0
482
-
483
- source.lines.to_a.each_with_index{ | line, index |
484
-
485
- # remove cr/lf
486
- line.chomp!
487
-
488
- # remove trailing whitespaces
489
- line.rstrip!
490
-
491
- # count nesting depth
492
- line.match( /^(\s*)/ )
493
-
494
- nesting = $1.size
495
-
496
- # remove leading whitespaces
497
- line.lstrip!
498
-
499
- if nesting == 0
500
-
501
- line =~ /^([*|&]{0,1}\w+(\#\w+?)*)$/i
502
-
503
- unless $1.nil?
504
-
505
- # argument name
506
- current_argument = $1
507
-
508
- arguments_found += 1 unless line.include?( "#" )
509
-
510
- current_section = nil
511
-
512
- current_argument_type = nil
513
-
514
- result << { current_argument => { :argument_type_order => [], :types => {} } }
515
-
516
- argument_index += 1
517
-
518
- end
519
-
520
- else
521
-
522
- # is line content class name? (argument variable type)
523
- line =~ /^(.*)$/i
524
-
525
- if !$1.nil? && ( 65..90 ).include?( $1[0] ) && nesting == 1 # "Array", "String", "Integer"
526
-
527
- #Kernel.const_get( $1 ) rescue abort( "Line %s: \"%s\" is not valid argument variable type. (e.g. OK: \"String\", \"Array\", \"Fixnum\" etc) " % [ index +1, $1 ] )
528
-
529
- current_argument_type = $1
530
-
531
- result[ argument_index ][ current_argument ][ :argument_type_order ] << $1
532
-
533
- result[ argument_index ][ current_argument ][ :types ][ current_argument_type ] = {}
534
-
535
- #result[ argument_index ][ current_argument ][ current_argument_type ] = {}
536
-
537
- current_section = nil
538
-
539
- else
540
-
541
- raise_error("Unable add argument details (line %s: \"%s\") for \"%s\" due to argument variable type must be defined first.\nPlease note that argument type must start with capital letter (e.g. OK: \"String\" NOK: \"string\")" % [ index + 1, line, current_argument ] ) if current_argument_type.nil?
542
-
543
- line =~ /^(.*?)\:{1}($|[\r\n\t\s]{1})(.*)$/i
544
-
545
- if $1.nil?
546
-
547
- raise_error("Unable add argument details (line %s: \"%s\") for \"%s\" due to section name not defined. Sections names are written in lowercase with trailing colon and whitespace (e.g. OK: \"example: 10\", NOK: \"example:10\")" % [ index +1, line, current_argument]) if $1.nil? && current_section.nil?
548
-
549
- # remove leading & trailing whitespaces
550
- section_content = line.strip
551
-
552
- else
553
-
554
- current_section = $1
555
-
556
- if result[ argument_index ][ current_argument ][ :types ].has_key?( current_argument_type )
557
-
558
- #unless result[ argument_index ][ current_argument ][ current_argument_type ].has_key?( current_section )
559
- unless result[ argument_index ][ current_argument ][ :types ][ current_argument_type ].has_key?( current_section )
560
-
561
- #result[ argument_index ][ current_argument ][ current_argument_type ][ current_section ] = ""
562
- result[ argument_index ][ current_argument ][ :types ][ current_argument_type ][ current_section ] = ""
563
-
564
- end
565
-
566
-
567
- end
568
-
569
- section_content = $3.strip
570
-
571
- end
572
-
573
- raise_error("Unable add argument details due to argument not defined. Argument name must start from pos 1 of comment. (e.g. \"# my_variable\" NOK: \"# my_variable\", \"#myvariable\")") if current_argument.nil?
574
-
575
- if result[ argument_index ][ current_argument ][ :types ].has_key?( current_argument_type )
576
-
577
- if result[ argument_index ][ current_argument ][ :types ][ current_argument_type ].has_key?( current_section )
578
-
579
-
580
- # add one leading whitespace if current_section value is not empty
581
- #section_content = " " + section_content unless result[ argument_index ][ current_argument ][ current_argument_type ][ current_section ].empty?
582
- section_content = " " + section_content unless result[ argument_index ][ current_argument ][ :types ][ current_argument_type ][ current_section ].empty?
583
-
584
- # store section_content to current_section
585
- #result[ argument_index ][ current_argument ][ current_argument_type ][ current_section ] << section_content
586
- result[ argument_index ][ current_argument ][ :types ][ current_argument_type ][ current_section ] << section_content
587
-
588
- end
589
-
590
- end
591
-
592
- end
593
-
594
- end
595
-
596
- }
597
-
598
- order = []
599
-
600
- params_array = params_array.collect{ | o | [ o.first, Hash[:default, o[1], :optional, o.last] ] }
601
-
602
- params_hash = Hash[ params_array ]
603
-
604
- default_value_already_set = []
605
-
606
- params_array.each{ | param |
607
-
608
- if ( item = result.select{ | arg | arg.keys.include?( param.first ) }).empty?
609
-
610
- raise_error("Error: Argument '#{ param.first }' is implemented but not documented in '#{ @current_method.name }' ($MODULE).\nNote that documented argument and variable name must be identical.", [ 'writer', 'accessor' ].include?( @processing ) ? 'attr_argument' : 'arguments' )
611
-
612
- order << { param.first => {} }
613
-
614
- else
615
-
616
- arg = item.first
617
- arg_name = arg.keys.first
618
-
619
- # apply overriding default argument value from documentation
620
- arg[ arg_name ][ :argument_type_order ].each{ | type_name |
621
-
622
- type_hash = arg[ arg_name ][ :types ][ type_name ]
623
-
624
- unless type_hash["default"].nil?
625
-
626
- if arg[ arg_name ][ :default ].nil?
627
-
628
- if params_hash[ arg_name ][ :optional ] == false
629
-
630
- raise_error("Error: Default value given for mandatory argument #{ arg_name } (type: #{ type_name }).", 'default_value_mandatory_argument' )
631
-
632
- else
633
-
634
- arg[ arg_name ][ :default ] = type_hash["default"]
635
-
636
- end
637
-
638
- else
639
- raise_error("Error: Default value already given for #{ arg_name } (type: #{ type_name }).", 'default_argument_value_already_given' )
640
- end
641
-
642
- end
643
- }
644
-
645
- # if optional parameter and no overriding value defined, add one from implementation
646
- if arg[ arg_name ][:default].nil?
647
-
648
- arg[ arg_name ][ :default ] = params_hash[ arg_name ][ :default ] if params_hash[ arg_name ][ :optional ] == true
649
-
650
- end
651
-
652
- order << arg
653
-
654
- end
655
-
656
- }
657
-
658
- # collect all argument names and add block arguments if any
659
- found_keys = order.collect{ | pair | pair.keys }.flatten
660
-
661
- # collect all documented argument names
662
- documented_arguments = result.collect{ | arg | arg.keys }.flatten
663
-
664
- unimplemented_arguments = ( documented_arguments - found_keys )
665
-
666
- unless [ :attributes ].include?( @processing )
667
-
668
- unless unimplemented_arguments.empty?
669
-
670
- unimplemented_arguments.each{ | argument |
671
-
672
- raise_error("Error: Argument '#{ argument }' is documented but not implemented in '#{ @current_method.name }' ($MODULE).\nNote that documented argument and variable name must be identical.", [ :attributes ].include?( @processing ) ? 'attr_argument' : 'arguments' )
673
-
674
- }
675
-
676
- # remove unimplemented argument documentation
677
- result = result.select{ | documented_argument |
678
-
679
- unimplemented_arguments.include?( documented_argument.to_a.flatten.first ) == false
680
-
681
- }
682
-
683
- end
684
-
685
- end
686
-
687
- # add missing/undocumented arguments to order list
688
- missing = result.collect{ | value | order << value unless found_keys.include?( value.keys.first ) }
689
-
690
- [ order, arguments_found ]
691
-
692
- end
693
-
694
- def process_table( source )
695
-
696
- result = []
697
-
698
- #p source
699
-
700
- table_name = nil
701
- header_columns = 0
702
-
703
- source.lines.to_a.each_with_index{ | line, index |
704
-
705
- # remove cr/lf
706
- line.chomp!
707
-
708
- # remove trailing whitespaces
709
- line.rstrip!
710
-
711
- # count nesting depth
712
- line.match( /^(\s*)/ )
713
-
714
- nesting = $1.size
715
-
716
- #puts "%s,%s: %s" % [ index, nesting, line ]
717
-
718
- # new table
719
- if nesting == 0
720
-
721
- unless line.empty?
722
-
723
- line =~ /^(\w+)/i
724
-
725
- result << { "name" => $1, "content" => [] }
726
-
727
- table_name = $1.to_s
728
-
729
- else
730
-
731
- table_name = nil
732
-
733
- end
734
-
735
- else
736
-
737
- line.lstrip!
738
-
739
- if line[0].chr == '|'
740
-
741
- unless table_name.nil?
742
-
743
- if line[-1].chr != '|'
744
-
745
- raise_error( "Malformed custom table #{ result.last[ "name" ]}, line '#{ line }' ($MODULE). Line must start and end with '|' character.", "table_format" )
746
-
747
- else
748
-
749
- line[0] = ""
750
- line[-1] = ""
751
-
752
- columns = line.split("|")
753
-
754
- unless result.last[ "content" ].empty?
755
-
756
- raise_error( "Malformed custom table #{ result.last[ "name" ]}, line '#{ line }' ($MODULE). Number of columns (#{ columns.count }) does not match with header (#{ header_columns })", "table_format" ) if columns.count != header_columns
757
-
758
- else
759
-
760
- header_columns = columns.count
761
-
762
- end
763
-
764
- result.last[ "content" ] << columns
765
-
766
- end
767
-
768
- else
769
-
770
- raise_error( "Malformed custom table #{ result.last[ "name" ]} ($MODULE). Table name is missing.", "table_format" )
771
-
772
- end
773
-
774
- else
775
-
776
- unless line.empty?
777
-
778
- line =~ /^(.*?)\:{1}($|[\r\n\t\s]{1})(.*)$/i
779
-
780
- if $1.to_s.empty?
781
-
782
- raise_error( "Malformed custom table #{ result.last[ "name" ]}, line '#{ line }' ($MODULE). Table section name (e.g title) is missing.", "table_format" )
783
-
784
- else
785
-
786
- result.last[ $1.to_s ] = ( $3 || "" ).strip
787
-
788
- end
789
-
790
- else
791
-
792
- table_name = nil
793
-
794
- end
795
-
796
- end
797
-
798
- end
799
-
800
- }
801
-
802
- result
803
-
804
- end
805
-
806
- def process_formatted_section( source )
807
-
808
- result = []
809
-
810
- current_argument_type = nil
811
-
812
- current_section = nil
813
-
814
- argument_index = -1
815
-
816
- constants_to_classes = { "nil" => "NilClass", "true" => "TrueClass", "false" => "FalseClass" }
817
-
818
- source.lines.to_a.each_with_index{ | line, index |
819
-
820
- # remove cr/lf
821
- line.chomp!
822
-
823
- # remove trailing whitespaces
824
- line.rstrip!
825
-
826
- # count nesting depth
827
- line.match( /^(\s*)/ )
828
-
829
- nesting = $1.size
830
-
831
- # remove leading whitespaces
832
- line.lstrip!
833
-
834
- if nesting == 0
835
-
836
- # convert constants nil, true, false to real class names
837
- line = constants_to_classes[ line.downcase ] if constants_to_classes.include?( line.downcase )
838
-
839
- line =~ /^(.+)/i
840
-
841
- if !$1.nil? && (65..90).include?( $1[0] )
842
-
843
- #Kernel.const_get( $1 ) rescue abort( "Line %s: \"%s\" is not valid argument variable type. (e.g. OK: \"String\", \"Array\", \"Fixnum\" etc) " % [ index + 1, $1 ] ) if verify_type
844
-
845
- # argument type
846
- current_argument_type = $1 || ""
847
-
848
- current_section = nil
849
-
850
- result << { current_argument_type => {} }
851
-
852
- argument_index += 1
853
-
854
- end
855
-
856
- else
857
-
858
- raise_error("Unable add value details (line %s: \"%s\") for %s due to detail type must be defined first.\nPlease note that return value and exception type must start with capital letter (e.g. OK: \"String\" NOK: \"string\")" % [ index + 1, line, current_argument_type ] ) if current_argument_type.nil?
859
-
860
- line =~ /^(.*?)\:{1}($|[\r\n\t\s]{1})(.*)$/i
861
-
862
- if $1.nil?
863
-
864
- raise_error("Unable add value details (line %s: \"%s\") for %s due to section name not defined. Sections names are written in lowercase with trailing colon and whitespace (e.g. OK: \"example: 10\", NOK: \"example:10\")" % [ index +1, line, current_argument_type ]) if $1.nil? && current_section.nil?
865
-
866
- # remove leading & trailing whitespaces
867
- section_content = line.strip
868
-
869
- else
870
-
871
- current_section = $1
872
-
873
- if result[ argument_index ].has_key?( current_argument_type )
874
-
875
- unless result[ argument_index ][ current_argument_type ].has_key?( current_section )
876
-
877
- result[ argument_index ][ current_argument_type ][ current_section ] = ""
878
-
879
- end
880
-
881
- end
882
-
883
- section_content = ( $3 || "" ).strip
884
-
885
- end
886
-
887
- if current_argument_type.nil?
888
-
889
- raise_error("Unable add return value details due to variable type not defined. Argument type must be defined at pos 1 of comment. (e.g. \"# Integer\" NOK: \"# Integer\", \"#Integer\")")
890
-
891
- else
892
-
893
- # add one leading whitespace if current_section value is not empty
894
- section_content = " " + section_content unless result[ argument_index ][ current_argument_type ][ current_section ].empty?
895
-
896
- # store section_content to current_section
897
- result[ argument_index ][ current_argument_type ][ current_section ] << section_content
898
-
899
- end
900
-
901
- end
902
-
903
-
904
- }
905
-
906
- result
907
-
908
- end
909
-
910
- def store_to_results( module_name, name, type, params )
911
-
912
- unless @found_modules_and_methods.has_key?( module_name )
913
-
914
- @found_modules_and_methods[ module_name ] = []
915
-
916
- end
917
-
918
- #p params.select{ | param | param.last == false }
919
- #p params.select{ | param | param.last == true }
920
-
921
- #exit
922
-
923
- count = "%s;%s" % [ params.count, params.select{ | param | param.last == true }.count ]
924
-
925
- @found_modules_and_methods[ module_name ] << "%s#%s#%s" % [ name, type, count ] #{ :name => name, :type => type }
926
-
927
- end
928
-
929
- def process_arguments( arguments )
930
-
931
- return [] if arguments.to_s.empty?
932
-
933
- arguments = arguments[ 1 .. -2 ] if arguments[0].chr == "(" and arguments[-1].chr ==")"
934
-
935
- arguments.strip!
936
-
937
- # tokenize string
938
- tokenizer = RubyLex.new( arguments )
939
-
940
- # get first token
941
- token = tokenizer.token
942
-
943
- # set previous token to nil by default
944
- previous_token = nil
945
-
946
- args = []
947
-
948
- capture = true
949
- capture_depth = []
950
- capture_default = false
951
-
952
- default_value = []
953
-
954
- # loop while tokens available
955
- while token
956
-
957
- if [ RubyToken::TkLBRACE, RubyToken::TkLPAREN, RubyToken::TkLBRACK ].include?( token.class )
958
-
959
- default_value << token.text if capture_default
960
-
961
- capture_depth << token
962
-
963
- capture = false
964
-
965
- elsif [ RubyToken::TkRBRACE, RubyToken::TkRPAREN, RubyToken::TkRBRACK ].include?( token.class )
966
-
967
- default_value << token.text if capture_default
968
-
969
- capture_depth.pop
970
-
971
- capture = true if capture_depth.empty?
972
-
973
- # argument name
974
- elsif capture == true
975
-
976
- # argument name, or part of argument default value
977
- if token.kind_of?( RubyToken::TkIDENTIFIER ) and ![ RubyToken::TkDOT, RubyToken::TkCOLON2 ].include?( previous_token.class )
978
-
979
- args << [ token.name, nil, false ]
980
-
981
- # &blocks and *arguments are handled as optional parameters
982
- if [ RubyToken::TkBITAND, RubyToken::TkMULT ].include?( previous_token.class )
983
- #args.last[ 1 ] = previous_token.text
984
-
985
- args.last[ 0 ] = previous_token.text + args.last[ 0 ]
986
- args.last[ -1 ] = true
987
-
988
- end
989
-
990
- default_value = []
991
- capture_default = false
992
-
993
- elsif token.kind_of?( RubyToken::TkCOMMA )
994
-
995
- capture_default = false
996
-
997
- # detect optional argument
998
- elsif token.kind_of?( RubyToken::TkASSIGN )
999
-
1000
- capture_default = true
1001
-
1002
- # mark arguments as optional
1003
- args.last[ -1 ] = true
1004
-
1005
- else
1006
-
1007
- default_value << token.text if capture_default && ![ RubyToken::TkSPACE, RubyToken::TkNL ].include?( token.class )
1008
-
1009
- end
1010
-
1011
- else
1012
-
1013
- default_value << token.text if capture_default && ![ RubyToken::TkSPACE, RubyToken::TkNL ].include?( token.class )
1014
-
1015
- end
1016
-
1017
- unless default_value.empty?
1018
-
1019
- args.last[ 1 ] = default_value.join("")
1020
-
1021
- end
1022
-
1023
- # store previous token
1024
- previous_token = token
1025
-
1026
- # get next token
1027
- token = tokenizer.token
1028
-
1029
- end
1030
-
1031
- args
1032
-
1033
- end
1034
-
1035
- def process_undocumented_method_arguments( params )
1036
-
1037
- params.collect{ | param |
1038
-
1039
- hash = {}
1040
- hash[ :types ] = {}
1041
- hash[ :default ] = param[1] if param[-1] == true
1042
-
1043
- { param.first.to_s => hash }
1044
-
1045
- }
1046
-
1047
- end
1048
-
1049
- def process_method( method )
1050
-
1051
- results = []
1052
-
1053
- method_header = nil
1054
-
1055
- if ( method.visibility == :public && @module_path.first =~ /MobyBehaviour/ )
1056
-
1057
- params = method.kind_of?( RDoc::Attr ) ? [] : process_arguments( method.params )
1058
-
1059
- @current_method = method
1060
-
1061
- method_header = process_comment( method.comment )
1062
-
1063
- ## TODO: remember to verify that there are documentation for each argument!
1064
- ## TODO: verify that there is a tag for visualizer example
1065
-
1066
- arguments_found = 0
1067
-
1068
- method_header = Hash[ method_header.collect{ | key, value |
1069
-
1070
- if key == :arguments
1071
-
1072
- value, arguments_found = process_method_arguments_section( value, params )
1073
-
1074
- end
1075
-
1076
- if key == :returns
1077
-
1078
- value = process_formatted_section( value )
1079
-
1080
- end
1081
-
1082
- if key == :exceptions
1083
-
1084
- value = process_formatted_section( value )
1085
-
1086
- end
1087
-
1088
- if key == :tables
1089
-
1090
- value = process_table( value )
1091
-
1092
- end
1093
-
1094
- [ key, value ]
1095
-
1096
- }]
1097
-
1098
- method_header[ :__arguments_found ] = arguments_found
1099
-
1100
- # if no description found for arguments, add argument names to method_header hash
1101
- if ( params.count > 0 ) && ( method_header[ :arguments ].nil? || method_header[:arguments].empty? )
1102
-
1103
- #p params.count,
1104
- method_header[:arguments] = process_undocumented_method_arguments( params )
1105
-
1106
- end
1107
-
1108
- method_name = method.name.clone
1109
-
1110
- type = "method"
1111
-
1112
- if method.kind_of?( RDoc::Attr )
1113
-
1114
- case method.rw
1115
-
1116
- when "R"
1117
- type = "reader"
1118
- #store_to_results( @module_path.join("::"), method.name, type )
1119
- when "W"
1120
- type = "writer"
1121
- method_name << "="
1122
- #store_to_results( @module_path.join("::"), method.name + "=", type )
1123
- when "RW"
1124
- type = "accessor"
1125
- method_name << ";#{ method_name }="
1126
- #store_to_results( @module_path.join("::"), method.name + "=", type )
1127
-
1128
- else
1129
-
1130
- raise_error( "Unknown attribute format for '#{ method.name }' ($MODULE). Expected 'R' (attr_reader), 'W' (attr_writer) or 'RW' (attr_accessor), got: '#{ method.rw }'" )
1131
-
1132
- end
1133
-
1134
- #store_to_results( @module_path.join("::"), method.name, type )
1135
-
1136
- method_header.merge!( :__type => type )
1137
-
1138
- else
1139
-
1140
- method_header.merge!( :__type => "method" )
1141
-
1142
- end
1143
-
1144
- store_to_results( @module_path.join("::"), method.name, type, params )
1145
-
1146
- # do something
1147
- [ method_name, method_header ]
1148
-
1149
- else
1150
-
1151
- nil
1152
-
1153
- end
1154
-
1155
- end
1156
-
1157
- # verify if
1158
- def has_method?( target, method_name )
1159
-
1160
- target.method_list.select{ | method |
1161
-
1162
- method.name == method_name
1163
-
1164
- }.count > 0
1165
-
1166
- end
1167
-
1168
- def encode_string( string )
1169
-
1170
- return "" if string.nil?
1171
-
1172
- result = "%s" % string
1173
-
1174
- result.gsub!( /\&/, '&amp;' )
1175
- result.gsub!( /\</, '&lt;' )
1176
- result.gsub!( /\>/, '&gt;' )
1177
- result.gsub!( /\"/, '&quot;' )
1178
- result.gsub!( /\'/, '&apos;' )
1179
-
1180
- result
1181
-
1182
- end
1183
-
1184
- def process_attributes( attributes )
1185
-
1186
- @processing = :attributes
1187
-
1188
- results = []
1189
-
1190
- attributes.each{ | attribute |
1191
-
1192
- #p attribute.comment
1193
-
1194
- results << process_method( attribute )
1195
-
1196
- # TODO: tapa miten saadaan attribuuttien getteri ja setteri dokumentoitua implemenaatioon
1197
-
1198
- }
1199
-
1200
- Hash[ results ]
1201
-
1202
- end
1203
-
1204
- def process_comment( comment )
1205
-
1206
- header = {}
1207
-
1208
- current_section = nil
1209
-
1210
- return header if comment.nil? || comment.empty?
1211
-
1212
- comment.each_line{ | line |
1213
-
1214
- # remove '#' char from beginning of line
1215
- line.slice!( 0 )
1216
-
1217
- # if next character is whitespace assume that this is valid comment line
1218
- # NOTE: that if linefeed is required use "#<#32><#10>"
1219
- if [ 32 ].include?( line[ 0 ] )
1220
-
1221
- # remove first character
1222
- line.slice!( 0 )
1223
-
1224
- # if line is a section header
1225
- if line[ 0..2 ] == "== "
1226
-
1227
- # remove section header indicator string ("== ")
1228
- line.slice!( 0..2 )
1229
-
1230
- # remove cr/lf
1231
- line.gsub!( /[\n\r]/, "" )
1232
-
1233
- current_section = line.to_sym
1234
-
1235
- else
1236
-
1237
- unless current_section.nil?
1238
-
1239
- # remove cr/lf
1240
- # NOTE: if crlf is required use '\n'
1241
- line.gsub!( /[\n\r]/, "" )
1242
-
1243
- # store to header hash
1244
- if header.has_key?( current_section )
1245
-
1246
- header[ current_section ] << "\n" << ( line.rstrip )
1247
-
1248
- else
1249
-
1250
- header[ current_section ] = line.rstrip
1251
-
1252
- end
1253
-
1254
- else
1255
-
1256
- #puts "[nodoc?] %s" % line
1257
-
1258
- end
1259
-
1260
- end
1261
-
1262
- else
1263
-
1264
- #puts "[nodoc] %s" % line
1265
-
1266
- end
1267
-
1268
- }
1269
-
1270
- header
1271
-
1272
- end
1273
-
1274
- def apply_macros!( source, macros )
1275
-
1276
- macros.each_pair{ | key, value |
1277
-
1278
- source.gsub!( /(\$#{ key })\b/, value || "" )
1279
-
1280
- }
1281
-
1282
- source
1283
-
1284
- end
1285
-
1286
- def raise_error( text, topic = nil )
1287
-
1288
- type = ( @processing == "method" ) ? "method" : "attribute"
1289
-
1290
- text.gsub!( '$TYPE', type )
1291
-
1292
- text.gsub!( '$MODULE', @current_module.full_name )
1293
-
1294
- text = "=========================================================================================================\n" <<
1295
- "File: #{ @module_in_files.join(", ") }\n" << text << "\n\nExample:\n\n"
1296
-
1297
- text << help( topic ) unless topic.nil?
1298
-
1299
- warn( text << "\n" )
1300
-
1301
- end
1302
-
1303
- def generate_return_values_element( header, feature )
1304
-
1305
- return "" if ( [ 'writer' ].include?( feature.last[ :__type ] ) )
1306
-
1307
- return if feature.last[ :returns ].nil? || feature.last[ :returns ].empty?
1308
-
1309
- if feature.last[ :returns ].nil?
1310
-
1311
- raise_error("Error: $TYPE '#{ feature.first }' ($MODULE) doesn't have return value type(s) defined", 'returns' )
1312
-
1313
- end
1314
-
1315
- count = 0
1316
-
1317
- # generate return value types template
1318
- returns = feature.last[ :returns ].collect{ | return_types |
1319
-
1320
- return_types.collect{ | returns |
1321
-
1322
- count += 1
1323
-
1324
- # apply types to returns template
1325
- apply_macros!( @templates["behaviour.xml.returns"].clone, {
1326
- "RETURN_VALUE_TYPE" => encode_string( returns.first ),
1327
- "RETURN_VALUE_DESCRIPTION" => encode_string( returns.last["description"] ),
1328
- "RETURN_VALUE_EXAMPLE" => encode_string( returns.last["example"] ),
1329
- }
1330
- )
1331
-
1332
- }.join
1333
-
1334
- }.join
1335
-
1336
- if count > 0
1337
-
1338
- apply_macros!( @templates["behaviour.xml.method.returns"].clone, {
1339
-
1340
- "METHOD_RETURNS" => returns
1341
-
1342
- }
1343
- )
1344
-
1345
- else
1346
-
1347
- ""
1348
-
1349
- end
1350
-
1351
- end
1352
-
1353
- def generate_exceptions_element( header, feature )
1354
-
1355
- return "" if ( feature.last[:__type] != 'method' )
1356
-
1357
- #if feature.last[ :exceptions ].nil?
1358
- # raise_error("Error: $TYPE '#{ feature.first }' ($MODULE) doesn't have exceptions(s) defined", 'exceptions' )
1359
- #end
1360
-
1361
- return "" if feature.last[ :exceptions ].nil? || feature.last[ :exceptions ].empty?
1362
-
1363
- count = 0
1364
-
1365
- # generate exceptions template
1366
- exceptions = feature.last[ :exceptions ].collect{ | exceptions |
1367
-
1368
- exceptions.collect{ | exception |
1369
-
1370
- count += 1
1371
-
1372
- # apply types to exception template
1373
- apply_macros!( @templates["behaviour.xml.exception"].clone, {
1374
- "EXCEPTION_NAME" => encode_string( exception.first ),
1375
- "EXCEPTION_DESCRIPTION" => encode_string( exception.last["description"] )
1376
- }
1377
- )
1378
-
1379
- }.join
1380
-
1381
- }.join
1382
-
1383
- if count > 0
1384
-
1385
- apply_macros!( @templates["behaviour.xml.method.exceptions"].clone, {
1386
-
1387
- "METHOD_EXCEPTIONS" => exceptions
1388
-
1389
- }
1390
- )
1391
-
1392
- else
1393
-
1394
- ""
1395
-
1396
- end
1397
-
1398
- end
1399
-
1400
- def generate_arguments_element( header, feature )
1401
-
1402
- return "" if ( feature.last[:__type] == 'reader' )
1403
-
1404
- argument_types = { "*" => "multi", "&" => "block" }
1405
- argument_types.default = "normal"
1406
-
1407
- #return "" if ( @processing == :attributes && feature.last[:__type] == 'R' )
1408
-
1409
- feature.last[ :__type ]
1410
-
1411
- if feature.last[ :arguments ].nil? and feature.last[ :__arguments_found ] > 0
1412
-
1413
- note = ". Note that also attribute writer requires input value defined as argument." if [ 'writer', 'accessor' ].include?( @processing )
1414
-
1415
- raise_error("Error: $TYPE '#{ feature.first }' ($MODULE) doesn't have arguments(s) defined#{ note }", [ 'writer', 'accessor' ].include?( @processing ) ? 'attr_argument' : 'arguments' )
1416
-
1417
- end
1418
-
1419
- # generate arguments xml
1420
- arguments = ( feature.last[:arguments] || {} ).collect{ | arg |
1421
-
1422
- # generate argument types template
1423
- arg.collect{ | argument |
1424
-
1425
- argument_type = argument_types[ argument.first[0].chr ]
1426
- argument_name = "%s" % argument.first
1427
- argument_name[0]="" if argument_types.has_key?( argument_name[0].chr )
1428
-
1429
- argument_type = "block_argument" if argument_type == "block" && argument_name.include?( "#" )
1430
-
1431
- default_value_set = false
1432
- default_value = nil
1433
-
1434
- if argument.last.has_key?( :argument_type_order )
1435
-
1436
- argument_types_in_order = argument.last[:argument_type_order].collect{ | type |
1437
- [ type, argument.last[:types][ type ] ]
1438
- }
1439
-
1440
- else
1441
-
1442
- argument_types_in_order = argument.last[ :types ]
1443
-
1444
- end
1445
-
1446
- argument_types_in_order ||= []
1447
-
1448
- # in case of argument is not documented at all...
1449
- if argument_types_in_order.empty?
1450
-
1451
- # set optional flag if default value given
1452
- unless argument.last[:default].nil?
1453
-
1454
- default_value = argument.last[:default]
1455
- default_value_set = true
1456
-
1457
- end
1458
-
1459
- end
1460
-
1461
- types_xml = argument_types_in_order.collect{ | type |
1462
-
1463
- unless argument.last[:default].nil?
1464
-
1465
- # show warning if default value for optional argument is already set
1466
- #raise_error( "Error: Default value for optional argument '%s' ($MODULE) is already set! ('%s' --> '%s')" % [ argument.first, default_value, type.last["default"] ] ) if default_value_set == true
1467
-
1468
- default_value = argument.last[:default]
1469
- default_value_set = true
1470
-
1471
- end
1472
-
1473
- =begin
1474
- unless type.last["default"].nil?
1475
-
1476
- # show warning if default value for optional argument is already set
1477
- #raise_error( "Error: Default value for optional argument '%s' ($MODULE) is already set! ('%s' --> '%s')" % [ argument.first, default_value, type.last["default"] ] ) if default_value_set == true
1478
-
1479
-
1480
- default_value = type.last["default"]
1481
- default_value_set = true
1482
-
1483
- end
1484
- =end
1485
-
1486
- if type.last["description"].nil?
1487
-
1488
- raise_error("Warning: Argument description for '%s' ($MODULE) is empty." % [ argument.first ], 'argument' )
1489
-
1490
- end
1491
-
1492
- if type.last["example"].nil?
1493
-
1494
- raise_error("Warning: Argument '%s' ($MODULE) example is empty." % [ argument.first ])
1495
-
1496
- end
1497
-
1498
- apply_macros!( @templates["behaviour.xml.argument_type"].clone, {
1499
-
1500
- "ARGUMENT_TYPE" => encode_string( argument_type == 'block' ? "Proc" : type.first ),
1501
- "ARGUMENT_DESCRIPTION" => encode_string( type.last["description"] ),
1502
- "ARGUMENT_EXAMPLE" => encode_string( type.last["example"] ),
1503
-
1504
- }
1505
- )
1506
-
1507
- }.join
1508
-
1509
- if argument_type == "multi"
1510
-
1511
- default_value = "[]"
1512
- default_value_set = true
1513
-
1514
- end
1515
-
1516
- if default_value_set
1517
-
1518
- default_value = apply_macros!( @templates["behaviour.xml.argument.default"].clone, {
1519
- "ARGUMENT_DEFAULT_VALUE" => encode_string( default_value || "" )
1520
- }
1521
- )
1522
-
1523
- else
1524
-
1525
- default_value = ""
1526
-
1527
- end
1528
-
1529
- # apply types to arguments template
1530
- apply_macros!( @templates["behaviour.xml.argument"].clone, {
1531
- "ARGUMENT_NAME" => encode_string( argument_name ),
1532
- "ARGUMENT_TYPE" => encode_string( argument_type ),
1533
- "ARGUMENT_TYPES" => types_xml,
1534
- "ARGUMENT_DEFAULT_VALUE" => default_value.to_s,
1535
- "ARGUMENT_OPTIONAL" => encode_string( argument_type == "multi" ? "true" : default_value_set.to_s )
1536
- }
1537
- )
1538
-
1539
- }.join
1540
-
1541
- }.join
1542
-
1543
- apply_macros!( @templates["behaviour.xml.method.arguments"].clone, {
1544
-
1545
- "METHOD_ARGUMENTS" => arguments
1546
-
1547
- }
1548
- )
1549
-
1550
-
1551
- end
1552
-
1553
- def generate_tables_element( header, features )
1554
-
1555
- tables = []
1556
-
1557
- unless features.last[:tables].nil? #[:tables]
1558
-
1559
- tables = features.last[:tables].collect{ | table |
1560
-
1561
- header = table[ "content" ].first.collect{ | header_item |
1562
- apply_macros!( @templates["behaviour.xml.table.item"].clone, {
1563
- "ITEM" => encode_string( header_item )
1564
- }
1565
- )
1566
- }
1567
-
1568
- rows = table[ "content" ][ 1 .. -1 ].collect{ | row |
1569
-
1570
- row_items = row.collect{ | row_item |
1571
-
1572
- apply_macros!( @templates["behaviour.xml.table.item"].clone, {
1573
- "ITEM" => encode_string( row_item )
1574
- }
1575
- )
1576
- }
1577
-
1578
- apply_macros!( @templates["behaviour.xml.table.row"].clone, {
1579
-
1580
- "TABLE_ROW_ITEMS" => row_items.join("")
1581
-
1582
- }
1583
- )
1584
-
1585
- }
1586
-
1587
-
1588
- apply_macros!( @templates["behaviour.xml.table"].clone, {
1589
- "TABLE_NAME" => encode_string( table[ "name" ] ),
1590
- "TABLE_TITLE" => encode_string( table[ "title" ] ),
1591
- "TABLE_HEADER_ITEMS" => header.join(""),
1592
- "TABLE_ROWS" => rows.join("")
1593
- }
1594
- )
1595
- }
1596
-
1597
- end
1598
-
1599
- if tables.count > 0
1600
-
1601
- apply_macros!( @templates["behaviour.xml.method.tables"].clone, {
1602
-
1603
- "METHOD_TABLES" => tables.join("")
1604
-
1605
- }
1606
- )
1607
-
1608
- else
1609
-
1610
- ""
1611
-
1612
- end
1613
-
1614
- end
1615
-
1616
- def generate_deprecated_element( header, feature, &block )
1617
-
1618
- if feature.last.has_key?( :deprecated )
1619
-
1620
- yield
1621
-
1622
- apply_macros!( @templates["behaviour.xml.method.deprecated"].clone, {
1623
- "DEPRECATED_IN_VERSION_NUMBER" => encode_string( feature.last[:deprecated] )
1624
- }
1625
- )
1626
-
1627
- else
1628
-
1629
- ""
1630
-
1631
- end
1632
-
1633
- end
1634
-
1635
- def generate_info_element( header, feature )
1636
-
1637
- if feature.last.has_key?( :info )
1638
-
1639
- apply_macros!( @templates["behaviour.xml.method.info"].clone, {
1640
- "METHOD_INFO" => encode_string( feature.last[:info] )
1641
- }
1642
- )
1643
-
1644
- else
1645
-
1646
- ""
1647
-
1648
- end
1649
-
1650
- end
1651
-
1652
- def generate_methods_element( header, features )
1653
-
1654
- # collect method and attribute templates
1655
- methods = features.collect{ | feature_set |
1656
-
1657
- feature_set.collect{ | feature |
1658
-
1659
- @processing = feature.last[:__type]
1660
-
1661
- # TODO: tarkista lähdekoodista että onko argument optional vai ei
1662
- # TODO: tarkista että onko kaikki argumentit dokumentoitu
1663
-
1664
- arguments = generate_arguments_element( header, feature )
1665
-
1666
- returns = generate_return_values_element( header, feature )
1667
-
1668
- exceptions = generate_exceptions_element( header, feature )
1669
-
1670
- tables = generate_tables_element( header, feature )
1671
-
1672
- info = generate_info_element( header, feature )
1673
-
1674
- deprecated = generate_deprecated_element( header, feature ){
1675
-
1676
- arguments = ""
1677
- returns = ""
1678
- exceptions = ""
1679
- tables = ""
1680
-
1681
- }
1682
-
1683
- if feature.last[:description].nil?
1684
-
1685
- raise_error("Warning: $TYPE description for '#{ feature.first }' ($MODULE) is empty.", 'description')
1686
-
1687
- end
1688
-
1689
- # generate method template
1690
- apply_macros!( @templates["behaviour.xml.method"].clone, {
1691
- "METHOD_NAME" => encode_string( feature.first ),
1692
- "METHOD_TYPE" => encode_string( feature.last[:__type] || "unknown" ),
1693
- "METHOD_DEPRECATED" => deprecated,
1694
- "METHOD_DESCRIPTION" => encode_string( feature.last[:description] ),
1695
- "METHOD_ARGUMENTS" => arguments,
1696
- "METHOD_RETURNS" => returns,
1697
- "METHOD_EXCEPTIONS" => exceptions,
1698
- "METHOD_TABLES" => tables,
1699
- "METHOD_INFO" => info # feature.last[:info]
1700
- }
1701
- )
1702
-
1703
- }.join
1704
-
1705
- }.join
1706
-
1707
-
1708
- end
1709
-
1710
- def generate_behaviour_element( header, methods )
1711
-
1712
- # verify that behaviour description is defined
1713
- unless header.has_key?(:description)
1714
-
1715
- raise_error("Warning: Behaviour description for $MODULE is empty.", 'behaviour_description' ) unless methods.empty?
1716
-
1717
- end
1718
-
1719
- # verify that behaviour name is defined
1720
- unless header.has_key?(:behaviour)
1721
-
1722
- raise_error("Warning: Behaviour name for $MODULE is not defined.", 'behaviour_name' ) unless methods.empty?
1723
-
1724
- end
1725
-
1726
- # verify that behaviour object type(s) is defined
1727
- unless header.has_key?(:objects)
1728
-
1729
- raise_error("Warning: Behaviour object type(s) for $MODULE is not defined.", 'behaviour_object_types' ) unless methods.empty?
1730
-
1731
- end
1732
-
1733
- # verify that behaviour sut type(s) is defined
1734
- unless header.has_key?(:sut_type)
1735
-
1736
- raise_error("Warning: Behaviour SUT type for $MODULE is not defined.", 'behaviour_sut_type' ) unless methods.empty?
1737
-
1738
- end
1739
-
1740
- # verify that behaviour input type(s) is defined
1741
- unless header.has_key?(:input_type)
1742
-
1743
- raise_error("Warning: Behaviour input type for $MODULE is not defined.", 'behaviour_input_type' ) unless methods.empty?
1744
-
1745
- end
1746
-
1747
- # verify that behaviour sut version(s) is defined
1748
- unless header.has_key?(:sut_version)
1749
-
1750
- raise_error("Warning: Behaviour SUT version for $MODULE is not defined.", 'behaviour_version' ) unless methods.empty?
1751
-
1752
- end
1753
-
1754
- # verify that behaviour sut version(s) is defined
1755
- unless header.has_key?(:requires)
1756
-
1757
- raise_error("Warning: Required plugin name is not defined for $MODULE.", 'behaviour_requires' ) unless methods.empty?
1758
-
1759
- end
1760
-
1761
- # apply header
1762
- text = apply_macros!( @templates["behaviour.xml"].clone, {
1763
- "REQUIRED_PLUGIN" => encode_string( header[:requires] ),
1764
- "BEHAVIOUR_NAME" => encode_string( header[:behaviour] ),
1765
- "BEHAVIOUR_METHODS" => methods,
1766
- "OBJECT_TYPE" => encode_string( header[:objects] ),
1767
- "SUT_TYPE" => encode_string( header[:sut_type] ),
1768
- "INPUT_TYPE" => encode_string( header[:input_type] ),
1769
- "VERSION" => encode_string( header[:sut_version] ),
1770
- "MODULE_NAME" => encode_string( @module_path.join("::") )
1771
- }
1772
- )
1773
-
1774
- # remove extra linefeeds
1775
- text.gsub!( /^[\n]+/, "\n" )
1776
-
1777
- text.gsub!( /^(\s)*$/, "" )
1778
-
1779
- text
1780
-
1781
- end
1782
-
1783
- def generate_behaviour( header, *features )
1784
-
1785
- methods = generate_methods_element( header, features )
1786
-
1787
- generate_behaviour_element( header, methods )
1788
-
1789
- end
1790
-
1791
- def process_module( _module )
1792
-
1793
- @already_processed_files << _module.full_name
1794
-
1795
- # skip if not a behaviour module
1796
- return if /^MobyBehaviour.*/ !~ _module.full_name.to_s
1797
-
1798
- module_header = process_comment( _module.comment )
1799
-
1800
- # store information where module is stored
1801
- @module_in_files = _module.in_files.collect{ | file | file.file_absolute_name }
1802
-
1803
- #unless module_header.empty?
1804
-
1805
- @current_module = _module
1806
-
1807
- # process methods
1808
- methods = process_methods( _module.method_list )
1809
-
1810
- # process attributes
1811
- attributes = process_attributes( _module.attributes )
1812
-
1813
- print " ... %s" % module_header[:behaviour]
1814
-
1815
- xml = generate_behaviour( module_header, methods, attributes )
1816
-
1817
- xml_file_name = '%s.%s' % [ module_header[:behaviour], 'xml' ]
1818
-
1819
- begin
1820
-
1821
- if xml_file_name != '.xml'
1822
-
1823
- open( xml_file_name, 'w'){ | file | file << xml }
1824
-
1825
- puts ".xml"
1826
-
1827
- else
1828
-
1829
- if methods.count > 0
1830
-
1831
- xml_file_name = ( @module_path[1..-1].join("") ) + '.xml'
1832
-
1833
- warn("Warning: #{ @module_path.join("::") } does not have behaviour (module) description defined, saving as %s " % xml_file_name )
1834
-
1835
- open( xml_file_name, 'w'){ | file | file << xml }
1836
-
1837
- else
1838
-
1839
- warn("Skip: #{ @module_path.join("::") } does not have any public methods")
1840
-
1841
- end
1842
-
1843
- #p xml
1844
-
1845
- #warn("Skip: #{ @module_path.join("::") } XML not saved due to missing behaviour name/description ") #in #{ @module_in_files.join(", ") }")
1846
-
1847
- end
1848
-
1849
- rescue Exception => exception
1850
-
1851
- warn("Warning: Error writing file %s (%s: %s)" % [ xml_file_name, exception.class, exception.message ] )
1852
-
1853
- end
1854
-
1855
- #end
1856
-
1857
- # process if any child modules
1858
- process_modules( _module.modules ) unless _module.modules.empty?
1859
-
1860
- end
1861
-
1862
- end
1863
-
1864
- end
1865
-