chatterbot 2.0.0.pre → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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