termplot 0.1.0 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1e3e2ddb262dda39fcc498fb8fed6bd84c1023c97a21d1a2aa2a7bb2ba22c59
4
- data.tar.gz: 87012dbfb94747ecc1d90530d7a199a74cd118a59e4ea8d2396b283519b1d628
3
+ metadata.gz: e44e30011841535366e60fe122b1a1975614d2907db4b99fc5e78538ffc1cc8d
4
+ data.tar.gz: b63812a1a1823e0126eec29b14072ac6a7ee4b95f52a02977ea5e35432e2a905
5
5
  SHA512:
6
- metadata.gz: fd4bdb6d311d03c7987fc3efcb0c6773d2abd40af2a13a5e7d9743ad4b6af0fce70ccd10414dded74bad0451f742ad50582cbc3e95813f8dfe1cfec115f322d5
7
- data.tar.gz: bcc75b035ea812d163c5fb4bdbd7d35f387cce9d9d0b38938ce86acdd7005d2effb4f2b865344c7a6ce03c5de835a1a7a41535c444e4017eae9954105f755be2
6
+ metadata.gz: 2a15e0921c87254909bfdb11f35c0c3ac5bc85b8bd06c023234ac6c735a73cde92a7bcc2423ad40e5c37ac2718338a502e92e9b85ff6865760bca56e8671cea1
7
+ data.tar.gz: f4ba5aaea3ce9ef9870becafbfb7c58b79bebb76ab9d96161533f13c824a2e905964f39e99c7b4b1352df5d65b154e2d6b593099cc36ea43aafd25dc2b2d0366
data/README.md CHANGED
@@ -4,7 +4,7 @@ Termplot is a simple terminal plotting tool for visualising streaming data.
4
4
 
5
5
  See the demo on Asciinema:
6
6
 
7
- [![Termplot Demo Asciicast](https://asciinema.org/a/3rzeUSXp2fRjnErX0p3SptP5e.png)](https://asciinema.org/a/3rzeUSXp2fRjnErX0p3SptP5e)
7
+ [![Termplot Demo Asciicast](https://asciinema.org/a/370325.svg)](https://asciinema.org/a/3rzeUSXp2fRjnErX0p3SptP5e)
8
8
 
9
9
  ## Overview
10
10
 
@@ -27,26 +27,34 @@ The basic usage is simple:
27
27
  ```
28
28
 
29
29
  `{command}` is any command that will periodically output numbers to standard out
30
- delimited by a newline. Options and examples are given below. All command line
31
- options are optional.
30
+ delimited by a newline. You can also instead specify a command to run at a given
31
+ interval to produce the data.
32
32
 
33
- Options:
33
+ Options and examples are given below. All command line options are
34
+ optional.
34
35
 
35
36
  ```
36
37
  Usage: termplot [OPTIONS]
37
- -r, --rows ROWS Number of rows in the chart window (default: 19)
38
- -c, --cols COLS Number of cols in the chart window (default: 80)
39
- -t, --title TITLE Title of the series (default: Series)
38
+ -r, --rows ROWS Number of rows in the chart window (default: 19)
40
39
 
41
- --line-style STYLE Line style. Options are:
42
- line [default], heavy-line, dot, star, x
40
+ -c, --cols COLS Number of cols in the chart window (default: 80)
43
41
 
44
- --color COLOR Series color, specified as ansi 16-bit color name:
45
- (i.e. black, red [default], green, yellow, blue,
46
- magenta, cyan, white). Light versions are specified
47
- as light_{color}
42
+ -t, --title TITLE Title of the series (default: 'Series')
48
43
 
49
- -h, --help Display this help message
44
+ --line-style STYLE Line style. Options are: line (default), heavy-line, dot, star, x
45
+
46
+ --color COLOR Series color, specified as ansi 16-bit color name:
47
+ (i.e. black, light_black, red (default), light_red, green,
48
+ light_green, yellow, light_yellow, blue, light_blue, magenta,
49
+ light_magenta, cyan, light_cyan, white, light_white, default)
50
+
51
+ --command COMMAND Enables command mode, where input is received by executing
52
+ the specified command in intervals rather than from stdin
53
+
54
+ --interval INTERVAL The interval at which to run the specified command in
55
+ command mode in milliseconds (default: 1000)
56
+
57
+ -h, --help Display this help message
50
58
  ```
51
59
 
52
60
  ## Examples
@@ -59,25 +67,21 @@ for i in $(seq 500); do \
59
67
  sleep 0.5; \
60
68
  done | termplot -t "Sin(x)"
61
69
  ```
62
- ![Sine Wave Plot](http://localhost:8080/doc/sin.png)
70
+ ![Sine Wave Plot](doc/sin.png)
63
71
 
64
72
  Total % memory usage:
65
73
  ```
66
- while true; do \
67
- free | awk 'NR==2 { print ($3/$2) * 100 }'; \
68
- sleep 0.5; \
69
- done | termplot -t "Memory (% used)" --color light_magenta --line-style heavy-line
74
+ termplot --command "free | awk 'NR==2 { print ($3/$2) * 100 }'" \
75
+ -t "Memory (% used)" --color light_magenta --line-style heavy-line
70
76
  ```
71
- ![Free Memory % Chart](http://localhost:8080/doc/memory.png)
77
+ ![Free Memory % Chart](doc/memory.png)
72
78
 
73
79
  % CPU usage of a "puma" process:
74
80
  ```
75
- while true; do \
76
- ps au | grep puma | awk 'NR==1{ print $3 }'; \
77
- sleep 0.5; \
78
- done | termplot -t "Ruby CPU(%)" --color yellow --line-style dot -r10 -c 120
81
+ termplot --command "ps au | grep puma | awk 'NR==1{ print $3 }'" \
82
+ -t "Ruby CPU(%)" --color yellow --line-style dot -r10 -c 120
79
83
  ```
80
- ![CPU % Chart](http://localhost:8080/doc/cpu.png)
84
+ ![CPU % Chart](doc/cpu.png)
81
85
 
82
86
 
83
87
  ## Notes
@@ -87,10 +91,6 @@ while true; do \
87
91
  - The samples received are plotted in sequence order, and there is no notion of
88
92
  temporal spacing. So even if the time between samples is inconsistent, they
89
93
  will be plotted with the same amount of space between them.
90
- - The `while true; do {...}; sleep INTERVAL` is pretty typical, I would like to
91
- sometime soon implement a `--command "{...}" --interval INTERVAL` which would
92
- reduce some of the boilerplate of calling some command at an interval and make
93
- it easy to watch and plot.
94
94
 
95
95
  ## Background
96
96
 
@@ -107,12 +107,10 @@ ruby.
107
107
  Now with termplot, it's as easy as:
108
108
 
109
109
  ```
110
- while true; do \
111
- ss -s | head -n1 | cut -d ' ' -f2; sleep 1; \
112
- done | termplot -t "TCP Connections"
110
+ termplot --command "ss -s | head -n1 | cut -d' ' -f2" --interval 500 -t "TCP Connections"
113
111
  ```
114
112
 
115
- ![TCP Connections](http://localhost:8080/doc/tcp.png)
113
+ ![TCP Connections](doc/tcp.png)
116
114
 
117
115
  ## Development
118
116
 
data/Rakefile CHANGED
@@ -1,8 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
3
  task :bin do
4
- Bundler.require(:default)
5
- exec "bin/termplot", *ARGV[2..-1]
4
+ exec "ruby", "-Ilib", "bin/termplot", *ARGV[2..-1]
6
5
  end
7
6
 
8
7
  task :sin_test do
@@ -16,3 +15,6 @@ task :sin_test do
16
15
  exec cmd
17
16
  end
18
17
 
18
+ task :command_test do
19
+ exec "ruby -Ilib bin/termplot --command 'echo $RANDOM' --interval 900"
20
+ end
@@ -1,59 +1,12 @@
1
- require "optparse"
1
+ # frozen_string_literal: true
2
+ require "termplot/options"
2
3
  require "termplot/consumer"
3
4
 
4
5
  module Termplot
5
6
  class CLI
6
7
  def self.run
7
- opts = self.parse_options
8
- Consumer.new(**opts).run
9
- end
10
-
11
- private
12
- def self.parse_options
13
- options = {
14
- rows: 19,
15
- cols: 80,
16
- title: "Series",
17
- line_style: "line",
18
- color: "red",
19
- debug: false
20
- }
21
- OptionParser.new do |opts|
22
- opts.banner = "Usage: termplot [OPTIONS]"
23
-
24
- opts.on("-rROWS", "--rows ROWS", "Number of rows in the chart window (default: 19)") do |v|
25
- options[:rows] = v.to_i
26
- end
27
-
28
- opts.on("-cCOLS", "--cols COLS", "Number of cols in the chart window (default: 80)") do |v|
29
- options[:cols] = v.to_i
30
- end
31
-
32
- opts.on("-tTITLE", "--title TITLE", "Title of the series (default: Series)") do |v|
33
- options[:title] = v
34
- end
35
-
36
- opts.on("--line-style STYLE", "Line style. Options are: line [default], heavy-line, dot, star, x") do |v|
37
- options[:line_style] = v.downcase
38
- end
39
-
40
- opts.on("--color COLOR", "Series color, specified as ansi 16-bit color name",
41
- "(i.e. black, red [default], green, yellow, blue, magenta, cyan, white)",
42
- "with light versions specified as light_{color}") do |v|
43
- options[:color] = v.downcase
44
- end
45
-
46
- opts.on("-d", "--debug", "Enable debug mode, Logs window data to stdout instead of rendering") do |v|
47
- options[:debug] = v
48
- end
49
-
50
- opts.on("-h", "--help", "Display this help message") do
51
- puts opts
52
- exit(0)
53
- end
54
-
55
- end.parse!
56
- options
8
+ opts = Options.new.parse_options!
9
+ Consumer.new(opts).run
57
10
  end
58
11
  end
59
12
  end
@@ -1,36 +1,36 @@
1
1
  module Termplot
2
2
  class Colors
3
- class << self
4
- COLORS = {
5
- black: 0,
6
- light_black: 60,
7
- red: 1,
8
- light_red: 61,
9
- green: 2,
10
- light_green: 62,
11
- yellow: 3,
12
- light_yellow: 63,
13
- blue: 4,
14
- light_blue: 64,
15
- magenta: 5,
16
- light_magenta: 65,
17
- cyan: 6,
18
- light_cyan: 66,
19
- white: 7,
20
- light_white: 67,
21
- default: 9
22
- }
3
+ COLORS = {
4
+ black: 0,
5
+ light_black: 60,
6
+ red: 1,
7
+ light_red: 61,
8
+ green: 2,
9
+ light_green: 62,
10
+ yellow: 3,
11
+ light_yellow: 63,
12
+ blue: 4,
13
+ light_blue: 64,
14
+ magenta: 5,
15
+ light_magenta: 65,
16
+ cyan: 6,
17
+ light_cyan: 66,
18
+ white: 7,
19
+ light_white: 67,
20
+ default: 9
21
+ }
23
22
 
24
- MODES = {
25
- default: 0,
26
- bold: 1,
27
- italic: 3,
28
- underline: 4,
29
- blink: 5,
30
- swap: 7,
31
- hide: 8
32
- }
23
+ MODES = {
24
+ default: 0,
25
+ bold: 1,
26
+ italic: 3,
27
+ underline: 4,
28
+ blink: 5,
29
+ swap: 7,
30
+ hide: 8
31
+ }
33
32
 
33
+ class << self
34
34
  COLORS.each do |(color, code)|
35
35
  define_method(color) do |str|
36
36
  escape_color(color) + str + escape_mode(:default)
@@ -1,22 +1,24 @@
1
1
  require "termplot/series"
2
2
  require "termplot/renderer"
3
3
  require "termplot/shell"
4
+ require "termplot/producers"
4
5
 
5
6
  module Termplot
6
7
  class Consumer
7
- attr_reader :series, :renderer
8
+ attr_reader :options, :series, :renderer
8
9
 
9
- def initialize(cols:, rows:, title:, line_style:, color:, debug:)
10
+ def initialize(options)
11
+ @options = options
10
12
  @renderer = Renderer.new(
11
- cols: cols,
12
- rows: rows,
13
- debug: debug
13
+ cols: options.cols,
14
+ rows: options.rows,
15
+ debug: options.debug
14
16
  )
15
17
  @series = Series.new(
16
- title: title,
18
+ title: options.title,
17
19
  max_data_points: renderer.inner_width,
18
- line_style: line_style,
19
- color: color,
20
+ line_style: options.line_style,
21
+ color: options.color,
20
22
  )
21
23
  end
22
24
 
@@ -27,7 +29,7 @@ module Termplot
27
29
  # Consumer thread will process and render any available input in the
28
30
  # queue. If samples are available faster than it can render, multiple
29
31
  # samples will be shifted from the queue so they can be rendered at once.
30
- # If no samples are available but stdin is open, it will sleep until
32
+ # If no samples are available but the queue is open, it will sleep until
31
33
  # woken to render new input.
32
34
  consumer = Thread.new do
33
35
  while !queue.closed?
@@ -45,27 +47,29 @@ module Termplot
45
47
  end
46
48
  end
47
49
 
48
- # Main thread will accept samples as fast as they become available from stdin,
49
- # and wake the consumer thread to process them if its asleep
50
- while n = STDIN.gets&.chomp do
51
- if numeric?(n)
52
- queue << n.to_f
53
- consumer.run
54
- end
55
- end
50
+ # Producer will run in the main thread and will block while producing
51
+ # samples from some source (which depends on the type of producer).
52
+ # Samples will be added to the queue as they are available, and the
53
+ # consumer will be woken to check the queue
54
+ producer = build_producer(queue)
55
+ producer.register_consumer(consumer)
56
+ producer.run
56
57
 
57
- # Queue is closed as soon as stdin is closed, and we wait for the consumer
58
- # to finish rendering
59
- queue.close
58
+ # As soon as producer continues, and we first give the consumer a chance
59
+ # to finish rendering the queue, then close the queue.
60
60
  consumer.run
61
+ producer.close
61
62
  consumer.join
62
63
  end
63
64
 
64
65
  private
65
66
 
66
- FLOAT_REGEXP = /^[-+]?[0-9]*\.?[0-9]+$/
67
- def numeric?(n)
68
- n =~ FLOAT_REGEXP
67
+ def build_producer(queue)
68
+ producer_class = {
69
+ command: "Termplot::Producers::CommandProducer",
70
+ stdin: "Termplot::Producers::StdinProducer"
71
+ }.fetch(options.mode)
72
+ Object.const_get(producer_class).new(queue, options)
69
73
  end
70
74
  end
71
75
  end
@@ -0,0 +1,7 @@
1
+ module Termplot
2
+ module Cursors
3
+ autoload :VirtualCursor, "termplot/cursors/virtual_cursor"
4
+ autoload :ConsoleCursor, "termplot/cursors/console_cursor"
5
+ autoload :BufferedConsoleCursor, "termplot/cursors/buffered_console_cursor"
6
+ end
7
+ end
@@ -1,70 +1,69 @@
1
- require "termplot/cursors/virtual_cursor"
2
- require "termplot/cursors/control_chars"
3
-
4
1
  module Termplot
5
- class BufferedConsoleCursor < VirtualCursor
6
- include Termplot::ControlChars
7
- attr_reader :buffer
2
+ module Cursors
3
+ class BufferedConsoleCursor < VirtualCursor
4
+ include Termplot::ControlChars
5
+ attr_reader :buffer
8
6
 
9
- def initialize(window, buffer)
10
- super(window)
11
- @buffer = buffer
12
- end
7
+ def initialize(window, buffer)
8
+ super(window)
9
+ @buffer = buffer
10
+ end
13
11
 
14
- def write(char)
15
- if writeable?
16
- buffer << char
17
- super(char)
12
+ def write(char)
13
+ if writeable?
14
+ buffer << char
15
+ super(char)
16
+ end
18
17
  end
19
- end
20
18
 
21
- def forward(n = 1)
22
- moved = super(n)
23
- moved.times { buffer << FORWARD }
24
- end
19
+ def forward(n = 1)
20
+ moved = super(n)
21
+ moved.times { buffer << FORWARD }
22
+ end
25
23
 
26
- def back(n = 1)
27
- moved = super(n)
28
- moved.times { buffer << BACK }
29
- end
24
+ def back(n = 1)
25
+ moved = super(n)
26
+ moved.times { buffer << BACK }
27
+ end
30
28
 
31
- def up(n=1)
32
- moved = super(n)
33
- moved.times { buffer << UP }
34
- end
29
+ def up(n=1)
30
+ moved = super(n)
31
+ moved.times { buffer << UP }
32
+ end
35
33
 
36
- def down(n=1)
37
- moved = super(n)
38
- moved.times { buffer << DOWN }
39
- end
34
+ def down(n=1)
35
+ moved = super(n)
36
+ moved.times { buffer << DOWN }
37
+ end
40
38
 
41
- def beginning_of_line
42
- super
43
- buffer << CR
44
- end
39
+ def beginning_of_line
40
+ super
41
+ buffer << CR
42
+ end
45
43
 
46
- def new_line
47
- buffer << NEWLINE
48
- end
44
+ def new_line
45
+ buffer << NEWLINE
46
+ end
49
47
 
50
- def clear_buffer
51
- buffer.clear
52
- end
48
+ def clear_buffer
49
+ buffer.clear
50
+ end
53
51
 
54
- def flush
55
- print buffer.join
56
- end
52
+ def flush
53
+ print buffer.join
54
+ end
57
55
 
58
- def position=()
59
- raise "Cannot set cursor position directly"
60
- end
56
+ def position=()
57
+ raise "Cannot set cursor position directly"
58
+ end
61
59
 
62
- def row=()
63
- raise "Cannot set cursor position directly"
64
- end
60
+ def row=()
61
+ raise "Cannot set cursor position directly"
62
+ end
65
63
 
66
- def col=()
67
- raise "Cannot set cursor position directly"
64
+ def col=()
65
+ raise "Cannot set cursor position directly"
66
+ end
68
67
  end
69
68
  end
70
69
  end
@@ -1,56 +1,57 @@
1
- require "termplot/cursors/virtual_cursor"
2
- require "termplot/cursors/control_chars"
1
+ require "termplot/control_chars"
3
2
 
4
3
  module Termplot
5
- class ConsoleCursor < VirtualCursor
6
- include Termplot::ControlChars
7
-
8
- def write(char)
9
- if writeable?
10
- print(char)
11
- super(char)
4
+ module Cursors
5
+ class ConsoleCursor < VirtualCursor
6
+ include Termplot::ControlChars
7
+
8
+ def write(char)
9
+ if writeable?
10
+ print(char)
11
+ super(char)
12
+ end
12
13
  end
13
- end
14
14
 
15
- def forward(n = 1)
16
- moved = super(n)
17
- moved.times { print FORWARD }
18
- end
15
+ def forward(n = 1)
16
+ moved = super(n)
17
+ moved.times { print FORWARD }
18
+ end
19
19
 
20
- def back(n = 1)
21
- moved = super(n)
22
- moved.times { print BACK }
23
- end
20
+ def back(n = 1)
21
+ moved = super(n)
22
+ moved.times { print BACK }
23
+ end
24
24
 
25
- def up(n=1)
26
- moved = super(n)
27
- moved.times { print UP }
28
- end
25
+ def up(n=1)
26
+ moved = super(n)
27
+ moved.times { print UP }
28
+ end
29
29
 
30
- def down(n=1)
31
- moved = super(n)
32
- moved.times { print DOWN }
33
- end
30
+ def down(n=1)
31
+ moved = super(n)
32
+ moved.times { print DOWN }
33
+ end
34
34
 
35
- def beginning_of_line
36
- super
37
- print CR
38
- end
35
+ def beginning_of_line
36
+ super
37
+ print CR
38
+ end
39
39
 
40
- def new_line
41
- print NEWLINE
42
- end
40
+ def new_line
41
+ print NEWLINE
42
+ end
43
43
 
44
- def position=()
45
- raise "Cannot set cursor position directly"
46
- end
44
+ def position=()
45
+ raise "Cannot set cursor position directly"
46
+ end
47
47
 
48
- def row=()
49
- raise "Cannot set cursor position directly"
50
- end
48
+ def row=()
49
+ raise "Cannot set cursor position directly"
50
+ end
51
51
 
52
- def col=()
53
- raise "Cannot set cursor position directly"
52
+ def col=()
53
+ raise "Cannot set cursor position directly"
54
+ end
54
55
  end
55
56
  end
56
57
  end
@@ -1,76 +1,78 @@
1
1
  module Termplot
2
- class VirtualCursor
3
- attr_reader :position, :window
2
+ module Cursors
3
+ class VirtualCursor
4
+ attr_reader :position, :window
4
5
 
5
- def initialize(window)
6
- @window = window
7
- @position = 0
8
- end
6
+ def initialize(window)
7
+ @window = window
8
+ @position = 0
9
+ end
9
10
 
10
- def write(char)
11
- @position += 1 if writeable?
12
- end
11
+ def write(char)
12
+ @position += 1 if writeable?
13
+ end
13
14
 
14
- def writeable?
15
- position < window.buffer.size
16
- end
15
+ def writeable?
16
+ position < window.buffer.size
17
+ end
17
18
 
18
- def forward(n = 1)
19
- movable_chars = window.buffer.size - position
20
- chars_to_move = [movable_chars, n].min
21
- @position += chars_to_move
22
- chars_to_move
23
- end
19
+ def forward(n = 1)
20
+ movable_chars = window.buffer.size - position
21
+ chars_to_move = [movable_chars, n].min
22
+ @position += chars_to_move
23
+ chars_to_move
24
+ end
24
25
 
25
- def back(n = 1)
26
- chars_to_move = [position, n].min
27
- @position -= chars_to_move
28
- chars_to_move
29
- end
26
+ def back(n = 1)
27
+ chars_to_move = [position, n].min
28
+ @position -= chars_to_move
29
+ chars_to_move
30
+ end
30
31
 
31
- def up(n=1)
32
- return unless row > 0
33
- rows_to_move = [n, row].min
34
- @position -= rows_to_move * window.cols
35
- rows_to_move
36
- end
32
+ def up(n=1)
33
+ return unless row > 0
34
+ rows_to_move = [n, row].min
35
+ @position -= rows_to_move * window.cols
36
+ rows_to_move
37
+ end
37
38
 
38
- def row
39
- (position / window.cols).floor
40
- end
39
+ def row
40
+ (position / window.cols).floor
41
+ end
41
42
 
42
- def col
43
- position % window.cols
44
- end
43
+ def col
44
+ position % window.cols
45
+ end
45
46
 
46
- def row=(y)
47
- @position = y * window.cols + col
48
- end
47
+ def row=(y)
48
+ @position = y * window.cols + col
49
+ end
49
50
 
50
- def col=(x)
51
- beginning_of_line
52
- forward(x)
53
- end
51
+ def col=(x)
52
+ beginning_of_line
53
+ forward(x)
54
+ end
54
55
 
55
- def down(n=1)
56
- return 0 unless row < (window.rows - 1)
57
- rows_to_move = [n, window.rows - 1 - row].min
58
- @position += window.cols * rows_to_move
59
- rows_to_move
60
- end
56
+ def down(n=1)
57
+ return 0 unless row < (window.rows - 1)
58
+ rows_to_move = [n, window.rows - 1 - row].min
59
+ @position += window.cols * rows_to_move
60
+ rows_to_move
61
+ end
61
62
 
62
- def beginning_of_line
63
- @position = position - (position % window.cols)
64
- end
63
+ def beginning_of_line
64
+ @position = position - (position % window.cols)
65
+ end
65
66
 
66
- def position=(n)
67
- @position = n
68
- end
67
+ def position=(n)
68
+ @position = n
69
+ end
69
70
 
70
- def reset_position
71
- return if position == 0
72
- up(row) # Go up by row num times
73
- beginning_of_line
71
+ def reset_position
72
+ return if position == 0
73
+ up(row) # Go up by row num times
74
+ beginning_of_line
75
+ end
74
76
  end
75
77
  end
76
78
  end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+ require "termplot/character_map"
5
+ require "termplot/colors"
6
+
7
+ module Termplot
8
+ class Options
9
+ attr_reader :rows,
10
+ :cols,
11
+ :title,
12
+ :line_style,
13
+ :color,
14
+ :debug,
15
+ :command,
16
+ :interval
17
+
18
+ def initialize
19
+ @rows = 19
20
+ @cols = 80
21
+ @title = "Series"
22
+ @line_style = "line"
23
+ @color = "red"
24
+ @debug = false
25
+ @command = nil
26
+ @interval = 1000
27
+ end
28
+
29
+ def mode
30
+ @command.nil? ? :stdin : :command
31
+ end
32
+
33
+ def parse_options!
34
+ # Debug option is parsed manually to prevent it from showing up in the
35
+ # options help
36
+ parse_debug
37
+
38
+ OptionParser.new do |opts|
39
+ opts.banner = "Usage: termplot [OPTIONS]"
40
+
41
+ parse_rows(opts)
42
+ parse_cols(opts)
43
+ parse_title(opts)
44
+ parse_line_style(opts)
45
+ parse_color(opts)
46
+ parse_command(opts)
47
+ parse_interval(opts)
48
+
49
+ opts.on("-h", "--help", "Display this help message") do
50
+ puts opts
51
+ exit(0)
52
+ end
53
+
54
+ end.parse!
55
+ self
56
+ end
57
+
58
+ private
59
+
60
+ def parse_rows(opts)
61
+ opts.on("-r ROWS", "--rows ROWS",
62
+ "Number of rows in the chart window (default: #{@rows})") do |v|
63
+ @rows = v.to_i
64
+ end
65
+ end
66
+
67
+ def parse_cols(opts)
68
+ opts.on("-c COLS", "--cols COLS",
69
+ "Number of cols in the chart window (default: #{@cols})") do |v|
70
+ @cols = v.to_i
71
+ end
72
+ end
73
+
74
+ def parse_title(opts)
75
+ opts.on("-tTITLE", "--title TITLE",
76
+ "Title of the series (default: '#{@title}')") do |v|
77
+ @title = v
78
+ end
79
+ end
80
+
81
+ def parse_line_style(opts)
82
+ line_style_opts = with_default(Termplot::CharacterMap::LINE_STYLES.keys, @line_style)
83
+ opts.on("--line-style STYLE",
84
+ "Line style. Options are: #{line_style_opts.join(", ")}") do |v|
85
+ @line_style = v.downcase
86
+ end
87
+ end
88
+
89
+ def parse_color(opts)
90
+ color_opts = Termplot::Colors::COLORS.keys.map(&:to_s).reject do |c|
91
+ c == :default
92
+ end
93
+ color_opts = with_default(color_opts, @color)
94
+ opts.on("--color COLOR",
95
+ "Series color, specified as ansi 16-bit color name:",
96
+ "(i.e. #{color_opts.join(", ")})") do |v|
97
+ @color = v.downcase
98
+ end
99
+ end
100
+
101
+ def parse_command(opts)
102
+ opts.on("--command COMMAND",
103
+ "Enables command mode, where input is received by executing",
104
+ "the specified command in intervals rather than from stdin") do |v|
105
+ @command = v
106
+ end
107
+ end
108
+
109
+ def parse_interval(opts)
110
+ opts.on("--interval INTERVAL",
111
+ "The interval at which to run the specified command in",
112
+ "command mode in milliseconds (default: #{@interval})") do |v|
113
+ @interval = v.to_i
114
+ end
115
+ end
116
+
117
+ def parse_debug
118
+ if ARGV.delete("--debug") || ARGV.delete("-d")
119
+ @debug = true
120
+ end
121
+ end
122
+
123
+ def with_default(opt_arr, default)
124
+ opt_arr.map do |opt|
125
+ opt == default ?
126
+ opt + " (default)" :
127
+ opt
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,7 @@
1
+ module Termplot
2
+ module Producers
3
+ autoload :BaseProducer, "termplot/producers/base_producer.rb"
4
+ autoload :CommandProducer, "termplot/producers/command_producer.rb"
5
+ autoload :StdinProducer, "termplot/producers/stdin_producer.rb"
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ module Termplot
2
+ module Producers
3
+ class BaseProducer
4
+ def initialize(queue, options)
5
+ @options = options
6
+ @queue = queue
7
+ @consumer = nil
8
+ end
9
+
10
+ def register_consumer(consumer)
11
+ @consumer = consumer
12
+ end
13
+
14
+ def shift
15
+ queue.shift
16
+ end
17
+
18
+ def closed?
19
+ queue.closed?
20
+ end
21
+
22
+ def close
23
+ queue.close
24
+ end
25
+
26
+ private
27
+ attr_reader :queue, :consumer, :options
28
+
29
+ FLOAT_REGEXP = /^[-+]?[0-9]*\.?[0-9]+$/
30
+ def numeric?(n)
31
+ n =~ FLOAT_REGEXP
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,20 @@
1
+ module Termplot
2
+ module Producers
3
+ class CommandProducer < BaseProducer
4
+ def run
5
+ loop do
6
+ n = `/bin/bash -c '#{options.command}'`.chomp
7
+ # TODO: Error handling...
8
+
9
+ if numeric?(n)
10
+ queue << n.to_f
11
+ consumer&.run
12
+ end
13
+
14
+ # Interval is in ms
15
+ sleep(options.interval / 1000.0)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Termplot
2
+ module Producers
3
+ class StdinProducer < BaseProducer
4
+ def run
5
+ while n = STDIN.gets&.chomp do
6
+ if numeric?(n)
7
+ queue << n.to_f
8
+ consumer&.run
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Termplot
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,5 +1,5 @@
1
- require "termplot/cursors/virtual_cursor"
2
- require "termplot/cursors/buffered_console_cursor"
1
+ require "termplot/control_chars"
2
+ require "termplot/cursors"
3
3
 
4
4
  module Termplot
5
5
  class Window
@@ -11,14 +11,14 @@ module Termplot
11
11
  end
12
12
 
13
13
  def cursor
14
- @cursor ||= VirtualCursor.new(self)
14
+ @cursor ||= Termplot::Cursors::VirtualCursor.new(self)
15
15
  end
16
16
 
17
17
  def console_cursor
18
18
  # Console buffer has an extra rows - 1 to account for new line characters
19
19
  # between rows
20
20
  @console_cursor ||=
21
- BufferedConsoleCursor.new(self, Array.new(cols * rows + rows - 1))
21
+ Termplot::Cursors::BufferedConsoleCursor.new(self, Array.new(cols * rows + rows - 1))
22
22
  end
23
23
 
24
24
  def size
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: termplot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Nyaga
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-04 00:00:00.000000000 Z
11
+ date: 2020-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-termios
@@ -42,7 +42,6 @@ files:
42
42
  - bin/termplot
43
43
  - doc/cpu.png
44
44
  - doc/demo.cast
45
- - doc/demo.gif
46
45
  - doc/memory.png
47
46
  - doc/sin.png
48
47
  - doc/tcp.png
@@ -51,10 +50,16 @@ files:
51
50
  - lib/termplot/cli.rb
52
51
  - lib/termplot/colors.rb
53
52
  - lib/termplot/consumer.rb
53
+ - lib/termplot/control_chars.rb
54
+ - lib/termplot/cursors.rb
54
55
  - lib/termplot/cursors/buffered_console_cursor.rb
55
56
  - lib/termplot/cursors/console_cursor.rb
56
- - lib/termplot/cursors/control_chars.rb
57
57
  - lib/termplot/cursors/virtual_cursor.rb
58
+ - lib/termplot/options.rb
59
+ - lib/termplot/producers.rb
60
+ - lib/termplot/producers/base_producer.rb
61
+ - lib/termplot/producers/command_producer.rb
62
+ - lib/termplot/producers/stdin_producer.rb
58
63
  - lib/termplot/renderer.rb
59
64
  - lib/termplot/series.rb
60
65
  - lib/termplot/shell.rb
@@ -83,8 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
88
  - !ruby/object:Gem::Version
84
89
  version: '0'
85
90
  requirements: []
86
- rubyforge_project:
87
- rubygems_version: 2.7.3
91
+ rubygems_version: 3.1.4
88
92
  signing_key:
89
93
  specification_version: 4
90
94
  summary: Plot time series charts in your terminal
Binary file