vedeu 0.1.15 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +2 -0
  3. data/README.md +116 -98
  4. data/lib/vedeu.rb +24 -11
  5. data/lib/vedeu/api/api.rb +174 -33
  6. data/lib/vedeu/api/composition.rb +2 -13
  7. data/lib/vedeu/api/helpers.rb +41 -0
  8. data/lib/vedeu/api/interface.rb +147 -34
  9. data/lib/vedeu/api/line.rb +47 -0
  10. data/lib/vedeu/api/stream.rb +41 -0
  11. data/lib/vedeu/application.rb +9 -2
  12. data/lib/vedeu/configuration.rb +66 -8
  13. data/lib/vedeu/launcher.rb +11 -0
  14. data/lib/vedeu/models/attributes/background.rb +29 -0
  15. data/lib/vedeu/models/attributes/coercions.rb +30 -0
  16. data/lib/vedeu/models/attributes/colour_translator.rb +106 -16
  17. data/lib/vedeu/models/attributes/foreground.rb +29 -0
  18. data/lib/vedeu/models/attributes/presentation.rb +15 -0
  19. data/lib/vedeu/models/colour.rb +12 -7
  20. data/lib/vedeu/models/composition.rb +23 -5
  21. data/lib/vedeu/models/geometry.rb +101 -16
  22. data/lib/vedeu/models/interface.rb +36 -28
  23. data/lib/vedeu/models/line.rb +16 -14
  24. data/lib/vedeu/models/stream.rb +17 -25
  25. data/lib/vedeu/models/style.rb +29 -0
  26. data/lib/vedeu/support/buffer.rb +36 -21
  27. data/lib/vedeu/support/buffers.rb +88 -0
  28. data/lib/vedeu/{output → support}/clear.rb +9 -2
  29. data/lib/vedeu/support/esc.rb +16 -2
  30. data/lib/vedeu/support/event.rb +104 -0
  31. data/lib/vedeu/support/events.rb +61 -0
  32. data/lib/vedeu/support/focus.rb +69 -0
  33. data/lib/vedeu/{api → support}/grid.rb +29 -25
  34. data/lib/vedeu/support/groups.rb +51 -0
  35. data/lib/vedeu/support/input.rb +5 -0
  36. data/lib/vedeu/support/log.rb +105 -0
  37. data/lib/vedeu/support/menu.rb +19 -0
  38. data/lib/vedeu/support/position.rb +7 -0
  39. data/lib/vedeu/{output → support}/render.rb +12 -6
  40. data/lib/vedeu/support/terminal.rb +21 -0
  41. data/lib/vedeu/support/trace.rb +54 -0
  42. data/lib/vedeu/{output → support}/view.rb +15 -10
  43. data/test/lib/vedeu/api/api_test.rb +55 -29
  44. data/test/lib/vedeu/api/interface_test.rb +3 -49
  45. data/test/lib/vedeu/api/line_test.rb +71 -0
  46. data/test/lib/vedeu/api/stream_test.rb +25 -0
  47. data/test/lib/vedeu/models/attributes/background_test.rb +83 -0
  48. data/test/lib/vedeu/models/attributes/coercer_test.rb +52 -0
  49. data/test/lib/vedeu/models/attributes/foreground_test.rb +83 -0
  50. data/test/lib/vedeu/models/attributes/presentation_test.rb +30 -0
  51. data/test/lib/vedeu/models/composition_test.rb +6 -6
  52. data/test/lib/vedeu/models/geometry_test.rb +34 -0
  53. data/test/lib/vedeu/models/interface_test.rb +0 -12
  54. data/test/lib/vedeu/models/line_test.rb +1 -13
  55. data/test/lib/vedeu/models/stream_test.rb +4 -50
  56. data/test/lib/vedeu/models/style_test.rb +39 -0
  57. data/test/lib/vedeu/support/buffer_test.rb +7 -3
  58. data/test/lib/vedeu/support/buffers_test.rb +15 -0
  59. data/test/lib/vedeu/{output → support}/clear_test.rb +8 -1
  60. data/test/lib/vedeu/support/esc_test.rb +2 -2
  61. data/test/lib/vedeu/support/event_test.rb +41 -0
  62. data/test/lib/vedeu/support/events_test.rb +70 -0
  63. data/test/lib/vedeu/support/focus_test.rb +114 -0
  64. data/test/lib/vedeu/support/grid_test.rb +31 -0
  65. data/test/lib/vedeu/support/groups_test.rb +65 -0
  66. data/test/lib/vedeu/{output → support}/render_test.rb +8 -1
  67. data/test/lib/vedeu/{output → support}/view_test.rb +1 -1
  68. data/test/test_helper.rb +3 -1
  69. data/vedeu.gemspec +3 -2
  70. metadata +67 -31
  71. data/lib/vedeu/api/events.rb +0 -46
  72. data/lib/vedeu/api/log.rb +0 -84
  73. data/lib/vedeu/models/attributes/attributes.rb +0 -25
  74. data/lib/vedeu/models/store.rb +0 -29
  75. data/lib/vedeu/output/buffers.rb +0 -65
  76. data/test/lib/vedeu/api/events_test.rb +0 -36
  77. data/test/lib/vedeu/api/grid_test.rb +0 -33
  78. data/test/lib/vedeu/models/attributes/attributes_test.rb +0 -39
  79. data/test/lib/vedeu/models/attributes/colour_translator_test.rb +0 -78
  80. data/test/lib/vedeu/models/store_test.rb +0 -57
  81. data/test/lib/vedeu/output/buffers_test.rb +0 -35
@@ -0,0 +1,29 @@
1
+ module Vedeu
2
+ class Style
3
+
4
+ attr_reader :values
5
+
6
+ # @param values [String|Array]
7
+ # @return [Style]
8
+ def initialize(values)
9
+ @values = values
10
+ end
11
+
12
+ # @return [String]
13
+ def to_s
14
+ escape_sequences
15
+ end
16
+
17
+ private
18
+
19
+ def escape_sequences
20
+ @_sequences ||= if values.nil? || values.empty?
21
+ ''
22
+
23
+ else
24
+ Array(values).flatten.map { |value| Esc.string(value) }.join
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,41 +1,56 @@
1
1
  module Vedeu
2
2
  class Buffer
3
- attr_reader :clear, :current, :group, :name, :_next
4
3
 
5
- def initialize(vars)
6
- @vars = vars
7
- @name = vars.fetch(:name)
8
- @clear = vars.fetch(:clear)
9
- @current = vars.fetch(:current)
10
- @group = vars.fetch(:group)
11
- @_next = vars.fetch(:next)
4
+ attr_reader :back, :front, :interface
5
+
6
+ # @param attributes [Hash]
7
+ # @return [Buffer]
8
+ def initialize(attributes = {})
9
+ @attributes = attributes
10
+
11
+ @back = attributes.fetch(:back)
12
+ @front = attributes.fetch(:front)
13
+ @interface = attributes.fetch(:interface)
12
14
  end
13
15
 
14
- def enqueue(sequence)
15
- merge({ next: sequence })
16
+ # @param view [Interface]
17
+ # @return [Buffer]
18
+ def enqueue(view)
19
+ merge({ back: view })
16
20
  end
17
21
 
22
+ # @return [Buffer]
18
23
  def refresh
19
- sequence = if !_next.empty?
20
- merge({ current: _next, next: '' }).current
21
-
22
- elsif current.empty?
23
- clear
24
+ return merge({ front: back, back: nil }).render if content_available?
25
+ return clear if no_content_available?
26
+ return render
27
+ end
24
28
 
25
- else
26
- current
29
+ def render
30
+ Terminal.output(front.to_s)
27
31
 
28
- end
32
+ self
33
+ end
29
34
 
30
- Terminal.output(sequence)
35
+ def clear
36
+ Terminal.output(interface.clear)
31
37
 
32
38
  self
33
39
  end
34
40
 
35
41
  private
36
42
 
37
- def merge(vars)
38
- Buffer.new(@vars.merge(vars))
43
+ def merge(new_attributes)
44
+ Buffer.new(@attributes.merge(new_attributes))
39
45
  end
46
+
47
+ def content_available?
48
+ !!(back)
49
+ end
50
+
51
+ def no_content_available?
52
+ front.nil?
53
+ end
54
+
40
55
  end
41
56
  end
@@ -0,0 +1,88 @@
1
+ module Vedeu
2
+ module Buffers
3
+
4
+ extend self
5
+
6
+ # @param attributes [Hash]
7
+ # @return [Hash]
8
+ def create(attributes)
9
+ store_attributes(attributes)
10
+
11
+ groups.add(attributes[:group], attributes[:name], attributes[:delay])
12
+
13
+ store_interface(Interface.new(attributes))
14
+ end
15
+
16
+ # @return [Hash]
17
+ def reset
18
+ @_storage = {}
19
+ @_buffers = {}
20
+ groups.reset
21
+ end
22
+
23
+ # @param name [String]
24
+ # @return [Hash]
25
+ def retrieve_attributes(name)
26
+ storage.fetch(name) { fail EntityNotFound, 'Interface was not found.' }
27
+ end
28
+
29
+ # @param name [String]
30
+ # @return [Buffer]
31
+ def retrieve_interface(name)
32
+ buffers.fetch(name) { fail EntityNotFound, 'Interface was not found.' }
33
+ end
34
+
35
+ # @param attributes [Hash]
36
+ # @return [Hash]
37
+ def store_attributes(attributes)
38
+ storage.store(attributes[:name], attributes)
39
+ end
40
+
41
+ # @param interface [Interface]
42
+ # @return [Buffer]
43
+ def store_interface(interface)
44
+ update(interface.name,
45
+ Buffer.new(interface: interface, back: nil, front: nil))
46
+ end
47
+
48
+ # @param name [String]
49
+ # @param view [Interface]
50
+ # @return []
51
+ def enqueue(name, view)
52
+ update(name, retrieve_interface(name).enqueue(view))
53
+ end
54
+
55
+ # @return [Array]
56
+ def refresh_all
57
+ buffers.keys.map { |name| refresh(name) }
58
+ end
59
+
60
+ # @return [Array]
61
+ def refresh_group(group_name)
62
+ groups.find(group_name).map { |name| refresh(name) }
63
+ end
64
+
65
+ def refresh(name)
66
+ update(name, retrieve_interface(name).refresh)
67
+ end
68
+
69
+ private
70
+
71
+ def update(name, buffer)
72
+ buffers.store(name, buffer)
73
+ end
74
+
75
+ def groups
76
+ @_groups ||= Groups.new
77
+ end
78
+
79
+ def buffers
80
+ @_buffers ||= {}
81
+ end
82
+
83
+ def storage
84
+ @_storage ||= {}
85
+ end
86
+
87
+ end
88
+ end
@@ -1,16 +1,22 @@
1
1
  module Vedeu
2
2
  class Clear
3
+
4
+ # @param interface [Interface]
5
+ # @return [String]
3
6
  def self.call(interface)
4
7
  new(interface).clear
5
8
  end
6
9
 
10
+ # @param interface [Interface]
11
+ # @return [Clear]
7
12
  def initialize(interface)
8
13
  @interface = interface
9
14
  end
10
15
 
16
+ # @return [String]
11
17
  def clear
12
18
  rows.inject([colours]) do |line, index|
13
- line << interface.origin(index) { ' ' * interface.width }
19
+ line << interface.origin(index) { ' ' * interface.viewport_width }
14
20
  end.join
15
21
  end
16
22
 
@@ -23,7 +29,8 @@ module Vedeu
23
29
  end
24
30
 
25
31
  def rows
26
- interface.height.times
32
+ interface.viewport_height.times
27
33
  end
34
+
28
35
  end
29
36
  end
@@ -1,18 +1,25 @@
1
1
  module Vedeu
2
2
  module Esc
3
+
3
4
  extend self
4
5
 
6
+ # @param y [Fixnum]
7
+ # @param x [Fixnum]
8
+ # @param block [Proc]
9
+ # @return [String]
5
10
  def set_position(y = 1, x = 1, &block)
6
11
  Position.new(y, x).to_s(&block)
7
12
  end
8
13
 
14
+ # @param value [String]
15
+ # @return [String]
9
16
  def string(value = '')
10
17
  case value
11
18
  when 'bg_reset' then "\e[48;2;49m"
12
19
  when 'blink' then "\e[5m"
13
20
  when 'blink_off' then "\e[25m"
14
21
  when 'bold' then "\e[1m"
15
- when 'bold_off' then "\e[21m"
22
+ when 'bold_off' then "\e[22m"
16
23
  when 'clear' then "\e[38;2;39m\e[48;2;49m\e[2J"
17
24
  when 'clear_line' then "\e[38;2;39m\e[48;2;49m\e[2K"
18
25
  when 'colour_reset' then "\e[38;2;39m\e[48;2;49m"
@@ -23,7 +30,7 @@ module Vedeu
23
30
  when 'negative' then "\e[7m"
24
31
  when 'positive' then "\e[27m"
25
32
  when 'reset' then "\e[0m"
26
- when 'normal' then "\e[24m\e[21m\e[27m"
33
+ when 'normal' then "\e[24m\e[22m\e[27m"
27
34
  when 'dim' then "\e[2m"
28
35
  when 'show_cursor' then "\e[?25h"
29
36
  when 'underline' then "\e[4m"
@@ -32,5 +39,12 @@ module Vedeu
32
39
  ''
33
40
  end
34
41
  end
42
+
43
+ # private
44
+
45
+ # def method_missing(method, *args, &block)
46
+ # self.send(:string, method, &block)
47
+ # end
48
+
35
49
  end
36
50
  end
@@ -0,0 +1,104 @@
1
+ module Vedeu
2
+ class Event
3
+
4
+ # @param closure [Proc]
5
+ # @param options [Hash]
6
+ # @return [Event]
7
+ def initialize(closure, options = {})
8
+ @closure = closure
9
+ @options = options
10
+ @deadline = 0
11
+ @executed_at = 0
12
+ @now = 0
13
+ end
14
+
15
+ # @params args [Array]
16
+ # @return []
17
+ def trigger(*args)
18
+ return execute(*args) unless debouncing? || throttling?
19
+
20
+ return execute(*args) if debouncing? && set_executed > deadline
21
+
22
+ return execute(*args) if throttling? && elapsed_time > delay
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :closure
28
+ attr_accessor :deadline, :executed_at, :now
29
+
30
+ def execute(*args)
31
+ reset_deadline
32
+
33
+ set_executed
34
+
35
+ reset_time
36
+
37
+ closure.call(*args)
38
+ end
39
+
40
+ def throttling?
41
+ set_time
42
+
43
+ options[:delay] > 0
44
+ end
45
+
46
+ def debouncing?
47
+ set_time
48
+
49
+ set_deadline unless has_deadline?
50
+
51
+ options[:debounce] > 0
52
+ end
53
+
54
+ def elapsed_time
55
+ now - @executed_at
56
+ end
57
+
58
+ def set_executed
59
+ @executed_at = now
60
+ end
61
+
62
+ def set_time
63
+ @now = Time.now.to_f
64
+ end
65
+
66
+ def reset_time
67
+ @now = 0
68
+ end
69
+
70
+ def has_deadline?
71
+ @deadline > 0
72
+ end
73
+
74
+ def reset_deadline
75
+ @deadline = 0
76
+ end
77
+
78
+ def set_deadline
79
+ @deadline = now + debounce
80
+
81
+ nil
82
+ end
83
+
84
+ def debounce
85
+ options[:debounce]
86
+ end
87
+
88
+ def delay
89
+ options[:delay]
90
+ end
91
+
92
+ def options
93
+ defaults.merge!(@options)
94
+ end
95
+
96
+ def defaults
97
+ {
98
+ delay: 0,
99
+ debounce: 0
100
+ }
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,61 @@
1
+ module Vedeu
2
+ class Events
3
+
4
+ # @param block [Proc]
5
+ # @return [Events]
6
+ def initialize(&block)
7
+ @handlers = Hash.new { |hash, key| hash[key] = { events: [] } }
8
+
9
+ instance_eval(&block) if block_given?
10
+ end
11
+
12
+ # @param object []
13
+ # @param block [Proc]
14
+ # @return []
15
+ def add(object, &block)
16
+ @self_before_instance_eval = eval('self', block.binding)
17
+
18
+ instance_eval(&block)
19
+ end
20
+
21
+ # @see Vedeu::API#event
22
+ def event(name, opts = {}, &block)
23
+ handlers[name][:events] << Event.new(block, opts)
24
+ handlers[name]
25
+ end
26
+
27
+ # Unregisters the event by name, effectively deleting the associated events
28
+ # bound with it also.
29
+ #
30
+ # @param name [Symbol]
31
+ # @return []
32
+ def unevent(name)
33
+ handlers.delete_if { |k, v| k == name }
34
+ end
35
+
36
+ # Returns a collection of the names of all the registered events.
37
+ #
38
+ # @return [Array]
39
+ def registered
40
+ handlers.keys
41
+ end
42
+
43
+ # @see Vedeu::API#trigger
44
+ def trigger(name, *args)
45
+ handlers[name][:events].each { |event| event.trigger(*args) }
46
+ end
47
+
48
+ def reset
49
+ @handlers = Hash.new { |hash, key| hash[key] = { events: [] } }
50
+ end
51
+
52
+ private
53
+
54
+ attr_reader :handlers
55
+
56
+ def method_missing(method, *args, &block)
57
+ @self_before_instance_eval.send(method, *args, &block)
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,69 @@
1
+ module Vedeu
2
+ NoInterfacesDefined = Class.new(StandardError)
3
+ InterfaceNotFound = Class.new(StandardError)
4
+
5
+ # Maintains which interface is current in focus.
6
+ class Focus
7
+
8
+ def initialize
9
+ register_events
10
+
11
+ self
12
+ end
13
+
14
+ def add(name)
15
+ if registered?(name)
16
+ storage
17
+
18
+ else
19
+ storage << name
20
+
21
+ end
22
+ end
23
+
24
+ def by_name(name)
25
+ fail InterfaceNotFound unless storage.include?(name)
26
+
27
+ storage.rotate!(storage.index(name))
28
+
29
+ current
30
+ end
31
+
32
+ def current
33
+ fail NoInterfacesDefined if storage.empty?
34
+
35
+ storage.first
36
+ end
37
+
38
+ def next_item
39
+ storage.rotate!
40
+
41
+ current
42
+ end
43
+
44
+ def prev_item
45
+ storage.rotate!(-1)
46
+
47
+ current
48
+ end
49
+
50
+ def register_events
51
+ Vedeu.event(:_focus_next_) { next_item }
52
+ Vedeu.event(:_focus_prev_) { prev_item }
53
+ Vedeu.event(:_focus_by_name_) { |name| by_name(name) }
54
+ end
55
+
56
+ private
57
+
58
+ def registered?(name)
59
+ return false if storage.empty?
60
+
61
+ storage.include?(name)
62
+ end
63
+
64
+ def storage
65
+ @storage ||= []
66
+ end
67
+
68
+ end
69
+ end