cinch-cooldown 1.0.1 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,24 +4,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'cinch/cooldown/version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
- gem.name = "cinch-cooldown"
8
- gem.version = Cinch::Cooldown::VERSION
9
- gem.authors = ["Brian Haberer"]
10
- gem.email = ["bhaberer@gmail.com"]
7
+ gem.name = 'cinch-cooldown'
8
+ gem.version = Cinch::Cooldowns::VERSION
9
+ gem.authors = ['Brian Haberer']
10
+ gem.email = ['bhaberer@gmail.com']
11
11
  gem.description = %q{This gem allows you to set a shared timer across plugins that are configured to respect it.}
12
12
  gem.summary = %q{Global Cooldown tracker for Cinch Plugins}
13
- gem.homepage = "https://github.com/bhaberer/cinch-cooldown"
13
+ gem.homepage = 'https://github.com/bhaberer/cinch-cooldown'
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
16
16
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ["lib"]
18
+ gem.require_paths = ['lib']
19
+ gem.license = 'MIT'
19
20
 
20
- gem.add_development_dependency 'rake'
21
- gem.add_development_dependency 'rspec'
22
- gem.add_development_dependency 'coveralls'
23
- gem.add_development_dependency 'cinch-test'
21
+ gem.add_development_dependency 'rake'
22
+ gem.add_development_dependency 'rspec'
23
+ gem.add_development_dependency 'coveralls'
24
+ gem.add_development_dependency 'cinch-test'
24
25
 
25
- gem.add_dependency 'time-lord', '~> 1.0.1'
26
- gem.add_dependency 'cinch', '~> 2.0.5'
26
+ gem.add_dependency 'time-lord', '~> 1.0.1'
27
+ gem.add_dependency 'cinch', '~> 2.0.12'
27
28
  end
@@ -1,120 +1,6 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require 'cinch/cooldown/version'
3
+ require 'cinch/plugin/hooks'
4
+ require 'cinch/plugin/cooldown'
5
+ require 'cinch/plugin/cooldowns'
2
6
  require 'time-lord'
3
-
4
- module Cinch
5
- module Plugin
6
- module ClassMethods
7
- def enforce_cooldown
8
- hook(:pre, :for => [:match], :method => lambda {|m| cooldown_finished?(m)})
9
- end
10
- end
11
-
12
- def cooldown_finished?(m)
13
- # return if we don't have a cooldown config
14
- return true unless shared[:cooldown] && shared[:cooldown][:config]
15
- synchronize(:cooldown) do
16
- # return if we don't have a channel (i.e. user is pming the bot)
17
- return true if m.channel.nil?
18
-
19
- channel = m.channel.name
20
- user = m.user.nick
21
-
22
- # Make sure the configuration is sane.
23
- return true if configuration_broken?(channel)
24
-
25
- # Make sure it's not the first command
26
- return true if first_run?(channel, user)
27
-
28
- # Check if timers are finished
29
- return true if cooldowns_finished?(channel, user)
30
-
31
- # Handle unfinished cooldowns here
32
- m.user.notice cooldown_message(channel, user)
33
- return false
34
- end
35
- end
36
-
37
- def configuration_broken?(channel)
38
- # return if the config doesn't smell right for this channel
39
- return true unless shared[:cooldown][:config].key?(channel) &&
40
- config_for(channel).key?(:global) &&
41
- config_for(channel).key?(:user)
42
- false
43
- end
44
-
45
- def first_run?(channel, user)
46
- unless shared[:cooldown].key?(channel)
47
- trigger_cooldown_for(channel, user)
48
- return true
49
- end
50
- end
51
-
52
- def cooldowns_finished?(channel, user)
53
- # Normal usage stuff starts here, check and see if the channel time is up
54
- if channel_cooldown_finished?(channel)
55
- # channel cd is up, check per user by checking if the user's even triggered a cd yet
56
- if shared[:cooldown][channel].key?(user)
57
- # User's in the config, check time
58
- if user_cooldown_finished?(channel, user)
59
- # Their time's up, run the command
60
- trigger_cooldown_for(channel, user)
61
- return true
62
- end
63
- else
64
- # User's not used bot before, run the command
65
- trigger_cooldown_for(channel, user)
66
- return true
67
- end
68
- end
69
- return false
70
- end
71
-
72
- def cooldown_message(channel, user)
73
- message = ['Sorry, you\'ll have to wait']
74
- unless channel_cooldown_finished?(channel)
75
- message << TimeLord::Period.new(cooldown_channel_expire_time(channel), Time.now).to_words
76
- message << 'before I can talk in the channel again, and'
77
- end
78
- message << TimeLord::Period.new(cooldown_user_expire_time(channel, user), Time.now).to_words
79
- message << 'before you can use any commands.'
80
-
81
- return message.join(' ')
82
- end
83
-
84
- def trigger_cooldown_for(channel, user)
85
- shared[:cooldown][channel] = { :global => Time.now, user => Time.now }
86
- end
87
-
88
- def cooldown_channel_expire_time(channel)
89
- global_cooldown_for(channel) + config_for(channel)[:global]
90
- end
91
-
92
- def cooldown_user_expire_time(channel, user)
93
- user_cooldown_for(channel, user) + config_for(channel)[:user]
94
- end
95
-
96
- def user_cooldown_finished?(channel, user)
97
- cooldown = config_for(channel)[:user]
98
- elapsed = Time.now - user_cooldown_for(channel, user)
99
- return cooldown <= elapsed
100
- end
101
-
102
- def channel_cooldown_finished?(channel)
103
- cooldown = config_for(channel)[:global]
104
- elapsed = Time.now - global_cooldown_for(channel)
105
- return cooldown <= elapsed
106
- end
107
-
108
- def config_for(chan)
109
- shared[:cooldown][:config][chan]
110
- end
111
-
112
- def global_cooldown_for(chan)
113
- shared[:cooldown][chan][:global] ||= Time.now
114
- end
115
-
116
- def user_cooldown_for(chan, nick)
117
- shared[:cooldown][chan][nick] || Time.now
118
- end
119
- end
120
- end
@@ -1,5 +1,7 @@
1
+ # -*- coding: utf-8 -*-
1
2
  module Cinch
2
- module Cooldown
3
- VERSION = "1.0.1"
3
+ # Versioning info
4
+ module Cooldowns
5
+ VERSION = '1.1.3'
4
6
  end
5
7
  end
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Cinch
3
+ module Plugin
4
+ # An alteration to the Plugin Module to allow for configurable cooldowns.
5
+ class Cooldown
6
+ attr_accessor :time, :duration, :expires_at
7
+
8
+ def initialize(duration, time = Time.now)
9
+ @time = time
10
+ @duration = duration
11
+ @expires_at = @time + @duration
12
+ end
13
+
14
+ def time_till_expire_in_words
15
+ return 'until right now' if (expires_at - Time.now) < 0
16
+ TimeLord::Period.new(expires_at, Time.now).to_words
17
+ end
18
+
19
+ def time_till_expire
20
+ period = @expires_at - Time.now
21
+ return 0 if period < 0
22
+ period
23
+ end
24
+
25
+ def cooled_down?
26
+ time_till_expire.zero?
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,128 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Cinch
3
+ module Plugin
4
+ module Cooldowns
5
+ include Cinch::Plugin
6
+
7
+ @cooldowns = {}
8
+ @config = nil
9
+
10
+ # Main method called by the hook
11
+ def self.finished?(m, shared, bot)
12
+ return unless shared.is_a?(Hash)
13
+ @config = shared[:config]
14
+ @cooldowns = shared[:cooldowns] if shared.key?(:cooldowns)
15
+
16
+ # Don't run if we there's no cooldown config
17
+ return true unless @config
18
+
19
+ bot.synchronize(:cooldown) do
20
+ # Avoid cooldown if we don't have a channel
21
+ # (i.e. user is pming the bot)
22
+ return true if m.channel.nil?
23
+
24
+ clean_expired_cooldowns(m.channel.name)
25
+
26
+ # return true if the cooldowns have expired
27
+ return true if cool?(m.channel.name, m.user.nick)
28
+
29
+ # Otherwise message the user about unfinished cooldowns
30
+ m.user.notice message(m.channel.name, m.user.nick)
31
+
32
+ # and return false so the command gets dropped by the hook
33
+ false
34
+ end
35
+ end
36
+
37
+ # Main cooldown data check
38
+ def self.cool?(channel, user)
39
+ # Make sure the configuration is sane.
40
+ return true if config_broken?(channel) ||
41
+ # Make sure it's not the first command
42
+ first_run?(channel, user) ||
43
+ # Check if timers are finished
44
+ cooldowns_finished?(channel, user)
45
+
46
+ # Otherwise trigger cooldown
47
+ false
48
+ end
49
+
50
+ def self.config_broken?(channel)
51
+ # return true if the config doesn't have needed info this channel
52
+ return true unless @config.key?(channel) &&
53
+ config_for(channel).key?(:global) &&
54
+ config_for(channel).key?(:user)
55
+ # otherwise abort cooldown enforcement
56
+ false
57
+ end
58
+
59
+ def self.config_for(chan)
60
+ @config[chan]
61
+ end
62
+
63
+ def self.first_run?(channel, user)
64
+ unless @cooldowns.key?(channel)
65
+ trigger_cooldown_for(channel, user)
66
+ return true
67
+ end
68
+ false
69
+ end
70
+
71
+ def self.purge!
72
+ @cooldowns = {}
73
+ end
74
+
75
+ def self.cooldowns_finished?(channel, user)
76
+ # Chuck all the cooldowns that have expired
77
+ clean_expired_cooldowns(channel)
78
+
79
+ # if the channel's cooldown is up
80
+ if @cooldowns[channel][:global].nil?
81
+ # And their cd's up, or they've not used bot before, run the command
82
+ if @cooldowns[channel][user].nil?
83
+ # trigger a new cooldown
84
+ trigger_cooldown_for(channel, user)
85
+ # and run the command
86
+ return true
87
+ end
88
+ end
89
+ false
90
+ end
91
+
92
+ def self.clean_expired_cooldowns(channel)
93
+ return unless @cooldowns.key?(channel)
94
+ @cooldowns[channel].each_pair do |key, cooldown|
95
+ if cooldown.cooled_down?
96
+ @cooldowns[channel].delete(key)
97
+ end
98
+ end
99
+ end
100
+
101
+ def self.message(channel, user)
102
+ cds = []
103
+ if @cooldowns[channel].key?(:global)
104
+ chan_exp = @cooldowns[channel][:global].time_till_expire_in_words
105
+ cds << "#{chan_exp} before I can talk in the channel again"
106
+ elsif @cooldowns[channel].key?(user)
107
+ user_exp = @cooldowns[channel][user].time_till_expire_in_words
108
+ cds << "#{user_exp} before you can use any commands"
109
+ end
110
+ ['Sorry, cooldown is in effect:', cds.join(', and ')].join(' ')
111
+ end
112
+
113
+ def self.trigger_cooldown_for(channel, user)
114
+ # Make sure the channel array has been init
115
+ @cooldowns[channel] ||= {}
116
+
117
+ # Create a cooldown for the channel
118
+ @cooldowns[channel][:global] =
119
+ Cooldown.new(@config[channel][:global])
120
+ # Create a cooldown for the user
121
+ @cooldowns[channel][user] =
122
+ Cooldown.new(@config[channel][:user])
123
+
124
+ warn "[[ Cooldown Triggered for user: #{user} ]]"
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Cinch
3
+ # An alteration to the Plugin Module to allow for configurable cooldowns.
4
+ module Plugin
5
+ # Add the pre hook to all messages triggered
6
+ module ClassMethods
7
+ def enforce_cooldown
8
+ hook(:pre, for: [:match],
9
+ method: ->(m){ Cooldowns.finished?(m, shared[:cooldown], @bot) })
10
+ end
11
+ end
12
+ end
13
+ end
@@ -12,71 +12,94 @@ class MyPlugin
12
12
  end
13
13
 
14
14
  def bot_for_cooldowns(global = 10, user = 0)
15
- @bot = Cinch::Test::MockBot.new do
16
- configure do |c|
17
- c.nick = 'testbot'
18
- c.server = nil
19
- c.channels = ['foo']
20
- c.reconnect = false
21
- c.plugins.plugins = [MyPlugin]
22
- c.shared[:cooldown] = { :config => { '#foo' => { :global => global, :user => user } } }
23
- end
24
- end
15
+ Cinch::Test::MockBot.new do
16
+ configure do |c|
17
+ c.nick = 'testbot'
18
+ c.server = nil
19
+ c.channels = ['foo']
20
+ c.reconnect = false
21
+ c.plugins.plugins = [MyPlugin]
22
+ c.shared[:cooldown] = { :config => { '#foo' => { :global => global, :user => user } } }
23
+ end
24
+ end
25
25
  end
26
26
 
27
- describe Cinch::Cooldown do
27
+ describe Cinch::Cooldowns do
28
28
  include Cinch::Test
29
29
 
30
+ after(:each) do
31
+ Cinch::Plugin::Cooldowns.purge!
32
+ end
33
+
30
34
  it 'should not trigger cooldowns on private messages' do
31
- @bot = bot_for_cooldowns(10)
32
- get_replies(make_message(@bot, "!thing"))
33
- get_replies(make_message(@bot, "!thing")).first.text.
35
+ bot = bot_for_cooldowns(10)
36
+ get_replies(make_message(bot, "!thing"))
37
+ get_replies(make_message(bot, "!thing")).first.text.
34
38
  should match "OMG"
35
39
  end
36
40
 
37
41
  it 'should allow plugins to mandate a global cooldown between responses in channel' do
38
- @bot = bot_for_cooldowns(10)
39
- get_replies(make_message(@bot, "!thing", channel: '#foo'))
40
- get_replies(make_message(@bot, "!thing", channel: '#foo')).first.text.
41
- should match(/Sorry, you'll have to wait \d+ seconds from now before I can talk/)
42
+ bot = bot_for_cooldowns(10)
43
+ get_replies(make_message(bot, "!thing", channel: '#foo'))
44
+ get_replies(make_message(bot, "!thing", channel: '#foo')).first.text.
45
+ should match(/Sorry, cooldown is in effect: \d+ seconds from now before/)
42
46
  end
43
47
 
44
48
  it 'should allow plugins allow responses after the global cooldown' do
45
- @bot = bot_for_cooldowns(5)
46
- get_replies(make_message(@bot, "!thing", channel: '#foo'))
47
- sleep 5
48
- get_replies(make_message(@bot, "!thing", channel: '#foo')).first.text.
49
+ bot = bot_for_cooldowns(5, 5)
50
+ get_replies(make_message(bot, "!thing", channel: '#foo'))
51
+ sleep 7
52
+ get_replies(make_message(bot, "!thing", channel: '#foo')).first.text.
49
53
  should == 'OMG'
50
54
  end
51
55
 
52
56
  it 'should allow plugins to mandate a minimum time between responses in channel' do
53
- @bot = bot_for_cooldowns(5, 10)
54
- get_replies(make_message(@bot, "!thing", channel: '#foo'))
55
- sleep 6
56
- get_replies(make_message(@bot, "!thing", channel: '#foo')).first.text.
57
- should match(/Sorry, you'll have to wait \d+ seconds from now before you can use/)
57
+ bot = bot_for_cooldowns(5, 10)
58
+ get_replies(make_message(bot, "!thing", channel: '#foo'))
59
+ sleep 7
60
+ get_replies(make_message(bot, "!thing", channel: '#foo')).first.text.
61
+ should match(/Sorry, cooldown is in effect: \d+ seconds from now before you can use/)
58
62
  end
59
63
 
60
64
  it 'should allow plugins to mandate a minimum time between responses in channel' do
61
- @bot = bot_for_cooldowns(5, 10)
62
- get_replies(make_message(@bot, "!thing", channel: '#foo'))
63
- sleep 10
64
- get_replies(make_message(@bot, "!thing", channel: '#foo')).first.text.
65
+ bot = bot_for_cooldowns(5, 10)
66
+ get_replies(make_message(bot, "!thing", channel: '#foo'))
67
+ sleep 12
68
+ get_replies(make_message(bot, "!thing", channel: '#foo')).first.text.
69
+ should == 'OMG'
70
+ end
71
+
72
+ it 'should aplugins to mandate a minimum time between responses in channel' do
73
+ bot = bot_for_cooldowns(5, 10)
74
+ get_replies(make_message(bot, "!thing", channel: '#foo'))
75
+ get_replies(make_message(bot, "thing", channel: '#foo'))
76
+ sleep 6
77
+ get_replies(make_message(bot, "!thing", channel: '#foo', nick: 'george'))
78
+ sleep 5
79
+ get_replies(make_message(bot, "!thing", channel: '#foo')).first.text.
65
80
  should == 'OMG'
66
81
  end
67
82
 
68
83
  it 'should not trigger if the config for the current channel does not exist' do
69
- @bot = bot_for_cooldowns(5, 10)
70
- get_replies(make_message(@bot, "!thing", channel: '#bar'))
71
- get_replies(make_message(@bot, "!thing", channel: '#bar')).first.text.
84
+ bot = bot_for_cooldowns(5, 10)
85
+ get_replies(make_message(bot, "!thing", channel: '#bar'))
86
+ get_replies(make_message(bot, "!thing", channel: '#bar')).first.text.
72
87
  should == 'OMG'
73
88
  end
74
89
 
75
- it 'should trigger for other users if the global cooldown is not finished' do
76
- @bot = bot_for_cooldowns(10, 20)
77
- get_replies(make_message(@bot, "!thing", channel: '#foo', nick: 'test1')).first.text.
90
+ it 'should trigger for other users if the global cooldown is finished' do
91
+ bot = bot_for_cooldowns(0, 20)
92
+ get_replies(make_message(bot, "!thing", channel: '#foo', nick: 'test1')).first.text.
93
+ should == 'OMG'
94
+ sleep 1
95
+ get_replies(make_message(bot, "!thing", channel: '#foo', nick: 'test2')).first.text.
96
+ should == 'OMG'
97
+ end
98
+ it 'should trigger for other users if the global cooldown is finished' do
99
+ bot = bot_for_cooldowns(10, 20)
100
+ get_replies(make_message(bot, "!thing", channel: '#foo', nick: 'test1')).first.text.
78
101
  should == 'OMG'
79
- get_replies(make_message(@bot, "!thing", channel: '#foo', nick: 'test2')).first.text.
102
+ get_replies(make_message(bot, "!thing", channel: '#foo', nick: 'test2')).first.text.
80
103
  should_not == 'OMG'
81
104
  end
82
105
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cinch-cooldown
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-04 00:00:00.000000000 Z
12
+ date: 2014-02-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -98,7 +98,7 @@ dependencies:
98
98
  requirements:
99
99
  - - ~>
100
100
  - !ruby/object:Gem::Version
101
- version: 2.0.5
101
+ version: 2.0.12
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,7 +106,7 @@ dependencies:
106
106
  requirements:
107
107
  - - ~>
108
108
  - !ruby/object:Gem::Version
109
- version: 2.0.5
109
+ version: 2.0.12
110
110
  description: This gem allows you to set a shared timer across plugins that are configured
111
111
  to respect it.
112
112
  email:
@@ -124,10 +124,14 @@ files:
124
124
  - cinch-cooldown.gemspec
125
125
  - lib/cinch/cooldown.rb
126
126
  - lib/cinch/cooldown/version.rb
127
+ - lib/cinch/plugin/cooldown.rb
128
+ - lib/cinch/plugin/cooldowns.rb
129
+ - lib/cinch/plugin/hooks.rb
127
130
  - spec/cinch-cooldown_spec.rb
128
131
  - spec/spec_helper.rb
129
132
  homepage: https://github.com/bhaberer/cinch-cooldown
130
- licenses: []
133
+ licenses:
134
+ - MIT
131
135
  post_install_message:
132
136
  rdoc_options: []
133
137
  require_paths:
@@ -146,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
150
  version: '0'
147
151
  requirements: []
148
152
  rubyforge_project:
149
- rubygems_version: 1.8.24
153
+ rubygems_version: 1.8.25
150
154
  signing_key:
151
155
  specification_version: 3
152
156
  summary: Global Cooldown tracker for Cinch Plugins