viking-pairity 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,69 @@
1
+ require 'yaml'
2
+
3
+ module Pairity
4
+ class Config
5
+
6
+ FILENAME = '.pairity'
7
+ PATH = "#{Dir.home}/#{FILENAME}"
8
+
9
+ @@config = {}
10
+
11
+ def self.config
12
+ @@config
13
+ end
14
+
15
+ def self.configured?
16
+ self.load
17
+ !@@config.any? { |key, value| value.nil? || value.empty? }
18
+ end
19
+
20
+ def self.add(options={})
21
+ add_option(:channel, options[:channel])
22
+ add_option(:url, options[:url])
23
+ end
24
+
25
+ def self.save
26
+ File.open(PATH, 'w+') do |f|
27
+ f.write(YAML.dump(config))
28
+ end
29
+ end
30
+
31
+ def self.load
32
+ file_exists = File.exists?(PATH)
33
+ if File.exists?(PATH)
34
+ value = YAML.load_file(PATH)
35
+ else
36
+ value = defaults
37
+ end
38
+ @@config = value
39
+ end
40
+
41
+ def self.get(key)
42
+ config[key]
43
+ end
44
+
45
+ def self.display
46
+ if config.empty?
47
+ puts "No config values set"
48
+ else
49
+ config.each do |key, value|
50
+ puts "#{key.upcase}: #{value}"
51
+ end
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def self.defaults
58
+ {
59
+ :channel => 'general',
60
+ :url => '',
61
+ }
62
+ end
63
+
64
+ def self.add_option(key, value)
65
+ config[key] = value unless value.nil?
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,17 @@
1
+ module Pairity
2
+
3
+ class Edge
4
+ attr_accessor :weight, :days, :resistance
5
+
6
+ def initialize(weight: 0, days: 0, resistance: 1)
7
+ @weight = weight
8
+ @days = days
9
+ @resistance = resistance
10
+ end
11
+
12
+ def to_s
13
+ "Weight: #{weight} Days: #{days}"
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,174 @@
1
+ require "google/api_client"
2
+ require 'pp'
3
+ require "google_drive"
4
+ require "ruby-progressbar"
5
+
6
+ ENV['SSL_CERT_FILE'] = Gem.loaded_specs['google-api-client'].full_gem_path+'/lib/cacerts.pem'
7
+
8
+ module Pairity
9
+ class GoogleSync
10
+
11
+ CONFIG_FILE = Dir.home + "/.pairity_google.json"
12
+
13
+ attr_reader :sheet_url
14
+
15
+ def initialize(matrix)
16
+ @matrix = matrix
17
+ @people = {}
18
+ @sheet_url = nil
19
+ end
20
+
21
+ def load
22
+ unless File.exists?(CONFIG_FILE)
23
+ puts "Welcome, newcomer!"
24
+ puts "Please follow these instructions to allow #{Rainbow("Pairity").white} to use Google Sheets to sync its precious data."
25
+ end
26
+
27
+ session = GoogleDrive.saved_session(CONFIG_FILE)
28
+
29
+ puts "Loading Matrix from Google Sheets..."
30
+ progressbar = ProgressBar.create(total: 100)
31
+
32
+ progressbar.progress += 20
33
+ sheet = session.spreadsheet_by_title("Pairity")
34
+ unless sheet
35
+ puts "Creating a new spreadsheet called: Pairity"
36
+ sheet = session.create_spreadsheet("Pairity")
37
+ sheet.add_worksheet("Days")
38
+ sheet.add_worksheet("Resistance")
39
+ sheet.add_worksheet("Weights")
40
+ ws = sheet.worksheets[0]
41
+ ws.title = "People"
42
+ ws.save
43
+ else
44
+ end
45
+ @sheet_url = sheet.worksheets[0].human_url
46
+
47
+ ws = sheet.worksheets[0]
48
+
49
+ # Add People and Tiers to Matrix
50
+ ws.num_rows.times do |row|
51
+ next unless row > 0
52
+ name = ws[row + 1, 1]
53
+ next if name.strip.empty?
54
+ tier = ws[row + 1, 2]
55
+ if name == "Han Solo"
56
+ person = @matrix.han_solo
57
+ else
58
+ person = Person.new(name: name, tier: tier)
59
+ @matrix.add_person(person)
60
+ end
61
+ @people[person] = row + 1
62
+ end
63
+
64
+ # Add data to edges
65
+ (1..3).each do |i|
66
+ ws = sheet.worksheets[i]
67
+ @people.each do |p1, row|
68
+ @people.each do |p2, col|
69
+ next if p1 == p2
70
+ data = ws[row, col]
71
+ edit_edge(p1, p2, data, i)
72
+ end
73
+ end
74
+ end
75
+
76
+ @matrix
77
+ end
78
+
79
+
80
+ def clear_worksheet(ws)
81
+ (1..ws.num_rows).each do |i|
82
+ (1..ws.num_rows).each do |j|
83
+ ws[i, j] = ""
84
+ ws[j, i] = ""
85
+ end
86
+ end
87
+ end
88
+
89
+ def save
90
+ puts "Saving Matrix to Google Sheets..."
91
+ progressbar = ProgressBar.create(total: 100)
92
+
93
+ session = GoogleDrive.saved_session(CONFIG_FILE)
94
+ sheet = session.spreadsheet_by_title("Pairity")
95
+ @people = @matrix.all_people.sort
96
+ p @matrix.matrix
97
+
98
+ progressbar.progress += 20
99
+
100
+ ws = sheet.worksheets[0]
101
+
102
+ clear_worksheet(ws)
103
+
104
+ ws[1, 1] = "Name"
105
+ ws[1, 2] = "Tier (1-3)"
106
+ @people.each_with_index do |person, index|
107
+ ws[index + 2, 1] = person.name
108
+ ws[index + 2, 2] = person.tier
109
+ end
110
+ ws.save
111
+
112
+ (1..3).each do |i|
113
+ ws = sheet.worksheets[i]
114
+
115
+ clear_worksheet(ws)
116
+
117
+ @people.each_with_index do |person, index|
118
+ ws[1, index + 2] = person.name
119
+ ws[index + 2, 1] = person.name
120
+ end
121
+
122
+ progressbar.progress += 20
123
+ @people.combination(2) do |pair|
124
+ p1, p2 = pair
125
+ index1 = @people.index(p1)
126
+ index2 = @people.index(p2)
127
+ edge = @matrix[p1,p2]
128
+ case i
129
+ when 1
130
+ ws[1,1] = "Days"
131
+ data = edge.days
132
+ when 2
133
+ ws[1,1] = "Resistances"
134
+ data = edge.resistance
135
+ when 3
136
+ ws[1,1] = "Weights"
137
+ data = edge.weight
138
+ end
139
+ ws[index1 + 2, index2 + 2] = data
140
+ ws[index2 + 2, index1 + 2] = data
141
+ end
142
+
143
+ max = ws.max_rows
144
+
145
+ @people.each_with_index do |person, index|
146
+ ws[index + 2, index + 2] = ""
147
+ ws[index + 2, index + 2] = ""
148
+ max = index + 3
149
+ end
150
+
151
+ ws.save
152
+ end
153
+ progressbar.progress += 20
154
+
155
+ end
156
+
157
+ def edit_edge(p1, p2, data, i)
158
+ case i
159
+ when 1
160
+ @matrix[p1, p2].days = data.to_i
161
+ when 2
162
+ @matrix[p1, p2].resistance = (data ? 1 : data.to_i)
163
+ when 3
164
+ @matrix[p1, p2].weight = data.to_i
165
+ end
166
+ end
167
+
168
+ def find_person(name)
169
+
170
+ person = @people.find { |person| person.name == name }
171
+
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,79 @@
1
+ require 'byebug'
2
+ require 'pry-byebug'
3
+
4
+ module Pairity
5
+ class PairGenerator
6
+
7
+ @@shuffle = false
8
+
9
+ attr_reader :pairs, :last_pairs
10
+
11
+ def self.shuffle=(toggle)
12
+ @@shuffle = toggle
13
+ end
14
+
15
+ def initialize(matrix)
16
+ @matrix = matrix
17
+ @last_pairs = []
18
+ @pairs = []
19
+ @nopes = []
20
+ end
21
+
22
+ def generate_pairs
23
+ @pairs = []
24
+ @pairs = @matrix.optimal_pairs(@nopes)
25
+ move_solo_to_the_end
26
+ @pairs
27
+ end
28
+
29
+ def possible_pairs
30
+ @matrix.possible_pairs.reject { |pairing| pairing.any? { |pair| @nopes.include?(pair) }}
31
+ end
32
+
33
+ def move_solo_to_the_end
34
+ solo = @pairs.find { |pair| pair.any? { |person| person.name == "Han Solo" } }
35
+ return @pairs unless solo
36
+ index = @pairs.index(solo)
37
+ @pairs[index], @pairs[-1] = @pairs[-1], @pairs[index]
38
+ @pairs
39
+ end
40
+
41
+ def nope(p1,p2)
42
+ pair = [p1, p2].sort
43
+ @nopes << pair
44
+ end
45
+
46
+ def save_pairs
47
+ @pairs.each do |pair|
48
+ @matrix.add_weight_to_pair(1, pair)
49
+ @matrix.add_day_to_pair(pair)
50
+ end
51
+ @nopes = []
52
+ @last_pairs = @pairs
53
+ end
54
+
55
+ def revert
56
+ @pairs = @last_pairs
57
+ end
58
+
59
+ def days_for_pair(person1, person2)
60
+ @matrix[person1, person2].days
61
+ end
62
+
63
+ def abolish_pairing(person1, person2)
64
+ @matrix.add_weight_to_pair(1_000_000,[person1,person2].sort)
65
+ end
66
+
67
+ def resistance(person1, person2, resistance)
68
+ @matrix[person1, person2].resistance = resistance
69
+ end
70
+
71
+ def equilibrium
72
+ @matrix.people.combination(2).to_a.size / (@matrix.people.size / 2)
73
+ end
74
+
75
+ def include?(person1, person2)
76
+ @pairs.any? { |pair| pair == [person1, person2].sort }
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,20 @@
1
+ module Pairity
2
+ class PairSaver
3
+ def initialize(pairs)
4
+ @pairs = pairs
5
+ end
6
+
7
+ def post_to_slack
8
+ rows = []
9
+ @pairs.each_with_index do |pair, index|
10
+ col = []
11
+ col << "Room ##{index+1}"
12
+ col << pair[0]
13
+ col << pair[1]
14
+ rows << col
15
+ end
16
+ table = Terminal::Table.new headings: ["Room","Driver","Navigator"], rows: rows
17
+ Slackbot.new.post("```#{table.to_s}```")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module Pairity
2
+ class PairRenderer
3
+ def initialize(matrix)
4
+ @matrix = matrix
5
+ end
6
+
7
+ def stats_for_pair(person1, person2)
8
+ edge = @matrix[person1, person2]
9
+ "paired #{Rainbow(edge.days).white} times."
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ module Pairity
2
+ class Person
3
+ @@id = 0
4
+
5
+ attr_accessor :name, :tier, :id
6
+
7
+ def initialize(name:, tier: 2)
8
+ @name = name
9
+ @tier = !((1..3) === tier) ? 2 : tier
10
+ end
11
+
12
+ def <=>(other_person)
13
+ return 1 if name == "Han Solo"
14
+ return -1 if other_person.name == "Han Solo"
15
+ name <=> other_person.name
16
+ end
17
+
18
+ def to_s
19
+ "#{name}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # require 'slack-poster'
2
+
3
+ module Pairity
4
+ class Slackbot
5
+
6
+ def initialize
7
+ Config.load
8
+ hook = Config.get(:url)
9
+ options = {
10
+ icon_url: 'https://static1.squarespace.com/static/54e22d6be4b00617871820ca/54e567bbe4b022f3194c63b5/55ddd86ae4b0f0c3127f8483/1440605037480/?format=1000w',
11
+ username: 'Pairity',
12
+ channel: slack_channel
13
+ }
14
+ # @poster = Slack::Poster.new(hook, options)
15
+ end
16
+
17
+ def post(message)
18
+ # @poster.send_message(message)
19
+ end
20
+
21
+ def slack_channel
22
+ channel = Config.get(:channel)
23
+ return "#" + channel unless channel =~ /^#/
24
+ channel
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module Pairity
2
+ VERSION = "0.1.1"
3
+ end
data/pairity.gemspec ADDED
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pairity/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "viking-pairity"
8
+ spec.version = Pairity::VERSION
9
+ spec.authors = ["Kit Langton"]
10
+ spec.email = ["kitlangton@gmail.com"]
11
+
12
+ spec.summary = %q{A fair and balanced gem for pair rotation.}
13
+ spec.description = %q{A fair and balanced gem for pair rotation.}
14
+ spec.homepage = "https://github.com/kitlangton/pairity"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.11"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "rspec", "~> 3.0"
33
+ spec.add_development_dependency "guard-rspec"
34
+ spec.add_development_dependency "byebug"
35
+ spec.add_development_dependency "pry-byebug"
36
+
37
+ spec.add_runtime_dependency "highline"
38
+ spec.add_runtime_dependency "rainbow"
39
+ spec.add_runtime_dependency "google_drive"
40
+ spec.add_runtime_dependency "google-api-client", "~> 0.8.6"
41
+ spec.add_runtime_dependency "terminal-table"
42
+ spec.add_runtime_dependency "ruby-progressbar"
43
+ spec.add_runtime_dependency "slack-poster"
44
+ spec.add_runtime_dependency "graph_matching"
45
+ end