whirly 0.1.1 → 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.
@@ -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