vedeu 0.2.3 → 0.2.4

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