fitbit_alarms_cli 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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +18 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +7 -0
- data/bin/fac +3 -0
- data/fitbit_alarms_cli.gemspec +20 -0
- data/lib/fitbit_alarms_cli.rb +74 -0
- data/lib/fitbit_alarms_cli/client.rb +116 -0
- data/lib/fitbit_alarms_cli/setup.rb +74 -0
- data/lib/fitbit_alarms_cli/version.rb +3 -0
- data/test/fitbit_alarms_cli_test.rb +7 -0
- data/test/test_helper.rb +17 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d57a33a593111e65cceae5cd7670984e5dc59e5b
|
4
|
+
data.tar.gz: ad04ddaeb8c523ce2c67e7c384ec4d6ac11fedf2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cd90a5ced0d0c465a57b638381144a4b8e66dcbc6ce8c12e5db0c6ffe0f736bd18c0860871f827c7524e4c3c30f5944a8ae868d2fdc464add71a18c1f62cad0f
|
7
|
+
data.tar.gz: a1b0cca80a312f6fe5f3c2ff12f3c926788c37bc848ed3159fa74eb21eca3d0320c7396b228e8552d4764afc8dd0da5fb0e9378c39ae94178e3be18547b5b3ff
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'bundler', '~> 1.6'
|
4
|
+
gem 'fitgem'
|
5
|
+
gem 'rake'
|
6
|
+
gem 'thor'
|
7
|
+
|
8
|
+
group :test do
|
9
|
+
#gem 'backports'
|
10
|
+
#gem 'coveralls', :require => false
|
11
|
+
#gem 'json', :platforms => [:ruby_19]
|
12
|
+
#gem 'rubocop', '>= 0.23', :platforms => [:ruby_19, :ruby_20, :ruby_21]
|
13
|
+
gem 'minitest', '~> 5.3.5'
|
14
|
+
gem 'simplecov', :require => false
|
15
|
+
#gem 'yardstick'
|
16
|
+
end
|
17
|
+
|
18
|
+
gemspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Ben Colon
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# FitbitAlarmsCli
|
2
|
+
|
3
|
+
A CLI gem to setup Fitbit alarms
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install the gem on your system:
|
8
|
+
|
9
|
+
$ gem install fitbit_alarms_cli
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
Enjoy `fac` executable
|
14
|
+
|
15
|
+
```bash
|
16
|
+
Commands:
|
17
|
+
fac add # Add a new alarm
|
18
|
+
fac help [COMMAND] # Describe available commands or one specific command
|
19
|
+
fac list # List all alarms
|
20
|
+
fac remove # Remove an alarm
|
21
|
+
fac setup # Start the setup of Fitbit Alarms CLI
|
22
|
+
fac version # Fitbit Alarms CLI version
|
23
|
+
```
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/fitbit_alarms_cli/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/fac
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "fitbit_alarms_cli/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "fitbit_alarms_cli"
|
8
|
+
spec.version = FitbitAlarmsCli::VERSION
|
9
|
+
spec.authors = ["Ben Colon"]
|
10
|
+
spec.email = ["ben@colon.com.fr"]
|
11
|
+
spec.summary = "A CLI gem to setup Fitbit alarms"
|
12
|
+
spec.description = "A CLI gem to setup Fitbit alarms"
|
13
|
+
spec.homepage = "https://github.com/bencolon/fitbit_alarms_cli"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = ["fac"]
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "fitbit_alarms_cli/version"
|
3
|
+
require "fitbit_alarms_cli/setup"
|
4
|
+
require "fitbit_alarms_cli/client"
|
5
|
+
|
6
|
+
module FitbitAlarmsCli
|
7
|
+
class Commands < Thor
|
8
|
+
desc "version", "Fitbit Alarms CLI version"
|
9
|
+
def version
|
10
|
+
puts "Fitbit Alarms CLI - v#{VERSION}"
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "setup", "Run the setup of Fitbit Alarms CLI"
|
14
|
+
long_desc <<-LONGDESC
|
15
|
+
Guide you to setup Fitbit Alarms CLI across authentication process.
|
16
|
+
LONGDESC
|
17
|
+
def setup
|
18
|
+
Setup.start
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "list", "List all alarms"
|
22
|
+
long_desc <<-LONGDESC
|
23
|
+
List all Fitbit alarms. By default, list all alarms from ALL you devices.
|
24
|
+
|
25
|
+
With -D option, you can specify a device ID to get only device's alarms.
|
26
|
+
LONGDESC
|
27
|
+
option :device, :aliases => :"-D", :type => :numeric
|
28
|
+
def list
|
29
|
+
client = Client.new
|
30
|
+
client.list_alarms(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "add TIME", "Add a new alarm"
|
34
|
+
long_desc <<-LONGDESC
|
35
|
+
Add a new alarm with <time>. <time> should be HH:MM+TZ:00 formatted.
|
36
|
+
\x5 By default, the new alarm is assigned to the first device with these settings: today, enabled and no recurring.
|
37
|
+
|
38
|
+
With -e option, you can enabled/disabled the alarm (true or false).
|
39
|
+
|
40
|
+
With -d option, you can set the day(s) the alarm will be active for recurring alarm only.
|
41
|
+
\x5 You have to pass coma separated values (MONDAY,FRIDAY,...).
|
42
|
+
|
43
|
+
With -r option, you can set if it's a one time alarm or a recurring alarm (true or false).
|
44
|
+
|
45
|
+
With -l option, you can add a label to the alarm.
|
46
|
+
\x5 Unfortunately, this label will not be displayed on you're Fitbit :(
|
47
|
+
\x5 I really hope this feature will be added asap to the Fitbit firmware.
|
48
|
+
|
49
|
+
With -D option, you can specify a device ID to specify on which device the alarm has to be added.
|
50
|
+
LONGDESC
|
51
|
+
option :enabled, :aliases => :"-e", :type => :boolean
|
52
|
+
option :week_days, :aliases => :"-d", :type => :array
|
53
|
+
option :recurring, :aliases => :"-r", :type => :boolean
|
54
|
+
option :label, :aliases => :"-l", :type => :string
|
55
|
+
option :device_id, :aliases => :"-D", :type => :numeric
|
56
|
+
def add(time)
|
57
|
+
client = Client.new
|
58
|
+
client.add_alarm(time, options)
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "remove ALARM_ID", "Remove an alarm"
|
62
|
+
long_desc <<-LONGDESC
|
63
|
+
Remove the alarm with the corresponding <alarm_id>.
|
64
|
+
\x5 By default, try to remove the alarm from the first device.
|
65
|
+
|
66
|
+
With -D option, you can specify the device ID from where the alarm has to be removed.
|
67
|
+
LONGDESC
|
68
|
+
option :device, :aliases => :"-D", :type => :numeric
|
69
|
+
def remove(alarm_id)
|
70
|
+
client = Client.new
|
71
|
+
client.remove_alarm(alarm_id, options)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'fitgem'
|
3
|
+
|
4
|
+
module FitbitAlarmsCli
|
5
|
+
class Client
|
6
|
+
MAX_ALARMS_COUNT = 8
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
unless File.exists?(Setup::AUTH_FILE_PATH)
|
10
|
+
puts "You haven't setup FitbitAlarmsCli."
|
11
|
+
puts "Please run `fac setup` before."
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
auth = YAML.load_file(Setup::AUTH_FILE_PATH)
|
16
|
+
unless auth[:consumer_key] && auth[:consumer_secret] && auth[:token] && auth[:secret]
|
17
|
+
puts "FitbitAlarmsCli configuration seems corrupted."
|
18
|
+
puts "Please run `fac setup` again."
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
|
22
|
+
@client = Fitgem::Client.new({ :consumer_key => auth[:consumer_key],
|
23
|
+
:consumer_secret => auth[:consumer_secret],
|
24
|
+
:token => auth[:token],
|
25
|
+
:secret => auth[:secret] })
|
26
|
+
end
|
27
|
+
|
28
|
+
def list_alarms(options)
|
29
|
+
if options[:device]
|
30
|
+
puts_device_alarms(options[:device])
|
31
|
+
else
|
32
|
+
check_response(devices = @client.devices)
|
33
|
+
devices.each do |device|
|
34
|
+
puts_device_alarms(device['id'])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_alarm(time, options)
|
40
|
+
unless /^\d{2}:\d{2}\+\d{2}:\d{2}$/.match(time)
|
41
|
+
puts_and_exit "ERROR: Invalid time. Time should be HH:MM+TZ:00 formatted (ex: 23:30+02:00)."
|
42
|
+
end
|
43
|
+
|
44
|
+
device_id = options[:device] || first_device
|
45
|
+
alarms = @client.get_alarms(device_id)
|
46
|
+
puts_and_exit "ERROR: You reached the maximum alarms count (8) on this device." if alarms["trackerAlarms"].count == MAX_ALARMS_COUNT
|
47
|
+
|
48
|
+
settings = { :device_id => device_id,
|
49
|
+
:time => time,
|
50
|
+
:enabled => true,
|
51
|
+
:recurring => false,
|
52
|
+
:weekDays => Time.now.strftime("%A").upcase
|
53
|
+
}
|
54
|
+
|
55
|
+
# symbolize_keys and update weird week_days API params
|
56
|
+
options = options.each_with_object({}) do |(k,v), h|
|
57
|
+
k = "weekDays" if k == "week_days"
|
58
|
+
h[k.to_sym] = v
|
59
|
+
end
|
60
|
+
|
61
|
+
settings.merge!(options)
|
62
|
+
check_response(@client.add_alarm(settings))
|
63
|
+
|
64
|
+
list_alarms(options)
|
65
|
+
end
|
66
|
+
|
67
|
+
def remove_alarm(alarm_id, options)
|
68
|
+
device_id = options[:device] || first_device
|
69
|
+
check_response(@client.delete_alarm(alarm_id, device_id))
|
70
|
+
list_alarms(options)
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def first_device
|
76
|
+
@client.devices.first["id"]
|
77
|
+
end
|
78
|
+
|
79
|
+
def check_response(response)
|
80
|
+
puts_and_exit "ERROR: #{response["errors"]}" if response.is_a?(Hash) && response["errors"]
|
81
|
+
end
|
82
|
+
|
83
|
+
def puts_device_alarms(device_id)
|
84
|
+
puts "Device ##{device_id}\n--------------------------------"
|
85
|
+
check_response(response = @client.get_alarms(device_id))
|
86
|
+
format_alarms(response["trackerAlarms"])
|
87
|
+
end
|
88
|
+
|
89
|
+
def format_alarms(alarms)
|
90
|
+
puts_and_exit " Device not found." unless alarms
|
91
|
+
puts_and_exit " No alarms set on this device." if alarms.empty?
|
92
|
+
|
93
|
+
alarms.each do |alarm|
|
94
|
+
label = alarm['label'] ? " (#{alarm['label']})" : ""
|
95
|
+
time = alarm['time']
|
96
|
+
day = alarm['recurring'] ? "" : today_or_tomorrow(time[0..1], time[3..4], time[5..10])
|
97
|
+
recurring = alarm['recurring'] ? " every #{alarm['weekDays']}" : ""
|
98
|
+
enabled = alarm['enabled'] ? 'enabled' : 'disabled'
|
99
|
+
synced = alarm['syncedToDevice'] ? "synced" : "not synced"
|
100
|
+
|
101
|
+
puts " Alarm ##{alarm['alarmId']}#{label}, #{day}at #{alarm['time']}#{recurring} is #{enabled}/#{synced}."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def today_or_tomorrow(h, m, tz)
|
106
|
+
now = Time.now
|
107
|
+
alarm = Time.new(now.year, now.month, now.day, h, m, 0, tz)
|
108
|
+
now < alarm ? "today " : "tomorrow "
|
109
|
+
end
|
110
|
+
|
111
|
+
def puts_and_exit(message)
|
112
|
+
puts message
|
113
|
+
exit
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module FitbitAlarmsCli
|
2
|
+
module Setup
|
3
|
+
AUTH_FILE_PATH = "#{Dir.home}/.fitbit_alarms_cli"
|
4
|
+
|
5
|
+
def self.start
|
6
|
+
if File.exists?(AUTH_FILE_PATH)
|
7
|
+
puts "You already setup FitbitAlarmsCli."
|
8
|
+
puts "Are you sure you want to setup it again? yes/no"
|
9
|
+
response = $stdin.gets
|
10
|
+
exit if response.strip != "yes"
|
11
|
+
end
|
12
|
+
run
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def self.run
|
18
|
+
@auth = {}
|
19
|
+
|
20
|
+
intro
|
21
|
+
consumer_infos
|
22
|
+
tokens
|
23
|
+
congrats
|
24
|
+
|
25
|
+
rescue Exception => e
|
26
|
+
puts "An error has ocurred during authentication. Please try again."
|
27
|
+
puts e.message
|
28
|
+
#puts e.backtrace.inspect
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.intro
|
32
|
+
puts "First, go register a new Fitbit application at https://dev.fitbit.com/apps/new"
|
33
|
+
puts "Fill the form and come back"
|
34
|
+
puts "Press a key to continue..."
|
35
|
+
$stdin.gets
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.consumer_infos
|
39
|
+
begin
|
40
|
+
puts "Enter the consumer key you got and press enter:"
|
41
|
+
end while (key = $stdin.gets.strip).empty?
|
42
|
+
@auth[:consumer_key] = key
|
43
|
+
|
44
|
+
begin
|
45
|
+
puts "Enter the consumer secret you got and press enter:"
|
46
|
+
end while (secret = $stdin.gets.strip).empty?
|
47
|
+
@auth[:consumer_secret] = secret
|
48
|
+
|
49
|
+
@client = Fitgem::Client.new({ :consumer_key => @auth[:consumer_key],
|
50
|
+
:consumer_secret => @auth[:consumer_secret] })
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.tokens
|
54
|
+
request_token = @client.authentication_request_token
|
55
|
+
|
56
|
+
puts "Your application is now set up, you now have to authorize this app access you data."
|
57
|
+
puts "Visit the following link, log in if needed, and then authorize the app."
|
58
|
+
puts request_token.authorize_url
|
59
|
+
|
60
|
+
puts "When you've authorized that app, enter the verifier code you got and press enter:"
|
61
|
+
verifier = $stdin.gets.strip
|
62
|
+
access_token = @client.authorize(request_token.token, request_token.secret, :oauth_verifier => verifier)
|
63
|
+
@auth[:token] = access_token.token
|
64
|
+
@auth[:secret] = access_token.secret
|
65
|
+
|
66
|
+
File.open(AUTH_FILE_PATH, "w") {|f| YAML.dump(@auth, f) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.congrats
|
70
|
+
puts "Congrats, FitbitAlarmsCli is setup!"
|
71
|
+
puts "Have a look to the help to enjoy it: `fac help`"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
#require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
#Coveralls::SimpleCov::Formatter,
|
7
|
+
]
|
8
|
+
|
9
|
+
SimpleCov.start do
|
10
|
+
minimum_coverage 100
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'fitbit_alarms_cli'
|
14
|
+
require 'minitest'
|
15
|
+
require 'minitest/autorun'
|
16
|
+
require 'minitest/pride'
|
17
|
+
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fitbit_alarms_cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Colon
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-25 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A CLI gem to setup Fitbit alarms
|
14
|
+
email:
|
15
|
+
- ben@colon.com.fr
|
16
|
+
executables:
|
17
|
+
- fac
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- ".gitignore"
|
22
|
+
- ".ruby-version"
|
23
|
+
- ".travis.yml"
|
24
|
+
- Gemfile
|
25
|
+
- LICENSE.txt
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- bin/fac
|
29
|
+
- fitbit_alarms_cli.gemspec
|
30
|
+
- lib/fitbit_alarms_cli.rb
|
31
|
+
- lib/fitbit_alarms_cli/client.rb
|
32
|
+
- lib/fitbit_alarms_cli/setup.rb
|
33
|
+
- lib/fitbit_alarms_cli/version.rb
|
34
|
+
- test/fitbit_alarms_cli_test.rb
|
35
|
+
- test/test_helper.rb
|
36
|
+
homepage: https://github.com/bencolon/fitbit_alarms_cli
|
37
|
+
licenses:
|
38
|
+
- MIT
|
39
|
+
metadata: {}
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 2.2.2
|
57
|
+
signing_key:
|
58
|
+
specification_version: 4
|
59
|
+
summary: A CLI gem to setup Fitbit alarms
|
60
|
+
test_files:
|
61
|
+
- test/fitbit_alarms_cli_test.rb
|
62
|
+
- test/test_helper.rb
|