vedeu 0.1.3 → 0.1.4

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 (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