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
@@ -50,7 +50,10 @@ module Vedeu
50
50
 
51
51
  # The client application may have created a line that us too long for the
52
52
  # interface. This code tries to truncate streams whilst preserving styles
53
- # and colours.
53
+ # and colours. To achieve this, it successively checks each stream length
54
+ # against remaining line length and truncates the stream data if it
55
+ # exceeds the line length. Further stream data that does not fit is
56
+ # discarded.
54
57
  #
55
58
  # @api private
56
59
  # @return [Array]
@@ -60,32 +63,24 @@ module Vedeu
60
63
  lines.map do |line|
61
64
  if exceeds_width?(line)
62
65
  line_length = 0
63
- processed = []
64
- line.streams.each do |stream|
66
+ new_streams = []
67
+
68
+ new_streams = line.streams.map do |stream|
65
69
  next if stream.text.empty?
66
70
 
67
71
  if (line_length += stream.text.size) >= width
68
72
  remainder = width - line_length
73
+ truncated = truncate(stream.text, remainder)
69
74
 
70
- processed << Stream.new({
71
- colour: stream.colour.attributes,
72
- style: stream.style.values,
73
- text: truncate(stream.text, remainder),
74
- parent: line.view_attributes,
75
- })
75
+ build_stream(line, stream, truncated)
76
76
 
77
77
  else
78
- processed << stream
78
+ stream
79
79
 
80
80
  end
81
81
  end
82
82
 
83
- Line.new({
84
- colour: line.colour.attributes,
85
- streams: processed,
86
- style: line.style.values,
87
- parent: interface.view_attributes,
88
- })
83
+ build_line(line, new_streams)
89
84
 
90
85
  else
91
86
  line
@@ -94,13 +89,45 @@ module Vedeu
94
89
  end
95
90
  end
96
91
 
92
+ # Builds a new Stream object with the newly truncated text and previous
93
+ # attributes.
94
+ #
95
+ # @api private
96
+ # @param line [Line]
97
+ # @param stream [Stream]
98
+ # @param text [String]
99
+ # @return [Stream]
100
+ def build_stream(line, stream, text)
101
+ attributes = stream.view_attributes.merge!({
102
+ parent: line.view_attributes,
103
+ text: text,
104
+ })
105
+
106
+ Stream.new(attributes)
107
+ end
108
+
109
+ # Builds a new Line object with the new streams and previous attributes.
110
+ #
111
+ # @api private
112
+ # @param line [Line]
113
+ # @param streams [Array]
114
+ # @return [Line]
115
+ def build_line(line, streams)
116
+ attributes = line.view_attributes.merge!({
117
+ parent: interface.view_attributes,
118
+ streams: streams,
119
+ })
120
+
121
+ Line.new(attributes)
122
+ end
123
+
97
124
  # Converts all streams within a line into a single line of text to then
98
125
  # check that this line (without formatting, as that is not visible) exceeds
99
126
  # the width of the interface.
100
127
  #
101
128
  # @api private
102
129
  # @param line [Line]
103
- # @return [TrueClass|FalseClass]
130
+ # @return [Boolean]
104
131
  def exceeds_width?(line)
105
132
  line.streams.map(&:text).join.size > width
106
133
  end
@@ -4,6 +4,9 @@ module Vedeu
4
4
  # This method should contain attributes required to build a view or views.
5
5
  # These attributes will be added to the back buffer of each interface
6
6
  # mentioned, to be rendered upon next refresh.
7
+ #
8
+ # @deprecated May disappear in 0.3.0. Prefer {Vedeu::API#render} instead.
9
+ # @see Vedeu::API#render
7
10
  class View
8
11
 
9
12
  include Vedeu::API
@@ -9,28 +9,16 @@ module Vedeu
9
9
  include Vedeu::Common
10
10
  extend self
11
11
 
12
- # @param attributes [Hash]
13
- # @return [Hash]
14
- def create(attributes)
15
- add(attributes)
16
-
17
- Vedeu::Interfaces.add(attributes)
18
- Vedeu::Refresh.add_interface(attributes)
19
-
20
- Vedeu::Groups.add(attributes)
21
- Vedeu::Refresh.add_group(attributes)
22
-
23
- Vedeu::Focus.add(attributes)
24
- end
25
-
26
12
  # Add an interface view into the back buffer. If the buffer is already
27
- # registered, then we preserve its front buffer.
13
+ # registered, then we preserve its front buffer. Returns the name of the
14
+ # buffer added to storage.
28
15
  #
29
16
  # @param attributes [Hash]
30
- # @return [Hash]
17
+ # @return [String]
31
18
  def add(attributes)
32
19
  if registered?(attributes[:name])
33
20
  buffer = find(attributes[:name])
21
+
34
22
  buffer[:back_buffer] = attributes
35
23
 
36
24
  else
@@ -41,7 +29,7 @@ module Vedeu
41
29
 
42
30
  end
43
31
 
44
- storage
32
+ attributes[:name]
45
33
  end
46
34
 
47
35
  # Find the buffer by name.
@@ -72,10 +60,10 @@ module Vedeu
72
60
  def latest(name)
73
61
  if new_content?(name)
74
62
  swap_buffers(name)
75
- content(name)
63
+ front_buffer(name)
76
64
 
77
65
  elsif old_content?(name)
78
- content(name)
66
+ front_buffer(name)
79
67
 
80
68
  else
81
69
  nil
@@ -83,16 +71,35 @@ module Vedeu
83
71
  end
84
72
  end
85
73
 
86
- # Returns the named front buffer.
74
+ # Returns a collection of the names of all registered buffers.
75
+ #
76
+ # @return [Array]
77
+ def registered
78
+ storage.keys
79
+ end
80
+
81
+ # Returns a boolean indicating whether the named buffer is registered.
87
82
  #
83
+ # @api private
88
84
  # @param name [String]
85
+ # @return [Boolean]
86
+ def registered?(name)
87
+ storage.key?(name)
88
+ end
89
+
90
+ # Reset the buffers repository; removing all buffers. This does not delete
91
+ # the interfaces themselves.
92
+ #
89
93
  # @return [Hash]
90
- def content(name)
91
- front_buffer(name)
94
+ def reset
95
+ @_storage = in_memory
92
96
  end
93
97
 
98
+ private
99
+
94
100
  # Swap the named back buffer into the front buffer of the same name.
95
101
  #
102
+ # @api private
96
103
  # @param name [String]
97
104
  # @return [Hash]
98
105
  def swap_buffers(name)
@@ -104,21 +111,11 @@ module Vedeu
104
111
  })
105
112
  end
106
113
 
107
- # Reset the buffers repository; removing all buffers. This does not delete
108
- # the interfaces themselves.
109
- #
110
- # @return [Hash]
111
- def reset
112
- @_storage = in_memory
113
- end
114
-
115
- private
116
-
117
114
  # Return a boolean indicating whether the named back buffer has new content.
118
115
  #
119
116
  # @api private
120
117
  # @param name [String]
121
- # @return [TrueClass|FalseClass]
118
+ # @return [Boolean]
122
119
  def new_content?(name)
123
120
  defined_value?(back_buffer(name))
124
121
  end
@@ -127,7 +124,7 @@ module Vedeu
127
124
  #
128
125
  # @api private
129
126
  # @param name [String]
130
- # @return [TrueClass|FalseClass]
127
+ # @return [Boolean]
131
128
  def old_content?(name)
132
129
  defined_value?(front_buffer(name))
133
130
  end
@@ -150,15 +147,8 @@ module Vedeu
150
147
  find(name).fetch(:front_buffer, nil)
151
148
  end
152
149
 
153
- # Returns a boolean indicating whether the named buffer is registered.
150
+ # Access to the storage for this repository.
154
151
  #
155
- # @api private
156
- # @param name [String]
157
- # @return [TrueClass|FalseClass]
158
- def registered?(name)
159
- storage.key?(name)
160
- end
161
-
162
152
  # @api private
163
153
  # @return [Hash]
164
154
  def storage
@@ -16,18 +16,13 @@ module Vedeu
16
16
  instance_eval(&block) if block_given?
17
17
  end
18
18
 
19
- # @param object []
20
- # @param block [Proc]
21
- # @return []
22
- def add(object, &block)
23
- @self_before_instance_eval = eval('self', block.binding)
24
-
25
- instance_eval(&block)
26
- end
27
-
28
19
  # @see Vedeu::API#event
29
20
  def event(name, opts = {}, &block)
30
- handlers[name][:events] << Event.new(block, opts)
21
+ Vedeu.log("Registering event '#{name}'")
22
+
23
+ options = opts.merge!({ event_name: name })
24
+
25
+ handlers[name][:events] << Event.new(block, options)
31
26
  handlers[name]
32
27
  end
33
28
 
@@ -45,7 +40,9 @@ module Vedeu
45
40
 
46
41
  # Returns a Boolean indicating whether the named event is registered.
47
42
  #
48
- # @return [TrueClass|FalseClass]
43
+ # @api private
44
+ # @param name [Symbol] The name of the event to check.
45
+ # @return [Boolean]
49
46
  def registered?(name)
50
47
  handlers.key?(name)
51
48
  end
@@ -41,6 +41,8 @@ module Vedeu
41
41
  def current
42
42
  fail NoInterfacesDefined if storage.empty?
43
43
 
44
+ Vedeu.log("Interface in focus: '#{storage.first}'")
45
+
44
46
  storage.first
45
47
  end
46
48
 
@@ -69,32 +71,32 @@ module Vedeu
69
71
  storage
70
72
  end
71
73
 
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
74
  # Returns a boolean indicating whether the named interface is registered.
83
75
  #
84
76
  # @api private
85
- # @return [TrueClass|FalseClass]
77
+ # @return [Boolean]
86
78
  def registered?(name)
87
79
  return false if storage.empty?
88
80
 
89
81
  storage.include?(name)
90
82
  end
91
83
 
92
- # Provides accessor to the in-memory storage.
84
+ # Reset the focus repository; removing all items. This does not delete
85
+ # the interfaces themselves.
86
+ #
87
+ # @return [Hash]
88
+ def reset
89
+ @_storage = in_memory
90
+ end
91
+
92
+ private
93
+
94
+ # Access to the storage for this repository.
93
95
  #
94
96
  # @api private
95
97
  # @return [Array]
96
98
  def storage
97
- @storage ||= in_memory
99
+ @_storage ||= in_memory
98
100
  end
99
101
 
100
102
  # Returns an empty collection ready for the storing of interface names.
@@ -5,6 +5,7 @@ module Vedeu
5
5
  # @api private
6
6
  module Groups
7
7
 
8
+ include Vedeu::Common
8
9
  extend self
9
10
 
10
11
  # Add an interface name to a group, creating the group if it doesn't already
@@ -13,9 +14,13 @@ module Vedeu
13
14
  # @param attributes [Hash]
14
15
  # @return [Groups|FalseClass]
15
16
  def add(attributes)
16
- return false if attributes[:group].empty?
17
+ return false unless defined_value?(attributes[:group])
17
18
 
18
19
  storage[attributes[:group]] << attributes[:name]
20
+
21
+ register_event(attributes)
22
+
23
+ true
19
24
  end
20
25
 
21
26
  # Return the whole repository.
@@ -45,7 +50,7 @@ module Vedeu
45
50
 
46
51
  # Returns a Boolean indicating whether the named group is registered.
47
52
  #
48
- # @return [TrueClass|FalseClass]
53
+ # @return [Boolean]
49
54
  def registered?(name)
50
55
  storage.key?(name)
51
56
  end
@@ -60,6 +65,19 @@ module Vedeu
60
65
 
61
66
  private
62
67
 
68
+ # @see Vedeu::Refresh.register_event
69
+ # @api private
70
+ # @param attributes [Hash]
71
+ # @return [Boolean]
72
+ def register_event(attributes)
73
+ name = attributes[:group]
74
+ delay = attributes[:delay] || 0.0
75
+
76
+ Vedeu::Refresh.register_event(:by_group, name, delay)
77
+ end
78
+
79
+ # Access to the storage for this repository.
80
+ #
63
81
  # @api private
64
82
  # @return [Hash]
65
83
  def storage
@@ -5,6 +5,7 @@ module Vedeu
5
5
  # @api private
6
6
  module Interfaces
7
7
 
8
+ include Vedeu::Common
8
9
  extend self
9
10
 
10
11
  # Stores the interface attributes defined by the API.
@@ -12,9 +13,15 @@ module Vedeu
12
13
  # @param attributes [Hash]
13
14
  # @return [Hash|FalseClass]
14
15
  def add(attributes)
15
- return false if attributes[:name].empty?
16
+ return false unless defined_value?(attributes[:name])
17
+
18
+ Vedeu.log("Registering interface '#{attributes[:name]}'")
16
19
 
17
20
  storage.store(attributes[:name], attributes)
21
+
22
+ register_event(attributes)
23
+
24
+ true
18
25
  end
19
26
 
20
27
  # Return the whole repository.
@@ -44,7 +51,7 @@ module Vedeu
44
51
 
45
52
  # Returns a boolean indicating whether the named interface is registered.
46
53
  #
47
- # @return [TrueClass|FalseClass]
54
+ # @return [Boolean]
48
55
  def registered?(name)
49
56
  storage.key?(name)
50
57
  end
@@ -60,6 +67,19 @@ module Vedeu
60
67
 
61
68
  private
62
69
 
70
+ # @see Vedeu::Refresh.register_event
71
+ # @api private
72
+ # @param attributes [Hash]
73
+ # @return [Boolean]
74
+ def register_event(attributes)
75
+ name = attributes[:name]
76
+ delay = attributes[:delay] || 0.0
77
+
78
+ Vedeu::Refresh.register_event(:by_name, name, delay)
79
+ end
80
+
81
+ # Access to the storage for this repository.
82
+ #
63
83
  # @api private
64
84
  # @return [Hash]
65
85
  def storage
@@ -0,0 +1,104 @@
1
+ module Vedeu
2
+
3
+ # Validates that a given key is can be used and is not already in-use, either
4
+ # by the same interface, globally or as a system key.
5
+ #
6
+ class KeymapValidator
7
+
8
+ include Common
9
+
10
+ # Checks the key is not in use by the system, is not already defined as a
11
+ # global key, is not already defined for the interface specified.
12
+ #
13
+ # @param storage [Hash]
14
+ # @param key [String|Symbol]
15
+ # @param interface [String]
16
+ # @return [Array] A boolean indicating validity, and a helpful message.
17
+ def self.check(storage, key, interface = '')
18
+ new(storage, key, interface).check
19
+ end
20
+
21
+ # Instantiates a new KeymapValidator instance.
22
+ #
23
+ # @param storage [Hash]
24
+ # @param key [String|Symbol]
25
+ # @param interface [String]
26
+ # @return [KeymapValidator]
27
+ def initialize(storage, key, interface = '')
28
+ @storage, @key, @interface = storage, key, interface
29
+ end
30
+
31
+ # @see KeymapValidator.check
32
+ def check
33
+ if system_key?(key)
34
+ [false, "#{fail_message(key)} by the system."]
35
+
36
+ elsif global_key?(key)
37
+ [false, "#{fail_message(key)} as a global key."]
38
+
39
+ elsif interface_key?(key, interface)
40
+ if defined_value?(interface)
41
+ [false, "#{fail_message(key)} by this interface."]
42
+
43
+ else
44
+ [false, "#{fail_message(key)} by another interface and therefore " \
45
+ 'cannot be global.']
46
+
47
+ end
48
+ else
49
+ [true, 'Key can be registered.']
50
+
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ attr_reader :storage, :key, :interface
57
+
58
+ # Returns a boolean indicating whether the key has been registered for the
59
+ # named interface's keymap. If no interface is specified, then it is
60
+ # assumed that the key is attempting to be registered globally, and so all
61
+ # interfaces are checked for this key. (A key cannot be global if an
62
+ # interface is using it.)
63
+ #
64
+ # @param key [String|Symbol]
65
+ # @param interface [String]
66
+ # @return [Boolean]
67
+ def interface_key?(key, interface = '')
68
+ if defined_value?(interface)
69
+ return false unless storage.key?(interface)
70
+
71
+ storage.fetch(interface).keys.include?(key)
72
+
73
+ else
74
+ storage.keys.reject do |keymap|
75
+ keymap == '_global_keymap_'
76
+ end.map { |name| storage[name].keys.include?(key) }.any?
77
+
78
+ end
79
+ end
80
+
81
+ # Returns a boolean indicating whether the key is in the global keymap.
82
+ #
83
+ # @param key [String|Symbol]
84
+ # @return [Boolean]
85
+ def global_key?(key)
86
+ storage.fetch('_global_keymap_').keys.include?(key)
87
+ end
88
+
89
+ # Returns a boolean indicating whether the key is in the system keymap.
90
+ # At present, it is not possible to redefine system keys.
91
+ #
92
+ # @param key [String|Symbol]
93
+ # @return [Boolean]
94
+ def system_key?(key)
95
+ Configuration.system_keys.values.include?(key)
96
+ end
97
+
98
+ def fail_message(key)
99
+ "Cannot register key '#{key.to_s}' as already in use"
100
+ end
101
+
102
+ end
103
+
104
+ end