thunk 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +6 -0
- data/Manifest.txt +2 -0
- data/README.rdoc +2 -0
- data/Rakefile +3 -1
- data/bin/thunk +8 -8
- data/lib/thunk.rb +28 -71
- data/lib/thunk/server.rb +71 -0
- data/test/test_thunk.rb +12 -66
- data/test/test_thunk_server.rb +73 -0
- metadata +18 -13
data/CHANGELOG.rdoc
CHANGED
data/Manifest.txt
CHANGED
data/README.rdoc
CHANGED
@@ -8,6 +8,8 @@
|
|
8
8
|
An API for talking to thunk.us, a (soon to be) generally awesome
|
9
9
|
notification service. Thunk lets you share and change simple state.
|
10
10
|
|
11
|
+
== Notes in Progress
|
12
|
+
|
11
13
|
We know these docs are rough, but we wanted to get a version of the
|
12
14
|
API out quickly. We'll have it all polished by 1.0, we promise. :)
|
13
15
|
|
data/Rakefile
CHANGED
@@ -4,7 +4,8 @@ Hoe.plugin :doofus, :git
|
|
4
4
|
Hoe.plugins.delete :rubyforge
|
5
5
|
|
6
6
|
Hoe.spec "thunk" do
|
7
|
-
developer "Eleven Eleven", "hello@
|
7
|
+
developer "Eleven Eleven", "hello@thunk.us"
|
8
|
+
developer "John Barnette", "john@thunk.us"
|
8
9
|
|
9
10
|
self.extra_rdoc_files = Dir["*.rdoc"]
|
10
11
|
self.history_file = "CHANGELOG.rdoc"
|
@@ -14,4 +15,5 @@ Hoe.spec "thunk" do
|
|
14
15
|
extra_deps << %w(json_pure 1.2.0)
|
15
16
|
extra_dev_deps << %w(fakeweb 1.2.8)
|
16
17
|
extra_dev_deps << %w(minitest 1.5.0)
|
18
|
+
extra_dev_deps << %w(mocha 0.9.8)
|
17
19
|
end
|
data/bin/thunk
CHANGED
@@ -7,14 +7,15 @@ OptionParser.new do |opts|
|
|
7
7
|
@payload = nil
|
8
8
|
@poke = nil
|
9
9
|
@raw = false
|
10
|
+
@server = Thunk::Server.new
|
10
11
|
|
11
|
-
opts.banner =
|
12
|
-
"Usage: thunk [options] --create [
|
12
|
+
opts.banner =
|
13
|
+
"Usage: thunk [options] --create [name]\n" +
|
13
14
|
" thunk [options] <uuid>\n" +
|
14
15
|
" thunk [options] {--good, --bad, --iffy, --unknown} <uuid>\n\n"
|
15
16
|
|
16
|
-
opts.on "--create [
|
17
|
-
thunk =
|
17
|
+
opts.on "--create [NAME]", "-c", "Create a thunk, optional name." do |n|
|
18
|
+
thunk = @server.create n
|
18
19
|
puts thunk.uuid if thunk.uuid
|
19
20
|
exit thunk.exists? ? 0 : 1
|
20
21
|
end
|
@@ -25,7 +26,7 @@ OptionParser.new do |opts|
|
|
25
26
|
end
|
26
27
|
|
27
28
|
opts.on "--payload PAYLOAD", "-p", "-m",
|
28
|
-
"
|
29
|
+
"Add a payload/message to a poke." do |p|
|
29
30
|
|
30
31
|
@payload = p
|
31
32
|
end
|
@@ -35,7 +36,7 @@ OptionParser.new do |opts|
|
|
35
36
|
end
|
36
37
|
|
37
38
|
opts.on "--url URL", "Use a different base URL." do |url|
|
38
|
-
Thunk.
|
39
|
+
@server = Thunk::Server.new url
|
39
40
|
end
|
40
41
|
|
41
42
|
opts.on "--version", "-V", "Prints #{Thunk::VERSION}." do
|
@@ -61,10 +62,9 @@ OptionParser.new do |opts|
|
|
61
62
|
end
|
62
63
|
|
63
64
|
abort "#$0: Specify a thunk UUID!" unless uuid = ARGV.shift
|
64
|
-
thunk =
|
65
|
+
thunk = @server.get uuid
|
65
66
|
|
66
67
|
if @poke
|
67
|
-
p @payload
|
68
68
|
thunk.send "#{@poke}!", @payload
|
69
69
|
else
|
70
70
|
if @raw
|
data/lib/thunk.rb
CHANGED
@@ -1,76 +1,32 @@
|
|
1
|
-
require "
|
2
|
-
require "json/pure"
|
3
|
-
require "net/http"
|
4
|
-
require "uri"
|
1
|
+
require "thunk/server"
|
5
2
|
|
6
3
|
class Thunk
|
7
|
-
VERSION = "0.
|
8
|
-
URL = "http://thunk.us".freeze
|
9
|
-
|
10
|
-
class << self
|
11
|
-
attr_accessor :url
|
12
|
-
private :new
|
13
|
-
|
14
|
-
def create name = nil
|
15
|
-
json = request :post, url, :name => name
|
16
|
-
new "#{url}/#{json["uuid"]}", json
|
17
|
-
end
|
18
|
-
|
19
|
-
def for url
|
20
|
-
url = "#{self.url}/#{url}" unless /^http/ =~ url
|
21
|
-
json = request :get, url
|
22
|
-
new url, json
|
23
|
-
end
|
24
|
-
|
25
|
-
def request method, url, options = {}
|
26
|
-
url = URI.parse url
|
27
|
-
|
28
|
-
unless options.empty?
|
29
|
-
url.query = options.collect { |k ,v|
|
30
|
-
"#{CGI.escape k.to_s}=#{CGI.escape v.to_s}"
|
31
|
-
}.join "&"
|
32
|
-
end
|
33
|
-
|
34
|
-
# FIX http timeout settings
|
35
|
-
# FIX exception handing, etc
|
36
|
-
|
37
|
-
http = Net::HTTP.new url.host, url.port
|
38
|
-
rclass = { :get => Net::HTTP::Get, :post => Net::HTTP::Post }[method]
|
39
|
-
req = rclass.new url.request_uri
|
40
|
-
res = http.request req
|
41
|
-
success = %w(200 201).include? res.code
|
42
|
-
|
43
|
-
unless success
|
44
|
-
warn "[Thunk] #{res.code}, #{method}, #{url}: #{res.message}"
|
45
|
-
warn res.body if res.body
|
46
|
-
end
|
47
|
-
|
48
|
-
return success if res.body.empty?
|
49
|
-
|
50
|
-
data = JSON.parse(res.body) rescue {}
|
51
|
-
|
52
|
-
unless Hash === data
|
53
|
-
warn "[Thunk] Malformed JSON response: #{data.inspect}"
|
54
|
-
data = {}
|
55
|
-
end
|
56
|
-
|
57
|
-
warn warning if warning = data.delete("warn")
|
58
|
-
abort critical if critical = data.delete("abort")
|
59
|
-
|
60
|
-
data
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
self.url = URL
|
4
|
+
VERSION = "0.1.0"
|
65
5
|
|
66
6
|
attr_reader :name
|
67
7
|
attr_reader :payload
|
68
8
|
attr_reader :puuid
|
69
9
|
attr_reader :state
|
70
10
|
attr_reader :updated
|
71
|
-
attr_reader :url
|
72
11
|
attr_reader :uuid
|
73
12
|
|
13
|
+
def self.create *args
|
14
|
+
server.create *args
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.get *args
|
18
|
+
server.get *args
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.server
|
22
|
+
@server ||= Thunk::Server.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize server, json
|
26
|
+
@server = server
|
27
|
+
apply json
|
28
|
+
end
|
29
|
+
|
74
30
|
def bad?
|
75
31
|
:bad == state
|
76
32
|
end
|
@@ -80,7 +36,7 @@ class Thunk
|
|
80
36
|
end
|
81
37
|
|
82
38
|
def exists?
|
83
|
-
|
39
|
+
@server.request :get, url
|
84
40
|
end
|
85
41
|
|
86
42
|
def good?
|
@@ -99,7 +55,9 @@ class Thunk
|
|
99
55
|
poke :iffy, payload
|
100
56
|
end
|
101
57
|
|
102
|
-
|
58
|
+
# Used for the --raw option in the command-line client.
|
59
|
+
|
60
|
+
def json # :nodoc:
|
103
61
|
json = {
|
104
62
|
:name => name,
|
105
63
|
:payload => payload,
|
@@ -115,7 +73,7 @@ class Thunk
|
|
115
73
|
end
|
116
74
|
|
117
75
|
def poke state, payload = nil
|
118
|
-
if
|
76
|
+
if @server.request :post, "#{url}/#{state}", :payload => payload
|
119
77
|
@payload = payload
|
120
78
|
@state = state.to_sym
|
121
79
|
@updated = Time.now.utc
|
@@ -140,13 +98,12 @@ class Thunk
|
|
140
98
|
poke :unknown, payload
|
141
99
|
end
|
142
100
|
|
143
|
-
|
144
|
-
|
145
|
-
def initialize url, json
|
146
|
-
@url = url
|
147
|
-
apply json
|
101
|
+
def url
|
102
|
+
"#{@server.url}/#{uuid}"
|
148
103
|
end
|
149
104
|
|
105
|
+
private
|
106
|
+
|
150
107
|
def apply json
|
151
108
|
@name = json["name"]
|
152
109
|
@payload = json["payload"]
|
data/lib/thunk/server.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "json/pure"
|
3
|
+
require "net/http"
|
4
|
+
require "uri"
|
5
|
+
|
6
|
+
require "thunk"
|
7
|
+
|
8
|
+
class Thunk
|
9
|
+
|
10
|
+
class << self
|
11
|
+
public :new # FIX
|
12
|
+
end
|
13
|
+
|
14
|
+
class Server
|
15
|
+
attr_reader :url
|
16
|
+
|
17
|
+
def initialize url = "http://thunk.us"
|
18
|
+
@url = url
|
19
|
+
end
|
20
|
+
|
21
|
+
def create name = nil
|
22
|
+
json = request :post, url, :name => name
|
23
|
+
url = "#{self.url}/#{json['uuid']}"
|
24
|
+
|
25
|
+
Thunk.new self, json
|
26
|
+
end
|
27
|
+
|
28
|
+
def get uuid
|
29
|
+
url = "#{self.url}/#{uuid}"
|
30
|
+
Thunk.new self, request(:get, url)
|
31
|
+
end
|
32
|
+
|
33
|
+
def request method, url, options = {}
|
34
|
+
url = URI.parse url
|
35
|
+
|
36
|
+
unless options.empty?
|
37
|
+
url.query = options.collect { |k ,v|
|
38
|
+
"#{CGI.escape k.to_s}=#{CGI.escape v.to_s}"
|
39
|
+
}.join "&"
|
40
|
+
end
|
41
|
+
|
42
|
+
# FIX http timeout settings
|
43
|
+
# FIX exception handing, etc
|
44
|
+
|
45
|
+
http = Net::HTTP.new url.host, url.port
|
46
|
+
rclass = { :get => Net::HTTP::Get, :post => Net::HTTP::Post }[method]
|
47
|
+
req = rclass.new url.request_uri
|
48
|
+
res = http.request req
|
49
|
+
success = %w(200 201).include? res.code
|
50
|
+
|
51
|
+
unless success
|
52
|
+
warn "[Thunk] #{res.code}, #{method}, #{url}: #{res.message}"
|
53
|
+
warn res.body if res.body
|
54
|
+
end
|
55
|
+
|
56
|
+
return success if res.body.empty?
|
57
|
+
|
58
|
+
data = JSON.parse(res.body) rescue {}
|
59
|
+
|
60
|
+
unless Hash === data
|
61
|
+
warn "[Thunk] Malformed JSON response: #{data.inspect}"
|
62
|
+
data = {}
|
63
|
+
end
|
64
|
+
|
65
|
+
warn warning if warning = data.delete("warn")
|
66
|
+
abort critical if critical = data.delete("abort")
|
67
|
+
|
68
|
+
data
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/test/test_thunk.rb
CHANGED
@@ -1,29 +1,19 @@
|
|
1
1
|
require "fakeweb"
|
2
2
|
require "minitest/autorun"
|
3
|
+
require "mocha"
|
3
4
|
|
4
5
|
require "thunk"
|
5
6
|
|
6
7
|
FakeWeb.allow_net_connect = false
|
7
8
|
|
8
|
-
class Thunk
|
9
|
-
class << self
|
10
|
-
def abort *; end
|
11
|
-
def warn *; end
|
12
|
-
|
13
|
-
public :new
|
14
|
-
end
|
15
|
-
|
16
|
-
public :initialize
|
17
|
-
end
|
18
|
-
|
19
9
|
class TestThunk < MiniTest::Unit::TestCase
|
20
10
|
def setup
|
21
11
|
FakeWeb.clean_registry
|
22
|
-
|
12
|
+
@server = Thunk::Server.new
|
23
13
|
end
|
24
14
|
|
25
15
|
def test_bangs_and_predicates
|
26
|
-
t = Thunk.new "
|
16
|
+
t = Thunk.new @server, { "uuid" => "uuid" }
|
27
17
|
|
28
18
|
[:good, :iffy, :bad, :unknown].each do |state|
|
29
19
|
FakeWeb.register_uri :post, "http://thunk.us/uuid/#{state}?payload=hi",
|
@@ -38,8 +28,8 @@ class TestThunk < MiniTest::Unit::TestCase
|
|
38
28
|
end
|
39
29
|
|
40
30
|
def test_exists?
|
41
|
-
good = Thunk.new "
|
42
|
-
bad = Thunk.new "
|
31
|
+
good = Thunk.new @server, { "uuid" => "exists" }
|
32
|
+
bad = Thunk.new @server, { "uuid" => "nonexistent" }
|
43
33
|
|
44
34
|
FakeWeb.register_uri :get, "http://thunk.us/exists", :status => 200
|
45
35
|
FakeWeb.register_uri :get, "http://thunk.us/nonexistent", :status => 404
|
@@ -55,66 +45,22 @@ class TestThunk < MiniTest::Unit::TestCase
|
|
55
45
|
FakeWeb.register_uri :get, "http://thunk.us/public",
|
56
46
|
:body => JSON.generate({ :uuid => "public" })
|
57
47
|
|
58
|
-
t =
|
48
|
+
t = @server.get "pokeable"
|
59
49
|
assert t.pokeable?, "pokeable"
|
60
50
|
refute t.public?, "public"
|
61
51
|
|
62
|
-
t =
|
52
|
+
t = @server.get "public"
|
63
53
|
refute t.pokeable?, "pokeable"
|
64
54
|
assert t.public?, "public"
|
65
55
|
end
|
66
56
|
|
67
57
|
def test_self_create
|
68
|
-
|
69
|
-
|
70
|
-
:puuid => "public",
|
71
|
-
:state => :new,
|
72
|
-
:uuid => "uuid"
|
73
|
-
}
|
74
|
-
|
75
|
-
FakeWeb.register_uri :post, "http://thunk.us?name=Hello",
|
76
|
-
:body => JSON.generate(response)
|
77
|
-
|
78
|
-
t = Thunk.create "Hello"
|
79
|
-
|
80
|
-
response.each do |key, value|
|
81
|
-
assert_equal value, t.send(key)
|
82
|
-
end
|
83
|
-
|
84
|
-
assert_equal "http://thunk.us/uuid", t.url
|
58
|
+
Thunk.server.expects(:create).with "foo"
|
59
|
+
Thunk.create "foo"
|
85
60
|
end
|
86
61
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
t = Thunk.create "Hello"
|
92
|
-
assert_equal :unknown, t.state
|
93
|
-
end
|
94
|
-
|
95
|
-
def test_self_for
|
96
|
-
response = {
|
97
|
-
:name => "Hello",
|
98
|
-
:payload => "All is well!",
|
99
|
-
:puuid => "public",
|
100
|
-
:state => :good,
|
101
|
-
:uuid => "uuid"
|
102
|
-
}
|
103
|
-
|
104
|
-
FakeWeb.register_uri :get, "http://thunk.us/uuid",
|
105
|
-
:body => JSON.generate(response)
|
106
|
-
|
107
|
-
t = Thunk.for "uuid"
|
108
|
-
|
109
|
-
response.each do |key, value|
|
110
|
-
assert_equal value, t.send(key)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_self_url
|
115
|
-
assert_equal "http://thunk.us", Thunk.url
|
116
|
-
|
117
|
-
Thunk.url = "bleh"
|
118
|
-
assert_equal "bleh", Thunk.url
|
62
|
+
def test_self_get
|
63
|
+
Thunk.server.expects(:get).with "foo"
|
64
|
+
Thunk.get "foo"
|
119
65
|
end
|
120
66
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "fakeweb"
|
2
|
+
require "minitest/autorun"
|
3
|
+
|
4
|
+
require "thunk"
|
5
|
+
|
6
|
+
FakeWeb.allow_net_connect = false
|
7
|
+
|
8
|
+
class Thunk::Server
|
9
|
+
def abort *; end
|
10
|
+
def warn *; end
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestThunkServer < MiniTest::Unit::TestCase
|
14
|
+
def setup
|
15
|
+
FakeWeb.clean_registry
|
16
|
+
@server = Thunk::Server.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_create
|
20
|
+
response = {
|
21
|
+
:name => "Hello",
|
22
|
+
:puuid => "public",
|
23
|
+
:state => :new,
|
24
|
+
:uuid => "uuid"
|
25
|
+
}
|
26
|
+
|
27
|
+
FakeWeb.register_uri :post, "http://thunk.us?name=Hello",
|
28
|
+
:body => JSON.generate(response)
|
29
|
+
|
30
|
+
t = @server.create "Hello"
|
31
|
+
|
32
|
+
response.each do |key, value|
|
33
|
+
assert_equal value, t.send(key)
|
34
|
+
end
|
35
|
+
|
36
|
+
assert_equal "http://thunk.us/uuid", t.url
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_create_bad
|
40
|
+
FakeWeb.register_uri :post, "http://thunk.us?name=Hello",
|
41
|
+
:status => 500, :body => "[]"
|
42
|
+
|
43
|
+
t = @server.create "Hello"
|
44
|
+
assert_equal :unknown, t.state
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_get
|
48
|
+
response = {
|
49
|
+
:name => "Hello",
|
50
|
+
:payload => "All is well!",
|
51
|
+
:puuid => "public",
|
52
|
+
:state => :good,
|
53
|
+
:uuid => "uuid"
|
54
|
+
}
|
55
|
+
|
56
|
+
FakeWeb.register_uri :get, "http://thunk.us/uuid",
|
57
|
+
:body => JSON.generate(response)
|
58
|
+
|
59
|
+
t = @server.get "uuid"
|
60
|
+
|
61
|
+
response.each do |key, value|
|
62
|
+
assert_equal value, t.send(key)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_initialize
|
67
|
+
s = Thunk::Server.new
|
68
|
+
assert_equal "http://thunk.us", s.url
|
69
|
+
|
70
|
+
s = Thunk::Server.new "http://thunk.local"
|
71
|
+
assert_equal "http://thunk.local", s.url
|
72
|
+
end
|
73
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thunk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eleven Eleven
|
8
|
+
- John Barnette
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date: 2010-01-
|
13
|
+
date: 2010-01-29 00:00:00 -08:00
|
13
14
|
default_executable:
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
@@ -52,6 +53,16 @@ dependencies:
|
|
52
53
|
- !ruby/object:Gem::Version
|
53
54
|
version: 1.5.0
|
54
55
|
version:
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: mocha
|
58
|
+
type: :development
|
59
|
+
version_requirement:
|
60
|
+
version_requirements: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - "="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: 0.9.8
|
65
|
+
version:
|
55
66
|
- !ruby/object:Gem::Dependency
|
56
67
|
name: hoe
|
57
68
|
type: :development
|
@@ -65,18 +76,9 @@ dependencies:
|
|
65
76
|
description: |-
|
66
77
|
An API for talking to thunk.us, a (soon to be) generally awesome
|
67
78
|
notification service. Thunk lets you share and change simple state.
|
68
|
-
|
69
|
-
We know these docs are rough, but we wanted to get a version of the
|
70
|
-
API out quickly. We'll have it all polished by 1.0, we promise. :)
|
71
|
-
|
72
|
-
Since Thunk gets used in basic infrastructure tools, it works extra
|
73
|
-
hard to never throw exceptions or cause hangs/timeouts. If it does,
|
74
|
-
please file a bug! Even a nonexistent or read-only thunk will
|
75
|
-
successfully respond to pokes, returning stub information. If you need
|
76
|
-
to make extra sure you're hooked up to a valid thunk, check out
|
77
|
-
<tt>Thunk#exists?</tt> and <tt>Thunk#pokeable?</tt>.
|
78
79
|
email:
|
79
|
-
- hello@
|
80
|
+
- hello@thunk.us
|
81
|
+
- john@thunk.us
|
80
82
|
executables:
|
81
83
|
- thunk
|
82
84
|
extensions: []
|
@@ -93,7 +95,9 @@ files:
|
|
93
95
|
- Rakefile
|
94
96
|
- bin/thunk
|
95
97
|
- lib/thunk.rb
|
98
|
+
- lib/thunk/server.rb
|
96
99
|
- test/test_thunk.rb
|
100
|
+
- test/test_thunk_server.rb
|
97
101
|
has_rdoc: true
|
98
102
|
homepage: http://github.com/eleven/thunk
|
99
103
|
licenses: []
|
@@ -125,3 +129,4 @@ specification_version: 3
|
|
125
129
|
summary: An API for talking to thunk.us, a (soon to be) generally awesome notification service
|
126
130
|
test_files:
|
127
131
|
- test/test_thunk.rb
|
132
|
+
- test/test_thunk_server.rb
|