spinning_cursor 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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