vedeu 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Guardfile +5 -0
  3. data/README.md +34 -0
  4. data/deps.md +13 -13
  5. data/lib/vedeu.rb +1 -1
  6. data/lib/vedeu/instrumentation.rb +1 -1
  7. data/lib/vedeu/models/geometry.rb +76 -0
  8. data/lib/vedeu/models/interface.rb +9 -21
  9. data/lib/vedeu/models/stream.rb +16 -4
  10. data/lib/vedeu/output/clear_interface.rb +4 -4
  11. data/lib/vedeu/{support/translator.rb → output/colour_translator.rb} +1 -1
  12. data/lib/vedeu/output/erb_parser.rb +11 -0
  13. data/lib/vedeu/output/raw_parser.rb +9 -1
  14. data/lib/vedeu/output/render_interface.rb +3 -3
  15. data/lib/vedeu/support/esc.rb +8 -6
  16. data/lib/vedeu/support/helpers.rb +39 -18
  17. data/lib/vedeu/support/interface_template.rb +42 -19
  18. data/test/lib/vedeu/models/composition_test.rb +27 -21
  19. data/test/lib/vedeu/models/geometry_test.rb +183 -0
  20. data/test/lib/vedeu/models/interface_test.rb +26 -59
  21. data/test/lib/vedeu/models/stream_test.rb +57 -7
  22. data/test/lib/vedeu/output/clear_interface_test.rb +8 -4
  23. data/test/lib/vedeu/{support/translator_test.rb → output/colour_translator_test.rb} +8 -8
  24. data/test/lib/vedeu/output/erb_parser_test.rb +158 -70
  25. data/test/lib/vedeu/output/render_interface_test.rb +4 -3
  26. data/test/lib/vedeu/support/esc_test.rb +10 -2
  27. data/test/lib/vedeu/support/helpers_test.rb +11 -4
  28. data/test/lib/vedeu/support/interface_template_test.rb +58 -34
  29. data/test/support/colours.rb +2 -2
  30. data/test/support/erb/line.erb +4 -0
  31. data/test/support/erb/line_2x.erb +10 -0
  32. data/test/support/erb/line_foreground.erb +4 -0
  33. data/test/support/erb/line_foreground_2x.erb +5 -0
  34. data/vedeu.gemspec +2 -1
  35. metadata +30 -8
  36. data/lib/vedeu/support/geometry.rb +0 -172
  37. data/test/lib/vedeu/support/geometry_test.rb +0 -408
@@ -1,3 +1,4 @@
1
+ require 'pry'
1
2
  require 'vedeu/support/esc'
2
3
  require 'vedeu/models/colour'
3
4
 
@@ -5,41 +6,61 @@ require 'vedeu/models/colour'
5
6
 
6
7
  module Vedeu
7
8
  module Helpers
9
+ def line(&block)
10
+ output = capture(&block)
11
+ ERB.new(output.gsub(/\n/, ''), nil, '-').result(block.binding)
12
+ end
13
+
8
14
  def foreground(value, &block)
9
- @output = ''
10
- @output << Esc.foreground_colour(value)
11
- @output << block.call if block_given?
12
- @output
15
+ output = Esc.foreground_colour(value)
16
+
17
+ if block_given?
18
+ output << block.call
19
+ output << Esc.string('fg_reset')
20
+ end
21
+
22
+ output
13
23
  end
14
24
  alias_method :fg, :foreground
15
25
 
16
26
  def background(value, &block)
17
- @output = ''
18
- @output << Esc.background_colour(value)
19
- @output << block.call if block_given?
20
- @output
27
+ output = Esc.background_colour(value)
28
+
29
+ if block_given?
30
+ output << block.call
31
+ output << Esc.string('bg_reset')
32
+ end
33
+
34
+ output
21
35
  end
22
36
  alias_method :bg, :background
23
37
 
24
38
  def colour(attributes = {}, &block)
25
- @output = ''
26
- @output << Colour.new(attributes).to_s
27
- @output << block.call if block_given?
28
- @output
39
+ output = Colour.new(attributes).to_s
40
+
41
+ if block_given?
42
+ output << block.call
43
+ output << Esc.string('colour_reset')
44
+ end
45
+
46
+ output
29
47
  end
30
48
 
31
49
  def style(*value_or_values, &block)
32
- @output = ''
33
50
  if value_or_values.one?
34
- @output << Esc.string(value_or_values.first)
35
- @output << block.call if block_given?
51
+ output = Esc.string(value_or_values.first)
36
52
  else
37
- @output << value_or_values.map do |s|
53
+ output = value_or_values.map do |s|
38
54
  Esc.string(s)
39
55
  end.join
40
- @output << block.call if block_given?
41
56
  end
42
- @output
57
+
58
+ if block_given?
59
+ output << block.call
60
+ output << Esc.string('reset')
61
+ end
62
+
63
+ output
43
64
  end
44
65
  end
45
66
  end
@@ -1,7 +1,13 @@
1
- require 'vedeu/support/geometry'
1
+ require 'vedeu/models/geometry'
2
2
  require 'vedeu/support/interface_store'
3
+ require 'vedeu/support/terminal'
3
4
 
4
5
  module Vedeu
6
+ InvalidHeight = Class.new(StandardError)
7
+ InvalidWidth = Class.new(StandardError)
8
+ XOutOfBounds = Class.new(StandardError)
9
+ YOutOfBounds = Class.new(StandardError)
10
+
5
11
  class InterfaceTemplate
6
12
  def self.save(name, &block)
7
13
  new(name).save(&block)
@@ -17,35 +23,52 @@ module Vedeu
17
23
  InterfaceStore.create(attributes)
18
24
  end
19
25
 
20
- private
26
+ def x(value)
27
+ fail XOutOfBounds if x_out_of_bounds?(value)
21
28
 
22
- attr_reader :name
29
+ attributes[:geometry][:x] = value
30
+ end
31
+
32
+ def y(value)
33
+ fail YOutOfBounds if y_out_of_bounds?(value)
23
34
 
24
- def overrides
25
- @overrides = if user_attributes[:centred] == true
26
- { x: geometry.left, y: geometry.top }
27
- else
28
- {}
29
- end
35
+ attributes[:geometry][:y] = value
30
36
  end
31
37
 
32
- def geometry
33
- @_geometry ||= Geometry.new({
34
- height: user_attributes[:height],
35
- width: user_attributes[:width],
36
- })
38
+ def width(value)
39
+ fail InvalidWidth if x_out_of_bounds?(value)
40
+
41
+ attributes[:geometry][:width] = value
37
42
  end
38
43
 
39
- def attributes
40
- user_attributes.merge!(overrides)
44
+ def height(value)
45
+ fail InvalidHeight if y_out_of_bounds?(value)
46
+
47
+ attributes[:geometry][:height] = value
41
48
  end
42
49
 
43
- def user_attributes
44
- @attributes ||= { name: name }
50
+ def centred(value)
51
+ attributes[:geometry][:centred] = value
52
+ end
53
+
54
+ private
55
+
56
+ attr_reader :name
57
+
58
+ def attributes
59
+ @attributes ||= { name: name, geometry: {} }
45
60
  end
46
61
 
47
62
  def method_missing(method_name, arg, &block)
48
- user_attributes[method_name] = arg
63
+ attributes[method_name] = arg
64
+ end
65
+
66
+ def y_out_of_bounds?(value)
67
+ value < 1 || value > Terminal.height
68
+ end
69
+
70
+ def x_out_of_bounds?(value)
71
+ value < 1 || value > Terminal.width
49
72
  end
50
73
  end
51
74
  end
@@ -10,8 +10,10 @@ module Vedeu
10
10
  interfaces: [
11
11
  {
12
12
  name: 'Composition.enqueue_1',
13
- width: 35,
14
- height: 5,
13
+ geometry: {
14
+ width: 35,
15
+ height: 5,
16
+ },
15
17
  lines: {
16
18
  streams: {
17
19
  text: 'bd459118e6175689e4394e242debc2ae'
@@ -19,8 +21,10 @@ module Vedeu
19
21
  }
20
22
  }, {
21
23
  name: 'Composition.enqueue_2',
22
- width: 35,
23
- height: 5,
24
+ geometry: {
25
+ width: 35,
26
+ height: 5,
27
+ },
24
28
  lines: {
25
29
  streams: {
26
30
  text: '837acb2cb2ea3ef359257851142a7830'
@@ -45,8 +49,10 @@ module Vedeu
45
49
  Composition.new({
46
50
  interfaces: {
47
51
  name: 'dummy',
48
- width: 5,
49
- height: 5
52
+ geometry: {
53
+ width: 5,
54
+ height: 5
55
+ }
50
56
  }
51
57
  }).interfaces.first.must_be_instance_of(Interface)
52
58
  end
@@ -58,7 +64,7 @@ module Vedeu
58
64
 
59
65
  describe '#to_s' do
60
66
  it 'returns the stringified content for a single interface, single line, single stream' do
61
- InterfaceStore.create({ name: 'int1_lin1_str1', y: 3, x: 3, width: 15, height: 3 })
67
+ InterfaceStore.create({ name: 'int1_lin1_str1', geometry: { y: 3, x: 3, width: 15, height: 3 } })
62
68
  json = File.read('test/support/json/int1_lin1_str1.json')
63
69
  attributes = JSON.load(json, nil, symbolize_names: true)
64
70
 
@@ -71,7 +77,7 @@ module Vedeu
71
77
  end
72
78
 
73
79
  it 'returns the stringified content for a single interface, single line, multiple streams' do
74
- InterfaceStore.create({ name: 'int1_lin1_str3', y: 3, x: 3, width: 30, height: 3 })
80
+ InterfaceStore.create({ name: 'int1_lin1_str3', geometry: { y: 3, x: 3, width: 30, height: 3 } })
75
81
  json = File.read('test/support/json/int1_lin1_str3.json')
76
82
  attributes = JSON.load(json, nil, symbolize_names: true)
77
83
 
@@ -84,7 +90,7 @@ module Vedeu
84
90
  end
85
91
 
86
92
  it 'returns the stringified content for a single interface, multiple lines, single stream' do
87
- InterfaceStore.create({ name: 'int1_lin2_str1', y: 3, x: 3, width: 15, height: 3 })
93
+ InterfaceStore.create({ name: 'int1_lin2_str1', geometry: { y: 3, x: 3, width: 15, height: 3 } })
88
94
  json = File.read('test/support/json/int1_lin2_str1.json')
89
95
  attributes = JSON.load(json, nil, symbolize_names: true)
90
96
 
@@ -98,7 +104,7 @@ module Vedeu
98
104
  end
99
105
 
100
106
  it 'returns the stringified content for a single interface, multiple lines, multiple streams' do
101
- InterfaceStore.create({ name: 'int1_lin2_str3', y: 3, x: 3, width: 30, height: 3 })
107
+ InterfaceStore.create({ name: 'int1_lin2_str3', geometry: { y: 3, x: 3, width: 30, height: 3 } })
102
108
  json = File.read('test/support/json/int1_lin2_str3.json')
103
109
  attributes = JSON.load(json, nil, symbolize_names: true)
104
110
 
@@ -114,7 +120,7 @@ module Vedeu
114
120
  it 'returns the stringified content for a single interface, multiple lines, multiple streams, streams contain styles' do
115
121
  json = File.read('test/support/json/int1_lin2_str3_styles.json')
116
122
  attributes = JSON.load(json, nil, symbolize_names: true)
117
- InterfaceStore.create({ name: 'int1_lin2_str3_styles', y: 3, x: 3, width: 30, height: 3 })
123
+ InterfaceStore.create({ name: 'int1_lin2_str3_styles', geometry: { y: 3, x: 3, width: 30, height: 3 } })
118
124
 
119
125
  Composition.new(attributes).to_s.must_equal(
120
126
  "\e[3;3H \e[3;3H" \
@@ -125,8 +131,8 @@ module Vedeu
125
131
  end
126
132
 
127
133
  it 'returns the stringified content for multiple interfaces, single line, single stream' do
128
- InterfaceStore.create({ name: 'int2_lin1_str1_1', y: 3, x: 3, width: 15, height: 3 })
129
- InterfaceStore.create({ name: 'int2_lin1_str1_2', y: 6, x: 6, width: 15, height: 3 })
134
+ InterfaceStore.create({ name: 'int2_lin1_str1_1', geometry: { y: 3, x: 3, width: 15, height: 3 } })
135
+ InterfaceStore.create({ name: 'int2_lin1_str1_2', geometry: { y: 6, x: 6, width: 15, height: 3 } })
130
136
  json = File.read('test/support/json/int2_lin1_str1.json')
131
137
  attributes = JSON.load(json, nil, symbolize_names: true)
132
138
 
@@ -143,8 +149,8 @@ module Vedeu
143
149
  end
144
150
 
145
151
  it 'returns the stringified content for multiple interfaces, single line, multiple streams' do
146
- InterfaceStore.create({ name: 'int2_lin1_str3_1', y: 3, x: 3, width: 30, height: 3 })
147
- InterfaceStore.create({ name: 'int2_lin1_str3_2', y: 6, x: 6, width: 30, height: 3 })
152
+ InterfaceStore.create({ name: 'int2_lin1_str3_1', geometry: { y: 3, x: 3, width: 30, height: 3 } })
153
+ InterfaceStore.create({ name: 'int2_lin1_str3_2', geometry: { y: 6, x: 6, width: 30, height: 3 } })
148
154
  json = File.read('test/support/json/int2_lin1_str3.json')
149
155
  attributes = JSON.load(json, nil, symbolize_names: true)
150
156
 
@@ -161,8 +167,8 @@ module Vedeu
161
167
  end
162
168
 
163
169
  it 'returns the stringified content for multiple interfaces, multiple lines, single stream' do
164
- InterfaceStore.create({ name: 'int2_lin2_str1_1', y: 3, x: 3, width: 15, height: 3 })
165
- InterfaceStore.create({ name: 'int2_lin2_str1_2', y: 6, x: 6, width: 15, height: 3 })
170
+ InterfaceStore.create({ name: 'int2_lin2_str1_1', geometry: { y: 3, x: 3, width: 15, height: 3 } })
171
+ InterfaceStore.create({ name: 'int2_lin2_str1_2', geometry: { y: 6, x: 6, width: 15, height: 3 } })
166
172
  json = File.read('test/support/json/int2_lin2_str1.json')
167
173
  attributes = JSON.load(json, nil, symbolize_names: true)
168
174
 
@@ -181,8 +187,8 @@ module Vedeu
181
187
  end
182
188
 
183
189
  it 'returns the stringified content for multiple interfaces, multiple lines, multiple streams' do
184
- InterfaceStore.create({ name: 'int2_lin2_str3_1', y: 3, x: 3, width: 30, height: 3 })
185
- InterfaceStore.create({ name: 'int2_lin2_str3_2', y: 6, x: 6, width: 30, height: 3 })
190
+ InterfaceStore.create({ name: 'int2_lin2_str3_1', geometry: { y: 3, x: 3, width: 30, height: 3 } })
191
+ InterfaceStore.create({ name: 'int2_lin2_str3_2', geometry: { y: 6, x: 6, width: 30, height: 3 } })
186
192
  json = File.read('test/support/json/int2_lin2_str3.json')
187
193
  attributes = JSON.load(json, nil, symbolize_names: true)
188
194
 
@@ -201,8 +207,8 @@ module Vedeu
201
207
  end
202
208
 
203
209
  it 'returns the stringified content for multiple interfaces, multiple lines, multiple streams, streams contain styles' do
204
- InterfaceStore.create({ name: 'int2_lin2_str3_styles_1', y: 3, x: 3, width: 30, height: 3 })
205
- InterfaceStore.create({ name: 'int2_lin2_str3_styles_2', y: 6, x: 6, width: 30, height: 3 })
210
+ InterfaceStore.create({ name: 'int2_lin2_str3_styles_1', geometry: { y: 3, x: 3, width: 30, height: 3 } })
211
+ InterfaceStore.create({ name: 'int2_lin2_str3_styles_2', geometry: { y: 6, x: 6, width: 30, height: 3 } })
206
212
  json = File.read('test/support/json/int2_lin2_str3_styles.json')
207
213
  attributes = JSON.load(json, nil, symbolize_names: true)
208
214
 
@@ -0,0 +1,183 @@
1
+ require 'test_helper'
2
+ require 'vedeu/models/geometry'
3
+
4
+ module Vedeu
5
+ describe Geometry do
6
+ describe '#origin' do
7
+ it 'returns the origin for the interface' do
8
+ geometry = Geometry.new({ width: 5, height: 5 })
9
+ geometry.origin.must_equal("\e[1;1H")
10
+ end
11
+
12
+ it 'returns the origin for the interface' do
13
+ console = IO.console
14
+ console.stub :winsize, [25, 80] do
15
+ geometry = Geometry.new({ width: 5, height: 5, centred: true })
16
+ geometry.origin.must_equal("\e[10;38H")
17
+ end
18
+ end
19
+
20
+ it 'returns the line position relative to the origin' do
21
+ geometry = Geometry.new({ width: 5, height: 5 })
22
+ geometry.origin(3).must_equal("\e[4;1H")
23
+ end
24
+
25
+ it 'returns the origin for the interface when the interface' \
26
+ ' is at a custom position' do
27
+ geometry = Geometry.new({ width: 5, height: 5, x: 3, y: 6 })
28
+ geometry.origin.must_equal("\e[6;3H")
29
+ end
30
+
31
+ it 'returns the line position relative to the origin when the' \
32
+ ' interface is at a custom position' do
33
+ geometry = Geometry.new({ width: 5, height: 5, x: 3, y: 6 })
34
+ geometry.origin(3).must_equal("\e[9;3H")
35
+ end
36
+ end
37
+
38
+ describe '#top' do
39
+ it 'centred is true' do
40
+ console = IO.console
41
+ console.stub :winsize, [12, 80] do
42
+ geometry = Geometry.new({ height: 6, width: 18, centred: true })
43
+ geometry.top.must_equal(3)
44
+ end
45
+ end
46
+
47
+ it 'centred is false' do
48
+ geometry = Geometry.new({ height: 6, width: 18 })
49
+ geometry.top.must_equal(1)
50
+ end
51
+
52
+ it 'centred is false and y is set' do
53
+ geometry = Geometry.new({ height: 6, width: 18, y: 4 })
54
+ geometry.top.must_equal(4)
55
+ end
56
+ end
57
+
58
+ describe '#left' do
59
+ it 'centred is true' do
60
+ console = IO.console
61
+ console.stub :winsize, [25, 40] do
62
+ geometry = Geometry.new({ height: 6, width: 18, centred: true })
63
+ geometry.left.must_equal(11)
64
+ end
65
+ end
66
+
67
+ it 'centred is false' do
68
+ geometry = Geometry.new({ height: 6, width: 18 })
69
+ geometry.left.must_equal(1)
70
+ end
71
+
72
+ it 'centred is false and x is set' do
73
+ geometry = Geometry.new({ height: 6, width: 18, x: 5 })
74
+ geometry.left.must_equal(5)
75
+ end
76
+ end
77
+
78
+ describe '#bottom' do
79
+ it 'centred is true' do
80
+ console = IO.console
81
+ console.stub :winsize, [20, 40] do
82
+ geometry = Geometry.new({ height: 6, width: 18, centred: true })
83
+ geometry.bottom.must_equal(13)
84
+ end
85
+ end
86
+
87
+ it 'centred is false' do
88
+ geometry = Geometry.new({ height: 6, width: 18 })
89
+ geometry.bottom.must_equal(7)
90
+ end
91
+
92
+ it 'centred is false and y is set' do
93
+ geometry = Geometry.new({ height: 6, width: 18, y: 5 })
94
+ geometry.bottom.must_equal(11)
95
+ end
96
+ end
97
+
98
+ describe '#right' do
99
+ it 'centred is true' do
100
+ console = IO.console
101
+ console.stub :winsize, [25, 40] do
102
+ geometry = Geometry.new({ height: 6, width: 18, centred: true })
103
+ geometry.right.must_equal(29)
104
+ end
105
+ end
106
+
107
+ it 'centred is false' do
108
+ geometry = Geometry.new({ height: 6, width: 18 })
109
+ geometry.right.must_equal(19)
110
+ end
111
+
112
+ it 'centred is false and x is set' do
113
+ geometry = Geometry.new({ height: 6, width: 18, x: 5 })
114
+ geometry.right.must_equal(23)
115
+ end
116
+ end
117
+
118
+ describe '#position' do
119
+ it 'centred is true' do
120
+ console = IO.console
121
+ console.stub :winsize, [25, 80] do
122
+ geometry = Geometry.new({ height: 6, width: 18, centred: true })
123
+ geometry.position.must_equal({
124
+ y: 9,
125
+ x: 31,
126
+ height: 6,
127
+ width: 18,
128
+ centred: true,
129
+ top: 9,
130
+ bottom: 15,
131
+ left: 31,
132
+ right: 49,
133
+ })
134
+ end
135
+ end
136
+
137
+ it 'centred is false and x is set' do
138
+ geometry = Geometry.new({ height: 6, width: 18, x: 7 })
139
+ geometry.position.must_equal({
140
+ y: 1,
141
+ x: 7,
142
+ height: 6,
143
+ width: 18,
144
+ centred: false,
145
+ top: 1,
146
+ bottom: 7,
147
+ left: 7,
148
+ right: 25,
149
+ })
150
+ end
151
+
152
+ it 'centred is false and y is set' do
153
+ geometry = Geometry.new({ height: 6, width: 18, y: 5 })
154
+ geometry.position.must_equal({
155
+ y: 5,
156
+ x: 1,
157
+ height: 6,
158
+ width: 18,
159
+ centred: false,
160
+ top: 5,
161
+ bottom: 11,
162
+ left: 1,
163
+ right: 19,
164
+ })
165
+ end
166
+
167
+ it 'centred is false' do
168
+ geometry = Geometry.new({ height: 6, width: 18 })
169
+ geometry.position.must_equal({
170
+ y: 1,
171
+ x: 1,
172
+ height: 6,
173
+ width: 18,
174
+ centred: false,
175
+ top: 1,
176
+ bottom: 7,
177
+ left: 1,
178
+ right: 19,
179
+ })
180
+ end
181
+ end
182
+ end
183
+ end