timber 2.0.24 → 2.1.0.rc1
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/CHANGELOG +3 -0
- data/README.md +314 -59
- data/bin/timber +11 -2
- data/lib/timber.rb +2 -7
- data/lib/timber/cli.rb +16 -28
- data/lib/timber/cli/api.rb +80 -14
- data/lib/timber/cli/api/application.rb +30 -0
- data/lib/timber/cli/config_file.rb +66 -0
- data/lib/timber/cli/file_helper.rb +43 -0
- data/lib/timber/cli/installer.rb +58 -0
- data/lib/timber/cli/installers.rb +37 -0
- data/lib/timber/cli/installers/other.rb +47 -0
- data/lib/timber/cli/installers/rails.rb +255 -0
- data/lib/timber/cli/installers/root.rb +189 -0
- data/lib/timber/cli/io.rb +97 -0
- data/lib/timber/cli/io/ansi.rb +22 -0
- data/lib/timber/cli/io/messages.rb +213 -0
- data/lib/timber/cli/os_helper.rb +53 -0
- data/lib/timber/config.rb +97 -43
- data/lib/timber/config/integrations.rb +63 -0
- data/lib/timber/config/integrations/rack.rb +74 -0
- data/lib/timber/context.rb +13 -10
- data/lib/timber/contexts.rb +1 -0
- data/lib/timber/contexts/custom.rb +16 -3
- data/lib/timber/contexts/http.rb +10 -3
- data/lib/timber/contexts/organization.rb +4 -0
- data/lib/timber/contexts/release.rb +46 -0
- data/lib/timber/contexts/runtime.rb +7 -1
- data/lib/timber/contexts/session.rb +8 -1
- data/lib/timber/contexts/system.rb +5 -1
- data/lib/timber/contexts/user.rb +9 -2
- data/lib/timber/current_context.rb +43 -11
- data/lib/timber/events/controller_call.rb +4 -0
- data/lib/timber/events/custom.rb +13 -5
- data/lib/timber/events/exception.rb +4 -0
- data/lib/timber/events/http_client_request.rb +4 -0
- data/lib/timber/events/http_client_response.rb +4 -0
- data/lib/timber/events/http_server_request.rb +5 -0
- data/lib/timber/events/http_server_response.rb +15 -3
- data/lib/timber/events/sql_query.rb +3 -0
- data/lib/timber/events/template_render.rb +3 -0
- data/lib/timber/integration.rb +40 -0
- data/lib/timber/integrations.rb +21 -14
- data/lib/timber/integrations/action_controller.rb +18 -0
- data/lib/timber/integrations/action_controller/log_subscriber.rb +2 -0
- data/lib/timber/integrations/action_controller/log_subscriber/timber_log_subscriber.rb +6 -0
- data/lib/timber/integrations/action_dispatch.rb +23 -0
- data/lib/timber/integrations/action_dispatch/debug_exceptions.rb +2 -0
- data/lib/timber/integrations/action_view.rb +18 -0
- data/lib/timber/integrations/action_view/log_subscriber.rb +2 -0
- data/lib/timber/integrations/action_view/log_subscriber/timber_log_subscriber.rb +10 -0
- data/lib/timber/integrations/active_record.rb +18 -0
- data/lib/timber/integrations/active_record/log_subscriber.rb +2 -0
- data/lib/timber/integrations/active_record/log_subscriber/timber_log_subscriber.rb +8 -0
- data/lib/timber/integrations/rack.rb +12 -2
- data/lib/timber/integrations/rack/exception_event.rb +38 -5
- data/lib/timber/integrations/rack/http_context.rb +4 -6
- data/lib/timber/integrations/rack/http_events.rb +177 -27
- data/lib/timber/integrations/rack/middleware.rb +28 -0
- data/lib/timber/integrations/rack/session_context.rb +5 -6
- data/lib/timber/integrations/rack/user_context.rb +90 -43
- data/lib/timber/integrations/rails.rb +22 -0
- data/lib/timber/integrations/rails/rack_logger.rb +2 -0
- data/lib/timber/integrator.rb +18 -3
- data/lib/timber/log_devices/http.rb +107 -99
- data/lib/timber/log_devices/http/dropping_sized_queue.rb +26 -0
- data/lib/timber/log_devices/http/flushable_sized_queue.rb +42 -0
- data/lib/timber/log_entry.rb +14 -2
- data/lib/timber/logger.rb +51 -36
- data/lib/timber/overrides.rb +2 -0
- data/lib/timber/overrides/active_support_3_tagged_logging.rb +103 -0
- data/lib/timber/overrides/active_support_tagged_logging.rb +53 -90
- data/lib/timber/timer.rb +21 -0
- data/lib/timber/util/hash.rb +1 -1
- data/lib/timber/util/http_event.rb +16 -3
- data/lib/timber/version.rb +1 -1
- data/spec/support/timber.rb +2 -3
- data/spec/timber/cli/installers/rails_spec.rb +160 -0
- data/spec/timber/cli/installers/root_spec.rb +100 -0
- data/spec/timber/config_spec.rb +28 -0
- data/spec/timber/current_context_spec.rb +61 -12
- data/spec/timber/events/custom_spec.rb +13 -2
- data/spec/timber/events/exception_spec.rb +15 -0
- data/spec/timber/events/http_server_request_spec.rb +3 -3
- data/spec/timber/integrations/rack/http_events_spec.rb +101 -0
- data/spec/timber/log_devices/http_spec.rb +20 -4
- data/spec/timber/log_entry_spec.rb +2 -1
- data/spec/timber/logger_spec.rb +8 -8
- metadata +40 -9
- data/benchmarks/rails.rb +0 -122
- data/lib/timber/cli/application.rb +0 -28
- data/lib/timber/cli/install.rb +0 -196
- data/lib/timber/cli/io_helper.rb +0 -65
- data/lib/timber/cli/messages.rb +0 -180
- data/lib/timber/integrations/active_support/tagged_logging.rb +0 -71
@@ -1,28 +0,0 @@
|
|
1
|
-
require "json"
|
2
|
-
|
3
|
-
module Timber
|
4
|
-
class CLI
|
5
|
-
class Application
|
6
|
-
|
7
|
-
attr_reader :api_key, :environment, :framework_type, :heroku_drain_url, :language_type,
|
8
|
-
:name, :platform_type
|
9
|
-
|
10
|
-
def initialize(api)
|
11
|
-
res = api.application!
|
12
|
-
parsed_body = JSON.parse(res.body)
|
13
|
-
application_data = parsed_body.fetch("data")
|
14
|
-
@api_key = application_data.fetch("api_key")
|
15
|
-
@environment = application_data.fetch("environment")
|
16
|
-
@framework_type = application_data.fetch("framework_type")
|
17
|
-
@heroku_drain_url = application_data.fetch("heroku_drain_url")
|
18
|
-
@language_type = application_data.fetch("language_type")
|
19
|
-
@name = application_data.fetch("name")
|
20
|
-
@platform_type = application_data.fetch("platform_type")
|
21
|
-
end
|
22
|
-
|
23
|
-
def heroku?
|
24
|
-
platform_type == "heroku"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
data/lib/timber/cli/install.rb
DELETED
@@ -1,196 +0,0 @@
|
|
1
|
-
require "fileutils"
|
2
|
-
|
3
|
-
module Timber
|
4
|
-
class CLI
|
5
|
-
class Install
|
6
|
-
EXCLUDED_ENVIRONMENTS = ["test"].freeze
|
7
|
-
|
8
|
-
class << self
|
9
|
-
include IOHelper
|
10
|
-
|
11
|
-
def run(api_key)
|
12
|
-
puts colorize(Messages.header, :green)
|
13
|
-
puts colorize(Messages.separator, :green)
|
14
|
-
puts colorize(Messages.contact, :green)
|
15
|
-
puts colorize(Messages.separator, :green)
|
16
|
-
puts ""
|
17
|
-
|
18
|
-
if !api_key
|
19
|
-
puts Messages.no_api_key_provided
|
20
|
-
return
|
21
|
-
end
|
22
|
-
|
23
|
-
api = API.new(api_key)
|
24
|
-
|
25
|
-
api.event!(:started)
|
26
|
-
|
27
|
-
app = Application.new(api)
|
28
|
-
|
29
|
-
puts Messages.application_details(app)
|
30
|
-
puts ""
|
31
|
-
|
32
|
-
case ask_yes_no("Are the above details correct?", api)
|
33
|
-
when :yes
|
34
|
-
if app.heroku?
|
35
|
-
update_environment_config("production", :stdout, api)
|
36
|
-
|
37
|
-
puts ""
|
38
|
-
puts Messages.separator
|
39
|
-
puts ""
|
40
|
-
puts Messages.heroku_install(app)
|
41
|
-
puts ""
|
42
|
-
|
43
|
-
ask_yes_no("Ready to proceed?", api)
|
44
|
-
puts ""
|
45
|
-
|
46
|
-
else
|
47
|
-
puts ""
|
48
|
-
puts Messages.separator
|
49
|
-
puts ""
|
50
|
-
puts "How would you like configure Timber?"
|
51
|
-
puts ""
|
52
|
-
puts "1) Using environment variables"
|
53
|
-
puts "2) Configuring in my app"
|
54
|
-
puts ""
|
55
|
-
|
56
|
-
case ask("Enter your choice: (1/2) ", api)
|
57
|
-
when "1"
|
58
|
-
update_environment_config("production", :http, api, :api_key_code => "ENV['TIMBER_API_KEY']")
|
59
|
-
|
60
|
-
puts ""
|
61
|
-
puts Messages.http_environment_variables(app.api_key)
|
62
|
-
puts ""
|
63
|
-
|
64
|
-
ask_yes_no("Ready to proceed?", api)
|
65
|
-
puts ""
|
66
|
-
|
67
|
-
when "2"
|
68
|
-
update_environment_config("production", :http, api, :api_key_code => "'#{app.api_key}'")
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
send_test_messages(api_key)
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
api.wait_for_logs do |iteration|
|
77
|
-
write Messages.task_start("Waiting for logs")
|
78
|
-
write Messages.spinner(iteration)
|
79
|
-
end
|
80
|
-
|
81
|
-
puts colorize(Messages.task_complete("Waiting for logs"), :green)
|
82
|
-
|
83
|
-
puts ""
|
84
|
-
puts Messages.separator
|
85
|
-
puts ""
|
86
|
-
puts Messages.commit_and_deploy_reminder
|
87
|
-
|
88
|
-
api.event!(:success)
|
89
|
-
|
90
|
-
collect_feedback(api)
|
91
|
-
|
92
|
-
puts ""
|
93
|
-
puts Messages.separator
|
94
|
-
puts ""
|
95
|
-
puts Messages.free_data
|
96
|
-
puts ""
|
97
|
-
|
98
|
-
when :no
|
99
|
-
puts ""
|
100
|
-
puts "Bummer. Head to this URL to update the details:"
|
101
|
-
puts ""
|
102
|
-
puts " #{Messages.edit_app_url(app)}"
|
103
|
-
puts ""
|
104
|
-
puts "exiting..."
|
105
|
-
return false
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
def update_environment_config(name, log_device_type, api, options = {})
|
111
|
-
path = File.join("config", "environments", "#{name}.rb")
|
112
|
-
|
113
|
-
puts ""
|
114
|
-
task_message = "Configuring Timber in #{path}"
|
115
|
-
write Messages.task_start(task_message)
|
116
|
-
|
117
|
-
init_logger_code = defined?(::ActiveSupport::TaggedLogging) ? "ActiveSupport::TaggedLogging.new(logger)" : "logger"
|
118
|
-
|
119
|
-
logger_code = \
|
120
|
-
case log_device_type
|
121
|
-
when :http
|
122
|
-
api_key_code = options[:api_key_code] || raise(ArgumentError.new("the :api_key_code option is required"))
|
123
|
-
|
124
|
-
code = <<-CODE
|
125
|
-
# Install the Timber.io logger, send logs over HTTP
|
126
|
-
log_device = Timber::LogDevices::HTTP.new(#{api_key_code})
|
127
|
-
logger = Timber::Logger.new(log_device)
|
128
|
-
logger.level = config.log_level
|
129
|
-
config.logger = #{init_logger_code}
|
130
|
-
CODE
|
131
|
-
code.rstrip
|
132
|
-
|
133
|
-
when :stdout
|
134
|
-
code = <<-CODE
|
135
|
-
# Install the Timber.io logger, send logs to STDOUT
|
136
|
-
logger = Timber::Logger.new(STDOUT)
|
137
|
-
logger.level = config.log_level
|
138
|
-
config.logger = #{init_logger_code}
|
139
|
-
CODE
|
140
|
-
code.rstrip
|
141
|
-
end
|
142
|
-
|
143
|
-
|
144
|
-
current_contents = File.read(path)
|
145
|
-
|
146
|
-
if !current_contents.include?("Timber::Logger.new")
|
147
|
-
new_contents = current_contents.sub(/\nend/, "\n\n#{logger_code}\nend")
|
148
|
-
File.write(path, new_contents)
|
149
|
-
api.event!(:file_written, path: path)
|
150
|
-
end
|
151
|
-
|
152
|
-
puts colorize(Messages.task_complete(task_message), :green)
|
153
|
-
end
|
154
|
-
|
155
|
-
def send_test_messages(api_key)
|
156
|
-
write Messages.task_start("Sending test logs")
|
157
|
-
|
158
|
-
http_device = LogDevices::HTTP.new(api_key)
|
159
|
-
logger = Logger.new(http_device)
|
160
|
-
logger.info("Welcome to Timber!")
|
161
|
-
logger.info("This is a test log to ensure the pipes are working")
|
162
|
-
logger.info("Be sure to commit and deploy your app to start seeing real logs")
|
163
|
-
|
164
|
-
puts colorize(Messages.task_complete("Sending test logs"), :green)
|
165
|
-
end
|
166
|
-
|
167
|
-
def collect_feedback(api)
|
168
|
-
puts ""
|
169
|
-
puts Messages.separator
|
170
|
-
puts ""
|
171
|
-
|
172
|
-
rating = ask("How would rate this install experience? 1 (bad) - 5 (perfect)", api)
|
173
|
-
|
174
|
-
case rating
|
175
|
-
when "4", "5"
|
176
|
-
api.event!(:feedback, rating: rating.to_i)
|
177
|
-
puts ""
|
178
|
-
puts Messages.we_love_you_too
|
179
|
-
|
180
|
-
when "1", "2", "3"
|
181
|
-
puts ""
|
182
|
-
puts Messages.bad_experience_message
|
183
|
-
puts ""
|
184
|
-
|
185
|
-
comments = ask("Type your comments (enter sends)", api)
|
186
|
-
|
187
|
-
api.event!(:feedback, rating: rating.to_i, comments: comments)
|
188
|
-
|
189
|
-
puts ""
|
190
|
-
puts "Thank you! We take feedback seriously and will work to improve this."
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
data/lib/timber/cli/io_helper.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
module Timber
|
2
|
-
class CLI
|
3
|
-
module IOHelper
|
4
|
-
def ask(message, api)
|
5
|
-
api.event!(:waiting_for_input, prompt: message)
|
6
|
-
|
7
|
-
write message + " "
|
8
|
-
input = gets
|
9
|
-
|
10
|
-
api.event!(:received_input, prompt: message, value: input)
|
11
|
-
|
12
|
-
input
|
13
|
-
end
|
14
|
-
|
15
|
-
def ask_yes_no(message, api)
|
16
|
-
case ask(message + " (y/n)", api)
|
17
|
-
when "y", "Y"
|
18
|
-
:yes
|
19
|
-
when "n", "N"
|
20
|
-
:no
|
21
|
-
else
|
22
|
-
puts "Woops! That's not a valid input. Please try again."
|
23
|
-
ask_yes_no(message, api)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def colorize(text, color)
|
28
|
-
return text if Gem.win_platform?
|
29
|
-
|
30
|
-
code =
|
31
|
-
case color
|
32
|
-
when :blue then 34
|
33
|
-
when :red then 31
|
34
|
-
when :green then 32
|
35
|
-
when :yellow then 33
|
36
|
-
else 0
|
37
|
-
end
|
38
|
-
|
39
|
-
"\e[#{code}m#{text}\e[0m"
|
40
|
-
end
|
41
|
-
|
42
|
-
def gets
|
43
|
-
value = stdin.gets
|
44
|
-
value ? value.chomp.downcase : ""
|
45
|
-
end
|
46
|
-
|
47
|
-
def puts(message)
|
48
|
-
stdout.puts(message)
|
49
|
-
end
|
50
|
-
|
51
|
-
def write(message)
|
52
|
-
stdout.write(message)
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
def stdout
|
57
|
-
$stdout
|
58
|
-
end
|
59
|
-
|
60
|
-
def stdin
|
61
|
-
$stdin
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
data/lib/timber/cli/messages.rb
DELETED
@@ -1,180 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Timber
|
4
|
-
class CLI
|
5
|
-
module Messages
|
6
|
-
include IOHelper
|
7
|
-
|
8
|
-
extend self
|
9
|
-
|
10
|
-
APP_URL = "https://app.timber.io"
|
11
|
-
DOCS_URL = "https://timber.io/docs"
|
12
|
-
REPO_URL = "https://github.com/timberio/timber-ruby"
|
13
|
-
SUPPORT_EMAIL = "support@timber.io"
|
14
|
-
TWITTER_HANDLE = "@timberdotio"
|
15
|
-
WEBSITE_URL = "https://timber.io"
|
16
|
-
MAX_LENGTH = 80.freeze
|
17
|
-
|
18
|
-
def application_details(app)
|
19
|
-
message = <<-MESSAGE
|
20
|
-
Woot! Your API 🔑 is valid:
|
21
|
-
|
22
|
-
Name: #{app.name} (#{app.environment})
|
23
|
-
Framework: #{app.framework_type}
|
24
|
-
Platform: #{app.platform_type}
|
25
|
-
MESSAGE
|
26
|
-
message.rstrip
|
27
|
-
end
|
28
|
-
|
29
|
-
def edit_app_url(app)
|
30
|
-
"#{APP_URL}"
|
31
|
-
end
|
32
|
-
|
33
|
-
def bad_experience_message
|
34
|
-
message = <<-MESSAGE
|
35
|
-
Bummer! That is certainly not the experience we were going for.
|
36
|
-
|
37
|
-
Could you tell us why you a bad experience?
|
38
|
-
|
39
|
-
(this will be sent directly to the Timber engineering team)
|
40
|
-
MESSAGE
|
41
|
-
message.rstrip
|
42
|
-
end
|
43
|
-
|
44
|
-
def commit_and_deploy_reminder
|
45
|
-
message = <<-MESSAGE
|
46
|
-
Last step! Commit and deploy:
|
47
|
-
|
48
|
-
#{colorize("git commit -m 'Install Timber' config/environments/production.rb", :blue)}
|
49
|
-
|
50
|
-
#{colorize("push and deploy", :blue)} 🚀
|
51
|
-
MESSAGE
|
52
|
-
message.rstrip
|
53
|
-
end
|
54
|
-
|
55
|
-
def console_url(app)
|
56
|
-
message = <<-MESSAGE
|
57
|
-
Your console URL: https://app.timber.io/organizations/timber/apps/#{app.slug}/console
|
58
|
-
MESSAGE
|
59
|
-
end
|
60
|
-
|
61
|
-
def contact
|
62
|
-
message = <<-MESSAGE
|
63
|
-
Website: #{WEBSITE_URL}
|
64
|
-
Documentation: #{DOCS_URL}
|
65
|
-
Support: #{SUPPORT_EMAIL}
|
66
|
-
MESSAGE
|
67
|
-
message.rstrip
|
68
|
-
end
|
69
|
-
|
70
|
-
def http_environment_variables(api_key)
|
71
|
-
message = <<-MESSAGE
|
72
|
-
Great! Add this variable to your environment:
|
73
|
-
|
74
|
-
#{colorize("export TIMBER_API_KEY=\"#{api_key}\"", :blue)}
|
75
|
-
|
76
|
-
MESSAGE
|
77
|
-
message.rstrip
|
78
|
-
end
|
79
|
-
|
80
|
-
def free_data
|
81
|
-
message = <<-MESSAGE
|
82
|
-
As a welcome gift, we've credited your account with ✨ 50mb✨. Get more:
|
83
|
-
|
84
|
-
* Get ✨ 250mb✨ for tweeting your experience to #{TWITTER_HANDLE}
|
85
|
-
* Get ✨ 100mb✨ for starring our repo: #{REPO_URL}
|
86
|
-
* Get ✨ 100mb✨ for following #{TWITTER_HANDLE} on twitter
|
87
|
-
MESSAGE
|
88
|
-
message.rstrip
|
89
|
-
end
|
90
|
-
|
91
|
-
def header
|
92
|
-
message = <<-MESSAGE
|
93
|
-
🌲 Timber.io Ruby Installer
|
94
|
-
|
95
|
-
^ ^ ^ ^ ___I_ ^ ^ ^ ^ ^ ^ ^
|
96
|
-
/|\\/|\\/|\\ /|\\ /\\-_--\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
|
97
|
-
/|\\/|\\/|\\ /|\\ / \\_-__\\ /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
|
98
|
-
/|\\/|\\/|\\ /|\\ |[]| [] | /|\\/|\\ /|\\/|\\/|\\ /|\\/|\\
|
99
|
-
MESSAGE
|
100
|
-
message.rstrip
|
101
|
-
end
|
102
|
-
|
103
|
-
def heroku_install(app)
|
104
|
-
message = <<-MESSAGE
|
105
|
-
To send logs from Heroku please run this command in a separate window:
|
106
|
-
|
107
|
-
#{colorize("heroku drains:add #{app.heroku_drain_url}", :blue)}
|
108
|
-
|
109
|
-
MESSAGE
|
110
|
-
message.rstrip
|
111
|
-
end
|
112
|
-
|
113
|
-
def no_api_key_provided
|
114
|
-
message = <<-MESSAGE
|
115
|
-
Hey there! Welcome to Timber. In order to proceed, you'll need an API key.
|
116
|
-
If you already have one, you can run this installer like:
|
117
|
-
|
118
|
-
#{colorize("bundle exec timber install my-api-key", :blue)}
|
119
|
-
|
120
|
-
#{obtain_key_instructions}
|
121
|
-
MESSAGE
|
122
|
-
message.rstrip
|
123
|
-
end
|
124
|
-
|
125
|
-
def obtain_key_instructions
|
126
|
-
message = <<-MESSAGE
|
127
|
-
Don't have a key? Head over to:
|
128
|
-
|
129
|
-
#{colorize("https://app.timber.io", :blue)}
|
130
|
-
|
131
|
-
Once there, create an application. Your API key will be displayed afterwards.
|
132
|
-
For more detailed instructions, checkout our docs page:
|
133
|
-
|
134
|
-
https://timber.io/docs/app/obtain-api-key/
|
135
|
-
|
136
|
-
If you're confused, don't hesitate to contact us: #{SUPPORT_EMAIL}
|
137
|
-
|
138
|
-
MESSAGE
|
139
|
-
message.rstrip
|
140
|
-
end
|
141
|
-
|
142
|
-
def separator
|
143
|
-
"--------------------------------------------------------------------------------"
|
144
|
-
end
|
145
|
-
|
146
|
-
def spinner(iteration)
|
147
|
-
rem = iteration % 3
|
148
|
-
case rem
|
149
|
-
when 0
|
150
|
-
"/"
|
151
|
-
when 1
|
152
|
-
"-"
|
153
|
-
when 2
|
154
|
-
"\\"
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def success
|
159
|
-
"✓ Success!"
|
160
|
-
end
|
161
|
-
|
162
|
-
def task_complete(message)
|
163
|
-
remainder = MAX_LENGTH - message.length - success.length
|
164
|
-
|
165
|
-
dots = "." * remainder
|
166
|
-
"\r#{message}#{dots}#{success}"
|
167
|
-
end
|
168
|
-
|
169
|
-
def task_start(message)
|
170
|
-
remainder = MAX_LENGTH - message.length - success.length
|
171
|
-
|
172
|
-
"\r#{message}" + ("." * remainder)
|
173
|
-
end
|
174
|
-
|
175
|
-
def we_love_you_too
|
176
|
-
"Thanks! We 💖 you too!"
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|