class Spinner

Constants

VERSION

Attributes

queue[R]

Public Class Methods

new(*tasks) click to toggle source
# File lib/spinner.rb, line 9
def initialize(*tasks)
  @queue = tasks
  @width = 0
  @chars = %w{ | / - \\ }
end

Public Instance Methods

spin!() click to toggle source

Starts executing the queued tasks.

# File lib/spinner.rb, line 44
def spin!
  # Handle no tasks in the queue.
  return unless @queue.any?

  # Mark the current time in order to calculate the total duration.
  start_time = Time.now

  # Pluralize the number of tasks in the queue.
  task_counter = "#{@queue.size} task" << (@queue.size == 1 ? '' : 's')

  # Update the print width.
  @width = (@width + (@queue.size.to_s.length + 2) * 2) + 1

  # Execute each task in sequence.
  @queue.each_with_index do |task, i|
    run_task(task, i+1)
  end

  # Reset this spinner instance so that it can be reused.
  reset!

  # Mark the completion time and calculate the duration.
  end_time = Time.now
  time_taken = distance_of_time_in_words(start_time, end_time)

  # Print the completion message.
  print("Done! #{task_counter} completed in #{time_taken} :-)\n")
end
task(title=nil, task_name=nil, &block) click to toggle source

Injects a new task into the queue.

# File lib/spinner.rb, line 16
def task(title=nil, task_name=nil, &block)
  # Handle no task being supplied.
  return @queue.map(&:title) unless block_given? || task_name

  # Set default title.
  title = 'Executing' unless title

  # Tasks can be given a block to evaluate or
  # a rake task name to invoke.
  if block_given?
    task_block = block
  elsif task_name
    task_block = Rake::Task[task_name]
  end

  # Inject the task into the queue.
  @queue << [ title, task_block ]

  # Amend the output width if necessary.
  if @width < title.length
    @width = title.length
  end

  # Return the new list of tasks.
  @queue.map(&:first)
end

Private Instance Methods

clear() click to toggle source

Clears the current printed output.

# File lib/spinner.rb, line 81
def clear
  print("\r")
  print(" ".ljust(@width + 5))
  print("\r")
end
distance_of_time_in_words(from_time, to_time) click to toggle source

Simplified extraction from ActionView.

# File lib/spinner.rb, line 129
def distance_of_time_in_words(from_time, to_time)
  distance_in_minutes = ((to_time - from_time) / 60.0).round
  distance_in_seconds = (to_time - from_time).round

  case distance_in_minutes
    when 0..1
      case distance_in_seconds
        when 0..4   then "less than 5 seconds"
        when 5..9   then "less than 10 seconds"
        when 10..19 then "less than 20 seconds"
        when 20..39 then "about half a minute"
        when 40..59 then "less than one minute"
        else             "one minute"
      end

    when 2...45  then "about #{distance_in_minutes} minutes"
    when 45...90 then "about an hour"
    else              "over an hour"
  end
end
print(*args) click to toggle source

Outputs to the console.

reset!() click to toggle source

Reset this spinner instance to defaults.

# File lib/spinner.rb, line 88
def reset!
  @width = 0
  @queue = []
end
run_task(item, counter) click to toggle source

Executes a single task.

# File lib/spinner.rb, line 94
def run_task(item, counter)
  # Extract the title & task block.
  title, task = *item

  # Print the task counter and title.
  print("#{counter}/#{queue.size}: #{title}".ljust(@width, '.') + '... ')

  # Begin a new thread to update the printed output while
  # the task runs.
  t = Thread.new {
    # Suppress $stdout during the task's execution.
    $stdout = StringIO.new
    if task.respond_to?(:invoke)
      task.invoke
    else
      task.call
    end
  }

  # Run the spinner for the duration of the task,
  # then clear the output.
  spin while t.alive?
  t.join
  clear
end
spin() click to toggle source

Update the position of the spinner.

# File lib/spinner.rb, line 121
def spin
  print(@chars[0])          # Print the next character...
  sleep(0.1)                # ...wait 100ms...
  print("\b")               # ...move the cursor back by one...
  @chars.push(@chars.shift) # ...rotate the characters array.
end