replacer_bot 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +23 -0
  7. data/LICENSE.md +22 -0
  8. data/README.md +7 -0
  9. data/Rakefile +10 -0
  10. data/bin/replacer +4 -0
  11. data/config/defaults.yml +6 -0
  12. data/features/replacer.feature +5 -0
  13. data/features/support/env.rb +2 -0
  14. data/lib/replacer_bot.rb +16 -0
  15. data/lib/replacer_bot/cli.rb +17 -0
  16. data/lib/replacer_bot/config.rb +31 -0
  17. data/lib/replacer_bot/helpers.rb +93 -0
  18. data/lib/replacer_bot/replacer.rb +40 -0
  19. data/lib/replacer_bot/twitter_client.rb +14 -0
  20. data/lib/replacer_bot/version.rb +3 -0
  21. data/replacer_bot.gemspec +35 -0
  22. data/spec/lib/replacer_bot/config_spec.rb +9 -0
  23. data/spec/lib/replacer_bot/helpers_spec.rb +88 -0
  24. data/spec/lib/replacer_bot/replacer_spec.rb +70 -0
  25. data/spec/lib/replacer_bot/twitter_client_spec.rb +7 -0
  26. data/spec/spec_helper.rb +14 -0
  27. data/spec/support/vcr_setup.rb +19 -0
  28. data/spec/vcr/ReplacerBot_Replacer/only_find_new_tweets/finds_new_tweets.yml +1202 -0
  29. data/spec/vcr/ReplacerBot_Replacer/only_find_new_tweets/finds_newer_tweets.yml +1349 -0
  30. data/spec/vcr/ReplacerBot_Replacer/save_and_retrieve/saves_the_ID_of_the_last_tweet.yml +1344 -0
  31. data/spec/vcr/ReplacerBot_Replacer/save_and_retrive/saves_the_ID_of_the_last_tweet.yml +1345 -0
  32. data/spec/vcr/ReplacerBot_Replacer/save_last_tweet/only_saves_if_there_is_something_to_save.yml +1381 -0
  33. data/spec/vcr/ReplacerBot_Replacer/save_last_tweet/saves_the_ID_of_the_last_tweet.yml +1390 -0
  34. data/spec/vcr/ReplacerBot_Replacer/search/finds_the_correct_tweets.yml +1202 -0
  35. data/spec/vcr/ReplacerBot_Replacer/search/finds_tweets.yml +1202 -0
  36. data/spec/vcr/ReplacerBot_Replacer/search/saves_the_text_of_its_tweets.yml +1178 -0
  37. data/spec/vcr/ReplacerBot_Replacer/search/searches_for_tweets.yml +1191 -0
  38. data/spec/vcr/ReplacerBot_Replacer/search/uniqs_its_tweets.yml +2353 -0
  39. data/spec/vcr/ReplacerBot_Replacer/tweet/prepares_sensible_tweets.yml +1178 -0
  40. 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
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ .env
17
+ last.tweet
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format documentation
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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in replacer_bot.gemspec
4
+ gemspec
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
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'cucumber/rake/task'
4
+ require 'coveralls/rake/task'
5
+
6
+ Coveralls::RakeTask.new
7
+ RSpec::Core::RakeTask.new
8
+ Cucumber::Rake::Task.new
9
+
10
+ task :default => [:spec, 'coveralls:push']
data/bin/replacer ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'replacer_bot/cli'
4
+ ReplacerBot::CLI.start
@@ -0,0 +1,6 @@
1
+ search_term: open data
2
+ save_file: last.tweet
3
+ replacements:
4
+ - open data: Taylor Swift
5
+ - opendata: TaylorSwift
6
+ interval: 60 #seconds
@@ -0,0 +1,5 @@
1
+ Feature: Replacer
2
+
3
+ Scenario: Show version
4
+ When I successfully run `replacer version`
5
+ Then the output should contain "replacer version "
@@ -0,0 +1,2 @@
1
+ require 'aruba/cucumber'
2
+ require 'cucumber/rspec/doubles'
@@ -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,3 @@
1
+ module ReplacerBot
2
+ VERSION = "0.0.2"
3
+ 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,9 @@
1
+ module ReplacerBot
2
+ describe Config do
3
+ let(:conf) { ReplacerBot::Config.instance.config }
4
+
5
+ it 'has defaults' do
6
+ expect(conf['search_term']).to eq 'open data'
7
+ end
8
+ end
9
+ 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