Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Symbol
- def / sym
- :"#{self}/#{sym}"
- end
- def ~
- Checklist.lists[self].start
- end
- end
- module Checklist
- class << self; attr_accessor :lists; end
- def checklist label=nil, description=nil, &block
- label ||= "list-#{Time.now.to_i}-#{rand 1000}"
- Checklist.lists ||= {}
- Checklist.lists[label] = List.new label, description, &block
- end
- class List
- attr_accessor :current, :score_override, :total_override
- attr_reader :checks
- def initialize label, description=nil, &block
- @label = label
- @description = description
- @checks = []
- instance_eval &block
- end
- def check description=nil, options={}, &block
- options[:checklist] ||= self
- @checks << Check.new(description, options, &block)
- end
- def previous
- @current > 0 ? @checks[@current-1].run : @checks[@current].run
- end
- def next
- available = @current+1 <= @checks.size-1
- if available then
- @checks[@current+1].run
- else
- @checks[@current].answer ? finish : @checks[@current].run
- end
- end
- def start
- @checks.first.run
- end
- def finish
- report
- exit
- end
- def report
- puts
- puts "="*50
- @checks.each_with_index do |check, i|
- puts "Check\t##{i+1}: #{check.score}/#{check.total}"
- end
- puts "-"*50
- puts "Score: #{score}/#{total}"
- puts "="*50
- end
- def score
- @checks.map{|c| c.score}.reduce :"+"
- end
- def total
- @checks.map{|c| c.total}.reduce :"+"
- end
- end
- class Check
- attr_reader :answer, :score
- def initialize description=nil, options={}, &block
- @description = description
- @options = options
- @options[:value] ||= 1
- @options[:mandatory] ||= false
- @score = 0
- instance_eval &block if block_given?
- raise RuntimeError, "Task #{@options[:label]} is not assigned to any checklist" unless @options[:checklist]
- raise RuntimeError, "No description provided for task #{@options[:label]}" unless @description
- [:value, :label, :mandatory, :checklist].each do |v|
- var = :"@#{v}"
- instance_variable_set var, @options[v] unless instance_variable_get var
- end
- end
- def total
- if @choices then
- @choices.map{|c| c[:value]}.max
- else
- @value
- end
- end
- def description text
- @description = text
- end
- def mandatory
- @mandatory = true
- end
- def beforehand &block
- @beforehand = block
- end
- def afterwards &block
- @afterwards = block
- end
- def value n
- @value = n
- end
- def choice description, value=1
- @choices ||= []
- @choices << {description: description, value: value}
- end
- def run
- @checklist.current = @checklist.checks.index self
- instance_eval &@beforehand if @beforehand
- loop do
- puts "="*50
- puts "Check #{@checklist.current+1}/#{@checklist.checks.size} (Score: #{@checklist.score}/#{@checklist.total})"
- puts "-"*50
- describe
- break if (@choices ? choose : confirm)
- end
- instance_eval &@afterwards if @afterwards
- @checklist.next
- end
- protected
- def describe
- print @description
- end
- def choose
- print "\n"
- @choices.each_with_index do |choice, i|
- puts "-- #{i+1}. #{choice[:description]}"
- end
- @answer = input do |answer|
- sel = answer.to_i
- sel > 0 && sel <= @choices.size
- end
- @score = @choices[@answer.to_i-1][:value] if @answer
- end
- def confirm
- print " [y/n]\n"
- @answer = input do |answer|
- answer =~ /^(y(es)?|n(o)?)$/i
- end
- if @answer then
- @score = @answer =~ /^y(es)?$/i ? @value : 0
- end
- end
- def finish
- @checklist.finish
- end
- def separate
- puts '='*50
- end
- def input(message="=> Error: Invalid answer.", prompt='~> ', &block)
- puts "~"*50
- print prompt
- answer = gets.chomp
- case answer
- when '<' then
- @checklist.previous
- return
- when '>' then
- if @mandatory then
- message = "=> Error: check cannot be skipped."
- else
- @checklist.next
- return
- end
- when '<<' then
- @checklist.start
- return
- when '>>' then
- @checklist.finish
- end
- valid = block.call(answer)
- if valid then
- answer
- else
- puts message
- false
- end
- end
- end
- end
- ###########################
- include Checklist
- checklist :test/:checklist do
- check "Ready?"
- check do
- description "Choose something"
- mandatory
- choice "Do this"
- choice "Do that", 0
- choice "None of the above", 2
- afterwards do
- if @score > 1 then
- finish
- end
- end
- end
- check do
- description "Do something else?"
- value 3
- end
- check "OK?", value: 10, mandatory: true
- end
- ~(:test/:checklist)
Add Comment
Please, Sign In to add comment