chatterbot 1.0.2 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -2
  3. data/LICENSE.txt +18 -9
  4. data/README.markdown +83 -65
  5. data/bin/chatterbot-register +0 -1
  6. data/chatterbot.gemspec +3 -10
  7. data/examples/class_bot.rb +0 -1
  8. data/examples/echoes_bot.rb +2 -2
  9. data/examples/search_bot.rb +1 -1
  10. data/examples/streaming_bot.rb +21 -15
  11. data/lib/chatterbot.rb +7 -12
  12. data/lib/chatterbot/blocklist.rb +61 -0
  13. data/lib/chatterbot/bot.rb +118 -13
  14. data/lib/chatterbot/client.rb +52 -20
  15. data/lib/chatterbot/config.rb +92 -215
  16. data/lib/chatterbot/config_manager.rb +49 -0
  17. data/lib/chatterbot/direct_messages.rb +46 -0
  18. data/lib/chatterbot/dsl.rb +157 -78
  19. data/lib/chatterbot/followers.rb +4 -0
  20. data/lib/chatterbot/handler.rb +29 -0
  21. data/lib/chatterbot/helpers.rb +14 -3
  22. data/lib/chatterbot/home_timeline.rb +5 -8
  23. data/lib/chatterbot/logging.rb +0 -17
  24. data/lib/chatterbot/profile.rb +0 -1
  25. data/lib/chatterbot/reply.rb +6 -11
  26. data/lib/chatterbot/retweet.rb +2 -6
  27. data/lib/chatterbot/safelist.rb +33 -0
  28. data/lib/chatterbot/search.rb +26 -16
  29. data/lib/chatterbot/skeleton.rb +7 -38
  30. data/lib/chatterbot/streaming.rb +26 -33
  31. data/lib/chatterbot/tweet.rb +0 -1
  32. data/lib/chatterbot/ui.rb +9 -2
  33. data/lib/chatterbot/utils.rb +13 -0
  34. data/lib/chatterbot/version.rb +1 -1
  35. data/spec/blocklist_spec.rb +170 -0
  36. data/spec/bot_spec.rb +83 -8
  37. data/spec/client_spec.rb +61 -7
  38. data/spec/config_manager_spec.rb +59 -0
  39. data/spec/config_spec.rb +33 -158
  40. data/spec/direct_messages_spec.rb +115 -0
  41. data/spec/dsl_spec.rb +95 -53
  42. data/spec/handler_spec.rb +27 -0
  43. data/spec/helpers_spec.rb +7 -11
  44. data/spec/home_timeline_spec.rb +42 -31
  45. data/spec/logging_spec.rb +0 -34
  46. data/spec/reply_spec.rb +10 -34
  47. data/spec/search_spec.rb +65 -6
  48. data/spec/spec_helper.rb +25 -1
  49. data/spec/streaming_spec.rb +56 -58
  50. data/spec/whitelist_spec.rb +10 -10
  51. data/specs.watchr +2 -4
  52. data/templates/skeleton.txt +148 -12
  53. metadata +20 -22
  54. data/bin/chatterbot-blacklist +0 -65
  55. data/bin/chatterbot-status +0 -55
  56. data/examples/loop_bot.rb +0 -44
  57. data/lib/chatterbot/blacklist.rb +0 -61
  58. data/lib/chatterbot/db.rb +0 -79
  59. data/lib/chatterbot/streaming_handler.rb +0 -96
  60. data/lib/chatterbot/whitelist.rb +0 -32
  61. data/spec/blacklist_spec.rb +0 -116
  62. data/spec/db_spec.rb +0 -53
  63. data/spec/streaming_handler_spec.rb +0 -78
@@ -0,0 +1,49 @@
1
+ module Chatterbot
2
+ require 'yaml/store'
3
+
4
+ #
5
+ # wrap YAML::Store to maintain config but have a few read-only
6
+ # variables which we will never set/override
7
+ #
8
+ class ConfigManager
9
+
10
+ # list of vars that shouldn't ever be written
11
+ READ_ONLY_VARIABLES = [:consumer_key, :consumer_secret, :access_token, :access_token_secret, :log_dest]
12
+
13
+ # if true, we will never actually update the config file
14
+ attr_accessor :no_update
15
+
16
+ def initialize(dest, read_only={}, no_update=false)
17
+ @read_only = read_only
18
+ @store = YAML::Store.new(dest, true)
19
+ @no_update = no_update
20
+ end
21
+
22
+ # delete a key from the config
23
+ def delete(key)
24
+ return if @no_update == true
25
+ @store.transaction do
26
+ @store.delete(key)
27
+ end
28
+ end
29
+
30
+ # set/update a key
31
+ def []=(key, value)
32
+ return if @no_update == true
33
+ @store.transaction do
34
+ @store[key] = value
35
+ end
36
+ end
37
+
38
+ # retrieve a key
39
+ def [](key)
40
+ if READ_ONLY_VARIABLES.include?(key)
41
+ return @read_only[key]
42
+ end
43
+ @store.transaction do
44
+ @store[key]
45
+ end
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,46 @@
1
+ module Chatterbot
2
+ #
3
+ # handle Twitter DMs
4
+ module DirectMessages
5
+ #
6
+ # send a direct message
7
+ #
8
+ def direct_message(txt, user=nil)
9
+ return unless require_login
10
+
11
+ if user.nil?
12
+ user = current_user
13
+ end
14
+ client.create_direct_message(user, txt)
15
+ end
16
+
17
+ #
18
+ # check direct messages for the bot
19
+ #
20
+ def direct_messages(opts = {}, &block)
21
+ return unless require_login
22
+ debug "check for DMs since #{since_id_dm}"
23
+
24
+ #
25
+ # search twitter
26
+ #
27
+
28
+ @current_tweet = nil
29
+ client.direct_messages_received(since_id:since_id_dm, count:200).each { |s|
30
+ update_since_id_dm(s)
31
+ debug s.text
32
+ if has_safelist? && !on_safelist?(s.sender)
33
+ debug "skipping because user not on safelist"
34
+ elsif block_given? && !on_blocklist?(s.sender) && !skip_me?(s)
35
+ @current_tweet = s
36
+ yield s
37
+ end
38
+ }
39
+ @current_tweet = nil
40
+ rescue Twitter::Error::Forbidden => e
41
+ puts "sorry, looks like we're not allowed to check DMs for this account"
42
+ end
43
+
44
+ end
45
+ end
46
+
@@ -14,20 +14,17 @@ module Chatterbot
14
14
  #
15
15
  # search twitter for the specified terms, then pass any matches to
16
16
  # the block.
17
- # @param opts [Hash] options. these will be passed directly to
17
+ # @param args [Hash] options. these will be passed directly to
18
18
  # Twitter via the twitter gem. You can see the possible arguments
19
19
  # at http://www.rubydoc.info/gems/twitter/Twitter/REST/Search#search-instance_method
20
- # There is one extra argument:
21
- # @option options [Integer] :limit limit the number of tweets to
22
- # return per search
23
-
20
+ #
24
21
  # @example
25
22
  # search("chatterbot is cool!") do |tweet|
26
23
  # puts tweet.text # this is the actual tweeted text
27
24
  # reply "I agree!", tweet
28
25
  # end
29
- def search(query, opts = {}, &block)
30
- bot.search(query, opts, &block)
26
+ def search(*args, &block)
27
+ bot.register_handler(:search, args, &block)
31
28
  end
32
29
 
33
30
  #
@@ -39,8 +36,8 @@ module Chatterbot
39
36
  # puts tweet.text # this is the actual tweeted text
40
37
  # favorite tweet # i like to fave tweets
41
38
  # end
42
- def home_timeline(opts = {}, &block)
43
- bot.home_timeline(opts, &block)
39
+ def home_timeline(&block)
40
+ bot.register_handler(:home_timeline, block)
44
41
  end
45
42
 
46
43
  #
@@ -53,23 +50,64 @@ module Chatterbot
53
50
  # reply "Thanks for the mention!", tweet
54
51
  # end
55
52
  def replies(&block)
56
- bot.replies(&block)
53
+ bot.register_handler(:replies, block)
57
54
  end
58
55
 
59
- def streaming(opts = {}, &block)
60
- params = {
61
- :endpoint => :user
62
- }.merge(opts)
56
+ #
57
+ # handle direct messages sent to the bot. Each time this is called, chatterbot
58
+ # will pass any DMs since the last call to the specified block
59
+ #
60
+ # @example
61
+ # direct_messages do |dm|
62
+ # puts dm.text # this is the actual tweeted text
63
+ # direct_message "Thanks for the mention!", dm.sender
64
+ # end
65
+ def direct_messages(&block)
66
+ bot.register_handler(:direct_messages, block)
67
+ end
68
+
69
+
70
+ #
71
+ # handle notifications of bot tweets favorited by other users.
72
+ # Using this block will require usage of the Streaming API.
73
+ #
74
+ # @example
75
+ # favorited do |tweet|
76
+ # puts tweet.text # this is the actual tweeted text
77
+ # reply "@#{user.screen_name} thanks for the fave!", tweet
78
+ # end
79
+ def favorited(&block)
80
+ bot.register_handler(:favorited, block)
81
+ end
82
+
83
+ #
84
+ # handle notifications that the bot has a new follower.
85
+ # Using this block will require usage of the Streaming API.
86
+ #
87
+ # @example
88
+ # followed do |user|
89
+ # follow user
90
+ # end
91
+ def followed(&block)
92
+ bot.register_handler(:followed, block)
93
+ end
94
+
95
+ #
96
+ # handle notifications of tweets on the bot's timeline that were deleted.
97
+ # Using this block will require usage of the Streaming API.
98
+ def deleted(&block)
99
+ bot.register_handler(:deleted, block)
100
+ end
63
101
 
64
- h = StreamingHandler.new(bot, params)
65
- h.apply block
66
102
 
67
- bot.do_streaming(h)
103
+ #
104
+ # enable or disable usage of the Streaming API
105
+ #
106
+ def use_streaming(s=nil)
107
+ s = true if s.nil?
108
+ bot.streaming = s
68
109
  end
69
110
 
70
- def streaming_tweets(opts={}, &block)
71
- bot.streaming_tweets(opts, &block)
72
- end
73
111
 
74
112
  #
75
113
  # send a tweet
@@ -107,6 +145,16 @@ module Chatterbot
107
145
  bot.reply(txt, source)
108
146
  end
109
147
 
148
+ #
149
+ # send a direct message to the specified user
150
+ #
151
+ # @param [String] txt the text you want to tweet
152
+ # @param [User] user to send the DM to
153
+ def direct_message(txt, user=nil)
154
+ bot.direct_message(txt, user)
155
+ end
156
+
157
+
110
158
  #
111
159
  # handle getting/setting the profile text.
112
160
  # @param [p] p The new value for the profile. If this isn't passed in, the method will simply return the current value
@@ -121,7 +169,7 @@ module Chatterbot
121
169
 
122
170
  #
123
171
  # handle getting/setting the profile website
124
- # @param [p] p The new value for the website. If this isn't passed in, the method will simply return the current value
172
+ # @param [w] w The new value for the website. If this isn't passed in, the method will simply return the current value
125
173
  # @return profile website
126
174
  def profile_website(w=nil)
127
175
  if w.nil?
@@ -138,6 +186,7 @@ module Chatterbot
138
186
  def bot
139
187
  return @bot unless @bot.nil?
140
188
 
189
+ @bot_command = nil
141
190
 
142
191
  #
143
192
  # parse any command-line options and use them to initialize the bot
@@ -153,26 +202,24 @@ module Chatterbot
153
202
  opts.separator "Specific options:"
154
203
 
155
204
 
156
- opts.on('-d', '--db [ARG]', "Specify a DB connection URI") { |d| ENV["chatterbot_db"] = d }
157
205
  opts.on('-c', '--config [ARG]', "Specify a config file to use") { |c| ENV["chatterbot_config"] = c }
158
206
  opts.on('-t', '--test', "Run the bot without actually sending any tweets") { params[:debug_mode] = true }
159
207
  opts.on('-v', '--verbose', "verbose output to stdout") { params[:verbose] = true }
160
208
  opts.on('--dry-run', "Run the bot in test mode, and also don't update the database") { params[:debug_mode] = true ; params[:no_update] = true }
161
- opts.on('-s', '--since_id [ARG]', "Check for tweets since tweet id #[ARG]") { |s| params[:since_id] = s.to_i }
162
- opts.on('-m', '--since_id_reply [ARG]', "Check for mentions since tweet id #[ARG]") { |s| params[:since_id_reply] = s.to_i }
209
+
163
210
  opts.on('-r', '--reset', "Reset your bot to ignore old tweets") {
164
- params[:debug_mode] = true
165
- params[:reset_since_id] = true
211
+ @bot_command = :reset_since_id_counters
166
212
  }
213
+
167
214
  opts.on('--profile [ARG]', "get/set your bot's profile text") { |p|
168
- @handle_profile_text = true
169
- @profile_text = p
215
+ @bot_command = :profile_text
216
+ @bot_command_args = [ p ]
170
217
  }
218
+
171
219
  opts.on('--website [ARG]', "get/set your bot's profile URL") { |u|
172
- @handle_profile_website = true
173
- @profile_website = u
220
+ @bot_command = :profile_website
221
+ @bot_command_args = [ u ]
174
222
  }
175
-
176
223
 
177
224
  opts.on_tail("-h", "--help", "Show this message") do
178
225
  puts opts
@@ -183,25 +230,10 @@ module Chatterbot
183
230
  #:nocov:
184
231
 
185
232
  @bot = Chatterbot::Bot.new(params)
186
-
187
- if @handle_profile_text == true
188
- if !@profile_text.nil?
189
- @bot.profile_text @profile_text
190
- else
191
- puts @bot.profile_text
192
- end
193
- end
194
-
195
- if @handle_profile_website == true
196
- if !@profile_website.nil?
197
- @bot.profile_website @profile_website
198
- else
199
- puts @bot.profile_website
200
- end
201
- end
202
-
203
- if @handle_profile_website == true || @handle_profile_text == true
204
- exit
233
+ if @bot_command != nil
234
+ @bot.skip_run = true
235
+ result = @bot.send(@bot_command, *@bot_command_args)
236
+ puts result
205
237
  end
206
238
 
207
239
  @bot
@@ -235,45 +267,52 @@ module Chatterbot
235
267
  end
236
268
 
237
269
  #
238
- # specify a bot-specific blacklist of users. accepts an array, or a
270
+ # specify a bot-specific blocklist of users. accepts an array, or a
239
271
  # comma-delimited string. when called, any subsequent calls to
240
272
  # search or replies will filter out these users.
241
273
  #
242
274
  # @param [Array, String] args list of usernames
243
275
  # @example
244
- # blacklist "mean_user, private_user"
276
+ # blocklist "mean_user, private_user"
245
277
  #
246
- def blacklist(*args)
278
+ def blocklist(*args)
247
279
  list = flatten_list_of_strings(args)
248
280
 
249
281
  if list.nil? || list.empty?
250
- bot.blacklist = []
282
+ bot.blocklist = []
251
283
  else
252
- bot.blacklist += list
284
+ bot.blocklist += list
253
285
  end
254
286
  end
287
+ alias :blacklist :blocklist
255
288
 
289
+
256
290
  #
257
- # specify a bot-specific whitelist of users. accepts an array, or a
291
+ # specify a bot-specific safelist of users. accepts an array, or a
258
292
  # comma-delimited string. when called, any subsequent calls to
259
293
  # search or replies will only act upon these users.
260
294
  #
261
295
  # @param [Array, String] args list of usernames or Twitter::User objects
262
296
  # @example
263
- # whitelist "mean_user, private_user"
297
+ # safelist "mean_user, private_user"
264
298
  #
265
- def whitelist(*args)
299
+ def safelist(*args)
266
300
  list = flatten_list_of_strings(args)
267
301
 
268
302
  if list.nil? || list.empty?
269
- bot.whitelist = []
303
+ bot.safelist = []
270
304
  else
271
- bot.whitelist += list
305
+ bot.safelist += list
272
306
  end
273
307
  end
274
-
308
+ alias :whitelist :safelist
309
+
310
+ #
311
+ # specify that the bot should only reply to tweets from users that
312
+ # are followers, basically making interactions opt-in
313
+ #
275
314
  def only_interact_with_followers
276
- whitelist followers
315
+ bot.config[:only_interact_with_followers] = true
277
316
  end
278
317
 
279
318
  #
@@ -299,10 +338,55 @@ module Chatterbot
299
338
  # lifted from https://github.com/dariusk/wordfilter/blob/master/lib/badwords.json
300
339
  #
301
340
  def bad_words
302
- ["skank", "wetback", "bitch", "cunt", "dick", "douchebag", "dyke", "fag", "nigger", "tranny", "trannies",
303
- "paki", "pussy", "retard", "slut", "titt", "tits", "wop", "whore", "chink", "fatass", "shemale", "daygo",
304
- "dego", "dago", "gook", "kike", "kraut", "spic", "twat", "lesbo", "homo", "fatso", "lardass", "jap",
305
- "biatch", "tard", "gimp", "gyp", "chinaman", "chinamen", "golliwog", "crip", "raghead" ]
341
+ [
342
+ "biatch",
343
+ "bitch",
344
+ "chinaman",
345
+ "chinamen",
346
+ "chink",
347
+ "crip",
348
+ "cunt",
349
+ "dago",
350
+ "daygo",
351
+ "dego",
352
+ "dick",
353
+ "douchebag",
354
+ "dyke",
355
+ "fag",
356
+ "fatass",
357
+ "fatso",
358
+ "gash",
359
+ "gimp",
360
+ "golliwog",
361
+ "gook",
362
+ "gyp",
363
+ "homo",
364
+ "hooker",
365
+ "jap",
366
+ "kike",
367
+ "kraut",
368
+ "lardass",
369
+ "lesbo",
370
+ "negro",
371
+ "nigger",
372
+ "paki",
373
+ "pussy",
374
+ "raghead",
375
+ "retard",
376
+ "shemale",
377
+ "skank",
378
+ "slut",
379
+ "spic",
380
+ "tard",
381
+ "tits",
382
+ "titt",
383
+ "trannies",
384
+ "tranny",
385
+ "twat",
386
+ "wetback",
387
+ "whore",
388
+ "wop"
389
+ ]
306
390
  end
307
391
 
308
392
  #
@@ -338,13 +422,15 @@ module Chatterbot
338
422
  # set the consumer secret
339
423
  # @param s [String] the consumer secret
340
424
  def consumer_secret(s)
425
+ bot.deprecated "Setting consumer_secret outside of your config file is deprecated!", Kernel.caller.first
341
426
  bot.config[:consumer_secret] = s
342
427
  end
343
-
428
+
344
429
  #
345
430
  # set the consumer key
346
431
  # @param k [String] the consumer key
347
432
  def consumer_key(k)
433
+ bot.deprecated "Setting consumer_key outside of your config file is deprecated!", Kernel.caller.first
348
434
  bot.config[:consumer_key] = k
349
435
  end
350
436
 
@@ -352,14 +438,16 @@ module Chatterbot
352
438
  # set the secret
353
439
  # @param s [String] the secret
354
440
  def secret(s)
355
- bot.config[:secret] = s
441
+ bot.deprecated "Setting access_token_secret outside of your config file is deprecated!", Kernel.caller.first
442
+ bot.config[:access_token_secret] = s
356
443
  end
357
444
 
358
445
  #
359
446
  # set the token
360
447
  # @param s [String] the token
361
448
  def token(s)
362
- bot.config[:token] = s
449
+ bot.deprecated "Setting access_token outside of your config file is deprecated!", Kernel.caller.first
450
+ bot.config[:access_token] = s
363
451
  end
364
452
 
365
453
  #
@@ -377,15 +465,6 @@ module Chatterbot
377
465
  bot.update_config
378
466
  end
379
467
 
380
- #
381
- # return the bot's current database connection, if available.
382
- # handy if you need to manage data with your bot
383
- #
384
- def db
385
- bot.db
386
- end
387
-
388
-
389
468
  protected
390
469
 
391
470
  #