command_kit 0.2.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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