command_kit 0.2.2 → 0.4.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +4 -5
  3. data/.rubocop.yml +14 -1
  4. data/ChangeLog.md +82 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE.txt +1 -1
  7. data/README.md +18 -9
  8. data/command_kit.gemspec +0 -1
  9. data/examples/printing/tables.rb +141 -0
  10. data/gemspec.yml +3 -3
  11. data/lib/command_kit/arguments/argument.rb +2 -2
  12. data/lib/command_kit/arguments.rb +27 -2
  13. data/lib/command_kit/bug_report.rb +105 -0
  14. data/lib/command_kit/colors.rb +488 -15
  15. data/lib/command_kit/command.rb +1 -2
  16. data/lib/command_kit/edit.rb +54 -0
  17. data/lib/command_kit/env.rb +1 -1
  18. data/lib/command_kit/file_utils.rb +46 -0
  19. data/lib/command_kit/options/option.rb +45 -22
  20. data/lib/command_kit/options/option_value.rb +2 -2
  21. data/lib/command_kit/options/parser.rb +1 -4
  22. data/lib/command_kit/options/quiet.rb +1 -1
  23. data/lib/command_kit/options/verbose.rb +2 -2
  24. data/lib/command_kit/options/version.rb +10 -0
  25. data/lib/command_kit/options.rb +89 -14
  26. data/lib/command_kit/os.rb +1 -1
  27. data/lib/command_kit/printing/fields.rb +56 -0
  28. data/lib/command_kit/printing/indent.rb +1 -1
  29. data/lib/command_kit/printing/lists.rb +91 -0
  30. data/lib/command_kit/printing/tables/border_style.rb +169 -0
  31. data/lib/command_kit/printing/tables/cell_builder.rb +93 -0
  32. data/lib/command_kit/printing/tables/row_builder.rb +111 -0
  33. data/lib/command_kit/printing/tables/style.rb +198 -0
  34. data/lib/command_kit/printing/tables/table_builder.rb +145 -0
  35. data/lib/command_kit/printing/tables/table_formatter.rb +254 -0
  36. data/lib/command_kit/printing/tables.rb +208 -0
  37. data/lib/command_kit/program_name.rb +9 -0
  38. data/lib/command_kit/stdio.rb +5 -1
  39. data/lib/command_kit/version.rb +1 -1
  40. data/spec/arguments_spec.rb +33 -0
  41. data/spec/bug_report_spec.rb +266 -0
  42. data/spec/colors_spec.rb +232 -195
  43. data/spec/command_name_spec.rb +1 -1
  44. data/spec/command_spec.rb +2 -2
  45. data/spec/edit_spec.rb +72 -0
  46. data/spec/file_utils_spec.rb +59 -0
  47. data/spec/fixtures/template.erb +5 -0
  48. data/spec/options/option_spec.rb +48 -2
  49. data/spec/options/parser_spec.rb +0 -10
  50. data/spec/options/quiet_spec.rb +51 -0
  51. data/spec/options/verbose_spec.rb +51 -0
  52. data/spec/options/version_spec.rb +146 -0
  53. data/spec/options_spec.rb +46 -0
  54. data/spec/pager_spec.rb +1 -1
  55. data/spec/printing/fields_spec.rb +167 -0
  56. data/spec/printing/lists_spec.rb +99 -0
  57. data/spec/printing/tables/border_style.rb +43 -0
  58. data/spec/printing/tables/cell_builer_spec.rb +135 -0
  59. data/spec/printing/tables/row_builder_spec.rb +165 -0
  60. data/spec/printing/tables/style_spec.rb +377 -0
  61. data/spec/printing/tables/table_builder_spec.rb +252 -0
  62. data/spec/printing/tables/table_formatter_spec.rb +1180 -0
  63. data/spec/printing/tables_spec.rb +1069 -0
  64. data/spec/program_name_spec.rb +8 -0
  65. metadata +36 -7
@@ -0,0 +1,377 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/printing/tables/style'
3
+
4
+ describe CommandKit::Printing::Tables::Style do
5
+ describe "BORDER_STYLES" do
6
+ subject { described_class::BORDER_STYLES }
7
+
8
+ it "must be a Hash" do
9
+ expect(subject).to be_kind_of(Hash)
10
+ end
11
+
12
+ describe ":ascii" do
13
+ subject { super()[:ascii] }
14
+
15
+ it "must be a CommandKit::Printing::Tables::BorderStyle" do
16
+ expect(subject).to be_kind_of(CommandKit::Printing::Tables::BorderStyle)
17
+ end
18
+
19
+ it "must set #top_left_corner to '+'" do
20
+ expect(subject.top_left_corner).to eq('+')
21
+ end
22
+
23
+ it "must set #top_border to '-'" do
24
+ expect(subject.top_border).to eq('-')
25
+ end
26
+
27
+ it "must set #top_joined_border to '+'" do
28
+ expect(subject.top_joined_border).to eq('+')
29
+ end
30
+
31
+ it "must set #top_right_corner to '+'" do
32
+ expect(subject.top_right_corner).to eq('+')
33
+ end
34
+
35
+ it "must set #left_border to '|'" do
36
+ expect(subject.left_border).to eq('|')
37
+ end
38
+
39
+ it "must set #left_joined_border to '+'" do
40
+ expect(subject.left_joined_border).to eq('+')
41
+ end
42
+
43
+ it "must set #horizontal_separator to '-'" do
44
+ expect(subject.horizontal_separator).to eq('-')
45
+ end
46
+
47
+ it "must set #vertical_separator to '|'" do
48
+ expect(subject.vertical_separator).to eq('|')
49
+ end
50
+
51
+ it "must set #inner_joined_border to '+'" do
52
+ expect(subject.inner_joined_border).to eq('+')
53
+ end
54
+
55
+ it "must set #right_border to '|'" do
56
+ expect(subject.right_border).to eq('|')
57
+ end
58
+
59
+ it "must set #right_joined_border to '+'" do
60
+ expect(subject.right_joined_border).to eq('+')
61
+ end
62
+
63
+ it "must set #bottom_border to '-'" do
64
+ expect(subject.bottom_border).to eq('-')
65
+ end
66
+
67
+ it "must set #bottom_left_corner to '+'" do
68
+ expect(subject.bottom_left_corner).to eq('+')
69
+ end
70
+
71
+ it "must set #bottom_joined_border to '+'" do
72
+ expect(subject.bottom_joined_border).to eq('+')
73
+ end
74
+
75
+ it "must set #bottom_right_corner to '+'" do
76
+ expect(subject.bottom_right_corner).to eq('+')
77
+ end
78
+ end
79
+
80
+ describe ":line" do
81
+ subject { super()[:line] }
82
+
83
+ it "must be a CommandKit::Printing::Tables::BorderStyle" do
84
+ expect(subject).to be_kind_of(CommandKit::Printing::Tables::BorderStyle)
85
+ end
86
+
87
+ it "must set #top_left_corner to '┌'" do
88
+ expect(subject.top_left_corner).to eq('┌')
89
+ end
90
+
91
+ it "must set #top_border to '─'" do
92
+ expect(subject.top_border).to eq('─')
93
+ end
94
+
95
+ it "must set #top_joined_border to '┬'" do
96
+ expect(subject.top_joined_border).to eq('┬')
97
+ end
98
+
99
+ it "must set #top_right_corner to '┐'" do
100
+ expect(subject.top_right_corner).to eq('┐')
101
+ end
102
+
103
+ it "must set #left_border to '│'" do
104
+ expect(subject.left_border).to eq('│')
105
+ end
106
+
107
+ it "must set #left_joined_border to '├'" do
108
+ expect(subject.left_joined_border).to eq('├')
109
+ end
110
+
111
+ it "must set #horizontal_separator to '─'" do
112
+ expect(subject.horizontal_separator).to eq('─')
113
+ end
114
+
115
+ it "must set #vertical_separator to '│'" do
116
+ expect(subject.vertical_separator).to eq('│')
117
+ end
118
+
119
+ it "must set #inner_joined_border to '┼'" do
120
+ expect(subject.inner_joined_border).to eq('┼')
121
+ end
122
+
123
+ it "must set #right_border to '│'" do
124
+ expect(subject.right_border).to eq('│')
125
+ end
126
+
127
+ it "must set #right_joined_border to '┤'" do
128
+ expect(subject.right_joined_border).to eq('┤')
129
+ end
130
+
131
+ it "must set #bottom_border to '─'" do
132
+ expect(subject.bottom_border).to eq('─')
133
+ end
134
+
135
+ it "must set #bottom_left_corner to '└'" do
136
+ expect(subject.bottom_left_corner).to eq('└')
137
+ end
138
+
139
+ it "must set #bottom_joined_border to '┴'" do
140
+ expect(subject.bottom_joined_border).to eq('┴')
141
+ end
142
+
143
+ it "must set #bottom_right_corner to '┘'" do
144
+ expect(subject.bottom_right_corner).to eq('┘')
145
+ end
146
+ end
147
+
148
+ describe ":double_line" do
149
+ subject { super()[:double_line] }
150
+
151
+ it "must be a CommandKit::Printing::Tables::BorderStyle" do
152
+ expect(subject).to be_kind_of(CommandKit::Printing::Tables::BorderStyle)
153
+ end
154
+
155
+ it "must set #top_left_corner to '╔'" do
156
+ expect(subject.top_left_corner).to eq('╔')
157
+ end
158
+
159
+ it "must set #top_border to '═'" do
160
+ expect(subject.top_border).to eq('═')
161
+ end
162
+
163
+ it "must set #top_joined_border to '╦'" do
164
+ expect(subject.top_joined_border).to eq('╦')
165
+ end
166
+
167
+ it "must set #top_right_corner to '╗'" do
168
+ expect(subject.top_right_corner).to eq('╗')
169
+ end
170
+
171
+ it "must set #left_border to '║'" do
172
+ expect(subject.left_border).to eq('║')
173
+ end
174
+
175
+ it "must set #left_joined_border to '╠'" do
176
+ expect(subject.left_joined_border).to eq('╠')
177
+ end
178
+
179
+ it "must set #horizontal_separator to '═'" do
180
+ expect(subject.horizontal_separator).to eq('═')
181
+ end
182
+
183
+ it "must set #vertical_separator to '║'" do
184
+ expect(subject.vertical_separator).to eq('║')
185
+ end
186
+
187
+ it "must set #inner_joined_border to '╬'" do
188
+ expect(subject.inner_joined_border).to eq('╬')
189
+ end
190
+
191
+ it "must set #right_border to '║'" do
192
+ expect(subject.right_border).to eq('║')
193
+ end
194
+
195
+ it "must set #right_joined_border to '╣'" do
196
+ expect(subject.right_joined_border).to eq('╣')
197
+ end
198
+
199
+ it "must set #bottom_border to '═'" do
200
+ expect(subject.bottom_border).to eq('═')
201
+ end
202
+
203
+ it "must set #bottom_left_corner to '╚'" do
204
+ expect(subject.bottom_left_corner).to eq('╚')
205
+ end
206
+
207
+ it "must set #bottom_joined_border to '╩'" do
208
+ expect(subject.bottom_joined_border).to eq('╩')
209
+ end
210
+
211
+ it "must set #bottom_right_corner to '╝'" do
212
+ expect(subject.bottom_right_corner).to eq('╝')
213
+ end
214
+ end
215
+ end
216
+
217
+ describe "#initialize" do
218
+ it "must default #border to nil" do
219
+ expect(subject.border).to be(nil)
220
+ end
221
+
222
+ it "must default #padding to 1" do
223
+ expect(subject.padding).to be(1)
224
+ end
225
+
226
+ it "must default #justify to :left" do
227
+ expect(subject.justify).to be(:left)
228
+ end
229
+
230
+ it "must default #justify_header to :center" do
231
+ expect(subject.justify_header).to be(:center)
232
+ end
233
+
234
+ it "must default #separate_rows to false" do
235
+ expect(subject.separate_rows).to eq(false)
236
+ end
237
+
238
+ context "when given the border: keyword argument" do
239
+ context "and it's a Hash" do
240
+ let(:hash) do
241
+ {
242
+ top_left_corner: '=',
243
+ top_border: '=',
244
+ top_joined_border: '=',
245
+ top_right_corner: '=',
246
+ bottom_left_corner: '=',
247
+ bottom_border: '=',
248
+ bottom_joined_border: '=',
249
+ bottom_right_corner: '='
250
+ }
251
+ end
252
+
253
+ subject { described_class.new(border: hash) }
254
+
255
+ it "must initialize #border to a new CommandKit::Printing::Tables::BorderStyle" do
256
+ expect(subject.border).to be_kind_of(CommandKit::Printing::Tables::BorderStyle)
257
+ expect(subject.border.top_left_corner).to eq('=')
258
+ expect(subject.border.top_border).to eq('=')
259
+ expect(subject.border.top_joined_border).to eq('=')
260
+ expect(subject.border.top_right_corner).to eq('=')
261
+ expect(subject.border.bottom_left_corner).to eq('=')
262
+ expect(subject.border.bottom_border).to eq('=')
263
+ expect(subject.border.bottom_joined_border).to eq('=')
264
+ expect(subject.border.bottom_right_corner).to eq('=')
265
+ end
266
+ end
267
+
268
+ context "and it's :ascii" do
269
+ subject { described_class.new(border: :ascii) }
270
+
271
+ it "must set #border to BORDER_STYLES[:ascii]" do
272
+ expect(subject.border).to be(described_class::BORDER_STYLES[:ascii])
273
+ end
274
+ end
275
+
276
+ context "and it's :line" do
277
+ subject { described_class.new(border: :line) }
278
+
279
+ it "must set #border to BORDER_STYLES[:line]" do
280
+ expect(subject.border).to be(described_class::BORDER_STYLES[:line])
281
+ end
282
+ end
283
+
284
+ context "and it's :double_line" do
285
+ subject { described_class.new(border: :double_line) }
286
+
287
+ it "must set #border to BORDER_STYLES[:double_line]" do
288
+ expect(subject.border).to be(described_class::BORDER_STYLES[:double_line])
289
+ end
290
+ end
291
+
292
+ context "but it's an unknwon Symbol" do
293
+ let(:border) { :foo }
294
+
295
+ it do
296
+ expect {
297
+ described_class.new(border: border)
298
+ }.to raise_error(ArgumentError,"unknown border style (#{border.inspect}) must be either :ascii, :line, :double_line")
299
+ end
300
+ end
301
+
302
+ context "and it's nil" do
303
+ subject { described_class.new(border: nil) }
304
+
305
+ it "must set #border to nil" do
306
+ expect(subject.border).to be(nil)
307
+ end
308
+ end
309
+
310
+ context "but it's not a Symbol, Hash, or nil" do
311
+ let(:border) { Object.new }
312
+
313
+ it do
314
+ expect {
315
+ described_class.new(border: border)
316
+ }.to raise_error(ArgumentError,"invalid border value (#{border.inspect}) must be either :ascii, :line, :double_line, Hash, or nil")
317
+ end
318
+ end
319
+ end
320
+
321
+ context "when given the padding: keyword argument" do
322
+ let(:padding) { 2 }
323
+
324
+ subject { described_class.new(padding: padding) }
325
+
326
+ it "must set #padding" do
327
+ expect(subject.padding).to eq(padding)
328
+ end
329
+ end
330
+
331
+ context "when given the justify: keyword argument" do
332
+ let(:justify) { :center }
333
+
334
+ subject { described_class.new(justify: justify) }
335
+
336
+ it "must set #justify" do
337
+ expect(subject.justify).to eq(justify)
338
+ end
339
+ end
340
+
341
+ context "when given the justify: keyword argument" do
342
+ let(:justify_header) { :left }
343
+
344
+ subject { described_class.new(justify_header: justify_header) }
345
+
346
+ it "must set #justify_header" do
347
+ expect(subject.justify_header).to eq(justify_header)
348
+ end
349
+ end
350
+
351
+ context "when given the separate_rows: keyword argument" do
352
+ let(:separate_rows) { true }
353
+
354
+ subject { described_class.new(separate_rows: separate_rows) }
355
+
356
+ it "must set #separate_rows" do
357
+ expect(subject.separate_rows).to eq(separate_rows)
358
+ end
359
+ end
360
+ end
361
+
362
+ describe "#separate_rows?" do
363
+ context "when initialized with separate_rows: true" do
364
+ subject { described_class.new(separate_rows: true) }
365
+
366
+ it "must return true" do
367
+ expect(subject.separate_rows?).to be(true)
368
+ end
369
+ end
370
+
371
+ context "when not initialized with separate_rows: true" do
372
+ it "must return false" do
373
+ expect(subject.separate_rows?).to be(false)
374
+ end
375
+ end
376
+ end
377
+ end
@@ -0,0 +1,252 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/printing/tables/table_builder'
3
+
4
+ describe CommandKit::Printing::Tables::TableBuilder do
5
+ it { expect(described_class).to include(Enumerable) }
6
+
7
+ describe "#initialize" do
8
+ it "must initialize #rows to an empty Array" do
9
+ expect(subject.rows).to eq([])
10
+ end
11
+
12
+ it "must default #height to 0" do
13
+ expect(subject.height).to eq(0)
14
+ end
15
+
16
+ it "must default #width to 0" do
17
+ expect(subject.width).to eq(0)
18
+ end
19
+
20
+ it "must iniitialize #column_widths to an empty Array" do
21
+ expect(subject.column_widths).to eq([])
22
+ end
23
+
24
+ it "must default #max_columns to 0" do
25
+ expect(subject.max_columns).to eq(0)
26
+ end
27
+
28
+ it "must default #max_rows to 0" do
29
+ expect(subject.max_rows).to eq(0)
30
+ end
31
+
32
+ context "when given initial rows" do
33
+ let(:row1) { %w[foo bar] }
34
+ let(:row2) { %w[baz qux] }
35
+ let(:rows) { [row1, row2] }
36
+
37
+ subject { described_class.new(rows) }
38
+
39
+ it "must append the rows to the table" do
40
+ expect(subject.rows[0]).to be_kind_of(CommandKit::Printing::Tables::RowBuilder)
41
+ expect(subject.rows[0].cells[0].lines[0]).to eq(row1[0])
42
+ expect(subject.rows[0].cells[1].lines[0]).to eq(row1[1])
43
+
44
+ expect(subject.rows[1]).to be_kind_of(CommandKit::Printing::Tables::RowBuilder)
45
+ expect(subject.rows[1].cells[0].lines[0]).to eq(row2[0])
46
+ expect(subject.rows[1].cells[1].lines[0]).to eq(row2[1])
47
+ end
48
+
49
+ context "and when given the header: keyword argument" do
50
+ let(:header) { %w[A B] }
51
+
52
+ subject { described_class.new(rows, header: header) }
53
+
54
+ it "must append the header: value before the rows" do
55
+ expect(subject.rows[0]).to be_kind_of(CommandKit::Printing::Tables::RowBuilder)
56
+ expect(subject.rows[0].cells[0].lines[0]).to eq(header[0])
57
+ expect(subject.rows[0].cells[1].lines[0]).to eq(header[1])
58
+
59
+ expect(subject.rows[1]).to be_kind_of(CommandKit::Printing::Tables::RowBuilder)
60
+ expect(subject.rows[1].cells[0].lines[0]).to eq(row1[0])
61
+ expect(subject.rows[1].cells[1].lines[0]).to eq(row1[1])
62
+
63
+ expect(subject.rows[2]).to be_kind_of(CommandKit::Printing::Tables::RowBuilder)
64
+ expect(subject.rows[2].cells[0].lines[0]).to eq(row2[0])
65
+ expect(subject.rows[2].cells[1].lines[0]).to eq(row2[1])
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#header?" do
72
+ let(:header) { %w[A B] }
73
+ let(:rows) do
74
+ [
75
+ %w[foo bar],
76
+ %w[baz qux]
77
+ ]
78
+ end
79
+
80
+ context "when initialized with the header: keyword argument" do
81
+ subject { described_class.new(rows, header: header) }
82
+
83
+ it "must return true" do
84
+ expect(subject.header?).to be(true)
85
+ end
86
+ end
87
+
88
+ context "when not initialized with the header: keyword argument" do
89
+ it "must return false" do
90
+ expect(subject.header?).to be(false)
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "#<<" do
96
+ let(:row) { %w[foo bar] }
97
+
98
+ it "must append a new CommandKit::Printing::Tables::RowBuilder object to #rows" do
99
+ subject << row
100
+
101
+ expect(subject.rows.last).to be_kind_of(CommandKit::Printing::Tables::RowBuilder)
102
+ expect(subject.rows.last.cells[0].lines[0]).to eq(row[0])
103
+ expect(subject.rows.last.cells[1].lines[0]).to eq(row[1])
104
+ end
105
+
106
+ it "must increment #max_rows by 1" do
107
+ expect(subject.max_rows).to eq(0)
108
+
109
+ subject << row
110
+ expect(subject.max_rows).to eq(1)
111
+
112
+ subject << row
113
+ expect(subject.max_rows).to eq(2)
114
+ end
115
+
116
+ it "must return self" do
117
+ expect(subject << row).to be(subject)
118
+ end
119
+
120
+ context "when the row does contain any multi-line Strings" do
121
+ let(:row1) { %w[foo bar] }
122
+ let(:row2) { ["foo", "bar\nbaz"] }
123
+
124
+ it "must increase #height by the line height of the new row" do
125
+ expect(subject.height).to eq(0)
126
+
127
+ subject << row1
128
+ expect(subject.height).to eq(subject.rows.first.height)
129
+
130
+ subject << row2
131
+ expect(subject.height).to eq(
132
+ subject.rows[0].height + subject.rows[1].height
133
+ )
134
+ end
135
+ end
136
+
137
+ context "when the row does not contain any multi-line Strings" do
138
+ let(:row1) { %w[foo bar] }
139
+ let(:row2) { %w[baz qux] }
140
+
141
+ it "must increase #height by 1" do
142
+ expect(subject.height).to eq(0)
143
+
144
+ subject << row1
145
+ expect(subject.height).to eq(1)
146
+
147
+ subject << row2
148
+ expect(subject.height).to eq(2)
149
+ end
150
+ end
151
+
152
+ context "when the row contains more characters than the current #width" do
153
+ let(:row1) { %w[foo bar] }
154
+ let(:row2) { %w[foo barAAAAAAAA] }
155
+
156
+ it "must update #width to the new row's width" do
157
+ expect(subject.width).to eq(0)
158
+
159
+ subject << row1
160
+ expect(subject.width).to eq(subject.rows[0].width)
161
+
162
+ subject << row2
163
+ expect(subject.width).to eq(subject.rows[1].width)
164
+ end
165
+ end
166
+
167
+ context "when the row does not contains more characters than #width" do
168
+ let(:row1) { %w[foo bar] }
169
+ let(:row2) { %w[foo bar] }
170
+
171
+ it "must not update #width" do
172
+ expect(subject.width).to eq(0)
173
+
174
+ subject << row1
175
+ expect(subject.width).to eq(subject.rows[0].width)
176
+
177
+ subject << row2
178
+ expect(subject.width).to eq(subject.rows[0].width)
179
+ end
180
+ end
181
+
182
+ context "when the row contains more columns than the current #max_columns" do
183
+ let(:row1) { %w[foo bar] }
184
+ let(:row2) { %w[foo bar qux] }
185
+
186
+ it "must update #max_columns to the new row's #columns" do
187
+ expect(subject.max_columns).to eq(0)
188
+
189
+ subject << row1
190
+ expect(subject.max_columns).to eq(subject.rows[0].columns)
191
+
192
+ subject << row2
193
+ expect(subject.max_columns).to eq(subject.rows[1].columns)
194
+ end
195
+ end
196
+
197
+ context "when the row does not contain more columns than the current #max_columns" do
198
+ let(:row1) { %w[foo bar] }
199
+ let(:row2) { %w[foo bar] }
200
+
201
+ it "must not update #max_columns" do
202
+ expect(subject.max_columns).to eq(0)
203
+
204
+ subject << row1
205
+ expect(subject.max_columns).to eq(subject.rows[0].columns)
206
+
207
+ subject << row2
208
+ expect(subject.max_columns).to eq(subject.rows[0].columns)
209
+ end
210
+ end
211
+ end
212
+
213
+ describe "#[]" do
214
+ context "when the row index is within the bounds of #rows" do
215
+ before do
216
+ subject << %w[foo bar]
217
+ subject << %w[baz qux]
218
+ end
219
+
220
+ it "must return the row at the given index" do
221
+ expect(subject[1]).to be(subject.rows[1])
222
+ end
223
+ end
224
+
225
+ context "when the row index is not within the bounds of #rows" do
226
+ it "must return nil" do
227
+ expect(subject[2]).to be(nil)
228
+ end
229
+ end
230
+ end
231
+
232
+ describe "#each" do
233
+ before do
234
+ subject << %w[foo bar]
235
+ subject << %w[baz qux]
236
+ end
237
+
238
+ context "when given a block" do
239
+ it "must yield each row in #rows" do
240
+ expect { |b|
241
+ subject.each(&b)
242
+ }.to yield_successive_args(*subject.rows)
243
+ end
244
+ end
245
+
246
+ context "when no block is given" do
247
+ it "must return an Enumerator for #rows" do
248
+ expect(subject.each.to_a).to eq(subject.rows)
249
+ end
250
+ end
251
+ end
252
+ end