mob_rotation 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/.rspec +2 -0
- data/.rubocop.yml +33 -0
- data/.travis.yml +4 -0
- data/Changelog.md +4 -0
- data/Contributors.md +29 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +27 -0
- data/Rakefile +1 -0
- data/bin/mob_rotation +13 -0
- data/lib/mob_rotation.rb +7 -0
- data/lib/mob_rotation/command_routing.rb +29 -0
- data/lib/mob_rotation/database.rb +32 -0
- data/lib/mob_rotation/mobster.rb +12 -0
- data/lib/mob_rotation/rotation.rb +210 -0
- data/lib/mob_rotation/version.rb +3 -0
- data/mob_rotation.gemspec +24 -0
- data/spec/foo_fighter_spec.rb +31 -0
- data/spec/mob_rotation_executable_spec.rb +324 -0
- data/spec/rotation_spec.rb +129 -0
- data/spec/spec_helper.rb +19 -0
- data/todo.md +113 -0
- data/woot_camp_todo.md +28 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4eac9d67bd7b967609ce166c6785f810ff8e7310
|
4
|
+
data.tar.gz: 8921a18fe1c2501f1440ad93c75deba49583e9b0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5440387200cf66a07f8b019e24a2ab08efc448837c8e6859314bd8e0839acc2f54b917f21dd511460db2a2440330edaf3790f7f36efe7c07f69955f83a13c0f0
|
7
|
+
data.tar.gz: 27b0e608088f922085c72017a0f7543520f49b7dd92753735c3d8582e1d979245ae8e03b131d60f8609d150b85e9a8a31e98a6dba265be07285c30d98592794e
|
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
/.bundle/
|
2
|
+
/.yardoc
|
3
|
+
/Gemfile.lock
|
4
|
+
/_yardoc/
|
5
|
+
/coverage/
|
6
|
+
/doc/
|
7
|
+
/pkg/
|
8
|
+
/spec/reports/
|
9
|
+
/tmp/
|
10
|
+
*.bundle
|
11
|
+
*.so
|
12
|
+
*.o
|
13
|
+
*.a
|
14
|
+
*~
|
15
|
+
*_test.*
|
16
|
+
rotation.txt
|
17
|
+
test*.txt
|
18
|
+
results.txt
|
19
|
+
rotate.txt
|
20
|
+
\#*\#
|
21
|
+
.\#*
|
22
|
+
tmp
|
23
|
+
vendor
|
24
|
+
*.swp
|
25
|
+
mkmf.log
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Default settings here:
|
2
|
+
# https://github.com/bbatsov/rubocop/blob/master/config/default.yml
|
3
|
+
# Find enabled settings here:
|
4
|
+
# https://github.com/bbatsov/rubocop/blob/master/config/enabled.yml
|
5
|
+
# We also prefer `or` and `and` for control flow:
|
6
|
+
# http://devblog.avdi.org/2014/08/26/how-to-use-rubys-english-andor-operators-without-going-nuts/
|
7
|
+
AllCops:
|
8
|
+
Exclude:
|
9
|
+
- bin/**
|
10
|
+
- config/**/*
|
11
|
+
- script/**
|
12
|
+
# Follow the Jim Weirich school of thought on usage of do/end vs. {...}:
|
13
|
+
# http://devblog.avdi.org/2011/07/26/the-procedurefunction-block-convention-in-ruby/
|
14
|
+
Blocks:
|
15
|
+
Enabled: false
|
16
|
+
CollectionMethods:
|
17
|
+
PreferredMethods:
|
18
|
+
map: "collect"
|
19
|
+
find: "detect"
|
20
|
+
find_all: "select"
|
21
|
+
reduce: "inject"
|
22
|
+
Documentation:
|
23
|
+
Enabled: false
|
24
|
+
EachWithObject:
|
25
|
+
Enabled: false
|
26
|
+
Lambda:
|
27
|
+
Enabled: false
|
28
|
+
RegexpLiteral:
|
29
|
+
MaxSlashes: 0
|
30
|
+
StringLiterals:
|
31
|
+
EnforcedStyle: double_quotes
|
32
|
+
TrailingBlankLines:
|
33
|
+
EnforcedStyle: final_newline
|
data/.travis.yml
ADDED
data/Changelog.md
ADDED
data/Contributors.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
* [Abhishek Bose](http://abhishekbose.com)
|
2
|
+
* [Alex Harms](http://twitter.com/onealexharms)
|
3
|
+
* [Alistair Cockburn](http://alistair.cockburn.us)
|
4
|
+
* [Amitai Schlair](http://www.schmonz.com)
|
5
|
+
* [Andrew Broman](http://github/afbroman)
|
6
|
+
* [Ben Thompson](http://github.com/kotay)
|
7
|
+
* [Dan Wagner](http://github.com/danwagnerco)
|
8
|
+
* [Harri Jauri](http://twitter.com/harrijauri)
|
9
|
+
* [Jacqueline S. Homan](http://github.com/jacqueline-homan)
|
10
|
+
* [Jared Smith](http://sublimecoding.com)
|
11
|
+
* [J. B. Rainsberger](http://jbrains.ca)
|
12
|
+
* [Jen Diamond](http://jendiamond.com)
|
13
|
+
* [Jonathan Whittington](http://github.com/ixil)
|
14
|
+
* Kocur4d
|
15
|
+
* [Lucas Mendelowski](http://github.com/lowski)
|
16
|
+
* [Luisa Lima](http://github.com/luisalima)
|
17
|
+
* [Luke DeWitt](http://github.com/ledewitt)
|
18
|
+
* [Luqi Pan](https://github.com/LuqiPan)
|
19
|
+
* [Mark](https://github.com/Digital-Learner)
|
20
|
+
* [Mike Bonifer](http://gamechangers.com)
|
21
|
+
* [Pat Maddox](http://patmaddox.com)
|
22
|
+
* [Paul Yeoh](http://github.com/paul-ylz)
|
23
|
+
* [Philip Coates](http://github.com/pcoates99)
|
24
|
+
* [Ralph Hafliger](http://github.com/heroturtle)
|
25
|
+
* [Rob Wilkinson](http://github.com/robawilkinson)
|
26
|
+
* [Russell Baker](http://twitter.com/_russellb)
|
27
|
+
* [Sean Miller](http://github.com/smiller)
|
28
|
+
* [Willem Larsen](http://github.com/willemlarsen)
|
29
|
+
* [Woody Zuill](http://zuill.us/WoodyZuill/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Pat Maddox
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Mob Rotation
|
2
|
+
============
|
3
|
+
|
4
|
+
### Features
|
5
|
+
* Command line interface to simulate the [mob programming][mob_wiki_link] environment
|
6
|
+
* Timer funtionality to indicate rotation
|
7
|
+
* Ability to tell who is the driver, navigator and mobsters
|
8
|
+
|
9
|
+
### Instructions For Use
|
10
|
+
TODO
|
11
|
+
|
12
|
+
### Gems and Dependencies
|
13
|
+
* Ruby 2.1.2
|
14
|
+
* RSpec
|
15
|
+
|
16
|
+
### Upcoming Features
|
17
|
+
* Timer
|
18
|
+
* Randomization of Driver/Navigator
|
19
|
+
* Browser-based GUI
|
20
|
+
|
21
|
+
### Additional Resources
|
22
|
+
* <http://mobprogramming.org/>
|
23
|
+
|
24
|
+
### Credits
|
25
|
+
TODO
|
26
|
+
|
27
|
+
[mob_wiki_link]: http://en.wikipedia.org/wiki/Mob_programming
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/mob_rotation
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "mob_rotation"
|
3
|
+
|
4
|
+
file_name = ENV["DB_FILE"] || "rotate.txt"
|
5
|
+
command = ARGV[0] || "show"
|
6
|
+
mobster_names = ARGV[1..-1]
|
7
|
+
git_dir = ENV["MOB_GIT_DIR"] || File.join(Dir.pwd, ".git")
|
8
|
+
|
9
|
+
mob_rotator = MobRotation::Rotation.new(
|
10
|
+
MobRotation::Database.new(file_name),
|
11
|
+
git_dir
|
12
|
+
)
|
13
|
+
mob_rotator.command_router(command, mobster_names)
|
data/lib/mob_rotation.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module MobRotation
|
2
|
+
module CommandRouting
|
3
|
+
COMMAND_MAPPINGS = {}
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def define_command(name, &block)
|
7
|
+
CommandRouting::COMMAND_MAPPINGS[name] = block
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def command_router(command, mobster_names)
|
12
|
+
command_implementation = CommandRouting::COMMAND_MAPPINGS.fetch(command) {
|
13
|
+
lambda { |command|
|
14
|
+
inform_lovely_user(command)
|
15
|
+
}
|
16
|
+
}
|
17
|
+
case command_implementation.arity
|
18
|
+
when -2
|
19
|
+
instance_exec(command, *mobster_names, &command_implementation)
|
20
|
+
when -1
|
21
|
+
instance_exec(*mobster_names, &command_implementation)
|
22
|
+
when 1
|
23
|
+
instance_exec(command, &command_implementation)
|
24
|
+
else
|
25
|
+
instance_exec(&command_implementation)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module MobRotation
|
4
|
+
class Database
|
5
|
+
def sanitized_entries_in
|
6
|
+
each_database_entry(@filename) do |entry|
|
7
|
+
yield(entry.to_s.strip)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(filename)
|
12
|
+
@filename = filename
|
13
|
+
FileUtils.touch(filename) unless File.exist?(filename)
|
14
|
+
end
|
15
|
+
|
16
|
+
def write(mobsters)
|
17
|
+
File.open(@filename, "w") do |file|
|
18
|
+
mobsters.each do |mobster|
|
19
|
+
file << format_mobster(mobster.name, mobster.email) << "\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def format_mobster(name, email)
|
25
|
+
name + (" <#{email}>" if email && !email.empty?).to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def each_database_entry(filename)
|
29
|
+
File.readlines(filename).collect { |entry| yield(entry) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require "time"
|
2
|
+
require "mob_rotation/command_routing"
|
3
|
+
require "mob_rotation/mobster"
|
4
|
+
|
5
|
+
module MobRotation
|
6
|
+
class Rotation
|
7
|
+
include CommandRouting
|
8
|
+
extend CommandRouting::ClassMethods
|
9
|
+
|
10
|
+
define_command("show") do
|
11
|
+
show_mobsters
|
12
|
+
end
|
13
|
+
|
14
|
+
define_command("run_with_timer") do
|
15
|
+
countdown_to_rotate(ARGV[1].to_i)
|
16
|
+
end
|
17
|
+
|
18
|
+
define_command("rotate") do
|
19
|
+
rotate
|
20
|
+
show_mobsters
|
21
|
+
end
|
22
|
+
|
23
|
+
define_command("random") do
|
24
|
+
random(ARGV[1])
|
25
|
+
show_mobsters
|
26
|
+
end
|
27
|
+
|
28
|
+
define_command("add") do |*mobster_names|
|
29
|
+
add_mobster(*mobster_names)
|
30
|
+
show_mobsters
|
31
|
+
end
|
32
|
+
|
33
|
+
define_command("remove") do |*mobster_names|
|
34
|
+
remove_mobsters(*mobster_names)
|
35
|
+
show_mobsters
|
36
|
+
end
|
37
|
+
|
38
|
+
define_command("help") do
|
39
|
+
show_help
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.annoying_and_probably_not_accidental_beep(n = number_of_beeps)
|
43
|
+
n.times { print("\a") || sleep(minimum_sleep_between_beeps) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.minimum_sleep_between_beeps
|
47
|
+
0.2
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.number_of_beeps
|
51
|
+
5
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(database, git_dir)
|
55
|
+
@git_dir = git_dir
|
56
|
+
@database = database
|
57
|
+
@real_mobsters = @database.sanitized_entries_in do | entry |
|
58
|
+
build_mobster(entry)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_mobster(entry)
|
63
|
+
name = extract_name_from(entry)
|
64
|
+
email = extract_email_from(entry)
|
65
|
+
Mobster.new(name, email)
|
66
|
+
end
|
67
|
+
|
68
|
+
def extract_email_from(entry)
|
69
|
+
if entry =~ /\<(.*)\>/
|
70
|
+
Regexp.last_match[1]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def write(text)
|
75
|
+
puts(text)
|
76
|
+
end
|
77
|
+
|
78
|
+
def show_mobsters
|
79
|
+
@real_mobsters.each_with_index do |person, index|
|
80
|
+
case index
|
81
|
+
when 0
|
82
|
+
write("git username: #{person.name}")
|
83
|
+
write("git user email: #{person.email}")
|
84
|
+
format_mobster("Driver", person)
|
85
|
+
when 1
|
86
|
+
format_mobster("Navigator", person)
|
87
|
+
else
|
88
|
+
format_mobster("Mobster", person)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def format_mobster(role, person)
|
94
|
+
if person.email.to_s.empty?
|
95
|
+
write("#{role} #{person.name}")
|
96
|
+
else
|
97
|
+
write("#{role} #{person.name.strip} <#{person.email.strip}>")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_mobster(*mobsters_to_add)
|
102
|
+
mobsters_to_add.collect(&:to_s).collect(&:strip).each do |mobster_to_add|
|
103
|
+
fail if mobster_to_add.empty?
|
104
|
+
|
105
|
+
if @real_mobsters.collect(&:name).include?(mobster_to_add)
|
106
|
+
write("user name '#{mobster_to_add}' already exists")
|
107
|
+
next
|
108
|
+
end
|
109
|
+
|
110
|
+
@real_mobsters << Mobster.new(mobster_to_add)
|
111
|
+
end
|
112
|
+
|
113
|
+
sync
|
114
|
+
end
|
115
|
+
|
116
|
+
def remove_mobster(given_mobster)
|
117
|
+
@real_mobsters.each_with_index do |mobster, i|
|
118
|
+
if found_mobster(mobster, given_mobster)
|
119
|
+
@real_mobsters.delete_at(i)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
sync
|
123
|
+
end
|
124
|
+
|
125
|
+
def remove_mobsters(*mobsters)
|
126
|
+
mobsters.each do |mobster|
|
127
|
+
remove_mobster(mobster)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def show_help
|
132
|
+
puts ["Available commands are:",
|
133
|
+
"show",
|
134
|
+
"help",
|
135
|
+
"rotate",
|
136
|
+
"random",
|
137
|
+
"add <name1> [name2]",
|
138
|
+
"remove <name1> [name2]",
|
139
|
+
"run_with_timer [seconds]"
|
140
|
+
]
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
def countdown_to_rotate(seconds = 300)
|
145
|
+
sleep(seconds)
|
146
|
+
puts("Time to rotate")
|
147
|
+
self.class.annoying_and_probably_not_accidental_beep
|
148
|
+
end
|
149
|
+
|
150
|
+
def inform_lovely_user(command)
|
151
|
+
puts("Unknown command #{command}")
|
152
|
+
show_help
|
153
|
+
end
|
154
|
+
|
155
|
+
def rotate_mobsters(&rotation_algorithm)
|
156
|
+
rotation_algorithm.call
|
157
|
+
git_config_update
|
158
|
+
sync
|
159
|
+
end
|
160
|
+
|
161
|
+
def rotate
|
162
|
+
puts("")
|
163
|
+
rotate_mobsters do
|
164
|
+
@real_mobsters << @real_mobsters.shift
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def random(seed = nil)
|
169
|
+
puts("Randomized Output")
|
170
|
+
rotate_mobsters do
|
171
|
+
srand(seed.to_i) if seed
|
172
|
+
@real_mobsters.shuffle!
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def extract_next_mobster_email
|
177
|
+
email = @real_mobsters.first.email.to_s.strip
|
178
|
+
email.empty? ? "mob@rubysteps.com" : email
|
179
|
+
end
|
180
|
+
|
181
|
+
def time_to_rotate
|
182
|
+
puts("Time to rotate!")
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def git_config_update
|
188
|
+
# FIX yo that rescue nil is bogus
|
189
|
+
system(git_config_for("name", @real_mobsters.first.name)) rescue nil
|
190
|
+
system(git_config_for("email", extract_next_mobster_email)) rescue nil
|
191
|
+
end
|
192
|
+
|
193
|
+
def git_config_for(property, value)
|
194
|
+
"git --git-dir=#{@git_dir} config user.#{property} '#{value}'"
|
195
|
+
end
|
196
|
+
|
197
|
+
def sync
|
198
|
+
@database.write(@real_mobsters)
|
199
|
+
end
|
200
|
+
|
201
|
+
def found_mobster(line, mobster)
|
202
|
+
line.to_s.strip == mobster.to_s
|
203
|
+
end
|
204
|
+
|
205
|
+
def extract_name_from(entry)
|
206
|
+
entry_to_array = entry.split("")
|
207
|
+
entry_to_array.take_while { |c| c != "<" }.join("")
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "mob_rotation/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "mob_rotation"
|
8
|
+
spec.version = MobRotation::VERSION
|
9
|
+
spec.authors = ["Pat Maddox"]
|
10
|
+
spec.email = ["pat@rubysteps.com"]
|
11
|
+
spec.summary = "Manage a mob list during a mobbing session"
|
12
|
+
spec.description = "Provides an executable to manage a mob list"
|
13
|
+
spec.homepage = "https://github.com/RubySteps/mob_rotation"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe FooFighter do
|
4
|
+
it "raises an error when a class defines `#foo`" do
|
5
|
+
expect {
|
6
|
+
class TestClass
|
7
|
+
extend FooFighter
|
8
|
+
|
9
|
+
def foo
|
10
|
+
"shouldn't work"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
}.to raise_error(/no foo for you/)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "removes a method named `#foo`" do
|
17
|
+
begin
|
18
|
+
class TestClass2
|
19
|
+
extend FooFighter
|
20
|
+
|
21
|
+
def foo
|
22
|
+
"shouldn't work"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
rescue => e
|
26
|
+
# no-op
|
27
|
+
ensure
|
28
|
+
expect(TestClass2.instance_methods - Object.methods).to_not include(:foo)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "timeout"
|
3
|
+
require "mob_rotation"
|
4
|
+
|
5
|
+
describe "mob_rotation command line tool" do
|
6
|
+
let(:temp_rotation_db) { "/tmp/rotation_test.txt" }
|
7
|
+
|
8
|
+
before do
|
9
|
+
`rm -rf ./tmp/test_project`
|
10
|
+
`mkdir -p ./tmp/test_project`
|
11
|
+
`git init ./tmp/test_project`
|
12
|
+
end
|
13
|
+
|
14
|
+
def remove_temp_rotation_db
|
15
|
+
FileUtils.rm(temp_rotation_db) if File.exist?(temp_rotation_db)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_name_and_email_to_temp_db(name, email = nil)
|
19
|
+
s = email ? " <#{email}>" : ""
|
20
|
+
`echo "#{name} #{s}" >> #{temp_rotation_db}`
|
21
|
+
end
|
22
|
+
|
23
|
+
before do
|
24
|
+
remove_temp_rotation_db
|
25
|
+
|
26
|
+
add_name_and_email_to_temp_db("Bob")
|
27
|
+
add_name_and_email_to_temp_db("Phoebe")
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_rotate(command = nil)
|
31
|
+
run_rotate_with_specified_redirect(command, "> /tmp/results.txt")
|
32
|
+
end
|
33
|
+
|
34
|
+
def run_rotate_with_specified_redirect(command = nil, redirect = nil)
|
35
|
+
# TODO: we have no idea why this is necessary, and don't like it
|
36
|
+
@our_output = nil
|
37
|
+
|
38
|
+
`MOB_GIT_DIR='./tmp/test_project/.git' DB_FILE='#{temp_rotation_db}' #{RbConfig.ruby} #{File.join(Dir.pwd, "bin/mob_rotation")} #{command} #{redirect}`
|
39
|
+
end
|
40
|
+
|
41
|
+
def our_output
|
42
|
+
@our_output ||= File.readlines("/tmp/results.txt").collect(&:strip)
|
43
|
+
.reject(&:empty?)
|
44
|
+
end
|
45
|
+
|
46
|
+
context "command: ruby mob_rotation" do
|
47
|
+
it "defaults to 'rotate.txt' when no database file is specified" do
|
48
|
+
if backup = File.exist?("./rotate.txt")
|
49
|
+
FileUtils.mv("./rotate.txt", "./rotate.txt.backup")
|
50
|
+
end
|
51
|
+
FileUtils.cp(temp_rotation_db, "./rotate.txt")
|
52
|
+
`#{RbConfig.ruby} #{File.join(Dir.pwd, "bin/mob_rotation")} > /tmp/results.txt`
|
53
|
+
begin
|
54
|
+
expect(our_output).to include("Driver Bob", "Navigator Phoebe")
|
55
|
+
ensure
|
56
|
+
FileUtils.mv("./rotate.txt.backup", "./rotate.txt") if backup
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "prints out the rotation order" do
|
61
|
+
run_rotate
|
62
|
+
expect(our_output).to include("Driver Bob", "Navigator Phoebe")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "command: ruby mob_rotation help" do
|
67
|
+
it "prints out help" do
|
68
|
+
run_rotate("help")
|
69
|
+
expected = ["Available commands are:",
|
70
|
+
"show",
|
71
|
+
"help",
|
72
|
+
"rotate",
|
73
|
+
"random",
|
74
|
+
"add <name1> [name2]",
|
75
|
+
"remove <name1> [name2]",
|
76
|
+
"run_with_timer [seconds]"
|
77
|
+
]
|
78
|
+
|
79
|
+
expect(our_output).to eq(expected)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "command: ruby mob_rotation arbitrary" do
|
84
|
+
it "prints out help on an unknown command" do
|
85
|
+
run_rotate("arbitrary")
|
86
|
+
expected = ["Unknown command arbitrary",
|
87
|
+
"Available commands are:"
|
88
|
+
]
|
89
|
+
|
90
|
+
expect(our_output).to include(*expected)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "command: ruby mob_rotation random" do
|
95
|
+
it "Identifies list as randomized" do
|
96
|
+
run_rotate("random 1")
|
97
|
+
|
98
|
+
expect(our_output).to include("Randomized Output")
|
99
|
+
expect(our_output).to include("Driver Bob", "Navigator Phoebe")
|
100
|
+
end
|
101
|
+
|
102
|
+
it "produces a different order with a different seed" do
|
103
|
+
run_rotate("random 0")
|
104
|
+
|
105
|
+
expect(our_output).to include("Driver Phoebe", "Navigator Bob")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "saves the rotation order" do
|
109
|
+
run_rotate("random 0")
|
110
|
+
run_rotate
|
111
|
+
|
112
|
+
expect(our_output).to include("Driver Phoebe", "Navigator Bob")
|
113
|
+
end
|
114
|
+
|
115
|
+
it "updates the git username" do
|
116
|
+
remove_temp_rotation_db
|
117
|
+
add_name_and_email_to_temp_db("Bob Example", "bob@example.com")
|
118
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
119
|
+
|
120
|
+
run_rotate("random 0")
|
121
|
+
|
122
|
+
git_username = `git --git-dir=./tmp/test_project/.git config user.name`
|
123
|
+
.strip
|
124
|
+
expect(git_username).to eq("Phoebe Example")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "command: ruby mob_rotation rotate" do
|
129
|
+
it "changes the order of rotation" do
|
130
|
+
run_rotate("rotate")
|
131
|
+
expect(our_output).to include("Driver Phoebe", "Navigator Bob")
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "git stuff" do
|
135
|
+
it "includes the email addresses in rotation output" do
|
136
|
+
remove_temp_rotation_db
|
137
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
138
|
+
add_name_and_email_to_temp_db("Bob Example", "bob@example.com")
|
139
|
+
add_name_and_email_to_temp_db("Joe Example", "joe@example.com")
|
140
|
+
run_rotate("rotate")
|
141
|
+
|
142
|
+
expect(our_output).to include(
|
143
|
+
"Driver Bob Example <bob@example.com>",
|
144
|
+
"Navigator Joe Example <joe@example.com>",
|
145
|
+
"Mobster Phoebe Example <phoebe@example.com>"
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "outputs the new git username when running rotate" do
|
150
|
+
remove_temp_rotation_db
|
151
|
+
add_name_and_email_to_temp_db("Phoebe Example")
|
152
|
+
|
153
|
+
run_rotate("rotate")
|
154
|
+
|
155
|
+
expect(our_output).to include(
|
156
|
+
"git username: Phoebe Example",
|
157
|
+
"Driver Phoebe Example"
|
158
|
+
)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "outputs the new git email when running rotate" do
|
162
|
+
remove_temp_rotation_db
|
163
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
164
|
+
|
165
|
+
run_rotate "rotate"
|
166
|
+
|
167
|
+
expect(our_output).to include("git user email: phoebe@example.com")
|
168
|
+
|
169
|
+
add_name_and_email_to_temp_db(
|
170
|
+
"David Example",
|
171
|
+
"david-example@example.com"
|
172
|
+
)
|
173
|
+
|
174
|
+
run_rotate("rotate")
|
175
|
+
|
176
|
+
expect(our_output).to include(
|
177
|
+
"git user email: david-example@example.com"
|
178
|
+
)
|
179
|
+
end
|
180
|
+
|
181
|
+
it "outputs the new git email when rotating a list of multiple users" do
|
182
|
+
remove_temp_rotation_db
|
183
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
184
|
+
add_name_and_email_to_temp_db("David Example", "david@example.com")
|
185
|
+
|
186
|
+
run_rotate("rotate")
|
187
|
+
|
188
|
+
expect(our_output).to include("git user email: david@example.com")
|
189
|
+
end
|
190
|
+
|
191
|
+
it "updates the git user.name config when running rotate" do
|
192
|
+
remove_temp_rotation_db
|
193
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
194
|
+
|
195
|
+
run_rotate("rotate")
|
196
|
+
|
197
|
+
git_username = `git --git-dir=./tmp/test_project/.git config user.name`
|
198
|
+
.strip
|
199
|
+
expect(git_username).to eq("Phoebe Example")
|
200
|
+
end
|
201
|
+
|
202
|
+
it "updates the git user.email config when running rotate" do
|
203
|
+
remove_temp_rotation_db
|
204
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
205
|
+
|
206
|
+
run_rotate("rotate")
|
207
|
+
|
208
|
+
git_email = `git --git-dir=./tmp/test_project/.git config user.email`
|
209
|
+
.strip
|
210
|
+
expect(git_email).to eq("phoebe@example.com")
|
211
|
+
end
|
212
|
+
|
213
|
+
it "updates the email in the mobsters database when rotating" do
|
214
|
+
remove_temp_rotation_db
|
215
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
216
|
+
add_name_and_email_to_temp_db("Bob Example" "bob@example.com")
|
217
|
+
add_name_and_email_to_temp_db("Joe Example", "joe@example.com")
|
218
|
+
|
219
|
+
run_rotate("rotate")
|
220
|
+
run_rotate("rotate")
|
221
|
+
|
222
|
+
git_email = `git --git-dir=./tmp/test_project/.git config user.email`
|
223
|
+
.strip
|
224
|
+
expect(git_email).to eq("joe@example.com")
|
225
|
+
end
|
226
|
+
|
227
|
+
it "falls back to a default email address when the driver has none" do
|
228
|
+
remove_temp_rotation_db
|
229
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
230
|
+
add_name_and_email_to_temp_db("Bob Example")
|
231
|
+
|
232
|
+
run_rotate("rotate")
|
233
|
+
|
234
|
+
git_email = `git --git-dir=./tmp/test_project/.git config user.email`
|
235
|
+
.strip
|
236
|
+
expect(git_email).to eq("mob@rubysteps.com")
|
237
|
+
end
|
238
|
+
|
239
|
+
it "updates the email in the mobsters database when rotating, even when someone's missing an email address" do
|
240
|
+
remove_temp_rotation_db
|
241
|
+
add_name_and_email_to_temp_db("Phoebe Example", "phoebe@example.com")
|
242
|
+
add_name_and_email_to_temp_db("Bob Example")
|
243
|
+
add_name_and_email_to_temp_db("Joe Example", "joe@example.com")
|
244
|
+
|
245
|
+
run_rotate("rotate")
|
246
|
+
run_rotate("rotate")
|
247
|
+
|
248
|
+
git_email = `git --git-dir=./tmp/test_project/.git config user.email`
|
249
|
+
.strip
|
250
|
+
expect(git_email).to eq("joe@example.com")
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context "command: ruby mob_rotation add one_name [two three]" do
|
256
|
+
it "adds one mobster to the mob list" do
|
257
|
+
run_rotate("add Joe")
|
258
|
+
expect(our_output).to include(
|
259
|
+
"Driver Bob",
|
260
|
+
"Navigator Phoebe",
|
261
|
+
"Mobster Joe"
|
262
|
+
)
|
263
|
+
end
|
264
|
+
|
265
|
+
it "adds multiple mobsters at once" do
|
266
|
+
run_rotate("add Phil Steve")
|
267
|
+
expect(our_output).to include("Mobster Phil", "Mobster Steve")
|
268
|
+
end
|
269
|
+
|
270
|
+
it "new name cannot match existing name" do
|
271
|
+
run_rotate("add Ralph")
|
272
|
+
run_rotate("add Ralph")
|
273
|
+
|
274
|
+
expect(our_output).to include("user name 'Ralph' already exists")
|
275
|
+
expect(our_output.select { |l| l.include?("Ralph") }.size).to eq(2)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
context "command: ruby mob_rotation remove one_name [two three]" do
|
280
|
+
it "removes one mobster from the mob list" do
|
281
|
+
run_rotate("remove Bob")
|
282
|
+
expect(our_output).to include("Driver Phoebe")
|
283
|
+
end
|
284
|
+
|
285
|
+
it "removes multiple mobsters at once" do
|
286
|
+
# TODO: Doesn't test what it claims to test.
|
287
|
+
run_rotate("add Phil")
|
288
|
+
run_rotate("remove Bob Phoebe")
|
289
|
+
expect(our_output).to include("Driver Phil")
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
context "command: ruby mob_rotation run_with_timer N" do
|
294
|
+
it "it runs for a specific amount of time" do
|
295
|
+
ts = Time.now
|
296
|
+
run_rotate("run_with_timer 3")
|
297
|
+
tf = Time.now
|
298
|
+
threshold = 3.0 + MobRotation::Rotation.minimum_sleep_between_beeps * MobRotation::Rotation.number_of_beeps
|
299
|
+
expect(tf - ts).to be_within(1).of(threshold)
|
300
|
+
expect(our_output).to include("Time to rotate")
|
301
|
+
end
|
302
|
+
|
303
|
+
it "waits until time runs out before stating 'Time to Rotate'" do
|
304
|
+
expect {
|
305
|
+
Timeout.timeout(1) { run_rotate("run_with_timer 5") }
|
306
|
+
}.to raise_error(Timeout::Error)
|
307
|
+
expect(our_output).to eq([])
|
308
|
+
end
|
309
|
+
|
310
|
+
it "notifies with a beep" do
|
311
|
+
stdout_output = run_rotate_with_specified_redirect("run_with_timer")
|
312
|
+
expect(stdout_output).to include("\a")
|
313
|
+
end
|
314
|
+
|
315
|
+
it "runs for a specified amount of time and then notifies with a beep" do
|
316
|
+
ts = Time.now
|
317
|
+
stdout_output = run_rotate_with_specified_redirect("run_with_timer 2")
|
318
|
+
tf = Time.now
|
319
|
+
expect(tf - ts).to be_within(1).of(2.0 + MobRotation::Rotation.minimum_sleep_between_beeps * MobRotation::Rotation.number_of_beeps)
|
320
|
+
expect(stdout_output).to include("Time to rotate")
|
321
|
+
expect(stdout_output).to include("\a")
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe MobRotation::Rotation do
|
4
|
+
extend FooFighter
|
5
|
+
|
6
|
+
let(:mob_rotator) {
|
7
|
+
MobRotation::Rotation.new(
|
8
|
+
MobRotation::Database.new(file_name),
|
9
|
+
"./tmp/test_project/.git"
|
10
|
+
)
|
11
|
+
}
|
12
|
+
|
13
|
+
before { FileUtils.rm_f(file_name) }
|
14
|
+
|
15
|
+
describe "#show_mobsters" do
|
16
|
+
let(:file_name) { "test.txt" }
|
17
|
+
let(:output) { Output.new }
|
18
|
+
|
19
|
+
before do
|
20
|
+
File.open(file_name, "w") do |file|
|
21
|
+
file << "Bob\n" << "Phoebe\n" << "Joe\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
$stdout = output
|
25
|
+
|
26
|
+
mob_rotator.show_mobsters
|
27
|
+
end
|
28
|
+
|
29
|
+
it "print out all the mobsters in the text file" do
|
30
|
+
expect(output.mobsters.join).to include("Mobster Joe")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "prints out driver" do
|
34
|
+
expect(output.mobsters.join).to include("Driver Bob")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "prints out navigator" do
|
38
|
+
expect(output.mobsters.join).to include("Navigator Phoebe")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#add_mobster" do
|
43
|
+
let(:file_name) { "test.txt" }
|
44
|
+
|
45
|
+
it "adds a mobster to the file" do
|
46
|
+
mob_rotator.add_mobster("Jackie")
|
47
|
+
mob_rotator.add_mobster("Phil")
|
48
|
+
|
49
|
+
expect(File.read(file_name)).to eq("Jackie\nPhil\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "accepts more than one mobster" do
|
53
|
+
mob_rotator.add_mobster("Jackie", "Phil")
|
54
|
+
expect(File.read(file_name)).to include("\nPhil")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "skips adding duplicate mobster name" do
|
58
|
+
mob_rotator.add_mobster("Rosie", "Rosie")
|
59
|
+
expect(File.read(file_name)).to eq("Rosie\n")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "strips leading and trailing whitespace" do
|
63
|
+
mob_rotator.add_mobster(" \n Rosie \n ")
|
64
|
+
expect(File.read(file_name)).to eq("Rosie\n")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "does not allow blank usernames" do
|
68
|
+
expect { mob_rotator.add_mobster(" ") }
|
69
|
+
.to raise_error
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#remove_mobster" do
|
74
|
+
let(:file_name) { "test_remove.txt" }
|
75
|
+
|
76
|
+
before do
|
77
|
+
File.open(file_name, "w") do |file|
|
78
|
+
file << "Bob\n" << "Phoebe\n" << "Joe"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "removes a mobster from the file" do
|
83
|
+
mob_rotator.remove_mobster("Bob")
|
84
|
+
expect(File.read(file_name)).not_to include("Bob")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "#rotate" do
|
89
|
+
let(:file_name) { "test_remove.txt" }
|
90
|
+
|
91
|
+
before do
|
92
|
+
File.open(file_name, "w") do |file|
|
93
|
+
file << "Bob\n" << "Phoebe\n" << "Joe\n"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "rotates mobsters" do
|
98
|
+
mob_rotator.rotate
|
99
|
+
# new file to equal "Phoebe Joe Bob"
|
100
|
+
expect(File.read(file_name)).to eq("Phoebe\nJoe\nBob\n")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "#extract_email_from(entry)" do
|
105
|
+
let(:file_name) { "irrelevant_file" }
|
106
|
+
|
107
|
+
after(:each) do
|
108
|
+
FileUtils.rm_f(file_name)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "returns the email address" do
|
112
|
+
email = MobRotation::Rotation.new(
|
113
|
+
MobRotation::Database.new(file_name),
|
114
|
+
"irrelevant git dir"
|
115
|
+
).extract_email_from("a <b@example.com>")
|
116
|
+
|
117
|
+
expect(email).to eq("b@example.com")
|
118
|
+
end
|
119
|
+
|
120
|
+
it "it handles arbitary email addresses" do
|
121
|
+
email = MobRotation::Rotation.new(
|
122
|
+
MobRotation::Database.new(file_name),
|
123
|
+
"irrelevant git dir"
|
124
|
+
).extract_email_from("bob <bob@example.com>")
|
125
|
+
|
126
|
+
expect(email).to eq("bob@example.com")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "mob_rotation"
|
3
|
+
|
4
|
+
class Output
|
5
|
+
attr_accessor :mobsters
|
6
|
+
|
7
|
+
def write(argument)
|
8
|
+
@mobsters ||= []
|
9
|
+
@mobsters << argument
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module FooFighter
|
14
|
+
def method_added(m)
|
15
|
+
return unless m.to_s == "foo"
|
16
|
+
remove_method(m)
|
17
|
+
fail("no foo for you")
|
18
|
+
end
|
19
|
+
end
|
data/todo.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
- get a real test environment separated from production
|
2
|
+
- add email git config on rotate DONE
|
3
|
+
- in our tests change directory when running command line stuff
|
4
|
+
- get the tests passing DONE
|
5
|
+
- clean up this working directory
|
6
|
+
- rename unit and acceptance tests to be more intuitive (maybe)
|
7
|
+
- refactor MobRotation#initialize to read file once
|
8
|
+
- refactor MobRotation#initialize to use either 2 class methods or 2 instance methods (extract_<something>_from)
|
9
|
+
- add hook to emacs configuration to automatically show line numbers in (all?) files - DONE
|
10
|
+
- match pattern on remove (like remove Jacq*)
|
11
|
+
- shuffle the mobsters
|
12
|
+
- move test output to ./tmp instead of /tmp
|
13
|
+
- move todo/features to git issues/ clean up todo
|
14
|
+
- Timer
|
15
|
+
|
16
|
+
help w/o specifying database
|
17
|
+
make main class match file name **** Done
|
18
|
+
lots of commented out code in mob_rotation executable *** Done
|
19
|
+
refactor case statement***
|
20
|
+
include role information in database file
|
21
|
+
#add_mobster takes multiple mobsters
|
22
|
+
explicit path in acceptance tests only works on the mob station
|
23
|
+
auto-generate help based on known commands *
|
24
|
+
broken tests break production rotate.txt file - DONE
|
25
|
+
|
26
|
+
delete Timer *** DONE
|
27
|
+
each_with_index ? in remove_mobster ... * DONE
|
28
|
+
known default database file, overridable * WIP
|
29
|
+
refactor add_mobster to use sync!* DONE
|
30
|
+
Tmux integration: powerline
|
31
|
+
refactor to mob commands vs timer class (and stuff like that :) **
|
32
|
+
too much going on in mob_rotation executable? *
|
33
|
+
add run_with_timer to help.
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
Break functions out of mob_rotation.rb (God class)
|
38
|
+
clean up directory structure...**
|
39
|
+
do all the tests pass???****
|
40
|
+
understand what it actually does...?
|
41
|
+
play firecrackers whenever we rotate ***
|
42
|
+
prevent non-driver from interacting w/ terminal
|
43
|
+
get more information / permissions about participants (class-based?)
|
44
|
+
include the project history in README
|
45
|
+
create a README********
|
46
|
+
abandon this and move on to something
|
47
|
+
start a new project
|
48
|
+
build a browser-based gui
|
49
|
+
randomize driver / navigator (with limits) **
|
50
|
+
record a history of rotation
|
51
|
+
designated driver
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
TODO
|
56
|
+
- Unrecognized commands show help DONE
|
57
|
+
- Timer! *
|
58
|
+
|
59
|
+
Fails: ruby mob_rotation asdf cows
|
60
|
+
|
61
|
+
____
|
62
|
+
|
63
|
+
Add/remove multiple mobsters in one call**
|
64
|
+
Timer ****
|
65
|
+
Detect mobsters
|
66
|
+
Tmux integration: powerline *
|
67
|
+
|
68
|
+
|
69
|
+
# Time.now() == 7min ->timeisup!
|
70
|
+
|
71
|
+
# naming acceptance ... again!~~~
|
72
|
+
# No Readme file ~~~
|
73
|
+
# End goal of the app ~~~
|
74
|
+
# add a timer feature ~~~
|
75
|
+
# is this going to stay a CLI, gem, rails app feature? Forward direction? ~~
|
76
|
+
|
77
|
+
# introduce helper spec~
|
78
|
+
# separate implementation from script~
|
79
|
+
# organizing cli vs unit specs ~
|
80
|
+
# Common structure for running tests
|
81
|
+
# our 'clean state' isnt that clean. Lots of duplicate files from before
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
# DONE adding remove mobster feature ----
|
86
|
+
# naming the acteptance---
|
87
|
+
# add timer feature---
|
88
|
+
# refactor to dependency injection --
|
89
|
+
# seperating implementation from the script --
|
90
|
+
# connect the app with ruby lobby api * -
|
91
|
+
# add new api via CLI-
|
92
|
+
# introducing helper_spec(moving)-
|
93
|
+
|
94
|
+
# do we keep features that are done or move to changelog?
|
95
|
+
# focus on refactoring vs adding features?
|
96
|
+
# adding directory structure
|
97
|
+
|
98
|
+
# DONE show mobster should display who navigates and who is driver ****
|
99
|
+
# DONE method to add
|
100
|
+
# remove mobsters ***
|
101
|
+
# remove dependency to / with file ***
|
102
|
+
# DONE give the describe block a name **
|
103
|
+
# operating on standard out... would it be worth it to refactor? **
|
104
|
+
# DONE change it statement... don't know what the subject is *
|
105
|
+
|
106
|
+
# --------
|
107
|
+
|
108
|
+
# store more mata data in db file(rotation time...)
|
109
|
+
# write specs for next method rotate?
|
110
|
+
# how important is it really?
|
111
|
+
# could change spec to add more meaning
|
112
|
+
# removing time_to_rotate
|
113
|
+
|
data/woot_camp_todo.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
* establish behavior in the tests ***** DONE
|
2
|
+
* pending tests drive the team nuts **** DONE
|
3
|
+
|
4
|
+
* what happens when two people have the same name? **** DONE
|
5
|
+
|
6
|
+
* blank user for no apparent reason *** DONE
|
7
|
+
* name with trailing whitespace? DONE
|
8
|
+
|
9
|
+
|
10
|
+
* disappearing emails...
|
11
|
+
* some emails nil, some blank?
|
12
|
+
|
13
|
+
* what should rotate do if next user has no email?
|
14
|
+
* encapsulate the mobster class DONE
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
BUGS
|
19
|
+
|
20
|
+
|
21
|
+
IDEA
|
22
|
+
|
23
|
+
* gemify so that we can run a stable version while developing
|
24
|
+
* erase production db?
|
25
|
+
* check email format
|
26
|
+
* validate email for GitHub user
|
27
|
+
|
28
|
+
* exchange twitter / email contact info (team)
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mob_rotation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pat Maddox
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.1'
|
55
|
+
description: Provides an executable to manage a mob list
|
56
|
+
email:
|
57
|
+
- pat@rubysteps.com
|
58
|
+
executables:
|
59
|
+
- mob_rotation
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rspec"
|
65
|
+
- ".rubocop.yml"
|
66
|
+
- ".travis.yml"
|
67
|
+
- Changelog.md
|
68
|
+
- Contributors.md
|
69
|
+
- Gemfile
|
70
|
+
- LICENSE.txt
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- bin/mob_rotation
|
74
|
+
- lib/mob_rotation.rb
|
75
|
+
- lib/mob_rotation/command_routing.rb
|
76
|
+
- lib/mob_rotation/database.rb
|
77
|
+
- lib/mob_rotation/mobster.rb
|
78
|
+
- lib/mob_rotation/rotation.rb
|
79
|
+
- lib/mob_rotation/version.rb
|
80
|
+
- mob_rotation.gemspec
|
81
|
+
- spec/foo_fighter_spec.rb
|
82
|
+
- spec/mob_rotation_executable_spec.rb
|
83
|
+
- spec/rotation_spec.rb
|
84
|
+
- spec/spec_helper.rb
|
85
|
+
- todo.md
|
86
|
+
- woot_camp_todo.md
|
87
|
+
homepage: https://github.com/RubySteps/mob_rotation
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.4.5
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Manage a mob list during a mobbing session
|
111
|
+
test_files:
|
112
|
+
- spec/foo_fighter_spec.rb
|
113
|
+
- spec/mob_rotation_executable_spec.rb
|
114
|
+
- spec/rotation_spec.rb
|
115
|
+
- spec/spec_helper.rb
|