balinterdi-twuckoo 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,5 @@
1
+ v0.2 Wikipedia TFA module, command line argument decides which file to include
2
+ v0.1.3 Length of sleeping interval settable from config
3
+ v0.1.2 Sleeping interval set with duration-string
4
+ v0.1.1 Removing unnecessary gem requires and config files
5
+ v0.1 Initial release: can tweet from a file.
data/Manifest ADDED
@@ -0,0 +1,18 @@
1
+ bin/twuckoo
2
+ CHANGELOG
3
+ lib/duration_string.rb
4
+ lib/environments.rb
5
+ lib/modules/one_line_from_file.rb
6
+ lib/modules/wikipedia_tfa.rb
7
+ lib/twuckoo.rb
8
+ Manifest
9
+ Rakefile
10
+ README.markdown
11
+ spec/duration_string_spec.rb
12
+ spec/one_line_from_file_spec.rb
13
+ spec/spec.opts
14
+ spec/spec_helper.rb
15
+ spec/twuckoo_spec.rb
16
+ spec/wikipedia_tfa_spec.rb
17
+ tasks/spec.rake
18
+ twuckoo.gemspec
data/README.markdown ADDED
@@ -0,0 +1,4 @@
1
+ # Twuckoo
2
+
3
+ Need to tweet periodically and in an automated fashion? Cuckoo twitterer is for you.
4
+
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('twuckoo', '0.2.1') do |p|
6
+ p.description = "A simple yet elegant solution to tweet a message regularly from a file (and in the future: from a webpage, a database, etc.)"
7
+ p.url = "http://github.com/balinterdi/twuckoo"
8
+ p.author = "Bálint Érdi"
9
+ p.email = "balint@bucionrails.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*", "*.txt", "pkg"]
11
+ p.runtime_dependencies = ["twibot >=0.1.7"]
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
15
+
data/bin/twuckoo ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ require File.join(dir, 'twuckoo')
6
+
7
+ Dir.glob(File.join(dir, 'modules', '*.rb')).each do |mod|
8
+ require mod
9
+ end
10
+
11
+ module_to_include = case ARGV.first.downcase
12
+ when "from_file"
13
+ OneLineFromFile
14
+ when "file"
15
+ OneLineFromFile
16
+ when "wikipedia_tfa"
17
+ WikipediaTFA
18
+ else
19
+ raise "No module to include was provided."
20
+ end
21
+
22
+ Twuckoo.send(:include, module_to_include)
23
+ @cuckoo = Twuckoo.new
24
+ # @cuckoo.set_testing
25
+ @cuckoo.run
@@ -0,0 +1,12 @@
1
+ module DurationString
2
+ class << self
3
+ MULTIPLIERS = { "s" => 1, "m" => 60, "h" => 60 * 60, "d" => 60 * 60 * 24, "w" => 60 * 60 * 24 * 7 }
4
+ def to_seconds(duration)
5
+ duration.scan(/(\d+)([smhdw])/).inject(0) do |seconds, match|
6
+ num, dur_chr = match
7
+ multiplier = MULTIPLIERS[dur_chr]
8
+ seconds + num.to_i * multiplier
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module TwuckooEnvironment
2
+ def set_testing
3
+ ENV["CUCKOO_ENV"] = "testing"
4
+ end
5
+ def testing?
6
+ ENV["CUCKOO_ENV"] == "testing"
7
+ end
8
+ end
@@ -0,0 +1,70 @@
1
+ module OneLineFromFile
2
+ # read all lines from the file that contains the strategies
3
+ # select the strategies that are not used yet
4
+ # pick a random strategy
5
+
6
+ # store used strategies in a file with (store the md5 sum of the strategies' text)
7
+ attr_reader :lines
8
+
9
+ LINES_FILE = 'lines.txt'
10
+ USED_LINES_FILE = 'used_lines.txt'
11
+
12
+ def initialize
13
+ @lines = []
14
+ # load_lines
15
+ end
16
+
17
+ def load_tweets
18
+ load_lines
19
+ end
20
+
21
+ def get_lines_from_file
22
+ begin
23
+ IO::readlines(LINES_FILE).map { |line| line.chomp }
24
+ rescue Errno::ENOENT
25
+ []
26
+ end
27
+ end
28
+
29
+ def get_all_lines
30
+ @fresh_lines ||= get_lines_from_file
31
+ end
32
+
33
+ def get_used_lines_from_file
34
+ begin
35
+ IO::readlines(USED_LINES_FILE).map { |line| line.chomp }
36
+ rescue Errno::ENOENT
37
+ []
38
+ end
39
+ end
40
+
41
+ def get_used_lines
42
+ @used_lines ||= get_used_lines_from_file
43
+ end
44
+
45
+ def load_lines
46
+ used = get_used_lines
47
+ unused_lines = get_all_lines.select { |line| !used.include?(line) }
48
+ add_lines(*unused_lines)
49
+ end
50
+
51
+ def add_lines(*new_lines)
52
+ @lines.concat(new_lines)
53
+ end
54
+
55
+ def pick
56
+ rand(lines.length)
57
+ end
58
+
59
+ def store(line)
60
+ open(USED_LINES_FILE, "a") do |file|
61
+ file.write(line + "\n")
62
+ end
63
+ end
64
+
65
+ def next
66
+ @lines.delete_at(pick)
67
+ end
68
+
69
+ end
70
+
@@ -0,0 +1,24 @@
1
+ require "open-uri"
2
+ require "hpricot"
3
+
4
+ module WikipediaTFA
5
+
6
+ WIKIPEDIA_HOST = "http://en.wikipedia.org"
7
+
8
+ def load_tweets
9
+ end
10
+
11
+ def store(line)
12
+ end
13
+
14
+ def get_wikipedia_main_page
15
+ Hpricot(open("#{WIKIPEDIA_HOST}/wiki/Main_Page"))
16
+ end
17
+
18
+ def next
19
+ doc = get_wikipedia_main_page
20
+ tfa = doc.at("#mp-tfa p b a")
21
+ tfa_link = WIKIPEDIA_HOST + tfa["href"]
22
+ "#{tfa.inner_html}: #{tfa_link}"
23
+ end
24
+ end
data/lib/twuckoo.rb ADDED
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require File.join(File.dirname(__FILE__), 'environments')
3
+ require File.join(File.dirname(__FILE__), 'duration_string')
4
+ require 'twibot'
5
+
6
+ class Twuckoo
7
+ include TwuckooEnvironment
8
+ # the idea is to include a module with a well-defined API with three methods:
9
+ # - load_tweets
10
+ # - next
11
+ # - store(tweet)
12
+ attr_accessor :time_to_sleep
13
+
14
+ def initialize
15
+ @time_to_sleep = "1d"
16
+ super
17
+ end
18
+
19
+ def tweet
20
+ next_tweet = self.next
21
+ unless next_tweet.nil?
22
+ store(next_tweet)
23
+ if testing?
24
+ puts "(test) Tweeting #{next_tweet}"
25
+ else
26
+ twitter.status(:post, next_tweet)
27
+ end
28
+ end
29
+ next_tweet
30
+ end
31
+
32
+ def get_config_values_from_file
33
+ begin
34
+ open('config/cuckoo.yml', 'r') do |f|
35
+ YAML.load(f.read)
36
+ end
37
+ rescue
38
+ {}
39
+ end
40
+ end
41
+
42
+ def setup
43
+ get_config_values_from_file.each_pair do |attr, value|
44
+ self.send("#{attr}=".to_sym, value)
45
+ end
46
+ end
47
+
48
+ def relax
49
+ seconds_to_sleep = DurationString.to_seconds(time_to_sleep)
50
+ sleep(seconds_to_sleep)
51
+ end
52
+
53
+ def run
54
+ setup
55
+ load_tweets
56
+ loop do
57
+ tweeted = tweet
58
+ quit if tweeted.nil?
59
+ relax
60
+ end
61
+ end
62
+
63
+ def quit
64
+ exit
65
+ end
66
+ end
@@ -0,0 +1,30 @@
1
+ require "spec"
2
+ dir = File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require File.join(dir, 'duration_string')
4
+
5
+ describe "a string representing a duration" do
6
+ it "gives back the number of seconds for seconds" do
7
+ DurationString.to_seconds("17s").should == 17
8
+ end
9
+
10
+ it "gives back the number of seconds for dur. strings with only minutes defined" do
11
+ DurationString.to_seconds("7m").should == 7 * 60
12
+ end
13
+
14
+ it "gives back the number of seconds for hours for dur. strings with only hours defined" do
15
+ DurationString.to_seconds("4h").should == 60 * 60 * 4
16
+ end
17
+
18
+ it "gives back the number of seconds for hours for dur. strings with only days defined" do
19
+ DurationString.to_seconds("2d").should == 60 * 60 * 24 * 2
20
+ end
21
+
22
+ it "gives back the number of seconds for hours for dur. strings with only weeks defined" do
23
+ DurationString.to_seconds("3w").should == 60 * 60 * 24 * 7 * 3
24
+ end
25
+
26
+ it "gives back the number of seconds for a dur. string that combines several dur. characters" do
27
+ DurationString.to_seconds("1d3h18m22s").should == (60 * 60 * 24 * 1) + (60 * 60 * 3) + (60 * 18) + 22
28
+ end
29
+
30
+ end
@@ -0,0 +1,105 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require File.join(dir, 'modules', 'one_line_from_file')
5
+
6
+ # use mocha for mocking instead of
7
+ # Rspec's own mock framework
8
+ Spec::Runner.configure do |config|
9
+ config.mock_with :mocha
10
+ end
11
+
12
+ class TwuckooWithOneLineFromFileSpec
13
+
14
+ extend TwuckooEnvironment
15
+ set_testing
16
+
17
+ describe "A cuckoo twitterer with one line from a file" do
18
+ before do
19
+ Twuckoo.send(:include, OneLineFromFile)
20
+ @cuckoo = Twuckoo.new
21
+ # just so that no files will be written
22
+ @cuckoo.stubs(:store).returns(nil)
23
+ end
24
+
25
+ it "stores a line that was sent to it correctly" do
26
+ @cuckoo.lines.should be_empty
27
+ @cuckoo.add_lines("I am happy", "I am sad")
28
+ @cuckoo.lines.should == ["I am happy", "I am sad"]
29
+ end
30
+
31
+ it "loads all the lines in the file when sent the load_tweets message" do
32
+ lines = ["I am happy", "I am sad", "I am thrilled", "I am bored"]
33
+ @cuckoo.expects(:get_lines_from_file).returns(lines)
34
+ @cuckoo.load_tweets
35
+ @cuckoo.lines.should == lines
36
+ end
37
+
38
+ describe "when it tweeted a line already" do
39
+ before do
40
+ @cuckoo.add_lines("I am happy", "I am sad", "I am thrilled", "I am bored")
41
+ @cuckoo.stubs(:pick).returns(0)
42
+ @cuckoo.tweet
43
+ end
44
+
45
+ it "it removes it" do
46
+ @cuckoo.lines.should == ["I am sad", "I am thrilled", "I am bored"]
47
+ end
48
+
49
+ it "stores it" do
50
+ @cuckoo.stubs(:pick).returns(0)
51
+ @cuckoo.expects(:store).with("I am sad")
52
+ @cuckoo.tweet
53
+ end
54
+
55
+ it "it picks an unused line to tweet next" do
56
+ next_pick = @cuckoo.next
57
+ ["I am sad", "I am thrilled", "I am bored"].should include(next_pick)
58
+ end
59
+ end
60
+
61
+ it "tweets all the available lines in as many 'rounds' as there are lines" do
62
+ lines = ["I am happy", "I am sad", "I am thrilled", "I am bored"]
63
+ @cuckoo.add_lines(*lines)
64
+ lines.length.times { @cuckoo.tweet }
65
+ @cuckoo.lines.should be_empty
66
+ end
67
+
68
+ it "only reads the file to load lines from the first time around" do
69
+ pending
70
+ @cuckoo.stubs(:get_used_lines_from_file).returns([])
71
+ @cuckoo.expects(:get_lines_from_file).returns(["I am happy", "I am sad", "I am thrilled", "I am bored"])
72
+ 2.times { @cuckoo.load_lines }
73
+ end
74
+
75
+ it "only reads the file to load used lines from the first time around" do
76
+ pending
77
+ @cuckoo.stubs(:get_lines_from_file).returns(["I am happy", "I am sad", "I am thrilled", "I am bored"])
78
+ @cuckoo.expects(:get_used_lines_from_file).returns([])
79
+ 2.times { @cuckoo.load_lines }
80
+ end
81
+
82
+ describe "when loading lines to use" do
83
+ before do
84
+ @cuckoo.stubs(:get_lines_from_file).returns(["I am happy", "I am sad", "I am thrilled", "I am bored"])
85
+ @cuckoo.stubs(:get_used_lines_from_file).returns([])
86
+ end
87
+
88
+ it "loads the available ones" do
89
+ @cuckoo.load_lines
90
+ @cuckoo.lines.should == ["I am happy", "I am sad", "I am thrilled", "I am bored"]
91
+ end
92
+
93
+ describe "when having used ones from a previous run" do
94
+ before do
95
+ @cuckoo.stubs(:get_used_lines_from_file).returns(["I am happy", "I am sad"])
96
+ @cuckoo.load_lines
97
+ end
98
+ it "should not pick those used lines" do
99
+ @cuckoo.lines.should == ["I am thrilled", "I am bored"]
100
+ end
101
+ end
102
+ end
103
+
104
+ end
105
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --loadby random
3
+ --format progress
4
+ --backtrace
5
+ --debugger
@@ -0,0 +1,10 @@
1
+ require "spec"
2
+ require "mocha"
3
+
4
+ dir = File.join(File.dirname(__FILE__), '..', 'lib')
5
+ require File.join(dir, 'twuckoo')
6
+ require File.join(dir, 'environments')
7
+
8
+ Spec::Runner.configure do |config|
9
+ config.mock_with :mocha
10
+ end
@@ -0,0 +1,44 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ class TwuckooSpec
4
+ extend TwuckooEnvironment
5
+ set_testing
6
+
7
+ describe "A twuckoo" do
8
+ before do
9
+ @cuckoo = Twuckoo.new
10
+ end
11
+
12
+ it "responds to tweet" do
13
+ @cuckoo.should respond_to(:tweet)
14
+ end
15
+
16
+ it "waits 1 day between tweets by default" do
17
+ @cuckoo.time_to_sleep.should == "1d"
18
+ end
19
+
20
+ describe "loading values from the config file" do
21
+ it "sets the time interval to wait b/w tweets correctly" do
22
+ @cuckoo.expects(:get_config_values_from_file).returns({ :time_to_sleep => "3m" })
23
+ @cuckoo.setup
24
+ @cuckoo.time_to_sleep.should == "3m"
25
+ end
26
+ end
27
+
28
+ describe "when there is nothing to tweet" do
29
+ before do
30
+ @cuckoo.stubs(:next).returns(nil)
31
+ @cuckoo.stubs(:load_tweets).returns(nil)
32
+ end
33
+ it "does not call store" do
34
+ @cuckoo.expects(:store).never
35
+ @cuckoo.tweet
36
+ end
37
+ it "quits" do
38
+ pending
39
+ @cuckoo.expects(:quit).once
40
+ @cuckoo.run
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require File.join(dir, 'modules', 'wikipedia_tfa')
5
+
6
+ class TwuckooForWikipediaTfaSpec
7
+
8
+ extend TwuckooEnvironment
9
+ set_testing
10
+
11
+ describe "A cuckoo twitterer for wikipedia featured article" do
12
+ before do
13
+ Twuckoo.send(:include, WikipediaTFA)
14
+ @cuckoo = Twuckoo.new
15
+ end
16
+ it "works" do
17
+ @cuckoo.tweet
18
+ end
19
+ end
20
+ end
data/tasks/spec.rake ADDED
@@ -0,0 +1,11 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "spec/rake/spectask"
4
+
5
+ ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
6
+
7
+ desc "Run all specs"
8
+ Spec::Rake::SpecTask.new(:spec) do |t|
9
+ t.spec_opts << '--options' << ROOT + '/spec/spec.opts'
10
+ t.spec_files = Dir.glob('spec/**/*_spec.rb').map { |f| f.to_s }
11
+ end
data/twuckoo.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{twuckoo}
5
+ s.version = "0.2.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["B\303\241lint \303\211rdi"]
9
+ s.date = %q{2009-06-16}
10
+ s.default_executable = %q{twuckoo}
11
+ s.description = %q{A simple yet elegant solution to tweet a message regularly from a file (and in the future: from a webpage, a database, etc.)}
12
+ s.email = %q{balint@bucionrails.com}
13
+ s.executables = ["twuckoo"]
14
+ s.extra_rdoc_files = ["bin/twuckoo", "CHANGELOG", "lib/duration_string.rb", "lib/environments.rb", "lib/modules/one_line_from_file.rb", "lib/modules/wikipedia_tfa.rb", "lib/twuckoo.rb", "README.markdown", "tasks/spec.rake"]
15
+ s.files = ["bin/twuckoo", "CHANGELOG", "lib/duration_string.rb", "lib/environments.rb", "lib/modules/one_line_from_file.rb", "lib/modules/wikipedia_tfa.rb", "lib/twuckoo.rb", "Manifest", "Rakefile", "README.markdown", "spec/duration_string_spec.rb", "spec/one_line_from_file_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/twuckoo_spec.rb", "spec/wikipedia_tfa_spec.rb", "tasks/spec.rake", "twuckoo.gemspec"]
16
+ s.homepage = %q{http://github.com/balinterdi/twuckoo}
17
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Twuckoo", "--main", "README.markdown"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{twuckoo}
20
+ s.rubygems_version = %q{1.3.3}
21
+ s.summary = %q{A simple yet elegant solution to tweet a message regularly from a file (and in the future: from a webpage, a database, etc.)}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<twibot>, [">= 0.1.7"])
29
+ else
30
+ s.add_dependency(%q<twibot>, [">= 0.1.7"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<twibot>, [">= 0.1.7"])
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: balinterdi-twuckoo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - "B\xC3\xA1lint \xC3\x89rdi"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-16 00:00:00 -07:00
13
+ default_executable: twuckoo
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: twibot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.1.7
24
+ version:
25
+ description: "A simple yet elegant solution to tweet a message regularly from a file (and in the future: from a webpage, a database, etc.)"
26
+ email: balint@bucionrails.com
27
+ executables:
28
+ - twuckoo
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - bin/twuckoo
33
+ - CHANGELOG
34
+ - lib/duration_string.rb
35
+ - lib/environments.rb
36
+ - lib/modules/one_line_from_file.rb
37
+ - lib/modules/wikipedia_tfa.rb
38
+ - lib/twuckoo.rb
39
+ - README.markdown
40
+ - tasks/spec.rake
41
+ files:
42
+ - bin/twuckoo
43
+ - CHANGELOG
44
+ - lib/duration_string.rb
45
+ - lib/environments.rb
46
+ - lib/modules/one_line_from_file.rb
47
+ - lib/modules/wikipedia_tfa.rb
48
+ - lib/twuckoo.rb
49
+ - Manifest
50
+ - Rakefile
51
+ - README.markdown
52
+ - spec/duration_string_spec.rb
53
+ - spec/one_line_from_file_spec.rb
54
+ - spec/spec.opts
55
+ - spec/spec_helper.rb
56
+ - spec/twuckoo_spec.rb
57
+ - spec/wikipedia_tfa_spec.rb
58
+ - tasks/spec.rake
59
+ - twuckoo.gemspec
60
+ has_rdoc: false
61
+ homepage: http://github.com/balinterdi/twuckoo
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --line-numbers
65
+ - --inline-source
66
+ - --title
67
+ - Twuckoo
68
+ - --main
69
+ - README.markdown
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ version:
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: "1.2"
83
+ version:
84
+ requirements: []
85
+
86
+ rubyforge_project: twuckoo
87
+ rubygems_version: 1.2.0
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: "A simple yet elegant solution to tweet a message regularly from a file (and in the future: from a webpage, a database, etc.)"
91
+ test_files: []
92
+