lita-karma 0.0.1 → 0.0.2

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: fa005d01f58fb03aa07984d4441b9caa058d9598
4
- data.tar.gz: 041ea5301d6b8190b847497e59489d58b860979d
3
+ metadata.gz: 6582ca790003f6b94e624a9b7d8fd81103ca5261
4
+ data.tar.gz: 7017b65d8c0a75a412fe15856771f5889c24729d
5
5
  SHA512:
6
- metadata.gz: 14d8b05cf3a25c8bba3e6fd010d089915ac93982993497ccf34575a929c0dc580be77e74f7570db9d93521c416873df1db77c27d06347627dc320437cd5d25db
7
- data.tar.gz: b0683a98f70347a1e16ddd58cab5d7c0b64d0d862bcb7e6db60a30468fddb4228b9fad9f9f9269c3afd509f4ef8e77c622bcfa9efd75edd8a0f50da3d1787afb
6
+ metadata.gz: ddc01d87d46b225edd96e5b899db22f8f21b420aba0d402a2bea691cf7dc031465a471235d808e7102e5e5dda647f6c302320383b5248cf82d498bceac53f806
7
+ data.tar.gz: 95020fb1b2c6fbfe7f83a089230af1bad2ed966470af53c08e72bc58724a5685f1a43baef08b3263faccf615be12ed6855e620bd7f24c987cae0bd87f659326b
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ script: bundle exec rspec
5
+ before_install:
6
+ - gem update --system
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # lita-karma
2
2
 
3
+ [![Build Status](https://travis-ci.org/jimmycuadra/lita-karma.png)](https://travis-ci.org/jimmycuadra/lita-karma)
4
+ [![Code Climate](https://codeclimate.com/github/jimmycuadra/lita-karma.png)](https://codeclimate.com/github/jimmycuadra/lita-karma)
5
+ [![Coverage Status](https://coveralls.io/repos/jimmycuadra/lita-karma/badge.png)](https://coveralls.io/r/jimmycuadra/lita-karma)
6
+
3
7
  **lita-karma** is a handler for [Lita](https://github.com/jimmycuadra/lita) that tracks karma points for arbitrary terms. It listens for upvotes and downvotes and keeps a tally of the scores for them in Redis.
4
8
 
5
9
  ## Installation
@@ -10,6 +14,16 @@ Add lita-karma to your Lita instance's Gemfile:
10
14
  gem "lita-karma"
11
15
  ```
12
16
 
17
+ ## Configuration
18
+
19
+ lita-karma has one option, the cooldown, which controls how long a user must wait after modifying a term before they can modify it again. The value should be an integer number of seconds. The default is 300 (5 minutes). Set it to `nil` to disable rate limiting.
20
+
21
+ ```
22
+ Lita.configure do |config|
23
+ config.handlers.karma.cooldown = 600
24
+ end
25
+ ```
26
+
13
27
  ## Usage
14
28
 
15
29
  Lita will add a karma point whenever it hears a term upvoted:
@@ -32,6 +46,12 @@ term~~
32
46
 
33
47
  To list the top scoring terms:
34
48
 
49
+ ```
50
+ Lita: karma best
51
+ ```
52
+
53
+ or simply:
54
+
35
55
  ```
36
56
  Lita: karma
37
57
  ```
@@ -58,7 +78,7 @@ bar++
58
78
  Lita: foo += bar
59
79
  > bar has been linked to foo.
60
80
  foo~~
61
- > foo: 2
81
+ > foo: 2 (1), linked to: bar: 1
62
82
  bar~~
63
83
  > bar: 1
64
84
  Lita: foo -= bar
@@ -67,6 +87,8 @@ foo~~
67
87
  > foo: 1
68
88
  ```
69
89
 
90
+ When a term is linked, the total karma score is displayed first, followed by the score of the term without its linked terms in parentheses.
91
+
70
92
  ## License
71
93
 
72
94
  [MIT](http://opensource.org/licenses/MIT)
@@ -6,9 +6,12 @@ module Lita
6
6
  route %r{([^\s]{2,})\+\+}, to: :increment
7
7
  route %r{([^\s]{2,})\-\-}, to: :decrement
8
8
  route %r{([^\s]{2,})~~}, to: :check
9
- route %r{karma}, to: :list, command: true
10
- route %r{([^\s]{2,})\s*\+=\s*([^\s]{2,})}, to: :link, command: true
11
- route %r{([^\s]{2,})\s*-=\s*([^\s]{2,})}, to: :unlink, command: true
9
+ route %r{^karma\s+worst}, to: :list_worst, command: true
10
+ route %r{^karma\s+best}, to: :list_best, command: true
11
+ route %r{^karma\s+modified}, to: :modified, command: true
12
+ route %r{^karma\s*$}, to: :list_best, command: true
13
+ route %r{^([^\s]{2,})\s*\+=\s*([^\s]{2,})}, to: :link, command: true
14
+ route %r{^([^\s]{2,})\s*-=\s*([^\s]{2,})}, to: :unlink, command: true
12
15
 
13
16
  def increment(matches)
14
17
  modify(matches, 1)
@@ -23,39 +26,31 @@ module Lita
23
26
 
24
27
  matches.each do |match|
25
28
  term = match[0]
26
- score = redis.zscore("terms", term).to_i
29
+ own_score = score = redis.zscore("terms", term).to_i
30
+ links = []
27
31
  redis.smembers("links:#{term}").each do |link|
28
- score += redis.zscore("terms", link).to_i
32
+ link_score = redis.zscore("terms", link).to_i
33
+ links << "#{link}: #{link_score}"
34
+ score += link_score
29
35
  end
30
- output << "#{term}: #{score}"
36
+
37
+ string = "#{term}: #{score}"
38
+ unless links.empty?
39
+ string << " (#{own_score}), linked to: "
40
+ string << links.join(", ")
41
+ end
42
+ output << string
31
43
  end
32
44
 
33
45
  reply *output
34
46
  end
35
47
 
36
- def list(matches)
37
- redis_command = case args.first
38
- when "worst"
39
- :zrange
40
- else
41
- :zrevrange
42
- end
43
-
44
- n = (args[1] || 5).to_i - 1
45
-
46
- terms_scores = redis.public_send(
47
- redis_command, "terms", 0, n, with_scores: true
48
- )
49
-
50
- output = terms_scores.each_with_index.map do |term_score, index|
51
- "#{index + 1}. #{term_score[0]} (#{term_score[1].to_i})"
52
- end.join("\n")
48
+ def list_best(matches)
49
+ list(:zrevrange)
50
+ end
53
51
 
54
- if output.length == 0
55
- reply "There are no terms being tracked yet."
56
- else
57
- reply output
58
- end
52
+ def list_worst(matches)
53
+ list(:zrange)
59
54
  end
60
55
 
61
56
  def link(matches)
@@ -82,21 +77,69 @@ module Lita
82
77
  end
83
78
  end
84
79
 
80
+ def modified(matches)
81
+ term = args[1]
82
+
83
+ if term.nil? || term.strip.empty?
84
+ reply "Format: #{robot.name}: karma modified TERM"
85
+ return
86
+ end
87
+
88
+ user_ids = redis.smembers("modified:#{term}")
89
+
90
+ if user_ids.empty?
91
+ reply "#{term} has never been modified."
92
+ else
93
+ reply user_ids.map { |id| User.find_by_id(id).name }.join(", ")
94
+ end
95
+ end
96
+
85
97
  private
86
98
 
87
99
  def modify(matches, delta)
88
- output = []
89
-
90
100
  matches.each do |match|
91
101
  term = match[0]
92
- score = redis.zincrby("terms", delta, term).to_i
93
- output << "#{term}: #{score}"
102
+
103
+ ttl = redis.ttl("cooldown:#{user.id}:#{term}")
104
+ if ttl >= 0
105
+ cooldown_message =
106
+ "You cannot modify #{term} for another #{ttl} second"
107
+ cooldown_message << (ttl == 1 ? "." : "s.")
108
+ reply cooldown_message
109
+ else
110
+ redis.zincrby("terms", delta, term)
111
+ redis.sadd("modified:#{term}", user.id)
112
+ cooldown = Lita.config.handlers.karma.cooldown
113
+ if cooldown
114
+ redis.setex("cooldown:#{user.id}:#{term}", cooldown.to_i, 1)
115
+ end
116
+ end
94
117
  end
95
118
 
96
- reply *output
119
+ check(matches)
120
+ end
121
+
122
+ def list(redis_command)
123
+ n = (args[1] || 5).to_i - 1
124
+
125
+ terms_scores = redis.public_send(
126
+ redis_command, "terms", 0, n, with_scores: true
127
+ )
128
+
129
+ output = terms_scores.each_with_index.map do |term_score, index|
130
+ "#{index + 1}. #{term_score[0]} (#{term_score[1].to_i})"
131
+ end.join("\n")
132
+
133
+ if output.length == 0
134
+ reply "There are no terms being tracked yet."
135
+ else
136
+ reply output
137
+ end
97
138
  end
98
139
  end
99
140
 
141
+ Lita.config.handlers.karma = Config.new
142
+ Lita.config.handlers.karma.cooldown = 300
100
143
  Lita.register_handler(Karma)
101
144
  end
102
145
  end
data/lita-karma.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "lita-karma"
3
- spec.version = "0.0.1"
3
+ spec.version = "0.0.2"
4
4
  spec.authors = ["Jimmy Cuadra"]
5
5
  spec.email = ["jimmy@jimmycuadra.com"]
6
6
  spec.description = %q{A Lita handler for tracking karma points for arbitrary terms.}
@@ -13,9 +13,11 @@ Gem::Specification.new do |spec|
13
13
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
14
14
  spec.require_paths = ["lib"]
15
15
 
16
- spec.add_runtime_dependency "lita", "~> 0.0.1"
16
+ spec.add_runtime_dependency "lita", "~> 1.0"
17
17
 
18
18
  spec.add_development_dependency "bundler", "~> 1.3"
19
19
  spec.add_development_dependency "rake"
20
20
  spec.add_development_dependency "rspec", ">= 2.14.0rc1"
21
+ spec.add_development_dependency "simplecov"
22
+ spec.add_development_dependency "coveralls"
21
23
  end
@@ -1,166 +1,188 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Lita::Handlers::Karma, lita_handler: true do
3
+ describe Lita::Handlers::Karma, lita: true do
4
+ before { Lita.config.handlers.karma.cooldown = nil }
5
+
4
6
  it { routes("foo++").to(:increment) }
5
7
  it { routes("foo--").to(:decrement) }
6
8
  it { routes("foo~~").to(:check) }
7
- it { routes("#{robot.name}: karma").to(:list) }
9
+ it { routes("#{robot.name}: karma best").to(:list_best) }
10
+ it { routes("#{robot.name}: karma worst").to(:list_worst) }
11
+ it { routes("#{robot.name}: karma modified").to(:modified) }
12
+ it { routes("#{robot.name}: karma").to(:list_best) }
8
13
  it { routes("#{robot.name}: foo += bar").to(:link) }
9
14
  it { routes("#{robot.name}: foo -= bar").to(:unlink) }
10
15
 
11
- let(:source) { an_instance_of(Lita::Source) }
12
-
13
16
  describe "#increment" do
14
17
  it "increases the term's score by one and says the new score" do
15
- expect(robot).to receive(:send_messages).with(source, "foo: 1")
18
+ expect_reply("foo: 1")
16
19
  send_test_message("foo++")
17
20
  end
18
21
 
19
22
  it "matches multiple terms in one message" do
20
- expect(robot).to receive(:send_messages).with(source, "foo: 1", "bar: 1")
23
+ expect_replies("foo: 1", "bar: 1")
21
24
  send_test_message("foo++ bar++")
22
25
  end
23
26
 
24
27
  it "doesn't start from zero if the term already has a positive score" do
25
- allow(robot).to receive(:send_messages)
26
28
  send_test_message("foo++")
27
- expect(robot).to receive(:send_messages).with(source, "foo: 2")
29
+ expect_reply("foo: 2")
30
+ send_test_message("foo++")
31
+ end
32
+
33
+ it "replies with a warning if term increment is on cooldown" do
34
+ Lita.config.handlers.karma.cooldown = 10
35
+ send_test_message("foo++")
36
+ expect_reply(/cannot modify foo/)
28
37
  send_test_message("foo++")
29
38
  end
30
39
  end
31
40
 
32
41
  describe "#decrement" do
33
42
  it "decreases the term's score by one and says the new score" do
34
- expect(robot).to receive(:send_messages).with(source, "foo: -1")
43
+ expect_reply("foo: -1")
35
44
  send_test_message("foo--")
36
45
  end
37
46
 
38
47
  it "matches multiple terms in one message" do
39
- expect(robot).to receive(:send_messages).with(
40
- source,
41
- "foo: -1",
42
- "bar: -1"
43
- )
48
+ expect_replies("foo: -1", "bar: -1")
44
49
  send_test_message("foo-- bar--")
45
50
  end
46
51
 
47
52
  it "doesn't start from zero if the term already has a positive score" do
48
- allow(robot).to receive(:send_messages)
49
53
  send_test_message("foo++")
50
- expect(robot).to receive(:send_messages).with(source, "foo: 0")
54
+ expect_reply("foo: 0")
55
+ send_test_message("foo--")
56
+ end
57
+
58
+ it "replies with a warning if term increment is on cooldown" do
59
+ Lita.config.handlers.karma.cooldown = 10
60
+ send_test_message("foo--")
61
+ expect_reply(/cannot modify foo/)
51
62
  send_test_message("foo--")
52
63
  end
53
64
  end
54
65
 
55
66
  describe "#check" do
56
67
  it "says the term's current score" do
57
- expect(robot).to receive(:send_messages).with(source, "foo: 0")
68
+ expect_reply("foo: 0")
58
69
  send_test_message("foo~~")
59
70
  end
60
71
 
61
72
  it "matches multiple terms in one message" do
62
- expect(robot).to receive(:send_messages).with(
63
- source,
64
- "foo: 0",
65
- "bar: 0"
66
- )
73
+ expect_replies("foo: 0", "bar: 0")
67
74
  send_test_message("foo~~ bar~~")
68
75
  end
69
76
  end
70
77
 
71
78
  describe "#list" do
72
- before do
73
- allow(robot).to receive(:send_messages)
74
- send_test_message(
75
- "one++ one++ one++ two++ two++ three++ four++ four-- five--"
76
- )
79
+ it "replies with a warning if there are no terms" do
80
+ expect_reply(/no terms being tracked/)
81
+ send_test_message("#{robot.name}: karma")
77
82
  end
78
83
 
79
- it "lists the top 5 terms by default" do
80
- expect(robot).to receive(:send_messages).with source, <<-MSG.chomp
84
+ context "with modified terms" do
85
+ before do
86
+ send_test_message(
87
+ "one++ one++ one++ two++ two++ three++ four++ four-- five--"
88
+ )
89
+ end
90
+
91
+ it "lists the top 5 terms by default" do
92
+ expect_reply <<-MSG.chomp
81
93
  1. one (3)
82
94
  2. two (2)
83
95
  3. three (1)
84
96
  4. four (0)
85
97
  5. five (-1)
86
98
  MSG
87
- send_test_message("#{robot.name}: karma")
88
- end
99
+ send_test_message("#{robot.name}: karma")
100
+ end
89
101
 
90
- it 'lists the bottom 5 terms when passed "worst"' do
91
- expect(robot).to receive(:send_messages).with source, <<-MSG.chomp
102
+ it 'lists the bottom 5 terms when passed "worst"' do
103
+ expect_reply <<-MSG.chomp
92
104
  1. five (-1)
93
105
  2. four (0)
94
106
  3. three (1)
95
107
  4. two (2)
96
108
  5. one (3)
97
109
  MSG
98
- send_test_message("#{robot.name}: karma worst")
99
- end
110
+ send_test_message("#{robot.name}: karma worst")
111
+ end
100
112
 
101
- it "limits the list to the count passed as the second argument" do
102
- expect(robot).to receive(:send_messages).with source, <<-MSG.chomp
113
+ it "limits the list to the count passed as the second argument" do
114
+ expect_reply <<-MSG.chomp
103
115
  1. one (3)
104
116
  2. two (2)
105
117
  MSG
106
- send_test_message("#{robot.name}: karma best 2")
118
+ send_test_message("#{robot.name}: karma best 2")
119
+ end
107
120
  end
108
121
  end
109
122
 
110
123
  describe "#link" do
111
124
  it "says that it's linked term 2 to term 1" do
112
- expect(robot).to receive(:send_messages).with(
113
- source,
114
- "bar has been linked to foo."
115
- )
125
+ expect_reply("bar has been linked to foo.")
116
126
  send_test_message("#{robot.name}: foo += bar")
117
127
  end
118
128
 
119
129
  it "says that term 2 was already linked to term 1 if it was" do
120
- allow(robot).to receive(:send_messages)
121
130
  send_test_message("#{robot.name}: foo += bar")
122
- expect(robot).to receive(:send_messages).with(
123
- source,
124
- "bar is already linked to foo."
125
- )
131
+ expect_reply("bar is already linked to foo.")
126
132
  send_test_message("#{robot.name}: foo += bar")
127
133
  end
128
134
 
129
135
  it "causes term 1's score to be modified by term 2's" do
130
- allow(robot).to receive(:send_messages)
131
- send_test_message("foo++ bar++")
136
+ send_test_message("foo++ bar++ baz++")
132
137
  send_test_message("#{robot.name}: foo += bar")
133
- expect(robot).to receive(:send_messages).with(source, "foo: 2")
138
+ send_test_message("#{robot.name}: foo += baz")
139
+ expect_reply("foo: 3 (1), linked to: baz: 1, bar: 1")
134
140
  send_test_message("foo~~")
135
141
  end
136
142
  end
137
143
 
138
144
  describe "#unlink" do
139
145
  it "says that it's unlinked term 2 from term 1" do
140
- allow(robot).to receive(:send_messages)
141
146
  send_test_message("#{robot.name}: foo += bar")
142
- expect(robot).to receive(:send_messages).with(
143
- source,
144
- "bar has been unlinked from foo."
145
- )
147
+ expect_reply("bar has been unlinked from foo.")
146
148
  send_test_message("#{robot.name}: foo -= bar")
147
149
  end
148
150
 
149
151
  it "says that term 2 was not linked to term 1 if it wasn't" do
150
- expect(robot).to receive(:send_messages).with(
151
- source,
152
- "bar is not linked to foo."
153
- )
152
+ expect_reply("bar is not linked to foo.")
154
153
  send_test_message("#{robot.name}: foo -= bar")
155
154
  end
156
155
 
157
156
  it "causes term 1's score to stop being modified by term 2's" do
158
- allow(robot).to receive(:send_messages)
159
157
  send_test_message("foo++ bar++")
160
158
  send_test_message("#{robot.name}: foo += bar")
161
159
  send_test_message("#{robot.name}: foo -= bar")
162
- expect(robot).to receive(:send_messages).with(source, "foo: 1")
160
+ expect_reply("foo: 1")
163
161
  send_test_message("foo~~")
164
162
  end
165
163
  end
164
+
165
+ describe "#modified" do
166
+ it "replies with the required format if a term is not provided" do
167
+ expect_reply(/^Format:/)
168
+ send_test_message("#{robot.name}: karma modified")
169
+ end
170
+
171
+ it "replies with the required format if the term is an empty string" do
172
+ expect_reply(/^Format:/)
173
+ send_test_message("#{robot.name}: karma modified ' '")
174
+ end
175
+
176
+ it "replies with a message if the term hasn't been modified" do
177
+ expect_reply(/never been modified/)
178
+ send_test_message("#{robot.name}: karma modified foo")
179
+ end
180
+
181
+ it "lists users who have modified the given term" do
182
+ allow(Lita::User).to receive(:find_by_id).and_return(user)
183
+ send_test_message("foo++")
184
+ expect_reply(user.name)
185
+ send_test_message("#{robot.name}: karma modified foo")
186
+ end
187
+ end
166
188
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,10 @@
1
- require "lita-karma"
1
+ require "simplecov"
2
+ require "coveralls"
3
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
4
+ SimpleCov::Formatter::HTMLFormatter,
5
+ Coveralls::SimpleCov::Formatter
6
+ ]
7
+ SimpleCov.start
2
8
 
9
+ require "lita-karma"
3
10
  require "lita/rspec"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lita-karma
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jimmy Cuadra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-15 00:00:00.000000000 Z
11
+ date: 2013-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lita
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.1
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 0.0.1
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: 2.14.0rc1
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: coveralls
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  description: A Lita handler for tracking karma points for arbitrary terms.
70
98
  email:
71
99
  - jimmy@jimmycuadra.com
@@ -74,6 +102,7 @@ extensions: []
74
102
  extra_rdoc_files: []
75
103
  files:
76
104
  - .gitignore
105
+ - .travis.yml
77
106
  - Gemfile
78
107
  - README.md
79
108
  - Rakefile