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
@@ -13,13 +13,11 @@ module Chatterbot
13
13
  path = File.join(Chatterbot.libdir, "..", "templates", "skeleton.txt")
14
14
  src = File.read(path)
15
15
 
16
- opts = bot.config.merge({
16
+ opts = bot.config.to_h.merge({
17
17
  :name => bot.botname,
18
18
  :timestamp => Time.now
19
19
  })
20
20
 
21
- puts opts.inspect
22
-
23
21
  src % opts
24
22
  end
25
23
  end
@@ -13,7 +13,16 @@ module Chatterbot
13
13
  debug "I'm in debug mode, otherwise I would tweet: #{txt}"
14
14
  else
15
15
  debug txt
16
- client.update txt, params
16
+ if params.has_key?(:media)
17
+ file = params.delete(:media)
18
+ if ! file.is_a?(File)
19
+ file = File.new(file)
20
+ end
21
+
22
+ client.update_with_media txt, file, params
23
+ else
24
+ client.update txt, params
25
+ end
17
26
  end
18
27
  rescue Twitter::Error::Forbidden => e
19
28
  #:nocov:
@@ -22,10 +31,12 @@ module Chatterbot
22
31
  #:nocov:
23
32
  end
24
33
 
34
+
25
35
  # reply to a tweet
26
- def reply(txt, source)
36
+ def reply(txt, source, params = {})
27
37
  debug txt
28
- tweet txt, {:in_reply_to_status_id => source[:id]}, source
38
+ params = {:in_reply_to_status_id => source.id}.merge(params)
39
+ tweet txt, params, source
29
40
  end
30
41
  end
31
42
  end
data/lib/chatterbot/ui.rb CHANGED
@@ -5,7 +5,7 @@ module Chatterbot
5
5
  #
6
6
  module UI
7
7
  # Where to send users who need to get API keys
8
- API_SIGNUP_URL = "https://twitter.com/apps/new"
8
+ API_SIGNUP_URL = "https://apps.twitter.com/app/new"
9
9
 
10
10
 
11
11
  #:nocov:
@@ -13,7 +13,6 @@ module Chatterbot
13
13
  puts str.colorize(:red)
14
14
  end
15
15
 
16
- #:nocov:
17
16
  def green(str)
18
17
  puts str.colorize(:green)
19
18
  end
@@ -52,27 +51,35 @@ module Chatterbot
52
51
  # sleep here so that if launchy has any output (which it does
53
52
  # sometimes), it doesn't interfere with our input prompt
54
53
 
55
- sleep(1)
54
+ sleep(2)
56
55
 
57
56
  puts "Paste your PIN and hit enter when you have completed authorization.\n\n"
58
57
  print "> "
59
58
 
60
- STDIN.readline.chomp
59
+ STDIN.readline.chomp.strip
61
60
  rescue Interrupt => e
62
61
  exit
63
62
  end
64
63
 
65
- #
66
- # Ask the user to get an API key from Twitter.
67
- def get_api_key
68
- green "****************************************"
69
- green "****************************************"
70
- green "**** API SETUP TIME! ****"
71
- green "****************************************"
72
- green "****************************************"
64
+ def ask_yes_no(q)
65
+ prompt = "> "
66
+ response = ""
67
+
73
68
 
69
+ while ! ["y", "n"].include?(response)
70
+ puts "#{q} [Y/N]"
71
+ print prompt
72
+ response = $stdin.gets.chomp.downcase[0]
73
+ end
74
74
 
75
- puts "Hey, looks like you need to get an API key from Twitter before you can get started."
75
+ if response == "y"
76
+ true
77
+ else
78
+ false
79
+ end
80
+ end
81
+
82
+ def send_to_app_creation
76
83
  puts "Please hit enter, and I will send you to #{API_SIGNUP_URL} to start the process."
77
84
  puts "(If it doesn't work, you can open a browser and paste the URL in manually)"
78
85
 
@@ -81,21 +88,82 @@ module Chatterbot
81
88
  STDIN.readline
82
89
 
83
90
  Launchy.open(API_SIGNUP_URL)
91
+
84
92
  # pause to allow any launchy output
85
- sleep(1)
93
+ sleep(2)
86
94
 
87
95
  puts "\n\n"
96
+
97
+
98
+ puts "Once you've filled out the app form, click on the 'Keys and Access Tokens' link"
99
+ end
100
+
101
+ #
102
+ # Ask the user to get an API key from Twitter.
103
+ def get_api_key
104
+
105
+ green "****************************************"
106
+ green "****************************************"
107
+ green "**** API SETUP TIME! ****"
108
+ green "****************************************"
109
+ green "****************************************"
110
+
111
+
112
+ puts "\n\nWelcome to Chatterbot. Let's walk through the steps to get a bot running.\n\n"
113
+
114
+
115
+ #
116
+ # At this point, we don't have any API credentials at all for
117
+ # this bot, but it's possible the user has already setup an app.
118
+ # Let's ask!
119
+ #
88
120
 
89
- print "\n\nPaste the 'API Key' here: "
121
+ puts "Hey, looks like you need to get an API key from Twitter before you can get started.\n\n"
122
+
123
+ app_already_exists = ask_yes_no("Have you already set up an app with Twitter?")
124
+
125
+ if app_already_exists
126
+ puts "Terrific! Let's get your bot running!\n\n"
127
+ else
128
+ puts "OK, I can help with that!\n\n"
129
+ send_to_app_creation
130
+ end
131
+
132
+
133
+ print "\n\nPaste the 'Consumer Key' here: "
90
134
  STDOUT.flush
91
- config[:consumer_key] = STDIN.readline.chomp
135
+ config[:consumer_key] = STDIN.readline.chomp.strip
92
136
 
93
- print "Paste the 'API Secret' here: "
137
+ print "Paste the 'Consumer Secret' here: "
94
138
  STDOUT.flush
95
- config[:consumer_secret] = STDIN.readline.chomp
139
+ config[:consumer_secret] = STDIN.readline.chomp.strip
140
+
96
141
 
97
- # reset the client so we can re-init with new OAuth credentials
98
- reset_client
142
+ puts "\n\nNow it's time to authorize your bot!\n\n"
143
+
144
+ if ! app_already_exists && ask_yes_no("Do you want to authorize a bot using the account that created the app?")
145
+ puts "OK, on the app page, you can click the 'Create my access token' button to proceed.\n\n"
146
+
147
+ print "Paste the 'Access Token' here: "
148
+ STDOUT.flush
149
+ config[:access_token] = STDIN.readline.chomp.strip
150
+
151
+
152
+ print "\n\nPaste the 'Access Token Secret' here: "
153
+ STDOUT.flush
154
+ config[:access_token_secret] = STDIN.readline.chomp.strip
155
+
156
+
157
+ # reset the client so we can re-init with new OAuth credentials
158
+ reset_client
159
+
160
+ # at this point we should have a fully validated client, so grab
161
+ # the screen name
162
+ @screen_name = client.user.screen_name rescue nil
163
+ else
164
+ reset_client
165
+ end
166
+
99
167
 
100
168
  #
101
169
  # capture ctrl-c and exit without a stack trace
@@ -1,3 +1,3 @@
1
1
  module Chatterbot
2
- VERSION = "2.0.0.pre"
2
+ VERSION = "2.1.0"
3
3
  end
data/spec/bot_spec.rb CHANGED
@@ -5,88 +5,13 @@ describe "Chatterbot::Bot" do
5
5
  @bot = Chatterbot::Bot.new
6
6
  end
7
7
 
8
- describe "Streaming API" do
9
- it "should call streaming_client.user" do
10
- expect(@bot.streaming_client).to receive(:user)
11
- @bot.stream!
12
- end
13
- end
14
8
 
15
9
  describe "REST API" do
16
10
  it "should work" do
17
- expect(@bot).to receive(:require_login).and_return(true)
18
- expect(@bot).to receive(:client).and_return(fake_home_timeline(3))
11
+ allow(@bot).to receive(:require_login).and_return(false)
12
+ allow(@bot).to receive(:client).and_return(fake_home_timeline(3))
19
13
  @bot.register_handler(:home_timeline) {}
20
14
  @bot.run!
21
15
  end
22
16
  end
23
-
24
- describe "run_or_stream" do
25
- it "should use streaming if specified" do
26
- expect(@bot).to receive(:stream!)
27
- @bot.streaming = true
28
- @bot.run_or_stream
29
- end
30
-
31
- it "should use streaming if required by handler" do
32
- expect(@bot).to receive(:stream!)
33
- @bot.register_handler(:deleted) {}
34
- @bot.run_or_stream
35
- end
36
-
37
- it "should use REST if specified" do
38
- expect(@bot).to receive(:run!)
39
- @bot.run_or_stream
40
- end
41
- end
42
-
43
-
44
-
45
- describe "stream!" do
46
- before(:each) do
47
- @sc = double(Twitter::Client)
48
- expect(@bot).to receive(:streaming_client).and_return(@sc)
49
- end
50
-
51
- it "tweaks settings for searches" do
52
- @bot.register_handler(:search, "hello") {}
53
- expect(@sc).to receive(:filter)
54
-
55
- @bot.stream!
56
- end
57
-
58
- it "calls :user for non-searches" do
59
- @bot.register_handler(:home_timeline) {}
60
- expect(@sc).to receive(:user)
61
-
62
- @bot.stream!
63
- end
64
- end
65
-
66
- describe "streamify_search_options" do
67
- it "works with string" do
68
- expect( @bot.streamify_search_options("hello there") ).
69
- to eql({track:"hello there"})
70
-
71
-
72
- expect( @bot.streamify_search_options("hello there, friend") ).
73
- to eql({track:"hello there, friend"})
74
- end
75
-
76
- it "works with array" do
77
- expect( @bot.streamify_search_options(["hello there"]) ).
78
- to eql({track:"hello there"})
79
-
80
- expect( @bot.streamify_search_options(["hello there", "friend"]) ).
81
- to eql({track:"hello there, friend"})
82
- end
83
-
84
- it "works with hash" do
85
- opts = {filter:"hello"}
86
- expect( @bot.streamify_search_options(opts) ).
87
- to eql(opts)
88
-
89
- end
90
- end
91
-
92
17
  end
data/spec/client_spec.rb CHANGED
@@ -8,9 +8,6 @@ describe "Chatterbot::Client" do
8
8
  it "should initialize client" do
9
9
  expect(@bot.client).to be_a(Twitter::REST::Client)
10
10
  end
11
- it "should initialize streaming client" do
12
- expect(@bot.streaming_client).to be_a(Twitter::Streaming::Client)
13
- end
14
11
 
15
12
  describe "reset!" do
16
13
  it "should reset a bunch of stuff" do
@@ -139,12 +136,11 @@ describe "Chatterbot::Client" do
139
136
  and_return(double(:token => "access_token", :secret => "access_secret"))
140
137
 
141
138
  expect(@bot).to receive(:get_screen_name)
142
- expect(@bot).to receive(:update_config)
143
139
 
144
140
  @bot.login
145
141
 
146
- expect(@bot.config[:token]).to eq("access_token")
147
- expect(@bot.config[:secret]).to eq("access_secret")
142
+ expect(@bot.config[:access_token]).to eq("access_token")
143
+ expect(@bot.config[:access_token_secret]).to eq("access_secret")
148
144
  end
149
145
 
150
146
  it "handles errors" do
@@ -1,11 +1,16 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'tempfile'
3
+ require 'tmpdir'
4
+
3
5
 
4
6
  describe "Chatterbot::ConfigManager" do
5
7
  before(:each) do
6
- @tmp_config_dest = "/tmp/bot.yml"
8
+ tempdir = Dir.tmpdir
9
+
10
+ @tmp_config_dest = File.join(tempdir, 'bot.yml')
7
11
  @config = Chatterbot::ConfigManager.new(@tmp_config_dest, {:consumer_key => "bar"})
8
12
  end
13
+
9
14
  after(:each) do
10
15
  if File.exist?(@tmp_config_dest)
11
16
  File.unlink(@tmp_config_dest)
@@ -17,10 +22,6 @@ describe "Chatterbot::ConfigManager" do
17
22
  expect(@config.delete(:baz)).to be_nil
18
23
  end
19
24
 
20
- it "works with missing key" do
21
-
22
- end
23
-
24
25
  it "retains read-only data" do
25
26
  expect(@config[:consumer_key]).to eql("bar")
26
27
  expect(@config.delete(:consumer_key)).to be_nil
data/spec/config_spec.rb CHANGED
@@ -1,12 +1,15 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'tempfile'
3
+ require 'tmpdir'
3
4
 
4
5
  describe "Chatterbot::Config" do
5
6
  before(:each) do
6
7
  @bot = Chatterbot::Bot.new
7
- @tmp_config_dest = "/tmp/bot.yml"
8
+ tempdir = Dir.tmpdir
9
+ @tmp_config_dest = File.join(tempdir, 'bot.yml')
8
10
  allow(@bot).to receive(:config_file).and_return(@tmp_config_dest)
9
11
  end
12
+
10
13
  after(:each) do
11
14
  if File.exist?(@tmp_config_dest)
12
15
  File.unlink(@tmp_config_dest)
data/spec/dsl_spec.rb CHANGED
@@ -100,7 +100,7 @@ describe "Chatterbot::DSL" do
100
100
 
101
101
  describe "search" do
102
102
  it "passes along to bot object" do
103
- allow(@bot).to receive(:run_or_stream)
103
+ allow(@bot).to receive(:run!)
104
104
  expect(@bot).to receive(:register_handler).with(:search, ["foo"])
105
105
  search("foo") {}
106
106
  end
@@ -118,39 +118,7 @@ describe "Chatterbot::DSL" do
118
118
  end
119
119
  end
120
120
 
121
- describe "favorited" do
122
- it "passes along to bot object" do
123
- expect(@bot).to receive(:register_handler).with(:favorited, instance_of(Proc))
124
-
125
- favorited {}
126
- end
127
- end
128
-
129
- describe "followed" do
130
- it "passes along to bot object" do
131
- expect(@bot).to receive(:register_handler).with(:followed, instance_of(Proc))
132
-
133
- followed {}
134
- end
135
- end
136
-
137
- describe "deleted" do
138
- it "passes along to bot object" do
139
- expect(@bot).to receive(:register_handler).with(:deleted, instance_of(Proc))
140
-
141
- deleted {}
142
- end
143
- end
144
-
145
121
 
146
- describe "streaming" do
147
- it "passes along to bot object" do
148
- expect(@bot).to receive(:streaming=).with(true)
149
- use_streaming
150
- end
151
- end
152
-
153
-
154
122
  it "#retweet passes along to bot object" do
155
123
  expect(@bot).to receive(:retweet).with(1234)
156
124
  retweet(1234)
@@ -187,10 +155,17 @@ describe "Chatterbot::DSL" do
187
155
  end
188
156
 
189
157
  it "#reply passes along to bot object" do
190
- expect(@bot).to receive(:reply).with("hello sailor!", { :source => "source "})
191
- reply "hello sailor!", { :source => "source "}
158
+ source = double(Twitter::Tweet)
159
+ expect(@bot).to receive(:reply).with("hello sailor!", source, {})
160
+ reply "hello sailor!", source
192
161
  end
193
162
 
163
+ it "#reply passes along to bot object with media" do
164
+ source = double(Twitter::Tweet)
165
+ expect(@bot).to receive(:reply).with("hello sailor!", source, {media:"/tmp/foo.jpg"})
166
+ reply "hello sailor!", source, media:"/tmp/foo.jpg"
167
+ end
168
+
194
169
  describe "#direct_message" do
195
170
  it "passes along to bot object" do
196
171
  expect(@bot).to receive(:direct_message).with("hello sailor!", nil)
Binary file
data/spec/search_spec.rb CHANGED
@@ -7,7 +7,6 @@ describe "Chatterbot::Search" do
7
7
  bot.search("foo")
8
8
  end
9
9
 
10
-
11
10
  it "calls update_since_id" do
12
11
  bot = test_bot
13
12
 
@@ -32,6 +31,46 @@ describe "Chatterbot::Search" do
32
31
  bot.search(["foo", "bar"])
33
32
  end
34
33
 
34
+ it "encloses search queries in quotes" do
35
+ bot = test_bot
36
+
37
+ allow(bot).to receive(:client).and_return(fake_search(100, 1))
38
+ expect(bot.client).to receive(:search).
39
+ with("\"foo bar baz\"", {
40
+ :result_type=>"recent",
41
+ :since_id => 1,
42
+ :since_id_reply => 1
43
+ })
44
+
45
+ bot.search("foo bar baz")
46
+ end
47
+
48
+ it "doesn't enclose search queries in quotes if not exact" do
49
+ bot = test_bot
50
+
51
+ allow(bot).to receive(:client).and_return(fake_search(100, 1))
52
+ expect(bot.client).to receive(:search).
53
+ with("foo bar baz", {
54
+ :result_type=>"recent",
55
+ :since_id => 1,
56
+ :since_id_reply => 1
57
+ })
58
+
59
+ bot.search("foo bar baz", exact:false)
60
+ end
61
+
62
+ it "passes along since_id" do
63
+ bot = test_bot
64
+ allow(bot).to receive(:since_id).and_return(123)
65
+ allow(bot).to receive(:since_id_reply).and_return(456)
66
+
67
+ allow(bot).to receive(:client).and_return(fake_search(100, 1))
68
+ expect(bot.client).to receive(:search).with("foo", {:since_id => 123, :result_type => "recent", :since_id_reply => 456})
69
+
70
+ bot.search("foo")
71
+ end
72
+
73
+
35
74
  it "accepts extra params" do
36
75
  bot = test_bot
37
76