vedeu 0.1.17 → 0.1.18

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/README.md +17 -3
  4. data/lib/vedeu.rb +12 -7
  5. data/lib/vedeu/api/api.rb +37 -13
  6. data/lib/vedeu/api/composition.rb +1 -6
  7. data/lib/vedeu/api/helpers.rb +2 -0
  8. data/lib/vedeu/api/interface.rb +47 -55
  9. data/lib/vedeu/api/line.rb +6 -0
  10. data/lib/vedeu/api/stream.rb +9 -1
  11. data/lib/vedeu/application.rb +38 -50
  12. data/lib/vedeu/configuration.rb +163 -44
  13. data/lib/vedeu/launcher.rb +3 -6
  14. data/lib/vedeu/models/attributes/background.rb +9 -1
  15. data/lib/vedeu/models/attributes/colour_translator.rb +40 -2
  16. data/lib/vedeu/models/attributes/foreground.rb +9 -1
  17. data/lib/vedeu/models/colour.rb +6 -0
  18. data/lib/vedeu/models/composition.rb +8 -1
  19. data/lib/vedeu/models/geometry.rb +27 -14
  20. data/lib/vedeu/models/interface.rb +59 -0
  21. data/lib/vedeu/models/line.rb +4 -0
  22. data/lib/vedeu/models/stream.rb +10 -0
  23. data/lib/vedeu/models/style.rb +2 -0
  24. data/lib/vedeu/support/buffer.rb +12 -1
  25. data/lib/vedeu/support/buffers.rb +10 -0
  26. data/lib/vedeu/support/clear.rb +4 -0
  27. data/lib/vedeu/support/esc.rb +26 -8
  28. data/lib/vedeu/support/event.rb +28 -0
  29. data/lib/vedeu/support/events.rb +2 -0
  30. data/lib/vedeu/support/focus.rb +14 -6
  31. data/lib/vedeu/support/grid.rb +6 -0
  32. data/lib/vedeu/support/groups.rb +13 -3
  33. data/lib/vedeu/support/input.rb +7 -2
  34. data/lib/vedeu/support/log.rb +7 -1
  35. data/lib/vedeu/support/position.rb +6 -0
  36. data/lib/vedeu/support/render.rb +38 -0
  37. data/lib/vedeu/support/terminal.rb +69 -15
  38. data/lib/vedeu/support/trace.rb +8 -0
  39. data/lib/vedeu/support/view.rb +6 -0
  40. data/test/integration/run_once_test.rb +26 -0
  41. data/test/lib/vedeu/api/api_test.rb +19 -6
  42. data/test/lib/vedeu/api/interface_test.rb +67 -1
  43. data/test/lib/vedeu/api/line_test.rb +10 -0
  44. data/test/lib/vedeu/api/stream_test.rb +8 -0
  45. data/test/lib/vedeu/configuration_test.rb +119 -12
  46. data/test/lib/vedeu/models/attributes/background_test.rb +1 -1
  47. data/test/lib/vedeu/models/attributes/foreground_test.rb +1 -1
  48. data/test/lib/vedeu/models/interface_test.rb +22 -0
  49. data/test/lib/vedeu/support/buffer_test.rb +44 -0
  50. data/test/lib/vedeu/support/events_test.rb +3 -9
  51. data/test/lib/vedeu/support/input_test.rb +1 -0
  52. data/test/lib/vedeu/support/terminal_test.rb +128 -5
  53. data/test/test_helper.rb +2 -2
  54. data/vedeu.gemspec +1 -1
  55. metadata +5 -2
@@ -76,7 +76,7 @@ module Vedeu
76
76
 
77
77
  class Log
78
78
 
79
- # @return []
79
+ # @return [TrueClass]
80
80
  def self.logger
81
81
  @logger ||= MonoLogger.new(filename).tap do |log|
82
82
  log.formatter = proc do |_, time, _, message|
@@ -87,16 +87,22 @@ module Vedeu
87
87
 
88
88
  private
89
89
 
90
+ # @api private
91
+ # @return [String]
90
92
  def self.filename
91
93
  @_filename ||= directory + '/vedeu.log'
92
94
  end
93
95
 
96
+ # @api private
97
+ # @return [String]
94
98
  def self.directory
95
99
  FileUtils.mkdir_p(path) unless File.directory?(path)
96
100
 
97
101
  path
98
102
  end
99
103
 
104
+ # @api private
105
+ # @return [String]
100
106
  def self.path
101
107
  Dir.home + '/.vedeu'
102
108
  end
@@ -22,14 +22,20 @@ module Vedeu
22
22
 
23
23
  private
24
24
 
25
+ # @api private
26
+ # @return [String]
25
27
  def sequence
26
28
  ["\e[", y, ';', x, 'H'].join
27
29
  end
28
30
 
31
+ # @api private
32
+ # @return [Fixnum]
29
33
  def y
30
34
  (@y == 0 || @y == nil) ? 1 : @y
31
35
  end
32
36
 
37
+ # @api private
38
+ # @return [Fixnum]
33
39
  def x
34
40
  (@x == 0 || @x == nil) ? 1 : @x
35
41
  end
@@ -1,18 +1,28 @@
1
1
  module Vedeu
2
2
  class Render
3
3
 
4
+ # Attempts to convert the provided interface object with associated lines,
5
+ # streams, colours, styles, etc, into a single string containing all content
6
+ # and escape sequences.
7
+ #
8
+ # @api private
4
9
  # @param interface [Interface]
5
10
  # @return [String]
6
11
  def self.call(interface)
7
12
  new(interface).render
8
13
  end
9
14
 
15
+ # Initializes a new Render object with the provided interface.
16
+ #
10
17
  # @param interface [Interface]
11
18
  # @return [Render]
12
19
  def initialize(interface)
13
20
  @interface = interface
14
21
  end
15
22
 
23
+ # Produces a single string which contains all content and escape sequences
24
+ # required to render this interface to a position in the terminal window.
25
+ #
16
26
  # @return [String]
17
27
  def render
18
28
  out = [ Clear.call(interface) ]
@@ -33,6 +43,9 @@ module Vedeu
33
43
  # The client application may have created a line that us too long for the
34
44
  # interface. This code tries to truncate streams whilst preserving styles
35
45
  # and colours.
46
+ #
47
+ # @api private
48
+ # @return [Array]
36
49
  def processed_lines
37
50
  return [] unless lines.any? { |line| line.streams.any? }
38
51
 
@@ -71,22 +84,47 @@ module Vedeu
71
84
  end
72
85
  end
73
86
 
87
+ # Converts all streams within a line into a single line of text to then
88
+ # check that this line (without formatting, as that is not visible) exceeds
89
+ # the width of the interface.
90
+ #
91
+ # @api private
92
+ # @param line [Line]
93
+ # @return [TrueClass|FalseClass]
74
94
  def exceeds_width?(line)
75
95
  line.streams.map(&:text).join.size > width
76
96
  end
77
97
 
98
+ # Truncates the provided text.
99
+ #
100
+ # @api private
101
+ # @param text [String] The text to be truncated.
102
+ # @param value [Fixnum] The total length of the text after truncation.
103
+ # @return [String]
78
104
  def truncate(text, value)
79
105
  text.chomp.slice(0...value)
80
106
  end
81
107
 
108
+ # Provides a collection of lines associated with the interface.
109
+ #
110
+ # @api private
111
+ # @return [Array]
82
112
  def lines
83
113
  interface.lines
84
114
  end
85
115
 
116
+ # Provides the currently available height of the interface.
117
+ #
118
+ # @api private
119
+ # @return [Fixnum]
86
120
  def height
87
121
  interface.viewport_height
88
122
  end
89
123
 
124
+ # Provides the currently available width of the interface.
125
+ #
126
+ # @api private
127
+ # @return [Fixnum]
90
128
  def width
91
129
  interface.viewport_width
92
130
  end
@@ -1,24 +1,23 @@
1
1
  module Vedeu
2
2
  module Terminal
3
+
3
4
  extend self
4
5
 
5
- # @param mode [Symbol]
6
6
  # @param block [Proc]
7
7
  # @return []
8
- def open(mode, &block)
9
- @mode = mode
8
+ def open(&block)
9
+ fail InvalidSyntax, '`open` requires a block.' unless block_given?
10
10
 
11
- if block_given?
12
- if raw_mode?
13
- console.raw { initialize_screen { yield } }
11
+ if raw_mode?
12
+ console.raw { initialize_screen { yield } }
14
13
 
15
- else
16
- console.cooked { initialize_screen { yield } }
14
+ else
15
+ console.cooked { initialize_screen { yield } }
17
16
 
18
- end
19
17
  end
20
18
  ensure
21
19
  restore_screen
20
+
22
21
  end
23
22
 
24
23
  # @return [String]
@@ -69,9 +68,35 @@ module Vedeu
69
68
  output Esc.string 'show_cursor' unless raw_mode?
70
69
  end
71
70
 
71
+ # @return [Boolean]
72
+ def cooked_mode?
73
+ mode == :cooked
74
+ end
75
+
76
+ # @return [Symbol]
77
+ def cooked_mode!
78
+ @_mode = :cooked
79
+ end
80
+
72
81
  # @return [Boolean]
73
82
  def raw_mode?
74
- @mode == :raw
83
+ mode == :raw
84
+ end
85
+
86
+ # @return [Symbol]
87
+ def raw_mode!
88
+ @_mode = :raw
89
+ end
90
+
91
+ # @return [Symbol]
92
+ def switch_mode!
93
+ if raw_mode?
94
+ cooked_mode!
95
+
96
+ else
97
+ raw_mode!
98
+
99
+ end
75
100
  end
76
101
 
77
102
  # @return [String]
@@ -79,26 +104,54 @@ module Vedeu
79
104
  Esc.set_position((height - 1), 1) + Esc.string('clear_line')
80
105
  end
81
106
 
82
- # @return [Fixnum]
83
- def colour_mode
84
- Configuration.options[:colour_mode]
107
+ # Returns the mode of the terminal, either `:raw` or `:cooked`
108
+ #
109
+ # @return [Symbol]
110
+ def mode
111
+ @_mode ||= Configuration.terminal_mode
85
112
  end
86
113
 
114
+ # Returns a coordinate tuple of the format [y, x], where `y` is the row/line
115
+ # and `x` is the column/character.
116
+ #
87
117
  # @return [Array]
88
118
  def centre
89
119
  [(height / 2), (width / 2)]
90
120
  end
91
121
 
92
- # @return [Fixnum] The total width of the current terminal.
122
+ # Returns the `y` (row/line) component of the coordinate tuple provided by
123
+ # {Terminal.centre}
124
+ #
125
+ # @return [Fixnum]
126
+ def centre_y
127
+ centre.first
128
+ end
129
+
130
+ # Returns the `x` (column/character) component of the coodinate tuple
131
+ # provided by {Terminal.centre}
132
+ #
133
+ # @return [Fixnum]
134
+ def centre_x
135
+ centre.last
136
+ end
137
+
138
+ # Returns the total width (number of columns/characters) of the current
139
+ # terminal.
140
+ #
141
+ # @return [Fixnum]
93
142
  def width
94
143
  size.last
95
144
  end
96
145
 
97
- # @return [Fixnum] The total height of the current terminal.
146
+ # Returns the total height (number of rows/lines) of the current terminal.
147
+ #
148
+ # @return [Fixnum]
98
149
  def height
99
150
  size.first
100
151
  end
101
152
 
153
+ # Returns a tuple containing the height and width of the current terminal.
154
+ #
102
155
  # @return [Array]
103
156
  def size
104
157
  console.winsize
@@ -108,5 +161,6 @@ module Vedeu
108
161
  def console
109
162
  IO.console
110
163
  end
164
+
111
165
  end
112
166
  end
@@ -28,18 +28,26 @@ module Vedeu
28
28
 
29
29
  private
30
30
 
31
+ # @api private
32
+ # @return []
31
33
  def watched
32
34
  options[:event]
33
35
  end
34
36
 
37
+ # @api private
38
+ # @return []
35
39
  def klass
36
40
  options[:klass]
37
41
  end
38
42
 
43
+ # @api private
44
+ # @return [Hash]
39
45
  def options
40
46
  defaults.merge!(@options)
41
47
  end
42
48
 
49
+ # @api private
50
+ # @return [Hash]
43
51
  def defaults
44
52
  {
45
53
  event: 'call',
@@ -30,14 +30,20 @@ module Vedeu
30
30
 
31
31
  attr_reader :object
32
32
 
33
+ # @api private
34
+ # @return [Array]
33
35
  def interfaces
34
36
  composition.interfaces
35
37
  end
36
38
 
39
+ # @api private
40
+ # @return [Composition]
37
41
  def composition
38
42
  @_composition ||= Composition.new(attributes)
39
43
  end
40
44
 
45
+ # @api private
46
+ # @return []
41
47
  def attributes
42
48
  render
43
49
  end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ class MyFirstApplication
4
+ include Vedeu
5
+
6
+ interface 'hydrogen' do
7
+ x 2
8
+ y 2
9
+ width 50
10
+ height 2
11
+ end
12
+
13
+ def self.start
14
+ Vedeu::Launcher.new(['--run-once', '--noninteractive']).execute!
15
+ end
16
+ end
17
+
18
+ describe 'Run the application once, printing a message on the screen and ' \
19
+ 'gracefully terminating.' do
20
+ it 'writes a message to the screen' do
21
+ skip
22
+ stdout, stderr = capture_io { MyFirstApplication.start }
23
+ stdout.must_equal('Great success! Now, try something a little harder.')
24
+ stderr.must_equal('')
25
+ end
26
+ end
@@ -24,10 +24,6 @@ module Vedeu
24
24
  end
25
25
 
26
26
  describe '.events' do
27
- it 'should not be visible to the client' do
28
- skip
29
- end
30
-
31
27
  it 'returns the Events singleton' do
32
28
  Vedeu.events.must_be_instance_of(Vedeu::Events)
33
29
  end
@@ -45,7 +41,7 @@ module Vedeu
45
41
  it 'creates and stores a new interface' do
46
42
  Vedeu::Buffers.reset
47
43
 
48
- Vedeu.interface('Vedeu.interface').must_equal(true)
44
+ Vedeu.interface('Vedeu.interface').must_be_instance_of(API::Interface)
49
45
  end
50
46
  end
51
47
 
@@ -53,11 +49,24 @@ module Vedeu
53
49
  before { event.stubs(:trigger).returns(nil) }
54
50
 
55
51
  it 'returns nil' do
56
- skip
57
52
  Vedeu.keypress('k').must_equal(nil)
58
53
  end
59
54
  end
60
55
 
56
+ describe '.log' do
57
+ it 'writes the message to the log file when debugging is enabled' do
58
+ Configuration.stub(:debug?, true) do
59
+ Vedeu.log('some message...').must_equal(true)
60
+ end
61
+ end
62
+
63
+ it 'returns nil when debugging is disabled' do
64
+ Configuration.stub(:debug?, false) do
65
+ Vedeu.log('some message...').must_equal(nil)
66
+ end
67
+ end
68
+ end
69
+
61
70
  describe '.trigger' do
62
71
  it 'triggers the specifed event and returns the collection of events' \
63
72
  ' which this trigger triggers' do
@@ -128,6 +137,10 @@ module Vedeu
128
137
  }
129
138
  )
130
139
  end
140
+
141
+ it 'raises an exception if a block was not given' do
142
+ proc { Vedeu.views }.must_raise(InvalidSyntax)
143
+ end
131
144
  end
132
145
 
133
146
  describe '.width' do
@@ -8,7 +8,7 @@ module Vedeu
8
8
  interface = Interface.new({ name: 'widget' })
9
9
 
10
10
  it 'creates and stores a new interface' do
11
- interface.define.must_equal(true)
11
+ interface.define.must_be_instance_of(API::Interface)
12
12
  end
13
13
 
14
14
  it 'allows the setting of colours' do
@@ -834,6 +834,72 @@ module Vedeu
834
834
  )
835
835
  end
836
836
 
837
+ it 'allows inline values for line' do
838
+ Vedeu.interface 'helium' do
839
+ end
840
+ attributes = Vedeu.view 'helium' do
841
+ line 'A headline, if you will.'
842
+ line # with a spacer line
843
+ line 'This is a line of text...'
844
+ line do
845
+ text '...we can mix and match...'
846
+ end
847
+ line '...to our hearts content.'
848
+ end
849
+ attributes[:interfaces].first[:lines].size.must_equal(5)
850
+ end
851
+ end
852
+
853
+ describe '#cursor' do
854
+ it 'raises an exception if the value is invalid' do
855
+ proc {
856
+ Vedeu.interface 'beryllium' do
857
+ cursor :invalid
858
+ end
859
+ }.must_raise(InvalidSyntax)
860
+ end
861
+
862
+ it 'sets the cursor to true (visible)' do
863
+ Vedeu.interface 'beryllium' do
864
+ cursor true
865
+ end
866
+
867
+ Vedeu.use('beryllium').attributes[:cursor].must_equal(true)
868
+ end
869
+
870
+ it 'sets the cursor to false (hidden)' do
871
+ Vedeu.interface 'beryllium' do
872
+ cursor false
873
+ end
874
+
875
+ Vedeu.use('beryllium').attributes[:cursor].must_equal(false)
876
+ end
877
+ end
878
+
879
+ describe '#centred' do
880
+ it 'raises an exception if the value is invalid' do
881
+ proc {
882
+ Vedeu.interface 'boron' do
883
+ centred :invalid
884
+ end
885
+ }.must_raise(InvalidSyntax)
886
+ end
887
+
888
+ it 'sets the centred to true (visible)' do
889
+ Vedeu.interface 'boron' do
890
+ centred true
891
+ end
892
+
893
+ Vedeu.use('boron').attributes[:geometry][:centred].must_equal(true)
894
+ end
895
+
896
+ it 'sets the centred to false (hidden)' do
897
+ Vedeu.interface 'boron' do
898
+ centred false
899
+ end
900
+
901
+ Vedeu.use('boron').attributes[:geometry][:centred].must_equal(false)
902
+ end
837
903
  end
838
904
  end
839
905
  end