slack_pomodoro_timer 0.1.0.pre.beta
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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/Guardfile +70 -0
- data/LICENSE.txt +21 -0
- data/README.md +131 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/slack_pomodoro_timer +5 -0
- data/lib/slack_pomodoro_timer.rb +9 -0
- data/lib/slack_pomodoro_timer/cli.rb +135 -0
- data/lib/slack_pomodoro_timer/config.rb +104 -0
- data/lib/slack_pomodoro_timer/http.rb +123 -0
- data/lib/slack_pomodoro_timer/pomodorobot.rb +37 -0
- data/lib/slack_pomodoro_timer/timer.rb +148 -0
- data/lib/slack_pomodoro_timer/version.rb +3 -0
- data/slack_pomodoro_timer.gemspec +38 -0
- metadata +167 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce3b97366999a97518b7cb21bc4c2a51e735d4c2
|
4
|
+
data.tar.gz: 95c9b25ecf2a68958cb89acf8aa2e73caab8145f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bc47c95b57e33a6ee38f351c5fd6213c0b247e4034de9ea0bf0868fd0c52d4c7da525a37bafb01ef2fafa5e9b2cf8973615a0113631013c550318ceb2e0a246a
|
7
|
+
data.tar.gz: e8e2f41d5c2df2e7d03ca5d24770908aba5d8bcce6255660fb593ac7cf8ec0e1b57871645d9d05d599ce9b13324266484f886962c9b17ad96b1a191f2ada971b
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features) \
|
6
|
+
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
7
|
+
|
8
|
+
## Note: if you are using the `directories` clause above and you are not
|
9
|
+
## watching the project directory ('.'), then you will want to move
|
10
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
11
|
+
#
|
12
|
+
# $ mkdir config
|
13
|
+
# $ mv Guardfile config/
|
14
|
+
# $ ln -s config/Guardfile .
|
15
|
+
#
|
16
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
17
|
+
|
18
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
19
|
+
# rspec may be run, below are examples of the most common uses.
|
20
|
+
# * bundler: 'bundle exec rspec'
|
21
|
+
# * bundler binstubs: 'bin/rspec'
|
22
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
23
|
+
# installed the spring binstubs per the docs)
|
24
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
25
|
+
# * 'just' rspec: 'rspec'
|
26
|
+
|
27
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
28
|
+
require "guard/rspec/dsl"
|
29
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
30
|
+
|
31
|
+
# Feel free to open issues for suggestions and improvements
|
32
|
+
|
33
|
+
# RSpec files
|
34
|
+
rspec = dsl.rspec
|
35
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
36
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
37
|
+
watch(rspec.spec_files)
|
38
|
+
|
39
|
+
# Ruby files
|
40
|
+
ruby = dsl.ruby
|
41
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
42
|
+
|
43
|
+
# Rails files
|
44
|
+
rails = dsl.rails(view_extensions: %w(erb haml slim))
|
45
|
+
dsl.watch_spec_files_for(rails.app_files)
|
46
|
+
dsl.watch_spec_files_for(rails.views)
|
47
|
+
|
48
|
+
watch(rails.controllers) do |m|
|
49
|
+
[
|
50
|
+
rspec.spec.("routing/#{m[1]}_routing"),
|
51
|
+
rspec.spec.("controllers/#{m[1]}_controller"),
|
52
|
+
rspec.spec.("acceptance/#{m[1]}")
|
53
|
+
]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Rails config changes
|
57
|
+
watch(rails.spec_helper) { rspec.spec_dir }
|
58
|
+
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
59
|
+
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
60
|
+
|
61
|
+
# Capybara features specs
|
62
|
+
watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
|
63
|
+
watch(rails.layouts) { |m| rspec.spec.("features/#{m[1]}") }
|
64
|
+
|
65
|
+
# Turnip features and steps
|
66
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
67
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
|
68
|
+
Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
|
69
|
+
end
|
70
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Bideo Wego
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# SlackPomodoroTimer
|
2
|
+
|
3
|
+
by [kitlangton](https://github.com/kitlangton) and [Bideo Wego](https://github.com/BideoWego)
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
A Ruby powered command line app for sending timed messages to slack channels
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
### Install the gem
|
15
|
+
```shell
|
16
|
+
$ gem install slack_pomodoro_timer
|
17
|
+
```
|
18
|
+
|
19
|
+
### Configure your Slackbot URL
|
20
|
+
|
21
|
+
Configure the Slackbot URL:
|
22
|
+
|
23
|
+
```shell
|
24
|
+
$ slack_pomodoro_timer config --url https://company.slack.com/services/hooks/slackbot?token=YOUR_TOKEN_HERE
|
25
|
+
```
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
#### Not sure where to find your Slackbot URL?
|
30
|
+
|
31
|
+
1. Make sure you are signed into your Slack team at [https://slack.com/signin](https://slack.com/signin)
|
32
|
+
|
33
|
+
1. Then go to this link [https://slack.com/apps/build](https://slack.com/apps/build)
|
34
|
+
|
35
|
+
1. Click on the 'Configure' button in the top right
|
36
|
+
|
37
|
+
1. Now choose 'Custom Integrations'
|
38
|
+
|
39
|
+
1. Choose 'Slackbot'
|
40
|
+
|
41
|
+
1. If you do not have any Slackbot integrations you'll have to create one, otherwise skip this step and the next
|
42
|
+
|
43
|
+
1. Click 'Add Configuration' then 'Add Slackbot Configuration'
|
44
|
+
|
45
|
+
1. You should see an edit button next to your created integration as a pencil icon, click it!
|
46
|
+
|
47
|
+
1. Scroll down to 'Setup Instructions' and copy the full URL that you see under 'Your slackbot URL is:'
|
48
|
+
|
49
|
+
1. Now paste that URL into the above command to configure the URL for Slack Pomodoro Timer
|
50
|
+
|
51
|
+
1. You should now be able to run `$ slack_pomodoro_timer start 1`! See below for changing the channel.
|
52
|
+
|
53
|
+
|
54
|
+
NOTE: Slack Pomodoro Timer is actually able to accept a Webhook URL as well,
|
55
|
+
however this functionality is not fully tested at this time.
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
### Configure the channel
|
61
|
+
|
62
|
+
Slack Pomodoro Timer is configured to send messages to the 'general' channel by default.
|
63
|
+
If you want to send messages to another channel you'll have to configure it will that channel.
|
64
|
+
|
65
|
+
Configure the channel into which you would like to post (this defaults to the general channel):
|
66
|
+
|
67
|
+
```shell
|
68
|
+
$ slack_pomodoro_timer config --channel my_channel
|
69
|
+
```
|
70
|
+
|
71
|
+
You do not need to prepend your channel name with a # symbol, but if you absolutely must, then make sure to wrap your channel name in quotes:
|
72
|
+
|
73
|
+
```shell
|
74
|
+
$ slack_pomodoro_timer config --channel "#my_channel"
|
75
|
+
```
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
## Usage
|
80
|
+
|
81
|
+
To run 5 consecutive 25 minute Pomodoros:
|
82
|
+
|
83
|
+
```shell
|
84
|
+
$ slack_pomodoro_timer start 5
|
85
|
+
```
|
86
|
+
|
87
|
+
Here's how to use a custom pomodoro time length:
|
88
|
+
|
89
|
+
```shell
|
90
|
+
$ slack_pomodoro_timer start 5 --minutes 10
|
91
|
+
```
|
92
|
+
|
93
|
+
For help on command options and usage use the following syntax:
|
94
|
+
|
95
|
+
```shell
|
96
|
+
$ slack_pomodoro_timer help config
|
97
|
+
$ slack_pomodoro_timer help start
|
98
|
+
```
|
99
|
+
|
100
|
+
|
101
|
+
Still a work in progress, however there are minimal passing tests.
|
102
|
+
To run the tests you can simply run `$ rspec` or use Guard with `$ bundle exec guard`.
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
## Development
|
108
|
+
|
109
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
110
|
+
|
111
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
## Contributing
|
117
|
+
|
118
|
+
Bug reports and pull requests are welcome on GitHub [https://github.com/BideoWego/slack_pomodoro_timer](https://github.com/BideoWego/slack_pomodoro_timer)
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
## License
|
125
|
+
|
126
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "slack_pomodoro_timer"
|
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/setup
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require_relative 'slack_pomodoro_timer/version'
|
2
|
+
require_relative 'slack_pomodoro_timer/cli'
|
3
|
+
require_relative 'slack_pomodoro_timer/timer'
|
4
|
+
require_relative 'slack_pomodoro_timer/http'
|
5
|
+
require_relative 'slack_pomodoro_timer/config'
|
6
|
+
require_relative 'slack_pomodoro_timer/pomodorobot'
|
7
|
+
|
8
|
+
module SlackPomodoroTimer
|
9
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
|
4
|
+
module SlackPomodoroTimer
|
5
|
+
class CLI < Thor
|
6
|
+
|
7
|
+
desc 'config [OPTIONS]', 'set the url and channel options with this command'
|
8
|
+
|
9
|
+
|
10
|
+
long_desc %Q;
|
11
|
+
'config' is essential for Slack Pomodoro Timer to run
|
12
|
+
|
13
|
+
|
14
|
+
'config --url'
|
15
|
+
|
16
|
+
|
17
|
+
You must set a URL for the HTTP service to target.
|
18
|
+
It is recommended that you use the Slackbot integration URL for this.
|
19
|
+
|
20
|
+
For full instructions for how to set this up (you may already have one)
|
21
|
+
see the README on the main repository here:
|
22
|
+
|
23
|
+
|
24
|
+
https://github.com/BideoWego/slack_pomodoro_timer
|
25
|
+
|
26
|
+
|
27
|
+
Once you have the URL you may pass it to the config command like so:
|
28
|
+
|
29
|
+
$ slack_pomodoro_timer config --url https://company.slack.com/services/hooks/slackbot?token=YOUR_TOKEN_HERE
|
30
|
+
|
31
|
+
|
32
|
+
'config --channel'
|
33
|
+
|
34
|
+
|
35
|
+
Setting a channel is optional, however if you do not wish to post
|
36
|
+
to the default channel (general) then you will have to set it here.
|
37
|
+
|
38
|
+
|
39
|
+
To set the channel you may pass it to the config command like so:
|
40
|
+
|
41
|
+
$ slack_pomodoro_timer config --channel fox29actionnews
|
42
|
+
|
43
|
+
;
|
44
|
+
|
45
|
+
|
46
|
+
option :url, aliases: :u
|
47
|
+
option :channel, aliases: :c
|
48
|
+
|
49
|
+
|
50
|
+
# Configure the timer URL and channel
|
51
|
+
def config
|
52
|
+
Config.load
|
53
|
+
|
54
|
+
if options[:url]
|
55
|
+
if HTTP.valid_url?(options[:url])
|
56
|
+
Config.add(url: options[:url])
|
57
|
+
else
|
58
|
+
puts "You have not input a valid slack url."
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if options[:channel]
|
63
|
+
Config.add(channel: options[:channel])
|
64
|
+
end
|
65
|
+
|
66
|
+
Config.save
|
67
|
+
|
68
|
+
puts "Config updated:" if options[:url] || options[:channel]
|
69
|
+
Config.display
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
desc 'start COUNT [OPTIONS]', 'set the number of pomodoros and time interval here'
|
76
|
+
|
77
|
+
long_desc %Q;
|
78
|
+
'start' is the command that begins the timer and posts to Slack.
|
79
|
+
|
80
|
+
|
81
|
+
Pomodoros
|
82
|
+
|
83
|
+
|
84
|
+
By default, Slack Pomodoro Timer is set to post 1 pomdoro and has a time of 25 minutes.
|
85
|
+
|
86
|
+
To add more pomdoros simply specify how many pomodoros you'd like to post like so:
|
87
|
+
|
88
|
+
$ slack_pomodoro_timer start 5
|
89
|
+
|
90
|
+
|
91
|
+
'start --minutes'
|
92
|
+
|
93
|
+
The time limit defaults to 25 minutes.
|
94
|
+
|
95
|
+
Optionally you can provide a time limit in minutes. This will be display to you as the timer
|
96
|
+
counts down to zero, at which time the timer will fire again posting another pomodoro.
|
97
|
+
|
98
|
+
Pass a custom time limit to Slack Pomodoro Timer like so:
|
99
|
+
|
100
|
+
$ slack_pomodoro_timer start --minutes 10
|
101
|
+
|
102
|
+
|
103
|
+
Stopping the timer
|
104
|
+
|
105
|
+
At any given time while the timer is running you may stop the timer with CTRL-C.
|
106
|
+
|
107
|
+
|
108
|
+
QUICK TIP!
|
109
|
+
|
110
|
+
To test the timer out try passing it a short time limit like 0.1
|
111
|
+
|
112
|
+
$ slack_pomodoro_timer start --minutes 0.1
|
113
|
+
|
114
|
+
;
|
115
|
+
|
116
|
+
|
117
|
+
option :minutes, aliases: :m, type: :numeric, default: 25
|
118
|
+
|
119
|
+
|
120
|
+
# Start a timer with a number of pomodoros
|
121
|
+
# and optional time limit in minutes
|
122
|
+
def start(pomodoros=1)
|
123
|
+
if Config.configured?
|
124
|
+
interval_in_seconds = options[:minutes] * 60
|
125
|
+
Pomodorobot.start_timer(pomodoros, interval_in_seconds)
|
126
|
+
else
|
127
|
+
puts "Not Configured."
|
128
|
+
puts "Run 'slack_pomodoro_timer help config'"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module SlackPomodoroTimer
|
4
|
+
class Config
|
5
|
+
|
6
|
+
FILENAME = '.slack_pomodoro_timer'
|
7
|
+
PATH = "#{Dir.home}/#{FILENAME}"
|
8
|
+
|
9
|
+
|
10
|
+
@@config = {}
|
11
|
+
|
12
|
+
|
13
|
+
# Class variable getter
|
14
|
+
# returns a hash of config values
|
15
|
+
def self.config
|
16
|
+
@@config
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# Returns true if
|
21
|
+
# configured properly
|
22
|
+
def self.configured?
|
23
|
+
self.load
|
24
|
+
if @@config.empty? ||
|
25
|
+
@@config.any? { |key, value| value.nil? || value.empty? }
|
26
|
+
false
|
27
|
+
else
|
28
|
+
true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Add a config option
|
34
|
+
# or options
|
35
|
+
def self.add(options={})
|
36
|
+
add_option(:channel, options[:channel])
|
37
|
+
add_option(:url, options[:url])
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Saves the current config
|
42
|
+
# hash as YAML to the
|
43
|
+
# path
|
44
|
+
def self.save
|
45
|
+
File.open(PATH, 'w+') do |f|
|
46
|
+
f.write(YAML.dump(config))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# Loads the config file if it exists
|
52
|
+
# or sets default values
|
53
|
+
# if the file does not exist
|
54
|
+
def self.load
|
55
|
+
file_exists = File.exists?(PATH)
|
56
|
+
if File.exists?(PATH)
|
57
|
+
value = YAML.load_file(PATH)
|
58
|
+
else
|
59
|
+
value = defaults
|
60
|
+
end
|
61
|
+
@@config = value
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Get a config value by key
|
66
|
+
def self.get(key)
|
67
|
+
config[key]
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# Display all config values
|
72
|
+
def self.display
|
73
|
+
if config.empty?
|
74
|
+
puts "No config values set"
|
75
|
+
else
|
76
|
+
config.each do |key, value|
|
77
|
+
puts "#{key.upcase}: #{value}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Returns the default config values
|
88
|
+
def self.defaults
|
89
|
+
{
|
90
|
+
:channel => 'general',
|
91
|
+
:url => '',
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
# Sets the key to the given value
|
97
|
+
# unless it is nil
|
98
|
+
def self.add_option(key, value)
|
99
|
+
config[key] = value unless value.nil?
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module SlackPomodoroTimer
|
5
|
+
class HTTP
|
6
|
+
|
7
|
+
REGEXES = {
|
8
|
+
:slackbot => /\.slack.com\/services\/hooks\/slackbot/,
|
9
|
+
:webhook => /hooks\.slack\.com\/services/
|
10
|
+
}
|
11
|
+
|
12
|
+
|
13
|
+
attr_accessor :url,
|
14
|
+
:data,
|
15
|
+
:response
|
16
|
+
|
17
|
+
attr_reader :integration_type
|
18
|
+
|
19
|
+
|
20
|
+
# Accepts options for url and data
|
21
|
+
def initialize(options={})
|
22
|
+
@url = options[:url]
|
23
|
+
@data = options[:data]
|
24
|
+
set_integration_type
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Overrides default setter
|
29
|
+
# to allow internally
|
30
|
+
# setting the integration type
|
31
|
+
# based on the URL
|
32
|
+
def url=(value)
|
33
|
+
@url = value
|
34
|
+
set_integration_type
|
35
|
+
@url
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Posts the data to the given URL
|
40
|
+
def post
|
41
|
+
data = serialized_data
|
42
|
+
url = url_for_integration_type
|
43
|
+
@response = Net::HTTP.post_form(URI.parse(url), data)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
private
|
48
|
+
# Returns a hash with a payload key
|
49
|
+
# conforming to what Net::HTTP expects
|
50
|
+
# in it's data parameter
|
51
|
+
def serialized_data
|
52
|
+
{
|
53
|
+
:payload => serialize_data_by_integration_type
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# Returns the data format that
|
59
|
+
# Slack expects for the
|
60
|
+
# integration type
|
61
|
+
# See:
|
62
|
+
# https://api.slack.com/slackbot
|
63
|
+
# https://api.slack.com/incoming-webhooks
|
64
|
+
def serialize_data_by_integration_type
|
65
|
+
if @integration_type == 'slackbot'
|
66
|
+
serialize_slackbot_data
|
67
|
+
else
|
68
|
+
serialize_webhook_data
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# Returns only the text
|
74
|
+
# of the original data
|
75
|
+
# as explain here
|
76
|
+
# https://api.slack.com/slackbot
|
77
|
+
# Slack expects only the raw text
|
78
|
+
# for this integration type
|
79
|
+
def serialize_slackbot_data
|
80
|
+
@data[:text]
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
# Returns the original data
|
85
|
+
# serialized into JSON
|
86
|
+
def serialize_webhook_data
|
87
|
+
@data.to_json
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# Returns the appropriate
|
92
|
+
# URL for the integration type
|
93
|
+
def url_for_integration_type
|
94
|
+
if @integration_type == 'slackbot'
|
95
|
+
url = @url
|
96
|
+
url += "&channel=#{URI.encode(@data[:channel])}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Sets the integration type
|
102
|
+
# based on the format of the URL
|
103
|
+
def set_integration_type
|
104
|
+
if @url.match(REGEXES[:slackbot])
|
105
|
+
@integration_type = 'slackbot'
|
106
|
+
elsif @url.match(REGEXES[:webhook])
|
107
|
+
@integration_type = 'webhook'
|
108
|
+
else
|
109
|
+
raise ArgumentError, "Slack URL is invalid"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# Validates that the URL fits the expected
|
115
|
+
# Slackbot or Webhook URL format
|
116
|
+
def self.valid_url?(url)
|
117
|
+
REGEXES.any? { |key, regex| regex.match(url) }
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module SlackPomodoroTimer
|
2
|
+
class Pomodorobot
|
3
|
+
|
4
|
+
# Start a new timer
|
5
|
+
# with the given number of pomodoroes
|
6
|
+
# that fires at the given interval in seconds
|
7
|
+
def self.start_timer(pomodoros, interval_in_seconds)
|
8
|
+
Config.load
|
9
|
+
timer = Timer.new(pomodoros: pomodoros.to_i, interval: interval_in_seconds)
|
10
|
+
timer.start do |current_pomodoro|
|
11
|
+
message = '@group :pomodoro:'
|
12
|
+
if current_pomodoro == timer.total
|
13
|
+
message += ' Last one!'
|
14
|
+
elsif current_pomodoro == Timer::DONE
|
15
|
+
message += "s are DONE!"
|
16
|
+
end
|
17
|
+
post message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Post the given text message to slack
|
25
|
+
def self.post(text)
|
26
|
+
http = HTTP.new(url: Config.get(:url))
|
27
|
+
data = {
|
28
|
+
channel: "##{Config.get(:channel)}",
|
29
|
+
text: text
|
30
|
+
}
|
31
|
+
http.data = data
|
32
|
+
http.post
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module SlackPomodoroTimer
|
2
|
+
class Timer
|
3
|
+
|
4
|
+
DONE = :done
|
5
|
+
|
6
|
+
attr_accessor :pomodoros,
|
7
|
+
:interval
|
8
|
+
|
9
|
+
attr_reader :total
|
10
|
+
|
11
|
+
|
12
|
+
# Accepts options for pomodoros
|
13
|
+
# and a time interval in seconds
|
14
|
+
def initialize(options={})
|
15
|
+
@pomodoros = options[:pomodoros]
|
16
|
+
@interval = options[:interval]
|
17
|
+
@total = options[:pomodoros]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Starts the timer
|
21
|
+
# calls the passed block
|
22
|
+
# for each pomodoro
|
23
|
+
# displays countdown until next interval
|
24
|
+
def start(&block)
|
25
|
+
puts start_message if @pomodoros == @total
|
26
|
+
begin
|
27
|
+
yield(current_pomodoro) if block_given?
|
28
|
+
display_countdown
|
29
|
+
@pomodoros -= 1
|
30
|
+
if stop?
|
31
|
+
stop(&block)
|
32
|
+
else
|
33
|
+
start(&block)
|
34
|
+
end
|
35
|
+
rescue SystemExit, Interrupt
|
36
|
+
puts quit_message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Sets the number of pomodoros
|
42
|
+
# and the resets total
|
43
|
+
def pomodoros=(pomodoros)
|
44
|
+
@total = pomodoros
|
45
|
+
@pomodoros = pomodoros
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# Calls the given block passing
|
54
|
+
#
|
55
|
+
def stop(&block)
|
56
|
+
yield(DONE)
|
57
|
+
puts stop_message
|
58
|
+
end
|
59
|
+
|
60
|
+
# Displays the timer countdown to next
|
61
|
+
# pomodoro in the console
|
62
|
+
def display_countdown
|
63
|
+
end_time = Time.now + @interval
|
64
|
+
until Time.now > end_time
|
65
|
+
print "#{time_remaining(end_time)}\r"
|
66
|
+
sleep 1
|
67
|
+
end
|
68
|
+
puts "#{pomodoro_status} -- POSTED at #{current_time}"
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Returns the time remaining until
|
73
|
+
# the next timer fire
|
74
|
+
def time_remaining(end_time)
|
75
|
+
remaining = (end_time - Time.now).ceil
|
76
|
+
format_countdown(remaining)
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
# Formats the countdown timer
|
81
|
+
# to display like a digital clock
|
82
|
+
# and returns the string
|
83
|
+
def format_countdown(seconds)
|
84
|
+
minutes = (seconds / 60).to_s.rjust(2,"0")
|
85
|
+
while seconds >= 60
|
86
|
+
seconds -= 60
|
87
|
+
end
|
88
|
+
seconds = seconds.to_s.rjust(2,"0")
|
89
|
+
|
90
|
+
"#{pomodoro_status} -- #{minutes}:#{seconds}"
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Get the current time
|
95
|
+
# formatted as an AM/PM digital clock
|
96
|
+
def current_time
|
97
|
+
Time.now.strftime("%l:%M %p")
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Returns the timer start message
|
102
|
+
def start_message
|
103
|
+
"Slack Pomodoro Timer started!" +
|
104
|
+
"\nStop the timer at any time with CTRL-C"
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
# Returns the timer stop message
|
109
|
+
def stop_message
|
110
|
+
"Slack Pomodoro Timer stopped!"
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# Returns the timer quit message
|
115
|
+
def quit_message
|
116
|
+
"\nRemaining pomodoros will not be posted." +
|
117
|
+
"\nQuitting slack_pomodoro_timer..."
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
# Returns the number of the
|
122
|
+
# current pomodoro fired in the total
|
123
|
+
def pomodoro_status
|
124
|
+
"Pomodoro #{current_pomodoro} of #{total}"
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# Returns the number of the current
|
129
|
+
# pomodoro in ascending increments
|
130
|
+
def current_pomodoro
|
131
|
+
total - pomodoros + 1
|
132
|
+
end
|
133
|
+
|
134
|
+
# Returns true if stopped
|
135
|
+
# manually or if no pomodoros
|
136
|
+
# left
|
137
|
+
def stop?
|
138
|
+
if @pomodoros <= 0
|
139
|
+
@pomodoros = total
|
140
|
+
true
|
141
|
+
else
|
142
|
+
false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'slack_pomodoro_timer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "slack_pomodoro_timer"
|
8
|
+
spec.version = SlackPomodoroTimer::VERSION
|
9
|
+
spec.authors = ["kitlangton", "Bideo Wego"]
|
10
|
+
spec.email = ["kit.langton@gmail.com", "bideowego@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A pomodoro timer for Slack}
|
13
|
+
spec.description = %q{Start up a pomodoro timer from your command line that posts to a channel in your Slack team.}
|
14
|
+
spec.homepage = "https://github.com/BideoWego/slack_pomodoro_timer"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_dependency "thor"
|
31
|
+
|
32
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
33
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
34
|
+
spec.add_development_dependency "rspec"
|
35
|
+
spec.add_development_dependency "guard"
|
36
|
+
spec.add_development_dependency "guard-rspec"
|
37
|
+
spec.add_development_dependency "webmock"
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: slack_pomodoro_timer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.pre.beta
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kitlangton
|
8
|
+
- Bideo Wego
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-01-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.10'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.10'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '10.0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '10.0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: guard
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: guard-rspec
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: webmock
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
description: Start up a pomodoro timer from your command line that posts to a channel
|
113
|
+
in your Slack team.
|
114
|
+
email:
|
115
|
+
- kit.langton@gmail.com
|
116
|
+
- bideowego@gmail.com
|
117
|
+
executables:
|
118
|
+
- slack_pomodoro_timer
|
119
|
+
extensions: []
|
120
|
+
extra_rdoc_files: []
|
121
|
+
files:
|
122
|
+
- ".gitignore"
|
123
|
+
- ".rspec"
|
124
|
+
- ".travis.yml"
|
125
|
+
- Gemfile
|
126
|
+
- Guardfile
|
127
|
+
- LICENSE.txt
|
128
|
+
- README.md
|
129
|
+
- Rakefile
|
130
|
+
- bin/console
|
131
|
+
- bin/setup
|
132
|
+
- exe/slack_pomodoro_timer
|
133
|
+
- lib/slack_pomodoro_timer.rb
|
134
|
+
- lib/slack_pomodoro_timer/cli.rb
|
135
|
+
- lib/slack_pomodoro_timer/config.rb
|
136
|
+
- lib/slack_pomodoro_timer/http.rb
|
137
|
+
- lib/slack_pomodoro_timer/pomodorobot.rb
|
138
|
+
- lib/slack_pomodoro_timer/timer.rb
|
139
|
+
- lib/slack_pomodoro_timer/version.rb
|
140
|
+
- slack_pomodoro_timer.gemspec
|
141
|
+
homepage: https://github.com/BideoWego/slack_pomodoro_timer
|
142
|
+
licenses:
|
143
|
+
- MIT
|
144
|
+
metadata:
|
145
|
+
allowed_push_host: https://rubygems.org
|
146
|
+
post_install_message:
|
147
|
+
rdoc_options: []
|
148
|
+
require_paths:
|
149
|
+
- lib
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 1.3.1
|
160
|
+
requirements: []
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 2.4.5
|
163
|
+
signing_key:
|
164
|
+
specification_version: 4
|
165
|
+
summary: A pomodoro timer for Slack
|
166
|
+
test_files: []
|
167
|
+
has_rdoc:
|