termistat 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ pkg/*
4
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in termistat.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ termistat (0.0.1)
5
+ ffi-ncurses
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ ffi (1.0.9)
11
+ ffi-ncurses (0.3.3)
12
+ ffi (>= 0.6.3)
13
+ rake (0.9.2)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ rake
20
+ termistat!
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2011 Solomon White
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # Termistat
2
+
3
+ Termistat displays an ncurses-based status bar atop your STDOUT.
4
+
5
+ ## Scenario:
6
+
7
+ You have a long-running process that writes detailed log information to
8
+ standard output. You would like to also be able to determine overall
9
+ progress at a glance. You could scatter status lines among the log
10
+ lines, but that's messy and can be hard to find. You could ditch the
11
+ detail output and display status only, but then you lose the sense of
12
+ what's going on at the detail level.
13
+
14
+ ## The Solution
15
+
16
+ Termistat gives you the best of both worlds. You still have your
17
+ detailed information, but you also have a status bar overlay with which
18
+ you can display summary information.
19
+
20
+ ## Screenshot
21
+
22
+ Here's what termistat looks like in action:
23
+
24
+ ![screenshot](https://github.com/rubysolo/termistat/raw/master/examples/file_copy.png)
25
+
26
+
27
+ ## Installation:
28
+
29
+ gem install termistat
30
+
31
+ ## Usage:
32
+
33
+ Include the module in your class, and you get a `status_bar` method.
34
+
35
+ class VerboseProcess
36
+ include Termistat
37
+
38
+ def perform
39
+ 1000.times do |index|
40
+ status_bar progress(index / 1000.0)
41
+ $stdout.puts "This is normal log entry number #{ index }"
42
+
43
+ # do some hard work
44
+ sleep(rand(10))
45
+ end
46
+ end
47
+
48
+ def progress(pct)
49
+ "status: %0.2f% complete" % (pct * 100)
50
+ end
51
+ end
52
+
53
+ Don't want to or can't include? No problem, you can use the module
54
+ method.
55
+
56
+ class VerboseProcess
57
+ def perform
58
+ 1000.times do |index|
59
+ Termistat.status_bar progress(index / 1000.0)
60
+ $stdout.puts "This is normal log entry number #{ index }"
61
+
62
+ # do some hard work
63
+ sleep(rand(10))
64
+ end
65
+ end
66
+
67
+ def progress(pct)
68
+ "status: %0.2f complete" % pct
69
+ end
70
+ end
71
+
72
+ ## Configuration:
73
+
74
+ Termistat provides a default configuration that will display your status
75
+ bar in the top right corner of your terminal. Using the configuration
76
+ DSL, you can customize the status bar to your liking.
77
+
78
+ Termistat.config do
79
+ position :top
80
+ align :center
81
+ background :black
82
+ foreground :magenta
83
+ end
84
+
85
+ ## Requirements
86
+
87
+ * ffi-ncurses gem
88
+ * ncurses (tested with homebrew-installed ncurses)
89
+
90
+ ## License
91
+
92
+ The MIT License (MIT)
93
+ Copyright (c) 2011 Solomon White
94
+
95
+ Permission is hereby granted, free of charge, to any person obtaining a copy
96
+ of this software and associated documentation files (the "Software"), to deal
97
+ in the Software without restriction, including without limitation the rights
98
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99
+ copies of the Software, and to permit persons to whom the Software is
100
+ furnished to do so, subject to the following conditions:
101
+
102
+ The above copyright notice and this permission notice shall be included in all
103
+ copies or substantial portions of the Software.
104
+
105
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
106
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
107
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
108
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
109
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
110
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
111
+ SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new('test') do |t|
5
+ t.pattern = 'test/**/test_*.rb'
6
+ t.warning = true
7
+ end
8
+
9
+ task :default => :test
10
+
Binary file
@@ -0,0 +1,17 @@
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'termistat'
3
+
4
+ class FileCopy
5
+ include Termistat
6
+
7
+ def simulate
8
+ ('a'..'z').to_a.each_with_index do |letter, index|
9
+ status_bar("%0.1f%% complete" % ((index / 26.to_f) * 100))
10
+ puts "copying /path/to/file/#{ letter }..."
11
+ sleep rand(0.5)
12
+ end
13
+ end
14
+ end
15
+
16
+ fc = FileCopy.new
17
+ fc.simulate
data/lib/termistat.rb ADDED
@@ -0,0 +1,146 @@
1
+ require 'termistat/config'
2
+ require 'termistat/tee_io'
3
+ require 'termistat/version'
4
+
5
+ begin
6
+ require 'ffi-ncurses'
7
+ rescue LoadError
8
+ require 'rubygems'
9
+ require 'ffi-ncurses'
10
+ end
11
+
12
+ #
13
+ # Termistat is a status bar for your terminal
14
+ #
15
+ # :title:Termistat
16
+
17
+ module Termistat
18
+ #
19
+ # The +status_bar+ instance method initializes the status bar if necessary
20
+ # and displays your message.
21
+ #
22
+ # === Parameters
23
+ # * message = the messge you want to display
24
+ #
25
+ # === Example
26
+ # include Termistat
27
+ # status_bar "37% complete"
28
+ #
29
+ def status_bar(message)
30
+ Termistat.status_bar message
31
+ end
32
+
33
+ class << self
34
+ #
35
+ # the +status_bar+ class method initializes the status bar if necessary
36
+ # and displays your message.
37
+ #
38
+ # === Parameters
39
+ # * message = the messge you want to display
40
+ #
41
+ # === Example
42
+ # Termistat.status_bar "37% complete"
43
+ #
44
+ def status_bar(message)
45
+ setup unless @stdscr
46
+ m = formatted_message(message, config.align, status_bar_width)
47
+
48
+ FFI::NCurses.wmove @status, 0, 0
49
+ FFI::NCurses.wattr_set @status, FFI::NCurses::A_NORMAL, 1, nil
50
+ FFI::NCurses.waddstr @status, m
51
+ FFI::NCurses.wrefresh @status
52
+ end
53
+
54
+ #
55
+ # +config+ either returns the active configuration or (when a block is
56
+ # passed), sets up the configuration DSL. See Termistat::Config for
57
+ # supported parameters and options.
58
+ #
59
+ # === Example
60
+ # Termistat.config do
61
+ # align :left
62
+ # end
63
+ #
64
+ def config(&block)
65
+ if block_given?
66
+ c = Config.new
67
+ c.instance_eval(&block)
68
+ @config = c
69
+ end
70
+
71
+ @config ||= Config.new
72
+ end
73
+
74
+ #:enddoc:
75
+ def config=(config)
76
+ @config = config
77
+ end
78
+
79
+ def setup
80
+ # set up ncurses standard screen
81
+ @stdscr = FFI::NCurses.initscr
82
+ FFI::NCurses.scrollok @stdscr, 1
83
+
84
+ # set up ncurses status bar
85
+ @height, @width = FFI::NCurses.getmaxyx(@stdscr)
86
+
87
+ @status = FFI::NCurses.newwin(*status_bar_params)
88
+ FFI::NCurses.scrollok @status, 0
89
+
90
+ # set up colors
91
+ FFI::NCurses.start_color
92
+ background = FFI::NCurses::Color.const_get(config.background.to_s.upcase)
93
+ foreground = FFI::NCurses::Color.const_get(config.foreground.to_s.upcase)
94
+ FFI::NCurses.init_pair(1, foreground, background)
95
+
96
+ # hide cursor
97
+ FFI::NCurses.curs_set 0
98
+
99
+ # redirect stdout
100
+ $stdout = TeeIO.new do |msg|
101
+ FFI::NCurses.addstr msg
102
+ FFI::NCurses.refresh
103
+
104
+ FFI::NCurses.touchwin @status
105
+ FFI::NCurses.wrefresh @status
106
+ end
107
+
108
+ at_exit do
109
+ FFI::NCurses.endwin
110
+
111
+ output = $stdout.string
112
+ $stdout = STDOUT
113
+ puts output
114
+ end
115
+ end
116
+
117
+ def status_bar_params
118
+ case config.position
119
+ when Array
120
+ config.position
121
+ when :top
122
+ [1, @width, 0, 0]
123
+
124
+ when :top_right
125
+ x = @width / 2
126
+ w = @width - x
127
+ [1, w, 0, x]
128
+
129
+ when :top_left
130
+ x = @width / 2
131
+ w = @width - x
132
+ [1, w, 0, 0]
133
+
134
+ end
135
+ end
136
+
137
+ def status_bar_width
138
+ status_bar_params[1]
139
+ end
140
+
141
+ def formatted_message(string, alignment, width)
142
+ return string.center(width) if :center === alignment
143
+ "%#{ :left === alignment ? '-' : '' }#{ width }s" % string
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,77 @@
1
+ module Termistat
2
+ #
3
+ # The configuration class and DSL for Termistat
4
+ #
5
+ class Config
6
+ def initialize(options={}) #:notnew:
7
+ @options = {
8
+ :position => :top_right,
9
+ :align => :left,
10
+ :foreground => :white,
11
+ :background => :blue,
12
+ }.merge(options)
13
+ end
14
+
15
+ #
16
+ # position of the status bar on the terminal
17
+ #
18
+ # === Supported Options
19
+ # * +:top_left+ : left half of top line
20
+ # * +:top+ : full top line
21
+ # * +:top_right+ : right half of top line
22
+ #
23
+ def position(position=nil)
24
+ @options[:position] = position unless position.nil?
25
+ @options[:position]
26
+ end
27
+
28
+ #
29
+ # alignment of text within the status bar
30
+ #
31
+ # === Supported Options
32
+ # * +:left+
33
+ # * +:center+
34
+ # * +:right+
35
+ #
36
+ def align(align=nil)
37
+ @options[:align] = align unless align.nil?
38
+ @options[:align]
39
+ end
40
+
41
+ #
42
+ # color of foreground (text)
43
+ #
44
+ # === Supported Options
45
+ # * +:black+
46
+ # * +:red+
47
+ # * +:green+
48
+ # * +:yellow+
49
+ # * +:blue+
50
+ # * +:magenta+
51
+ # * +:cyan+
52
+ # * +:white+
53
+ #
54
+ def foreground(color=nil)
55
+ @options[:foreground] = color unless color.nil?
56
+ @options[:foreground]
57
+ end
58
+
59
+ #
60
+ # color of background
61
+ #
62
+ # === Supported Options
63
+ # * +:black+
64
+ # * +:red+
65
+ # * +:green+
66
+ # * +:yellow+
67
+ # * +:blue+
68
+ # * +:magenta+
69
+ # * +:cyan+
70
+ # * +:white+
71
+ #
72
+ def background(color=nil)
73
+ @options[:background] = color unless color.nil?
74
+ @options[:background]
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,30 @@
1
+ require 'stringio'
2
+
3
+ module Termistat
4
+ #
5
+ # TeeIO wraps a StringIO object such that writes to the IO can trigger events
6
+ # immediately, but the entirety of the string is available later.
7
+ #
8
+ # initialize method takes a block that will be called on every write.
9
+ #
10
+ class TeeIO < StringIO
11
+ # create a new TeeIO object
12
+ #
13
+ # == Example
14
+ # $stdout = TeeIO.new {|str| STDOUT.puts str.reverse }
15
+ #
16
+ def initialize(&block)
17
+ @io = StringIO.new
18
+ @callback = block
19
+ end
20
+
21
+ def write(chars)
22
+ @io.write(chars)
23
+ @callback.call(chars)
24
+ end
25
+
26
+ def string
27
+ @io.string
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Termistat
2
+ VERSION = "0.0.1"
3
+ end
data/termistat.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "termistat/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "termistat"
7
+ s.version = Termistat::VERSION
8
+ s.authors = ["Solomon White"]
9
+ s.email = ["rubysolo@gmail.com"]
10
+ s.homepage = "https://github.com/rubysolo/termistat"
11
+ s.summary = %q{Terminal status bar}
12
+ s.description = %q{Display status bar overlay for summary information}
13
+
14
+ s.rubyforge_project = "termistat"
15
+
16
+ s.add_runtime_dependency "ffi-ncurses"
17
+ s.add_development_dependency "rake"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'minitest/autorun'
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
@@ -0,0 +1,16 @@
1
+ require_relative '../helper'
2
+ require 'termistat/tee_io'
3
+
4
+ class TestTeeIO < MiniTest::Unit::TestCase
5
+ def setup
6
+ @default = Termistat::Config.new
7
+ @custom = Termistat::Config.new(
8
+ :position => :top_right,
9
+ :align => :left,
10
+ )
11
+ end
12
+
13
+ def test_configuration
14
+ assert_equal :top_right, @default.position
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ require_relative '../helper'
2
+ require 'termistat/tee_io'
3
+
4
+ class TestTeeIO < MiniTest::Unit::TestCase
5
+ def test_callback
6
+ @capture = nil
7
+ @tee_io = Termistat::TeeIO.new {|msg| @capture = msg }
8
+ @tee_io.print "foo"
9
+ assert_equal "foo", @capture
10
+ end
11
+
12
+ def test_output_is_recorded
13
+ @tee_io = Termistat::TeeIO.new {|*args|}
14
+ @tee_io.puts "foo"
15
+ assert_equal "foo\n", @tee_io.string
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ require_relative '../helper'
2
+ require 'termistat'
3
+
4
+ class Included
5
+ include Termistat
6
+ end
7
+
8
+ class TestTermistat < MiniTest::Unit::TestCase
9
+ def setup
10
+ Termistat.config = nil
11
+ @included = Included.new
12
+ end
13
+
14
+ def test_status_bar_method
15
+ assert @included.respond_to?(:status_bar)
16
+ end
17
+
18
+ def test_ncurses_initialization
19
+ # @included.status_bar "hello"
20
+ end
21
+
22
+ def test_default_configuration
23
+ assert_equal :top_right, Termistat.config.position
24
+ end
25
+
26
+ def test_configuration
27
+ Termistat.config do
28
+ position :top_left
29
+ align :center
30
+ end
31
+
32
+ assert_equal :top_left, Termistat.config.position
33
+ end
34
+
35
+ def test_text_alignment
36
+ assert_equal "foo ", Termistat.formatted_message("foo", :left, 10)
37
+ assert_equal " foo", Termistat.formatted_message("foo", :right, 10)
38
+ assert_equal " foo ", Termistat.formatted_message("foo", :center, 10)
39
+ end
40
+
41
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: termistat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Solomon White
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-24 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi-ncurses
16
+ requirement: &70307433171700 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70307433171700
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70307433171180 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70307433171180
36
+ description: Display status bar overlay for summary information
37
+ email:
38
+ - rubysolo@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - Gemfile.lock
46
+ - LICENSE
47
+ - README.md
48
+ - Rakefile
49
+ - examples/file_copy.png
50
+ - examples/file_copy.rb
51
+ - lib/termistat.rb
52
+ - lib/termistat/config.rb
53
+ - lib/termistat/tee_io.rb
54
+ - lib/termistat/version.rb
55
+ - termistat.gemspec
56
+ - test/helper.rb
57
+ - test/units/test_config.rb
58
+ - test/units/test_tee_io.rb
59
+ - test/units/test_termistat.rb
60
+ homepage: https://github.com/rubysolo/termistat
61
+ licenses: []
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project: termistat
80
+ rubygems_version: 1.8.6
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Terminal status bar
84
+ test_files:
85
+ - test/helper.rb
86
+ - test/units/test_config.rb
87
+ - test/units/test_tee_io.rb
88
+ - test/units/test_termistat.rb