vedeu 0.0.31 → 0.0.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -4
  3. data/lib/vedeu.rb +1 -0
  4. data/lib/vedeu/models/collection.rb +17 -0
  5. data/lib/vedeu/models/colour.rb +27 -5
  6. data/lib/vedeu/models/line_collection.rb +4 -9
  7. data/lib/vedeu/models/stream.rb +1 -1
  8. data/lib/vedeu/models/stream_collection.rb +4 -9
  9. data/lib/vedeu/support/coordinate.rb +149 -0
  10. data/lib/vedeu/support/esc.rb +4 -0
  11. data/lib/vedeu/support/menu.rb +103 -0
  12. data/lib/vedeu/support/terminal.rb +4 -0
  13. data/test/example_app/lib/app.rb +25 -6
  14. data/test/lib/vedeu/models/collection_test.rb +50 -0
  15. data/test/lib/vedeu/models/colour_test.rb +58 -1
  16. data/test/lib/vedeu/models/command_test.rb +2 -1
  17. data/test/lib/vedeu/models/interface_collection_test.rb +4 -3
  18. data/test/lib/vedeu/models/line_test.rb +3 -1
  19. data/test/lib/vedeu/models/stream_test.rb +6 -3
  20. data/test/lib/vedeu/output/text_adaptor_test.rb +1 -1
  21. data/test/lib/vedeu/repository/command_repository_test.rb +2 -1
  22. data/test/lib/vedeu/repository/interface_repository_test.rb +2 -1
  23. data/test/lib/vedeu/repository/repository_test.rb +2 -1
  24. data/test/lib/vedeu/repository/storage_test.rb +6 -3
  25. data/test/lib/vedeu/support/coordinate_test.rb +363 -0
  26. data/test/lib/vedeu/support/esc_test.rb +8 -0
  27. data/test/lib/vedeu/support/menu_test.rb +202 -0
  28. data/test/lib/vedeu/support/parser_test.rb +2 -1
  29. data/test/lib/vedeu/support/parsing/hash_parser_test.rb +6 -3
  30. data/test/lib/vedeu/support/parsing/json_parser_test.rb +2 -1
  31. data/test/lib/vedeu/support/terminal_test.rb +9 -0
  32. data/test/lib/vedeu/support/translator_test.rb +2 -1
  33. data/test/test_helper.rb +12 -0
  34. data/vedeu.gemspec +1 -1
  35. metadata +11 -8
  36. data/lib/vedeu/models/background.rb +0 -13
  37. data/lib/vedeu/models/foreground.rb +0 -13
  38. data/test/lib/vedeu/models/background_test.rb +0 -19
  39. data/test/lib/vedeu/models/foreground_test.rb +0 -18
@@ -31,6 +31,10 @@ module Vedeu
31
31
  stream
32
32
  end
33
33
 
34
+ def centre
35
+ [(height / 2), (width / 2)]
36
+ end
37
+
34
38
  def width
35
39
  size.last
36
40
  end
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
+ require 'pry'
3
4
  require 'vedeu'
4
5
 
5
6
  module Example
@@ -35,16 +36,34 @@ module Example
35
36
  class App
36
37
  include Vedeu
37
38
 
39
+ def self.example_position
40
+ @_position = Vedeu::Coordinate.new({ width: 40, height: 5, centered: true }).position
41
+ end
42
+
43
+ def self.command_position
44
+ {
45
+ y: example_position[:bottom],
46
+ x: example_position[:x],
47
+ height: 1,
48
+ width: 40,
49
+ centered: true
50
+ }
51
+ end
52
+
38
53
  interface 'example', {
39
- y: 1, x: 1, width: 80, height: 5,
40
- colour: { background: '#ff0000', foreground: '#000000' },
54
+ colour: {
55
+ background: '#ff0000',
56
+ foreground: '#000000'
57
+ },
41
58
  cursor: false
42
- }
59
+ }.merge(example_position)
43
60
  interface 'command', {
44
- y: 6, x: 1, width: 80, height: 1,
45
- colour: { background: '#4040cc', foreground: '#aadd00' },
61
+ colour: {
62
+ background: '#4040cc',
63
+ foreground: '#aadd00'
64
+ },
46
65
  cursor: true
47
- }
66
+ }.merge(command_position)
48
67
  command 'time', {
49
68
  entity: ExampleCommand,
50
69
  keyword: 'time',
@@ -0,0 +1,50 @@
1
+ require_relative '../../../test_helper'
2
+ require_relative '../../../../lib/vedeu/models/collection'
3
+
4
+ module Vedeu
5
+ class TestClass
6
+ include Collection
7
+
8
+ def initialize(*args); end
9
+ end
10
+
11
+ describe Collection do
12
+ describe '#coercer' do
13
+ it 'returns an empty collection when nil or empty' do
14
+ Collection.coercer(nil, TestClass, :key).must_equal([])
15
+ end
16
+
17
+ it 'returns an empty collection when nil or empty' do
18
+ Collection.coercer('', TestClass, :key).must_equal([])
19
+ end
20
+
21
+ it 'returns an empty collection when nil or empty' do
22
+ Collection.coercer([], TestClass, :key).must_equal([])
23
+ end
24
+
25
+ it 'returns an empty collection when nil or empty' do
26
+ Collection.coercer({}, TestClass, :key).must_equal([])
27
+ end
28
+
29
+ it 'returns a single model in a collection when a String' do
30
+ Collection.coercer('test', TestClass, :key).size.must_equal(1)
31
+ end
32
+
33
+ it 'returns a collection of models when a single hash' do
34
+ Collection.coercer({ :test1 => 'test1' }, TestClass, :key)
35
+ .size.must_equal(1)
36
+ end
37
+
38
+ it 'returns a collection of models when multiple hashes' do
39
+ Collection.coercer([
40
+ { :test1 => 'test1' }, { :test2 => 'test2' }
41
+ ], TestClass, :key).size.must_equal(2)
42
+ end
43
+
44
+ it 'returns a collection of models when a single array' do
45
+ Collection.coercer([{ :test3 => 'test3' }], TestClass, :key)
46
+ .size.must_equal(1)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -3,12 +3,60 @@ require_relative '../../../../lib/vedeu/models/colour'
3
3
 
4
4
  module Vedeu
5
5
  describe Colour do
6
+ describe '#background' do
7
+ it 'returns an escape sequence' do
8
+ Colour.new({
9
+ background: '#000000'
10
+ }).background.must_equal("\e[48;5;16m")
11
+ end
12
+
13
+ it 'returns an empty string if the value is empty' do
14
+ Colour.new.background.must_equal('')
15
+ end
16
+ end
17
+
18
+ describe '#foreground' do
19
+ it 'returns an escape sequence' do
20
+ Colour.new({
21
+ foreground: '#ff0000'
22
+ }).foreground.must_equal("\e[38;5;196m")
23
+ end
24
+
25
+ it 'returns an empty string if the value is empty' do
26
+ Colour.new.foreground.must_equal('')
27
+ end
28
+ end
29
+
30
+ describe '#css_background' do
31
+ it 'returns an escape sequence' do
32
+ Colour.new({
33
+ background: '#000000'
34
+ }).css_background.must_equal('#000000')
35
+ end
36
+
37
+ it 'returns an empty string if the value is nil' do
38
+ Colour.new.css_background.must_equal('')
39
+ end
40
+ end
41
+
42
+ describe '#css_foreground' do
43
+ it 'returns an escape sequence' do
44
+ Colour.new({
45
+ foreground: '#ff0000'
46
+ }).css_foreground.must_equal('#ff0000')
47
+ end
48
+
49
+ it 'returns an empty string if the value is nil' do
50
+ Colour.new.css_foreground.must_equal('')
51
+ end
52
+ end
53
+
6
54
  describe '#to_json' do
7
55
  it 'returns the model as JSON' do
8
56
  Colour.new({
9
57
  foreground: '#ff0000',
10
58
  background: '#000000'
11
- }).to_json.must_equal("{\"foreground\":\"\\u001b[38;5;196m\",\"background\":\"\\u001b[48;5;16m\"}")
59
+ }).to_json.must_equal("{\"foreground\":\"#ff0000\",\"background\":\"#000000\"}")
12
60
  end
13
61
  end
14
62
 
@@ -36,5 +84,14 @@ module Vedeu
36
84
  Colour.new.to_s.must_equal('')
37
85
  end
38
86
  end
87
+
88
+ describe '#as_hash' do
89
+ it 'returns the model as a Hash' do
90
+ Colour.new({
91
+ foreground: '#ff0000',
92
+ background: '#000000'
93
+ }).as_hash.must_equal({ foreground: '#ff0000', background: '#000000' })
94
+ end
95
+ end
39
96
  end
40
97
  end
@@ -9,7 +9,8 @@ module Vedeu
9
9
  end
10
10
 
11
11
  it 'has an entity attribute' do
12
- Command.new({ entity: DummyCommand }).entity.must_equal(DummyCommand)
12
+ Command.new({ entity: DummyCommand }).entity
13
+ .must_equal(DummyCommand)
13
14
  end
14
15
 
15
16
  it 'has a keypress attribute' do
@@ -13,12 +13,13 @@ module Vedeu
13
13
  Composition.new.interfaces.must_equal([])
14
14
  end
15
15
 
16
- it 'returns a collection of Interface objects when there is a single interface' do
16
+ it 'returns a collection when there is a single interface' do
17
17
  skip
18
- Composition.new({ name: 'dummy' }).interfaces.first.must_be_instance_of(Interface)
18
+ Composition.new({ name: 'dummy' }).interfaces.first
19
+ .must_be_instance_of(Interface)
19
20
  end
20
21
 
21
- it 'returns a collection of Interface objects when there are multiple interfaces' do
22
+ it 'returns a collection when there are multiple interfaces' do
22
23
  Composition.new({ interfaces: [
23
24
  { name: 'dumb' },
24
25
  { name: 'dumber' }
@@ -8,7 +8,9 @@ module Vedeu
8
8
  end
9
9
 
10
10
  it 'has a colour attribute' do
11
- Line.new(colour: { foreground: '#ff0000', background: '#000000' }).colour.must_be_instance_of(Colour)
11
+ Line.new({
12
+ colour: { foreground: '#ff0000', background: '#000000' }
13
+ }).colour.must_be_instance_of(Colour)
12
14
  end
13
15
 
14
16
  it 'has a model attribute' do
@@ -4,7 +4,9 @@ require_relative '../../../../lib/vedeu/models/stream'
4
4
  module Vedeu
5
5
  describe Stream do
6
6
  it 'has a colour attribute' do
7
- Stream.new({ colour: { foreground: '#ff0000', background: '#000000' } }).colour.must_be_instance_of(Colour)
7
+ Stream.new({
8
+ colour: { foreground: '#ff0000', background: '#000000' }
9
+ }).colour.must_be_instance_of(Colour)
8
10
  end
9
11
 
10
12
  it 'has a text attribute' do
@@ -12,7 +14,8 @@ module Vedeu
12
14
  end
13
15
 
14
16
  it 'has a style attribute' do
15
- Stream.new({ style: 'normal' }).style.must_equal("\e[24m\e[21m\e[27m")
17
+ Stream.new({ style: 'normal' }).style
18
+ .must_equal("\e[24m\e[21m\e[27m")
16
19
  end
17
20
 
18
21
  describe '#to_s' do
@@ -31,7 +34,7 @@ module Vedeu
31
34
  style: 'normal',
32
35
  colour: { foreground: '#ff0000', background: '#000000' },
33
36
  text: 'Some text'
34
- }).to_json.must_equal("{\"colour\":{\"foreground\":\"\\u001b[38;5;196m\",\"background\":\"\\u001b[48;5;16m\"},\"style\":\"\\u001b[24m\\u001b[21m\\u001b[27m\",\"text\":\"Some text\"}")
37
+ }).to_json.must_equal("{\"colour\":{\"foreground\":\"#ff0000\",\"background\":\"#000000\"},\"style\":\"\\u001b[24m\\u001b[21m\\u001b[27m\",\"text\":\"Some text\"}")
35
38
  end
36
39
  end
37
40
  end
@@ -4,7 +4,7 @@ require_relative '../../../../lib/vedeu/output/text_adaptor'
4
4
  module Vedeu
5
5
  describe TextAdaptor do
6
6
  describe '.adapt' do
7
- it 'returns an empty collection when processing an empty string' do
7
+ it 'returns an empty collection for an empty string' do
8
8
  TextAdaptor.adapt('').must_be_empty
9
9
  end
10
10
 
@@ -34,7 +34,8 @@ module Vedeu
34
34
  end
35
35
 
36
36
  it 'returns FalseClass when no command was found' do
37
- CommandRepository.by_input('not_found').must_be_instance_of(FalseClass)
37
+ CommandRepository.by_input('not_found')
38
+ .must_be_instance_of(FalseClass)
38
39
  end
39
40
 
40
41
  it 'returns FalseClass when there is no input' do
@@ -20,7 +20,8 @@ module Vedeu
20
20
  width: 15,
21
21
  height: 2
22
22
  })
23
- InterfaceRepository.find('dummy').must_be_instance_of(Interface)
23
+ InterfaceRepository.find('dummy')
24
+ .must_be_instance_of(Interface)
24
25
  end
25
26
 
26
27
  it 'raises an exception when the interface does not exist' do
@@ -39,7 +39,8 @@ module Vedeu
39
39
  describe '#query' do
40
40
  it 'returns a Dummy' do
41
41
  dummy = DummyRepository.create(Dummy.new)
42
- DummyRepository.query(Dummy, :name, 'dummy').must_be_instance_of(Dummy)
42
+ DummyRepository.query(Dummy, :name, 'dummy')
43
+ .must_be_instance_of(Dummy)
43
44
  end
44
45
  end
45
46
 
@@ -6,13 +6,15 @@ module Vedeu
6
6
  describe Storage do
7
7
  describe '#create' do
8
8
  it 'returns the stored record' do
9
- Storage.new.create(DummyCommand.new).must_be_instance_of(DummyCommand)
9
+ Storage.new.create(DummyCommand.new)
10
+ .must_be_instance_of(DummyCommand)
10
11
  end
11
12
  end
12
13
 
13
14
  describe '#delete' do
14
15
  it 'returns a NilClass' do
15
- Storage.new.delete(DummyCommand.new).must_be_instance_of(NilClass)
16
+ Storage.new.delete(DummyCommand.new)
17
+ .must_be_instance_of(NilClass)
16
18
  end
17
19
  end
18
20
 
@@ -36,7 +38,8 @@ module Vedeu
36
38
 
37
39
  describe '#query' do
38
40
  it 'returns a FalseClass when the item cannot be found' do
39
- Storage.new.query(nil, nil, nil).must_be_instance_of(FalseClass)
41
+ Storage.new.query(nil, nil, nil)
42
+ .must_be_instance_of(FalseClass)
40
43
  end
41
44
  end
42
45
  end
@@ -0,0 +1,363 @@
1
+ require_relative '../../../test_helper'
2
+ require_relative '../../../../lib/vedeu/support/coordinate'
3
+
4
+ module Vedeu
5
+ describe Coordinate do
6
+ it 'raises an exception when the height attribute is not set' do
7
+ proc { Coordinate.new({ width: 18 }) }.must_raise(KeyError)
8
+ end
9
+
10
+ it 'raises an exception when the width attribute is not set' do
11
+ proc { Coordinate.new({ height: 6 }) }.must_raise(KeyError)
12
+ end
13
+
14
+ describe '#terminal_height' do
15
+ it 'raises an exception if the value is less than 1' do
16
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_height: -2 })
17
+ proc { coordinate.terminal_height }.must_raise(OutOfBoundsError)
18
+ end
19
+
20
+ it 'raises an exception if the value is greater than the terminal height' do
21
+ console = IO.console
22
+ console.stub :winsize, [25, 80] do
23
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_height: 30 })
24
+ proc { coordinate.terminal_height }.must_raise(OutOfBoundsError)
25
+ end
26
+ end
27
+
28
+ it 'returns the value of terminal_height' do
29
+ console = IO.console
30
+ console.stub :winsize, [25, 80] do
31
+ Coordinate.new({ height: 6, width: 18, terminal_height: 20 })
32
+ .terminal_height.must_equal(20)
33
+ end
34
+ end
35
+
36
+ it 'returns the default height if not set' do
37
+ console = IO.console
38
+ console.stub :winsize, [25, 80] do
39
+ Coordinate.new({ height: 6, width: 18 })
40
+ .instance_variable_get('@terminal_height').must_equal(25)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#height' do
46
+ it 'raises an exception if the value is less than 1' do
47
+ coordinate = Coordinate.new({ height: -6, width: 18 })
48
+ proc { coordinate.height }.must_raise(OutOfBoundsError)
49
+ end
50
+
51
+ it 'raises an exception if the value is greater than the terminal height' do
52
+ console = IO.console
53
+ console.stub :winsize, [25, 80] do
54
+ coordinate = Coordinate.new({ height: 30, width: 18 })
55
+ proc { coordinate.height }.must_raise(OutOfBoundsError)
56
+ end
57
+ end
58
+
59
+ it 'returns the value of height' do
60
+ Coordinate.new({ height: 6, width: 18 }).height.must_equal(6)
61
+ end
62
+ end
63
+
64
+ describe '#y' do
65
+ it 'raises an exception if the value is less than 1' do
66
+ coordinate = Coordinate.new({ height: 6, width: 18, y: -2 })
67
+ proc { coordinate.y }.must_raise(OutOfBoundsError)
68
+ end
69
+
70
+ it 'raises an exception if the value is greater than the terminal height' do
71
+ console = IO.console
72
+ console.stub :winsize, [25, 80] do
73
+ coordinate = Coordinate.new({ height: 6, width: 18, y: 30 })
74
+ proc { coordinate.y }.must_raise(OutOfBoundsError)
75
+ end
76
+ end
77
+
78
+ it 'returns the value of y' do
79
+ Coordinate.new({ height: 6, width: 18, y: 6 }).y.must_equal(6)
80
+ end
81
+
82
+ it 'returns 1 if not set' do
83
+ Coordinate.new({ height: 6, width: 18 }).y.must_equal(1)
84
+ end
85
+ end
86
+
87
+ describe '#terminal_width' do
88
+ it 'raises an exception if the value is less than 1' do
89
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_width: -2 })
90
+ proc { coordinate.terminal_width }.must_raise(OutOfBoundsError)
91
+ end
92
+
93
+ it 'raises an exception if the value is greater than the terminal width' do
94
+ console = IO.console
95
+ console.stub :winsize, [25, 80] do
96
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_width: 85 })
97
+ proc { coordinate.terminal_width }.must_raise(OutOfBoundsError)
98
+ end
99
+ end
100
+
101
+ it 'returns the value of terminal_width' do
102
+ console = IO.console
103
+ console.stub :winsize, [25, 80] do
104
+ Coordinate.new({ height: 6, width: 18, terminal_width: 40 })
105
+ .terminal_width.must_equal(40)
106
+ end
107
+ end
108
+
109
+ it 'returns the default width if not set' do
110
+ console = IO.console
111
+ console.stub :winsize, [25, 80] do
112
+ Coordinate.new({ height: 6, width: 18 })
113
+ .terminal_width.must_equal(80)
114
+ end
115
+ end
116
+ end
117
+
118
+ describe '#width' do
119
+ it 'raises an exception if the value is less than 1' do
120
+ coordinate = Coordinate.new({ height: 6, width: -18 })
121
+ proc { coordinate.width }.must_raise(OutOfBoundsError)
122
+ end
123
+
124
+ it 'raises an exception if the value is greater than the terminal width' do
125
+ console = IO.console
126
+ console.stub :winsize, [25, 80] do
127
+ coordinate = Coordinate.new({ height: 6, width: 85 })
128
+ proc { coordinate.width }.must_raise(OutOfBoundsError)
129
+ end
130
+ end
131
+
132
+ it 'returns the value of width' do
133
+ Coordinate.new({ height: 6, width: 18, x: 6 }).width
134
+ .must_equal(18)
135
+ end
136
+ end
137
+
138
+ describe '#x' do
139
+ it 'raises an exception if the value is less than 1' do
140
+ coordinate = Coordinate.new({ height: 6, width: 18, x: -2 })
141
+ proc { coordinate.x }.must_raise(OutOfBoundsError)
142
+ end
143
+
144
+ it 'raises an exception if the value is greater than the terminal width' do
145
+ console = IO.console
146
+ console.stub :winsize, [25, 80] do
147
+ coordinate = Coordinate.new({ height: 6, width: 18, x: 85 })
148
+ proc { coordinate.x }.must_raise(OutOfBoundsError)
149
+ end
150
+ end
151
+
152
+ it 'returns the value of x' do
153
+ Coordinate.new({ height: 6, width: 18, x: 6 }).x.must_equal(6)
154
+ end
155
+
156
+ it 'returns 1 if not set' do
157
+ Coordinate.new({ height: 6, width: 18 }).x.must_equal(1)
158
+ end
159
+ end
160
+
161
+ describe '#centered' do
162
+ it 'has a centred attribute' do
163
+ Coordinate.new({ height: 6, width: 18, centred: false })
164
+ .centred.must_equal(false)
165
+ end
166
+
167
+ it 'sets the centred attribute to true if not set' do
168
+ Coordinate.new({ height: 6, width: 18 })
169
+ .centred.must_equal(true)
170
+ end
171
+ end
172
+
173
+ describe '#centre' do
174
+ it 'returns a tuple containing the default centre coordinates' do
175
+ console = IO.console
176
+ console.stub :winsize, [25, 80] do
177
+ coordinate = Coordinate.new({ height: 6, width: 18 })
178
+ coordinate.centre.must_equal([12, 40])
179
+ end
180
+ end
181
+
182
+ it 'returns a tuple containing the centre coordinates' do
183
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_height: 12, terminal_width: 40 })
184
+ coordinate.centre.must_equal([6, 20])
185
+ end
186
+
187
+ it 'returns a tuple containing the centre coordinates when an' \
188
+ ' alternative terminal height is set' do
189
+ console = IO.console
190
+ console.stub :winsize, [25, 80] do
191
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_height: 12 })
192
+ coordinate.centre.must_equal([6, 40])
193
+ end
194
+ end
195
+
196
+ it 'returns a tuple containing the centre coordinates when an' \
197
+ ' alternative terminal width is set' do
198
+ console = IO.console
199
+ console.stub :winsize, [25, 80] do
200
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_width: 40 })
201
+ coordinate.centre.must_equal([12, 20])
202
+ end
203
+ end
204
+ end
205
+
206
+ describe '#top' do
207
+ it 'centred is true and terminal height is set' do
208
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_height: 12 })
209
+ coordinate.top.must_equal(3)
210
+ end
211
+
212
+ it 'centred is true and with default terminal height' do
213
+ console = IO.console
214
+ console.stub :winsize, [25, 80] do
215
+ coordinate = Coordinate.new({ height: 6, width: 18 })
216
+ coordinate.top.must_equal(9)
217
+ end
218
+ end
219
+
220
+ it 'centred is false' do
221
+ coordinate = Coordinate.new({ height: 6, width: 18, centred: false })
222
+ coordinate.top.must_equal(1)
223
+ end
224
+
225
+ it 'centred is false and y is set' do
226
+ coordinate = Coordinate.new({ height: 6, width: 18, y: 4, centred: false })
227
+ coordinate.top.must_equal(4)
228
+ end
229
+ end
230
+
231
+ describe '#left' do
232
+ it 'centred is true and terminal width is set' do
233
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_width: 40 })
234
+ coordinate.left.must_equal(11)
235
+ end
236
+
237
+ it 'centred is true and with default terminal width' do
238
+ console = IO.console
239
+ console.stub :winsize, [25, 80] do
240
+ coordinate = Coordinate.new({ height: 6, width: 18 })
241
+ coordinate.left.must_equal(31)
242
+ end
243
+ end
244
+
245
+ it 'centred is false' do
246
+ coordinate = Coordinate.new({ height: 6, width: 18, centred: false })
247
+ coordinate.left.must_equal(1)
248
+ end
249
+
250
+ it 'centred is false and x is set' do
251
+ coordinate = Coordinate.new({ height: 6, width: 18, x: 5, centred: false })
252
+ coordinate.left.must_equal(5)
253
+ end
254
+ end
255
+
256
+ describe '#bottom' do
257
+ it 'centred is true and terminal height is set' do
258
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_height: 12 })
259
+ coordinate.bottom.must_equal(9)
260
+ end
261
+
262
+ it 'centred is true and with default terminal height' do
263
+ console = IO.console
264
+ console.stub :winsize, [25, 80] do
265
+ coordinate = Coordinate.new({ height: 6, width: 18 })
266
+ coordinate.bottom.must_equal(15)
267
+ end
268
+ end
269
+
270
+ it 'centred is false' do
271
+ coordinate = Coordinate.new({ height: 6, width: 18, centred: false })
272
+ coordinate.bottom.must_equal(7)
273
+ end
274
+
275
+ it 'centred is false and y is set' do
276
+ coordinate = Coordinate.new({ height: 6, width: 18, y: 5, centred: false })
277
+ coordinate.bottom.must_equal(11)
278
+ end
279
+ end
280
+
281
+ describe '#right' do
282
+ it 'centred is true and terminal width is set' do
283
+ coordinate = Coordinate.new({ height: 6, width: 18, terminal_width: 40 })
284
+ coordinate.right.must_equal(29)
285
+ end
286
+
287
+ it 'centred is true and with default terminal width' do
288
+ console = IO.console
289
+ console.stub :winsize, [25, 80] do
290
+ coordinate = Coordinate.new({ height: 6, width: 18 })
291
+ coordinate.right.must_equal(49)
292
+ end
293
+ end
294
+
295
+ it 'centred is false' do
296
+ coordinate = Coordinate.new({ height: 6, width: 18, centred: false })
297
+ coordinate.right.must_equal(19)
298
+ end
299
+
300
+ it 'centred is false and x is set' do
301
+ coordinate = Coordinate.new({ height: 6, width: 18, x: 5, centred: false })
302
+ coordinate.right.must_equal(23)
303
+ end
304
+ end
305
+
306
+ describe '#position' do
307
+ it 'centred is true' do
308
+ console = IO.console
309
+ console.stub :winsize, [25, 80] do
310
+ coordinate = Coordinate.new({ height: 6, width: 18 })
311
+ coordinate.position.must_equal({
312
+ y: 9,
313
+ x: 31,
314
+ height: 6,
315
+ width: 18,
316
+ centred: true,
317
+ bottom: 15,
318
+ right: 49,
319
+ })
320
+ end
321
+ end
322
+
323
+ it 'centred is false and x is set' do
324
+ coordinate = Coordinate.new({ height: 6, width: 18, x: 7, centred: false })
325
+ coordinate.position.must_equal({
326
+ y: 1,
327
+ x: 7,
328
+ height: 6,
329
+ width: 18,
330
+ centred: false,
331
+ bottom: 7,
332
+ right: 25,
333
+ })
334
+ end
335
+
336
+ it 'centred is false and y is set' do
337
+ coordinate = Coordinate.new({ height: 6, width: 18, y: 5, centred: false })
338
+ coordinate.position.must_equal({
339
+ y: 5,
340
+ x: 1,
341
+ height: 6,
342
+ width: 18,
343
+ centred: false,
344
+ bottom: 11,
345
+ right: 19,
346
+ })
347
+ end
348
+
349
+ it 'centred is false' do
350
+ coordinate = Coordinate.new({ height: 6, width: 18, centred: false })
351
+ coordinate.position.must_equal({
352
+ y: 1,
353
+ x: 1,
354
+ height: 6,
355
+ width: 18,
356
+ centred: false,
357
+ bottom: 7,
358
+ right: 19,
359
+ })
360
+ end
361
+ end
362
+ end
363
+ end