lazybird 0.1.0

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/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Lazybird (Beta)
2
+
3
+ [![Gem Version](https://img.shields.io/badge/lazybird-v0.1.0beta-orange.svg)][gem]
4
+
5
+ [gem]: https://rubygems.org/gems/lazybird
6
+
7
+ Twitter for busy people.
8
+
9
+ ## Installation
10
+
11
+ Register at https://apps.twitter.com/app/new
12
+
13
+ Example:
14
+
15
+ ![](http://i.imgsafe.org/fbf19e8.png)
16
+
17
+ Then click on keys and access tokens and generate an access token. You will need this for the setup.
18
+
19
+
20
+ Install lazybird running:
21
+
22
+ $ gem install lazybird
23
+
24
+ ## Setup
25
+
26
+ Once lazybird is installed you can run it with:
27
+
28
+ `lazybird`
29
+
30
+ or
31
+
32
+ `bundle exec lazybird`
33
+
34
+ The CLI should appear:
35
+
36
+ ![](http://i.imgsafe.org/bdeff99.png)
37
+
38
+
39
+ Typically you want to setup the database first running `setup`
40
+
41
+ And run config to enter your twitter settings: `config consumer_key consumer_secret access_token access_token_secret`
42
+
43
+ ## Usage
44
+
45
+ Run it with `lazybird` - you would need to keep the app running as long as you want to tweet automatically.
46
+
47
+ Lazybird contains (at the moment) only two tasks that run at a certain configured time:
48
+
49
+
50
+ _retweet_random_: Retweets a random tweet (latest) from a random friend
51
+
52
+ _tweet_storm_: Tweets a random quote from the Storm API http://quotes.stormconsultancy.co.uk
53
+
54
+
55
+ Add them both to your list of tasks (this will store them in an internal DB to resume later)
56
+
57
+ `add retweet_random`
58
+
59
+ `add tweet_storm`
60
+
61
+ Then you want to either randomly tweet something now with `run now` or schedule it to tweet every N minutes/hours/day:s `run 2h` or `run 30m` for example.
62
+
63
+ You will need to keep the command line open and you should see an update everytime something random gets tweeted.
64
+
65
+ Lazybird stores a DB/config file at ~/.twitter.db - make sure it's safe.
66
+
67
+
68
+ ## Contributing
69
+
70
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bluegod/lazybird.
71
+
72
+ ## License
73
+
74
+ GPL v2
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "lazybird"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/lazybird ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "lazybird"
5
+ require "lazybird/cli/command_line"
6
+
7
+ Lazybird::Cli::CommandLine.new
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
data/lazybird.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lazybird/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'lazybird'
8
+ spec.version = Lazybird::VERSION
9
+ spec.authors = ['James Lopez']
10
+ spec.email = ['james@jameslopez.es']
11
+ spec.license = 'GPL-2.0'
12
+
13
+ spec.summary = %q{Twitter for lazy people. Automatically tweets/retweets random stuff. }
14
+ spec.description = %q{Provides a command line interface to interact with twitter and automatically tweets/retweets some predefined (or API based tweets) at a specified frequency. }
15
+ spec.homepage = "https://github.com/bluegod/lazybird"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "bin"
19
+ spec.executables = ['lazybird']
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.3"
25
+ spec.add_dependency 'twitter', '~> 5.15'
26
+ spec.add_dependency 'rufus-scheduler', '~> 3.1'
27
+ spec.add_dependency 'amalgalite', '~> 1.4'
28
+ spec.add_dependency 'sequel', '~> 4.27'
29
+ spec.add_dependency 'colorize', '~> 0.7'
30
+ end
@@ -0,0 +1,6 @@
1
+ retweet_random:
2
+ desc: 'Retweets a random tweet (latest) from a random friend'
3
+ class: Lazybird::Tasks::RetweetRandomTask
4
+ tweet_storm:
5
+ desc: 'Tweets a random quote from the Storm API http://quotes.stormconsultancy.co.uk'
6
+ class: Lazybird::Tasks::StormQuoteTask
data/lib/lazybird.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'lazybird/version'
2
+ require 'lazybird/config'
3
+ module Lazybird
4
+
5
+ end
@@ -0,0 +1,64 @@
1
+ require 'colorize'
2
+ require 'lazybird/version'
3
+ require 'lazybird/lazybird_facade'
4
+ require 'lazybird/cli/commands'
5
+ require 'rbconfig'
6
+
7
+ module Lazybird
8
+ module Cli
9
+ class CommandLine
10
+ include Lazybird::Cli::Commands
11
+
12
+ def initialize
13
+ @facade = Lazybird::LazybirdFacade.new
14
+ intro.display
15
+ setup_check
16
+ run_main_loop
17
+ end
18
+
19
+ private
20
+
21
+ def setup_check
22
+ if Lazybird::Config.db_file_exists?
23
+ @facade.load_default_tasks
24
+ else
25
+ puts 'Type: '.bold + "setup \u{23ce}".red.bold + " as this is the first time running the app.\n".bold
26
+ end
27
+ end
28
+
29
+ def run_main_loop
30
+ loop do
31
+ display_prompt
32
+ command, *params = gets.chomp.split /\s/
33
+ process_command(command, params) if command
34
+ end
35
+ end
36
+
37
+ def newline
38
+ puts
39
+ end
40
+
41
+ def process_command(command, params)
42
+ command.downcase!
43
+ if respond_to?(command)
44
+ send(command, params)
45
+ else
46
+ puts 'Invalid command'.light_red
47
+ end
48
+ end
49
+
50
+ def display_prompt
51
+ prompt.yellow.display
52
+ end
53
+
54
+ def prompt
55
+ @_prompt ||=
56
+ begin
57
+ os = RbConfig::CONFIG['host_os']
58
+ icon = os.start_with?('darwin') ? "\u{1F425}" : ')<'
59
+ "#{icon} Lazybird> "
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,88 @@
1
+ module Lazybird
2
+ module Cli
3
+ module Commands
4
+
5
+ def config(params)
6
+ @facade.config(params)
7
+ display_done
8
+ end
9
+
10
+ def setup(params)
11
+ @facade.init
12
+ display_done
13
+ end
14
+
15
+ def add(params)
16
+ @facade.add_task params.first
17
+ display_done
18
+ end
19
+
20
+ def my_tasks(params)
21
+ @facade.current_tasks.join("\n").green.display
22
+ newline
23
+ end
24
+
25
+ def rem(params)
26
+ @facade.rem_task(params.first)
27
+ display_done
28
+ end
29
+
30
+ def run(params)
31
+ cursor = -> () do
32
+ display_prompt
33
+ end
34
+ @facade.run_tasks(params, &cursor)
35
+ end
36
+
37
+ def my_run(params)
38
+ @facade.run_info.green.display
39
+ newline
40
+ end
41
+
42
+ def exit(params)
43
+ Kernel.exit(true)
44
+ end
45
+
46
+ def intro
47
+ "Lazybird v#{Lazybird.version}\n".light_yellow +
48
+ "by James Lopez <http://jameslopez.net> <https://github.com/bluegod/lazybird>\n".blue +
49
+ 'Type: ' + "help \u{23ce}".bold + " for a list of commands.\n"
50
+ end
51
+
52
+ def help(params)
53
+ begin
54
+ "List of available commands: \n".yellow +
55
+ "config ".bold + "consumer_key consumer_secret access_token access_token_secret".green + " \u{23ce} \n".white +
56
+ "Configures twitter account (Should be the first step!)\n" +
57
+ "tasks \u{23ce} \n".bold +
58
+ "Displays a list of available tasks \n" +
59
+ "my_tasks".bold + " \u{23ce} \n" +
60
+ "Displays a list of your selected tasks \n" +
61
+ "add ".bold + "task".green + " \u{23ce} \n".white +
62
+ "Adds a task to be randomly tweeted\n" +
63
+ "rem ".bold + "task".green + " \u{23ce} \n".white +
64
+ "Removes a task from your list\n" +
65
+ "run ".bold + "time".green + " \u{23ce} \n".white +
66
+ "Sets how frequent we tweet (Ex: run 3h or run 1d or run 30m)\n" +
67
+ "my_run ".bold + " \u{23ce} \n" +
68
+ "Displays the current frequency of tweets \n" +
69
+ "setup \u{23ce} \n".bold +
70
+ "setups the app for the first time \n" +
71
+ "exit \u{23ce} \n".bold +
72
+ "Exits the app \n"
73
+ end.display
74
+ end
75
+
76
+ def tasks(params)
77
+ @facade.tasks.each do |k, v|
78
+ puts "#{k}:".bold + " #{v['desc']}".green
79
+ end
80
+ end
81
+
82
+ def display_done
83
+ 'done!'.green.display
84
+ newline
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,37 @@
1
+ require 'twitter'
2
+ require 'yaml'
3
+ require 'lazybird/db'
4
+
5
+ module Lazybird
6
+ module Config
7
+ extend self
8
+
9
+ def client
10
+ @_client ||= Twitter::REST::Client.new do |config|
11
+ config.consumer_key = db_config[:consumer_key]
12
+ config.consumer_secret = db_config[:consumer_secret]
13
+ config.access_token = db_config[:access_token]
14
+ config.access_token_secret = db_config[:access_token_secret]
15
+ end
16
+ end
17
+
18
+ def tasks
19
+ @_tasks ||= YAML::load_file('./lib/config/tasks.yml')
20
+ end
21
+
22
+ def db_file
23
+ "#{Dir.home}/.twitter.db"
24
+ end
25
+
26
+ def db_file_exists?
27
+ File.file? db_file
28
+ end
29
+
30
+ private
31
+
32
+ def db_config
33
+ #TODO: nice to have - this should go to the DB if a new config is saved.
34
+ @_config ||= Lazybird::Db.config
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,84 @@
1
+ require 'sequel'
2
+ require 'lazybird/tasks/task'
3
+ require 'lazybird/utils'
4
+ require 'lazybird/config'
5
+ module Lazybird
6
+ module Db
7
+ extend self
8
+
9
+ #TODO: refactor this. This is a quick & dirty way to create the DB
10
+ def self.init
11
+ db.transaction do
12
+ db.create_table :config do
13
+ primary_key :id
14
+ String :name, :unique => true, :null => false
15
+ String :consumer_key, :null => false
16
+ String :consumer_secret, :null => false
17
+ String :access_token, :null => false
18
+ String :access_token_secret, :null => false
19
+ end
20
+
21
+ db.create_table :tweets do
22
+ primary_key :id
23
+ String :text, :unique => true, :null => false
24
+ DateTime :created_at
25
+ end
26
+
27
+ db.create_table :tasks do
28
+ primary_key :id
29
+ String :command, :unique => true, :null => false
30
+ String :options
31
+ DateTime :created_at
32
+ end
33
+ end
34
+ end
35
+
36
+ def save_tweet!(text:)
37
+ db[:tweets].insert(text: text, created_at: DateTime.now)
38
+ end
39
+
40
+ # TODO: Ideally we should have different configs, perhaps per twitter user
41
+ # for now, let's just delete every time we save a new one.
42
+ def save_config!(config)
43
+ db[:config].delete
44
+ db[:config].insert(config.merge(name: 'default'))
45
+ end
46
+
47
+ def config
48
+ db[:config].first
49
+ end
50
+
51
+ def save_task!(task)
52
+ task_hash = {command: task.command,
53
+ created_at: DateTime.now}
54
+ task_hash.merge!(options: task.opts) if !task.opts.empty?
55
+ db[:tasks].insert(Lazybird::Utils::Hash.compact(task_hash))
56
+ end
57
+
58
+ def rem_task!(task_command)
59
+ db[:tasks].where('command = ?', task_command).delete
60
+ end
61
+
62
+ def list_tasks
63
+ db[:tasks].select(:command)
64
+ end
65
+
66
+ def tasks
67
+ db[:tasks].all.map do |task|
68
+ found = Lazybird::Utils::Hash.find_by_key(Lazybird::Config.tasks, task[:command])
69
+ unless found.empty?
70
+ task_found(task[:command], found).new(command: task[:command],
71
+ options: found[:options])
72
+ end
73
+ end
74
+ end
75
+
76
+ def task_found(task_name, found)
77
+ Object.const_get(found[task_name]['class'])
78
+ end
79
+
80
+ def db
81
+ @_db ||= Sequel.amalgalite(Lazybird::Config.db_file)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,86 @@
1
+ require 'lazybird/config'
2
+ require 'lazybird/db'
3
+ require 'lazybird/utils'
4
+ require 'lazybird/tasks/storm_quote_task'
5
+ require 'lazybird/tasks/retweet_random_task'
6
+ require 'lazybird/tasks/task_scheduler'
7
+
8
+ module Lazybird
9
+ #TODO: split this file
10
+ class LazybirdFacade
11
+
12
+ attr_reader :tasks
13
+
14
+ def initialize
15
+ @current_tasks = Set.new
16
+ @tasks = Lazybird::Config.tasks
17
+ end
18
+
19
+ def add_task(task_name)
20
+ # TODO refactor this method
21
+ found = Lazybird::Utils::Hash.find_by_key(@tasks, task_name)
22
+ if found
23
+ task = Object.const_get(found[task_name]['class']).new(command: task_name)
24
+ begin
25
+ Lazybird::Db.save_task!(task)
26
+ rescue Sequel::UniqueConstraintViolation
27
+ puts 'Task added already'.light_red
28
+ end
29
+ @current_tasks << task
30
+ end
31
+ end
32
+
33
+ def rem_task(task_name)
34
+ Lazybird::Db.rem_task!(task_name)
35
+ @current_tasks.delete_if { |t| t.command == task_name }
36
+ end
37
+
38
+ def current_tasks
39
+ @current_tasks.map { |t| t.command }
40
+ end
41
+
42
+ def load_default_tasks
43
+ @current_tasks.merge(Lazybird::Db.tasks)
44
+ end
45
+
46
+ def init
47
+ Lazybird::Db.init
48
+ end
49
+
50
+ def config(params)
51
+ config = Lazybird::Utils::Hash.array_to_hash([:consumer_key,
52
+ :consumer_secret,
53
+ :access_token,
54
+ :access_token_secret], params)
55
+ Lazybird::Db.save_config! config
56
+ end
57
+
58
+ def run_tasks(params, &block)
59
+ if params.first == 'now'
60
+ run_random_task
61
+ else
62
+ Lazybird::Tasks::TaskScheduler.schedule(frequency: params.first) do
63
+ run_random_task(&block)
64
+ end
65
+ end
66
+ end
67
+
68
+ def run_info
69
+ Lazybird::Tasks::TaskScheduler.job_info
70
+ end
71
+
72
+ private
73
+
74
+ def run_random_task(&block)
75
+ puts 'Twitting something random...'.yellow
76
+ text = @current_tasks.to_a.sample.run
77
+ if text.nil?
78
+ puts "Sorry! We couldn't tweet :(".light_red
79
+ else
80
+ puts "<<#{text.magenta}>>"
81
+ end
82
+ yield if block
83
+ text
84
+ end
85
+ end
86
+ end