goalkeeper 0.2 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 151b87201e8fbaa657d6aad6ef7aed33f8bf328a
4
- data.tar.gz: 5a2b70b08cc0aa919d13cd3283300240d1895cdc
3
+ metadata.gz: 131ffcb82da5ac820f63710b94d5139cf249bc9d
4
+ data.tar.gz: d0ccd33c05701a7b3c5bb669008eb5bea1eedf32
5
5
  SHA512:
6
- metadata.gz: 2bb9d5d7819f6f778525ce4d1fbb638ac986f4a3644b26c306e07292396d8207adbb9499421fd33ce5f17034f03dc71c97cb3e893be537b3e761af16da1b3270
7
- data.tar.gz: 55e43ca0fe7926ef24984da40b29f82af3dd8e9ff48d111b01e932e130a73dc9379ec16b59044d2802b6d1bdaf3bdbd016fde60bef2863cb0f65f8ac85c4dccd
6
+ metadata.gz: ced9ac47bf52311689d02ded1b17c59067c9bd55906de495f53a4c3a59cf7242b8b3dce7f0eafb662326c6c8c3ab050d5377718dad07d95c221704fc4e2953d3
7
+ data.tar.gz: 928f802e2557c64bb046e9eec2769e66c9d4f075d34fc6b8b202111cd7b703693dfa4ac44e2bea08966ab2af33bc543e2a8172c0de9f397e5a60a84c761fc332
data/.gitignore CHANGED
@@ -11,4 +11,6 @@
11
11
  *.so
12
12
  *.o
13
13
  *.a
14
+ *.gem
14
15
  mkmf.log
16
+
data/README.md CHANGED
@@ -5,8 +5,7 @@ Goalkeeper is a simple system for tracking if system wide requirements have been
5
5
  An example usage would be validating if each customer was sent a daily report.
6
6
 
7
7
 
8
-
9
- ## Installation
8
+ ##### Installation
10
9
 
11
10
  Add this line to your application's Gemfile:
12
11
 
@@ -24,7 +23,34 @@ Or install it yourself as:
24
23
 
25
24
  ## Usage
26
25
 
27
- TODO: Write usage instructions here
26
+ ### Goal
27
+ | method | description | example |
28
+ | -------- | ------ | ----- |
29
+ | new(label) | Creates a new Goal with the unique label | `g = Goal.new('process')` |
30
+ | met? | Returns true if the Goal has been met | `g.met? #=> false` |
31
+ | met! | Marks the goal as completed with a timestamp | `g.met! #=> Time.now` |
32
+ | met\_at | Nil if unmet, otherwise returns the time the Goal was met. | `g.met_at #=> 2015-02-09 22:24:07 -0500` |
33
+ | ttl | The Redis ttl value if there is a record for the goal. | `g.ttl #=> 86400` |
34
+ | key | The key used to store the record in Redis. | `g.key #=> "Goalkeeper:process"` |
35
+ | clear! | Deletes the `met` record. Goal is now unmet. | `g.clear!` |
36
+
37
+
38
+ ### Set
39
+ | method | description | example |
40
+ | -------- | ------ | ----- |
41
+ | new | creates an empty set of goals. | `s = set.new` |
42
+ | add(label) | Adds a new Goal the Set. _chainable_ | `s.add('process.a').add('process.b')` |
43
+ | met? | Returns true if _all_ the Set's Goals have been met. | `s.met? #=> false` |
44
+ | met! | Calls `met!` on all Goals. | `s.met! #=> Time.now` |
45
+ | met\_at | Returns the most recent met_at for the Set's Goals. Nil if no Goal met. | `s.met_at #=> 2015-02-09 22:24:07 -0500` |
46
+ | clear! | Calls `clear!` on all Goals. | `s.clear!` |
47
+ | met | Returns a new Set with all Goals which have been met. | `s.met #=> Set(...)` |
48
+ | unmet | Returns a new Set with all Goals which have not been met. | `s.unmet` #=> Set(...) |
49
+
50
+ ### Goalkeeper
51
+ | method | description | example |
52
+ | -------- | ------ | ----- |
53
+ | ::met!(label) | Creates a new Goal and marks it met. | `Goalkeeper.met!('process') #=> <Goalkeepr::Goal>`
28
54
 
29
55
  ## Contributing
30
56
 
data/Rakefile CHANGED
@@ -5,6 +5,6 @@ task default: [:test]
5
5
 
6
6
  Rake::TestTask.new do |t|
7
7
  t.libs << 'test'
8
- t.pattern = "test/*_test.rb"
8
+ t.pattern = "test/**/*_test.rb"
9
9
  end
10
10
 
data/lib/goalkeeper.rb CHANGED
@@ -1,27 +1,64 @@
1
- require "goalkeeper/version"
2
1
  require 'forwardable'
3
2
  require 'redis'
4
3
  require 'time' # for Time.parse
5
4
 
6
- # Goalkeeper provides methods to track if specific events(Goals) have been completed(met).
5
+ # Goalkeeper provides methods to track if specific events(Goals) have been
6
+ # completed(met).
7
7
  #
8
- # It is not a complicated system and it is easy enough to roll your own. This
9
- # is an extraction from a system Pharos EI has been using.
8
+ # Its goes likes this..
9
+ #
10
+ # Lets ensure we wakeup New Years Day 2020. The goal will be called 'wakeup:2020-01-01'
11
+ # g = Goalkeeper::Goal.new('wakeup:2020-01-01')
12
+ # g.met? #=> false
10
13
  #
11
- # A Goal is just a unique string. It is up to your application to
12
- # define any schema for the Goal's label.
14
+ # Time flies... it is New Years Day 2020.
15
+ # g.met! # or Goalkeeper.met!('wakeup:2020-01-01')
16
+ # g.met? #=> true
17
+ # g.met_at #=> 2020-01-01 05:01:31 -0500
13
18
  #
14
- # For example you might have your Goals labeled by date and company id:
15
- # "job:2016-01-17:company:7"
19
+ # Now if our application checks our goal, it will be met.
20
+ # Goalkeeper::Goal.new('wakeup:2020-01-01').met? #=> true
21
+ # Goalkeeper.met?('wakeup:2020-01-01') #=> true
22
+ #
23
+ # Note: Once a Goal is 'met' the 'met_at' timestamp will not change, unless
24
+ # 'clear!' is called.
16
25
  #
17
- # When a Goal is met a record is created in Redis with a timestamp, this is the only
18
- # persistent layer.
19
- # Goalkeeper.met!("jobkey")
20
- # # or
21
- # Goalkeeper::Goal.new("jobkey").met!
26
+ # We are probably only interested in this goal being complete for a limited
27
+ # time, so it will expire and be removed from Redis.
28
+ # g.ttl #=> 86400 (1 day)
22
29
  #
23
- # To check if a Goal as been met
24
- # Goalkeeper::Goal.new("jobkey").met?
30
+ # If you need to reference the Redis key
31
+ # g.key #=> Goalkeeper:wakeup:2020-01-01
32
+ #
33
+ # Finally clear the Goal is simple
34
+ # g.clear!
35
+ #
36
+ # === Sets
37
+ #
38
+ # Perhaps you have a series of Goals you want to track, and see if they all have been met, or not.
39
+ #
40
+ # set = Goalkeeper::Set.new
41
+ # set.add('goal1').add('goal2')
42
+ # set.met? #=> false
43
+ #
44
+ # Lets have 1 goal met:
45
+ # Goalkeeper.met!('goal1')
46
+ #
47
+ # But our set is not met yet
48
+ # set.met? #=> false
49
+ #
50
+ # See which goals are met, or unmet
51
+ # set.met #=> [#<Goalkeeper::Goal @label="goal1">]
52
+ # set.unmet #=> [#<Goalkeeper::Goal @label="goal2">]
53
+ #
54
+ # Lets complete our set.
55
+ # Goalkeeper.met!('goal1')
56
+ # set.met? #=> true
57
+ #
58
+ # See the time the final goal was met
59
+ # set.met_at #=> 2015-01-01 08:02:15 -0500
60
+ #
61
+ # === Customization
25
62
  #
26
63
  # Customize the redis client by setting it in your application
27
64
  # Goalkeeper.redis = your_redis_client
@@ -29,11 +66,14 @@ require 'time' # for Time.parse
29
66
  # Each record has a default expiration of 24 hours, but this can be modified.
30
67
  # Goalkeeper.expiration = number_of_seconds
31
68
  #
32
- # Redis keys are stored under the default namespace of "Goalkeeper:". The namespace can be configured:
33
- #
69
+ # Redis keys are stored under the default namespace of "Goalkeeper:". The
70
+ # namespace can be configured:
34
71
  # Goalkeeper.namespace = string
35
72
  #
36
- class Goalkeeper
73
+ module Goalkeeper
74
+ require "goalkeeper/version"
75
+ require "goalkeeper/goal"
76
+ require "goalkeeper/set"
37
77
 
38
78
  # Set the Redis client to a non default setting
39
79
  def self.redis=(redis)
@@ -49,6 +89,10 @@ class Goalkeeper
49
89
  Goal.new(label).met!
50
90
  end
51
91
 
92
+ def self.met?(label)
93
+ Goal.new(label).met?
94
+ end
95
+
52
96
  # The TTL set for each met Goal record created in Redis
53
97
  # Default is 24 hours
54
98
  def self.expiration
@@ -67,118 +111,4 @@ class Goalkeeper
67
111
  def self.namespace=(ns)
68
112
  @namespace = ns
69
113
  end
70
-
71
- # List is a collection of Goals to simplify tracking multiple goals.
72
- #
73
- # Create a new list
74
- # mylist = Goalkeeper::List.new
75
- #
76
- # Add Goals you want to check for completion
77
- # mylist.add("job1").add("job2")
78
- # mylist.size
79
- # #=> 2
80
- #
81
- # Check if all the goals are completed
82
- # mylist.met?
83
- # #=> false
84
- #
85
- # Get the unmet Goals
86
- # mylist.unmet
87
- # #=> [...]
88
- #
89
- # Get the met Goals
90
- # mylist.met
91
- # #=> [...]
92
- #
93
- # Iterate all Goals
94
- # myslist.each {|goal| ...}
95
- # myslist.map {|goal| ...}
96
- class List
97
- extend Forwardable
98
- def_delegators :@list, :size, :[], :each, :map
99
-
100
- def initialize
101
- @list = []
102
- end
103
-
104
- # Creates a new Goal.
105
- # see Goal#new for usage
106
- def add(label, ref: nil)
107
- @list.push(Goal.new(label, ref: ref))
108
- self
109
- end
110
-
111
- # met? returns true if all Goals in the set have been met.
112
- def met?
113
- unmet.empty?
114
- end
115
-
116
- def unmet
117
- @list.select {|g| ! g.met?}
118
- end
119
-
120
- def met
121
- @list.select {|g| g.met?}
122
- end
123
- end
124
-
125
- class Goal
126
- # The unique label to identify this Goal
127
- attr_reader :label
128
-
129
- # An optional object refrence which allows an application author to
130
- # associate this goal to an object. The +ref+ is not used by Goalkeeper.
131
- attr_reader :ref
132
-
133
- # the TTL value for the Redis record. Defalts to Goalkeeper.expiration
134
- attr_reader :expiration
135
-
136
- # +label+ is a unique string to identify this Goal.
137
- # There is no checking if it is truly unique.
138
- #
139
- # +ref+ is an optional reference to any object. This
140
- # would be used by the end user's application.
141
- #
142
- # +expiration+ can be set to override the gobal expiratin.
143
- def initialize(label, ref: nil, expiration: Goalkeeper.expiration)
144
- @label = label
145
- @ref = ref
146
- @expiration = expiration
147
- end
148
-
149
- def met!
150
- write
151
- self
152
- end
153
-
154
- def met?
155
- ! read.nil?
156
- end
157
-
158
- # Time the goal was completed.
159
- # WARNING retuns nil if the job is not met
160
- def met_at
161
- if met?
162
- Time.parse(read)
163
- else
164
- nil
165
- end
166
- end
167
-
168
- # a namespaced key for the goal
169
- def key
170
- "#{Goalkeeper.namespace}:#{label}"
171
- end
172
-
173
- protected
174
-
175
- def write
176
- Goalkeeper.redis.set(self.key, Time.now)
177
- Goalkeeper.redis.expire(self.key, self.expiration)
178
- end
179
-
180
- def read
181
- Goalkeeper.redis.get self.key
182
- end
183
- end
184
114
  end
@@ -0,0 +1,66 @@
1
+ module Goalkeeper
2
+ # Goal represents a label which has either been +met+ or not.
3
+ #
4
+ class Goal
5
+ # The unique label to identify this Goal. There is no logic to check that the
6
+ # label is unique.
7
+ attr_reader :label
8
+
9
+ # the TTL value for the Redis record. Defalts to Goalkeeper.expiration
10
+ attr_reader :expiration
11
+
12
+ # +label+ is a unique string to identify this Goal.
13
+ # +expiration+ number secconds. This can be set to override the gobal expiration.
14
+ def initialize(label, expiration: Goalkeeper.expiration)
15
+ @label = label
16
+ @expiration = expiration
17
+ end
18
+
19
+ def met!
20
+ write unless met?
21
+ self
22
+ end
23
+
24
+ def met?
25
+ !read.nil?
26
+ end
27
+
28
+ # Time the goal was completed.
29
+ # WARNING retuns nil if the job is not met
30
+ def met_at
31
+ return Time.parse(read) if met?
32
+ nil
33
+ end
34
+
35
+ # clear! removes the met state of the Goal.
36
+ def clear!
37
+ Goalkeeper.redis.del(key)
38
+ end
39
+
40
+ # a namespaced key for the goal
41
+ def key
42
+ "#{Goalkeeper.namespace}:#{label}"
43
+ end
44
+
45
+ # ttl returns the time to live on the redis key
46
+ def ttl
47
+ Goalkeeper.redis.ttl(key)
48
+ end
49
+
50
+ # All Goalkeeper::Goals with the same label are equal
51
+ def ==(other)
52
+ other.is_a?(Goalkeeper::Goal) && other.label == label
53
+ end
54
+
55
+ protected
56
+
57
+ def write
58
+ Goalkeeper.redis.set(key, Time.now)
59
+ Goalkeeper.redis.expire(key, expiration)
60
+ end
61
+
62
+ def read
63
+ Goalkeeper.redis.get(key)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,87 @@
1
+ module Goalkeeper
2
+ # Set is an Array of Goals to simplify tracking multiple goals.
3
+ # Since Set is an array, you have all Array methods available.
4
+ #
5
+ # Create a new set
6
+ # myset = Goalkeeper::Set.new
7
+ #
8
+ # Add Goals you want to check for completion
9
+ # myset.add("job1").add("job2")
10
+ # myset.size
11
+ # #=> 2
12
+ #
13
+ # Check if all the goals are completed
14
+ # myset.met?
15
+ # #=> false
16
+ #
17
+ # Get the unmet Goals
18
+ # myset.unmet
19
+ # #=> [...]
20
+ #
21
+ # Get the met Goals
22
+ # myset.met
23
+ # #=> [...]
24
+ #
25
+ # Iterate all Goals
26
+ # myset.each {|goal| ...}
27
+ # myset.map {|goal| ...}
28
+ class Set < Array
29
+ def initialize
30
+ super
31
+ end
32
+
33
+ # Creates a new Goal.
34
+ # see Goal#initialize for usage
35
+ def add(*args)
36
+ push(Goal.new(*args))
37
+ self
38
+ end
39
+
40
+ # met? returns true if all Goals in the set have been met.
41
+ def met?
42
+ unmet.empty?
43
+ end
44
+
45
+ # unmet returns a Set with the all the Goals that have not been met.
46
+ def unmet
47
+ subset(select { |g| !g.met? })
48
+ end
49
+
50
+ # met returns a Set with the all the Goals that have been met.
51
+ def met
52
+ subset(select { |g| g.met? })
53
+ end
54
+
55
+ # nil if this set is not met?
56
+ # otherwise returns the met_at Time for the last met goal
57
+ def met_at
58
+ if met?
59
+ self.map(&:met_at).sort.last
60
+ else
61
+ nil
62
+ end
63
+ end
64
+
65
+ def <<(other)
66
+ if other.is_a?(Goal) && !include?(other)
67
+ super
68
+ else
69
+ false
70
+ end
71
+ end
72
+
73
+ def push(*others)
74
+ others.each do |o|
75
+ self << o
76
+ end
77
+ end
78
+
79
+ protected
80
+
81
+ def subset(set)
82
+ Goalkeeper::Set.new.tap do |s|
83
+ set.each {|i| s << i}
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,3 +1,3 @@
1
- class Goalkeeper
2
- VERSION = "0.2"
1
+ module Goalkeeper
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,103 @@
1
+ require 'test_helper'
2
+
3
+ describe Goalkeeper::Goal do
4
+ before do
5
+ Goalkeeper.redis.flushdb
6
+ end
7
+
8
+ let(:goal) { Goalkeeper::Goal.new("test") }
9
+
10
+ it "has a label" do
11
+ assert_equal "test", goal.label
12
+ end
13
+
14
+ it "has a namespaced key" do
15
+ assert_equal "Goalkeeper:test", goal.key
16
+ end
17
+
18
+ it "is met? if the label has a Redis record" do
19
+ assert !goal.met?
20
+ Goalkeeper.redis.set goal.key, Time.now
21
+ assert goal.met?
22
+ end
23
+
24
+ describe "met_at" do
25
+ it "is nil if the Goal is not met" do
26
+ assert_equal nil, goal.met_at
27
+ end
28
+
29
+ it "is the timestamp that the Goal was met" do
30
+ @t = Time.parse(Time.now.to_s)
31
+ goal.met!
32
+ assert_equal @t, goal.met_at
33
+ end
34
+ end
35
+
36
+ describe "#met!" do
37
+ it "creates a timestamp record with the Goal's key" do
38
+ Time.stub(:now, 'timestamp') do
39
+ assert_equal nil, Goalkeeper.redis.get(goal.key)
40
+ goal.met!
41
+ assert_equal 'timestamp', Goalkeeper.redis.get(goal.key)
42
+ end
43
+ end
44
+
45
+ it "has a default ttl expiration" do
46
+ goal.met!
47
+ assert_equal goal.expiration, Goalkeeper.redis.ttl(goal.key)
48
+ end
49
+
50
+ it "does nothing if the goal is already met" do
51
+ t = Time.now
52
+ Time.stub(:now, t) do
53
+ goal.met!
54
+ assert_equal Time.parse(t.to_s), goal.met_at
55
+ end
56
+
57
+ Time.stub(:now, t + 1000) do
58
+ goal.met!
59
+ assert_equal Time.parse(t.to_s), goal.met_at
60
+ end
61
+ end
62
+ end
63
+
64
+ describe "#clear!" do
65
+ it "removes the met state of the Goal" do
66
+ goal.met!
67
+ assert_equal true, goal.met?
68
+ goal.clear!
69
+ assert_equal false, goal.met?
70
+ end
71
+ end
72
+
73
+ describe "#expiration" do
74
+ it "has a default of 24 hours" do
75
+ assert_equal 24 * 60 * 60, goal.expiration
76
+ end
77
+
78
+ it "can be set at initialization" do
79
+ g = Goalkeeper::Goal.new("x", expiration: 60)
80
+ assert_equal 60, g.expiration
81
+ end
82
+ end
83
+
84
+ describe "equality" do
85
+ it "should be true when the labels are the same" do
86
+ a = Goalkeeper::Goal.new("a")
87
+ b = Goalkeeper::Goal.new("b")
88
+ a2 = Goalkeeper::Goal.new("a")
89
+
90
+ assert_equal a, a2
91
+ assert a != b
92
+ end
93
+ end
94
+
95
+ describe "#ttl" do
96
+ it "returns the ttl on the Redis record" do
97
+ a = Goalkeeper::Goal.new("a")
98
+ assert_equal(-2, a.ttl)
99
+ a.met!
100
+ assert_equal Goalkeeper.expiration, a.ttl
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,104 @@
1
+ require 'test_helper'
2
+
3
+ describe Goalkeeper::Set do
4
+ before do
5
+ Goalkeeper.redis.flushdb
6
+ end
7
+
8
+ let(:goals) { Goalkeeper::Set.new }
9
+
10
+ describe "#add" do
11
+ it "creates a Goal from the label" do
12
+ goals.add("a:1")
13
+ assert_equal 1, goals.size
14
+ assert_equal "a:1", goals[0].label
15
+ end
16
+
17
+ it "accepts an option expiration" do
18
+ goals.add("a:1", expiration: 20)
19
+ assert_equal 20, goals.first.expiration
20
+ end
21
+
22
+ it "should return itself (so it is chainable)" do
23
+ assert_equal goals, goals.add("a:1")
24
+ end
25
+ end
26
+
27
+ it "behaves as a unique set" do
28
+ goals << Goalkeeper::Goal.new("a")
29
+ goals << Goalkeeper::Goal.new("b")
30
+ goals << Goalkeeper::Goal.new("a")
31
+ goals.push Goalkeeper::Goal.new("a")
32
+
33
+ assert_equal 2, goals.size
34
+ end
35
+
36
+ it "ignores insertion of nonGoals" do
37
+ goals << "a"
38
+ goals.push 1, 2, :a
39
+ assert_equal 0, goals.size
40
+ end
41
+
42
+ describe "with goals" do
43
+ before do
44
+ goals.add("x").add("y")
45
+ end
46
+
47
+ describe "#met" do
48
+ it "returns all Goals which have been met" do
49
+ assert goals.met.empty?
50
+ goals[0].met!
51
+ assert_equal ["x"], goals.met.map(&:label)
52
+ goals[1].met!
53
+ assert_equal(%w( x y ), goals.met.map(&:label))
54
+
55
+ assert goals.met.is_a?(Goalkeeper::Set)
56
+ end
57
+ end
58
+
59
+ describe "#unmet" do
60
+ it "returns all Goals which have not been met" do
61
+ assert_equal(%w( x y ), goals.unmet.map(&:label))
62
+ goals[0].met!
63
+ assert_equal ["y"], goals.unmet.map(&:label)
64
+ goals[1].met!
65
+ assert goals.unmet.empty?
66
+
67
+ assert goals.unmet.is_a?(Goalkeeper::Set)
68
+ end
69
+ end
70
+
71
+ describe "#met?" do
72
+ it "is true when all Goals have been met" do
73
+ assert !goals.met?
74
+ goals.each(&:met!)
75
+ assert goals.met?
76
+ end
77
+ end
78
+
79
+ describe "#met_at" do
80
+ before do
81
+ goals << Goalkeeper::Goal.new("a")
82
+ goals << Goalkeeper::Goal.new("b")
83
+ goals << Goalkeeper::Goal.new("a")
84
+ end
85
+
86
+ it "is nil unless all Goals are met" do
87
+ goals[0].met!
88
+ goals[1].met!
89
+ assert_equal nil, goals.met_at
90
+ end
91
+
92
+ it "is the most recent met_at from the Goals" do
93
+ t = Time.now
94
+ Time.stub(:now, t + 1000) do
95
+ goals.first.met!
96
+ end
97
+ # meet the reset
98
+ goals.each &:met!
99
+
100
+ assert_equal((t + 1000).to_a, goals.met_at.to_a)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -28,118 +28,4 @@ describe Goalkeeper do
28
28
  Goalkeeper.namespace = ns
29
29
  end
30
30
  end
31
-
32
- describe Goalkeeper::List do
33
- before do
34
- @goals = Goalkeeper::List.new
35
- end
36
-
37
- describe "#add" do
38
- it "creates a Goal" do
39
- @goals.add("a:1")
40
- assert_equal 1, @goals.size
41
- assert_equal "a:1", @goals[0].label
42
- end
43
-
44
- it "accepts an optional reference object" do
45
- o = Object.new
46
- @goals.add("a:1", ref: o)
47
- assert_equal o, @goals[0].ref
48
- end
49
-
50
- it "should return itself (so it is chainable)" do
51
- assert_equal @goals, @goals.add("a:1")
52
- end
53
- end
54
-
55
- describe "with goals" do
56
- before do
57
- @goals.add("x").add("y")
58
- end
59
-
60
- describe "#met" do
61
- it "returns all Goals which have been met" do
62
- assert @goals.met.empty?
63
- @goals[0].met!
64
- assert_equal ["x"], @goals.met.map(&:label)
65
- @goals[1].met!
66
- assert_equal ["x","y"], @goals.met.map(&:label)
67
- end
68
- end
69
-
70
- describe "#unmet" do
71
- it "returns all Goals which have not been met" do
72
- assert_equal ["x","y"], @goals.unmet.map(&:label)
73
- @goals[0].met!
74
- assert_equal ["y"], @goals.unmet.map(&:label)
75
- @goals[1].met!
76
- assert @goals.unmet.empty?
77
- end
78
- end
79
-
80
- describe "#met?" do
81
- it "is true when all Goals have been met" do
82
- assert ! @goals.met?
83
- @goals.each(&:met!)
84
- assert @goals.met?
85
- end
86
- end
87
- end
88
- end
89
-
90
- describe Goalkeeper::Goal do
91
- before do
92
- @goal = Goalkeeper::Goal.new("b")
93
- end
94
-
95
- it "has a label" do
96
- assert_equal "b", @goal.label
97
- end
98
-
99
- it "has a namespaced key" do
100
- assert_equal "Goalkeeper:b", @goal.key
101
- end
102
-
103
- it "is met? if the label has a Redis record" do
104
- assert ! @goal.met?
105
- Goalkeeper.redis.set @goal.key, Time.now
106
- assert @goal.met?
107
- end
108
-
109
- describe "met_at" do
110
- it "is nil if the Goal is not met" do
111
- assert_equal nil, @goal.met_at
112
- end
113
-
114
- it "is the timestamp that the Goal was met" do
115
- @t = Time.parse(Time.now.to_s)
116
- @goal.met!
117
- assert_equal @t, @goal.met_at
118
- end
119
- end
120
-
121
- describe "#met!" do
122
- it "creates a Redis record" do
123
- assert Goalkeeper.redis.get(@goal.key).nil?
124
- @goal.met!
125
- assert ! Goalkeeper.redis.get(@goal.key).nil?
126
- end
127
-
128
- it "has a default ttl expiration" do
129
- @goal.met!
130
- assert_equal @goal.expiration, Goalkeeper.redis.ttl(@goal.key)
131
- end
132
- end
133
-
134
- describe "#expiration" do
135
- it "has a default of 24 hours" do
136
- assert_equal 24 * 60 * 60, @goal.expiration
137
- end
138
-
139
- it "can be set at initialization" do
140
- g = Goalkeeper::Goal.new("x", expiration: 60)
141
- assert_equal 60, g.expiration
142
- end
143
- end
144
- end
145
31
  end
data/test/test_helper.rb CHANGED
@@ -1,11 +1,8 @@
1
1
  require 'minitest/unit'
2
2
  require 'minitest/autorun'
3
3
  require 'minitest/pride'
4
-
5
4
  require './lib/goalkeeper'
6
-
7
5
  require './test/support/redis_instance'
8
6
 
9
7
  # Start up Redis on a random port
10
8
  Goalkeeper.redis = RedisInstance.run!
11
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goalkeeper
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Weir
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-04 00:00:00.000000000 Z
11
+ date: 2015-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -63,12 +63,15 @@ files:
63
63
  - ".gitignore"
64
64
  - Gemfile
65
65
  - LICENSE
66
- - LICENSE.txt
67
66
  - README.md
68
67
  - Rakefile
69
68
  - goalkeeper.gemspec
70
69
  - lib/goalkeeper.rb
70
+ - lib/goalkeeper/goal.rb
71
+ - lib/goalkeeper/set.rb
71
72
  - lib/goalkeeper/version.rb
73
+ - test/goalkeeper/goal_test.rb
74
+ - test/goalkeeper/set_test.rb
72
75
  - test/goalkeeper_test.rb
73
76
  - test/support/redis_instance.rb
74
77
  - test/test_helper.rb
@@ -97,6 +100,8 @@ signing_key:
97
100
  specification_version: 4
98
101
  summary: A Todo App for your application.
99
102
  test_files:
103
+ - test/goalkeeper/goal_test.rb
104
+ - test/goalkeeper/set_test.rb
100
105
  - test/goalkeeper_test.rb
101
106
  - test/support/redis_instance.rb
102
107
  - test/test_helper.rb
data/LICENSE.txt DELETED
@@ -1,22 +0,0 @@
1
- Copyright (c) 2015 John Weir
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.