Module: Whirly

Defined in:
lib/whirly.rb,
lib/whirly/version.rb,
lib/whirly/spinners.rb

Overview

TODO configure extra-line below TODO clear previous frame

Constant Summary collapse

CLI_COMMANDS =
{
  hide_cursor: "\x1b[?25l",
  show_cursor: "\x1b[?25h",
}
VERSION =
"0.1.1".freeze
SPINNERS =
JSON.load(File.read(File.dirname(__FILE__) + "/../../data/spinners.json"))

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.statusObject

Returns the value of attribute status.



16
17
18
# File 'lib/whirly.rb', line 16

def status
  @status
end

Class Method Details

.continueObject



112
113
114
115
# File 'lib/whirly.rb', line 112

def self.continue
  @stream.print CLI_COMMANDS[:hide_cursor] if @hide_cursor
  @paused = false
end

.enabled?Boolean

Returns:

  • (Boolean)


19
20
21
# File 'lib/whirly.rb', line 19

def self.enabled?
  @enabled
end

.next_colorObject



133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/whirly.rb', line 133

def self.next_color
  @color = @color.scan(/../).map.with_index{ |c, i|
    color_change = rand(@color_change_rate) * @color_directions[i]
    nc = c.to_i(16) + color_change
    if nc <= 0
      nc = 0
      @color_directions[i] = rand(3) - 1
    elsif nc >= 255
      nc = 255
      @color_directions[i] = rand(3) - 1
    end
    "%.2x" % nc
  }.join
end

.pauseObject



102
103
104
105
106
107
108
109
110
# File 'lib/whirly.rb', line 102

def self.pause
  # unrender
  @paused = true
  @stream.print CLI_COMMANDS[:show_cursor] if @hide_cursor
  if block_given?
    yield
    continue
  end
end

.paused?Boolean

Returns:

  • (Boolean)


23
24
25
# File 'lib/whirly.rb', line 23

def self.paused?
  @paused
end

.renderObject



123
124
125
126
127
128
129
130
131
# File 'lib/whirly.rb', line 123

def self.render
  return if @paused
  unrender
  @current_frame = @proc ? @proc.call : @frames.next
  @current_frame = Paint[@current_frame, @color] if @color
  @current_frame += "  #{@status}" if @status
  # @stream.print "\e[s#{@current_frame}\e[u"
  @stream.print "\n\e[s#{@current_frame}\e[u\e[1A"
end

.start(stream: $stdout, interval: nil, spinner: "whirly", use_color: defined?(Paint), color_change_rate: 30, status: nil, hide_cursor: true, non_tty: false) ⇒ Object

Raises:

  • (ArgumentError)


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/whirly.rb', line 27

def self.start(stream: $stdout,
               interval: nil,
               spinner: "whirly",
               use_color: defined?(Paint),
               color_change_rate: 30,
               status: nil,
               hide_cursor: true,
               non_tty: false)
  # only actviate if we are on a real terminal (or forced)
  return false unless stream.tty? || non_tty

  # ensure cursor is visible after exit
  at_exit{ @stream.print CLI_COMMANDS[:show_cursor] } if !defined?(@enabled) && hide_cursor

  # only activate once
  return false if @enabled

  # save options and preprocess
  @enabled  = true
  @paused   = false
  @stream   = stream
  @status   = status
  if spinner.is_a? Hash
    @spinner = spinner
  else
    @spinner  = SPINNERS[spinner.to_s]
  end
  raise(ArgumentError, "Whirly: Invalid spinner given") if !@spinner || (!@spinner["frames"] && !@spinner["proc"])
  @hide_cursor = hide_cursor
  @interval = (interval || @spinner["interval"] || 100) * 0.001
  @frames   = @spinner["frames"] && @spinner["frames"].cycle
  @proc     = @spinner["proc"]

  # init color
  if use_color
    if defined?(Paint)
      @color = "%.6x" % rand(16777216)
      @color_directions = (0..2).map{ |e| rand(3) - 1 }
      @color_change_rate = color_change_rate
    else
      warn "Whirly warning: Using colors requires the paint gem"
    end
  end

  # hide cursor
  @stream.print CLI_COMMANDS[:hide_cursor] if @hide_cursor

  # start spinner loop
  @thread = Thread.new do
    while true # it's just a spinner, no exact timing here
      next_color if @color
      render
      sleep(@interval)
    end
  end

  # idiomatic block syntax
  if block_given?
    yield
    Whirly.stop
  end

  true
end

.stop(delete = false) ⇒ Object



92
93
94
95
96
97
98
99
100
# File 'lib/whirly.rb', line 92

def self.stop(delete = false)
  return false unless @enabled
  @thread.terminate
  @enabled = false
  @stream.print CLI_COMMANDS[:show_cursor] if @hide_cursor
  print "TODO" if delete
  
  true
end

.unrenderObject



117
118
119
120
121
# File 'lib/whirly.rb', line 117

def self.unrender
  return unless @current_frame
  current_frame_size = @current_frame.size
  @stream.print "\n\e[s#{' ' * current_frame_size}\e[u\e[1A"
end