vedeu 0.2.0 → 0.2.1

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -9
  3. data/docs/api.md +70 -42
  4. data/elements.txt +118 -0
  5. data/lib/vedeu.rb +14 -4
  6. data/lib/vedeu/api/api.rb +67 -24
  7. data/lib/vedeu/api/composition.rb +19 -0
  8. data/lib/vedeu/api/defined.rb +7 -0
  9. data/lib/vedeu/api/interface.rb +103 -75
  10. data/lib/vedeu/api/keymap.rb +62 -0
  11. data/lib/vedeu/api/menu.rb +3 -1
  12. data/lib/vedeu/configuration.rb +24 -6
  13. data/lib/vedeu/models/attributes/coercions.rb +18 -26
  14. data/lib/vedeu/models/attributes/colour_translator.rb +7 -7
  15. data/lib/vedeu/models/attributes/presentation.rb +12 -1
  16. data/lib/vedeu/models/geometry.rb +5 -1
  17. data/lib/vedeu/models/interface.rb +6 -47
  18. data/lib/vedeu/models/keymap.rb +66 -0
  19. data/lib/vedeu/models/line.rb +3 -1
  20. data/lib/vedeu/models/stream.rb +10 -1
  21. data/lib/vedeu/models/style.rb +10 -1
  22. data/lib/vedeu/output/compositor.rb +3 -0
  23. data/lib/vedeu/output/refresh.rb +16 -74
  24. data/lib/vedeu/output/render.rb +44 -17
  25. data/lib/vedeu/output/view.rb +3 -0
  26. data/lib/vedeu/repositories/buffers.rb +32 -42
  27. data/lib/vedeu/repositories/events.rb +8 -11
  28. data/lib/vedeu/repositories/focus.rb +15 -13
  29. data/lib/vedeu/repositories/groups.rb +20 -2
  30. data/lib/vedeu/repositories/interfaces.rb +22 -2
  31. data/lib/vedeu/repositories/keymap_validator.rb +104 -0
  32. data/lib/vedeu/repositories/keymaps.rb +239 -0
  33. data/lib/vedeu/repositories/menus.rb +12 -3
  34. data/lib/vedeu/support/common.rb +2 -2
  35. data/lib/vedeu/support/cursor.rb +3 -0
  36. data/lib/vedeu/support/event.rb +48 -7
  37. data/lib/vedeu/support/grid.rb +1 -1
  38. data/lib/vedeu/support/registrar.rb +66 -0
  39. data/lib/vedeu/support/trace.rb +71 -12
  40. data/test/lib/vedeu/api/api_test.rb +27 -9
  41. data/test/lib/vedeu/api/composition_test.rb +10 -0
  42. data/test/lib/vedeu/api/defined_test.rb +14 -0
  43. data/test/lib/vedeu/api/interface_test.rb +86 -85
  44. data/test/lib/vedeu/api/keymap_test.rb +61 -0
  45. data/test/lib/vedeu/configuration_test.rb +12 -0
  46. data/test/lib/vedeu/models/attributes/coercions_test.rb +3 -4
  47. data/test/lib/vedeu/models/interface_test.rb +0 -43
  48. data/test/lib/vedeu/models/keymap_test.rb +19 -0
  49. data/test/lib/vedeu/models/style_test.rb +10 -0
  50. data/test/lib/vedeu/output/refresh_test.rb +0 -12
  51. data/test/lib/vedeu/output/render_test.rb +51 -0
  52. data/test/lib/vedeu/repositories/buffers_test.rb +39 -12
  53. data/test/lib/vedeu/repositories/events_test.rb +6 -0
  54. data/test/lib/vedeu/repositories/focus_test.rb +12 -0
  55. data/test/lib/vedeu/repositories/keymap_validator_test.rb +81 -0
  56. data/test/lib/vedeu/repositories/keymaps_test.rb +254 -0
  57. data/test/lib/vedeu/support/common_test.rb +26 -0
  58. data/test/lib/vedeu/support/registrar_test.rb +68 -0
  59. data/vedeu.gemspec +1 -1
  60. metadata +18 -2
@@ -0,0 +1,239 @@
1
+ module Vedeu
2
+
3
+ # Repository for storing, retrieving and using defined keymaps.
4
+ #
5
+ # @api private
6
+ module Keymaps
7
+
8
+ include Vedeu::Common
9
+ extend self
10
+
11
+ # Stores the keymap attributes defined by the API.
12
+ #
13
+ # @param attributes [Hash]
14
+ # @return [TrueClass|KeyInUse|FalseClass]
15
+ def add(attributes)
16
+ return false unless defined_value?(attributes[:keys])
17
+
18
+ if defined_value?(attributes[:interfaces])
19
+ attributes[:interfaces].map do |interface|
20
+ storage.store(interface, {}) unless registered?(interface)
21
+
22
+ register(attributes, interface)
23
+ end
24
+
25
+ else
26
+ register(attributes)
27
+
28
+ end
29
+
30
+ true
31
+ end
32
+
33
+ # Return the whole repository of keymaps.
34
+ #
35
+ # @return [Hash]
36
+ def all
37
+ storage
38
+ end
39
+
40
+ # Find a keymap by interface name.
41
+ #
42
+ # @param name [String]
43
+ # @return [Hash]
44
+ def find(name)
45
+ storage.fetch(name, {})
46
+ end
47
+
48
+ # Return a boolean indicating whether the key is registered as a global key.
49
+ #
50
+ # @param key [String|Symbol]
51
+ # @return [Boolean]
52
+ def global_key?(key)
53
+ global_keys.include?(key)
54
+ end
55
+
56
+ # Return the collection of global keys.
57
+ #
58
+ # @return [Array]
59
+ def global_keys
60
+ storage.fetch('_global_keymap_', {}).keys
61
+ end
62
+
63
+ # Return a boolean indicating whether the key is registered as an interface
64
+ # key. When an interface argument is provided, only that interface is
65
+ # checked.
66
+ #
67
+ # @param key [String|Symbol]
68
+ # @param interface [String]
69
+ # @return [Boolean]
70
+ def interface_key?(key, interface = '')
71
+ if defined_value?(interface)
72
+ find(interface).keys.include?(key)
73
+
74
+ else
75
+ interface_keys.include?(key)
76
+
77
+ end
78
+ end
79
+
80
+ # Return a collection of interface keys.
81
+ #
82
+ # @return [Hash]
83
+ def interface_keys
84
+ storage.reject do |k, _|
85
+ k == '_global_keymap_'
86
+ end.map { |_, v| v.keys }.flatten.uniq
87
+ end
88
+
89
+ # Returns a collection of the interface names of all the registered keymaps.
90
+ #
91
+ # @return [Array]
92
+ def registered
93
+ storage.keys
94
+ end
95
+
96
+ # Returns a boolean indicating whether the named interface has a keymap
97
+ # registered.
98
+ #
99
+ # @param name [String]
100
+ # @return [Boolean]
101
+ def registered?(name)
102
+ storage.key?(name)
103
+ end
104
+
105
+ # Reset the keymaps repository; removing all registered keymaps. Only the
106
+ # system keymap will remain.
107
+ #
108
+ # @return [Hash]
109
+ def reset
110
+ @_storage = in_memory
111
+ end
112
+
113
+ # Return a boolean indicating whether the key is registered as a system key.
114
+ #
115
+ # @param key [String|Symbol]
116
+ # @return [Boolean]
117
+ def system_key?(key)
118
+ system_keys.include?(key)
119
+ end
120
+
121
+ # Return a collection of system keys.
122
+ #
123
+ # @return [Array]
124
+ def system_keys
125
+ Configuration.system_keys.invert.keys
126
+ end
127
+
128
+ # Handles the keypress in your application. Can also be used to simulate a
129
+ # keypress.
130
+ #
131
+ # 1) Log the keypress if debugging is enabled.
132
+ # 2) Trigger the client application's `:key` event (it may not exist).
133
+ # 3) Determine if the key pertains to the focussed interface and action it,
134
+ # or check both global, then system keys to action it. Returns false if
135
+ # nothing can deal with it.
136
+ #
137
+ # @param key [String|Symbol] The key which was pressed. Escape sequences
138
+ # are also supported. Special keys like the F-keys are named as symbols;
139
+ # i.e. `:f4`. A list of these translations can be found at {Vedeu::Input}.
140
+ #
141
+ # @example
142
+ # Vedeu.keypress('s')
143
+ #
144
+ # @return [|FalseClass]
145
+ def use(key)
146
+ Vedeu.log("Key pressed: '#{key}'")
147
+
148
+ Vedeu.trigger(:key, key)
149
+
150
+ focussed_interface = Vedeu::Focus.current
151
+
152
+ if interface_key?(key, focussed_interface)
153
+ find(focussed_interface).fetch(key, noop).call
154
+
155
+ elsif global_key?(key)
156
+ find('_global_keymap_').fetch(key, noop).call
157
+
158
+ elsif system_key?(key)
159
+ system_key(key)
160
+
161
+ else
162
+ false
163
+
164
+ end
165
+ end
166
+
167
+ private
168
+
169
+ # Triggers the system event defined for this key.
170
+ #
171
+ # @param key [String|Symbol]
172
+ # @return []
173
+ def system_key(key)
174
+ action = Vedeu::Configuration.system_keys.key(key)
175
+ event = ['_', action, '_'].join.to_sym
176
+
177
+ Vedeu.trigger(event)
178
+ end
179
+
180
+ # @param key [String|Symbol]
181
+ # @param interface [String]
182
+ # @return []
183
+ def validate(key, interface = '')
184
+ Vedeu::KeymapValidator.check(storage, key, interface)
185
+ end
186
+
187
+ # Registers the key.
188
+ #
189
+ # @api private
190
+ # @param attributes [Hash]
191
+ # @param interface [String]
192
+ # @return []
193
+ def register(attributes, interface = '')
194
+ attributes[:keys].map do |keymap|
195
+ valid, message = validate(keymap[:key], interface)
196
+
197
+ fail KeyInUse, message unless valid
198
+
199
+ Vedeu.log("Registering key '#{keymap[:key]}' with " \
200
+ "'#{namespace(interface)}'")
201
+
202
+ storage[namespace(interface)]
203
+ .merge!({ keymap[:key] => keymap[:action] })
204
+ end
205
+ end
206
+
207
+ # Determine which interface to store the key with.
208
+ #
209
+ # @api private
210
+ # @param interface [String]
211
+ # @return [String]
212
+ def namespace(interface = '')
213
+ return defined_value?(interface) ? interface : '_global_keymap_'
214
+ end
215
+
216
+ # Returns a noop proc which when called returns :noop.
217
+ #
218
+ # @return [Proc]
219
+ def noop
220
+ proc { :noop }
221
+ end
222
+
223
+ # Access to the storage for this repository.
224
+ #
225
+ # @api private
226
+ # @return [Array]
227
+ def storage
228
+ @_storage ||= in_memory
229
+ end
230
+
231
+ # @api private
232
+ # @return [Array]
233
+ def in_memory
234
+ { '_global_keymap_' => {} }
235
+ end
236
+
237
+ end
238
+
239
+ end
@@ -5,6 +5,7 @@ module Vedeu
5
5
  # @api private
6
6
  module Menus
7
7
 
8
+ include Common
8
9
  extend self
9
10
 
10
11
  # System events which when called with the appropriate menu name will
@@ -25,7 +26,9 @@ module Vedeu
25
26
  # @param attributes [Hash]
26
27
  # @return [Hash|FalseClass]
27
28
  def add(attributes)
28
- return false if attributes[:name].empty?
29
+ return false unless defined_value?(attributes[:name])
30
+
31
+ Vedeu.log("Registering menu '#{attributes[:name]}'")
29
32
 
30
33
  storage.store(attributes[:name], attributes)
31
34
  end
@@ -57,7 +60,8 @@ module Vedeu
57
60
 
58
61
  # Returns a boolean indicating whether the named menu is registered.
59
62
  #
60
- # @return [TrueClass|FalseClass]
63
+ # @param name [String]
64
+ # @return [Boolean]
61
65
  def registered?(name)
62
66
  storage.key?(name)
63
67
  end
@@ -65,7 +69,7 @@ module Vedeu
65
69
  # Removes the menu from the repository and associated events.
66
70
  #
67
71
  # @param name [String]
68
- # @return [TrueClass|FalseClass]
72
+ # @return [Boolean]
69
73
  def remove(name)
70
74
  return false unless registered?(name)
71
75
 
@@ -95,12 +99,17 @@ module Vedeu
95
99
 
96
100
  private
97
101
 
102
+ # Access to the storage for this repository.
103
+ #
98
104
  # @api private
99
105
  # @return [Hash]
100
106
  def storage
101
107
  @_storage ||= in_memory
102
108
  end
103
109
 
110
+ # Returns an empty collection ready for the storing of menus by name with
111
+ # associated menu instance.
112
+ #
104
113
  # @api private
105
114
  # @return [Hash]
106
115
  def in_memory
@@ -7,8 +7,8 @@ module Vedeu
7
7
 
8
8
  # Returns a boolean indicating whether a variable has a useful value.
9
9
  #
10
- # @param variable [String|Array] The variable to check.
11
- # @return [TrueClass|FalseClass]
10
+ # @param variable [String|Symbol|Array] The variable to check.
11
+ # @return [Boolean]
12
12
  def defined_value?(variable)
13
13
  return true unless variable.nil? || variable.empty?
14
14
 
@@ -5,6 +5,9 @@ module Vedeu
5
5
  # @api private
6
6
  class Cursor
7
7
 
8
+ # @return [Hash]
9
+ attr_reader :attributes
10
+
8
11
  # @return [Fixnum]
9
12
  attr_reader :top
10
13
 
@@ -25,9 +25,9 @@ module Vedeu
25
25
  def trigger(*args)
26
26
  return execute(*args) unless debouncing? || throttling?
27
27
 
28
- return execute(*args) if debouncing? && set_executed > deadline
28
+ return execute(*args) if debouncing? && debounce_expired?
29
29
 
30
- return execute(*args) if throttling? && elapsed_time > delay
30
+ return execute(*args) if throttling? && throttle_expired?
31
31
  end
32
32
 
33
33
  private
@@ -63,19 +63,36 @@ module Vedeu
63
63
  # throttling.
64
64
  #
65
65
  # @api private
66
- # @return [TrueClass|FalseClass]
66
+ # @return [Boolean]
67
67
  def throttling?
68
68
  set_time
69
69
 
70
70
  options[:delay] > 0
71
71
  end
72
72
 
73
+ # Returns a boolean indicating whether the throttle has expired.
74
+ #
75
+ # @api private
76
+ # @return [Boolean]
77
+ def throttle_expired?
78
+ if elapsed_time > delay
79
+ Vedeu.log("Event throttle has expired for '#{event_name}', executing " \
80
+ "event.")
81
+ true
82
+
83
+ else
84
+ Vedeu.log("Event throttle not yet expired for '#{event_name}'.")
85
+ false
86
+
87
+ end
88
+ end
89
+
73
90
  # Returns a boolean indicating whether debouncing is required for this
74
91
  # event. Setting the debounce option to any value greater than 0 will
75
92
  # enable debouncing.
76
93
  #
77
94
  # @api private
78
- # @return [TrueClass|FalseClass]
95
+ # @return [Boolean]
79
96
  def debouncing?
80
97
  set_time
81
98
 
@@ -84,6 +101,23 @@ module Vedeu
84
101
  options[:debounce] > 0
85
102
  end
86
103
 
104
+ # Returns a boolean indicating whether the debounce has expired.
105
+ #
106
+ # @api private
107
+ # @return [Boolean]
108
+ def debounce_expired?
109
+ if set_executed > deadline
110
+ Vedeu.log("Event debounce has expired for '#{event_name}', executing " \
111
+ "event.")
112
+ true
113
+
114
+ else
115
+ Vedeu.log("Event debounce not yet expired for '#{event_name}'.")
116
+ false
117
+
118
+ end
119
+ end
120
+
87
121
  # @api private
88
122
  # @return [Float]
89
123
  def elapsed_time
@@ -109,7 +143,7 @@ module Vedeu
109
143
  end
110
144
 
111
145
  # @api private
112
- # @return [TrueClass|FalseClass]
146
+ # @return [Boolean]
113
147
  def has_deadline?
114
148
  @deadline > 0
115
149
  end
@@ -128,6 +162,12 @@ module Vedeu
128
162
  nil
129
163
  end
130
164
 
165
+ # @api private
166
+ # @return [String]
167
+ def event_name
168
+ options[:event_name].to_s
169
+ end
170
+
131
171
  # @api private
132
172
  # @return [Fixnum|Float]
133
173
  def debounce
@@ -150,8 +190,9 @@ module Vedeu
150
190
  # @return [Hash]
151
191
  def defaults
152
192
  {
153
- delay: 0.0,
154
- debounce: 0.0
193
+ delay: 0.0,
194
+ debounce: 0.0,
195
+ event_name: '',
155
196
  }
156
197
  end
157
198
 
@@ -63,7 +63,7 @@ module Vedeu
63
63
  end
64
64
 
65
65
  # @api private
66
- # @return [TrueClass|FalseClass]
66
+ # @return [Boolean]
67
67
  def out_of_range?
68
68
  value < 1 || value > 12
69
69
  end
@@ -0,0 +1,66 @@
1
+ module Vedeu
2
+
3
+ # When the client application has defined interfaces to be used, the Registrar
4
+ # stores these interfaces into various repositories for later use.
5
+ #
6
+ # @api private
7
+ class Registrar
8
+
9
+ include Common
10
+
11
+ # @param attributes [Hash]
12
+ # @return [TrueClass|]
13
+ def self.record(attributes = {})
14
+ new(attributes).record
15
+ end
16
+
17
+ # @param attributes [Hash]
18
+ # @return [Registrar]
19
+ def initialize(attributes = {})
20
+ @attributes = attributes
21
+ end
22
+
23
+ # Adds the attributes to a variety of repositories to use later.
24
+ #
25
+ # @return [TrueClass|MissingRequired]
26
+ def record
27
+ validate_attributes!
28
+
29
+ Vedeu::Buffers.add(attributes)
30
+
31
+ Vedeu::Interfaces.add(attributes)
32
+
33
+ Vedeu::Groups.add(attributes)
34
+
35
+ Vedeu::Focus.add(attributes)
36
+
37
+ true
38
+ end
39
+
40
+ private
41
+
42
+ # Client application defined settings for interfaces etc.
43
+ attr_reader :attributes
44
+
45
+ # At present, validates that attributes has a `:name` key that is not nil or
46
+ # empty.
47
+ #
48
+ # @api private
49
+ # @return [TrueClass|MissingRequired]
50
+ def validate_attributes!
51
+ return exception unless attributes.key?(:name)
52
+ return exception unless defined_value?(attributes[:name])
53
+
54
+ true
55
+ end
56
+
57
+ # Raises the MissingRequired exception.
58
+ #
59
+ # @see Vedeu::MissingRequired
60
+ def exception
61
+ fail MissingRequired, 'Cannot store data without a name attribute.'
62
+ end
63
+
64
+ end
65
+
66
+ end