lib/secretsanta.rb in secretsanta-1.0.3 vs lib/secretsanta.rb in secretsanta-1.1.0
- old
+ new
@@ -1,66 +1,74 @@
# frozen_string_literal: true
require 'twilio-ruby'
-require_relative 'secretsanta/version'
-
-module SecretSanta
+class SecretSanta
class Error < StandardError; end
- module_function
+ VERSION = '1.1.0'
- def notify_participants!(options)
- client = Twilio::REST::Client.new(options.twilio_account_sid, options.twilio_auth_token)
- pairs = generate_pairs(options.participants)
+ def initialize(options)
+ @dry_run = options.dry_run
+ @from_number = options.from_number
+ @participants = options.participants
+ @sms = Twilio::REST::Client.new(options.twilio_account_sid, options.twilio_auth_token) unless @dry_run
+ end
- return pairs if options.dry_run
+ def notify_participants!
+ pairs = generate_pairs
+ return pairs if @dry_run
+
pairs.each do |pair|
- client.messages.create(
+ @sms.messages.create(
body: "Happy holidays! You have been assigned to give a gift to #{pair.recipient_name} this year.",
- from: options.from_number,
+ from: @from_number,
to: pair.sender_number
)
rescue Twilio::Rest::TwilioError => e
puts e.message
end
- "\nAll participants have been notified - happy holidays! 🎅 🎄 🎁\n\n"
+ "\nAll participants have been notified. Happy holidays! 🎅 🎄 🎁\n\n"
end
- def generate_pairs(participants)
+ def generate_pairs
+ raise Error, SecretSanta.error_message if impossible?
+
[].tap do |list|
loop do
- participants.each do |participant|
- index = rand 0..participants.length - 1
- recipient = participants[index]
+ @participants.each do |sender|
+ recipient = @participants.sample
- next if try_again?(participant, recipient)
+ next if try_again?(sender, recipient)
- list << { sender_number: participant[:number], recipient_name: recipient[:name] }
+ list << { sender_number: sender[:number], recipient_name: recipient[:name] }
- participant[:has_assignment] = true
- participants[index][:is_assigned] = true
+ sender[:has_assignment] = true
+ recipient[:is_assigned] = true
end
- break if done?(participants)
+ break if done?
end
end
end
- def try_again?(sender, recipient)
- disallowed = !sender[:disallow].nil? && sender[:disallow].include?(recipient[:name])
+ def done?
+ @participants.all? { |p| p[:has_assignment] && p[:is_assigned] }
+ end
- return true if disallowed || sender[:has_assignment] || recipient[:is_assigned]
+ def impossible?
+ @participants.one? || invalid_hash?
end
- def done?(participants)
- participants.all? { |p| p[:has_assignment] && p[:is_assigned] }
+ def try_again?(sender, recipient)
+ sender[:has_assignment] || recipient[:is_assigned] || sender[:number] == recipient[:number] ||
+ !sender[:disallow].nil? && sender[:disallow].include?(recipient[:name])
end
- def help_text
+ def self.help_text
<<~HEREDOC
SecretSanta, version #{VERSION}
To run, provide command-line arguments or set corresponding environment variables:
@@ -69,7 +77,27 @@
- TWILIO_PHONE_NUMBER
Command-line arguments:
HEREDOC
+ end
+
+ def self.error_message
+ <<~HEREDOC
+ Looks like something is wrong with your participants file. Make sure that it:
+
+ 1. Follows the format specified in README.md
+ 2. Contains enough participants so that everyone can be matched
+ 3. Doesn't have too many blacklisted participants (see "disallow" array in README.md)
+ HEREDOC
+ end
+
+ private
+
+ def invalid_hash?
+ @participants.each do |participant|
+ return true unless %i[name number].all? { |k| participant.key? k }
+ end
+
+ false
end
end