-
Notifications
You must be signed in to change notification settings - Fork 0
/
twitter_backup.rb
executable file
·153 lines (121 loc) · 3.66 KB
/
twitter_backup.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env ruby
require "rubygems"
require "bundler/setup"
require "byebug"
require "concurrent"
require "dotenv/load"
require "dry/cli"
require "dry/effects"
require "dry/files"
require "dry/monads"
require "dry/transformer/all"
require "json"
require "twitter"
module TwitterBackup
module Functions
extend Dry::Transformer::Registry
import Dry::Transformer::HashTransformations
import Dry::Transformer::ArrayTransformations
end
module Actions
class DoBackup
include Dry::Monads[:do, :result, :try, :task]
include Dry::Effects::Handler.State(:fetching_data)
include Dry::Effects.State(:fetching_data)
include Dry::Effects::Handler.State(:writing_data)
include Dry::Effects.State(:writing_data)
include Dry::Effects::Handler.Defer
include Dry::Effects.Defer
def call
# dry-effects to the rescue: printing dots while waiting for api request to finish
print "Fetching data ..."
json = with_defer do
is_fetching, result = with_fetching_data(true) do
defer do
j = yield fetch_data.fmap(&data_mapper)
self.fetching_data = false
j
end
end
defer { print_dots while is_fetching }
wait(result).tap { puts ' done' }
end
print "Writing to disk ..."
with_defer do
is_writing, result = with_writing_data(true) do
defer do
x = yield write_to_file(json)
self.writing_data = false
x
end
end
defer { print_dots while is_writing }
wait(result).tap { puts ' done' }
end
Success()
end
private
def print_dots
print '.'
sleep 0.1
end
def fetch_data
Try[Twitter::Error] do
{ friends: twitter_client.friends.to_a,
followers: twitter_client.followers.to_a }
end.to_result
end
def data_mapper
t(:map_values,
t(:map_array,
t(-> { _1.to_hash })
.>>(t(:symbolize_keys))
.>>(t(:accept_keys, [:id, :id_str, :name, :screen_name]))))
end
def write_to_file(blob)
Try[Dry::Files::IOError] do
f = Dry::Files.new
writer = f.method(:write)
path = f.expand_path( "./backups/backup_#{Time.now.strftime("%Y%m%d%H%M")}.json", __dir__)
output = JSON.pretty_generate(blob)
writer.(path, output)
end.to_result
end
def twitter_client
client = Twitter::REST::Client.new do |config|
config.consumer_key = ENV['CONSUMER_KEY']
config.consumer_secret = ENV['CONSUMER_SECRET']
config.access_token = ENV['ACCESS_TOKEN']
config.access_token_secret = ENV['ACCESS_TOKEN_SECRET']
end
end
def t(*args)
Functions[*args]
end
end
end
module CLI
module Commands
extend Dry::CLI::Registry
class CreateBackup < Dry::CLI::Command
include Dry::Monads[:result]
desc "Create a backup of all twitter setup (followers, ...)"
def call(*)
case Actions::DoBackup.new.()
in Success() | Success(_) then puts "Yeah 🎉"
in Failure(x) then puts "\nERROR: #{x.message}"
end
end
end
class Version < Dry::CLI::Command
desc "Print version"
def call(*)
puts "1.1.0"
end
end
register "version", Version, aliases: ["v", "-v", "--version"]
register "create", CreateBackup
end
end
end
Dry::CLI.new(TwitterBackup::CLI::Commands).call