assert 2.15.2 → 2.16.0

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.
Files changed (41) hide show
  1. checksums.yaml +5 -5
  2. data/lib/assert/assertions.rb +6 -0
  3. data/lib/assert/config_helpers.rb +35 -14
  4. data/lib/assert/context.rb +36 -43
  5. data/lib/assert/context/test_dsl.rb +4 -4
  6. data/lib/assert/default_suite.rb +35 -40
  7. data/lib/assert/default_view.rb +109 -37
  8. data/lib/assert/file_line.rb +1 -1
  9. data/lib/assert/result.rb +67 -27
  10. data/lib/assert/runner.rb +14 -10
  11. data/lib/assert/suite.rb +41 -50
  12. data/lib/assert/test.rb +39 -81
  13. data/lib/assert/version.rb +1 -1
  14. data/lib/assert/view_helpers.rb +11 -21
  15. data/test/helper.rb +40 -0
  16. data/test/system/test_tests.rb +90 -88
  17. data/test/unit/assertions/assert_block_tests.rb +14 -10
  18. data/test/unit/assertions/assert_empty_tests.rb +14 -10
  19. data/test/unit/assertions/assert_equal_tests.rb +22 -14
  20. data/test/unit/assertions/assert_file_exists_tests.rb +14 -10
  21. data/test/unit/assertions/assert_includes_tests.rb +14 -10
  22. data/test/unit/assertions/assert_instance_of_tests.rb +14 -10
  23. data/test/unit/assertions/assert_kind_of_tests.rb +14 -10
  24. data/test/unit/assertions/assert_match_tests.rb +14 -10
  25. data/test/unit/assertions/assert_nil_tests.rb +14 -10
  26. data/test/unit/assertions/assert_raises_tests.rb +14 -10
  27. data/test/unit/assertions/assert_respond_to_tests.rb +14 -10
  28. data/test/unit/assertions/assert_same_tests.rb +20 -14
  29. data/test/unit/assertions/assert_true_false_tests.rb +28 -20
  30. data/test/unit/assertions_tests.rb +12 -9
  31. data/test/unit/config_helpers_tests.rb +72 -13
  32. data/test/unit/context/test_dsl_tests.rb +38 -45
  33. data/test/unit/context_tests.rb +12 -8
  34. data/test/unit/default_suite_tests.rb +66 -43
  35. data/test/unit/file_line_tests.rb +4 -1
  36. data/test/unit/result_tests.rb +71 -47
  37. data/test/unit/runner_tests.rb +34 -16
  38. data/test/unit/suite_tests.rb +61 -29
  39. data/test/unit/test_tests.rb +97 -134
  40. data/test/unit/view_helpers_tests.rb +17 -31
  41. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA512:
3
- data.tar.gz: 87349e6848472856f049017257486230a2b69f52bcf4d5ebdf4d4a23f88dd5b479d1499890ea1c63e890186c4c86d665c982d162ebd86a51e07762b809029e26
4
- metadata.gz: 539e868afc215555b585a85dd4caf52e9fbc7082e2eada2c33aea41900e22bb3a547c193b40f5433192bcd27571efd79254d93f54b7a973eab8fef0489398a55
5
2
  SHA1:
6
- data.tar.gz: fd4a2030e5b99394b4461d7673324e00fad58647
7
- metadata.gz: bb7bf7dd4fb2b739e897932d9499487ac730e1fc
3
+ data.tar.gz: 05d9e740571423b4946bf4744e82d1c329635de5
4
+ metadata.gz: 059d25ec7c38612afd6e776156ca4e81459eafc7
5
+ SHA512:
6
+ data.tar.gz: 863376fa7090c85130e651358ddbe6a1c53e47de4d0c1698d51ca94ce665bb51f13ef2029909b6e4c6f84768fb5e4a0b606939c39642f8b4f64ee3e446585356
7
+ metadata.gz: c9dfcbdc44401730b6bf66f9adca789657d82911b784ed453a5f2b077717a98160334ddecf96bcc5198c999d556c3984b4e29a0037b09f6af0247442e8c015a0
@@ -264,6 +264,12 @@ module Assert
264
264
  end
265
265
  end
266
266
 
267
+ private
268
+
269
+ def __assert_config__
270
+ raise NotImplementedError # should be defined by the config mixing this in
271
+ end
272
+
267
273
  # exception raised utility classes
268
274
 
269
275
  class CheckException
@@ -18,28 +18,43 @@ module Assert
18
18
  self.config.single_test_file_line
19
19
  end
20
20
 
21
- def count(type)
22
- self.config.suite.count(type)
21
+ def tests_to_run?; self.config.suite.tests_to_run?; end
22
+ def tests_to_run_count; self.config.suite.tests_to_run_count; end
23
+
24
+ def test_count; self.config.suite.test_count; end
25
+ def result_count; self.config.suite.result_count; end
26
+ def pass_result_count; self.config.suite.pass_result_count; end
27
+ def fail_result_count; self.config.suite.fail_result_count; end
28
+ def error_result_count; self.config.suite.error_result_count; end
29
+ def skip_result_count; self.config.suite.skip_result_count; end
30
+ def ignore_result_count; self.config.suite.ignore_result_count; end
31
+
32
+ def all_pass?
33
+ self.pass_result_count == self.result_count
23
34
  end
24
35
 
25
- def tests?
26
- self.count(:tests) > 0
36
+ def formatted_run_time(run_time, format = '%.6f')
37
+ format % run_time
27
38
  end
28
39
 
29
- def all_pass?
30
- self.count(:pass) == self.count(:results)
40
+ def formatted_test_rate(test_rate, format = '%.6f')
41
+ format % test_rate
31
42
  end
32
43
 
33
- def formatted_run_time(format = '%.6f')
34
- format % self.config.suite.run_time
44
+ def formatted_result_rate(result_rate, format = '%.6f')
45
+ format % result_rate
35
46
  end
36
47
 
37
- def formatted_test_rate(format = '%.6f')
38
- format % self.config.suite.test_rate
48
+ def formatted_suite_run_time(format = '%.6f')
49
+ formatted_run_time(self.config.suite.run_time, format)
39
50
  end
40
51
 
41
- def formatted_result_rate(format = '%.6f')
42
- format % self.config.suite.result_rate
52
+ def formatted_suite_test_rate(format = '%.6f')
53
+ formatted_test_rate(self.config.suite.test_rate, format)
54
+ end
55
+
56
+ def formatted_suite_result_rate(format = '%.6f')
57
+ formatted_result_rate(self.config.suite.result_rate, format)
43
58
  end
44
59
 
45
60
  def show_test_profile_info?
@@ -50,13 +65,19 @@ module Assert
50
65
  !!self.config.verbose
51
66
  end
52
67
 
53
- # return a list of result symbols that have actually occurred
68
+ # return a list of result type symbols that have actually occurred
54
69
  def ocurring_result_types
55
70
  @result_types ||= [:pass, :fail, :ignore, :skip, :error].select do |sym|
56
- self.count(sym) > 0
71
+ self.send("#{sym}_result_count") > 0
57
72
  end
58
73
  end
59
74
 
75
+ private
76
+
77
+ def get_rate(count, time)
78
+ time == 0 ? 0.0 : (count.to_f / time.to_f)
79
+ end
80
+
60
81
  end
61
82
 
62
83
  end
@@ -39,22 +39,28 @@ module Assert
39
39
  self.suite.test_methods << klass_method_name
40
40
  end
41
41
 
42
- self.suite.tests << Test.for_method(
42
+ self.suite.on_test(Test.for_method(
43
43
  method_name.to_s,
44
44
  ContextInfo.new(self, nil, caller.first),
45
45
  self.suite.config
46
- )
46
+ ))
47
47
  end
48
48
  end
49
49
 
50
50
  def initialize(running_test, config, result_callback)
51
- @__running_test__ = running_test
52
- @__assert_config__ = config
53
- @__result_callback__ = result_callback
51
+ @__assert_running_test__ = running_test
52
+ @__assert_config__ = config
53
+ @__assert_with_bt__ = nil
54
+
55
+ @__assert_result_callback__ = proc do |result|
56
+ result.set_backtrace(@__assert_with_bt__) if @__assert_with_bt__
57
+ result_callback.call(result)
58
+ result
59
+ end
54
60
  end
55
61
 
56
- # check if the assertion is a truthy value, if so create a new pass result, otherwise
57
- # create a new fail result with the desc and what failed msg.
62
+ # check if the assertion is a truthy value, if so create a new pass result,
63
+ # otherwise create a new fail result with the desc and what failed msg.
58
64
  # all other assertion helpers use this one in the end
59
65
  def assert(assertion, desc = nil)
60
66
  if assertion
@@ -63,7 +69,8 @@ module Assert
63
69
  what = if block_given?
64
70
  yield
65
71
  else
66
- "Failed assert: assertion was `#{Assert::U.show(assertion, __assert_config__)}`."
72
+ "Failed assert: assertion was "\
73
+ "`#{Assert::U.show(assertion, __assert_config__)}`."
67
74
  end
68
75
  fail(fail_message(desc, what))
69
76
  end
@@ -73,7 +80,8 @@ module Assert
73
80
  # result, otherwise create a new fail result with the desc and it's what failed msg
74
81
  def assert_not(assertion, fail_desc = nil)
75
82
  assert(!assertion, fail_desc) do
76
- "Failed assert_not: assertion was `#{Assert::U.show(assertion, __assert_config__)}`."
83
+ "Failed assert_not: assertion was "\
84
+ "`#{Assert::U.show(assertion, __assert_config__)}`."
77
85
  end
78
86
  end
79
87
  alias_method :refute, :assert_not
@@ -81,17 +89,13 @@ module Assert
81
89
  # adds a Pass result to the end of the test's results
82
90
  # does not break test execution
83
91
  def pass(pass_msg = nil)
84
- capture_result do |test, backtrace|
85
- Assert::Result::Pass.for_test(test, pass_msg, backtrace)
86
- end
92
+ capture_result(Assert::Result::Pass, pass_msg)
87
93
  end
88
94
 
89
95
  # adds an Ignore result to the end of the test's results
90
96
  # does not break test execution
91
97
  def ignore(ignore_msg = nil)
92
- capture_result do |test, backtrace|
93
- Assert::Result::Ignore.for_test(test, ignore_msg, backtrace)
94
- end
98
+ capture_result(Assert::Result::Ignore, ignore_msg)
95
99
  end
96
100
 
97
101
  # adds a Fail result to the end of the test's results
@@ -100,31 +104,29 @@ module Assert
100
104
  if halt_on_fail?
101
105
  raise Result::TestFailure, message || ''
102
106
  else
103
- capture_result do |test, backtrace|
104
- Assert::Result::Fail.for_test(test, message || '', backtrace)
105
- end
107
+ capture_result(Assert::Result::Fail, message || '')
106
108
  end
107
109
  end
108
110
  alias_method :flunk, :fail
109
111
 
110
- # adds a Skip result to the end of the test's results and breaks test execution
112
+ # adds a Skip result to the end of the test's results
113
+ # breaks test execution
111
114
  def skip(skip_msg = nil, called_from = nil)
112
115
  err = Result::TestSkipped.new(skip_msg || '')
113
116
  err.set_backtrace([called_from]) if called_from
114
117
  raise(err)
115
118
  end
116
119
 
117
- # alter the backtraces of fail results generated in the given block
120
+ # alter the backtraces of fail/skip results generated in the given block
118
121
  def with_backtrace(bt, &block)
119
122
  bt ||= []
120
- current_results.size.tap do |size|
121
- begin
122
- instance_eval(&block)
123
- rescue Result::TestSkipped, Result::TestFailure => e
124
- e.set_backtrace(bt); raise(e)
125
- ensure
126
- current_results[size..-1].each{ |r| r.set_backtrace(bt) }
127
- end
123
+ begin
124
+ @__assert_with_bt__ = bt
125
+ instance_eval(&block)
126
+ rescue Result::TestSkipped, Result::TestFailure => e
127
+ e.set_backtrace(@__assert_with_bt__); raise(e)
128
+ ensure
129
+ @__assert_with_bt__ = nil
128
130
  end
129
131
  end
130
132
 
@@ -140,7 +142,8 @@ module Assert
140
142
 
141
143
  protected
142
144
 
143
- # Returns a Proc that will output a custom message along with the default fail message.
145
+ # Returns a Proc that will output a custom message along with the default
146
+ # fail message.
144
147
  def fail_message(fail_desc = nil, what_failed_msg = nil)
145
148
  [ fail_desc, what_failed_msg ].compact.join("\n")
146
149
  end
@@ -151,20 +154,10 @@ module Assert
151
154
  __assert_config__.halt_on_fail
152
155
  end
153
156
 
154
- def capture_result
155
- if block_given?
156
- result = yield __running_test__, caller
157
- __running_test__.capture_result(result, @__result_callback__)
158
- result
159
- end
160
- end
161
-
162
- def current_results
163
- __running_test__.results
164
- end
165
-
166
- def __running_test__
167
- @__running_test__
157
+ def capture_result(result_klass, msg)
158
+ @__assert_result_callback__.call(
159
+ result_klass.for_test(@__assert_running_test__, msg, caller)
160
+ )
168
161
  end
169
162
 
170
163
  def __assert_config__
@@ -13,12 +13,12 @@ class Assert::Context
13
13
  instance_eval(&desc_or_macro)
14
14
  elsif block_given?
15
15
  # create a test from the given code block
16
- self.suite.tests << Assert::Test.for_block(
16
+ self.suite.on_test(Assert::Test.for_block(
17
17
  desc_or_macro.kind_of?(Assert::Macro) ? desc_or_macro.name : desc_or_macro,
18
18
  Assert::ContextInfo.new(self, called_from, first_caller || caller.first),
19
19
  self.suite.config,
20
20
  &block
21
- )
21
+ ))
22
22
  else
23
23
  test_eventually(desc_or_macro, called_from, first_caller || caller.first, &block)
24
24
  end
@@ -27,12 +27,12 @@ class Assert::Context
27
27
  def test_eventually(desc_or_macro, called_from = nil, first_caller = nil, &block)
28
28
  # create a test from a proc that just skips
29
29
  ci = Assert::ContextInfo.new(self, called_from, first_caller || caller.first)
30
- self.suite.tests << Assert::Test.for_block(
30
+ self.suite.on_test(Assert::Test.for_block(
31
31
  desc_or_macro.kind_of?(Assert::Macro) ? desc_or_macro.name : desc_or_macro,
32
32
  ci,
33
33
  self.suite.config,
34
34
  &proc { skip('TODO', ci.called_from) }
35
- )
35
+ ))
36
36
  end
37
37
  alias_method :test_skip, :test_eventually
38
38
 
@@ -2,63 +2,58 @@ require 'assert/suite'
2
2
 
3
3
  module Assert
4
4
 
5
- # This is the default suite used by assert. It stores test/result data in-memory.
5
+ # This is the default suite used by assert. In addition to the base suite
6
+ # behavior, it accumulates test/result counts in memory. This data is used
7
+ # by the runner/view for handling and presentation purposes.
6
8
 
7
9
  class DefaultSuite < Assert::Suite
8
10
 
9
- # Test data
10
-
11
- def ordered_tests
12
- self.tests
13
- end
14
-
15
- def reversed_tests
16
- self.tests.reverse
11
+ def initialize(config)
12
+ super
13
+ reset_run_data
17
14
  end
18
15
 
19
- def ordered_tests_by_run_time
20
- self.ordered_tests.sort{ |a, b| a.run_time <=> b.run_time }
21
- end
16
+ def test_count; @test_count; end
17
+ def result_count; @result_count; end
18
+ def pass_result_count; @pass_result_count; end
19
+ def fail_result_count; @fail_result_count; end
20
+ def error_result_count; @error_result_count; end
21
+ def skip_result_count; @skip_result_count; end
22
+ def ignore_result_count; @ignore_result_count; end
22
23
 
23
- def reversed_tests_by_run_time
24
- self.ordered_tests_by_run_time.reverse
25
- end
24
+ # Callbacks
26
25
 
27
- def test_count
28
- self.tests.size
26
+ def on_start
27
+ reset_run_data
29
28
  end
30
29
 
31
- # Result data
32
-
33
- def ordered_results
34
- self.ordered_tests.inject([]){ |results, test| results += test.results }
30
+ def before_test(test)
31
+ @test_count += 1
35
32
  end
36
33
 
37
- def reversed_results
38
- self.ordered_results.reverse
34
+ def on_result(result)
35
+ @result_count += 1
36
+ self.send("increment_#{result.type}_result_count")
39
37
  end
40
38
 
41
- # dump failed or errored results,
42
- # dump skipped or ignored results if they have a message
43
- def ordered_results_for_dump
44
- self.ordered_results.select do |result|
45
- [:fail, :error].include?(result.to_sym) ||
46
- !!([:skip, :ignore].include?(result.to_sym) && result.message)
47
- end
48
- end
39
+ private
49
40
 
50
- def reversed_results_for_dump
51
- self.ordered_results_for_dump.reverse
52
- end
41
+ def increment_pass_result_count; @pass_result_count += 1; end
42
+ def increment_fail_result_count; @fail_result_count += 1; end
43
+ def increment_error_result_count; @error_result_count += 1; end
44
+ def increment_skip_result_count; @skip_result_count += 1; end
45
+ def increment_ignore_result_count; @ignore_result_count += 1; end
53
46
 
54
- def result_count(type = nil)
55
- self.tests.inject(0){ |count, test| count += test.result_count(type) }
47
+ def reset_run_data
48
+ @test_count = 0
49
+ @result_count = 0
50
+ @pass_result_count = 0
51
+ @fail_result_count = 0
52
+ @error_result_count = 0
53
+ @skip_result_count = 0
54
+ @ignore_result_count = 0
56
55
  end
57
56
 
58
- # Callbacks
59
-
60
- # no custom callbacks
61
-
62
57
  end
63
58
 
64
59
  end
@@ -22,58 +22,41 @@ module Assert
22
22
  end
23
23
 
24
24
  def after_load
25
- puts "Loaded suite (#{test_count_statement})"
25
+ puts "Loaded suite (#{tests_to_run_count_statement})"
26
26
  end
27
27
 
28
28
  def on_start
29
- end
30
-
31
- def before_test(test)
32
- if show_test_verbose_info?
33
- puts "#{test.name.inspect} (#{test.context_class})"
34
- puts " #{test.file_line}"
35
- print " "
36
- end
37
- end
38
-
39
- def on_result(result)
40
- print ansi_styled_msg(self.send("#{result.to_sym}_abbrev"), result)
41
- end
42
-
43
- def after_test(test)
44
- if show_test_verbose_info?
45
- print " #{test_run_time(test)} seconds,"\
46
- " #{test.result_count} results,"\
47
- " #{test_result_rate(test)} results/s\n"
48
- end
29
+ reset_run_data
30
+ set_callbacks
49
31
  end
50
32
 
51
33
  def on_finish
52
- if tests?
34
+ if self.test_count > 0
53
35
  dump_test_results
54
36
  end
55
37
 
56
38
  # show profile output
57
39
  if show_test_profile_info?
58
- config.suite.ordered_tests_by_run_time.each do |test|
59
- puts "#{test_run_time(test)} seconds,"\
60
- " #{test.result_count} results,"\
61
- " #{test_result_rate(test)} results/s --"\
62
- " #{test.context_class}: #{test.name.inspect}"
40
+ # sort the test datas fastest to slowest
41
+ @test_datas.values.sort{ |a, b| a.run_time <=> b.run_time }.each do |test_data|
42
+ puts "#{formatted_run_time(test_data.run_time)} seconds,"\
43
+ " #{test_data.result_count} results,"\
44
+ " #{formatted_result_rate(test_data.result_rate)} results/s --"\
45
+ " #{test_data.context}: #{test_data.name.inspect}"
63
46
  end
64
47
  puts
65
48
  end
66
49
 
67
50
  # style the summaries of each result set
68
- styled_results_sentence = results_summary_sentence do |summary, result_sym|
69
- ansi_styled_msg(summary, result_sym)
51
+ styled_results_sentence = results_summary_sentence do |summary, result_type|
52
+ ansi_styled_msg(summary, result_type)
70
53
  end
71
54
 
72
55
  puts "#{result_count_statement}: #{styled_results_sentence}"
73
56
  puts
74
- puts "(#{formatted_run_time} seconds, " \
75
- "#{formatted_test_rate} tests/s, " \
76
- "#{formatted_result_rate} results/s)"
57
+ puts "(#{formatted_suite_run_time} seconds, " \
58
+ "#{formatted_suite_test_rate} tests/s, " \
59
+ "#{formatted_suite_result_rate} results/s)"
77
60
  end
78
61
 
79
62
  def on_interrupt(err)
@@ -82,24 +65,113 @@ module Assert
82
65
 
83
66
  private
84
67
 
68
+ def reset_run_data
69
+ @results_to_dump = []
70
+ @test_datas = {}
71
+ end
72
+
73
+ def set_callbacks
74
+ @metaclass = class << self; self; end
75
+ if accumulate_test_data?
76
+ @metaclass.class_eval <<-callbacks
77
+ def before_test(test)
78
+ test_data = get_test_data(test)
79
+ puts "\#{test_data.name.inspect} (\#{test_data.context})"
80
+ puts " \#{test_data.file_line}"
81
+ print " "
82
+ end
83
+
84
+ def on_result(result)
85
+ print ansi_styled_msg(self.send("\#{result.to_sym}_abbrev"), result.type)
86
+ @results_to_dump << ResultData.for_result(result) if dumpable_result?(result)
87
+ find_test_data(result.test_file_line).result_count += 1
88
+ end
89
+
90
+ def after_test(test)
91
+ test_data = find_test_data(test.file_line)
92
+ test_data.run_time = test.run_time
93
+ test_data.result_rate = get_rate(test_data.result_count, test_data.run_time)
94
+
95
+ if show_test_verbose_info?
96
+ print " \#{formatted_run_time(test_data.run_time)} seconds,"\
97
+ " \#{test_data.result_count} results,"\
98
+ " \#{formatted_result_rate(test_data.result_rate)} results/s\n"
99
+ end
100
+ end
101
+ callbacks
102
+ else
103
+ @metaclass.class_eval <<-callbacks
104
+ def on_result(result)
105
+ print ansi_styled_msg(self.send("\#{result.to_sym}_abbrev"), result.type)
106
+ @results_to_dump << ResultData.for_result(result) if dumpable_result?(result)
107
+ end
108
+ callbacks
109
+ end
110
+ end
111
+
112
+ def accumulate_test_data?
113
+ show_test_verbose_info? || show_test_profile_info?
114
+ end
115
+
116
+ def get_test_data(test)
117
+ @test_datas[test.file_line.to_s] ||= TestData.for_test(test)
118
+ end
119
+
120
+ def find_test_data(test_file_line)
121
+ @test_datas[test_file_line.to_s]
122
+ end
123
+
124
+ def dumpable_result?(result)
125
+ [:fail, :error].include?(result.type) ||
126
+ !!([:skip, :ignore].include?(result.type) && result.message)
127
+ end
128
+
85
129
  def dump_test_results
86
130
  print "\n"
87
131
  puts
88
132
 
89
- config.suite.reversed_results_for_dump.each do |result|
133
+ @results_to_dump.sort.each do |result_data|
90
134
  # output the styled result details
91
- puts ansi_styled_msg(result.to_s, result)
135
+ puts ansi_styled_msg(result_data.details, result_data.type)
92
136
 
93
137
  # output any captured stdout
94
- puts captured_output(result.output) if result.output && !result.output.empty?
138
+ if result_data.output && !result_data.output.empty?
139
+ puts captured_output(result_data.output)
140
+ end
95
141
 
96
142
  # output re-run CLI cmd
97
- puts re_run_test_cmd(result.test_id)
143
+ puts re_run_test_cmd(result_data.test_id)
98
144
 
99
- # add an empty line between each result detail
145
+ # add an empty line between each dumped result
100
146
  puts
101
147
  end
148
+ end
149
+
150
+ attrs = [:name, :context, :file_line, :result_count, :run_time, :result_rate]
151
+ class TestData < Struct.new(*attrs)
152
+ def self.for_test(t)
153
+ self.new(t.name, t.context_class, t.file_line.to_s, 0, 0.0, 0.0)
154
+ end
155
+ end
156
+
157
+ attrs = [:type, :details, :output, :test_id, :sort_by]
158
+ class ResultData < Struct.new(*attrs)
159
+ def self.for_result(r)
160
+ self.new(r.type, r.to_s, r.output, r.test_id, self.sort_by(r))
161
+ end
102
162
 
163
+ def self.sort_by(r)
164
+ [r.test_file_name, r.test_line_num, r.file_name, r.line_num]
165
+ end
166
+
167
+ def <=>(other_rd)
168
+ # show in reverse definition order
169
+ if other_rd.kind_of?(ResultData)
170
+ other_rd.sort_by <=> self.sort_by
171
+ else
172
+ super
173
+ end
174
+ end
103
175
  end
104
176
 
105
177
  end