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,61 @@
1
+ module Chatterbot
2
+
3
+ #
4
+ # methods for preventing the bot from spamming people who don't want to hear from it
5
+ module Blocklist
6
+ attr_accessor :exclude, :blocklist
7
+
8
+ alias :blacklist :blocklist
9
+
10
+ # return a list of text strings which we will check for in incoming tweets.
11
+ # If the text is listed, we won't use this tweet
12
+ def exclude
13
+ @exclude || []
14
+ end
15
+
16
+ # A list of Twitter users that don't want to hear from the bot.
17
+ def blocklist
18
+ @blocklist || []
19
+ end
20
+ def blocklist=(b)
21
+ @blocklist = b
22
+ end
23
+
24
+ #
25
+ # Based on the text of this tweet, should it be skipped?
26
+ def skip_me?(s)
27
+ search = s.respond_to?(:text) ? s.text : s
28
+ exclude.detect { |e| search.downcase.include?(e) } != nil
29
+ end
30
+
31
+ def interact_with_user?(t)
32
+ return true unless only_interact_with_followers?
33
+ u = t.respond_to?(:user) ? t.user : t
34
+ client.friendship?(u, authenticated_user)
35
+ end
36
+
37
+ def valid_tweet?(object)
38
+ if has_safelist? && ! on_safelist?(object)
39
+ debug "skipping because user not on safelist"
40
+ return false
41
+ end
42
+
43
+ !skippable_retweet?(object) && ! on_blocklist?(object) && ! skip_me?(object) && interact_with_user?(object)
44
+ end
45
+
46
+ #
47
+ # Is this tweet from a user on our blocklist?
48
+ def on_blocklist?(s)
49
+ search = if s.is_a?(Twitter::User)
50
+ s.name
51
+ elsif s.respond_to?(:user) && !s.is_a?(Twitter::NullObject)
52
+ from_user(s)
53
+ else
54
+ s
55
+ end.downcase
56
+
57
+ blocklist.any? { |b| search.include?(b.downcase) }
58
+ end
59
+
60
+ end
61
+ end
@@ -1,15 +1,17 @@
1
1
  module Chatterbot
2
+ require 'chatterbot/handler'
2
3
 
3
4
  #
4
5
  # primary Bot object, includes all the other modules
5
6
  class Bot
6
7
  include Utils
7
- include Blacklist
8
- include Whitelist
9
8
  include Streaming
9
+ include Blocklist
10
+ include Safelist
10
11
  include Config
11
12
  include Logging
12
13
  include Search
14
+ include DirectMessages
13
15
  include HomeTimeline
14
16
  include Tweet
15
17
  include Profile
@@ -19,9 +21,14 @@ module Chatterbot
19
21
  include Followers
20
22
  include UI
21
23
  include Client
22
- include DB
23
24
  include Helpers
24
25
 
26
+ # handlers that can use the REST API
27
+ HANDLER_CALLS = [:direct_messages, :home_timeline, :replies, :search]
28
+
29
+ # handlers that require the Streaming API
30
+ STREAMING_ONLY_HANDLERS = [:favorited, :followed, :deleted]
31
+
25
32
  #
26
33
  # Create a new bot. No options for now.
27
34
  def initialize(params={})
@@ -30,19 +37,117 @@ module Chatterbot
30
37
  end
31
38
 
32
39
  @config = load_config(params)
40
+ @run_count = 0
41
+
42
+ #
43
+ # check for command line options
44
+ # handle resets, etc
45
+ #
46
+
47
+ at_exit do
48
+ if !@handlers.empty? && @run_count <= 0 && skip_run? != true
49
+ run_or_stream
50
+ end
51
+
52
+ raise $! if $!
53
+ end
54
+ @handlers = {}
55
+ end
33
56
 
34
- if reset_bot?
35
- reset_since_id
36
- update_config
37
- puts "Reset to #{@config[:since_id]}"
38
- exit
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!
39
64
  else
40
- # update config when we exit
41
- at_exit do
42
- raise $! if $!
43
- update_config_at_exit
44
- end
65
+ run!
66
+ end
67
+ end
68
+
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
+ #
107
+ # run the bot with the REST API
108
+ #
109
+ def run!
110
+ before_run
111
+
112
+ HANDLER_CALLS.each { |c|
113
+ if (h = @handlers[c])
114
+ puts "calling #{c} #{h.opts.inspect}"
115
+ send(c, *(h.opts)) do |obj|
116
+ h.call(obj)
117
+ end
118
+ end
119
+ }
120
+
121
+ after_run
122
+ end
123
+
124
+
125
+ def before_run
126
+ @run_count = @run_count + 1
127
+ end
128
+
129
+ def after_run
130
+
131
+ end
132
+
133
+ def call_api_immediately?
134
+ streaming?
135
+ end
136
+
137
+ def register_handler(method, opts = nil, &block)
138
+ # @todo raise error if method already defined
139
+ @handlers[method] = Handler.new(opts, &block)
140
+
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
45
149
  end
150
+
46
151
  end
47
152
  end
48
153
  end
@@ -6,32 +6,44 @@ 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, :search_client
9
+ attr_accessor :screen_name, :client, :streaming_client
10
10
 
11
11
  #
12
12
  # the main interface to the Twitter API
13
13
  #
14
14
  def client
15
- @client ||= Twitter::REST::Client.new(
16
- :consumer_key => client_params[:consumer_key],
17
- :consumer_secret => client_params[:consumer_secret],
18
- :access_token => client_params[:token],
19
- :access_token_secret => client_params[:secret]
20
- )
15
+ @client ||= Twitter::REST::Client.new(client_params)
21
16
  end
22
17
 
18
+ #
19
+ # interace to the Streaming API
20
+ #
23
21
  def streaming_client
24
- @streaming_client ||= Twitter::Streaming::Client.new(
25
- :consumer_key => client_params[:consumer_key],
26
- :consumer_secret => client_params[:consumer_secret],
27
- :access_token => client_params[:token],
28
- :access_token_secret => client_params[:secret]
29
- )
22
+ @streaming_client ||= Twitter::Streaming::Client.new(client_params)
23
+ end
24
+
25
+ #
26
+ # return the currently authenticated User
27
+ #
28
+ def authenticated_user
29
+ @user ||= client.user
30
30
  end
31
31
 
32
+ #
33
+ # reset a few tweet_id trackers
34
+ #
32
35
  def reset!
33
- config[:since_id] = 0
34
- config[:since_id_reply] = 0
36
+ config[:since_id] = 1
37
+ config[:since_id_reply] = 1
38
+ end
39
+
40
+ # reset all since_id counters
41
+ def reset_since_id_counters
42
+ reset!
43
+ reset_since_id
44
+ reset_since_id_reply
45
+ reset_since_id_home_timeline
46
+ reset_since_id_dm
35
47
  end
36
48
 
37
49
  #
@@ -40,8 +52,10 @@ module Chatterbot
40
52
  # the max_id
41
53
  #
42
54
  def reset_since_id
43
- config[:tmp_since_id] = 0
44
- result = client.search("a")
55
+ config[:since_id] = 1
56
+ # do a search of recent tweets with the letter 'a' in them to
57
+ # get a rough max tweet id
58
+ result = client.search("a", since:Time.now - 10).max_by(&:id)
45
59
  update_since_id(result)
46
60
  end
47
61
 
@@ -49,11 +63,28 @@ module Chatterbot
49
63
  # resets the since_id_reply for this bot to the last mention received
50
64
  #
51
65
  def reset_since_id_reply
52
- config[:tmp_since_id_reply] = 0
66
+ config[:since_id_reply] = 0
53
67
  result = client.mentions_timeline.max_by(&:id)
54
68
  update_since_id_reply(result)
55
69
  end
56
-
70
+
71
+ #
72
+ # resets the home_timeline_id_reply for this bot to the last tweet
73
+ # on the timeline
74
+ #
75
+ def reset_since_id_home_timeline
76
+ config[:since_id_reply] = 0
77
+ result = client.home_timeline.max_by(&:id)
78
+ update_since_id_home_timeline(result)
79
+ end
80
+
81
+ # reset to the last DM received
82
+ def reset_since_id_dm
83
+ config[:since_id_dm] = 0
84
+ result = client.direct_messages_received.max_by(&:id)
85
+ update_since_id_dm(result)
86
+ end
87
+
57
88
 
58
89
  #
59
90
  # the URL we should use for api calls
@@ -130,6 +161,7 @@ module Chatterbot
130
161
  "#{base_url}#{request.path}?#{params}"
131
162
  end
132
163
 
164
+ # grab a OAuth request token
133
165
  def request_token
134
166
  @request_token ||= consumer.get_request_token
135
167
  end
@@ -157,7 +189,7 @@ module Chatterbot
157
189
  end
158
190
 
159
191
  if needs_auth_token?
160
- pin = get_oauth_verifier #(request_token)
192
+ pin = get_oauth_verifier
161
193
  return false if pin.nil?
162
194
 
163
195
 
@@ -1,82 +1,115 @@
1
1
  module Chatterbot
2
-
2
+
3
3
  #
4
4
  # routines for storing config information for the bot
5
5
  module Config
6
6
  attr_accessor :config
7
7
 
8
- MAX_TWEET_ID = 9223372036854775807
9
- COMMAND_LINE_VARIABLES = [:debug_mode, :no_update, :verbose, :reset_since_id]
10
-
11
8
  #
12
9
  # the entire config for the bot, loaded from YAML files and the DB if applicable
13
10
  def config
14
11
  @config ||= load_config
15
12
  end
16
13
 
17
- #
18
- # has the config been loaded yet?
19
- def has_config?
20
- ! @config.nil?
21
- end
14
+ class << self
15
+ #
16
+ # simple boolean attribute generator. define the attribute and a
17
+ # default value and you get a setter and predicate method
18
+ #
19
+ # @param [Symbol] key the key for the variable
20
+ # @param [Boolean] default default value
21
+ def attr_boolean(key, default=false)
22
+ class_eval <<-EVAL
23
+ attr_writer :#{key.to_s}
24
+
25
+ def #{key.to_s}?
26
+ (@#{key.to_s} == true) || #{default}
27
+ end
28
+ EVAL
29
+ end
22
30
 
23
- #
24
- # should we log tweets to the database?
25
- def log_tweets?
26
- config.has_key?(:db_uri)
31
+ #
32
+ # generate a set of methods to manage checks around the
33
+ # assortment of since_id values we use to track most recent data
34
+ # retrieve from twitter
35
+ #
36
+ # @param [Symbol] key the key for the variable
37
+ def attr_since_id(key = nil)
38
+ attr_name = key.nil? ? "since_id" : ["since_id", key.to_s].join("_")
39
+ class_eval <<-EVAL
40
+ def #{attr_name}=(x)
41
+ config[:#{attr_name}] = x
42
+ end
43
+ def #{attr_name}
44
+ config[:#{attr_name}] || 1
45
+ end
46
+
47
+ def update_#{attr_name}(input)
48
+ max = max_id_from(input)
49
+ config[:#{attr_name}] = [config[:#{attr_name}].to_i, max.to_i].max
50
+ end
51
+ EVAL
52
+ end
27
53
  end
28
54
 
29
- #
30
- # Check to see if Sequel was loaded successfully. If not, we won't make any DB calls
31
- def has_sequel?
32
- ! defined?(Sequel).nil?
33
- end
34
55
 
56
+ attr_boolean :debug_mode, false
57
+ attr_boolean :verbose, false
58
+ attr_boolean :streaming, false
59
+ attr_boolean :skip_run, false
60
+ attr_boolean :only_interact_with_followers, false
61
+
62
+ attr_since_id
63
+ attr_since_id :home_timeline
64
+ attr_since_id :reply
65
+ attr_since_id :dm
66
+
35
67
  #
36
- # do we have a DB connection string?
37
- def has_db?
38
- has_sequel? && config.has_key?(:db_uri)
68
+ # should we update our config values?
69
+ # @param [Boolean] val true/false
70
+ def no_update=(val)
71
+ config.no_update = val
39
72
  end
40
73
 
41
- def debug_mode=(d)
42
- config[:debug_mode] = d
74
+ # should we update our config values?
75
+ def no_update?
76
+ config.no_update || false
43
77
  end
44
-
45
- def no_update=(d)
46
- config[:no_update] = d
78
+
79
+ #
80
+ # return a hash of the params we need to connect to the Twitter API
81
+ def client_params
82
+ {
83
+ :consumer_key => config[:consumer_key],
84
+ :consumer_secret => config[:consumer_secret],
85
+ :access_token => config[:access_token],
86
+ :access_token_secret => config[:access_token_secret]
87
+ }
47
88
  end
48
89
 
49
90
  #
50
- # should we reset the since_id for this bot?
51
- #
52
- def reset_bot?
53
- config[:reset_since_id] || false
91
+ # do we have an API key specified?
92
+ def needs_api_key?
93
+ config[:consumer_key].nil? || config[:consumer_secret].nil?
54
94
  end
55
-
95
+
56
96
  #
57
- # are we in debug mode?
58
- def debug_mode?
59
- config[:debug_mode] || false
97
+ # has this script validated with Twitter OAuth?
98
+ def needs_auth_token?
99
+ config[:access_token].nil?
60
100
  end
61
101
 
102
+
62
103
  #
63
104
  # Should we run any config updates?
64
105
  def update_config?
65
- config.has_key?(:no_update) ? ! config[:no_update] : true
106
+ !no_update?
66
107
  end
67
108
 
68
109
  #
69
110
  # should we write to a log file?
70
111
  def logging?
71
- has_config? && config.has_key?(:log_dest)
72
- end
73
-
74
- def verbose=(v)
75
- config[:verbose] = v
76
- end
77
-
78
- def verbose?
79
- config[:verbose] || false
112
+ config[:log_dest] != nil
80
113
  end
81
114
 
82
115
  #
@@ -86,109 +119,23 @@ module Chatterbot
86
119
  end
87
120
 
88
121
  #
89
- # store since_id to a different key so that it doesn't actually
90
- # get updated until the bot is done running
91
- def since_id=(x)
92
- config[:tmp_since_id] = x
93
- end
94
-
95
- #
96
- # return the ID of the most recent tweet pulled up in searches
97
- def since_id
98
- config[:since_id] || 1
99
- end
100
-
122
+ # given an array or object, return the highest id we can find
123
+ # @param [Enumerable] s the array to check
101
124
  #
102
- # store since_id_reply to a different key so that it doesn't actually
103
- # get updated until the bot is done running
104
- def since_id_reply=(x)
105
- config[:tmp_since_id_reply] = x
106
- end
107
-
108
- #
109
- # return the ID of the most recent tweet pulled up in mentions or since_id if since_id_reply is nil
110
- def since_id_reply
111
- config[:since_id_reply] || since_id
112
- end
113
-
114
- #
115
- # write out our config file
116
- def update_config
117
- return if ! update_config?
118
-
119
- # don't update flat file if we can store to the DB instead
120
- if has_db?
121
- debug "storing config to database -- you don't need local file anymore"
122
- store_database_config
123
- else
124
- store_local_config
125
- end
126
- end
127
-
128
- def update_config_at_exit
129
- update_config
130
- end
131
-
132
125
  def max_id_from(s)
133
- # don't use max_id if it's this ridiculous number
134
- # @see https://dev.twitter.com/issues/1300
135
- sorted = s.reject { |t| !t || t.id == MAX_TWEET_ID }.max { |a, b| a.id <=> b.id }
136
- sorted && sorted.id
137
- end
138
-
139
- #
140
- # update the since_id_reply with the id of the given tweet,
141
- # unless it is lower thant what we have already
142
- #
143
- def update_since_id_reply(tweet)
144
- return if tweet.nil? or tweet.class != Twitter::Tweet || tweet.id == MAX_TWEET_ID
145
-
146
- tmp_id = tweet.id
147
-
148
- config[:tmp_since_id_reply] = [config[:tmp_since_id_reply].to_i, tmp_id].max
149
- end
150
-
151
- #
152
- # update the since_id with either the highest ID of the specified
153
- # tweets, unless it is lower than what we have already
154
- def update_since_id(search)
155
- return if search.nil?
126
+ if ! s.respond_to?(:max)
127
+ if s.respond_to?(:id)
128
+ return s.id
129
+ else
130
+ return s
131
+ end
132
+ end
156
133
 
157
- tmp_id = if search.is_a?(Twitter::SearchResults)
158
- search.attrs[:search_metadata][:max_id]
159
- elsif search.respond_to?(:max)
160
- max_id_from(search)
161
- elsif search.is_a?(Twitter::Tweet)
162
- search.id
163
- else
164
- search
165
- end.to_i
166
134
 
167
- config[:tmp_since_id] = [config[:tmp_since_id].to_i, tmp_id].max
168
- end
169
-
170
- #
171
- # return a hash of the params we need to connect to the Twitter API
172
- def client_params
173
- {
174
- :consumer_key => config[:consumer_key],
175
- :consumer_secret => config[:consumer_secret],
176
- :token => config[:token].nil? ? nil : config[:token],
177
- :secret => config[:secret].nil? ? nil : config[:secret]
178
- }
179
- end
180
-
181
- #
182
- # do we have an API key specified?
183
- def needs_api_key?
184
- config[:consumer_key].nil? || config[:consumer_secret].nil?
135
+ sorted = s.max { |a, b| a.id.to_i <=> b.id.to_i }
136
+ sorted && sorted.id
185
137
  end
186
138
 
187
- #
188
- # has this script validated with Twitter OAuth?
189
- def needs_auth_token?
190
- config[:token].nil?
191
- end
192
139
 
193
140
  #
194
141
  # determine if we're being called by one of our internal scripts
@@ -263,87 +210,17 @@ module Chatterbot
263
210
  {
264
211
  :consumer_key => ENV["chatterbot_consumer_key"],
265
212
  :consumer_secret => ENV["chatterbot_consumer_secret"],
266
- :token => ENV["chatterbot_token"],
267
- :secret => ENV["chatterbot_secret"]
213
+ :access_token => ENV["chatterbot_access_token"],
214
+ :access_token_secret => ENV["chatterbot_access_secret"]
268
215
  }.delete_if { |k, v| v.nil? }.merge(slurp_file(config_file) || {})
269
216
  end
270
-
271
- #
272
- # load the config settings from the db, if possible
273
- def db_config
274
- return {} if db.nil?
275
- db[:config][:id => botname]
276
- end
277
217
 
278
- #
279
- # figure out what we should save to the local config file. we don't
280
- # save anything that exists in the global config, unless it's been modified
281
- # for this particular bot.
282
- def config_to_save
283
- # remove keys that are duped in the global config
284
- tmp = config.delete_if { |k, v| global_config.has_key?(k) && global_config[k] == config[k] }
285
-
286
- # let's not store these, they're just command-line options
287
- COMMAND_LINE_VARIABLES.each { |k|
288
- tmp.delete(k)
289
- }
290
-
291
- # update the since_id now
292
- tmp[:since_id] = tmp.delete(:tmp_since_id) unless ! tmp.has_key?(:tmp_since_id)
293
- tmp[:since_id_reply] = tmp.delete(:tmp_since_id_reply) unless ! tmp.has_key?(:tmp_since_id_reply)
294
-
295
- tmp
296
- end
297
218
 
298
219
  #
299
220
  # load in the config from the assortment of places it can be specified.
300
221
  def load_config(params={})
301
- # load the flat-files first
302
- @config = global_config.merge(bot_config)
303
- @config[:db_uri] ||= ENV["chatterbot_db"] unless ENV["chatterbot_db"].nil?
304
-
305
- # if we have a key to load from the DB, do that now
306
- if @config.has_key?(:db_uri) && @config[:db_uri]
307
- tmp = db_config
308
- @config = @config.merge(tmp) unless tmp.nil?
309
- end
310
- @config.merge(params)
311
- end
312
-
313
- #
314
- # write out the config file for this bot
315
- def store_local_config
316
- File.open(config_file, 'w') { |f| YAML.dump(config_to_save, f) }
222
+ read_only_data = global_config.merge(bot_config).merge(params)
223
+ @config = Chatterbot::ConfigManager.new(config_file, read_only_data)
317
224
  end
318
-
319
- #
320
- # store config settings in the database, if possible
321
- def store_database_config
322
- return false if db.nil?
323
-
324
- configs = db[:config]
325
- data = {
326
- :since_id => config.has_key?(:tmp_since_id) ? config[:tmp_since_id] : config[:since_id],
327
- :since_id_reply => config.has_key?(:tmp_since_id_reply) ? config[:tmp_since_id_reply] : config[:since_id_reply],
328
- :token => config[:token],
329
- :secret => config[:secret],
330
- :consumer_secret => config[:consumer_secret],
331
- :consumer_key => config[:consumer_key],
332
- :updated_at => Time.now #:NOW.sql_function
333
- }
334
-
335
- row = configs.filter('id = ?', botname)
336
-
337
- if row.count > 0
338
- row.update(data)
339
- else
340
- data[:id] = botname
341
- data[:created_at] = Time.now #:NOW.sql_function
342
- configs.insert data
343
- end
344
-
345
- true
346
- end
347
-
348
225
  end
349
226
  end