watcher_in_the_water 0.1
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.
- data/History.txt +6 -0
- data/Manifest.txt +13 -0
- data/README.rdoc +34 -0
- data/Rakefile +16 -0
- data/bin/watcher_in_the_water +6 -0
- data/lib/watcher_in_the_water.rb +68 -0
- data/test/fixtures/dimrill_gate +1 -0
- data/test/fixtures/durins_bridge +1 -0
- data/test/fixtures/west_gate +1 -0
- data/test/live.yml +6 -0
- data/test/live_test.rb +54 -0
- data/test/test_watcher_in_the_water.rb +60 -0
- data/test/watcher/test.yml +8 -0
- metadata +87 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.rdoc
|
4
|
+
Rakefile
|
5
|
+
bin/watcher_in_the_water
|
6
|
+
lib/watcher_in_the_water.rb
|
7
|
+
test/fixtures/dimrill_gate
|
8
|
+
test/fixtures/durins_bridge
|
9
|
+
test/fixtures/west_gate
|
10
|
+
test/live.yml
|
11
|
+
test/live_test.rb
|
12
|
+
test/test_watcher_in_the_water.rb
|
13
|
+
test/watcher/test.yml
|
data/README.rdoc
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
= Watcher In The Water - http://en.wikipedia.org/wiki/Watcher_in_the_Water
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
Want to know when the page at a given URL changes? The Watcher in the
|
6
|
+
Water will tell you over Jabber; just create a ~/.watcher/config.yml
|
7
|
+
file and toss +watcher_in_the_water+ into your crontab!
|
8
|
+
|
9
|
+
---
|
10
|
+
jid: watcher-in-the-water@jabber.org
|
11
|
+
password: mellon
|
12
|
+
recipient: phil@hagelb.org
|
13
|
+
urls:
|
14
|
+
- http://rubyconf.org
|
15
|
+
|
16
|
+
== Issues
|
17
|
+
|
18
|
+
XMPP4R takes a really long time to authenticate with my Jabber
|
19
|
+
server. Maybe it's just me though... No idea. This shouldn't run more
|
20
|
+
than once an hour or so, whatever; shouldn't matter.
|
21
|
+
|
22
|
+
== Install
|
23
|
+
|
24
|
+
$ sudo gem install technomancy-watcher_in_the_water --source=http://gems.github.com
|
25
|
+
|
26
|
+
== TODO
|
27
|
+
|
28
|
+
* Finish live tests?
|
29
|
+
* Just send a diff over IM?
|
30
|
+
* Only look at a given XPath?
|
31
|
+
|
32
|
+
== Author
|
33
|
+
|
34
|
+
By Phil Hagelberg (http://technomancy.us)
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/watcher_in_the_water.rb'
|
6
|
+
|
7
|
+
Hoe.new('watcher_in_the_water', WatcherInTheWater::VERSION) do |p|
|
8
|
+
p.rubyforge_name = "seattlerb"
|
9
|
+
p.summary = "Want to know when the page at a given URL changes?
|
10
|
+
The Watcher in the Water will tell you over Jabber."
|
11
|
+
p.developer('Phil Hagelberg', 'http://technomancy.us')
|
12
|
+
p.url = 'http://en.wikipedia.org/wiki/Watcher_in_the_Water'
|
13
|
+
p.extra_deps << 'xmpp4r'
|
14
|
+
end
|
15
|
+
|
16
|
+
# vim: syntax=Ruby
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'yaml'
|
6
|
+
require 'digest/sha1'
|
7
|
+
require 'xmpp4r'
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
module WatcherInTheWater
|
11
|
+
include Jabber
|
12
|
+
VERSION = '0.1'
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def configure(config = nil)
|
17
|
+
config = File.expand_path(config || '~/.watcher/config.yml')
|
18
|
+
FileUtils.cd(File.dirname(config))
|
19
|
+
@config = YAML.load(File.read(config))
|
20
|
+
rescue
|
21
|
+
abort "You need #{config} to contain a sender jabber ID, password,
|
22
|
+
a recipient jabber ID, and a list of URLs in YAML format. Example:
|
23
|
+
|
24
|
+
---
|
25
|
+
jid: watcher-in-the-water@jabber.org
|
26
|
+
password: mellon
|
27
|
+
recipient: phil@hagelb.org
|
28
|
+
urls: ---
|
29
|
+
http://rubyconf.org
|
30
|
+
"
|
31
|
+
end
|
32
|
+
|
33
|
+
def watch
|
34
|
+
@config['urls'].each do |url|
|
35
|
+
content = open(url).read
|
36
|
+
hash = Digest::SHA1.hexdigest(content)
|
37
|
+
filename = 'hashes/' + url_transform(url)
|
38
|
+
|
39
|
+
if File.exist?(filename)
|
40
|
+
if File.read(filename) != hash
|
41
|
+
alert("#{url} changed to #{content[0 .. 200]}")
|
42
|
+
end
|
43
|
+
else
|
44
|
+
alert("Watching #{url} for you!")
|
45
|
+
end
|
46
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
47
|
+
File.open(filename, 'w') { |f| f.write hash }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def alert(message)
|
52
|
+
connect
|
53
|
+
@client.send Message.new(@config['recipient'],
|
54
|
+
message).set_type(:normal).set_id('1')
|
55
|
+
end
|
56
|
+
|
57
|
+
def connect
|
58
|
+
return if @client
|
59
|
+
jid = JID.new("#{@config['jid']}/#{`hostname`.chomp}-watcher")
|
60
|
+
@client = Client.new(jid)
|
61
|
+
@client.connect
|
62
|
+
@client.auth(@config['password'])
|
63
|
+
end
|
64
|
+
|
65
|
+
def url_transform(url)
|
66
|
+
url.gsub(/[^\w]/, '_')[0 .. 50] + '_' + Digest::SHA1.hexdigest(url)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dimrill Gate
|
@@ -0,0 +1 @@
|
|
1
|
+
Durin's Bridge
|
@@ -0,0 +1 @@
|
|
1
|
+
West Gate
|
data/test/live.yml
ADDED
data/test/live_test.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
begin; gem 'miniunit'; rescue LoadError; end
|
3
|
+
require 'test/unit'
|
4
|
+
require 'mongrel'
|
5
|
+
require File.dirname(__FILE__) + '/../lib/watcher_in_the_water'
|
6
|
+
|
7
|
+
# launch Mongrel
|
8
|
+
class LiveServer < Mongrel::HttpHandler
|
9
|
+
attr_accessor :string
|
10
|
+
def process(request, response)
|
11
|
+
response.start(200) do |head,out|
|
12
|
+
out.write(@string || "hello!\n")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
MONGREL = Mongrel::HttpServer.new("0.0.0.0", "3000")
|
18
|
+
MONGREL.register("/test", SimpleHandler.new)
|
19
|
+
MONGREL.run
|
20
|
+
|
21
|
+
class LiveTest < Test::Unit::TestCase
|
22
|
+
def setup
|
23
|
+
WatcherInTheWater.configure(File.dirname(__FILE__) + '/live.yml')
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_live_usage
|
27
|
+
# should alert about all pages being watched on first run
|
28
|
+
# then should alert for a single change
|
29
|
+
# then should send no alerts if nothing's changed
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_host_not_found
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_404
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_sender_jabber_down
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_bad_auth
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_recipient_jabber_down
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_recipient_jid_not_found
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def watch
|
52
|
+
system "#{File.dirname(__FILE__)}/../bin/watcher #{File.dirname(__FILE__)}/live.yml"
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
begin; gem 'miniunit'; rescue LoadError; end
|
3
|
+
require 'test/unit'
|
4
|
+
require File.dirname(__FILE__) + '/../lib/watcher_in_the_water'
|
5
|
+
|
6
|
+
module WatcherInTheWater
|
7
|
+
# Let's mock out the Jabber connection
|
8
|
+
@client = Object.new
|
9
|
+
@messages = []
|
10
|
+
messages_for_closure = @messages
|
11
|
+
|
12
|
+
def @client.send(message)
|
13
|
+
WatcherInTheWater.messages << message
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.messages; @messages; end
|
17
|
+
def self.config; @config; end
|
18
|
+
end
|
19
|
+
|
20
|
+
WatcherInTheWater.configure(File.dirname(__FILE__) + '/watcher/test.yml')
|
21
|
+
|
22
|
+
class TestWatcherInTheWater < Test::Unit::TestCase
|
23
|
+
def setup
|
24
|
+
FileUtils.rm_rf('hashes')
|
25
|
+
FileUtils.rm_rf('fixtures')
|
26
|
+
FileUtils.cp_r('../fixtures', 'fixtures')
|
27
|
+
WatcherInTheWater.messages.clear
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_watch_first_time
|
31
|
+
WatcherInTheWater.watch
|
32
|
+
|
33
|
+
['fixtures_dimrill_gate_d2785ed5a8c89b47e541e85b7216d0153a383651',
|
34
|
+
'fixtures_durins_bridge_f81c948ae30baa391371150bc42cc935ebf8287c',
|
35
|
+
'fixtures_west_gate_cdef5d9283f6bdeddfa89de21bbca8d5acb3c673'].each do |u|
|
36
|
+
assert_equal 40, File.read('hashes/' + u).length
|
37
|
+
end
|
38
|
+
|
39
|
+
assert_equal 3, WatcherInTheWater.messages.size
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_watch_one_change
|
43
|
+
WatcherInTheWater.watch
|
44
|
+
WatcherInTheWater.messages.clear
|
45
|
+
|
46
|
+
File.open('fixtures/durins_bridge', 'w') { |f| f.puts "Durin's Super-Bridge!" }
|
47
|
+
WatcherInTheWater.watch
|
48
|
+
|
49
|
+
assert_equal 1, WatcherInTheWater.messages.size
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_watch_no_changes
|
53
|
+
WatcherInTheWater.watch
|
54
|
+
WatcherInTheWater.messages.clear
|
55
|
+
|
56
|
+
WatcherInTheWater.watch
|
57
|
+
|
58
|
+
assert_equal [], WatcherInTheWater.messages
|
59
|
+
end
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: watcher_in_the_water
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Phil Hagelberg
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-11-07 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: xmpp4r
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.2
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email:
|
37
|
+
- http://technomancy.us
|
38
|
+
executables:
|
39
|
+
- watcher_in_the_water
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- History.txt
|
44
|
+
- Manifest.txt
|
45
|
+
files:
|
46
|
+
- History.txt
|
47
|
+
- Manifest.txt
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- bin/watcher_in_the_water
|
51
|
+
- lib/watcher_in_the_water.rb
|
52
|
+
- test/fixtures/dimrill_gate
|
53
|
+
- test/fixtures/durins_bridge
|
54
|
+
- test/fixtures/west_gate
|
55
|
+
- test/live.yml
|
56
|
+
- test/live_test.rb
|
57
|
+
- test/test_watcher_in_the_water.rb
|
58
|
+
- test/watcher/test.yml
|
59
|
+
has_rdoc: true
|
60
|
+
homepage: http://en.wikipedia.org/wiki/Watcher_in_the_Water
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --main
|
64
|
+
- README.txt
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project: seattlerb
|
82
|
+
rubygems_version: 1.3.1
|
83
|
+
signing_key:
|
84
|
+
specification_version: 2
|
85
|
+
summary: Want to know when the page at a given URL changes? The Watcher in the Water will tell you over Jabber.
|
86
|
+
test_files:
|
87
|
+
- test/test_watcher_in_the_water.rb
|