chatterbot 2.0.0.pre → 2.1.0

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 (96) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +19 -0
  3. data/Gemfile +9 -17
  4. data/README.markdown +27 -34
  5. data/Rakefile +2 -18
  6. data/bin/chatterbot-register +6 -2
  7. data/chatterbot.gemspec +11 -12
  8. data/docs/Gemfile +3 -0
  9. data/docs/README.md +3 -0
  10. data/docs/_config.yml +37 -0
  11. data/docs/_includes/footer.html +3 -0
  12. data/docs/_includes/header.html +4 -0
  13. data/docs/_includes/navigation.html +23 -0
  14. data/docs/_layouts/default.html +98 -0
  15. data/docs/_layouts/page.html +11 -0
  16. data/docs/_posts/.gitkeep +0 -0
  17. data/docs/_site/Gemfile +3 -0
  18. data/docs/_site/advanced.html +465 -0
  19. data/docs/_site/configuration.html +436 -0
  20. data/docs/_site/contributing.html +414 -0
  21. data/docs/_site/css/main.css +58 -0
  22. data/docs/_site/css/syntax.css +61 -0
  23. data/docs/_site/deploying.html +451 -0
  24. data/docs/_site/examples.html +559 -0
  25. data/docs/_site/features.html +496 -0
  26. data/docs/_site/images/01-create-application.png +0 -0
  27. data/docs/_site/images/02-application-permissions.png +0 -0
  28. data/docs/_site/images/03-mobile-number.png +0 -0
  29. data/docs/_site/images/04-access-token.png +0 -0
  30. data/docs/_site/index.html +461 -0
  31. data/docs/_site/javascripts/main.js +1 -0
  32. data/docs/_site/other-tools.html +419 -0
  33. data/docs/_site/params.json +1 -0
  34. data/docs/_site/rdoc.html +409 -0
  35. data/docs/_site/setup.html +491 -0
  36. data/docs/_site/stylesheets/pygment_trac.css +68 -0
  37. data/docs/_site/stylesheets/stylesheet.css +247 -0
  38. data/docs/_site/tut.html +402 -0
  39. data/docs/_site/twitter-docs.html +409 -0
  40. data/docs/_site/walkthrough.html +447 -0
  41. data/docs/advanced.md +62 -0
  42. data/docs/basics.md +12 -0
  43. data/docs/bin/jekyll-page +109 -0
  44. data/docs/configuration.md +32 -0
  45. data/docs/contributing.md +14 -0
  46. data/docs/css/main.css +58 -0
  47. data/docs/css/syntax.css +61 -0
  48. data/docs/deploying.md +47 -0
  49. data/docs/examples.md +120 -0
  50. data/docs/features.md +88 -0
  51. data/docs/images/01-create-application.png +0 -0
  52. data/docs/images/02-application-permissions.png +0 -0
  53. data/docs/images/03-mobile-number.png +0 -0
  54. data/docs/images/04-access-token.png +0 -0
  55. data/docs/index.md +69 -0
  56. data/docs/javascripts/main.js +1 -0
  57. data/docs/other-tools.md +17 -0
  58. data/docs/params.json +1 -0
  59. data/docs/rdoc.md +6 -0
  60. data/docs/setup.md +84 -0
  61. data/docs/stylesheets/pygment_trac.css +68 -0
  62. data/docs/stylesheets/stylesheet.css +247 -0
  63. data/docs/tips.md +22 -0
  64. data/docs/tut.md +6 -0
  65. data/docs/twitter-docs.md +6 -0
  66. data/docs/walkthrough.md +46 -0
  67. data/ext/mkrf_conf.rb +28 -0
  68. data/lib/chatterbot.rb +0 -1
  69. data/lib/chatterbot/bot.rb +7 -63
  70. data/lib/chatterbot/client.rb +6 -12
  71. data/lib/chatterbot/config.rb +2 -2
  72. data/lib/chatterbot/config_manager.rb +7 -1
  73. data/lib/chatterbot/dsl.rb +20 -47
  74. data/lib/chatterbot/home_timeline.rb +1 -2
  75. data/lib/chatterbot/search.rb +26 -3
  76. data/lib/chatterbot/skeleton.rb +1 -3
  77. data/lib/chatterbot/tweet.rb +14 -3
  78. data/lib/chatterbot/ui.rb +88 -20
  79. data/lib/chatterbot/version.rb +1 -1
  80. data/spec/bot_spec.rb +2 -77
  81. data/spec/client_spec.rb +2 -6
  82. data/spec/config_manager_spec.rb +6 -5
  83. data/spec/config_spec.rb +4 -1
  84. data/spec/dsl_spec.rb +10 -35
  85. data/spec/fixtures/update_with_media.png +0 -0
  86. data/spec/search_spec.rb +40 -1
  87. data/spec/spec_helper.rb +1 -4
  88. data/spec/tweet_spec.rb +75 -38
  89. data/templates/skeleton.txt +26 -56
  90. metadata +84 -141
  91. data/.document +0 -5
  92. data/.travis.yml +0 -8
  93. data/examples/streaming_bot.rb +0 -48
  94. data/examples/tweet_logger.rb +0 -68
  95. data/lib/chatterbot/streaming.rb +0 -60
  96. data/spec/streaming_spec.rb +0 -170
data/docs/tips.md ADDED
@@ -0,0 +1,22 @@
1
+ ---
2
+ layout: page
3
+ title: "Tips and Tricks"
4
+ category: doc
5
+ published: false
6
+ ---
7
+
8
+ setting profile data
9
+
10
+ resetting since_id/since_id_reply
11
+
12
+ deleting tweets
13
+
14
+ making sure a user is following your bot
15
+
16
+ posting images
17
+
18
+ running multiple searches
19
+
20
+
21
+
22
+
data/docs/tut.md ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ layout: default
3
+ title: "Setup"
4
+ ---
5
+
6
+ setting up your bot!
@@ -0,0 +1,6 @@
1
+ ---
2
+ layout: page
3
+ title: "Twitter API docs"
4
+ category: links
5
+ link: https://dev.twitter.com/rest/public
6
+ ---
@@ -0,0 +1,46 @@
1
+ ---
2
+ layout: page
3
+ title: "Walkthrough"
4
+ category: tut
5
+ ---
6
+
7
+ Make a Twitter account
8
+ ----------------------
9
+
10
+ First thing you'll need to do is create an account for your bot on
11
+ Twitter. That's the easy part.
12
+
13
+ Run the generator
14
+ -----------------
15
+
16
+ Chatterbot comes with a script named `chatterbot-register` which will
17
+ handle two tasks -- it will authorize your bot with Twitter and it
18
+ will generate a skeleton script, which you use to implement your
19
+ actual bot.
20
+
21
+ When you run `chatterbot-register` it will walk you through the
22
+ authorization process. If you prefer, you can do this manually. If
23
+ you'd like to learn more about it, you can read the
24
+ [Authorizing your Bot](setup.html) section.
25
+
26
+ Write your bot
27
+ --------------
28
+
29
+ Chatterbot is written in ruby, but it accepts some very simple
30
+ scripting commands which can handle almost everything you might need
31
+ to do on Twitter. You can get some ideas of things you can do on the
32
+ [Examples](examples.html) page.
33
+
34
+ require 'chatterbot/dsl'
35
+ search("'surely you must be joking'") do |tweet|
36
+ reply "@#{tweet_user(tweet)} I am serious, and don't call me Shirley!", tweet
37
+ end
38
+
39
+ Or, you can create a bot object yourself, extend it if needed, and use it like so:
40
+
41
+ bot = Chatterbot::Bot.new
42
+ bot.search("'surely you must be joking'") do |tweet|
43
+ bot.reply "@#{tweet_user(tweet)} I am serious, and don't call me Shirley!", tweet
44
+ end
45
+
46
+ That's it!
data/ext/mkrf_conf.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems/dependency_installer'
2
+
3
+ #
4
+ # limit activesupport version if not on ruby 2.2 or higher
5
+ # @see https://www.tiredpixel.com/2014/01/05/curses-conditional-ruby-gem-installation-within-a-gemspec/
6
+ #
7
+
8
+ di = Gem::DependencyInstaller.new
9
+
10
+ begin
11
+ if RUBY_VERSION >= '2.2'
12
+ di.install "activesupport", "~> 4.2.8"
13
+ else
14
+ di.install "activesupport", "< 5.0.0"
15
+ end
16
+ rescue => e
17
+ warn "#{$0}: #{e}"
18
+
19
+ exit!
20
+ end
21
+
22
+
23
+ # https://en.wikibooks.org/wiki/Ruby_Programming/RubyGems#How_to_install_different_versions_of_gems_depending_on_which_version_of_ruby_the_installee_is_using
24
+
25
+ # create dummy rakefile to indicate success
26
+ f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w")
27
+ f.write("task :default\n")
28
+ f.close
data/lib/chatterbot.rb CHANGED
@@ -45,7 +45,6 @@ module Chatterbot
45
45
  require "chatterbot/followers"
46
46
  require "chatterbot/helpers"
47
47
  require "chatterbot/utils"
48
- require "chatterbot/streaming"
49
48
 
50
49
  require "chatterbot/bot"
51
50
  end
@@ -5,7 +5,6 @@ module Chatterbot
5
5
  # primary Bot object, includes all the other modules
6
6
  class Bot
7
7
  include Utils
8
- include Streaming
9
8
  include Blocklist
10
9
  include Safelist
11
10
  include Config
@@ -26,9 +25,6 @@ module Chatterbot
26
25
  # handlers that can use the REST API
27
26
  HANDLER_CALLS = [:direct_messages, :home_timeline, :replies, :search]
28
27
 
29
- # handlers that require the Streaming API
30
- STREAMING_ONLY_HANDLERS = [:favorited, :followed, :deleted]
31
-
32
28
  #
33
29
  # Create a new bot. No options for now.
34
30
  def initialize(params={})
@@ -46,7 +42,7 @@ module Chatterbot
46
42
 
47
43
  at_exit do
48
44
  if !@handlers.empty? && @run_count <= 0 && skip_run? != true
49
- run_or_stream
45
+ run!
50
46
  end
51
47
 
52
48
  raise $! if $!
@@ -54,55 +50,10 @@ module Chatterbot
54
50
  @handlers = {}
55
51
  end
56
52
 
57
- #
58
- # determine the right API to use and run the bot
59
- #
60
- def run_or_stream
61
- @run_count += 1
62
- if streaming?
63
- stream!
64
- else
65
- run!
66
- end
53
+ def screen_name
54
+ @screen_name ||= client.settings.screen_name
67
55
  end
68
56
 
69
- #
70
- # run the bot with the Streaming API
71
- #
72
- def stream!
73
- before_run
74
-
75
- #
76
- # figure out how we want to call streaming client
77
- #
78
- if @handlers[:search]
79
- method = :filter
80
- args = streamify_search_options(@handlers[:search].opts)
81
- else
82
- method = :user
83
- args = nil
84
- end
85
-
86
- streaming_client.send(method, args) do |object|
87
- handle_streaming_object(object)
88
- end
89
- after_run
90
- end
91
-
92
- #
93
- # the REST API and Streaming API have a slightly different format.
94
- # tweak our search handler to switch from REST to Streaming
95
- #
96
- def streamify_search_options(opts)
97
- if opts.is_a?(String)
98
- { track: opts }
99
- elsif opts.is_a?(Array)
100
- { track: opts.join(", ") }
101
- else
102
- opts
103
- end
104
- end
105
-
106
57
  #
107
58
  # run the bot with the REST API
108
59
  #
@@ -111,7 +62,6 @@ module Chatterbot
111
62
 
112
63
  HANDLER_CALLS.each { |c|
113
64
  if (h = @handlers[c])
114
- puts "calling #{c} #{h.opts.inspect}"
115
65
  send(c, *(h.opts)) do |obj|
116
66
  h.call(obj)
117
67
  end
@@ -131,23 +81,17 @@ module Chatterbot
131
81
  end
132
82
 
133
83
  def call_api_immediately?
134
- streaming?
84
+ true
135
85
  end
136
86
 
137
87
  def register_handler(method, opts = nil, &block)
138
88
  # @todo raise error if method already defined
139
89
  @handlers[method] = Handler.new(opts, &block)
140
90
 
141
- if STREAMING_ONLY_HANDLERS.include?(method)
142
- puts "Forcing usage of Streaming API to support #{method} calls"
143
- self.streaming = true
144
- elsif call_api_immediately?
145
- h = @handlers[method]
146
- send(method, *(h.opts)) do |obj|
147
- h.call(obj)
148
- end
91
+ h = @handlers[method]
92
+ self.send(method, *(h.opts)) do |obj|
93
+ h.call(obj)
149
94
  end
150
-
151
95
  end
152
96
  end
153
97
  end
@@ -6,7 +6,7 @@ module Chatterbot
6
6
  # routines for connecting to Twitter and validating the bot
7
7
  #
8
8
  module Client
9
- attr_accessor :screen_name, :client, :streaming_client
9
+ attr_accessor :screen_name, :client
10
10
 
11
11
  #
12
12
  # the main interface to the Twitter API
@@ -14,14 +14,7 @@ module Chatterbot
14
14
  def client
15
15
  @client ||= Twitter::REST::Client.new(client_params)
16
16
  end
17
-
18
- #
19
- # interace to the Streaming API
20
- #
21
- def streaming_client
22
- @streaming_client ||= Twitter::Streaming::Client.new(client_params)
23
- end
24
-
17
+
25
18
  #
26
19
  # return the currently authenticated User
27
20
  #
@@ -171,6 +164,7 @@ module Chatterbot
171
164
  #
172
165
  def get_screen_name(t = @access_token)
173
166
  return unless @screen_name.nil?
167
+ return if t.nil?
174
168
 
175
169
  oauth_response = t.get('/1.1/account/verify_credentials.json')
176
170
  @screen_name = JSON.parse(oauth_response.body)["screen_name"]
@@ -198,10 +192,10 @@ module Chatterbot
198
192
  @access_token = request_token.get_access_token(:oauth_verifier => pin.chomp)
199
193
  get_screen_name
200
194
 
201
- self.config[:token] = @access_token.token
202
- self.config[:secret] = @access_token.secret
195
+ self.config[:access_token] = @access_token.token
196
+ self.config[:access_token_secret] = @access_token.secret
203
197
 
204
- update_config unless ! do_update_config
198
+ #update_config unless ! do_update_config
205
199
  reset_client
206
200
 
207
201
  rescue OAuth::Unauthorized => e
@@ -55,7 +55,6 @@ module Chatterbot
55
55
 
56
56
  attr_boolean :debug_mode, false
57
57
  attr_boolean :verbose, false
58
- attr_boolean :streaming, false
59
58
  attr_boolean :skip_run, false
60
59
  attr_boolean :only_interact_with_followers, false
61
60
 
@@ -93,6 +92,7 @@ module Chatterbot
93
92
  config[:consumer_key].nil? || config[:consumer_secret].nil?
94
93
  end
95
94
 
95
+
96
96
  #
97
97
  # has this script validated with Twitter OAuth?
98
98
  def needs_auth_token?
@@ -211,7 +211,7 @@ module Chatterbot
211
211
  :consumer_key => ENV["chatterbot_consumer_key"],
212
212
  :consumer_secret => ENV["chatterbot_consumer_secret"],
213
213
  :access_token => ENV["chatterbot_access_token"],
214
- :access_token_secret => ENV["chatterbot_access_secret"]
214
+ :access_token_secret => ENV["chatterbot_access_secret"] || ENV["chatterbot_access_token_secret"]
215
215
  }.delete_if { |k, v| v.nil? }.merge(slurp_file(config_file) || {})
216
216
  end
217
217
 
@@ -27,6 +27,12 @@ module Chatterbot
27
27
  end
28
28
  end
29
29
 
30
+ def to_h
31
+ @store.transaction do
32
+ Hash[@store.roots.map { |k| [k, @store[k]] }]
33
+ end
34
+ end
35
+
30
36
  # set/update a key
31
37
  def []=(key, value)
32
38
  return if @no_update == true
@@ -37,7 +43,7 @@ module Chatterbot
37
43
 
38
44
  # retrieve a key
39
45
  def [](key)
40
- if READ_ONLY_VARIABLES.include?(key)
46
+ if READ_ONLY_VARIABLES.include?(key) && @read_only[key]
41
47
  return @read_only[key]
42
48
  end
43
49
  @store.transaction do
@@ -14,6 +14,10 @@ module Chatterbot
14
14
  #
15
15
  # search twitter for the specified terms, then pass any matches to
16
16
  # the block.
17
+ # NOTE: by default, search terms are wrapped in quotes so the
18
+ # Twitter API will return tweets that include your exact query.
19
+ # You can disable this by passing exact:false as an option
20
+ #
17
21
  # @param args [Hash] options. these will be passed directly to
18
22
  # Twitter via the twitter gem. You can see the possible arguments
19
23
  # at http://www.rubydoc.info/gems/twitter/Twitter/REST/Search#search-instance_method
@@ -66,55 +70,17 @@ module Chatterbot
66
70
  bot.register_handler(:direct_messages, block)
67
71
  end
68
72
 
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
101
-
102
-
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
109
- end
110
-
111
-
112
73
  #
113
74
  # send a tweet
114
75
  #
115
76
  # @param [String] txt the text you want to tweet
116
- # @param [Hash] params opts for the tweet
117
- # @see http://rdoc.info/gems/twitter/Twitter/API#update-instance_method
77
+ # @param [Hash] params options for the tweet. You can get an idea
78
+ # of possible values you can send here from the underlying Twitter
79
+ # gem docs: http://rdoc.info/gems/twitter/Twitter/API#update-instance_method
80
+ # @option params [String,File] :media Optional file object to send
81
+ # with the tweet. Must be an image or video that will be accepted by
82
+ # Twitter. You can pass a File object, or the path to a file
83
+ # @see http://rdoc.info/gems/twitter/Twitter/API#update-instance_method
118
84
  # @param [Tweet] original if this is a reply, the original tweet. this will
119
85
  # be used for variable substitution, and for logging
120
86
  def tweet(txt, params = {}, original = nil)
@@ -141,8 +107,15 @@ module Chatterbot
141
107
  #
142
108
  # @param [String] txt the text you want to tweet
143
109
  # @param [Tweet] source the original tweet you are replying to
144
- def reply(txt, source)
145
- bot.reply(txt, source)
110
+ # @param [Hash] params options for the tweet. You can get an idea
111
+ # of possible values you can send here from the underlying Twitter
112
+ # gem docs: http://rdoc.info/gems/twitter/Twitter/API#update-instance_method
113
+ # @option params [String,File] :media Optional file object to send with the
114
+ # tweet. Must be an image or video that will be accepted by
115
+ # Twitter. You can pass a File object, or the path to a file
116
+ # @see http://rdoc.info/gems/twitter/Twitter/API#update-instance_method
117
+ def reply(txt, source, params={})
118
+ bot.reply(txt, source, params)
146
119
  end
147
120
 
148
121
  #
@@ -7,8 +7,7 @@ module Chatterbot
7
7
  # handle the bots timeline
8
8
  def home_timeline(*args, &block)
9
9
  return unless require_login
10
-
11
- debug "check for home_timeline tweets since #{since_id}"
10
+ debug "check for home_timeline tweets since #{since_id_home_timeline}"
12
11
 
13
12
  opts = {
14
13
  :since_id => since_id_home_timeline,
@@ -24,25 +24,47 @@ module Chatterbot
24
24
  @skip_retweets = false
25
25
  end
26
26
 
27
-
27
+
28
28
  #
29
29
  # check if this is a retweet that we want to skip
30
30
  #
31
31
  def skippable_retweet?(t)
32
32
  @skip_retweets && t.retweeted_status?
33
33
  end
34
+
35
+ def wrap_search_query(q)
36
+ if q =~ / /
37
+ ['"', q.gsub(/^"/, '').gsub(/"$/, ''), '"'].join("")
38
+ else
39
+ q
40
+ end
41
+ end
34
42
 
35
43
  # internal search code
36
44
  def search(queries, opts = {}, &block)
37
45
  debug "check for tweets since #{since_id}"
38
46
 
39
47
  max_tweets = opts.delete(:limit) || MAX_SEARCH_TWEETS
48
+ exact_match = if opts.key?(:exact)
49
+ opts.delete(:exact)
50
+ else
51
+ true
52
+ end
53
+
40
54
 
41
55
  if queries.is_a?(String)
42
- queries = [queries]
56
+ queries = [
57
+ queries
58
+ ]
43
59
  end
44
60
 
45
- query = queries.join(" OR ")
61
+ query = queries.map { |q|
62
+ if exact_match == true
63
+ q = wrap_search_query(q)
64
+ end
65
+
66
+ q
67
+ }.join(" OR ")
46
68
 
47
69
  #
48
70
  # search twitter
@@ -50,6 +72,7 @@ module Chatterbot
50
72
 
51
73
  debug "search: #{query} #{default_opts.merge(opts)}"
52
74
  @current_tweet = nil
75
+
53
76
  client.search( query, default_opts.merge(opts) ).take(max_tweets).each { |s|
54
77
  update_since_id(s)
55
78
  debug s.text