goalkeeper 0.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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.