presence 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.simplecov CHANGED
@@ -10,5 +10,6 @@ SimpleCov.formatter = SimpleCov::Formatter::QualityFormatter
10
10
 
11
11
  SimpleCov.start do
12
12
  add_filter '/spec/'
13
- add_group 'CLI', 'lib/duple/cli'
13
+ add_group 'CLI', 'lib/presence/cli'
14
+ add_group 'Listeners', 'lib/presence/listeners'
14
15
  end
data/Rakefile CHANGED
@@ -13,7 +13,7 @@ begin
13
13
  cane.abc_max = 15
14
14
  cane.style_measure = 100
15
15
  cane.style_glob = '{lib}/**/*.rb'
16
- cane.gte = {'coverage/covered_percent' => 50}
16
+ cane.gte = {'coverage/covered_percent' => 80}
17
17
  end
18
18
  rescue LoadError
19
19
  warn "cane not available, quality task not provided."
data/bin/presence_scan CHANGED
@@ -8,14 +8,28 @@ if File.exists?(File.join(File.expand_path('../..', __FILE__), '.git'))
8
8
  end
9
9
 
10
10
  require 'presence'
11
+
11
12
  # Presence::CLI::Root.start
12
13
 
14
+ # Usage: presence [OPTIONS]
15
+ #
16
+ # presence --start 10.0.1.1 --end 10.0.1.30
17
+ # presence --prefix 192.168.0
18
+ # presence --verbose
19
+ # presence --quiet
20
+ # presence --once
21
+ # presence --loop
22
+ # presence --listener Carnegie::Listener
23
+
24
+ # --once
13
25
  # s = Presence::Scanner.new
14
26
  # s.register_listener(Presence::Logger.new)
15
27
  # s.register_listener(Presence::Tracker.new)
16
28
  # s.scan
17
29
 
30
+ # --loop
18
31
  Presence::Scanner.scan_loop do |s|
32
+ # s.options[:octet_range] = (30..32)
19
33
  s.register_listener(Presence::Logger.new)
20
34
  s.register_listener(Presence::Tracker.new)
21
35
  end
@@ -2,7 +2,8 @@ module Presence
2
2
  # Wrapper class for shell command execution.
3
3
  class Commands
4
4
  def arping(ip)
5
- result = run("sudo arping -c 1 #{ip}")
5
+ cmd = "sudo arping -c 1 #{ip}"
6
+ result = run(cmd)
6
7
  [cmd, result]
7
8
  end
8
9
 
@@ -0,0 +1,83 @@
1
+ require "net/https"
2
+ require "uri"
3
+
4
+ module Presence
5
+
6
+ # Scanner listener that sends an HTTP notification whenever a new client
7
+ # connects or when a connected client disconnects. This listener is intended
8
+ # to be used with Presence::Tracker when scanning in a loop.
9
+ class HTTPNotifier
10
+
11
+ def initialize(options = nil)
12
+ options ||= {}
13
+ @options = {
14
+ use_ssl: false,
15
+ verify_mode: OpenSSL::SSL::VERIFY_PEER
16
+ }.merge(options)
17
+ end
18
+
19
+ def listener_registered(l, scanner)
20
+ @scanner ||= scanner
21
+ end
22
+
23
+ def mac_connected(mac, ip)
24
+ notify(:mac_connected, { mac: mac, ip: ip })
25
+ end
26
+
27
+ def mac_disconnected(mac, old_ip)
28
+ notify(:mac_disconnected, { mac: mac, ip: old_ip })
29
+ end
30
+
31
+ protected
32
+
33
+ def notify_uri
34
+ @notify_uri ||= URI.parse(@options[:url])
35
+ end
36
+
37
+ def notify(event, params)
38
+ request = prepare_request(event, params)
39
+ do_request(request)
40
+ end
41
+
42
+ def do_request(request)
43
+ response = nil
44
+
45
+ begin
46
+ http = prepare_http
47
+ response = http.request(request)
48
+ check_response(response)
49
+ rescue SocketError,
50
+ Timeout::Error,
51
+ Errno::ECONNREFUSED,
52
+ Errno::EHOSTDOWN,
53
+ Errno::EHOSTUNREACH,
54
+ Errno::ETIMEDOUT => e
55
+ @scanner.dispatch(:http_notification_failed, e.class.name, e.message)
56
+ end
57
+
58
+ response
59
+ end
60
+
61
+ def prepare_request(event, params)
62
+ request = Net::HTTP::Post.new(notify_uri.request_uri, @options[:headers])
63
+ request.set_form_data(params.merge(event: event))
64
+ if @options[:username]
65
+ request.basic_auth(@options[:username], @options[:password])
66
+ end
67
+ request
68
+ end
69
+
70
+ def prepare_http
71
+ http = Net::HTTP.new(notify_uri.host, notify_uri.port)
72
+ http.use_ssl = @options[:use_ssl]
73
+ http.verify_mode = @options[:verify_mode]
74
+ http
75
+ end
76
+
77
+ def check_response(response)
78
+ unless (200..206).map(&:to_s).include?(response.code)
79
+ @scanner.dispatch(:http_notification_failed, response.code, response.body)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -5,61 +5,88 @@ module Presence
5
5
  # default, it uses a Logger instance that writes to stdout. To enable more
6
6
  # verbose output, set:
7
7
  #
8
- # logger.level = ::Logger::INFO
8
+ # logger.log.level = ::Logger::INFO
9
9
  #
10
10
  # or:
11
11
  #
12
- # logger.level = ::Logger::DEBUG
12
+ # logger.log.level = ::Logger::DEBUG
13
13
  #
14
- # To write to a file or some other outlet, pass an instance of Logger to the
14
+ # To write to a file or some other outlet, pass a Ruby Logger instance to the
15
15
  # constructor.
16
16
  class Logger
17
- attr_accessor :logger
17
+ attr_accessor :log
18
18
 
19
19
  def initialize(log = nil)
20
20
  if log.nil?
21
- log = ::Logger.new(STDOUT)
21
+ log = ::Logger.new($stdout)
22
22
  log.level = ::Logger::WARN
23
23
  log.formatter = proc do |severity, datetime, progname, msg|
24
24
  "#{msg}\n"
25
25
  end
26
26
  end
27
- self.logger = log
27
+ self.log = log
28
28
  end
29
29
 
30
30
  def listener_registered(listener, scanner)
31
- logger.info "Registered listener: <#{listener.class}> for: #{scanner}"
31
+ log.info "Registered listener: <#{listener.class}> for: #{scanner}"
32
32
  end
33
33
 
34
34
  def scan_started(ip_prefix, range)
35
- logger.info "Checking range: #{ip_prefix}.#{range.first} to #{ip_prefix}.#{range.last}"
35
+ log.info "Scanning range: #{ip_prefix}.#{range.first} to #{ip_prefix}.#{range.last}"
36
36
  end
37
37
 
38
38
  def scan_finished(ip_prefix, range)
39
- logger.info "Scan finished."
39
+ log.info "Scan finished."
40
40
  end
41
41
 
42
42
  def ip_scanned(ip, cmd, result)
43
- logger.debug " - Checked #{ip} with #{cmd}"
43
+ log.debug " - Checked #{ip} with #{cmd}"
44
44
  result.split("\n").each do |l|
45
- logger.debug " #{l}"
45
+ log.debug " #{l}"
46
46
  end
47
47
  end
48
48
 
49
49
  def localhost_found(ip, mac)
50
- logger.debug " * Found localhost!"
50
+ log.debug " * Found localhost!"
51
51
  end
52
52
 
53
53
  def mac_found(ip, mac)
54
- logger.debug
55
- logger.debug " * Found #{mac} at #{ip}"
56
- logger.debug
54
+ log.debug " * Found #{mac} at #{ip}"
57
55
  end
58
56
 
59
57
  def mac_not_found(ip)
60
- logger.debug
61
- logger.debug " * No MAC found at #{ip}"
62
- logger.debug
58
+ log.debug " * No MAC found at #{ip}"
59
+ end
60
+
61
+ protected
62
+
63
+ def log_unknown_event(method_sym, *arguments)
64
+ # puts "method_sym = #{method_sym}"
65
+ # puts "arguments = #{arguments.inspect}"
66
+ # puts "log = #{log}"
67
+ # raise 'hell'
68
+ log.warn("#{method_sym}: #{arguments.inspect}")
69
+ end
70
+
71
+ # Always log events, even if there is no explicit handler. Generate a
72
+ # method at runtime so we don't have to do method_missing every time.
73
+ def method_missing(method_sym, *arguments, &block)
74
+ arg_names = arguments.each_with_index.map { |arg, i| "arg#{i}" }
75
+ arg_list = arg_names.join(',')
76
+ instance_eval <<-RUBY
77
+ def #{method_sym}(#{arg_list})
78
+ log_unknown_event(:#{method_sym}, #{arg_list})
79
+ end
80
+ RUBY
81
+ # def method_sym(arg1, arg2, ...)
82
+ # log_unknown_event(:method_sym, arg1, arg2, ...)
83
+ # end
84
+ send(method_sym, *arguments)
85
+ end
86
+
87
+ # Respond to anything.
88
+ def respond_to_missing?(method_sym, include_private = false)
89
+ true
63
90
  end
64
91
  end
65
92
  end
@@ -7,20 +7,23 @@ module Presence
7
7
  # list of MAC addresses on the network and detect when a new client connects
8
8
  # or when a connected client disconnects.
9
9
  class Tracker
10
+
10
11
  def initialize
11
12
  @mac_history = {}
12
13
  @current_list = Presence::MACList.new
13
14
  end
14
15
 
15
16
  def listener_registered(l, scanner)
16
- scanner.register_listener(@current_list) if l == self
17
+ @scanner ||= scanner
18
+ @scanner.register_listener(@current_list) if l == self
17
19
  end
18
20
 
19
21
  def mac_found(ip, mac)
20
22
  if @mac_history[mac].nil?
21
- mac_connected(mac, ip)
23
+ dispatch(:mac_connected, mac, ip)
22
24
  elsif @mac_history[mac] != ip
23
- mac_changed(mac, @mac_history[mac], ip)
25
+ old_ip = @mac_history[mac]
26
+ dispatch(:mac_changed, mac, old_ip, ip)
24
27
  end
25
28
  @mac_history[mac] = ip
26
29
  end
@@ -29,25 +32,14 @@ module Presence
29
32
  macs_left = @mac_history.keys - @current_list.macs_found.keys
30
33
  macs_left.each do |mac|
31
34
  old_ip = @mac_history[mac]
32
- mac_disconnected(mac, old_ip)
35
+ dispatch(:mac_disconnected, mac, old_ip)
33
36
  @mac_history.delete(mac)
34
37
  end
35
38
  @current_list.macs_found.clear
36
39
  end
37
40
 
38
- def mac_connected(mac, ip)
39
- puts " ** #{mac} connected as #{ip}"
40
- # Do something interesting.
41
- end
42
-
43
- def mac_changed(mac, old_ip, new_ip)
44
- puts " ** #{mac} changed ip from: #{old_ip} to #{new_ip}"
45
- # Do something interesting.
46
- end
47
-
48
- def mac_disconnected(mac, old_ip)
49
- puts " ** #{mac} disconnected from #{old_ip}"
50
- # Do something interesting.
41
+ def dispatch(event, *args)
42
+ @scanner.dispatch(event, *args)
51
43
  end
52
44
  end
53
45
  end
@@ -82,12 +82,11 @@ module Presence
82
82
  class << self
83
83
  def check_env
84
84
  commands = Commands.new
85
- if commands.run('which ifconfig').size == 0
86
- raise Presence::InvalidEnvironment.new("Unsupported platform: ifconfig not found.")
87
- end
88
- if commands.run('which arping').size == 0
89
- raise Presence::InvalidEnvironment.new("Unsupported platform: arping not found.")
90
- raise Presence::InvalidEnvironment.new("Install arping first: brew install arping")
85
+ required_commands = %w{ifconfig arping}
86
+ required_commands.each do |cmd|
87
+ if commands.run("which #{cmd}").size == 0
88
+ raise Presence::InvalidEnvironment.new("Unsupported platform: #{cmd} not found.")
89
+ end
91
90
  end
92
91
  end
93
92
 
@@ -1,3 +1,3 @@
1
1
  module Presence
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/presence.rb CHANGED
@@ -7,3 +7,4 @@ require 'presence/listeners/mac_list'
7
7
  require 'presence/listeners/mac_printer'
8
8
  require 'presence/listeners/nmapper'
9
9
  require 'presence/listeners/tracker'
10
+ require 'presence/listeners/http_notifier'
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe Presence::HTTPNotifier do
4
+ let(:username) { nil }
5
+ let(:password) { nil }
6
+ let(:notifier) {
7
+ Presence::HTTPNotifier.new(
8
+ url: 'http://example.com/presence_events.json',
9
+ username: username,
10
+ password: password
11
+ )
12
+ }
13
+
14
+ let(:scanner) { stub(Presence::Scanner) }
15
+ before { notifier.listener_registered(notifier, scanner) }
16
+
17
+ let(:http) { stub(Net::HTTP, :use_ssl= => nil, :verify_mode= => nil) }
18
+ let(:response) { stub(code: '200') }
19
+ before {
20
+ http.stub(:request).and_return(response)
21
+ Net::HTTP.stub(:new).with('example.com', 80).and_return(http)
22
+ }
23
+
24
+ context 'with a username and password' do
25
+ let(:username) { 'margot' }
26
+ let(:password) { 'poppie' }
27
+
28
+ it 'sends the username and password in the request' do
29
+ http.should_receive(:request) do |r|
30
+ r['authorization'].should == 'Basic bWFyZ290OnBvcHBpZQ=='
31
+ response
32
+ end
33
+ notifier.mac_connected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
34
+ end
35
+ end
36
+
37
+ it 'dispatches an error notification if the request returns an error code' do
38
+ response.should_receive(:code).at_least(1).times.and_return('400')
39
+ response.should_receive(:body).and_return('Invalid request')
40
+ scanner.should_receive(:dispatch).with(:http_notification_failed, '400', 'Invalid request')
41
+
42
+ notifier.mac_connected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
43
+ end
44
+
45
+ it 'dispatches an error notification if the request raises a network error' do
46
+ http.should_receive(:request).and_raise(SocketError.new('bad things occurred'))
47
+ scanner.should_receive(:dispatch).with(:http_notification_failed, 'SocketError', 'bad things occurred')
48
+
49
+ notifier.mac_connected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
50
+ end
51
+
52
+ it 'sends a POST request on mac_connected' do
53
+ http.should_receive(:request) do |r|
54
+ r.method.should == 'POST'
55
+ r.body.should == 'mac=AA%3ABB%3ACC%3ADD%3AEE%3AFF&ip=10.0.1.49&event=mac_connected'
56
+ response
57
+ end
58
+ notifier.mac_connected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
59
+ end
60
+
61
+ it 'sends a POST request on mac_disconnected' do
62
+ http.should_receive(:request) do |r|
63
+ r.method.should == 'POST'
64
+ r.body.should == 'mac=AA%3ABB%3ACC%3ADD%3AEE%3AFF&ip=10.0.1.49&event=mac_disconnected'
65
+ response
66
+ end
67
+ notifier.mac_disconnected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
68
+ end
69
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe Presence::Logger do
4
+ let(:level) { ::Logger::INFO }
5
+ let(:io) { StringIO.new }
6
+ let(:log) {
7
+ log = ::Logger.new(io)
8
+ log.level = level
9
+ log.formatter = proc do |severity, datetime, progname, msg|
10
+ "#{msg}\n"
11
+ end
12
+ log
13
+ }
14
+ let(:logger) { Presence::Logger.new(log) }
15
+
16
+ context 'with no ::Logger specified' do
17
+ let(:log) { nil }
18
+
19
+ it 'logs warnings to stdout by default' do
20
+ result = capture_stdout do |variable|
21
+ logger.log.warn('Run, baby, run!')
22
+ end
23
+ result.should == "Run, baby, run!\n"
24
+ end
25
+
26
+ it 'does not log info by default' do
27
+ result = capture_stdout do |variable|
28
+ logger.log.info('Run, baby, run!')
29
+ end
30
+ result.should == ''
31
+ end
32
+ end
33
+
34
+ context 'with DEBUG logging' do
35
+ let(:level) { ::Logger::DEBUG }
36
+
37
+ it 'logs ip_scanned events' do
38
+ logger.ip_scanned('10.0.1.1', 'sudo arping', 'nada')
39
+ io.string.should == " - Checked 10.0.1.1 with sudo arping\n nada\n"
40
+ end
41
+
42
+ it 'logs localhost_found events' do
43
+ logger.localhost_found('10.0.1.1', 'AA:BB:CC:DD:EE:FF')
44
+ io.string.should == " * Found localhost!\n"
45
+ end
46
+
47
+ it 'logs mac_found events' do
48
+ logger.mac_found('10.0.1.1', 'aa:bb:cc:dd:ee:ff')
49
+ io.string.should == " * Found aa:bb:cc:dd:ee:ff at 10.0.1.1\n"
50
+ end
51
+
52
+ it 'logs mac_not_found events' do
53
+ logger.mac_not_found('10.0.1.1')
54
+ io.string.should == " * No MAC found at 10.0.1.1\n"
55
+ end
56
+
57
+ it 'logs unknown events' do
58
+ logger.respond_to?(:miracle_occurred).should be_true
59
+ logger.miracle_occurred('256.256.256.256', 'GG:GG:GG:GG:GG:GG', 49)
60
+ io.string.should == "miracle_occurred: [\"256.256.256.256\", \"GG:GG:GG:GG:GG:GG\", 49]\n"
61
+ end
62
+
63
+ end
64
+
65
+ context 'with INFO logging' do
66
+ let(:level) { ::Logger::INFO }
67
+
68
+ it 'logs listener_registered events' do
69
+ logger.listener_registered(logger, 'Scanner')
70
+ io.string.should == "Registered listener: <Presence::Logger> for: Scanner\n"
71
+ end
72
+
73
+ it 'logs scan_started events' do
74
+ logger.scan_started('10.0.1', (1..255))
75
+ io.string.should == "Scanning range: 10.0.1.1 to 10.0.1.255\n"
76
+ end
77
+
78
+ it 'logs scan_finished events' do
79
+ logger.scan_finished('10.0.1', (1..255))
80
+ io.string.should == "Scan finished.\n"
81
+ end
82
+
83
+ it 'does not log ip_scanned events' do
84
+ logger.ip_scanned('10.0.1.1', 'sudo arping', 'nada')
85
+ io.string.should == ''
86
+ end
87
+
88
+ it 'does not log localhost_found events' do
89
+ logger.localhost_found('10.0.1.1', 'aa:bb:cc:dd:ee:ff')
90
+ io.string.should == ''
91
+ end
92
+
93
+ it 'does not log mac_found events' do
94
+ logger.mac_found('10.0.1.1', 'aa:bb:cc:dd:ee:ff')
95
+ io.string.should == ''
96
+ end
97
+
98
+ it 'does not log mac_not_found events' do
99
+ logger.mac_not_found('10.0.1.1')
100
+ io.string.should == ''
101
+ end
102
+ end
103
+ end
@@ -10,7 +10,7 @@ describe Presence::Scanner do
10
10
 
11
11
  let(:commands) {
12
12
  commands = stub(Presence::Commands)
13
- Presence::Commands.should_receive(:new).and_return(commands)
13
+ Presence::Commands.stub(:new).and_return(commands)
14
14
  commands
15
15
  }
16
16
  let(:listener) {
@@ -28,6 +28,63 @@ describe Presence::Scanner do
28
28
  commands.stub(:arping).with(ip).and_return([arping_cmd, mac])
29
29
  }
30
30
 
31
+ describe '.check_env' do
32
+ before {
33
+ commands.stub(:run).with('which ifconfig').and_return('/sbin/ifconfig')
34
+ commands.stub(:run).with('which arping').and_return('/usr/local/sbin/arping')
35
+ }
36
+
37
+ it 'checks for ifconfig' do
38
+ commands.should_receive(:run).with('which ifconfig').and_return('/sbin/ifconfig')
39
+ Presence::Scanner.check_env
40
+ end
41
+
42
+ it 'raises an exception if ifconfig is not found' do
43
+ commands.should_receive(:run).with('which ifconfig').and_return('')
44
+ expect {
45
+ Presence::Scanner.check_env
46
+ }.to raise_error(Presence::InvalidEnvironment, "Unsupported platform: ifconfig not found.")
47
+ end
48
+
49
+ it 'checks for arping' do
50
+ commands.should_receive(:run).with('which arping').and_return('/usr/local/sbin/arping')
51
+ Presence::Scanner.check_env
52
+ end
53
+
54
+ it 'raises an exception if arping is not found' do
55
+ commands.should_receive(:run).with('which arping').and_return('')
56
+ expect {
57
+ Presence::Scanner.check_env
58
+ }.to raise_error(Presence::InvalidEnvironment, "Unsupported platform: arping not found.")
59
+ end
60
+ end
61
+
62
+ describe '.scan_loop' do
63
+ let(:scanner) { mock(Presence::Scanner) }
64
+ before { Presence::Scanner.should_receive(:new).and_return(scanner) }
65
+
66
+ it 'scans until interrupted' do
67
+ scanner.should_receive(:scan)
68
+ scanner.should_receive(:scan)
69
+ scanner.should_receive(:scan).and_raise(Interrupt.new)
70
+ Presence::Scanner.scan_loop
71
+ end
72
+
73
+ it 'yields the scanner instance to a block' do
74
+ scanner.stub(:scan).and_raise(Interrupt.new)
75
+ scanner.should_receive(:register_listener)
76
+ Presence::Scanner.scan_loop do |s|
77
+ s.register_listener(Object.new)
78
+ end
79
+ end
80
+ end
81
+
82
+ describe '#to_s' do
83
+ it 'overrides to_s' do
84
+ scanner.to_s.should == "<Presence::Scanner ip_prefix: '10.0.1' octet_range: (30..32)>"
85
+ end
86
+ end
87
+
31
88
  describe '#scan' do
32
89
  it 'dispatches a scan_started event' do
33
90
  listener.should_receive(:scan_started).with('10.0.1', octet_range)
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Presence::Tracker do
4
+ end
@@ -0,0 +1,33 @@
1
+ module Presence
2
+ module IOSpecHelpers
3
+ def suppress_output
4
+ @original_stdout, $stdout = $stdout, StringIO.new
5
+ @original_stderr, $stderr = $stderr, StringIO.new
6
+ end
7
+
8
+ def reset_output
9
+ $stdout = @original_stdout
10
+ $stderr = @original_stderr
11
+ end
12
+
13
+ def capture_stdout
14
+ original_stdout, $stdout = $stdout, StringIO.new
15
+ yield
16
+ $stdout.string
17
+ ensure
18
+ $stdout = original_stdout
19
+ end
20
+
21
+ def capture_stderr
22
+ original_stderr, $stderr = $stderr, StringIO.new
23
+ yield
24
+ $stderr.string
25
+ ensure
26
+ $stderr = original_stderr
27
+ end
28
+ end
29
+ end
30
+
31
+ RSpec.configure do |config|
32
+ config.include Presence::IOSpecHelpers
33
+ end
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: presence
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jason Wadsworth
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-23 00:00:00.000000000 Z
12
+ date: 2012-11-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  prerelease: false
@@ -94,6 +94,7 @@ files:
94
94
  - lib/presence.rb
95
95
  - lib/presence/commands.rb
96
96
  - lib/presence/errors.rb
97
+ - lib/presence/listeners/http_notifier.rb
97
98
  - lib/presence/listeners/logger.rb
98
99
  - lib/presence/listeners/mac_list.rb
99
100
  - lib/presence/listeners/mac_printer.rb
@@ -102,8 +103,12 @@ files:
102
103
  - lib/presence/scanner.rb
103
104
  - lib/presence/version.rb
104
105
  - presence.gemspec
106
+ - spec/presence/http_notifier_spec.rb
107
+ - spec/presence/logger_spec.rb
105
108
  - spec/presence/scanner_spec.rb
109
+ - spec/presence/tracker_spec.rb
106
110
  - spec/spec_helper.rb
111
+ - spec/support/io_spec_helpers.rb
107
112
  homepage: https://github.com/subakva/presence
108
113
  licenses: []
109
114
  post_install_message:
@@ -129,5 +134,9 @@ signing_key:
129
134
  specification_version: 3
130
135
  summary: Plays theme music when d8:d1:cb:b3:af:c4 arrives.
131
136
  test_files:
137
+ - spec/presence/http_notifier_spec.rb
138
+ - spec/presence/logger_spec.rb
132
139
  - spec/presence/scanner_spec.rb
140
+ - spec/presence/tracker_spec.rb
133
141
  - spec/spec_helper.rb
142
+ - spec/support/io_spec_helpers.rb