whirly 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,7 @@
1
- require "json"
2
-
3
1
  module Whirly
4
- SPINNERS = JSON.load(File.read(File.dirname(__FILE__) + "/../../data/spinners.json"))
5
- SPINNERS["whirly"] = { "proc" => ->(){ [0x1F600 + rand(55)].pack("U") }, "interval" => 200 }
2
+ module Spinners
3
+ end
6
4
  end
5
+
6
+ require_relative "spinners/whirly"
7
+ require_relative "spinners/cli"
@@ -0,0 +1,7 @@
1
+ require "json"
2
+
3
+ module Whirly
4
+ module Spinners
5
+ CLI = JSON.load(File.read(File.dirname(__FILE__) + "/../../../data/cli-spinners.json")).freeze
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ require "json"
2
+
3
+ module Whirly
4
+ module Spinners
5
+ WHIRLY = {
6
+ "whirly" => { "proc" => ->(){ [0x1F600 + rand(55) ].pack("U") }, "interval" => 200 },
7
+ "random_dots" => { "proc" => ->(){ [ 0x2800 + rand(256)].pack("U") }, "interval" => 100 },
8
+ "circled_letter" => { "proc" => ->(){ [ 0x24B6 + rand(26) ].pack("U") }, "interval" => 120 },
9
+ "circled_number" => { "proc" => ->(){ [ 0x2460 + rand(9) ].pack("U") }, "interval" => 120 },
10
+ "starlike" => { "proc" => ->(){ [ 0x2729 + rand(34) ].pack("U") }, "interval" => 120 },
11
+ "mahjong" => { "proc" => ->(){ [0x1F000 + rand(44)].pack("U") }, "interval" => 200 },
12
+ "domino" => { "proc" => ->(){ [0x1F030 + rand(50)].pack("U") }, "interval" => 200 },
13
+ "vertical_domino" => { "proc" => ->(){ [0x1F062 + rand(50)].pack("U") }, "interval" => 200 },
14
+ "letters_with_parens" => { "proc" => ->(){ [0x1F110 + rand(26)].pack("U") }, "interval" => 150 },
15
+ }
16
+ WHIRLY.merge! JSON.load(File.read(File.dirname(__FILE__) + "/../../../data/whirly-static-spinners.json"))
17
+
18
+ WHIRLY.freeze
19
+ end
20
+ end
@@ -1,4 +1,4 @@
1
1
  module Whirly
2
- VERSION = "0.1.1".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
4
4
 
data/spec/whirly_spec.rb CHANGED
@@ -1,29 +1,250 @@
1
1
  require_relative "../lib/whirly"
2
2
  require "minitest/autorun"
3
+ # require "irbtools/binding"
4
+ require "stringio"
5
+
6
+ def short_sleep
7
+ sleep 0.1
8
+ end
9
+
10
+ def medium_sleep
11
+ sleep 0.4
12
+ end
13
+
14
+ def long_sleep
15
+ sleep 1
16
+ end
3
17
 
4
18
  describe Whirly do
5
- describe "usage" do
19
+ before do
20
+ Whirly.reset
21
+ @capture = StringIO.new
22
+ Whirly.configure(non_tty: true, stream: @capture)
23
+ end
24
+
25
+ describe "General Usage" do
6
26
  it "outputs every frame of the spinner" do
7
- spinner = { "frames" => ["first", "second", "third"], "interval" => 10 }
27
+ spinner = { "frames" => ["first", "second", "third"], "interval" => 5 }
28
+
29
+ Whirly.start(spinner: spinner)
30
+ short_sleep
31
+ Whirly.stop
32
+
33
+ assert_match /first.*second.*third/m, @capture.string
34
+ end
35
+
36
+ it "calls spinner proc instead of frames if proc is given" do
37
+ spinner = { "proc" => ->(){ "frame" }, "interval" => 5 }
8
38
 
9
- assert_output /first.*second.*third/m do
10
- Whirly.start(spinner: spinner, non_tty: true)
11
- sleep 0.1
39
+ Whirly.start(spinner: spinner)
40
+ short_sleep
41
+ Whirly.stop
42
+
43
+ assert_match /frame/, @capture.string
44
+ end
45
+ end
46
+
47
+ describe "Status Updates" do
48
+ it "shows status text alongside spinner" do
49
+ Whirly.start
50
+ Whirly.status = "Fetching…"
51
+ medium_sleep
52
+ Whirly.status = "Updates…"
53
+ medium_sleep
54
+ Whirly.stop
55
+
56
+ assert_match /Fetching.*Updates…/m, @capture.string
57
+ end
58
+
59
+ it "shows initial status" do
60
+ Whirly.start(status: "Initial")
61
+ short_sleep
62
+ Whirly.stop
63
+
64
+ assert_match /Initial/, @capture.string
65
+ end
66
+ end
67
+
68
+ describe "Finishing" do
69
+ it "shows spinner finished frame if stop is set in spinner definition" do
70
+ spinner = { "frames" => ["first", "second", "third"], "stop" => "STOP", "interval" => 5 }
71
+
72
+ Whirly.start(spinner: spinner)
73
+ short_sleep
74
+ Whirly.stop
75
+
76
+ assert_match /STOP/, @capture.string
77
+ end
78
+
79
+ it "shows spinner finished frame if stop frame is passed when stopping" do
80
+ spinner = { "frames" => ["first", "second", "third"], "interval" => 5 }
81
+
82
+ Whirly.start(spinner: spinner)
83
+ short_sleep
84
+ Whirly.stop("STOP")
85
+
86
+ assert_match /STOP/, @capture.string
87
+ end
88
+
89
+ it "shows spinner finished frame if stop frame is passed when starting" do
90
+ spinner = { "frames" => ["first", "second", "third"], "interval" => 5 }
91
+
92
+ Whirly.start(spinner: spinner, stop: "STOP")
93
+ short_sleep
94
+ Whirly.stop
95
+
96
+ assert_match /STOP/, @capture.string
97
+ end
98
+
99
+ it "appends newline when stopping" do
100
+ Whirly.start(hide_cursor: false)
101
+ short_sleep
102
+ Whirly.stop
103
+
104
+ assert_match /\n\z/, @capture.string
105
+ end
106
+
107
+ it "appends no newline when stopping when :append_newline option is false" do
108
+ Whirly.start(hide_cursor: false, append_newline: false)
109
+ short_sleep
110
+ Whirly.stop
111
+
112
+ assert_match /[^\n]\z/, @capture.string
113
+ end
114
+
115
+ it "removes the spinner after stopping when :remove_after_stop is true" do
116
+ Whirly.start(hide_cursor: false, remove_after_stop: true)
117
+ short_sleep
118
+ Whirly.stop
119
+
120
+ assert_match /\e\[u\n\z/, @capture.string
121
+ end
122
+ end
123
+
124
+ describe "Spinner" do
125
+ describe "Passing a Spinner" do
126
+ it "can be the name of a bundled spinner (whirly-spinners)" do
127
+ Whirly.start(spinner: "pencil")
128
+ medium_sleep
129
+ Whirly.stop
130
+
131
+ assert_match /✎/, @capture.string
132
+ end
133
+
134
+ it "can be the name of a bundled spinner (cli-spinners)" do
135
+ Whirly.start(spinner: "dots3")
136
+ medium_sleep
137
+ Whirly.stop
138
+
139
+ assert_match /⠋/, @capture.string
140
+ end
141
+
142
+ it "can be an Array of frames" do
143
+ Whirly.start(spinner: ["A", "B"])
144
+ medium_sleep
12
145
  Whirly.stop
146
+
147
+ assert_match /A.*B/m, @capture.string
148
+ end
149
+
150
+ it "can be an Enumerator of frames" do
151
+ Whirly.start(spinner: "A".."B")
152
+ medium_sleep
153
+ Whirly.stop
154
+
155
+ assert_match /A.*B/m, @capture.string
156
+ end
157
+
158
+ it "can be a Proc which generates frames" do
159
+ Whirly.start(spinner: ->(){ "frame" })
160
+ medium_sleep
161
+ Whirly.stop
162
+
163
+ assert_match /frame/m, @capture.string
13
164
  end
14
165
  end
15
166
 
16
- it "calls spinner proc instead of frames if proc is given" do
17
- spinner = { "proc" => ->(){ "frame" }, "interval" => 10 }
167
+ describe "Frame Mode" do
168
+ it "can be set to random" do
169
+ spinner = { "frames" => "A".."H", "mode" => "random", "interval" => 10 }
170
+
171
+ Whirly.start(spinner: spinner)
172
+ medium_sleep
173
+ Whirly.stop
174
+
175
+ refute /A.*B.*C.*D.*E.*F.*G.*H/m =~ @capture.string
176
+ end
177
+
178
+ it "can be set to reverse" do
179
+ spinner = { "frames" => "A".."H", "mode" => "reverse", "interval" => 10 }
180
+
181
+ Whirly.start(spinner: spinner)
182
+ medium_sleep
183
+ Whirly.stop
184
+
185
+ assert_match /H.*G.*F.*E.*D.*C.*B.*A/m, @capture.string
186
+ end
187
+
188
+ it "can be set to swing" do
189
+ spinner = { "frames" => "A".."H", "mode" => "swing", "interval" => 10 }
18
190
 
19
- assert_output /frame/ do
20
- Whirly.start(spinner: spinner, non_tty: true)
21
- sleep 0.1
191
+ Whirly.start(spinner: spinner)
192
+ medium_sleep
22
193
  Whirly.stop
194
+
195
+ assert_match /A.*B.*C.*D.*E.*F.*G.*H.*G.*F.*E.*D.*C.*B.*A/m, @capture.string
23
196
  end
24
197
  end
25
198
  end
26
199
 
200
+ describe "Ansi Escape Mode" do
201
+ it "will use save and restore ANSI sequences as default (or when 'restore') is given" do
202
+ Whirly.start
203
+ short_sleep
204
+ Whirly.stop
205
+ assert_match /\e\[s.*\e\[u/m, @capture.string
206
+ end
207
+
208
+ it "will use beginning of line and clear line ANSI sequences when 'line' is given" do
209
+ Whirly.start(ansi_escape_mode: 'line')
210
+ medium_sleep
211
+ Whirly.stop
212
+ assert_match /\e\[G.*\e\[1K/m, @capture.string
213
+ end
214
+ end
215
+
216
+ describe "Positioning" do
217
+ it "will render spinner 1 line further below (useful for spinning while git cloning)" do
218
+ Whirly.start(position: "below")
219
+ short_sleep
220
+ Whirly.stop
221
+
222
+ assert_match /\n.*\e\[1A/m, @capture.string
223
+ end
224
+ end
225
+
226
+ describe "Configure and Reset" do
227
+ it "can be configured before starting" do
228
+ Whirly.configure spinner: "dots", interval: 5
229
+
230
+ Whirly.start
231
+ short_sleep
232
+ Whirly.stop
233
+
234
+ assert_match /⠧/, @capture.string
235
+ end
236
+
237
+ it "can be reset using .reset" do
238
+ Whirly.configure spinner: "dots", interval: 5
239
+ Whirly.reset
240
+
241
+ Whirly.start(non_tty: true, stream: @capture)
242
+ short_sleep
243
+ Whirly.stop
244
+ assert_match /\A[^⠧]+\z/, @capture.string
245
+ end
246
+ end
247
+
27
248
  describe ".enabled?" do
28
249
  it "returns false if whirly was not started yet" do
29
250
  refute_predicate Whirly, :enabled?
data/whirly.gemspec CHANGED
@@ -6,18 +6,21 @@ Gem::Specification.new do |gem|
6
6
  gem.name = "whirly"
7
7
  gem.version = Whirly::VERSION
8
8
  gem.summary = "Whirly: The friendly terminal spinner"
9
- gem.description = "Whirly: The friendly terminal spinner"
9
+ gem.description = "Simple terminal spinner with support for custom spinners. Includes spinners from npm's cli-spinners."
10
10
  gem.authors = ["Jan Lelis"]
11
11
  gem.email = ["mail@janlelis.de"]
12
12
  gem.homepage = "https://github.com/janlelis/whirly"
13
13
  gem.license = "MIT"
14
14
 
15
15
  gem.files = Dir["{**/}{.*,*}"].select{ |path| File.file?(path) && path !~ /^(pkg|data)/ } + %w[
16
- data/spinners.json
16
+ data/cli-spinners.json
17
+ data/whirly-static-spinners.json
17
18
  ]
18
19
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19
20
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
21
  gem.require_paths = ["lib"]
21
22
 
23
+ gem.add_dependency "unicode-display_width", "~> 1.1"
24
+
22
25
  gem.required_ruby_version = "~> 2.0"
23
26
  end
metadata CHANGED
@@ -1,16 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whirly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Lelis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-30 00:00:00.000000000 Z
12
- dependencies: []
13
- description: 'Whirly: The friendly terminal spinner'
11
+ date: 2016-10-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: unicode-display_width
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ description: Simple terminal spinner with support for custom spinners. Includes spinners
28
+ from npm's cli-spinners.
14
29
  email:
15
30
  - mail@janlelis.de
16
31
  executables: []
@@ -27,13 +42,19 @@ files:
27
42
  - MIT-LICENSE.txt
28
43
  - README.md
29
44
  - Rakefile
30
- - data/spinners.json
31
- - euruko.rb
45
+ - data/cli-spinners.json
46
+ - data/whirly-static-spinners.json
47
+ - examples/all_spinners.rb
48
+ - examples/asciinema_bundled_spinners.rb
49
+ - examples/euruko.rb
50
+ - examples/multi_lines.rb
51
+ - examples/single.rb
52
+ - examples/status.rb
32
53
  - lib/whirly.rb
33
- - lib/whirly/.spinners.rb.swp
34
54
  - lib/whirly/spinners.rb
55
+ - lib/whirly/spinners/cli.rb
56
+ - lib/whirly/spinners/whirly.rb
35
57
  - lib/whirly/version.rb
36
- - spec/.whirly_spec.rb.swp
37
58
  - spec/whirly_spec.rb
38
59
  - whirly.gemspec
39
60
  homepage: https://github.com/janlelis/whirly
@@ -61,5 +82,4 @@ signing_key:
61
82
  specification_version: 4
62
83
  summary: 'Whirly: The friendly terminal spinner'
63
84
  test_files:
64
- - spec/.whirly_spec.rb.swp
65
85
  - spec/whirly_spec.rb
Binary file
Binary file