twitter_bot 0.0.1
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.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +36 -0
- data/PostInstall.txt +1 -0
- data/README.txt +44 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +75 -0
- data/config/requirements.rb +15 -0
- data/lib/jabber_bot.rb +41 -0
- data/lib/twitter_bot.rb +151 -0
- data/lib/twitter_bot/version.rb +9 -0
- data/rails_generators/twitter_bot/USAGE +0 -0
- data/rails_generators/twitter_bot/templates/awesome_twitter_bot.rb +25 -0
- data/rails_generators/twitter_bot/templates/twitter_bot +6 -0
- data/rails_generators/twitter_bot/templates/twitter_bot.yml +13 -0
- data/rails_generators/twitter_bot/templates/twitter_bot_runner.rb +4 -0
- data/rails_generators/twitter_bot/twitter_bot_generator.rb +24 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +83 -0
- data/setup.rb +1585 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/twitter_bot_spec.rb +11 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/website.rake +17 -0
- data/test/test_generator_helper.rb +29 -0
- data/test/test_twitter_bot_generator.rb +45 -0
- data/website/index.html +125 -0
- data/website/index.txt +53 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.html.erb +48 -0
- metadata +124 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Integrum Technologies, LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
PostInstall.txt
|
5
|
+
README.txt
|
6
|
+
Rakefile
|
7
|
+
config/hoe.rb
|
8
|
+
config/requirements.rb
|
9
|
+
lib/jabber_bot.rb
|
10
|
+
lib/twitter_bot.rb
|
11
|
+
lib/twitter_bot/version.rb
|
12
|
+
rails_generators/twitter_bot/USAGE
|
13
|
+
rails_generators/twitter_bot/templates/awesome_twitter_bot.rb
|
14
|
+
rails_generators/twitter_bot/templates/twitter_bot
|
15
|
+
rails_generators/twitter_bot/templates/twitter_bot.yml
|
16
|
+
rails_generators/twitter_bot/templates/twitter_bot_runner.rb
|
17
|
+
rails_generators/twitter_bot/twitter_bot_generator.rb
|
18
|
+
script/console
|
19
|
+
script/destroy
|
20
|
+
script/generate
|
21
|
+
script/txt2html
|
22
|
+
setup.rb
|
23
|
+
spec/spec.opts
|
24
|
+
spec/spec_helper.rb
|
25
|
+
spec/twitter_bot_spec.rb
|
26
|
+
tasks/deployment.rake
|
27
|
+
tasks/environment.rake
|
28
|
+
tasks/rspec.rake
|
29
|
+
tasks/website.rake
|
30
|
+
test/test_generator_helper.rb
|
31
|
+
test/test_twitter_bot_generator.rb
|
32
|
+
website/index.html
|
33
|
+
website/index.txt
|
34
|
+
website/javascripts/rounded_corners_lite.inc.js
|
35
|
+
website/stylesheets/screen.css
|
36
|
+
website/template.html.erb
|
data/PostInstall.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
For more information on twitter_bot, see http://integrum.rubyforge.org
|
data/README.txt
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
= twitter_bot
|
2
|
+
|
3
|
+
* http://integrum.rubyforge.org
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Enables adding twitter to your app. Uses Twitter's Jabber interface.
|
8
|
+
|
9
|
+
== SYNOPSIS:
|
10
|
+
|
11
|
+
script/generate twitter_bot name
|
12
|
+
name - the name of your twitter bot
|
13
|
+
|
14
|
+
1. Edit config/twitter_bot.yml to add authentication information
|
15
|
+
2. Edit lib/<name>_twitter_bot.rb to specify callback actions
|
16
|
+
|
17
|
+
== INSTALL:
|
18
|
+
|
19
|
+
* gem install twitter_bot
|
20
|
+
|
21
|
+
== LICENSE:
|
22
|
+
|
23
|
+
(The MIT License)
|
24
|
+
|
25
|
+
Copyright (c) 2008 Integrum Technologies, LLC
|
26
|
+
|
27
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
28
|
+
a copy of this software and associated documentation files (the
|
29
|
+
'Software'), to deal in the Software without restriction, including
|
30
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
31
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
32
|
+
permit persons to whom the Software is furnished to do so, subject to
|
33
|
+
the following conditions:
|
34
|
+
|
35
|
+
The above copyright notice and this permission notice shall be
|
36
|
+
included in all copies or substantial portions of the Software.
|
37
|
+
|
38
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
39
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
40
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
41
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
42
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
43
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
44
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'twitter_bot/version'
|
2
|
+
|
3
|
+
AUTHOR = "Jade Meskill, Curtis Miller, Curtis Edmond" # can also be an array of Authors
|
4
|
+
EMAIL = "info@integrumtech.com"
|
5
|
+
DESCRIPTION = "Twitter integration for your app using the Twitter Jabber bot"
|
6
|
+
GEM_NAME = 'twitter_bot' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'integrum' # The unix name for your project
|
8
|
+
HOMEPATH = "http://integrum.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/integrum/twitter_bot"
|
10
|
+
EXTRA_DEPENDENCIES = [
|
11
|
+
['daemons', '>= 1.0.9'],
|
12
|
+
['twitter', '>= 0.2.6'],
|
13
|
+
['xmpp4r', '>= 0.3.2']
|
14
|
+
]
|
15
|
+
|
16
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
17
|
+
@config = nil
|
18
|
+
RUBYFORGE_USERNAME = "unknown"
|
19
|
+
def rubyforge_username
|
20
|
+
unless @config
|
21
|
+
begin
|
22
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
23
|
+
rescue
|
24
|
+
puts <<-EOS
|
25
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
26
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
27
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
28
|
+
EOS
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
end
|
32
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
REV = nil
|
37
|
+
# UNCOMMENT IF REQUIRED:
|
38
|
+
# REV = YAML.load(`svn info`)['Revision']
|
39
|
+
VERS = TwitterBot::VERSION::STRING + (REV ? ".#{REV}" : "")
|
40
|
+
RDOC_OPTS = ['--quiet', '--title', 'twitter_bot documentation',
|
41
|
+
"--opname", "index.html",
|
42
|
+
"--line-numbers",
|
43
|
+
"--main", "README",
|
44
|
+
"--inline-source"]
|
45
|
+
|
46
|
+
class Hoe
|
47
|
+
def extra_deps
|
48
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
49
|
+
@extra_deps
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Generate all the Rake tasks
|
54
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
55
|
+
$hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
56
|
+
p.developer(AUTHOR, EMAIL)
|
57
|
+
p.description = DESCRIPTION
|
58
|
+
p.summary = DESCRIPTION
|
59
|
+
p.url = HOMEPATH
|
60
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
61
|
+
p.test_globs = ["test/**/test_*.rb"]
|
62
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
63
|
+
|
64
|
+
# == Optional
|
65
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
66
|
+
p.extra_deps = EXTRA_DEPENDENCIES
|
67
|
+
|
68
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
69
|
+
end
|
70
|
+
|
71
|
+
CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
72
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
73
|
+
$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
74
|
+
$hoe.rsync_args = '-av --delete --ignore-errors'
|
75
|
+
$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
data/lib/jabber_bot.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'xmpp4r/client'
|
2
|
+
|
3
|
+
class JabberBot < Jabber::Client
|
4
|
+
include Jabber
|
5
|
+
|
6
|
+
def initialize(jabber_id, jabber_password, options = {})
|
7
|
+
@jabber_id = jabber_id
|
8
|
+
@jabber_password = jabber_password
|
9
|
+
@options = options
|
10
|
+
|
11
|
+
jid = JID::new(@jabber_id)
|
12
|
+
super(jid)
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_message(from, body)
|
16
|
+
raise "on_message not implemented!"
|
17
|
+
end
|
18
|
+
|
19
|
+
def connect_and_authenticate
|
20
|
+
connect
|
21
|
+
auth(@jabber_password)
|
22
|
+
send(Presence::new)
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
main = Thread.current
|
27
|
+
add_message_callback { |message|
|
28
|
+
next if message.type == :error or message.body.blank?
|
29
|
+
# support exit command if owner is set
|
30
|
+
main.wakeup if @options[:owner_jabber_id] == message.from && message.body == 'exit'
|
31
|
+
# simple callback
|
32
|
+
self.on_message(message.from, message.body, message.first_element('entry'))
|
33
|
+
}
|
34
|
+
Thread.stop
|
35
|
+
close
|
36
|
+
end
|
37
|
+
|
38
|
+
def say(jabber_id, body)
|
39
|
+
send(Message::new(jabber_id, body).set_type(:chat).set_id('1'))
|
40
|
+
end
|
41
|
+
end
|
data/lib/twitter_bot.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/jabber_bot'
|
2
|
+
require 'twitter'
|
3
|
+
|
4
|
+
class TwitterBot < JabberBot
|
5
|
+
TWITTER_JABBER_ID = 'twitter@twitter.com'
|
6
|
+
attr_accessor :track_phrases
|
7
|
+
|
8
|
+
CONFIG_FILE = File.join(RAILS_ROOT, 'config', 'twitter_bot.yml')
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
raise "File does not exist: '#{CONFIG_FILE}'" unless File.exist?(CONFIG_FILE)
|
12
|
+
|
13
|
+
twitter_bot_config = YAML.load(File.read(CONFIG_FILE))
|
14
|
+
twitter_config = twitter_bot_config['twitter']
|
15
|
+
jabber_config = twitter_bot_config['jabber']
|
16
|
+
|
17
|
+
raise "Please specify the twitter config in '#{CONFIG_FILE}'" if twitter_config.blank?
|
18
|
+
raise "Please specify the jabber config in '#{CONFIG_FILE}'" if jabber_config.blank?
|
19
|
+
|
20
|
+
@twitter_username = twitter_config['username']
|
21
|
+
@twitter_password = twitter_config['password']
|
22
|
+
jabber_id = jabber_config['id']
|
23
|
+
jabber_password = jabber_config['password']
|
24
|
+
|
25
|
+
raise "The twitter username has not been specified in '#{CONFIG_FILE}'" if @twitter_username.blank?
|
26
|
+
raise "The twitter password has not been specified in '#{CONFIG_FILE}'" if @twitter_password.blank?
|
27
|
+
raise "The jabber ID has not been specified in '#{CONFIG_FILE}'" if jabber_id.blank?
|
28
|
+
raise "The jabber password has not been specified in '#{CONFIG_FILE}'" if jabber_password.blank?
|
29
|
+
|
30
|
+
@track_phrases = twitter_bot_config['track'] || []
|
31
|
+
@followers = []
|
32
|
+
|
33
|
+
@twitter = Twitter::Base.new(@twitter_username, @twitter_password)
|
34
|
+
super(jabber_id, jabber_password)
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_directed_tweet(&block); @on_directed_tweet_callback = block; end
|
38
|
+
def on_tweet(&block); @on_tweet_callback = block; end
|
39
|
+
def on_track(&block); @on_track_callback = block; end
|
40
|
+
def on_follow(&block); @on_follow_callback = block; end
|
41
|
+
def on_unfollow(&block); @on_unfollow_callback = block; end
|
42
|
+
|
43
|
+
def create_twitter_entry(entry)
|
44
|
+
return if entry.nil?
|
45
|
+
xml = Hpricot.XML(entry.to_s)
|
46
|
+
Twitter::Status.new do |s|
|
47
|
+
s.id = xml.at('entry/id').innerHTML.split('/').last
|
48
|
+
s.created_at = Time.parse(xml.at('entry/published').innerHTML)
|
49
|
+
s.text = body
|
50
|
+
s.user = Twitter.User.new do |u|
|
51
|
+
u.screen_name = xml.at('author/name').innerHTML
|
52
|
+
u.url = xml.at('source/link')['href']
|
53
|
+
u.profile_image_url = xml.at('source/icon').innerHTML
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_message(from, body, entry = nil)
|
59
|
+
$stdout.flush
|
60
|
+
return unless from == TWITTER_JABBER_ID
|
61
|
+
entry = create_twitter_entry(entry) rescue nil
|
62
|
+
|
63
|
+
callback = @on_tweet_callback
|
64
|
+
twitter_message = body.split(': ')
|
65
|
+
twitter_body = twitter_message[1,twitter_message.size].join(': ')
|
66
|
+
twitter_from = twitter_message.first
|
67
|
+
|
68
|
+
if twitter_from =~ /You aren\'t tracking anything\. Reply with \'track your keywords\' to start\./
|
69
|
+
track_phrases.each { |phrase| say("track #{phrase}") }
|
70
|
+
else
|
71
|
+
if (track_notification = twitter_from.match(/\((.+)\)/))
|
72
|
+
twitter_from = track_notification[1] # Make sure that twitter_from gets set properly in case of event + @<username>
|
73
|
+
# callback = @on_track_callback
|
74
|
+
end
|
75
|
+
|
76
|
+
callback.call(twitter_from, twitter_body, entry) if callback
|
77
|
+
end
|
78
|
+
rescue => e
|
79
|
+
$stderr.puts("error parsing #{body} (#{e})")
|
80
|
+
end
|
81
|
+
|
82
|
+
def runn(options = {})
|
83
|
+
connect_and_authenticate
|
84
|
+
follow_all_followers if options[:follow_all_followers]
|
85
|
+
say("untrack all")
|
86
|
+
|
87
|
+
Thread.new do
|
88
|
+
followers_watcher(options)
|
89
|
+
end
|
90
|
+
run
|
91
|
+
end
|
92
|
+
|
93
|
+
def logger
|
94
|
+
@@logger ||= Logger.new(File.join(RAILS_ROOT, 'log', 'twitter_bot.log'))
|
95
|
+
end
|
96
|
+
|
97
|
+
def follow(username)
|
98
|
+
say("follow #{username}")
|
99
|
+
end
|
100
|
+
|
101
|
+
def say(line)
|
102
|
+
super(TWITTER_JABBER_ID, line)
|
103
|
+
end
|
104
|
+
|
105
|
+
def direct_message(username, message)
|
106
|
+
say("d #{username} #{message}")
|
107
|
+
end
|
108
|
+
|
109
|
+
def determine_phrase_for_body(body)
|
110
|
+
@track_phrases.each do |phrase|
|
111
|
+
phrase_expression = Regexp.new(phrase)
|
112
|
+
if phrase_expression.match(body.downcase)
|
113
|
+
return phrase
|
114
|
+
end
|
115
|
+
end
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def follow_all_followers
|
120
|
+
following = @twitter.friends.collect { |user| user.name }
|
121
|
+
@followers = @twitter.followers.collect { |user| user.name }
|
122
|
+
@followers.each do |username|
|
123
|
+
if !following.index(username)
|
124
|
+
follow(username)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def followers_watcher(options = {})
|
130
|
+
return unless @on_follow_callback || @on_unfollow_callback
|
131
|
+
options[:followers_check_wait] ||= 120
|
132
|
+
@followers = @twitter.followers.collect { |user| user.name } if @followers.empty?
|
133
|
+
while 1 == 1
|
134
|
+
twitter_followers = @twitter.followers.collect { |user| user.name }
|
135
|
+
twitter_followers.each do |username|
|
136
|
+
if !@followers.index(username)
|
137
|
+
@on_follow_callback.call(username) if @on_follow_callback
|
138
|
+
end
|
139
|
+
end
|
140
|
+
@followers.each do |username|
|
141
|
+
if !twitter_followers.index(username)
|
142
|
+
@on_unfollow_callback.call(username) if @on_unfollow_callback
|
143
|
+
end
|
144
|
+
end
|
145
|
+
@followers = twitter_followers
|
146
|
+
sleep(options[:followers_check_wait])
|
147
|
+
end
|
148
|
+
rescue => e
|
149
|
+
raise e
|
150
|
+
end
|
151
|
+
end
|
File without changes
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'drb'
|
2
|
+
|
3
|
+
class <%= file_name.classify %>TwitterBot < TwitterBot
|
4
|
+
def runn
|
5
|
+
self.on_tweet do |username, message, entry|
|
6
|
+
logger.info("#{username} said '#{message}'")
|
7
|
+
# Add tweet processing code here, not required
|
8
|
+
end
|
9
|
+
|
10
|
+
self.on_follow do |username|
|
11
|
+
logger.info("#{username} is following us, will follow #{username} too and send welcome message")
|
12
|
+
follow(username)
|
13
|
+
self.direct_message(username, "thanks for following me!")
|
14
|
+
# Add on follow processing here, not required
|
15
|
+
end
|
16
|
+
|
17
|
+
self.on_unfollow do |username|
|
18
|
+
logger.info("#{username} has stopped following us.")
|
19
|
+
# Add on unfollow processing here, not required
|
20
|
+
end
|
21
|
+
|
22
|
+
DRb.start_service("druby://:8997", self)
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|