cinch-cooldown 1.0.1 → 1.1.3

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.
@@ -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