rotation 0.0.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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +56 -0
- data/Rakefile +10 -0
- data/bin/rotation +4 -0
- data/lib/rotation.rb +9 -0
- data/lib/rotation/cli.rb +37 -0
- data/lib/rotation/configuration.rb +18 -0
- data/lib/rotation/topic.rb +31 -0
- data/lib/rotation/version.rb +3 -0
- data/rotation.gemspec +26 -0
- data/test/configuration_test.rb +20 -0
- data/test/fixtures/sample_config.yml +5 -0
- data/test/rotation_test.rb +4 -0
- data/test/test_helper.rb +5 -0
- data/test/topic_test.rb +84 -0
- metadata +143 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 Marcelo Silveira. http://www.mhfs.com.br
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
Rotation
|
2
|
+
========
|
3
|
+
|
4
|
+
Rotation is a simple command line utility to help you rotate any kind of
|
5
|
+
stuff over time. It was originally created to help control code review
|
6
|
+
rotation among the members of a team.
|
7
|
+
|
8
|
+
Currently it only rotates by any given number of weeks. More units
|
9
|
+
planned for the future.
|
10
|
+
|
11
|
+
Installation
|
12
|
+
------------
|
13
|
+
|
14
|
+
Install the gem:
|
15
|
+
|
16
|
+
gem install rotation
|
17
|
+
|
18
|
+
Usage
|
19
|
+
-----
|
20
|
+
|
21
|
+
Create your first rotation topic:
|
22
|
+
|
23
|
+
rotation init topic_name
|
24
|
+
|
25
|
+
This will create a `~/.rotation` file. It's a yaml file that will look
|
26
|
+
like:
|
27
|
+
|
28
|
+
topic_name:
|
29
|
+
start_date: 2011-09-12
|
30
|
+
duration: 1
|
31
|
+
first: Huey
|
32
|
+
candidates:
|
33
|
+
- Huey
|
34
|
+
- Dewey
|
35
|
+
- Louie
|
36
|
+
|
37
|
+
Tweak the file for your needs. Notice that you can create as many topics
|
38
|
+
as you want.
|
39
|
+
|
40
|
+
See who's in charge by typing:
|
41
|
+
|
42
|
+
rotation responsible topic_name
|
43
|
+
|
44
|
+
If you want to check the responsible of each of your topics type:
|
45
|
+
|
46
|
+
rotation responsibles
|
47
|
+
|
48
|
+
Author and License
|
49
|
+
------------------
|
50
|
+
|
51
|
+
Marcelo Silveira :: marcelo@mhfs.com.br :: @mhfsilveira
|
52
|
+
|
53
|
+
Released under the MIT License. See the [LICENSE][license] file for further
|
54
|
+
details.
|
55
|
+
|
56
|
+
[license]: https://github.com/mhfs/rotation/blob/master/MIT-LICENSE
|
data/Rakefile
ADDED
data/bin/rotation
ADDED
data/lib/rotation.rb
ADDED
data/lib/rotation/cli.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module Rotation
|
4
|
+
class CLI < Thor
|
5
|
+
CONFIG_PATH = File.expand_path("~/.rotation")
|
6
|
+
|
7
|
+
desc "init TOPIC", "Init a new dummy topic config in your ~/.rotation file."
|
8
|
+
def init(topic_name)
|
9
|
+
config = File.exists?(CONFIG_PATH) ? YAML.load_file(CONFIG_PATH) : {}
|
10
|
+
config[topic_name] = { "duration" => 1, "start_date" => Date.today, "first" => "Huey", "candidates" => ["Huey", "Dewey", "Louie"] }
|
11
|
+
File.open(CONFIG_PATH, "w") do |out|
|
12
|
+
YAML.dump(config, out)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "responsibles", "Gives the responsibles for all your configured topics"
|
17
|
+
def responsibles
|
18
|
+
load_settings
|
19
|
+
Configuration.config_store.each do |name, topic|
|
20
|
+
say_status(name, topic.responsible)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "responsible TOPIC", "Tells you who is in charge for a given topic."
|
25
|
+
def responsible(topic_name)
|
26
|
+
load_settings
|
27
|
+
topic = Configuration.fetch(topic_name)
|
28
|
+
say_status(topic_name, topic.responsible)
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def load_settings
|
34
|
+
Configuration.load(CONFIG_PATH)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rotation
|
2
|
+
module Configuration
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def load(config_path = "~/.rotation")
|
6
|
+
configs = YAML.load_file(config_path)
|
7
|
+
configs.each { |topic_name, params| config_store[topic_name] = Topic.new(topic_name, params) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def config_store
|
11
|
+
@config ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch(topic_name)
|
15
|
+
config_store[topic_name]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rotation
|
2
|
+
class Topic
|
3
|
+
attr_accessor :name, :duration, :start_date, :first, :candidates
|
4
|
+
|
5
|
+
def initialize(topic_name, params)
|
6
|
+
@name = topic_name
|
7
|
+
@duration = params["duration"]
|
8
|
+
@start_date = params["start_date"]
|
9
|
+
@first = params["first"]
|
10
|
+
@candidates = params["candidates"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def responsible(date = Date.today)
|
14
|
+
candidates[responsible_index(date)]
|
15
|
+
end
|
16
|
+
|
17
|
+
def responsible_index(date)
|
18
|
+
unit_delta = week_delta(start_date, date)
|
19
|
+
(cycle(unit_delta) + candidates.index(first)) % candidates.size
|
20
|
+
end
|
21
|
+
|
22
|
+
def cycle(unit_delta)
|
23
|
+
(unit_delta / duration.to_f).floor
|
24
|
+
end
|
25
|
+
|
26
|
+
def week_delta(d1, d2)
|
27
|
+
year_difference = (d2.year - d1.year) * 52
|
28
|
+
year_difference + (d2 - d2.wday).yday / 7 - (d1 -d1.wday).yday / 7
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/rotation.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rotation/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rotation"
|
7
|
+
s.version = Rotation::VERSION
|
8
|
+
s.authors = ["Marcelo Silveira"]
|
9
|
+
s.email = ["marcelo@mhfs.com.br"]
|
10
|
+
s.homepage = "https://github.com/mhfs/rotation/"
|
11
|
+
s.summary = %q{Command line utility to help you control rotation of stuff over time}
|
12
|
+
s.description = %q{Rotation is a quick utility to help you rotate any kind of stuff over time. I created it to control code review rotation among the team members.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "rotation"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rake"
|
22
|
+
s.add_development_dependency "contest"
|
23
|
+
s.add_development_dependency "redgreen"
|
24
|
+
|
25
|
+
s.add_runtime_dependency "thor"
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ConfigurationTest < Test::Unit::TestCase
|
4
|
+
setup do
|
5
|
+
Rotation::Configuration.load("./test/fixtures/sample_config.yml")
|
6
|
+
end
|
7
|
+
|
8
|
+
test "load settings from file" do
|
9
|
+
assert Rotation::Configuration.fetch("cool_topic").is_a?(Rotation::Topic)
|
10
|
+
end
|
11
|
+
|
12
|
+
test "correctly feed topics" do
|
13
|
+
topic = Rotation::Configuration.fetch("cool_topic")
|
14
|
+
assert_equal "cool_topic", topic.name
|
15
|
+
assert_equal 2, topic.duration
|
16
|
+
assert_equal Date.new(2011, 9, 13), topic.start_date
|
17
|
+
assert_equal "one", topic.first
|
18
|
+
assert_equal ["one", "two", "three"], topic.candidates
|
19
|
+
end
|
20
|
+
end
|
data/test/test_helper.rb
ADDED
data/test/topic_test.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class TopicTest < Test::Unit::TestCase
|
4
|
+
setup do
|
5
|
+
@topic = Rotation::Topic.new("test_topic", {
|
6
|
+
"duration" => 2,
|
7
|
+
"start_date" => Date.new(2011, 9, 5),
|
8
|
+
"first" => "one",
|
9
|
+
"candidates" => ["one", "two", "three"]
|
10
|
+
})
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#week_delta" do
|
14
|
+
test "is 0 for same week" do
|
15
|
+
assert_equal 0, @topic.week_delta(@topic.start_date, Date.new(2011, 9, 10))
|
16
|
+
end
|
17
|
+
|
18
|
+
test "is 1 for next week" do
|
19
|
+
assert_equal 1, @topic.week_delta(@topic.start_date, Date.new(2011, 9, 11))
|
20
|
+
end
|
21
|
+
|
22
|
+
test "is -1 for previous week" do
|
23
|
+
assert_equal -1, @topic.week_delta(@topic.start_date, Date.new(2011, 9, 3))
|
24
|
+
end
|
25
|
+
|
26
|
+
test "is not negative for lower dates in following years" do
|
27
|
+
assert_equal 17, @topic.week_delta(@topic.start_date, Date.new(2012, 1, 3))
|
28
|
+
end
|
29
|
+
|
30
|
+
test "is negative for higher dates in previous years" do
|
31
|
+
assert_equal -36, @topic.week_delta(@topic.start_date, Date.new(2010, 12, 31))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "#cycle" do
|
36
|
+
test "is 0 for up to duration value" do
|
37
|
+
assert_equal 0, @topic.cycle(0)
|
38
|
+
assert_equal 0, @topic.cycle(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
test "is 1 for up to twice the duration value" do
|
42
|
+
assert_equal 1, @topic.cycle(2)
|
43
|
+
assert_equal 1, @topic.cycle(3)
|
44
|
+
end
|
45
|
+
|
46
|
+
test "is 2 for up to three time the duration value" do
|
47
|
+
assert_equal 2, @topic.cycle(4)
|
48
|
+
assert_equal 2, @topic.cycle(5)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "#responsible_index and #responsible" do
|
53
|
+
test "is 0 in the first cycle" do
|
54
|
+
date = Date.new(2011, 9, 10)
|
55
|
+
assert_equal 0, @topic.responsible_index(date)
|
56
|
+
assert_equal "one", @topic.responsible(date)
|
57
|
+
end
|
58
|
+
|
59
|
+
test "is 1 for second cycle" do
|
60
|
+
date = Date.new(2011, 9, 18)
|
61
|
+
assert_equal 1, @topic.responsible_index(date)
|
62
|
+
assert_equal "two", @topic.responsible(date)
|
63
|
+
end
|
64
|
+
|
65
|
+
test "is 2 for third cycle" do
|
66
|
+
date = Date.new(2011, 10, 8)
|
67
|
+
assert_equal 2, @topic.responsible_index(date)
|
68
|
+
assert_equal "three", @topic.responsible(date)
|
69
|
+
end
|
70
|
+
|
71
|
+
test "is 0 again for fourth cycle" do
|
72
|
+
date = Date.new(2011, 10, 22)
|
73
|
+
assert_equal 0, @topic.responsible_index(date)
|
74
|
+
assert_equal "one", @topic.responsible(date)
|
75
|
+
end
|
76
|
+
|
77
|
+
test "is 2 for first cycle if first candidate says so" do
|
78
|
+
@topic.first = "three"
|
79
|
+
date = Date.new(2011, 9, 10)
|
80
|
+
assert_equal 2, @topic.responsible_index(date)
|
81
|
+
assert_equal "three", @topic.responsible(date)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rotation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Marcelo Silveira
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-09-12 00:00:00 -03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
requirement: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: contest
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
requirement: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: redgreen
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
requirement: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: thor
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :runtime
|
76
|
+
requirement: *id004
|
77
|
+
description: Rotation is a quick utility to help you rotate any kind of stuff over time. I created it to control code review rotation among the team members.
|
78
|
+
email:
|
79
|
+
- marcelo@mhfs.com.br
|
80
|
+
executables:
|
81
|
+
- rotation
|
82
|
+
extensions: []
|
83
|
+
|
84
|
+
extra_rdoc_files: []
|
85
|
+
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- Gemfile
|
89
|
+
- MIT-LICENSE
|
90
|
+
- README.md
|
91
|
+
- Rakefile
|
92
|
+
- bin/rotation
|
93
|
+
- lib/rotation.rb
|
94
|
+
- lib/rotation/cli.rb
|
95
|
+
- lib/rotation/configuration.rb
|
96
|
+
- lib/rotation/topic.rb
|
97
|
+
- lib/rotation/version.rb
|
98
|
+
- rotation.gemspec
|
99
|
+
- test/configuration_test.rb
|
100
|
+
- test/fixtures/sample_config.yml
|
101
|
+
- test/rotation_test.rb
|
102
|
+
- test/test_helper.rb
|
103
|
+
- test/topic_test.rb
|
104
|
+
has_rdoc: true
|
105
|
+
homepage: https://github.com/mhfs/rotation/
|
106
|
+
licenses: []
|
107
|
+
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
hash: 3
|
128
|
+
segments:
|
129
|
+
- 0
|
130
|
+
version: "0"
|
131
|
+
requirements: []
|
132
|
+
|
133
|
+
rubyforge_project: rotation
|
134
|
+
rubygems_version: 1.6.2
|
135
|
+
signing_key:
|
136
|
+
specification_version: 3
|
137
|
+
summary: Command line utility to help you control rotation of stuff over time
|
138
|
+
test_files:
|
139
|
+
- test/configuration_test.rb
|
140
|
+
- test/fixtures/sample_config.yml
|
141
|
+
- test/rotation_test.rb
|
142
|
+
- test/test_helper.rb
|
143
|
+
- test/topic_test.rb
|