chatterbot 1.0.2 → 2.0.0.pre

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