pushover 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,6 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ spec/test_config
19
+ .rspec
20
+ *.tmp
data/README.md CHANGED
@@ -2,13 +2,19 @@
2
2
 
3
3
  This gem provides a CLI and an API interface to http://pushover.net
4
4
 
5
- Currently it's a work in process and I haven't built out the CLI yet, that will happen shortly.
5
+ It's main usage as a CLI, see below for specifics.
6
+
7
+ Some CLI features:
8
+
9
+ * Multiple users/applications can be stored.
10
+ * Do not need to supply either, will find the first one available.
11
+ * Supplying on the CLI will always override the stored variables.
6
12
 
7
13
  ## Installation
8
14
 
9
15
  To install:
10
16
 
11
- $ gem install pushover
17
+ $ gem install pushover
12
18
 
13
19
  To use inside of an application, add this to the your gemfile:
14
20
 
@@ -16,24 +22,58 @@ To use inside of an application, add this to the your gemfile:
16
22
 
17
23
  and run bundle to make it available:
18
24
 
19
- $ Bundle
25
+ $ bundle
20
26
 
21
27
  ## Usage
22
28
 
23
- Progmatic usage:
29
+ ### API:
30
+
31
+ require 'pushover'
32
+
33
+ To send with the very minimum amount of information.
34
+
35
+ Pushover.notification('message', 'title', user:'USER_TOKEN', token:'APP_TOKEN')
36
+
37
+ Optional #configuration method:
38
+
39
+ Pushover.configure do |config|
40
+ config.user='USER_TOKEN'
41
+ config.token='APP_TOKEN'
42
+ end
43
+
44
+ Pushover.notification('message', 'title')
45
+
46
+ ### CLI:
47
+
48
+ To send a message. This will override any saved information available.
49
+
50
+ $ pushover -u user_token -a app_key message is the rest of the cli.
51
+
52
+ You can also save and use stored information. The username/application are titles. They can be anything you want to reference them.
53
+
54
+ User:
55
+
56
+ $ pushover -u user_token --save-user username
57
+
58
+ Application:
59
+
60
+ $ pushover -a app_key --save-user application
61
+
62
+ This will allow you to do:
63
+
64
+ $ pushover -a new_app -u username message body.
24
65
 
25
- ```ruby
26
- require 'pushover'
66
+ If you don't supply any credentials, and it has them saved, it will use the first set saved. This allows for a completely lazy mode ```pushover message body here``` for sending without having to constantly specify credentials.
27
67
 
28
- Pushover.notification('your_token', 'app_token', 'message', 'title')
29
- ```
68
+ Delete coming soon.
30
69
 
31
- Title is currently optional, it doesn't do more then this yet.
70
+ ## Testing
32
71
 
33
72
  CLI usage:
34
73
 
35
- $ pushover -a apitoken -t token -m 'message goes in here' -t 'title is optional.'
74
+ Testing, like this utility, it is a work in progress. I'm in the process of lifting some of the code into another library (config, options), so I will likely not be making more tests for those pieces.
36
75
 
76
+ The app testing itself requires you to use your own credentials, that way you get the spam from pushover and not me. I haven't figured out how to do this just yet.
37
77
 
38
78
  ## Contributing
39
79
 
@@ -5,39 +5,50 @@ require 'pushover'
5
5
  include Pushover
6
6
  Options.parse!
7
7
 
8
+ # Order is important.
9
+ if Options[:config_file]
10
+ puts "Selecting config file: #{Options[:config_file]}"
11
+ Pushover::Config.save_file = Options[:config_file]
12
+ end
13
+
8
14
  if Options[:save_app]
9
15
  puts "Saving application #{Options[:save_app][0]} to #{Options[:save_app][1]}."
10
- Pushover::App.add Options[:save_app][0], Options[:save_app][1]
16
+ App.add Options[:save_app][0], Options[:save_app][1]
17
+ puts "Save successful."
11
18
  exit
12
19
  end
13
20
 
14
21
  if Options[:save_user]
15
22
  puts "Saving user #{Options[:save_user][0]} to #{Options[:save_user][1]}."
16
- Pushover::User.add Options[:save_user][0], Options[:save_user][1]
23
+ User.add Options[:save_user][0], Options[:save_user][1]
24
+ puts "Save successful."
17
25
  exit
18
26
  end
19
-
20
27
  puts "Try pushover -h for help." if Options.empty? && ARGV.empty?
21
28
 
22
- if ARGV
23
- if !Options[:appkey]
24
- puts "Must supply the api_key or keyname via --(a)pp"
25
- exit
26
- end
27
-
28
- if !Options[:user]
29
- puts "Must supply the username or token via --(u)ser."
30
- exit
31
- end
32
-
33
- api_key = Pushover::App.find Options[:appkey]
34
- user = Pushover::User.find Options[:user]
35
-
36
- response = Pushover.notification user, api_key, ARGV.join(" ")
37
- if response.code == 200
38
- puts "Message sent successfully!"
39
- else
40
- puts "#{response.code}: #{response.body}"
41
- end
29
+ bail = false
30
+ message = ARGV.join(" ")
31
+
32
+ if !message
33
+ puts "Must supply a message to be sent."
34
+ bail = true
42
35
  end
43
36
 
37
+ if !App.current_app?
38
+ puts "Couldn't find an app via the cli or save file."
39
+ bail = true
40
+ end
41
+
42
+ if !User.current_user?
43
+ puts "Couldn't find a user via the cli or save file."
44
+ bail = true
45
+ end
46
+ exit if bail
47
+ title = nil
48
+ response = Pushover.notification message, title, user:User.current_user, token:App.current_app
49
+
50
+ if response.code == "200"
51
+ puts "Message sent successfully!"
52
+ else
53
+ puts "#{response.code} #{response.message}:#{response.body}"
54
+ end
@@ -0,0 +1 @@
1
+ * the file spec/test_config is ignored intentionally, you can load your personal pushover details into this file for running specs successfully.
@@ -7,15 +7,55 @@ require "pushover/user"
7
7
  require "pushover/config"
8
8
  require "pushover/optparser"
9
9
 
10
+ # The primary pushover namespace.
10
11
  module Pushover
12
+
13
+ def params
14
+ Pushover.parameters
15
+ end
16
+
17
+ extend self
18
+
19
+ attr_accessor :token, :user
20
+
11
21
  # push a message to across pushover, must supply all variables.
12
- def self.notification(token, application, message, title = nil)
13
- url = URI.parse("https://api.pushover.net/1/messages")
22
+ def notification(message, title = nil, tokens={})
23
+ url = URI.parse("https://api.pushover.net/1/messages.json")
14
24
  req = Net::HTTP::Post.new(url.path)
15
- req.set_form_data({:token => token, :user => application, :message => message, :title => title})
25
+ req.set_form_data((params.merge(tokens.merge({:message => message, :title => title}))))
16
26
  res = Net::HTTP.new(url.host, url.port)
17
27
  res.use_ssl = true
18
28
  res.verify_mode = OpenSSL::SSL::VERIFY_PEER
19
29
  res.start {|http| http.request(req) }
20
30
  end
31
+
32
+ # Adds a rails style configure method
33
+ def configure
34
+ yield self
35
+ parameters
36
+ end
37
+
38
+ # List available parameters and values in those params
39
+ def parameters
40
+ @values = {}
41
+ keys.each { |k| @values.merge! k => get_var("@#{k}") }
42
+ @values
43
+ end
44
+
45
+ # Returns true or false if all parameters are set.
46
+ def parameters?
47
+ parameters.values.all?
48
+ end
49
+
50
+ def keys
51
+ keys ||= [:token, :user]
52
+ end
53
+
54
+ private
55
+
56
+ # Helper to clean up recursive method in #parameters
57
+ def get_var(var)
58
+ self.instance_variable_get(var)
59
+ end
60
+
21
61
  end
@@ -1,5 +1,11 @@
1
1
  module Pushover
2
+ # Stores a application definition in the config file.
2
3
  module App
4
+ # an instance of an application.
5
+ # @!attribute name
6
+ # @return [String] the name of the application.
7
+ # @!attribute api_key
8
+ # @return [String] the api_key of the application.
3
9
  class App
4
10
  attr_accessor :name
5
11
  attr_accessor :api_key
@@ -7,21 +13,22 @@ module Pushover
7
13
  def initialize(api_key, name)
8
14
  @name = name
9
15
  @api_key = api_key
10
- Pushover::Config[:applications] = {} if !Pushover::Config[:applications]
16
+ Config[:applications] = {} if !Config[:applications]
11
17
  if name
12
- Pushover::Config[:applications][name] = api_key
18
+ Config[:applications][name] = api_key
13
19
  else
14
- Pushover::Config[:applications][api_key] = api_key
20
+ Config[:applications][api_key] = api_key
15
21
  end
16
22
  end
17
-
18
23
  end
19
24
 
25
+ extend self
26
+
20
27
  # Find the apikey in the applications, or pass on the word to try direct access.
21
28
  # @param [String] word the search token, can be an apikey or appname.
22
29
  # @return [String] return the apikey (if it can find one) or the word itself.
23
- def self.find(word)
24
- return Config[:applications][word] if Config[:applications] && Config[:applications].include?(word)
30
+ def find(word)
31
+ return Config[:applications][word] if Config[:applications][word]
25
32
  word
26
33
  end
27
34
 
@@ -29,9 +36,31 @@ module Pushover
29
36
  # @param [String] api_key is the api_key to be used.
30
37
  # @param [String] name is the short name that can be referenced later.
31
38
  # @return [Boolean] return the results of the save attempt.
32
- def self.add(api_key, name)
39
+ def add(api_key, name)
33
40
  App.new api_key, name
34
41
  Pushover::Config.save!
35
42
  end
43
+
44
+ # Return the current app selected, or the first one saved.
45
+ def current_app
46
+ return @current_app if @current_app
47
+
48
+ # did something get supplied on the cli? try to find it.
49
+ if Options[:appkey]
50
+ @current_app = Pushover::App.find Options[:appkey]
51
+ end
52
+
53
+ # no? do we have anything we can return?
54
+ if !@current_app
55
+ @current_app = Config[:applications].first
56
+ end
57
+ @current_app
58
+ end
59
+
60
+ # Will return true if we can find an application either via the cli or save file.
61
+ def current_app?
62
+ return true if current_app
63
+ return nil
64
+ end
36
65
  end
37
66
  end
@@ -1,40 +1,62 @@
1
1
  require 'fileutils'
2
2
 
3
3
  module Pushover
4
+ # This is an extended [Hash] that adds some saving features via yajl.
4
5
  class ConfigBlob < Hash
5
- BaseDir = "#{Dir.home}/.config/pushover"
6
+ attr_accessor :save_file
7
+
8
+ # @return [String] the dirname of the save file.
9
+ def save_dir
10
+ File.dirname @save_file
11
+ end
6
12
 
7
13
  def initialize(load = true)
8
- FileUtils.mkdir_p BaseDir if !Dir.exist? BaseDir
14
+ @save_file = "#{Dir.home}/.config/pushover/config.json"
15
+
9
16
  self.load if load
10
17
  end
11
18
 
12
- def file
13
- "#{BaseDir}/config.json"
19
+ # Clear the config file (not implemented)
20
+ def clear
14
21
  end
15
22
 
23
+ # Save the config, will raise an exception if the file exists.
16
24
  def save
25
+ FileUtils.mkdir_p save_dir if !Dir.exist? save_dir
17
26
  if any?
18
27
  # I do this the long way because I want an immediate sync.
19
- f = open(file, 'w')
28
+ f = open(@save_file, 'w')
20
29
  f.write Yajl.dump self
21
30
  f.sync
22
31
  f.close
23
32
  end
24
33
  end
25
34
 
26
- def save!
27
- FileUtils.rm file if File.file? file
35
+ # Backup our save file, will remove original in the process.
36
+ def backupSave
37
+ FileUtils.mv @save_file, "#{@save_file}.bak" if File.file? @save_file
38
+ end
39
+
40
+ # Save the config, removing the existing one if necessary.
41
+ def save!(backup = true)
42
+ if backup
43
+ backupSave
44
+ else
45
+ FileUtils.rm @save_file if File.file? @save_file
46
+ end
47
+
28
48
  save
29
49
  end
30
50
 
51
+ # Load the config file if it is available.
31
52
  def load
32
- if File.exist?(self.file) && File.stat(self.file).size > 0
33
- h = Yajl.load open(file, 'r').read
53
+ if File.exist?(@save_file) && File.stat(@save_file).size > 0
54
+ h = Yajl.load open(@save_file, 'r').read
34
55
  h.each { |k,v| self[k.to_sym] = v}
35
56
  end
36
57
  end
37
58
  end
38
59
 
60
+ # A convenience instance of config, provides Pushover.Config.
39
61
  Config = ConfigBlob.new
40
62
  end
@@ -1,6 +1,9 @@
1
1
  require 'optparse'
2
2
 
3
3
  module Pushover
4
+ # override the built-in [OptionParser], adding some nifty features.
5
+ # Options[] is a hash value designed to collect the contents added to @options.
6
+
4
7
  class OptionParser < ::OptionParser
5
8
  def initialize
6
9
  super
@@ -10,6 +13,7 @@ module Pushover
10
13
  on("-u", "--user USER", "Which user, can be a saved name or token.") { |o| @options[:user] = o}
11
14
  on("-a", "--app APPKEY", "Which app to notify, can be a saved name or apikey.") { |o| @options[:appkey] = o}
12
15
  on("-T", "--title [TITLE]", "Set the title of the notification (optional).") { |o| @options[:title] = o}
16
+ on("-c", "--config_file [FILE]", "Set the target config file.") {|o| @options[:config_file] = o}
13
17
  on("--save-app NAME", "Saves the application to the config file under NAME.") { |o| @options[:save_app] = [@options[:appkey], o]}
14
18
  on("--save-user NAME", "Saves the user to the config file under NAME.") { |o| @options[:save_user] = [@options[:user], o]}
15
19
  end
@@ -22,8 +26,10 @@ module Pushover
22
26
  end
23
27
  end
24
28
 
29
+ # Build out the banner and calls the built in parse!
30
+ # Loads any saved options automatically.
25
31
  def parse!
26
- @banner = Pushover::VERSION
32
+ @banner = "Send notifications over to pushover.net.\n\n"
27
33
  super
28
34
 
29
35
  if @options[:version]
@@ -38,20 +44,26 @@ module Pushover
38
44
  end
39
45
  end
40
46
 
47
+ # Entry point to the options hash
48
+ # @return will return the value of key if provided, else the entire [Hash]
41
49
  def [](k = nil)
42
50
  return @options[k] if k
43
51
  return @options if @options.any?
44
52
  nil
45
53
  end
46
54
 
55
+ # Set a value in the option array, used as a way to store the results of the parsed value.
47
56
  def []=(k,v)
48
57
  @options[k] = v
49
58
  end
50
59
 
60
+ # Check to see if the option hash has any k/v pairs.
61
+ # @return [Boolean] true if any pairs at all, false otherwise.
51
62
  def empty?
52
63
  @options.empty?
53
64
  end
54
65
  end
55
66
 
67
+ # Add a built in Options to the Pushover namespace, purely a convenience thing.
56
68
  Options = OptionParser.new
57
69
  end
@@ -1,5 +1,11 @@
1
1
  module Pushover
2
+ # The user module, saves any user information provided.
2
3
  module User
4
+ # The User class, for a single instance of it.
5
+ # @!attribute name
6
+ # @return [String] the name of the user.
7
+ # @!attribute token
8
+ # @return [String] the token of the user.
3
9
  class User
4
10
  attr_accessor :name
5
11
  attr_accessor :token
@@ -7,17 +13,19 @@ module Pushover
7
13
  def initialize(token, name)
8
14
  @name = name
9
15
  @token = token
10
- Pushover::Config[:users] = {} if !Pushover::Config[:users]
11
- Pushover::Config[:users][name] = token
16
+ Config[:users] = {} if !Config[:users]
17
+ Config[:users][name] = token
12
18
  end
13
19
 
14
20
  end
15
21
 
22
+ extend self
23
+
16
24
  # Find the apikey in the applications, or pass on the word to try direct access.
17
25
  # @param [String] word the search token, can be an apikey or appname.
18
26
  # @return [String] return the apikey (if it can find one) or the word itself.
19
- def self.find(word)
20
- return Config[:users][word] if Config[:users] && Config[:users].include?(word)
27
+ def find(word)
28
+ return Config[:users][word] if Config[:users][word]
21
29
  word
22
30
  end
23
31
 
@@ -25,9 +33,31 @@ module Pushover
25
33
  # @param [String] token is the token to be used.
26
34
  # @param [String] name is the short name that can be referenced later.
27
35
  # @return [Boolean] return the results of the save attempt.
28
- def self.add(token, name)
36
+ def add(token, name)
29
37
  User.new token, name
30
38
  Pushover::Config.save!
31
39
  end
40
+
41
+ # Return the current user selected, or the first one saved.
42
+ def current_user
43
+ return @current_user if @current_user
44
+
45
+ # did something get supplied on the cli? try to find it.
46
+ if Options[:user]
47
+ @current_user = Pushover::User.find Options[:user]
48
+ end
49
+
50
+ # no? do we have anything we can return?
51
+ if !@current_user
52
+ @current_user = Config[:users].first
53
+ end
54
+ @current_user
55
+ end
56
+
57
+ # Will return true if it can find a user either via the cli or save file.
58
+ def current_user?
59
+ return true if current_user
60
+ return nil
61
+ end
32
62
  end
33
63
  end
@@ -1,3 +1,4 @@
1
1
  module Pushover
2
- VERSION = "0.2.0"
2
+ # The current version of Pushover.
3
+ VERSION = "0.3.1"
3
4
  end
@@ -0,0 +1,19 @@
1
+ require 'pushover'
2
+
3
+ describe "application" do
4
+ before(:each) do
5
+ Pushover::Config.save_file = "test.save"
6
+ Pushover::Config.clear
7
+ end
8
+
9
+ it "can add a application to the Config[:application] hash." do
10
+ Pushover::App.add "bar", "foo"
11
+ Pushover::Config[:applications]["foo"].should eq("bar")
12
+ end
13
+
14
+ it "can remove a application from the hash."
15
+ it "can find the apikey from the name" do
16
+ Pushover::App.add "bar", "foo"
17
+ Pushover::App.find("foo").should eq("bar")
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ describe "CLI Interface" do
2
+ # the save file to be used.
3
+ SaveFile = 'spec/test_config'
4
+ # the exact string to execute the test version of pushover.
5
+ Exec = "bundle exec bin/pushover"
6
+ ExecConfig = Exec + " -c #{SaveFile}"
7
+ describe "Can select the config file" do
8
+ it "short form (-c)" do
9
+ output = `#{ExecConfig}`
10
+ output.include? "Selecting config file: #{SaveFile}"
11
+ end
12
+
13
+ it "long form (--config_file)" do
14
+ output = `#{Exec} -c #{SaveFile}`
15
+ output.include? "Selecting config file: #{SaveFile}"
16
+ end
17
+ end
18
+ describe "Saving" do
19
+ it "Application." do
20
+ output = `#{ExecConfig} --app 'test_app_api_key' --save-app test_app`
21
+ output.include?("Save successful").should be_true
22
+ end
23
+ it "User." do
24
+ output = `#{ExecConfig} --user 'test_user_key' --save-app test_user`
25
+ output.include?("Save successful").should be_true
26
+ end
27
+ end
28
+ describe "Sending a message" do
29
+ it "With no saved info."
30
+ context "With saved information" do
31
+ it "With a saved user"
32
+ it "With a saved app"
33
+ it "With both"
34
+ end
35
+ describe "Title" do
36
+ it "can send with a title"
37
+ it "can send without a title"
38
+ end
39
+ end
40
+ it "provides the proper version number"
41
+ end
42
+
@@ -0,0 +1,29 @@
1
+ require 'pushover'
2
+
3
+ describe "Config" do
4
+ before(:all) do
5
+ Pushover::Config.save_file = "config_spec.tmp"
6
+ Pushover::Config.clear
7
+ Pushover::Config[:test] = true
8
+ Pushover::Config.save!
9
+ end
10
+
11
+ it "should exist" do
12
+ expect { Pushover::Config }.to_not be(nil)
13
+ end
14
+
15
+ it "should have a save_file" do
16
+ Pushover::Config.save_file.should eq("config_spec.tmp")
17
+ end
18
+
19
+ it "save_dir should be the basename of save_file" do
20
+ Pushover::Config.save_dir.should eq(File.dirname Pushover::Config.save_file)
21
+ end
22
+
23
+ it "should save if not empty"
24
+ it "should make a backup"
25
+ it "should load" do
26
+ Pushover::Config.load
27
+ Pushover::Config[:test].should eq(true)
28
+ end
29
+ end
File without changes
@@ -0,0 +1,5 @@
1
+ require 'pushover'
2
+
3
+ describe "Pushover" do
4
+ it "can send a notification"
5
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
@@ -0,0 +1,21 @@
1
+ require 'pushover'
2
+
3
+ describe "user" do
4
+ before(:each) do
5
+ Pushover::Config.save_file = "test.save"
6
+ Pushover::Config.clear
7
+ end
8
+
9
+ it "can add a user to the Config[:application] hash." do
10
+ Pushover::User.add "bar", "foo"
11
+ Pushover::Config[:users]["foo"].should eq("bar")
12
+ end
13
+
14
+ it "can remove a user from the hash."
15
+ it "can find the token from the name" do
16
+ Pushover::User.add "bar", "foo"
17
+ Pushover::User.find("foo").should eq("bar")
18
+ end
19
+ end
20
+
21
+
@@ -0,0 +1,7 @@
1
+ 0.3.0
2
+ * No longer need to supply credentials at all if you have some saved.
3
+ * Fixed up a ton of documentation and spelling mistakes.
4
+ * Various bug fixes.
5
+ * About thirty percent of the tests are complete.
6
+ * Added convience methods for App.current_app and User.current_user to supply the correctly inherited credentials.
7
+ * Will only create the save directory if you attempt to save.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pushover
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-15 00:00:00.000000000 Z
12
+ date: 2012-10-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pry
@@ -57,6 +57,7 @@ files:
57
57
  - README.md
58
58
  - Rakefile
59
59
  - bin/pushover
60
+ - dev_notes.md
60
61
  - lib/pushover.rb
61
62
  - lib/pushover/app.rb
62
63
  - lib/pushover/config.rb
@@ -64,6 +65,14 @@ files:
64
65
  - lib/pushover/user.rb
65
66
  - lib/pushover/version.rb
66
67
  - pushover.gemspec
68
+ - spec/app_spec.rb
69
+ - spec/cli_spec.rb
70
+ - spec/config_spec.rb
71
+ - spec/optparser_spec.rb
72
+ - spec/pushover_spec.rb
73
+ - spec/spec_helper.rb
74
+ - spec/user_spec.rb
75
+ - whatsnew.md
67
76
  homepage: ''
68
77
  licenses: []
69
78
  post_install_message:
@@ -88,5 +97,12 @@ rubygems_version: 1.8.21
88
97
  signing_key:
89
98
  specification_version: 3
90
99
  summary: This gem will provide both an API and CLI interface to pushover.net.
91
- test_files: []
100
+ test_files:
101
+ - spec/app_spec.rb
102
+ - spec/cli_spec.rb
103
+ - spec/config_spec.rb
104
+ - spec/optparser_spec.rb
105
+ - spec/pushover_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/user_spec.rb
92
108
  has_rdoc: