vedeu 0.2.3 → 0.2.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/docs/api.md +2 -0
  3. data/docs/events.md +0 -4
  4. data/examples/cursor_app/cursor_app.rb +56 -44
  5. data/lib/vedeu/api/api.rb +4 -6
  6. data/lib/vedeu/api/composition.rb +3 -7
  7. data/lib/vedeu/api/interface.rb +2 -3
  8. data/lib/vedeu/api/menu.rb +5 -3
  9. data/lib/vedeu/api/stream.rb +34 -0
  10. data/lib/vedeu/application.rb +4 -7
  11. data/lib/vedeu/configuration/api.rb +0 -5
  12. data/lib/vedeu/configuration/cli.rb +0 -1
  13. data/lib/vedeu/configuration/configuration.rb +0 -12
  14. data/lib/vedeu/input/input.rb +0 -3
  15. data/lib/vedeu/launcher.rb +0 -1
  16. data/lib/vedeu/models/{attributes/background.rb → background.rb} +0 -4
  17. data/lib/vedeu/models/char.rb +43 -0
  18. data/lib/vedeu/models/colour.rb +0 -1
  19. data/lib/vedeu/models/composition.rb +4 -3
  20. data/lib/vedeu/models/cursor.rb +70 -146
  21. data/lib/vedeu/models/{attributes/foreground.rb → foreground.rb} +0 -4
  22. data/lib/vedeu/models/geometry.rb +19 -20
  23. data/lib/vedeu/models/interface.rb +36 -5
  24. data/lib/vedeu/models/keymap.rb +7 -4
  25. data/lib/vedeu/models/line.rb +31 -11
  26. data/lib/vedeu/models/offset.rb +84 -0
  27. data/lib/vedeu/models/stream.rb +37 -13
  28. data/lib/vedeu/models/style.rb +0 -1
  29. data/lib/vedeu/output/area.rb +284 -0
  30. data/lib/vedeu/output/clear.rb +2 -4
  31. data/lib/vedeu/output/compositor.rb +0 -4
  32. data/lib/vedeu/output/refresh.rb +1 -2
  33. data/lib/vedeu/output/render.rb +12 -163
  34. data/lib/vedeu/output/view.rb +0 -2
  35. data/lib/vedeu/output/viewport.rb +132 -0
  36. data/lib/vedeu/repositories/buffers.rb +11 -22
  37. data/lib/vedeu/repositories/cursors.rb +20 -47
  38. data/lib/vedeu/repositories/events.rb +2 -1
  39. data/lib/vedeu/repositories/focus.rb +16 -16
  40. data/lib/vedeu/repositories/groups.rb +1 -4
  41. data/lib/vedeu/repositories/interfaces.rb +10 -3
  42. data/lib/vedeu/repositories/keymaps.rb +0 -3
  43. data/lib/vedeu/repositories/menus.rb +0 -2
  44. data/lib/vedeu/repositories/offsets.rb +47 -0
  45. data/lib/vedeu/{models/attributes → support}/coercions.rb +0 -0
  46. data/lib/vedeu/{models/attributes → support}/colour_translator.rb +0 -16
  47. data/lib/vedeu/support/esc.rb +0 -22
  48. data/lib/vedeu/support/event.rb +1 -17
  49. data/lib/vedeu/support/exceptions.rb +0 -3
  50. data/lib/vedeu/support/grid.rb +0 -3
  51. data/lib/vedeu/support/log.rb +13 -14
  52. data/lib/vedeu/support/move.rb +50 -0
  53. data/lib/vedeu/support/position.rb +17 -9
  54. data/lib/vedeu/{models/attributes → support}/presentation.rb +1 -4
  55. data/lib/vedeu/support/registrar.rb +2 -2
  56. data/lib/vedeu/support/repository.rb +23 -2
  57. data/lib/vedeu/support/terminal.rb +0 -2
  58. data/lib/vedeu/support/trace.rb +0 -11
  59. data/lib/vedeu.rb +11 -5
  60. data/test/lib/vedeu/api/api_test.rb +14 -5
  61. data/test/lib/vedeu/api/composition_test.rb +9 -26
  62. data/test/lib/vedeu/api/keymap_test.rb +1 -1
  63. data/test/lib/vedeu/api/menu_test.rb +6 -0
  64. data/test/lib/vedeu/api/stream_test.rb +32 -0
  65. data/test/lib/vedeu/models/{attributes/background_test.rb → background_test.rb} +0 -0
  66. data/test/lib/vedeu/models/char_test.rb +46 -0
  67. data/test/lib/vedeu/models/composition_test.rb +7 -0
  68. data/test/lib/vedeu/models/cursor_test.rb +63 -80
  69. data/test/lib/vedeu/models/{attributes/foreground_test.rb → foreground_test.rb} +0 -0
  70. data/test/lib/vedeu/models/geometry_test.rb +8 -10
  71. data/test/lib/vedeu/models/interface_test.rb +26 -21
  72. data/test/lib/vedeu/models/keymap_test.rb +6 -0
  73. data/test/lib/vedeu/models/line_test.rb +82 -3
  74. data/test/lib/vedeu/models/offset_test.rb +121 -0
  75. data/test/lib/vedeu/models/stream_test.rb +107 -8
  76. data/test/lib/vedeu/output/area_test.rb +242 -0
  77. data/test/lib/vedeu/output/compositor_test.rb +12 -3
  78. data/test/lib/vedeu/output/render_test.rb +34 -39
  79. data/test/lib/vedeu/output/viewport_test.rb +36 -0
  80. data/test/lib/vedeu/repositories/cursors_test.rb +32 -9
  81. data/test/lib/vedeu/repositories/focus_test.rb +8 -0
  82. data/test/lib/vedeu/repositories/offsets_test.rb +32 -0
  83. data/test/lib/vedeu/{models/attributes → support}/coercions_test.rb +0 -0
  84. data/test/lib/vedeu/{models/attributes → support}/colour_translator_test.rb +0 -0
  85. data/test/lib/vedeu/support/move_test.rb +35 -0
  86. data/test/lib/vedeu/{models/attributes → support}/presentation_test.rb +0 -0
  87. data/test/lib/vedeu/support/registrar_test.rb +6 -0
  88. data/test/lib/vedeu_test.rb +5 -0
  89. data/vedeu.gemspec +1 -1
  90. metadata +37 -17
@@ -8,19 +8,28 @@ module Vedeu
8
8
 
9
9
  extend Forwardable
10
10
 
11
- def_delegators :geometry, :top, :right, :bottom, :left
11
+ def_delegators :interface, :top, :right, :bottom, :left
12
+
13
+ attr_reader :name, :state
12
14
 
13
15
  # Provides a new instance of Cursor.
14
16
  #
15
17
  # @param attributes [Hash] The stored attributes for a cursor.
18
+ # @option attributes :name [String] The name of the interface this cursor
19
+ # belongs to.
20
+ # @option attributes :state [Symbol] The visibility of the cursor, either
21
+ # +:hide+ or +:show+.
22
+ # @option attributes :x [Fixnum]
23
+ # @option attributes :y [Fixnum]
24
+ #
16
25
  # @return [Cursor]
17
26
  def initialize(attributes = {})
18
27
  @attributes = defaults.merge!(attributes)
19
28
 
20
- @name = @attributes[:name]
21
- @state = @attributes[:state]
22
- @x = @attributes[:x]
23
- @y = @attributes[:y]
29
+ @name = @attributes[:name]
30
+ @state = @attributes[:state]
31
+ @x = @attributes[:x]
32
+ @y = @attributes[:y]
24
33
  end
25
34
 
26
35
  # Returns an attribute hash for the current position and visibility of the
@@ -29,89 +38,64 @@ module Vedeu
29
38
  # @return [Hash]
30
39
  def attributes
31
40
  {
32
- name: name,
33
- state: state,
34
- x: x,
35
- y: y,
41
+ name: name,
42
+ state: state,
43
+ x: x,
44
+ y: y,
36
45
  }
37
46
  end
38
47
  alias_method :refresh, :attributes
39
48
 
40
- # Move the cursor up one row.
49
+ # Returns the x coordinate (column/character) of the cursor. Attempts to
50
+ # sensibly reposition the cursor if it is currently outside the interface.
41
51
  #
42
- # @return [Cursor]
43
- def move_up
44
- unless y == top || y - 1 < top
45
- @y -= 1
46
- end
52
+ # @return [Fixnum]
53
+ def x
54
+ if @x <= left
55
+ @x = left
47
56
 
48
- attributes
49
- end
57
+ elsif @x >= right
58
+ @x = right - 1
50
59
 
51
- # Move the cursor down one row.
52
- #
53
- # @return [Cursor]
54
- def move_down
55
- unless y == bottom || y + 1 >= bottom
56
- @y += 1
57
- end
60
+ else
61
+ @x
58
62
 
59
- attributes
63
+ end
60
64
  end
61
65
 
62
- # Move the cursor left one column.
66
+ # Returns the y coordinate (row/line) of the cursor. Attempts to sensibly
67
+ # reposition the cursor if it is currently outside the interface.
63
68
  #
64
- # @return [Cursor]
65
- def move_left
66
- unless x == left || x - 1 < left
67
- @x -= 1
68
- end
69
+ # @return [Fixnum]
70
+ def y
71
+ if @y <= top
72
+ @y = top
69
73
 
70
- attributes
71
- end
74
+ elsif @y >= bottom
75
+ @y = bottom - 1
72
76
 
73
- # Move the cursor right one column.
74
- #
75
- # @return [Cursor]
76
- def move_right
77
- unless x == right || x + 1 >= right
78
- @x += 1
79
- end
77
+ else
78
+ @y
80
79
 
81
- attributes
80
+ end
82
81
  end
83
82
 
84
- # Make the cursor visible if it is not already.
83
+ # Make the cursor visible.
85
84
  #
86
- # @return [Symbol]
85
+ # @return [Hash]
87
86
  def show
88
87
  @state = :show
89
88
 
90
- attributes
89
+ Cursors.update(attributes)
91
90
  end
92
91
 
93
- # Make the cursor invisible if it is not already.
92
+ # Make the cursor invisible.
94
93
  #
95
- # @return [Symbol]
94
+ # @return [Hash]
96
95
  def hide
97
96
  @state = :hide
98
97
 
99
- attributes
100
- end
101
-
102
- # Toggle the visibility of the cursor.
103
- #
104
- # @return [Symbol]
105
- def toggle
106
- if visible?
107
- @state = :hide
108
-
109
- else
110
- @state = :show
111
-
112
- end
113
-
114
- attributes
98
+ Cursors.update(attributes)
115
99
  end
116
100
 
117
101
  # Returns an escape sequence to position the cursor and set its visibility.
@@ -130,29 +114,35 @@ module Vedeu
130
114
  end
131
115
  end
132
116
 
133
- private
117
+ # Return a boolean indicating the visibility of the cursor, invisible if
118
+ # the state is not defined.
119
+ #
120
+ # @return [Boolean]
121
+ def visible?
122
+ return false unless states.include?(state)
123
+ return false if state == :hide
134
124
 
135
- attr_reader :name, :state
125
+ true
126
+ end
127
+
128
+ private
136
129
 
137
130
  # Returns the escape sequence to position the cursor and set its visibility.
138
131
  #
139
- # @api private
140
132
  # @return [String]
141
133
  def sequence
142
134
  [ position, visibility ].join
143
135
  end
144
136
 
145
- # Returns the escape sequence to position the cursor.
137
+ # Returns the escape sequence for setting the position of the cursor.
146
138
  #
147
- # @api private
148
139
  # @return [String]
149
140
  def position
150
- ["\e[", y, ';', x, 'H'].join
141
+ @_position ||= Position.new(y, x).to_s
151
142
  end
152
143
 
153
144
  # Returns the escape sequence for setting the visibility of the cursor.
154
145
  #
155
- # @api private
156
146
  # @return [String]
157
147
  def visibility
158
148
  return Esc.string('show_cursor') if visible?
@@ -160,85 +150,20 @@ module Vedeu
160
150
  Esc.string('hide_cursor')
161
151
  end
162
152
 
163
- # Return a boolean indicating the visibility of the cursor, invisible if
164
- # the state is not defined.
165
- #
166
- # @api private
167
- # @return [Boolean]
168
- def visible?
169
- return false unless states.include?(state)
170
- return false if state == :hide
171
-
172
- true
173
- end
174
-
175
- # Returns the y coordinate of the cursor, unless out of range, in which case
176
- # sets y to the first row (top) of the interface.
153
+ # Returns an instance of the associated interface for this cursor, used to
154
+ # ensure that {x} and {y} are still 'inside' the interface. A cursor could
155
+ # be 'outside' the interface if the terminal has resized, causing the
156
+ # geometry of an interface to change and therefore invalidating the cursor's
157
+ # position.
177
158
  #
178
159
  # @api private
179
- # @return [Fixnum]
180
- def y
181
- if y_out_of_range?
182
- @y = top
183
-
184
- else
185
- @y
186
-
187
- end
188
- end
189
-
190
- # Returns the x coordinate of the cursor, unless out of range, in which case
191
- # sets x to the first column (left) of the interface.
192
- #
193
- # @api private
194
- # @return [Fixnum]
195
- def x
196
- if x_out_of_range?
197
- @x = left
198
-
199
- else
200
- @x
201
-
202
- end
203
- end
204
-
205
- # Returns a boolean indicating whether the previous y coordinate is still
206
- # inside the interface or terminal.
207
- #
208
- # @api private
209
- # @return [Boolean]
210
- def y_out_of_range?
211
- @y < top || @y > bottom
212
- end
213
-
214
- # Returns a boolean indicating whether the previous x coordinate is still
215
- # inside the interface or terminal.
216
- #
217
- # @api private
218
- # @return [Boolean]
219
- def x_out_of_range?
220
- @x < left || @x > right
221
- end
222
-
223
- # Returns the position and size of the interface.
224
- #
225
- # @api private
226
- # @return [Geometry]
227
- def geometry
228
- @geometry ||= Vedeu::Geometry.new(interface[:geometry])
229
- end
230
-
231
- # Returns the attributes of a named interface.
232
- #
233
- # @api private
234
- # @return [Hash]
160
+ # @return [Interface]
235
161
  def interface
236
- Vedeu::Interfaces.find(name)
162
+ @interface ||= Interfaces.build(name)
237
163
  end
238
164
 
239
165
  # The valid visibility states for the cursor.
240
166
  #
241
- # @api private
242
167
  # @return [Array]
243
168
  def states
244
169
  [:show, :hide]
@@ -246,14 +171,13 @@ module Vedeu
246
171
 
247
172
  # The default values for a new instance of Cursor.
248
173
  #
249
- # @api private
250
174
  # @return [Hash]
251
175
  def defaults
252
176
  {
253
- name: '',
254
- x: 1,
255
- y: 1,
256
- state: :hide,
177
+ name: '',
178
+ state: :show,
179
+ x: 1,
180
+ y: 1,
257
181
  }
258
182
  end
259
183
 
@@ -8,19 +8,16 @@ module Vedeu
8
8
 
9
9
  private
10
10
 
11
- # @api private
12
11
  # @return [String]
13
12
  def named
14
13
  ["\e[", foreground_codes[colour], 'm'].join
15
14
  end
16
15
 
17
- # @api private
18
16
  # @return [String]
19
17
  def numbered
20
18
  ["\e[38;5;", css_to_numbered, 'm'].join
21
19
  end
22
20
 
23
- # @api private
24
21
  # @return [String]
25
22
  def rgb
26
23
  if Configuration.colour_mode == 16777216
@@ -35,7 +32,6 @@ module Vedeu
35
32
  # Produces the foreground named colour escape sequence hash from
36
33
  # {Vedeu::ColourTranslator#codes}
37
34
  #
38
- # @api private
39
35
  # @return [Hash]
40
36
  def foreground_codes
41
37
  codes
@@ -9,7 +9,7 @@ module Vedeu
9
9
  # @api private
10
10
  class Geometry
11
11
 
12
- attr_reader :attributes, :centred, :height, :width
12
+ attr_reader :attributes, :centred
13
13
 
14
14
  # Returns a new instance of Geometry.
15
15
  #
@@ -60,13 +60,13 @@ module Vedeu
60
60
  # is not off-screen.
61
61
  #
62
62
  # @return [Fixnum]
63
- def viewport_width
64
- if (x + width) > Terminal.width
65
- new_width = width - ((x + width) - Terminal.width)
63
+ def width
64
+ if (x + @width) > Terminal.width
65
+ new_width = @width - ((x + @width) - Terminal.width)
66
66
  return new_width < 1 ? 1 : new_width
67
67
 
68
68
  else
69
- width
69
+ @width
70
70
 
71
71
  end
72
72
  end
@@ -81,18 +81,21 @@ module Vedeu
81
81
  # Vedeu render the view to ensure the content is not off-screen.
82
82
  #
83
83
  # @return [Fixnum]
84
- def viewport_height
85
- if (y + height) > Terminal.height
86
- new_height = height - ((y + height) - Terminal.height)
84
+ def height
85
+ if (y + @height) > Terminal.height
86
+ new_height = @height - ((y + @height) - Terminal.height)
87
87
  return new_height < 1 ? 1 : new_height
88
88
 
89
89
  else
90
- height
90
+ @height
91
91
 
92
92
  end
93
93
  end
94
94
 
95
- # Returns the top-left coordinate, relative to the interface's position.
95
+ # Returns an escape sequence to position the cursor at the top-left
96
+ # coordinate, relative to the interface's position.
97
+ #
98
+ # @todo I think this method belongs with Area.
96
99
  #
97
100
  # @param index [Fixnum]
98
101
  # @param block [Proc]
@@ -107,7 +110,7 @@ module Vedeu
107
110
  # @return [Fixnum]
108
111
  def top
109
112
  if centred
110
- Terminal.centre_y - (viewport_height / 2)
113
+ Terminal.centre_y - (height / 2)
111
114
 
112
115
  else
113
116
  y
@@ -136,7 +139,7 @@ module Vedeu
136
139
  # @return [Fixnum]
137
140
  def left
138
141
  if centred
139
- Terminal.centre_x - (viewport_width / 2)
142
+ Terminal.centre_x - (width / 2)
140
143
 
141
144
  else
142
145
  x
@@ -162,9 +165,6 @@ module Vedeu
162
165
  # Returns the bottom coordinate of the interface, a fixed or dynamic value
163
166
  # depending on the value of {#top}.
164
167
  #
165
- # @todo I think `height` should be `viewport_height` because the terminal
166
- # may have resized, and viewport_height will properly handle this.
167
- #
168
168
  # @return [Fixnum]
169
169
  def bottom
170
170
  top + height
@@ -188,9 +188,6 @@ module Vedeu
188
188
  # Returns the right coordinate of the interface, a fixed or dynamic value
189
189
  # depending on the value of {#left}.
190
190
  #
191
- # @todo I think `width` should be `viewport_width` because the terminal may
192
- # have resized, and viewport_width will properly handle this.
193
- #
194
191
  # @return [Fixnum]
195
192
  def right
196
193
  left + width
@@ -213,6 +210,8 @@ module Vedeu
213
210
 
214
211
  # Provides a virtual y position within the interface's dimensions.
215
212
  #
213
+ # @todo I think this method belongs with Area.
214
+ #
216
215
  # @example
217
216
  # # top = 3
218
217
  # # bottom = 6
@@ -225,6 +224,8 @@ module Vedeu
225
224
 
226
225
  # Provides a virtual x position within the interface's dimensions.
227
226
  #
227
+ # @todo I think this method belongs with Area.
228
+ #
228
229
  # @example
229
230
  # # left = 9
230
231
  # # right = 13
@@ -245,8 +246,6 @@ module Vedeu
245
246
  width: width,
246
247
  x: x,
247
248
  y: y,
248
- viewport_height: viewport_height,
249
- viewport_width: viewport_width,
250
249
  top: top,
251
250
  right: right,
252
251
  bottom: bottom,
@@ -14,8 +14,7 @@ module Vedeu
14
14
  extend Forwardable
15
15
 
16
16
  def_delegators :geometry, :north, :east, :south, :west, :top, :right,
17
- :bottom, :left, :width, :height, :origin,
18
- :viewport_width, :viewport_height
17
+ :bottom, :left, :width, :height, :origin
19
18
 
20
19
  attr_reader :attributes, :delay, :group, :name, :parent
21
20
 
@@ -67,6 +66,17 @@ module Vedeu
67
66
  self
68
67
  end
69
68
 
69
+ # Returns an instance of Cursor.
70
+ #
71
+ # @return [Cursor]
72
+ def cursor
73
+ @_cursor ||= Cursor.new({
74
+ name: name,
75
+ x: area.x_position(offset.x),
76
+ y: area.y_position(offset.y),
77
+ })
78
+ end
79
+
70
80
  # Returns a boolean indicating whether this interface is currently in focus.
71
81
  #
72
82
  # @return [Boolean]
@@ -80,6 +90,7 @@ module Vedeu
80
90
  def lines
81
91
  @lines ||= Line.coercer(attributes[:lines])
82
92
  end
93
+ alias_method :content, :lines
83
94
 
84
95
  # Returns the position and size of the interface.
85
96
  #
@@ -88,11 +99,29 @@ module Vedeu
88
99
  @geometry ||= Geometry.new(attributes[:geometry])
89
100
  end
90
101
 
102
+ # Returns the current offset for the content within the interface.
103
+ #
104
+ # @return [Offset]
105
+ def offset
106
+ @offset ||= Offsets.find_or_create(name)
107
+ end
108
+
109
+ # Returns the currently visible area of the interface.
110
+ #
111
+ # @return [Viewport]
112
+ def viewport
113
+ @_viewport ||= Viewport.show(self)
114
+ end
115
+
91
116
  private
92
117
 
118
+ # @return [Area]
119
+ def area
120
+ @_area ||= Area.from_interface(self)
121
+ end
122
+
93
123
  # The default values for a new instance of Interface.
94
124
  #
95
- # @api private
96
125
  # @return [Hash]
97
126
  def defaults
98
127
  {
@@ -107,12 +136,14 @@ module Vedeu
107
136
  }
108
137
  end
109
138
 
110
- # @api private
139
+ # @param method [Symbol] The name of the method sought.
140
+ # @param args [Array] The arguments which the method was to be invoked with.
141
+ # @param block [Proc] The optional block provided to the method.
111
142
  # @return []
112
143
  def method_missing(method, *args, &block)
113
144
  Vedeu.log("Interface#method_missing '#{method.to_s}' (args: #{args.inspect})")
114
145
 
115
- @self_before_instance_eval.send(method, *args, &block)
146
+ @self_before_instance_eval.send(method, *args, &block) if @self_before_instance_eval
116
147
  end
117
148
 
118
149
  end # Interface
@@ -13,7 +13,9 @@ module Vedeu
13
13
  # Define a keymap for an interface or interfaces to perform an action when
14
14
  # a key is pressed whilst an aforementioned interface is in focus.
15
15
  #
16
- # @param attributes [Hash]
16
+ # @param attributes [Hash] The attributes to register the keymap with.
17
+ # @option attributes :interfaces []
18
+ # @option attributes :keys []
17
19
  # @param block [Proc]
18
20
  # @return [Keymap]
19
21
  def self.define(attributes = {}, &block)
@@ -48,7 +50,6 @@ module Vedeu
48
50
 
49
51
  # The default attributes of the Keymap model.
50
52
  #
51
- # @api private
52
53
  # @return [Hash]
53
54
  def defaults
54
55
  {
@@ -57,12 +58,14 @@ module Vedeu
57
58
  }
58
59
  end
59
60
 
60
- # @api private
61
+ # @param method [Symbol] The name of the method sought.
62
+ # @param args [Array] The arguments which the method was to be invoked with.
63
+ # @param block [Proc] The optional block provided to the method.
61
64
  # @return []
62
65
  def method_missing(method, *args, &block)
63
66
  Vedeu.log("Keymap#method_missing '#{method.to_s}' (args: #{args.inspect})")
64
67
 
65
- @self_before_instance_eval.send(method, *args, &block)
68
+ @self_before_instance_eval.send(method, *args, &block) if @self_before_instance_eval
66
69
  end
67
70
 
68
71
  end # Keymap
@@ -37,26 +37,44 @@ module Vedeu
37
37
  end
38
38
  end
39
39
 
40
- # Returns a collection of streams associated with this line.
40
+ # Returns an array of all the characters with formatting for this line.
41
41
  #
42
42
  # @return [Array]
43
- def streams
44
- @streams ||= Stream.coercer(attributes[:streams])
43
+ # @see Vedeu::Stream
44
+ def chars
45
+ return [] if empty?
46
+
47
+ @_chars ||= streams.map(&:chars).flatten
45
48
  end
46
49
 
47
- private
50
+ # Returns a boolean indicating whether the line has content.
51
+ #
52
+ # @return [Boolean]
53
+ def empty?
54
+ size == 0
55
+ end
48
56
 
49
- # Convenience method to provide Presentation with a consistent interface.
57
+ # Returns the size of the content in characters without formatting.
58
+ #
59
+ # @return [Fixnum]
60
+ def size
61
+ streams.map(&:size).inject(0, :+) { |sum, x| sum += x }
62
+ end
63
+
64
+ # Returns a collection of streams associated with this line. This method
65
+ # also has the alias_method :data, a convenience method to provide
66
+ # Presentation with a consistent interface.
50
67
  #
51
- # @api private
52
68
  # @return [Array]
53
- def data
54
- streams
69
+ def streams
70
+ @streams ||= Stream.coercer(attributes[:streams])
55
71
  end
72
+ alias_method :data, :streams
73
+
74
+ private
56
75
 
57
76
  # The default values for a new instance of Line.
58
77
  #
59
- # @api private
60
78
  # @return [Hash]
61
79
  def defaults
62
80
  {
@@ -67,12 +85,14 @@ module Vedeu
67
85
  }
68
86
  end
69
87
 
70
- # @api private
88
+ # @param method [Symbol] The name of the method sought.
89
+ # @param args [Array] The arguments which the method was to be invoked with.
90
+ # @param block [Proc] The optional block provided to the method.
71
91
  # @return []
72
92
  def method_missing(method, *args, &block)
73
93
  Vedeu.log("Line#method_missing '#{method.to_s}' (args: #{args.inspect})")
74
94
 
75
- @self_before_instance_eval.send(method, *args, &block)
95
+ @self_before_instance_eval.send(method, *args, &block) if @self_before_instance_eval
76
96
  end
77
97
 
78
98
  end # Line