spinning_cursor 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.
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ # - jruby-18mode # JRuby in 1.8 mode
6
+ # - jruby-19mode # JRuby in 1.9 mode
7
+ - rbx-18mode
8
+ - rbx-19mode
9
+ - 1.8.7
10
+ bundler_args: --without development
11
+ script: bundle exec rake -f Rakefile.ci
data/CHANGELOG CHANGED
@@ -1,6 +1,10 @@
1
1
  CHANGELOG
2
2
  ===============================================================================
3
3
 
4
+ v0.2.1 (2013-07-28)
5
+ - Fix banner overflowing issue #19
6
+ - Ensure cross-platform support #22 #23
7
+
4
8
  v0.2.0 (2013-07-13)
5
9
  - Several bug fixes/internal API improvements (#4 #8 #9 #10 #11 #13)
6
10
  - Suppress output from action block (#7)
data/Gemfile CHANGED
@@ -5,11 +5,19 @@ source "http://rubygems.org"
5
5
 
6
6
  # Add dependencies to develop your gem here.
7
7
  # Include everything needed to run rake, tests, features, etc.
8
+
9
+ gem "highline", "~> 1.6.19"
10
+
8
11
  group :development do
9
- gem "shoulda", ">= 0"
10
12
  gem "bundler", "~> 1.3.5"
11
13
  gem "jeweler", "~> 1.8.4"
12
14
  gem "yard", "~> 0.8.6.2"
13
15
  gem "redcarpet"
14
16
  gem "github-markup"
15
17
  end
18
+
19
+ group :test do
20
+ gem "minitest", "~> 4.7", :require => "minitest/unit"
21
+ gem "rake"
22
+ gem "shoulda-context", ">= 0"
23
+ end
data/Gemfile.lock CHANGED
@@ -1,14 +1,7 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- activesupport (4.0.0)
5
- i18n (~> 0.6, >= 0.6.4)
6
- minitest (~> 4.2)
7
- multi_json (~> 1.3)
8
- thread_safe (~> 0.1)
9
- tzinfo (~> 0.3.37)
10
4
  addressable (2.3.5)
11
- atomic (1.1.10)
12
5
  builder (3.2.2)
13
6
  faraday (0.8.7)
14
7
  multipart-post (~> 1.1)
@@ -24,7 +17,6 @@ GEM
24
17
  hashie (2.0.5)
25
18
  highline (1.6.19)
26
19
  httpauth (0.2.0)
27
- i18n (0.6.4)
28
20
  jeweler (1.8.6)
29
21
  builder
30
22
  bundler (~> 1.0)
@@ -42,6 +34,7 @@ GEM
42
34
  multi_xml (0.5.4)
43
35
  multipart-post (1.2.0)
44
36
  nokogiri (1.5.10)
37
+ nokogiri (1.5.10-x86-mingw32)
45
38
  oauth2 (0.9.2)
46
39
  faraday (~> 0.8)
47
40
  httpauth (~> 0.2)
@@ -54,24 +47,20 @@ GEM
54
47
  rdoc (4.0.1)
55
48
  json (~> 1.4)
56
49
  redcarpet (3.0.0)
57
- shoulda (3.5.0)
58
- shoulda-context (~> 1.0, >= 1.0.1)
59
- shoulda-matchers (>= 1.4.1, < 3.0)
60
50
  shoulda-context (1.1.4)
61
- shoulda-matchers (2.2.0)
62
- activesupport (>= 3.0.0)
63
- thread_safe (0.1.0)
64
- atomic
65
- tzinfo (0.3.37)
66
51
  yard (0.8.6.2)
67
52
 
68
53
  PLATFORMS
69
54
  ruby
55
+ x86-mingw32
70
56
 
71
57
  DEPENDENCIES
72
58
  bundler (~> 1.3.5)
73
59
  github-markup
60
+ highline (~> 1.6.19)
74
61
  jeweler (~> 1.8.4)
62
+ minitest (~> 4.7)
63
+ rake
75
64
  redcarpet
76
- shoulda
65
+ shoulda-context
77
66
  yard (~> 0.8.6.2)
data/README.md CHANGED
@@ -10,6 +10,8 @@ Inspired by Chris Wanstrath's
10
10
  [Choice](https://github.com/defunkt/choice), Spinning Cursor provides
11
11
  you with a _sexy_ DSL for easy use of the library.
12
12
 
13
+ [![Build Status](https://travis-ci.org/prydonius/spinning_cursor.png?branch=master)](https://travis-ci.org/prydonius/spinning_cursor)
14
+
13
15
  ## Installation
14
16
 
15
17
  As easy as RubyGems:
data/Rakefile.ci ADDED
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :test)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'rake/testtask'
15
+ Rake::TestTask.new(:test) do |test|
16
+ test.libs << 'lib' << 'test'
17
+ test.pattern = 'test/**/test_*.rb'
18
+ test.verbose = true
19
+ end
20
+
21
+ task :default => :test
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
@@ -53,6 +53,13 @@ module SpinningCursor
53
53
  #
54
54
  def stop
55
55
  begin
56
+ @spinner.kill
57
+ # Wait for the cursor to die -- can cause problems otherwise
58
+ @spinner.join
59
+ # Set cursor to nil so set_banner method only works
60
+ # when cursor is actually running.
61
+ @cursor = nil
62
+
56
63
  restore_stdout_sync_status
57
64
  if console_captured?
58
65
  $console.print ESC_R_AND_CLR + $stdout.string
@@ -60,12 +67,6 @@ module SpinningCursor
60
67
  end
61
68
  show_cursor
62
69
 
63
- @spinner.kill
64
- # Wait for the cursor to die -- can cause problems otherwise
65
- @spinner.join
66
- # Set cursor to nil so set_banner method only works
67
- # when cursor is actually running.
68
- @cursor = nil
69
70
  reset_line
70
71
  puts @parsed.message
71
72
  # Set parsed to nil so set_message method only works
@@ -1,4 +1,5 @@
1
1
  require 'stringio'
2
+ require 'highline/system_extensions'
2
3
 
3
4
  $console = STDOUT
4
5
 
@@ -7,7 +8,7 @@ module SpinningCursor
7
8
  if RUBY_PLATFORM =~ /(win|w)32$/
8
9
  # DOS
9
10
  # Contains a string to clear the line in the shell
10
- CLR = " \r"
11
+ CLR = "#{(2..HighLine::SystemExtensions.terminal_size[0]).map{' '}.join}\r"
11
12
  else
12
13
  # Unix
13
14
  # Contains a string to clear the line in the shell
@@ -20,12 +21,39 @@ module SpinningCursor
20
21
  ESC_CURS_VIS = "\e[?25h"
21
22
  # ANSI escape sequence for clearing line in terminal
22
23
  ESC_R_AND_CLR = "\r#{CLR}"
24
+ # ANSI escape sequence for going up a line in terminal
25
+ ESC_UP_A_LINE = "\e[1A"
26
+
27
+ @@prev = 0
23
28
 
24
29
  #
25
30
  # Manages line reset in the console
26
31
  #
27
32
  def reset_line(text = "")
28
- $console.print "#{ESC_R_AND_CLR}#{text}"
33
+ # Initialise ANSI escape string
34
+ escape = ""
35
+
36
+ # Get terminal window width
37
+ cols = console_columns
38
+
39
+ # The number of lines the previous message spanned
40
+ lines = @@prev / cols
41
+
42
+ # If cols == 80 and @@prev == 80, @@prev / cols == 1 but we don't want to
43
+ # go up an extra line since it fits exactly
44
+ lines -= 1 if @@prev % cols == 0
45
+
46
+ # Clear and go up a line
47
+ lines.times { escape += "#{ESC_R_AND_CLR}#{ESC_UP_A_LINE}" }
48
+
49
+ # Clear the line that is to be printed on
50
+ escape += "#{ESC_R_AND_CLR}"
51
+
52
+ # Console is clear, we can print!
53
+ $console.print "#{escape}#{text}"
54
+
55
+ # Store the current message so we know how many lines it spans
56
+ @@prev = text.to_s.length
29
57
  end
30
58
 
31
59
  #
@@ -84,5 +112,12 @@ module SpinningCursor
84
112
  def show_cursor
85
113
  $console.print ESC_CURS_VIS
86
114
  end
115
+
116
+ #
117
+ # Returns the width of the terminal window
118
+ #
119
+ def console_columns
120
+ HighLine::SystemExtensions.terminal_size.first
121
+ end
87
122
  end
88
123
  end
@@ -19,7 +19,6 @@ module SpinningCursor
19
19
  #
20
20
  def spin
21
21
  $stdout.sync = true
22
- $console.print @parsed.banner
23
22
  if @parsed.delay
24
23
  send @parsed.type, @parsed.delay
25
24
  else
@@ -51,9 +50,7 @@ module SpinningCursor
51
50
  $console.print "\n" unless $stdout.string[-1,1] == "\n"
52
51
  $stdout.string = "" # TODO: Check for race condition.
53
52
  end
54
- $console.print "#{ESC_R_AND_CLR}#{@parsed.banner}"
55
- $console.print " " unless @parsed.banner.empty?
56
- $console.print "#{char}"
53
+ reset_line @parsed.banner.empty? ? char : "#{@parsed.banner} #{char}"
57
54
  sleep delay
58
55
  end
59
56
  end
@@ -5,20 +5,20 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "spinning_cursor"
8
- s.version = "0.2.0"
8
+ s.version = "0.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Adnan Abdulhussein"]
12
- s.date = "2013-07-13"
12
+ s.date = "2013-07-28"
13
13
  s.description = "Spinning Cursor is a flexible DSL that allows you to easily produce a customizable waiting/loading message for your Ruby command line program. Beautifully keep your users informed with what your program is doing when a more complex solution, such as a progress bar, doesn't fit your needs."
14
14
  s.email = "adnan@prydoni.us"
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
- "README.md",
18
- "TODO"
17
+ "README.md"
19
18
  ]
20
19
  s.files = [
21
20
  ".document",
21
+ ".travis.yml",
22
22
  ".yardopts",
23
23
  "CHANGELOG",
24
24
  "Gemfile",
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  "LICENSE.txt",
27
27
  "README.md",
28
28
  "Rakefile",
29
- "TODO",
29
+ "Rakefile.ci",
30
30
  "VERSION",
31
31
  "lib/spinning_cursor.rb",
32
32
  "lib/spinning_cursor/console_helpers.rb",
@@ -50,14 +50,14 @@ Gem::Specification.new do |s|
50
50
  s.specification_version = 3
51
51
 
52
52
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
- s.add_development_dependency(%q<shoulda>, [">= 0"])
53
+ s.add_runtime_dependency(%q<highline>, ["~> 1.6.19"])
54
54
  s.add_development_dependency(%q<bundler>, ["~> 1.3.5"])
55
55
  s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
56
56
  s.add_development_dependency(%q<yard>, ["~> 0.8.6.2"])
57
57
  s.add_development_dependency(%q<redcarpet>, [">= 0"])
58
58
  s.add_development_dependency(%q<github-markup>, [">= 0"])
59
59
  else
60
- s.add_dependency(%q<shoulda>, [">= 0"])
60
+ s.add_dependency(%q<highline>, ["~> 1.6.19"])
61
61
  s.add_dependency(%q<bundler>, ["~> 1.3.5"])
62
62
  s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
63
63
  s.add_dependency(%q<yard>, ["~> 0.8.6.2"])
@@ -65,7 +65,7 @@ Gem::Specification.new do |s|
65
65
  s.add_dependency(%q<github-markup>, [">= 0"])
66
66
  end
67
67
  else
68
- s.add_dependency(%q<shoulda>, [">= 0"])
68
+ s.add_dependency(%q<highline>, ["~> 1.6.19"])
69
69
  s.add_dependency(%q<bundler>, ["~> 1.3.5"])
70
70
  s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
71
71
  s.add_dependency(%q<yard>, ["~> 0.8.6.2"])
data/test/helper.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  require 'rubygems'
2
2
  require 'bundler'
3
3
  begin
4
- Bundler.setup(:default, :development)
4
+ Bundler.setup(:default, :development, :test)
5
5
  rescue Bundler::BundlerError => e
6
6
  $stderr.puts e.message
7
7
  $stderr.puts "Run `bundle install` to install missing gems"
8
8
  exit e.status_code
9
9
  end
10
10
  require 'test/unit'
11
- require 'shoulda'
11
+ require 'shoulda-context'
12
12
 
13
13
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
14
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -26,7 +26,7 @@ def kill_other_threads
26
26
  th.join
27
27
  end
28
28
  end
29
-
29
+
30
30
  module Kernel
31
31
  def capture_stdout
32
32
  SpinningCursor.capture_console
data/test/test_cursors.rb CHANGED
@@ -1,83 +1,120 @@
1
1
  require 'helper'
2
2
 
3
3
  class TestSpinningCursorCursor < Test::Unit::TestCase
4
- context "dots" do
5
- parsed = Parser.new { type :dots; delay 0.2; banner ""}
6
- delay = parsed.delay
7
- should "change 'frames' with correct delay" do
4
+ context "SpinningCursor::ConsoleHelpers.reset_line" do
5
+ # get the current shell width
6
+ cols = SpinningCursor::ConsoleHelpers.console_columns
7
+ regex = Regexp.new(Regexp.escape("#{ESC_R_AND_CLR}#{ESC_UP_A_LINE}"))
8
+ should "not clear lines above if it fits within the width of the shell" do
9
+ # general case
8
10
  capture_stdout do |out|
9
- dots = Thread.new do
10
- SpinningCursor::Cursor.new(parsed).spin
11
+ SpinningCursor.start do
12
+ banner (1..cols-20).map { ('a'..'z').to_a[rand(26)] }.join
13
+ action { sleep 0.1 }
11
14
  end
12
- # slight delay to get things started
13
- sleep (delay/4.0)
14
- buffer = "#{ESC_R_AND_CLR}" << "."
15
- assert_equal buffer, out.string
15
+ assert_no_match regex, out.string
16
+ end
17
+ end
16
18
 
17
- sleep delay
18
- buffer << "#{ESC_R_AND_CLR}" << ".."
19
- assert_equal buffer, out.string
19
+ should "not clear lines above if it fits exactly on the line (edge case)" do
20
+ capture_stdout do |out|
21
+ SpinningCursor.start do
22
+ # spinner type takes up two characters, so minus 2 to fit exactly
23
+ banner (1..cols-2).map { ('a'..'z').to_a[rand(26)] }.join
24
+ action { sleep 0.1 }
25
+ end
26
+ assert_no_match regex, out.string
27
+ end
28
+ end
20
29
 
21
- sleep delay
22
- buffer << "#{ESC_R_AND_CLR}" << "..."
23
- assert_equal buffer, out.string
30
+ should "clear lines above if banner message overflows" do
31
+ capture_stdout do |out|
32
+ SpinningCursor.start do
33
+ # spinner type takes up two characters, so minus 2 to fit exactly
34
+ banner (1..400).map { ('a'..'z').to_a[rand(26)] }.join
35
+ action { sleep 0.1 }
36
+ end
37
+ assert_match regex, out.string
38
+ end
39
+ end
24
40
 
25
- sleep delay
26
- buffer << "#{ESC_R_AND_CLR}"
27
- assert_equal buffer, out.string
28
- # don't need to go through the whole thing, otherwise test will take
29
- # too long
30
- dots.kill
41
+ should "clear lines above if banner message overflows (edge case)" do
42
+ capture_stdout do |out|
43
+ SpinningCursor.start do
44
+ # spinner type takes up two characters, so minus 2 to fit exactly
45
+ banner (1..cols-1).map { ('a'..'z').to_a[rand(26)] }.join
46
+ action { sleep 0.1 }
47
+ end
48
+ assert_match regex, out.string
31
49
  end
32
50
  end
33
51
  end
34
52
 
35
- context "spinner" do
36
- should "cycle through correctly" do
37
- parsed = Parser.new { type :spinner; delay 0.2; banner ""}
38
- delay = parsed.delay
53
+ context "dots" do
54
+ setup do
55
+ parsed = Parser.new { type :dots; delay 0.2; banner ""}
56
+ @delay = parsed.delay
57
+ $cycle_steps = []
58
+ $cycle_times = []
39
59
  capture_stdout do |out|
40
60
  spinner = Thread.new do
41
- SpinningCursor::Cursor.new(parsed).spin
61
+ test_cursor = SpinningCursor::Cursor.new(parsed)
62
+ class << test_cursor
63
+ def reset_line(str)
64
+ $cycle_steps.push str
65
+ $cycle_times.push Time.now
66
+ Thread.current.kill if $cycle_times.size == 5
67
+ end
68
+ end
69
+ test_cursor.spin
42
70
  end
43
- # slight delay to get things started
44
- sleep (delay/3.0)
45
- buffer = (ESC_R_AND_CLR + "|")
46
- assert_equal buffer, out.string
47
- buffer += (ESC_R_AND_CLR + "/")
48
- sleep delay
49
- assert_equal buffer, out.string
50
- buffer += (ESC_R_AND_CLR + "-")
51
- sleep delay
52
- assert_equal buffer, out.string
53
- buffer += (ESC_R_AND_CLR + "\\")
54
- sleep delay
55
- assert_equal buffer, out.string
56
- sleep delay
57
- buffer += (ESC_R_AND_CLR + "|")
58
- assert_equal buffer, out.string
59
- spinner.kill
71
+ spinner.join
72
+ end
73
+ end
74
+
75
+ should "change 'frames' with correct delay" do
76
+ $cycle_times.each_cons(2) do |t1, t2|
77
+ interval = t2-t1
78
+ assert (interval > @delay and interval < (1.5 * @delay))
60
79
  end
61
80
  end
62
81
 
63
- should "changes 'frames' with correct delay" do
82
+ should "cycle through correctly" do
83
+ assert_equal [".", "..", "...", "", "."], $cycle_steps
84
+ end
85
+ end
86
+
87
+ context "spinner" do
88
+ setup do
64
89
  parsed = Parser.new { type :spinner; delay 0.2; banner ""}
65
- delay = parsed.delay
90
+ @delay = parsed.delay
91
+ $cycle_steps = []
92
+ $cycle_times = []
66
93
  capture_stdout do |out|
67
94
  spinner = Thread.new do
68
- SpinningCursor::Cursor.new(parsed).spin
95
+ test_cursor = SpinningCursor::Cursor.new(parsed)
96
+ class << test_cursor
97
+ def reset_line(str)
98
+ $cycle_steps.push str
99
+ $cycle_times.push Time.now
100
+ Thread.current.kill if $cycle_times.size == 5
101
+ end
102
+ end
103
+ test_cursor.spin
69
104
  end
70
- sleep (delay/4.0)
71
- buffer = (ESC_R_AND_CLR + "|")
72
- assert_equal buffer, out.string
73
- buffer += (ESC_R_AND_CLR + "/")
74
- sleep delay
75
- # next frame after 'delay' second
76
- assert_equal buffer, out.string
77
- # don't need to go through the whole thing, otherwise test will take
78
- # too long
79
- spinner.kill
105
+ spinner.join
106
+ end
107
+ end
108
+
109
+ should "change 'frames' with correct delay" do
110
+ $cycle_times.each_cons(2) do |t1, t2|
111
+ interval = t2-t1
112
+ assert (interval > @delay and interval < (1.5 * @delay))
80
113
  end
81
114
  end
115
+
116
+ should "cycle through correctly" do
117
+ assert_equal ["|", "/", "-", "\\", "|"], $cycle_steps
118
+ end
82
119
  end
83
120
  end
@@ -112,11 +112,9 @@ class TestSpinningCursor < Test::Unit::TestCase
112
112
  # Have to give it time to print the banners
113
113
  sleep 0.1
114
114
  assert_equal true, (out.string.include? "Loading"), "It should initialy show default banner"
115
- sleep 0.1
116
115
  SpinningCursor.set_banner "Finishing up"
117
- sleep 0.2
116
+ sleep 0.3
118
117
  assert_equal true, (out.string.include? "Finishing up"), "It should have changed banner"
119
- sleep 0.1
120
118
  end
121
119
  end
122
120
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spinning_cursor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,24 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-13 00:00:00.000000000 Z
12
+ date: 2013-07-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: shoulda
15
+ name: highline
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ! '>='
19
+ - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
21
+ version: 1.6.19
22
+ type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - ! '>='
27
+ - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: '0'
29
+ version: 1.6.19
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: bundler
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -117,9 +117,9 @@ extensions: []
117
117
  extra_rdoc_files:
118
118
  - LICENSE.txt
119
119
  - README.md
120
- - TODO
121
120
  files:
122
121
  - .document
122
+ - .travis.yml
123
123
  - .yardopts
124
124
  - CHANGELOG
125
125
  - Gemfile
@@ -127,7 +127,7 @@ files:
127
127
  - LICENSE.txt
128
128
  - README.md
129
129
  - Rakefile
130
- - TODO
130
+ - Rakefile.ci
131
131
  - VERSION
132
132
  - lib/spinning_cursor.rb
133
133
  - lib/spinning_cursor/console_helpers.rb
@@ -155,7 +155,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
155
155
  version: '0'
156
156
  segments:
157
157
  - 0
158
- hash: 2712039492645402918
158
+ hash: 699468937831844808
159
159
  required_rubygems_version: !ruby/object:Gem::Requirement
160
160
  none: false
161
161
  requirements:
data/TODO DELETED
@@ -1,6 +0,0 @@
1
- Suppress output and show later? (give option to produce log file, or just print it to the screen after it's finished),
2
- default to hide though.
3
- deal with returns?
4
- test changes to spinning cursor, check diff for changes
5
- refactor tests to use minitest
6
- setup travis ci to test across different versions of ruby