replacer_bot 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/Guardfile +23 -0
- data/LICENSE.md +22 -0
- data/README.md +7 -0
- data/Rakefile +10 -0
- data/bin/replacer +4 -0
- data/config/defaults.yml +6 -0
- data/features/replacer.feature +5 -0
- data/features/support/env.rb +2 -0
- data/lib/replacer_bot.rb +16 -0
- data/lib/replacer_bot/cli.rb +17 -0
- data/lib/replacer_bot/config.rb +31 -0
- data/lib/replacer_bot/helpers.rb +93 -0
- data/lib/replacer_bot/replacer.rb +40 -0
- data/lib/replacer_bot/twitter_client.rb +14 -0
- data/lib/replacer_bot/version.rb +3 -0
- data/replacer_bot.gemspec +35 -0
- data/spec/lib/replacer_bot/config_spec.rb +9 -0
- data/spec/lib/replacer_bot/helpers_spec.rb +88 -0
- data/spec/lib/replacer_bot/replacer_spec.rb +70 -0
- data/spec/lib/replacer_bot/twitter_client_spec.rb +7 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/vcr_setup.rb +19 -0
- data/spec/vcr/ReplacerBot_Replacer/only_find_new_tweets/finds_new_tweets.yml +1202 -0
- data/spec/vcr/ReplacerBot_Replacer/only_find_new_tweets/finds_newer_tweets.yml +1349 -0
- data/spec/vcr/ReplacerBot_Replacer/save_and_retrieve/saves_the_ID_of_the_last_tweet.yml +1344 -0
- data/spec/vcr/ReplacerBot_Replacer/save_and_retrive/saves_the_ID_of_the_last_tweet.yml +1345 -0
- data/spec/vcr/ReplacerBot_Replacer/save_last_tweet/only_saves_if_there_is_something_to_save.yml +1381 -0
- data/spec/vcr/ReplacerBot_Replacer/save_last_tweet/saves_the_ID_of_the_last_tweet.yml +1390 -0
- data/spec/vcr/ReplacerBot_Replacer/search/finds_the_correct_tweets.yml +1202 -0
- data/spec/vcr/ReplacerBot_Replacer/search/finds_tweets.yml +1202 -0
- data/spec/vcr/ReplacerBot_Replacer/search/saves_the_text_of_its_tweets.yml +1178 -0
- data/spec/vcr/ReplacerBot_Replacer/search/searches_for_tweets.yml +1191 -0
- data/spec/vcr/ReplacerBot_Replacer/search/uniqs_its_tweets.yml +2353 -0
- data/spec/vcr/ReplacerBot_Replacer/tweet/prepares_sensible_tweets.yml +1178 -0
- metadata +285 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e3f27f98339571d3f2f02f50776049785f1d52bb
|
4
|
+
data.tar.gz: 36a8af3bc649a8d18f9d1e59d19f6d715220e466
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1f8edccc8fb420dc44c9d58e931e8117cb677092879541df343e229e3a556b0ca49a379c03132446ab6d18026a80ece5eddf6b4ff52e89ee04f8beb5322e14b2
|
7
|
+
data.tar.gz: 3133bd60c3169fb6478a8a1422a9bb1d2ff0dbd23624ef75ceab47800a836fbd0c5595d6f92c2b5c50fb71d9eb18354746fe6873c637ba80e4ea5b80d4b74e02
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2.0
|
4
|
+
env:
|
5
|
+
global:
|
6
|
+
- secure: vZClOhjX33NL+SEWU72xyWcb9MHWPwZTp4YPgi5x3/hTRc8NB1IMBjicJu0KpxKzh7m7UfgbgVhHUwxkLn1oOBvTZteKvw4AcNpEdroLuxCfI1CpCUxwVOtyEacG369A3CZUCh+JaVc6JNtIXJeDYm+4gIv97g3xjw/kHMK/zwifZmo7LszrKluKfIvGe2JYImtXiGc/Lwn2F2JfxGwAx50oX3SPWXpte/uHhexG2q3nvUNhA7bAMO3tXLvSJDVv1Gs61q2rt3EkyaoUw9i7ZqI0/YSsOQzW40I1mNpSiEz0/SxzS9L/u7x9CwolRTJJ15SLajqzKT6Vr17ir3dMoM+jpYwxW4GyBotS9ScezFe6p/TBzVwFJclE2sAEE2DBUgSh9j0q4cTWnK3ff8RgkU+ECQaQPho/zp/eykgsr21pmKM3dxMrqtSoEBgF8TgGYYuPcR97NIbQv3g8XOJcwJhraqmgDgkV8KajuA6sx50KX8AxkaziD5eB2I8bqg3kev1BMd28OTvPEvAP0PF1/tIkp5oth9tgdVlGwJGncCLMZgtybjsYJEmDaGKtA0U+gOg/Cy9b3Irz0NgMVEeACN6wMetQYVJGAk7SN9AbCYMqK/gSMLR+vHd9I6ff/j0XsF8KXct9QpPMB6iZd+DFFt1ewq/+ECOsAcHvVQ1zv9Y=
|
7
|
+
- secure: Mbt5RWzZssdN7vOJ8XIvMKfb4WQlKaCcKJaIaRsT4dH33G7jd1nlifANx5MDW3SpqVa9lglzQ2uC8n1qWwY5l0va6uPZgm+FiInYnu+hQj0jsLb093K4kUZOGuqxYipXapITcgXGFmqlv75sABaFCFXKw9Pkn2XozeD2s4Hz6sh0J5TFnBAI5HrM4CUs8Zv2OSIQDEIjTi5PduYk91G5Tv/i6ihZsSJ9r9VloNoJak82rTeaL9JnUnZuZJwGF6ZsOLzYBRwInw/dI6ydhmSbkGosOTfl92q5NfBFeN0NroFiFVqkcDQInLhuNQZkwbvcdPs7/vOJzAOhuMlj8yPr8EYk2kS3HU7Zt0O853i8l3GehFsVthUQatriEeG0PBUmDl1Wj3srpaV8XQA6hMWHvDcD8afPRMAPYynoSkC06GVNDQjpEc1aZkSU8mdSyUcKtzjUiYhkOiwoRGoaPhnQwyHRg+7sE3SAQMVMqBukTlTnE6cCfcn0q/PGnD5dDuit7DkdSO6S96uVlC4VqxXPiHxtTNa/nThEQKetmt2cTJR9uA65HT/qlGQ4FVQcefXS3XIU7mIYzzw+g9cAzFz6j3wonKgHt6bKg0SmtqhZTxm6ZLbLvSx8jZzY6Hh/J9IRaLPskI/1iEZAeFCDkR5vYSalZCunWBz2r9UP0gmkJj0=
|
8
|
+
- secure: V2S0W5yqFmsMuTCQlObF23Aw5dGdv0ZFJRvNAVCAg8lx1sQFud43AZVqafzw0S/3NT63Cz9O+XskqOWZ5u8mBIZYmF9Gn0wX/2P1OFd4GxAJ9MXrG8T2dWWykHxachugibZXDIjedCRht4bWJ96GvitEt6tYbGr6yV0ziZgl/4U90bDvQ1XQzZkG637Gt/sFwAriGJ45V5H1ZzYHw7kaDFMhVzTk5sYjNoQD5rlcbZSBRV7MFK//wJA2pCNdwcS60LXpRyoqZXXrnD9vndFGEJoZM5DAPyNjlDk3nKvfkM/sAhJ4SRxEXqHDXMcpz3yoBTNHB0weJkczBS5VfeTcTIkEjWCYhZ0VVBdjXcDaxNRS1mj5Wb8O+3Dr5eSymZ98U3MT3k1MCZWyvmbFOJZnCbx4TbBHX4DjxMTjFPdG/RyFtCv+pFvSFTNl1jR/UP8VgcCDA+vg/YqNE5OxT2XXHYnmQHS2u0bHwsngI7cGVzKjgNN9lQKAehIVLy/2zWV49qK71RjqZlry1V8KsGxikVMEuqbLgP3szRdWTvBvO26uHv45+5i39nXU82ZT9DsPxH5jCqhblKPcT2CDp7ibVl3B1sURZ7YHIgfOWITjWU9H+XzzGLvtVPVcoMjBSP5uQft4Pgm6cRXC3SLiA8SpTQTS4hSzIPLJRhvcq420vxQ=
|
9
|
+
- secure: DP3Zj5bq5UXJQrVn+TBdQZp4U8JuQpKmw+KfVkphdL6NF/GLo7riNJdqRVMGpKI22WW9O3HWKV6Vnwq3jKkT+1ESdHUTBqkzgZc4jHOV36G3rIuhXj7hQbIcExJbxJ0LaePvDcxyVOB3oWTl0Kf2A7JN0Z9qb2ELshvB9pqV1KNJ2g4E9SNag5LM/TcZuQ7eGMIwFcT9+Ag83EszIBm/C1+qhFImMbbjrk5hA+mIogPtV9jQUtWAPPy0r7PHU+/1VPQhZWemtr8Ozlte2qELpyahyR6XzCF4Y7j3u4er3CfSWkb6B0u+bcKUJuaqavDi70ABP1UUGUzNOId4uDiXIgVG8JBFjPl4GUqe05xyq+4QYZMiqc1WTbIJJktntYpGV0Yq1q++osqFfbbt486L45+x/tyIk5E2f9TLNyn5fMNqh9LCQvq0KVdZMS2UrMzmOb3dwEre/NRAuvdeUwkusFaG0V6UVurhD+HN+yiqT//gy+YXI3uKtNCAGh4cpIZEqAyCaW4ehOjm3RvZNmCBbVr9F92WWfB8lVrHivHevGV4twVgapL0u0YAKDT66Dn2U5B3DmRBATw+OqitOddwQRO2h0lCzKdVhc9THDj5Boi/IWc/Y1PvKh/p74dp1PZab6zkitQ52KUOEPS/U6MrDOUKLZsDy8FtXSRL3rALj60=
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
2
|
+
require "guard/rspec/dsl"
|
3
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
4
|
+
|
5
|
+
# RSpec files
|
6
|
+
rspec = dsl.rspec
|
7
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
8
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
9
|
+
watch(rspec.spec_files)
|
10
|
+
|
11
|
+
# Ruby files
|
12
|
+
ruby = dsl.ruby
|
13
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
14
|
+
end
|
15
|
+
|
16
|
+
guard "cucumber" do
|
17
|
+
watch(%r{^features/.+\.feature$})
|
18
|
+
watch(%r{^features/support/.+$}) { "features" }
|
19
|
+
|
20
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) do |m|
|
21
|
+
Dir[File.join("**/#{m[1]}.feature")][0] || "features"
|
22
|
+
end
|
23
|
+
end
|
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 pikesley
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
[![Build Status](http://img.shields.io/travis/pikesley/replacer_bot.svg)](https://travis-ci.org/pikesley/replacer_bot)
|
2
|
+
[![Dependency Status](http://img.shields.io/gemnasium/pikesley/replacer_bot.svg)](https://gemnasium.com/pikesley/replacer_bot)
|
3
|
+
[![Coverage Status](http://img.shields.io/coveralls/pikesley/replacer_bot.svg)](https://coveralls.io/r/pikesley/replacer_bot)
|
4
|
+
[![Code Climate](http://img.shields.io/codeclimate/github/pikesley/replacer_bot.svg)](https://codeclimate.com/github/pikesley/replacer_bot)
|
5
|
+
[![Gem Version](http://img.shields.io/gem/v/replacer_bot.svg)](https://rubygems.org/gems/replacer_bot)
|
6
|
+
[![License](http://img.shields.io/:license-mit-blue.svg)](http://pikesley.mit-license.org)
|
7
|
+
[![Badges](http://img.shields.io/:badges-7/7-ff6799.svg)](https://github.com/badges/badgerbadgerbadger)
|
data/Rakefile
ADDED
data/bin/replacer
ADDED
data/config/defaults.yml
ADDED
data/lib/replacer_bot.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'twitter'
|
2
|
+
require 'dotenv'
|
3
|
+
require 'uri'
|
4
|
+
require 'singleton'
|
5
|
+
require 'thor'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
require 'replacer_bot/version'
|
9
|
+
require 'replacer_bot/replacer'
|
10
|
+
require 'replacer_bot/config'
|
11
|
+
require 'replacer_bot/helpers'
|
12
|
+
require 'replacer_bot/twitter_client'
|
13
|
+
|
14
|
+
Dotenv.load
|
15
|
+
|
16
|
+
TWITTER_LIMIT= 140
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'replacer_bot'
|
2
|
+
|
3
|
+
module ReplacerBot
|
4
|
+
class CLI < Thor
|
5
|
+
desc 'version', 'Print replacer version'
|
6
|
+
def version
|
7
|
+
puts "replacer version #{VERSION}"
|
8
|
+
end
|
9
|
+
map %w(-v --version) => :version
|
10
|
+
|
11
|
+
desc 'tweet', 'find, munge and send tweets'
|
12
|
+
def tweet
|
13
|
+
r = Replacer.new
|
14
|
+
r.tweet
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ReplacerBot
|
2
|
+
class Config
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
reset!
|
7
|
+
end
|
8
|
+
|
9
|
+
def reset! # testing a singleton is hard
|
10
|
+
custom = fetch_yaml "#{ENV['HOME']}/.replacer_bot/config.yml"
|
11
|
+
defaults = fetch_yaml (File.join(File.dirname(__FILE__), '..', '..', 'config/defaults.yml'))
|
12
|
+
defaults.merge! custom
|
13
|
+
|
14
|
+
@config = OpenStruct.new defaults
|
15
|
+
end
|
16
|
+
|
17
|
+
def config
|
18
|
+
@config
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def fetch_yaml file
|
24
|
+
begin
|
25
|
+
YAML.load File.open file
|
26
|
+
rescue
|
27
|
+
{}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module ReplacerBot
|
2
|
+
def self.encode term
|
3
|
+
URI.encode "\"#{term}\""
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.last_tweet
|
7
|
+
begin
|
8
|
+
Marshal.load File.read Config.instance.config.save_file
|
9
|
+
rescue ArgumentError
|
10
|
+
0
|
11
|
+
rescue Errno::ENOENT
|
12
|
+
0
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.validate string, term = Config.instance.config.search_term, ignore_spaces = true
|
17
|
+
return false if string[0...2] == 'RT'
|
18
|
+
return false if string[0] == '@'
|
19
|
+
|
20
|
+
term = term.gsub ' ', ' ?' if ignore_spaces
|
21
|
+
return true if string.index /#{term}/i
|
22
|
+
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.filter list
|
27
|
+
list.select { |i| self.validate i.text, Config.instance.config.search_term }.
|
28
|
+
select { |i| i.id > self.last_tweet}
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.dehash word
|
32
|
+
if word[0] == '#'
|
33
|
+
return word[1..-1]
|
34
|
+
end
|
35
|
+
|
36
|
+
word
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.despace string
|
40
|
+
string.gsub(/\n+/, ' ').gsub(/ +/, ' ').strip
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.truncate text
|
44
|
+
return_text = ''
|
45
|
+
text.split.each do |word|
|
46
|
+
new_text = "#{return_text} #{word}".strip
|
47
|
+
if new_text.length > TWITTER_LIMIT
|
48
|
+
return return_text
|
49
|
+
else
|
50
|
+
return_text = new_text
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
return_text
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.article string
|
58
|
+
string = self.dehash string
|
59
|
+
specials = [ 'hotel' ]
|
60
|
+
|
61
|
+
if specials.include? string.downcase
|
62
|
+
return 'an'
|
63
|
+
end
|
64
|
+
|
65
|
+
if 'aeiou'.include? string[0].downcase
|
66
|
+
return 'an'
|
67
|
+
end
|
68
|
+
|
69
|
+
'a'
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.replacement_extender replacement
|
73
|
+
[
|
74
|
+
replacement.map { |k, v| {"#{self.article k} #{k}" => "#{self.article v} #{v}"} }[0],
|
75
|
+
replacement.map { |k, v| {"#{self.article k} ##{k}" => "#{self.article v} ##{v}"} }[0]
|
76
|
+
]
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.replace string, subs = Config.instance.config.replacements
|
80
|
+
# Something about a frozen string
|
81
|
+
our_string = string.dup
|
82
|
+
subs.each do |substitute|
|
83
|
+
(self.replacement_extender(substitute) << substitute).each do |s|
|
84
|
+
s.each do |search, replace|
|
85
|
+
our_string = self.despace our_string
|
86
|
+
our_string.gsub! /#{search}/i, replace
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
our_string
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ReplacerBot
|
2
|
+
class Replacer
|
3
|
+
attr_reader :results, :config
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@config = Config.instance.config
|
7
|
+
@search_term = @config.search_term
|
8
|
+
@client = TwitterClient.client
|
9
|
+
end
|
10
|
+
|
11
|
+
def search count = 20
|
12
|
+
@results ||= begin
|
13
|
+
results = ReplacerBot.filter @client.search(ReplacerBot.encode(@search_term), result_type: 'recent').take(count)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def tweets
|
18
|
+
search.map { |r| ReplacerBot.truncate ReplacerBot.replace r.text }
|
19
|
+
end
|
20
|
+
|
21
|
+
def tweet
|
22
|
+
tweets.each do |tweet|
|
23
|
+
puts "Tweeting: #{tweet}"
|
24
|
+
@client.update tweet
|
25
|
+
puts "Sleeping #{@config.interval} seconds"
|
26
|
+
sleep @config.interval
|
27
|
+
end
|
28
|
+
|
29
|
+
save
|
30
|
+
end
|
31
|
+
|
32
|
+
def save
|
33
|
+
if search.first
|
34
|
+
File.open @config.save_file, 'w' do |file|
|
35
|
+
Marshal.dump search.first.id, file
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ReplacerBot
|
2
|
+
class TwitterClient
|
3
|
+
def self.client
|
4
|
+
config = {
|
5
|
+
consumer_key: ENV['CONSUMER_KEY'],
|
6
|
+
consumer_secret: ENV['CONSUMER_SECRET'],
|
7
|
+
access_token: ENV['TOKEN'],
|
8
|
+
access_token_secret: ENV['SECRET']
|
9
|
+
}
|
10
|
+
|
11
|
+
::Twitter::REST::Client.new(config)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'replacer_bot/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'replacer_bot'
|
8
|
+
spec.version = ReplacerBot::VERSION
|
9
|
+
spec.authors = ['pikesley']
|
10
|
+
spec.email = ['github@orgraphone.org']
|
11
|
+
spec.summary = %q{Taylor Swift}
|
12
|
+
spec.description = %q{Taylor Swift}
|
13
|
+
spec.homepage = ''
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'twitter', '~> 5.14'
|
22
|
+
spec.add_dependency 'dotenv', '~> 2.0'
|
23
|
+
spec.add_dependency 'thor', '~> 0.19'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.3'
|
28
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.6'
|
29
|
+
spec.add_development_dependency 'guard-cucumber', '~> 1.6'
|
30
|
+
spec.add_development_dependency 'vcr', '~> 2.9'
|
31
|
+
spec.add_development_dependency 'webmock', '~> 1.21'
|
32
|
+
spec.add_development_dependency 'cucumber' , '~> 2.0'
|
33
|
+
spec.add_development_dependency 'aruba', '~> 0.8'
|
34
|
+
spec.add_development_dependency 'coveralls', '~> 0.8'
|
35
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module ReplacerBot
|
2
|
+
describe 'Helpers' do
|
3
|
+
context 'URLs' do
|
4
|
+
it 'URL-encodes a search term' do
|
5
|
+
expect(ReplacerBot.encode 'open data').to eq '%22open%20data%22'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'last tweet' do
|
10
|
+
it 'gets a default value for the last tweet' do
|
11
|
+
expect(ReplacerBot.last_tweet).to eq 0
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'knows the ID of the last tweet' do
|
15
|
+
File.open 'last.tweet', 'w' do |f|
|
16
|
+
Marshal.dump 632586894455500800, f
|
17
|
+
end
|
18
|
+
expect(ReplacerBot.last_tweet).to eq 632586894455500800
|
19
|
+
FileUtils.rm 'last.tweet'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'filtering' do
|
24
|
+
it 'validates liberally' do
|
25
|
+
expect(ReplacerBot.validate 'opendata hulk', 'open data').to eq true
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'validates more strictly' do
|
29
|
+
expect(ReplacerBot.validate 'open data ftw', 'open data', ignore_spaces = false).to eq true
|
30
|
+
expect(ReplacerBot.validate 'i love opendata', 'open data', ignore_spaces = false).to eq false
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'validates away rubbish' do
|
34
|
+
expect(ReplacerBot.validate 'incredible hulk', 'open data').to eq false
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'filters retweets' do
|
38
|
+
expect(ReplacerBot.validate 'RT @xyz This is about Open Data').to eq false
|
39
|
+
end
|
40
|
+
it 'filters direct replies' do
|
41
|
+
expect(ReplacerBot.validate '@abc This is a reply about Open Data').to eq false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'search and replace' do
|
46
|
+
it 'removes a hash from the start of a word' do
|
47
|
+
expect(ReplacerBot.dehash '#opendata').to eq 'opendata'
|
48
|
+
expect(ReplacerBot.dehash 'data').to eq 'data'
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'squashes whitespace' do
|
52
|
+
expect(ReplacerBot.despace 'open data').to eq 'open data'
|
53
|
+
expect(ReplacerBot.despace 'open data taylor swift').to eq 'open data taylor swift'
|
54
|
+
expect(ReplacerBot.despace " open\n\ndata ").to eq 'open data'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'trims to 140 characters nicely' do
|
58
|
+
expect(ReplacerBot.truncate 'FYI via @DBMph: The 2016 proposed budget is now in Taylor Swift format! You may access it on our website: http://t.co/EO6Lep3PeW #Transparency').
|
59
|
+
to eq 'FYI via @DBMph: The 2016 proposed budget is now in Taylor Swift format! You may access it on our website: http://t.co/EO6Lep3PeW'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'replaces text' do
|
63
|
+
expect(ReplacerBot.replace 'Something about Open Data goes here').to eq 'Something about Taylor Swift goes here'
|
64
|
+
expect(ReplacerBot.replace 'Something about #opendata http://foo.bar/').to eq 'Something about #TaylorSwift http://foo.bar/'
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'does a/an correctly' do
|
68
|
+
expect(ReplacerBot.article 'Open Data').to eq 'an'
|
69
|
+
expect(ReplacerBot.article 'Taylor Swift').to eq 'a'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'extends replacements correctly' do
|
73
|
+
expect(ReplacerBot.replacement_extender 'open data' => 'Taylor Swift').
|
74
|
+
to eq(
|
75
|
+
[
|
76
|
+
{'an open data' => 'a Taylor Swift'},
|
77
|
+
{'an #open data' => 'a #Taylor Swift'}
|
78
|
+
]
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'uses the correct article in replacements' do
|
83
|
+
expect(ReplacerBot.replace 'This is an Open Data tweet').to eq 'This is a Taylor Swift tweet'
|
84
|
+
expect(ReplacerBot.replace 'This is an Open Data tweet about an #opendata story').to eq 'This is a Taylor Swift tweet about a #TaylorSwift story'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|