vedeu 0.1.18 → 0.1.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +5 -0
  3. data/Dockerfile +40 -0
  4. data/README.md +7 -30
  5. data/docs/api.md +79 -0
  6. data/docs/events.md +121 -0
  7. data/lib/vedeu.rb +61 -18
  8. data/lib/vedeu/api/api.rb +73 -53
  9. data/lib/vedeu/api/composition.rb +4 -1
  10. data/lib/vedeu/api/defined.rb +35 -0
  11. data/lib/vedeu/api/helpers.rb +20 -15
  12. data/lib/vedeu/api/interface.rb +17 -12
  13. data/lib/vedeu/api/line.rb +20 -12
  14. data/lib/vedeu/api/stream.rb +3 -0
  15. data/lib/vedeu/application.rb +34 -1
  16. data/lib/vedeu/configuration.rb +15 -3
  17. data/lib/vedeu/input/input.rb +77 -0
  18. data/lib/vedeu/launcher.rb +7 -0
  19. data/lib/vedeu/models/attributes/background.rb +15 -2
  20. data/lib/vedeu/models/attributes/coercions.rb +18 -3
  21. data/lib/vedeu/models/attributes/colour_translator.rb +23 -17
  22. data/lib/vedeu/models/attributes/foreground.rb +10 -2
  23. data/lib/vedeu/models/attributes/presentation.rb +62 -0
  24. data/lib/vedeu/models/colour.rb +7 -3
  25. data/lib/vedeu/models/composition.rb +17 -19
  26. data/lib/vedeu/models/geometry.rb +13 -5
  27. data/lib/vedeu/models/interface.rb +35 -19
  28. data/lib/vedeu/models/line.rb +24 -8
  29. data/lib/vedeu/models/stream.rb +13 -7
  30. data/lib/vedeu/models/style.rb +17 -7
  31. data/lib/vedeu/{support → output}/clear.rb +14 -0
  32. data/lib/vedeu/output/compositor.rb +77 -0
  33. data/lib/vedeu/output/refresh.rb +129 -0
  34. data/lib/vedeu/{support → output}/render.rb +49 -13
  35. data/lib/vedeu/{support → output}/view.rb +15 -8
  36. data/lib/vedeu/repositories/buffers.rb +181 -0
  37. data/lib/vedeu/{support → repositories}/events.rb +16 -6
  38. data/lib/vedeu/repositories/focus.rb +109 -0
  39. data/lib/vedeu/repositories/groups.rb +76 -0
  40. data/lib/vedeu/repositories/interfaces.rb +74 -0
  41. data/lib/vedeu/support/common.rb +20 -0
  42. data/lib/vedeu/support/cursor.rb +77 -0
  43. data/lib/vedeu/support/esc.rb +181 -46
  44. data/lib/vedeu/support/event.rb +22 -4
  45. data/lib/vedeu/support/grid.rb +10 -3
  46. data/lib/vedeu/support/log.rb +14 -1
  47. data/lib/vedeu/support/menu.rb +51 -12
  48. data/lib/vedeu/support/position.rb +9 -0
  49. data/lib/vedeu/support/terminal.rb +49 -15
  50. data/lib/vedeu/support/trace.rb +11 -4
  51. data/test/integration/defining_interfaces_test.rb +27 -0
  52. data/test/integration/views/basic_view_test.rb +767 -0
  53. data/test/lib/vedeu/api/api_test.rb +32 -37
  54. data/test/lib/vedeu/api/composition_test.rb +23 -61
  55. data/test/lib/vedeu/api/defined_test.rb +49 -0
  56. data/test/lib/vedeu/api/helpers_test.rb +91 -0
  57. data/test/lib/vedeu/api/interface_test.rb +136 -688
  58. data/test/lib/vedeu/api/line_test.rb +28 -32
  59. data/test/lib/vedeu/application_test.rb +6 -0
  60. data/test/lib/vedeu/configuration_test.rb +8 -4
  61. data/test/lib/vedeu/{support → input}/input_test.rb +9 -0
  62. data/test/lib/vedeu/launcher_test.rb +6 -0
  63. data/test/lib/vedeu/models/attributes/{coercer_test.rb → coercions_test.rb} +11 -10
  64. data/test/lib/vedeu/models/attributes/colour_translator_test.rb +13 -0
  65. data/test/lib/vedeu/models/attributes/presentation_test.rb +30 -0
  66. data/test/lib/vedeu/models/colour_test.rb +8 -0
  67. data/test/lib/vedeu/models/composition_test.rb +208 -200
  68. data/test/lib/vedeu/models/geometry_test.rb +39 -0
  69. data/test/lib/vedeu/models/interface_test.rb +11 -1
  70. data/test/lib/vedeu/models/line_test.rb +8 -1
  71. data/test/lib/vedeu/models/stream_test.rb +35 -0
  72. data/test/lib/vedeu/models/style_test.rb +8 -0
  73. data/test/lib/vedeu/{support → output}/clear_test.rb +1 -1
  74. data/test/lib/vedeu/output/compositor_test.rb +64 -0
  75. data/test/lib/vedeu/output/refresh_test.rb +48 -0
  76. data/test/lib/vedeu/{support → output}/render_test.rb +36 -0
  77. data/test/lib/vedeu/{support → output}/view_test.rb +0 -0
  78. data/test/lib/vedeu/repositories/buffers_test.rb +48 -0
  79. data/test/lib/vedeu/{support → repositories}/events_test.rb +0 -0
  80. data/test/lib/vedeu/repositories/focus_test.rb +74 -0
  81. data/test/lib/vedeu/repositories/groups_test.rb +66 -0
  82. data/test/lib/vedeu/repositories/interfaces_test.rb +6 -0
  83. data/test/lib/vedeu/support/common_test.rb +6 -0
  84. data/test/lib/vedeu/support/cursor_test.rb +79 -0
  85. data/test/lib/vedeu/support/log_test.rb +6 -0
  86. data/test/lib/vedeu/support/terminal_test.rb +6 -28
  87. data/test/lib/vedeu/support/trace_test.rb +6 -0
  88. data/test/test_helper.rb +37 -0
  89. data/vedeu.gemspec +1 -1
  90. metadata +65 -33
  91. data/bin/log +0 -13
  92. data/lib/vedeu/support/buffer.rb +0 -69
  93. data/lib/vedeu/support/buffers.rb +0 -106
  94. data/lib/vedeu/support/focus.rb +0 -83
  95. data/lib/vedeu/support/groups.rb +0 -61
  96. data/lib/vedeu/support/input.rb +0 -67
  97. data/test/lib/vedeu/support/buffer_test.rb +0 -83
  98. data/test/lib/vedeu/support/buffers_test.rb +0 -15
  99. data/test/lib/vedeu/support/focus_test.rb +0 -114
  100. data/test/lib/vedeu/support/groups_test.rb +0 -65
@@ -1,6 +1,13 @@
1
1
  module Vedeu
2
+
3
+ # Provides a mechanism for storing and retrieving events by name. A single
4
+ # name can contain many events. Also an event can trigger other events.
5
+ #
6
+ # @api private
2
7
  class Events
3
8
 
9
+ # Initializes a new Events class.
10
+ #
4
11
  # @param block [Proc]
5
12
  # @return [Events]
6
13
  def initialize(&block)
@@ -24,11 +31,7 @@ module Vedeu
24
31
  handlers[name]
25
32
  end
26
33
 
27
- # Unregisters the event by name, effectively deleting the associated events
28
- # bound with it also.
29
- #
30
- # @param name [Symbol]
31
- # @return []
34
+ # @see Vedeu::API#unevent
32
35
  def unevent(name)
33
36
  handlers.delete_if { |k, v| k == name }
34
37
  end
@@ -40,6 +43,13 @@ module Vedeu
40
43
  handlers.keys
41
44
  end
42
45
 
46
+ # Returns a Boolean indicating whether the named event is registered.
47
+ #
48
+ # @return [TrueClass|FalseClass]
49
+ def registered?(name)
50
+ handlers.key?(name)
51
+ end
52
+
43
53
  # @see Vedeu::API#trigger
44
54
  def trigger(name, *args)
45
55
  handlers[name][:events].each { |event| event.trigger(*args) }
@@ -47,7 +57,7 @@ module Vedeu
47
57
 
48
58
  # Remove all registered events. Used for testing purposes.
49
59
  #
50
- # @return []
60
+ # @return [Hash]
51
61
  def reset
52
62
  @handlers = Hash.new { |hash, key| hash[key] = { events: [] } }
53
63
  end
@@ -0,0 +1,109 @@
1
+ module Vedeu
2
+
3
+ # The Focus repository is simply a collection of interface names, this module
4
+ # serving to store and manipulate the which interface is currently being
5
+ # focussed.
6
+ #
7
+ # @api private
8
+ module Focus
9
+
10
+ extend self
11
+
12
+ # Add an interface name to the focus list unless it is already registered.
13
+ #
14
+ # @param attributes [String]
15
+ # @return [Array]
16
+ def add(attributes)
17
+ if registered?(attributes[:name])
18
+ storage
19
+
20
+ else
21
+ storage << attributes[:name]
22
+
23
+ end
24
+ end
25
+
26
+ # Focus an interface by name.
27
+ #
28
+ # @param name [String]
29
+ # @return [String]
30
+ def by_name(name)
31
+ fail InterfaceNotFound unless storage.include?(name)
32
+
33
+ storage.rotate!(storage.index(name))
34
+
35
+ current
36
+ end
37
+
38
+ # Return the interface currently focussed.
39
+ #
40
+ # @return [String]
41
+ def current
42
+ fail NoInterfacesDefined if storage.empty?
43
+
44
+ storage.first
45
+ end
46
+
47
+ # Put the next interface relative to the current interfaces in focus.
48
+ #
49
+ # @return [String]
50
+ def next_item
51
+ storage.rotate!
52
+
53
+ current
54
+ end
55
+
56
+ # Put the previous interface relative to the current interface in focus.
57
+ #
58
+ # @return [String]
59
+ def prev_item
60
+ storage.rotate!(-1)
61
+
62
+ current
63
+ end
64
+
65
+ # Returns all registered interfaces by name.
66
+ #
67
+ # @return [Array]
68
+ def registered
69
+ storage
70
+ end
71
+
72
+ # Reset the focus repository; removing all items. This does not delete
73
+ # the interfaces themselves.
74
+ #
75
+ # @return [Hash]
76
+ def reset
77
+ @storage = in_memory
78
+ end
79
+
80
+ private
81
+
82
+ # Returns a boolean indicating whether the named interface is registered.
83
+ #
84
+ # @api private
85
+ # @return [TrueClass|FalseClass]
86
+ def registered?(name)
87
+ return false if storage.empty?
88
+
89
+ storage.include?(name)
90
+ end
91
+
92
+ # Provides accessor to the in-memory storage.
93
+ #
94
+ # @api private
95
+ # @return [Array]
96
+ def storage
97
+ @storage ||= in_memory
98
+ end
99
+
100
+ # Returns an empty collection ready for the storing of interface names.
101
+ #
102
+ # @api private
103
+ # @return [Array]
104
+ def in_memory
105
+ []
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,76 @@
1
+ module Vedeu
2
+
3
+ # Repository for storing and retrieving interfaces by their group name.
4
+ #
5
+ # @api private
6
+ module Groups
7
+
8
+ extend self
9
+
10
+ # Add an interface name to a group, creating the group if it doesn't already
11
+ # exist, and rejecting the interface if it is already known.
12
+ #
13
+ # @param attributes [Hash]
14
+ # @return [Groups|FalseClass]
15
+ def add(attributes)
16
+ return false if attributes[:group].empty?
17
+
18
+ storage[attributes[:group]] << attributes[:name]
19
+ end
20
+
21
+ # Return the whole repository.
22
+ #
23
+ # @return [Set]
24
+ def all
25
+ storage
26
+ end
27
+
28
+ # Find a group by name and return all of its associated interfaces.
29
+ #
30
+ # @param name [String]
31
+ # @return [Set]
32
+ def find(name)
33
+ storage.fetch(name) do
34
+ fail GroupNotFound,
35
+ "Cannot find interface group with this name: #{name.to_s}."
36
+ end
37
+ end
38
+
39
+ # Returns a collection of the names of all registered groups.
40
+ #
41
+ # @return [Array]
42
+ def registered
43
+ storage.keys
44
+ end
45
+
46
+ # Returns a Boolean indicating whether the named group is registered.
47
+ #
48
+ # @return [TrueClass|FalseClass]
49
+ def registered?(name)
50
+ storage.key?(name)
51
+ end
52
+
53
+ # Reset the groups repository; removing all groups. This does not delete
54
+ # the interfaces themselves.
55
+ #
56
+ # @return [Hash]
57
+ def reset
58
+ @_storage = in_memory
59
+ end
60
+
61
+ private
62
+
63
+ # @api private
64
+ # @return [Hash]
65
+ def storage
66
+ @_storage ||= in_memory
67
+ end
68
+
69
+ # @api private
70
+ # @return [Hash]
71
+ def in_memory
72
+ Hash.new { |hash, key| hash[key] = Set.new }
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,74 @@
1
+ module Vedeu
2
+
3
+ # Repository for storing and retrieving defined interfaces.
4
+ #
5
+ # @api private
6
+ module Interfaces
7
+
8
+ extend self
9
+
10
+ # Stores the interface attributes defined by the API.
11
+ #
12
+ # @param attributes [Hash]
13
+ # @return [Hash]
14
+ def add(attributes)
15
+ storage.store(attributes[:name], attributes)
16
+ end
17
+
18
+ # Return the whole repository.
19
+ #
20
+ # @return [Hash]
21
+ def all
22
+ storage
23
+ end
24
+
25
+ # Find an interface by name and return the attributes used to define it.
26
+ #
27
+ # @param name [String]
28
+ # @return [Hash]
29
+ def find(name)
30
+ storage.fetch(name) do
31
+ fail InterfaceNotFound,
32
+ "Interface was not found with this name: #{name.to_s}."
33
+ end
34
+ end
35
+
36
+ # Returns a collection of the names of all the registered interfaces.
37
+ #
38
+ # @return [Array]
39
+ def registered
40
+ storage.keys
41
+ end
42
+
43
+ # Returns a boolean indicating whether the named interface is registered.
44
+ #
45
+ # @return [TrueClass|FalseClass]
46
+ def registered?(name)
47
+ storage.key?(name)
48
+ end
49
+
50
+ # Reset the interfaces repository; removing all registered interfaces.
51
+ # This will delete the interfaces themselves, and the client application
52
+ # will need to either redefine interfaces before using them, or restart.
53
+ #
54
+ # @return [Hash]
55
+ def reset
56
+ @_storage = in_memory
57
+ end
58
+
59
+ private
60
+
61
+ # @api private
62
+ # @return [Hash]
63
+ def storage
64
+ @_storage ||= in_memory
65
+ end
66
+
67
+ # @api private
68
+ # @return [Hash]
69
+ def in_memory
70
+ {}
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,20 @@
1
+ module Vedeu
2
+
3
+ # A module for common methods used throughout Vedeu.
4
+ #
5
+ # @api private
6
+ module Common
7
+
8
+ # Returns a boolean indicating whether a variable has a useful value.
9
+ #
10
+ # @param variable [String|Array] The variable to check.
11
+ # @return [TrueClass|FalseClass]
12
+ def defined_value?(variable)
13
+ return true unless variable.nil? || variable.empty?
14
+
15
+ false
16
+ end
17
+
18
+ end
19
+ end
20
+
@@ -0,0 +1,77 @@
1
+ module Vedeu
2
+
3
+ # Stores and manipulates the position of the current cursor.
4
+ #
5
+ # @api private
6
+ class Cursor
7
+
8
+ attr_reader :top, :bottom, :left, :right, :cursor_x, :cursor_y
9
+
10
+ # Provides a new instance of Cursor.
11
+ #
12
+ # @param attributes [Hash]
13
+ # @return [Cursor]
14
+ def initialize(attributes = {})
15
+ @attributes = attributes
16
+
17
+ @top = attributes.fetch(:top)
18
+ @bottom = attributes.fetch(:bottom)
19
+ @left = attributes.fetch(:left)
20
+ @right = attributes.fetch(:right)
21
+ @cursor_y = attributes.fetch(:cursor_y, @top)
22
+ @cursor_x = attributes.fetch(:cursor_x, @left)
23
+ end
24
+
25
+ # Reports the position of the cursor.
26
+ #
27
+ # @return [Array]
28
+ def position
29
+ [ @cursor_y, @cursor_x ]
30
+ end
31
+
32
+ # Move the cursor up one row.
33
+ #
34
+ # @return [Cursor]
35
+ def move_up
36
+ unless @cursor_y == top || @cursor_y - 1 < top
37
+ @cursor_y -= 1
38
+ end
39
+
40
+ self
41
+ end
42
+
43
+ # Move the cursor down one row.
44
+ #
45
+ # @return [Cursor]
46
+ def move_down
47
+ unless @cursor_y == bottom || @cursor_y + 1 > bottom
48
+ @cursor_y += 1
49
+ end
50
+
51
+ self
52
+ end
53
+
54
+ # Move the cursor left one column.
55
+ #
56
+ # @return [Cursor]
57
+ def move_left
58
+ unless @cursor_x == left || @cursor_x - 1 < left
59
+ @cursor_x -= 1
60
+ end
61
+
62
+ self
63
+ end
64
+
65
+ # Move the cursor right one column.
66
+ #
67
+ # @return [Cursor]
68
+ def move_right
69
+ unless @cursor_x == right || @cursor_x + 1 > right
70
+ @cursor_x += 1
71
+ end
72
+
73
+ self
74
+ end
75
+
76
+ end
77
+ end
@@ -1,4 +1,9 @@
1
1
  module Vedeu
2
+
3
+ # Provides escape sequence strings for setting the cursor position and various
4
+ # display related functions.
5
+ #
6
+ # @api private
2
7
  module Esc
3
8
 
4
9
  extend self
@@ -15,54 +20,184 @@ module Vedeu
15
20
  Position.new(y, x).to_s(&block)
16
21
  end
17
22
 
18
- # @param value [String]
23
+ # Return the escape sequence string from the list of recognised sequence
24
+ # 'commands', or an empty string if the 'command' cannot be found.
25
+ #
26
+ # @param value [String|Symbol]
19
27
  # @return [String]
20
28
  def string(value = '')
21
- case value
22
- when 'bg_reset' then "\e[48;2;49m"
23
- when 'blink' then "\e[5m"
24
- when 'blink_off' then "\e[25m"
25
- when 'bold' then "\e[1m"
26
- when 'bold_off' then "\e[22m"
27
- when 'clear' then "\e[38;2;39m\e[48;2;49m\e[2J"
28
- when 'clear_line' then "\e[38;2;39m\e[48;2;49m\e[2K"
29
- when 'colour_reset' then
30
- [ string('fg_reset'),
31
- string('bg_reset') ].join
32
-
33
- when 'dim' then "\e[2m"
34
- when 'fg_reset' then "\e[38;2;39m"
35
- when 'hide_cursor' then "\e[?25l"
36
- when 'negative' then "\e[7m"
37
- when 'normal' then
38
- [ string('underline_off'),
39
- string('bold_off'),
40
- string('positive') ].join
41
-
42
- when 'positive' then "\e[27m"
43
- when 'reset' then "\e[0m"
44
- when 'screen_init' then
45
- [ string('reset'),
46
- string('clear'),
47
- string('hide_cursor') ].join
48
-
49
- when 'screen_exit' then
50
- [ string('show_cursor'),
51
- string('colour_reset'),
52
- string('reset') ].join
53
- when 'show_cursor' then "\e[?25h"
54
- when 'underline' then "\e[4m"
55
- when 'underline_off' then "\e[24m"
56
- else
57
- ''
58
- end
59
- end
60
-
61
- # private
62
-
63
- # def method_missing(method, *args, &block)
64
- # self.send(:string, method, &block)
65
- # end
29
+ return '' if value.to_sym.empty?
30
+
31
+ sequences.fetch(value.to_sym, proc { '' }).call
32
+ end
33
+
34
+ private
35
+
36
+ # @api private
37
+ # @return [Hash]
38
+ def sequences
39
+ {
40
+ bg_reset: proc { bg_reset },
41
+ blink: proc { blink },
42
+ blink_off: proc { blink_off },
43
+ bold: proc { bold },
44
+ bold_off: proc { bold_off },
45
+ clear: proc { clear },
46
+ clear_line: proc { clear_line },
47
+ clear_last_line: proc { clear_last_line },
48
+ colour_reset: proc { colour_reset },
49
+ dim: proc { dim },
50
+ fg_reset: proc { fg_reset },
51
+ hide_cursor: proc { hide_cursor },
52
+ negative: proc { negative },
53
+ normal: proc { normal },
54
+ positive: proc { positive },
55
+ reset: proc { reset },
56
+ screen_init: proc { screen_init },
57
+ screen_exit: proc { screen_exit },
58
+ show_cursor: proc { show_cursor },
59
+ underline: proc { underline },
60
+ underline_off: proc { underline_off },
61
+ }
62
+ end
63
+
64
+ # @api private
65
+ # @return [String]
66
+ def bg_reset
67
+ "\e[48;2;49m"
68
+ end
69
+
70
+ # @api private
71
+ # @return [String]
72
+ def blink
73
+ "\e[5m"
74
+ end
75
+
76
+ # @api private
77
+ # @return [String]
78
+ def blink_off
79
+ "\e[25m"
80
+ end
81
+
82
+ # @api private
83
+ # @return [String]
84
+ def bold
85
+ "\e[1m"
86
+ end
87
+
88
+ # @api private
89
+ # @return [String]
90
+ def bold_off
91
+ "\e[22m"
92
+ end
93
+
94
+ # @api private
95
+ # @return [String]
96
+ def clear
97
+ [ string('fg_reset'),
98
+ string('bg_reset'),
99
+ "\e[2J" ].join
100
+ end
101
+
102
+ # @api private
103
+ # @return [String]
104
+ def clear_line
105
+ [ string('fg_reset'),
106
+ string('bg_reset'),
107
+ "\e[2K" ].join
108
+ end
109
+
110
+ # @api private
111
+ # @return [String]
112
+ def clear_last_line
113
+ [ set_position((Terminal.height - 1), 1),
114
+ string('clear_line') ].join
115
+ end
116
+
117
+ # @api private
118
+ # @return [String]
119
+ def colour_reset
120
+ [ string('fg_reset'),
121
+ string('bg_reset') ].join
122
+ end
123
+
124
+ # @api private
125
+ # @return [String]
126
+ def dim
127
+ "\e[2m"
128
+ end
129
+
130
+ # @api private
131
+ # @return [String]
132
+ def fg_reset
133
+ "\e[38;2;39m"
134
+ end
135
+
136
+ # @api private
137
+ # @return [String]
138
+ def hide_cursor
139
+ "\e[?25l"
140
+ end
141
+
142
+ # @api private
143
+ # @return [String]
144
+ def negative
145
+ "\e[7m"
146
+ end
147
+
148
+ # @api private
149
+ # @return [String]
150
+ def normal
151
+ [ string('underline_off'),
152
+ string('bold_off'),
153
+ string('positive') ].join
154
+ end
155
+
156
+ # @api private
157
+ # @return [String]
158
+ def positive
159
+ "\e[27m"
160
+ end
161
+
162
+ # @api private
163
+ # @return [String]
164
+ def reset
165
+ "\e[0m"
166
+ end
167
+
168
+ # @api private
169
+ # @return [String]
170
+ def screen_init
171
+ [ string('reset'),
172
+ string('clear'),
173
+ string('hide_cursor') ].join
174
+ end
175
+
176
+ # @api private
177
+ # @return [String]
178
+ def screen_exit
179
+ [ string('show_cursor'),
180
+ string('colour_reset'),
181
+ string('reset') ].join
182
+ end
183
+
184
+ # @api private
185
+ # @return [String]
186
+ def show_cursor
187
+ "\e[?25h"
188
+ end
189
+
190
+ # @api private
191
+ # @return [String]
192
+ def underline
193
+ "\e[4m"
194
+ end
195
+
196
+ # @api private
197
+ # @return [String]
198
+ def underline_off
199
+ "\e[24m"
200
+ end
66
201
 
67
202
  end
68
203
  end