viking-pairity 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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