tty-table 0.11.0 → 0.12.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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +104 -98
  5. data/lib/tty-table.rb +1 -1
  6. data/lib/tty/table.rb +70 -34
  7. data/lib/tty/table/alignment_set.rb +1 -3
  8. data/lib/tty/table/border.rb +50 -57
  9. data/lib/tty/table/border/ascii.rb +16 -16
  10. data/lib/tty/table/border/null.rb +19 -22
  11. data/lib/tty/table/border/row_line.rb +3 -2
  12. data/lib/tty/table/border/unicode.rb +16 -16
  13. data/lib/tty/table/border_dsl.rb +24 -22
  14. data/lib/tty/table/border_options.rb +32 -27
  15. data/lib/tty/table/column_constraint.rb +12 -9
  16. data/lib/tty/table/columns.rb +6 -6
  17. data/lib/tty/table/field.rb +46 -28
  18. data/lib/tty/table/header.rb +5 -5
  19. data/lib/tty/table/indentation.rb +7 -4
  20. data/lib/tty/table/operation/alignment.rb +1 -1
  21. data/lib/tty/table/operation/escape.rb +1 -2
  22. data/lib/tty/table/operation/padding.rb +1 -1
  23. data/lib/tty/table/operation/truncation.rb +1 -1
  24. data/lib/tty/table/operation/wrapped.rb +1 -1
  25. data/lib/tty/table/options.rb +1 -1
  26. data/lib/tty/table/orientation.rb +4 -4
  27. data/lib/tty/table/renderer.rb +8 -8
  28. data/lib/tty/table/renderer/ascii.rb +2 -2
  29. data/lib/tty/table/renderer/basic.rb +37 -40
  30. data/lib/tty/table/renderer/unicode.rb +1 -1
  31. data/lib/tty/table/row.rb +7 -7
  32. data/lib/tty/table/validatable.rb +23 -7
  33. data/lib/tty/table/version.rb +1 -1
  34. metadata +23 -272
  35. data/Rakefile +0 -10
  36. data/examples/alignment.rb +0 -10
  37. data/examples/basic.rb +0 -6
  38. data/examples/orientation.rb +0 -13
  39. data/examples/padding.rb +0 -15
  40. data/examples/resize.rb +0 -15
  41. data/spec/spec_helper.rb +0 -50
  42. data/spec/unit/access_spec.rb +0 -84
  43. data/spec/unit/add_row_spec.rb +0 -26
  44. data/spec/unit/alignment_set/each_spec.rb +0 -15
  45. data/spec/unit/alignment_set/new_spec.rb +0 -25
  46. data/spec/unit/alignment_set/to_ary_spec.rb +0 -12
  47. data/spec/unit/alignment_spec.rb +0 -69
  48. data/spec/unit/border/ascii/rendering_spec.rb +0 -88
  49. data/spec/unit/border/new_spec.rb +0 -25
  50. data/spec/unit/border/null/rendering_spec.rb +0 -128
  51. data/spec/unit/border/options/from_spec.rb +0 -36
  52. data/spec/unit/border/options/new_spec.rb +0 -12
  53. data/spec/unit/border/unicode/rendering_spec.rb +0 -61
  54. data/spec/unit/border_options/new_spec.rb +0 -18
  55. data/spec/unit/border_options/update_spec.rb +0 -16
  56. data/spec/unit/column_constraint/enforce_spec.rb +0 -68
  57. data/spec/unit/column_constraint/widths_spec.rb +0 -33
  58. data/spec/unit/columns/extract_widths_spec.rb +0 -41
  59. data/spec/unit/columns/total_width_spec.rb +0 -11
  60. data/spec/unit/columns/widths_from_spec.rb +0 -49
  61. data/spec/unit/data_spec.rb +0 -10
  62. data/spec/unit/each_spec.rb +0 -24
  63. data/spec/unit/each_with_index_spec.rb +0 -49
  64. data/spec/unit/empty_spec.rb +0 -21
  65. data/spec/unit/eql_spec.rb +0 -32
  66. data/spec/unit/field/equality_spec.rb +0 -49
  67. data/spec/unit/field/length_spec.rb +0 -33
  68. data/spec/unit/field/lines_spec.rb +0 -19
  69. data/spec/unit/field/new_spec.rb +0 -27
  70. data/spec/unit/field/width_spec.rb +0 -21
  71. data/spec/unit/filter_spec.rb +0 -20
  72. data/spec/unit/header/call_spec.rb +0 -28
  73. data/spec/unit/header/color_spec.rb +0 -17
  74. data/spec/unit/header/equality_spec.rb +0 -49
  75. data/spec/unit/header/height_spec.rb +0 -25
  76. data/spec/unit/header/new_spec.rb +0 -13
  77. data/spec/unit/header/set_spec.rb +0 -18
  78. data/spec/unit/header/to_ary_spec.rb +0 -12
  79. data/spec/unit/header_spec.rb +0 -11
  80. data/spec/unit/indentation/indent_spec.rb +0 -15
  81. data/spec/unit/new_spec.rb +0 -71
  82. data/spec/unit/operation/alignment/call_spec.rb +0 -37
  83. data/spec/unit/operation/escape/call_spec.rb +0 -13
  84. data/spec/unit/operation/filter/call_spec.rb +0 -14
  85. data/spec/unit/operation/truncation/call_spec.rb +0 -28
  86. data/spec/unit/operation/wrapped/call_spec.rb +0 -38
  87. data/spec/unit/operations/new_spec.rb +0 -28
  88. data/spec/unit/options/access_spec.rb +0 -12
  89. data/spec/unit/options_spec.rb +0 -23
  90. data/spec/unit/orientation_spec.rb +0 -143
  91. data/spec/unit/padding_spec.rb +0 -115
  92. data/spec/unit/properties_spec.rb +0 -23
  93. data/spec/unit/render_repeat_spec.rb +0 -39
  94. data/spec/unit/render_spec.rb +0 -61
  95. data/spec/unit/render_with_spec.rb +0 -104
  96. data/spec/unit/renderer/ascii/coloring_spec.rb +0 -83
  97. data/spec/unit/renderer/ascii/indentation_spec.rb +0 -39
  98. data/spec/unit/renderer/ascii/multiline_spec.rb +0 -99
  99. data/spec/unit/renderer/ascii/padding_spec.rb +0 -115
  100. data/spec/unit/renderer/ascii/render_spec.rb +0 -66
  101. data/spec/unit/renderer/ascii/resizing_spec.rb +0 -112
  102. data/spec/unit/renderer/ascii/separator_spec.rb +0 -38
  103. data/spec/unit/renderer/basic/alignment_spec.rb +0 -86
  104. data/spec/unit/renderer/basic/coloring_spec.rb +0 -59
  105. data/spec/unit/renderer/basic/extract_column_widths_spec.rb +0 -26
  106. data/spec/unit/renderer/basic/filter_spec.rb +0 -51
  107. data/spec/unit/renderer/basic/indentation_spec.rb +0 -46
  108. data/spec/unit/renderer/basic/multiline_spec.rb +0 -72
  109. data/spec/unit/renderer/basic/new_spec.rb +0 -24
  110. data/spec/unit/renderer/basic/options_spec.rb +0 -50
  111. data/spec/unit/renderer/basic/padding_spec.rb +0 -74
  112. data/spec/unit/renderer/basic/render_spec.rb +0 -55
  113. data/spec/unit/renderer/basic/resizing_spec.rb +0 -94
  114. data/spec/unit/renderer/basic/separator_spec.rb +0 -41
  115. data/spec/unit/renderer/basic/single_row_separator_spec.rb +0 -80
  116. data/spec/unit/renderer/basic/truncation_spec.rb +0 -33
  117. data/spec/unit/renderer/basic/wrapping_spec.rb +0 -38
  118. data/spec/unit/renderer/border_spec.rb +0 -102
  119. data/spec/unit/renderer/render_spec.rb +0 -34
  120. data/spec/unit/renderer/select_spec.rb +0 -20
  121. data/spec/unit/renderer/unicode/coloring_spec.rb +0 -68
  122. data/spec/unit/renderer/unicode/indentation_spec.rb +0 -39
  123. data/spec/unit/renderer/unicode/padding_spec.rb +0 -59
  124. data/spec/unit/renderer/unicode/render_spec.rb +0 -66
  125. data/spec/unit/renderer/unicode/separator_spec.rb +0 -36
  126. data/spec/unit/renderer_spec.rb +0 -17
  127. data/spec/unit/rotate_spec.rb +0 -84
  128. data/spec/unit/row/access_spec.rb +0 -23
  129. data/spec/unit/row/call_spec.rb +0 -43
  130. data/spec/unit/row/data_spec.rb +0 -24
  131. data/spec/unit/row/each_spec.rb +0 -29
  132. data/spec/unit/row/equality_spec.rb +0 -71
  133. data/spec/unit/row/height_spec.rb +0 -25
  134. data/spec/unit/row/new_spec.rb +0 -39
  135. data/spec/unit/row/to_ary_spec.rb +0 -12
  136. data/spec/unit/to_s_spec.rb +0 -56
  137. data/spec/unit/transformation/extract_tuples_spec.rb +0 -33
  138. data/spec/unit/utf_spec.rb +0 -31
  139. data/spec/unit/validatable/validate_options_spec.rb +0 -31
  140. data/spec/unit/validatable_spec.rb +0 -30
  141. data/tasks/console.rake +0 -11
  142. data/tasks/coverage.rake +0 -11
  143. data/tasks/spec.rake +0 -29
  144. data/tty-table.gemspec +0 -41
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Table::Renderer::Basic, 'resizing' do
4
- let(:header) { ['h1', 'h2', 'h3'] }
5
- let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
6
- let(:table) { TTY::Table.new(header, rows) }
7
-
8
- subject(:renderer) { described_class.new(table, options) }
9
-
10
- context 'when expanding' do
11
- context 'even columns' do
12
- let(:options) { {width: 16, resize: true} }
13
-
14
- it 'resizes each column' do
15
- expect(renderer.render).to eql unindent(<<-EOS)
16
- h1 h2 h3
17
- a1 a2 a3
18
- b1 b2 b3
19
- EOS
20
- end
21
- end
22
-
23
- context 'even columns with extra width' do
24
- let(:header) { ['h1', 'h2', 'h3', 'h4'] }
25
- let(:rows) { [['a1','a2','a3','a4'], ['b1','b2','b3','b4']] }
26
- let(:options) { {width: 21, resize: true} }
27
-
28
- it 'resizes each column' do
29
- expect(renderer.render).to eql unindent(<<-EOS)
30
- h1 h2 h3 h4
31
- a1 a2 a3 a4
32
- b1 b2 b3 b4
33
- EOS
34
- end
35
- end
36
-
37
- context 'uneven columns' do
38
- let(:header) { ['h1', 'h2', 'h3'] }
39
- let(:rows) { [['aaa1', 'aa2', 'aaaaaaa3'], ['b1', 'b2', 'b3']] }
40
- let(:options) { {width: 32, resize: true} }
41
-
42
- it 'resizes each column' do
43
- expect(renderer.render).to eql unindent(<<-EOS)
44
- h1 h2 h3
45
- aaa1 aa2 aaaaaaa3
46
- b1 b2 b3
47
- EOS
48
- end
49
- end
50
- end
51
-
52
- context 'when shrinking' do
53
- let(:header) { ['head1', 'head2'] }
54
- let(:rows) { [['aaaa1','aaaa2',], ['bbbb1','bbbb2']] }
55
-
56
- context 'even columns' do
57
- let(:options) { {width: 8, resize: true} }
58
-
59
- it 'resizes each column' do
60
- expect(renderer.render).to eql unindent(<<-EOS)
61
- he… h…
62
- aa… a…
63
- bb… b…
64
- EOS
65
- end
66
- end
67
-
68
- context 'even columns with extra width' do
69
- let(:options) { {width: 9, resize: true} }
70
-
71
- it 'resizes each column' do
72
- expect(renderer.render).to eql unindent(<<-EOS)
73
- he… he…
74
- aa… aa…
75
- bb… bb…
76
- EOS
77
- end
78
- end
79
-
80
- context 'uneven columns' do
81
- let(:header) { ['head1', 'head2', 'head3'] }
82
- let(:rows) { [['aaa1', 'aa2', 'aaaaaaa3'], ['b1', 'b2', 'b3']] }
83
- let(:options) { {width: 16, resize: true} }
84
-
85
- it 'resizes each column' do
86
- expect(renderer.render).to eql unindent(<<-EOS)
87
- he… he… head3
88
- aaa1 aa2 aaaa…
89
- b1 b2 b3
90
- EOS
91
- end
92
- end
93
- end
94
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Table::Renderer::Basic, 'with separator' do
4
- let(:header) { ['h1', 'h2', 'h3'] }
5
- let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
6
- let(:table) { TTY::Table.new(header, rows) }
7
-
8
- let(:object) { described_class.new table }
9
-
10
- subject(:renderer) { object }
11
-
12
- context 'when default' do
13
- it "sets through hash" do
14
- renderer.border :separator => :each_row
15
- expect(renderer.border.separator).to eql(:each_row)
16
- end
17
-
18
- it "sets through attribute" do
19
- renderer.border.separator= :each_row
20
- expect(renderer.border.separator).to eql(:each_row)
21
- end
22
-
23
- it "sets through block" do
24
- renderer.border do
25
- separator :each_row
26
- end
27
- expect(renderer.border.separator).to eql(:each_row)
28
- end
29
-
30
- it "renders each row" do
31
- renderer.border.separator= :each_row
32
- expect(renderer.render).to eq unindent(<<-EOS)
33
- h1 h2 h3
34
-
35
- a1 a2 a3
36
-
37
- b1 b2 b3
38
- EOS
39
- end
40
- end
41
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Table::Renderer::Basic, 'individual row separators' do
4
- context 'using the separator option' do
5
- let(:header) { ['h1', 'h2', 'h3'] }
6
- let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3']] }
7
- let(:table) { TTY::Table.new(header, rows) }
8
-
9
- let(:object) { described_class.new table }
10
-
11
- subject(:renderer) { object }
12
-
13
- it "can use an array to specify the rows to separate" do
14
- renderer.border.separator = [2]
15
- expect(renderer.render).to eq unindent(<<-EOS)
16
- h1 h2 h3
17
- a1 a2 a3
18
- b1 b2 b3
19
-
20
- c1 c2 c3
21
- EOS
22
- end
23
-
24
- it "can use a proc to specify the rows to separate" do
25
- renderer.border.separator = ->(line) { line == 2 }
26
- expect(renderer.render).to eq unindent(<<-EOS)
27
- h1 h2 h3
28
- a1 a2 a3
29
- b1 b2 b3
30
-
31
- c1 c2 c3
32
- EOS
33
- end
34
- end
35
-
36
- it "works without a header row" do
37
- table = TTY::Table.new([['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3']])
38
- renderer = described_class.new(table)
39
- renderer.border.separator = [1]
40
- expect(renderer.render).to eq unindent(<<-EOS)
41
- a1 a2 a3
42
- b1 b2 b3
43
-
44
- c1 c2 c3
45
- EOS
46
- end
47
-
48
- context 'using the :separator keyword as a row' do
49
- it "the :separator keyword can be used in the row definition" do
50
- table = TTY::Table.new([['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], :separator, ['c1', 'c2', 'c3']])
51
- expect(described_class.new(table).render).to eq unindent(<<-EOS)
52
- a1 a2 a3
53
- b1 b2 b3
54
-
55
- c1 c2 c3
56
- EOS
57
- end
58
-
59
- it "the :separator keyword can be pushed into a run" do
60
- table = TTY::Table.new([['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']])
61
- table << :separator << ['c1', 'c2', 'c3']
62
- expect(described_class.new(table).render).to eq unindent(<<-EOS)
63
- a1 a2 a3
64
- b1 b2 b3
65
-
66
- c1 c2 c3
67
- EOS
68
- end
69
-
70
- it "the :separator keyword be used between the header and the body" do
71
- table = TTY::Table.new(['h1', 'h2', 'h3'], [:separator, ['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']])
72
- expect(described_class.new(table).render).to eq unindent(<<-EOS)
73
- h1 h2 h3
74
-
75
- a1 a2 a3
76
- b1 b2 b3
77
- EOS
78
- end
79
- end
80
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Table::Renderer::Basic, 'truncation' do
4
- let(:header) { ['header1', 'head2', 'h3'] }
5
- let(:rows) { [['a1111111', 'a222', 'a3333333'], ['b111', 'b2222222', 'b333333']]}
6
- let(:table) { TTY::Table.new header, rows }
7
-
8
- subject(:renderer) { described_class.new(table, options) }
9
-
10
- context 'without column widths' do
11
- let(:options) { {} }
12
-
13
- it "doesn't shorten the fields" do
14
- expect(renderer.render).to eq unindent(<<-EOS)
15
- header1 head2 h3
16
- a1111111 a222 a3333333
17
- b111 b2222222 b333333
18
- EOS
19
- end
20
- end
21
-
22
- context 'with column widths' do
23
- let(:options) { { column_widths: [4, 5, 7] } }
24
-
25
- it 'shortens the fields' do
26
- expect(renderer.render).to eq unindent(<<-EOS)
27
- he… head2 h3
28
- a1… a222 a3333…
29
- b111 b22… b333333
30
- EOS
31
- end
32
- end
33
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Table::Renderer::Basic, 'wrapping' do
4
- let(:header) { ['header1', 'head2', 'h3'] }
5
- let(:rows) { [['a1111111', 'a222', 'a3333333'], ['b111', 'b2222222', 'b333333']]}
6
- let(:table) { TTY::Table.new header, rows }
7
-
8
- subject(:renderer) { described_class.new(table, options) }
9
-
10
- context 'without column widths' do
11
- let(:options) { {multiline: true} }
12
-
13
- it "doesn't wrap the fields" do
14
- expect(renderer.render).to eq unindent(<<-EOS)
15
- header1 head2 h3
16
- a1111111 a222 a3333333
17
- b111 b2222222 b333333
18
- EOS
19
- end
20
- end
21
-
22
- context 'with column widths' do
23
- let(:options) { { column_widths: [3, 5, 7], multiline: true} }
24
-
25
- it 'wraps the fields' do
26
- expect(renderer.render).to eq unindent(<<-EOS)
27
- hea head2 h3
28
- der
29
- 1
30
- a11 a222 a333333
31
- 111 3
32
- 11
33
- b11 b2222 b333333
34
- 1 222
35
- EOS
36
- end
37
- end
38
- end
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Table::Renderer, '#border' do
4
- let(:header) { ['h1', 'h2', 'h3'] }
5
- let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
6
- let(:border) { nil }
7
-
8
- let(:table) { TTY::Table.new(header, rows) }
9
-
10
- subject(:renderer) { described_class.select(type).new(table) }
11
-
12
- context 'when basic renderer' do
13
- let(:type) { :basic }
14
- let(:border) { {characters: {'top' => '-'}, style: :red} }
15
-
16
- it 'specifies border in hash' do
17
- renderer.border(border)
18
- expect(renderer.border.characters['top']).to eql('-')
19
- end
20
-
21
- it 'specifies border in characters attribute' do
22
- renderer.border.characters = {'top' => '*'}
23
- expect(renderer.border.characters['top']).to eql('*')
24
- end
25
-
26
- it 'specifies border in block' do
27
- renderer.border do
28
- mid '='
29
- mid_mid ' '
30
- end
31
-
32
- expect(renderer.render).to eq unindent(<<-EOS)
33
- h1 h2 h3
34
- == == ==
35
- a1 a2 a3
36
- b1 b2 b3
37
- EOS
38
- end
39
- end
40
-
41
- context 'when ascii renderer' do
42
- let(:type) { :ascii }
43
-
44
- it 'specifies border in block' do
45
- renderer.border do
46
- mid '='
47
- mid_mid '='
48
- mid_left '='
49
- mid_right '='
50
- end
51
-
52
- expect(renderer.render).to eq unindent(<<-EOS)
53
- +--+--+--+
54
- |h1|h2|h3|
55
- ==========
56
- |a1|a2|a3|
57
- |b1|b2|b3|
58
- +--+--+--+
59
- EOS
60
- end
61
-
62
- it 'specifies border as hash' do
63
- renderer.border({characters: {
64
- 'mid' => '=',
65
- 'mid_mid' => '=',
66
- 'mid_left' => '=',
67
- 'mid_right' => '=',
68
- }})
69
-
70
- expect(renderer.render).to eq unindent(<<-EOS)
71
- +--+--+--+
72
- |h1|h2|h3|
73
- ==========
74
- |a1|a2|a3|
75
- |b1|b2|b3|
76
- +--+--+--+
77
- EOS
78
- end
79
- end
80
-
81
- context 'when unicode renderer' do
82
- let(:type) { :unicode }
83
-
84
- it 'specifies border in block' do
85
- renderer.border do
86
- mid '='
87
- mid_mid '='
88
- mid_left '='
89
- mid_right '='
90
- end
91
-
92
- expect(renderer.render).to eq unindent(<<-EOS)
93
- ┌──┬──┬──┐
94
- │h1│h2│h3│
95
- ==========
96
- │a1│a2│a3│
97
- │b1│b2│b3│
98
- └──┴──┴──┘
99
- EOS
100
- end
101
- end
102
- end # border
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Table::Renderer, '#render' do
4
- let(:header) { ['h1', 'h2', 'h3'] }
5
- let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
6
- let(:table) { TTY::Table.new(header, rows) }
7
-
8
- subject { described_class.render(table, {}, &block) }
9
-
10
- context 'when default' do
11
- let(:renderer) { double(:renderer).as_null_object }
12
- let(:renderer_class) { double(:renderer_class).as_null_object }
13
- let(:yielded) { [] }
14
- let(:block) { proc { |render| yielded << render } }
15
-
16
- before { allow(described_class).to receive(:select).and_return(renderer_class) }
17
-
18
- it 'creates renderer' do
19
- subject
20
- expect(renderer_class).to have_received(:new).with(table, {})
21
- end
22
-
23
- it 'yields renderer' do
24
- allow(renderer_class).to receive(:new).and_return(renderer)
25
- expect { subject }.to change { yielded}.from([]).to([renderer])
26
- end
27
-
28
- it 'calls render' do
29
- allow(renderer_class).to receive(:new).and_return(renderer)
30
- subject
31
- expect(renderer).to have_received(:render)
32
- end
33
- end
34
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Table::Renderer, '#select' do
4
- let(:klass) { ::Class.new }
5
- let(:instance) { described_class }
6
-
7
- subject { instance.select(renderer) }
8
-
9
- context 'with basic' do
10
- let(:renderer) { :basic }
11
-
12
- it { is_expected.to be(TTY::Table::Renderer::Basic) }
13
- end
14
-
15
- context 'with unicode' do
16
- let(:renderer) { :unicode }
17
-
18
- it { is_expected.to be(TTY::Table::Renderer::Unicode) }
19
- end
20
- end