audible 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -0
- data/README.md +10 -0
- data/VERSION +1 -1
- data/audible.gemspec +14 -5
- data/lib/audible/audible.rb +5 -0
- data/lib/audible/pidfile.rb +16 -0
- data/spec/and_how_it_differs_from_observable_spec.rb +101 -0
- data/spec/examples/a_notifying_shell_spec.rb +28 -0
- data/spec/examples/logging_as_notifications_spec.rb +51 -0
- data/spec/relaying_notifications/about_the_notifications_spec.rb +69 -0
- data/spec/relaying_notifications/can_relay_notifications_spec.rb +43 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/system.tests/drb/bin/server +45 -0
- data/spec/system.tests/drb/drb_observers_spec.rb +65 -0
- data/spec/system.tests/drb/support/drb_server.rb +26 -0
- metadata +14 -5
- data/README.rdoc +0 -19
data/.travis.yml
CHANGED
data/README.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Audible
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/ben-biddington/audible.png?branch=master)](https://travis-ci.org/ben-biddington/audible)
|
4
|
+
|
5
|
+
A way to configure object communications as an alternative to `Observable`.
|
6
|
+
|
7
|
+
## Copyright
|
8
|
+
|
9
|
+
Copyright (c) 2013 Ben Biddington. See LICENSE.txt for
|
10
|
+
further details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/audible.gemspec
CHANGED
@@ -5,16 +5,16 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "audible"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ben Biddington"]
|
12
|
-
s.date = "
|
12
|
+
s.date = "2014-02-06"
|
13
13
|
s.description = "Object communications"
|
14
14
|
s.email = "ben.biddington@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE.txt",
|
17
|
-
"README.
|
17
|
+
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".document",
|
@@ -22,14 +22,23 @@ Gem::Specification.new do |s|
|
|
22
22
|
"Gemfile",
|
23
23
|
"Gemfile.lock",
|
24
24
|
"LICENSE.txt",
|
25
|
-
"README.
|
25
|
+
"README.md",
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
28
|
"audible.gemspec",
|
29
29
|
"lib/audible.rb",
|
30
30
|
"lib/audible/audible.rb",
|
31
|
+
"lib/audible/pidfile.rb",
|
32
|
+
"spec/and_how_it_differs_from_observable_spec.rb",
|
33
|
+
"spec/examples/a_notifying_shell_spec.rb",
|
34
|
+
"spec/examples/logging_as_notifications_spec.rb",
|
31
35
|
"spec/listening_spec.rb",
|
32
|
-
"spec/
|
36
|
+
"spec/relaying_notifications/about_the_notifications_spec.rb",
|
37
|
+
"spec/relaying_notifications/can_relay_notifications_spec.rb",
|
38
|
+
"spec/spec_helper.rb",
|
39
|
+
"spec/system.tests/drb/bin/server",
|
40
|
+
"spec/system.tests/drb/drb_observers_spec.rb",
|
41
|
+
"spec/system.tests/drb/support/drb_server.rb"
|
33
42
|
]
|
34
43
|
s.homepage = "http://github.com/ben-biddington/audible"
|
35
44
|
s.licenses = ["MIT"]
|
data/lib/audible/audible.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
class Pidfile
|
2
|
+
require "fileutils"; extend FileUtils
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def new(pid=$$)
|
6
|
+
File.open path, "w" do |f|
|
7
|
+
f.puts pid
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def missing?; false == exists? end
|
12
|
+
def exists?; File.exists? path; end
|
13
|
+
def delete; rm path; end
|
14
|
+
def path; File.join ".", ".pid"; end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Observable" do
|
4
|
+
let(:an_observable_object) do
|
5
|
+
Class.new do
|
6
|
+
require "observer"; include Observable
|
7
|
+
|
8
|
+
def poke
|
9
|
+
changed
|
10
|
+
notify_observers :poked
|
11
|
+
end
|
12
|
+
|
13
|
+
def tap
|
14
|
+
changed
|
15
|
+
notify_observers :tapped
|
16
|
+
end
|
17
|
+
end.new
|
18
|
+
end
|
19
|
+
|
20
|
+
it "you can register for notifications" do
|
21
|
+
an_observer = Class.new do
|
22
|
+
def update(args)
|
23
|
+
@notified = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def notified?; @notified === true; end
|
27
|
+
end.new
|
28
|
+
|
29
|
+
an_observable_object.add_observer(an_observer)
|
30
|
+
|
31
|
+
an_observable_object.poke
|
32
|
+
|
33
|
+
an_observer.must be_notified
|
34
|
+
end
|
35
|
+
|
36
|
+
it "and you can send arguments with your notification" do
|
37
|
+
an_observer = Class.new do
|
38
|
+
def update(args)
|
39
|
+
@args = args
|
40
|
+
end
|
41
|
+
|
42
|
+
def args; @args; end
|
43
|
+
end.new
|
44
|
+
|
45
|
+
an_observable_object.add_observer(an_observer)
|
46
|
+
|
47
|
+
an_observable_object.poke
|
48
|
+
|
49
|
+
an_observer.args.must === :poked
|
50
|
+
end
|
51
|
+
|
52
|
+
it "for multiple events the observer must decide for themselves" do
|
53
|
+
an_observer = Class.new do
|
54
|
+
def initialize
|
55
|
+
@poked,@tapped = 0,0
|
56
|
+
end
|
57
|
+
|
58
|
+
def update(args)
|
59
|
+
@poked = true if args === :poked
|
60
|
+
@tapped = true if args === :tapped
|
61
|
+
end
|
62
|
+
|
63
|
+
def poked?; @poked === true; end
|
64
|
+
def tapped?; @tapped === true; end
|
65
|
+
end.new
|
66
|
+
|
67
|
+
an_observable_object.add_observer(an_observer)
|
68
|
+
|
69
|
+
an_observable_object.poke
|
70
|
+
an_observable_object.tap
|
71
|
+
|
72
|
+
an_observer.must be_tapped
|
73
|
+
an_observer.must be_poked
|
74
|
+
end
|
75
|
+
|
76
|
+
it "notifications are not sent if `changed` not called" do
|
77
|
+
a_bung_observable_object_that_does_not_call_changed = Class.new do
|
78
|
+
require "observer"; include Observable
|
79
|
+
|
80
|
+
def poke
|
81
|
+
notify_observers :poked
|
82
|
+
end
|
83
|
+
end.new
|
84
|
+
|
85
|
+
an_observer = Class.new do
|
86
|
+
def update(args)
|
87
|
+
@notified = true
|
88
|
+
end
|
89
|
+
|
90
|
+
def notified?; @notified === true; end
|
91
|
+
end.new
|
92
|
+
|
93
|
+
a_bung_observable_object_that_does_not_call_changed.add_observer an_observer
|
94
|
+
|
95
|
+
a_bung_observable_object_that_does_not_call_changed.poke
|
96
|
+
|
97
|
+
an_observer.must_not(be_notified,
|
98
|
+
"Even though `notify_observers` was called, no notification was sent because you have to call `changed` beforehand."
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class Shell
|
4
|
+
require "audible"; extend Audible
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def exec(what)
|
8
|
+
require "open3"
|
9
|
+
Open3.popen2(what, :err => [:child, :out]) do |i,o,t|
|
10
|
+
o.each_line {|line| notify :progress, line}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "An audible shell" do
|
17
|
+
it "notifies for each line of output" do
|
18
|
+
result = StringIO.new
|
19
|
+
|
20
|
+
Shell.on :progress do |e, args|
|
21
|
+
result.puts args.first
|
22
|
+
end
|
23
|
+
|
24
|
+
Shell.exec "ls -a"
|
25
|
+
|
26
|
+
result.length.must be > 0
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class BusyBody
|
4
|
+
require "audible"; include Audible
|
5
|
+
|
6
|
+
def go
|
7
|
+
step_one
|
8
|
+
step_two
|
9
|
+
step_three
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
%w{one two three}.each do |name|
|
15
|
+
full_name = "step_#{name}".to_sym
|
16
|
+
|
17
|
+
define_method(full_name){ notify full_name }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class LogSpy
|
22
|
+
attr_reader :messages
|
23
|
+
|
24
|
+
def initialize(what)
|
25
|
+
@messages = []
|
26
|
+
|
27
|
+
what.on :step_one do
|
28
|
+
@messages << "Step 1"
|
29
|
+
end
|
30
|
+
|
31
|
+
what.on :step_two do
|
32
|
+
@messages << "Step 2"
|
33
|
+
end
|
34
|
+
|
35
|
+
what.on :step_three do
|
36
|
+
@messages << "Step 3"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe BusyBody, "and notifying instead of logging" do
|
42
|
+
it "attach the log by notification rather than as dependency" do
|
43
|
+
busy_body = BusyBody.new
|
44
|
+
|
45
|
+
log = LogSpy.new busy_body
|
46
|
+
|
47
|
+
busy_body.go
|
48
|
+
|
49
|
+
log.messages.must == ["Step 1", "Step 2", "Step 3"]
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "The relayed notifications" do
|
4
|
+
before :all do
|
5
|
+
an_audible_object = Class.new do
|
6
|
+
require "audible"; include Audible
|
7
|
+
|
8
|
+
def poke; notify :poked, {:a => "1", :b => "2"}; end
|
9
|
+
end.new
|
10
|
+
|
11
|
+
a_relaying_class = Class.new do
|
12
|
+
require "audible"; include Audible
|
13
|
+
|
14
|
+
def initialize(inner)
|
15
|
+
@inner = inner
|
16
|
+
relay @inner, :poked
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
a_relaying_object = a_relaying_class.new(an_audible_object)
|
21
|
+
|
22
|
+
a_relaying_object.on :poked do |e,args|
|
23
|
+
@relayed_notification,@relayed_args = e,args
|
24
|
+
end
|
25
|
+
|
26
|
+
an_audible_object.poke
|
27
|
+
end
|
28
|
+
|
29
|
+
it ("notifies with the same name") { expect(@relayed_notification).to eql :poked }
|
30
|
+
it ("notifies with the same arguments") { expect(@relayed_args.first).to eql({:a => "1", :b => "2"}) }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "You can rename the relayed notification to something else" do
|
34
|
+
let :an_audible_object do
|
35
|
+
Class.new do
|
36
|
+
require "audible"; include Audible
|
37
|
+
|
38
|
+
def poke; notify :poked; end
|
39
|
+
end.new
|
40
|
+
end
|
41
|
+
|
42
|
+
before do
|
43
|
+
a_relaying_class = Class.new do
|
44
|
+
require "audible"; include Audible
|
45
|
+
|
46
|
+
def initialize(inner)
|
47
|
+
relay inner, :poked, :as => :any_new_name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
@a_relaying_object = a_relaying_class.new(an_audible_object)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "notifies with the new name and suppresses the original" do
|
55
|
+
@a_relaying_object.on :poked do |e,args|
|
56
|
+
fail "Expected the <:poked> notification to be suppressed"
|
57
|
+
end
|
58
|
+
|
59
|
+
@a_relaying_object.on :any_new_name do |e,args|
|
60
|
+
notified = true
|
61
|
+
end
|
62
|
+
|
63
|
+
notified = false
|
64
|
+
|
65
|
+
an_audible_object.poke
|
66
|
+
|
67
|
+
expect(:notified).to be_true, "Expected to be notified with <#{:any_new_name}>"
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Relaying notifications" do
|
4
|
+
let(:an_audible_object) do
|
5
|
+
an_audible_class = Class.new do
|
6
|
+
require "audible"; include Audible
|
7
|
+
|
8
|
+
def poke; notify :poked ; end
|
9
|
+
def tap ; notify :tapped; end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def accepts?(e);
|
14
|
+
[:poked,:tapped].include? e
|
15
|
+
end
|
16
|
+
end.new
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:a_relaying_class) do
|
20
|
+
Class.new do
|
21
|
+
require "audible"; include Audible
|
22
|
+
|
23
|
+
def initialize(inner)
|
24
|
+
@inner = inner
|
25
|
+
relay @inner, :poked
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can be asked to relay requests" do
|
31
|
+
notified = false
|
32
|
+
|
33
|
+
a_relaying_object = a_relaying_class.new(an_audible_object)
|
34
|
+
|
35
|
+
a_relaying_object.on(:poked){ notified = true }
|
36
|
+
|
37
|
+
an_audible_object.poke
|
38
|
+
|
39
|
+
expect(notified).to be_true, "Expected the notification to have been relayed"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can be asked to rename the notification to something else"
|
43
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.join ".", "lib", "audible"
|
2
|
+
|
3
|
+
class TimeServer
|
4
|
+
require 'drb/observer'
|
5
|
+
include DRb::DRbObservable
|
6
|
+
include Audible
|
7
|
+
|
8
|
+
def get_current_time
|
9
|
+
return Time.now
|
10
|
+
end
|
11
|
+
|
12
|
+
def progress
|
13
|
+
3.times do
|
14
|
+
changed
|
15
|
+
notify_observers Time.now.to_s
|
16
|
+
notify :progress, Time.now.to_s
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
FRONT_OBJECT=TimeServer.new
|
22
|
+
|
23
|
+
$SAFE = 0
|
24
|
+
|
25
|
+
require 'drb/drb'
|
26
|
+
|
27
|
+
port = 9999
|
28
|
+
|
29
|
+
uri="druby://127.0.0.1:#{port}"
|
30
|
+
|
31
|
+
DRb.start_service(uri, FRONT_OBJECT)
|
32
|
+
|
33
|
+
puts "Server has started on port <#{port}>, process <#{$$}>"
|
34
|
+
|
35
|
+
Signal.trap("INT") do
|
36
|
+
puts "Stopping..."
|
37
|
+
|
38
|
+
Pidfile.delete
|
39
|
+
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
Pidfile.new $$
|
44
|
+
|
45
|
+
DRb.thread.join
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative File.join 'support', 'drb_server'
|
3
|
+
|
4
|
+
describe "Basic drb connections" do
|
5
|
+
before :all do
|
6
|
+
@server = DrbServer.new("druby://127.0.0.1:9999").tap {|server| server.start}
|
7
|
+
@timeserver = DRbObject.new_with_uri @server.url
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
@server.kill
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
@an_observer = Class.new do
|
16
|
+
def update(args)
|
17
|
+
@notified = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def notified?; @notified === true; end
|
21
|
+
|
22
|
+
def reset; @notified = false; end
|
23
|
+
end.new
|
24
|
+
end
|
25
|
+
|
26
|
+
it "tells me the time" do
|
27
|
+
expect(@timeserver.get_current_time.to_s).to match /^#{Time.now.year}/
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can notify" do
|
31
|
+
@timeserver.add_observer @an_observer
|
32
|
+
|
33
|
+
@timeserver.progress
|
34
|
+
|
35
|
+
expect(@an_observer).to be_notified
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can detach observer which stops notifications" do
|
39
|
+
@timeserver.add_observer @an_observer
|
40
|
+
|
41
|
+
@timeserver.progress
|
42
|
+
|
43
|
+
expect(@an_observer).to be_notified
|
44
|
+
|
45
|
+
@an_observer.reset
|
46
|
+
|
47
|
+
@timeserver.delete_observer @an_observer
|
48
|
+
|
49
|
+
@timeserver.progress
|
50
|
+
|
51
|
+
expect(@an_observer).to_not be_notified
|
52
|
+
end
|
53
|
+
|
54
|
+
it "can also get audible notifications" do
|
55
|
+
notified = false
|
56
|
+
|
57
|
+
@timeserver.on(:progress) do |e,args|
|
58
|
+
notified = true
|
59
|
+
end
|
60
|
+
|
61
|
+
@timeserver.progress
|
62
|
+
|
63
|
+
expect(notified).to be_true
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class DrbServer
|
2
|
+
attr_reader :url
|
3
|
+
|
4
|
+
def initialize(url)
|
5
|
+
@url = url
|
6
|
+
end
|
7
|
+
|
8
|
+
def start
|
9
|
+
exe = File.join(File.dirname(__FILE__), "..", "bin", "server")
|
10
|
+
|
11
|
+
@pid = Process.spawn "bundle exec ruby #{exe}", :err=>:out, :out => ".log"
|
12
|
+
|
13
|
+
while Pidfile.missing?
|
14
|
+
sleep 0.25
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'drb/drb'
|
18
|
+
|
19
|
+
DRb.start_service
|
20
|
+
end
|
21
|
+
|
22
|
+
def kill
|
23
|
+
Process.kill("INT", @pid)
|
24
|
+
Process.wait
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: audible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
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:
|
12
|
+
date: 2014-02-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rdoc
|
@@ -65,21 +65,30 @@ executables: []
|
|
65
65
|
extensions: []
|
66
66
|
extra_rdoc_files:
|
67
67
|
- LICENSE.txt
|
68
|
-
- README.
|
68
|
+
- README.md
|
69
69
|
files:
|
70
70
|
- .document
|
71
71
|
- .travis.yml
|
72
72
|
- Gemfile
|
73
73
|
- Gemfile.lock
|
74
74
|
- LICENSE.txt
|
75
|
-
- README.
|
75
|
+
- README.md
|
76
76
|
- Rakefile
|
77
77
|
- VERSION
|
78
78
|
- audible.gemspec
|
79
79
|
- lib/audible.rb
|
80
80
|
- lib/audible/audible.rb
|
81
|
+
- lib/audible/pidfile.rb
|
82
|
+
- spec/and_how_it_differs_from_observable_spec.rb
|
83
|
+
- spec/examples/a_notifying_shell_spec.rb
|
84
|
+
- spec/examples/logging_as_notifications_spec.rb
|
81
85
|
- spec/listening_spec.rb
|
86
|
+
- spec/relaying_notifications/about_the_notifications_spec.rb
|
87
|
+
- spec/relaying_notifications/can_relay_notifications_spec.rb
|
82
88
|
- spec/spec_helper.rb
|
89
|
+
- spec/system.tests/drb/bin/server
|
90
|
+
- spec/system.tests/drb/drb_observers_spec.rb
|
91
|
+
- spec/system.tests/drb/support/drb_server.rb
|
83
92
|
homepage: http://github.com/ben-biddington/audible
|
84
93
|
licenses:
|
85
94
|
- MIT
|
@@ -95,7 +104,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
104
|
version: '0'
|
96
105
|
segments:
|
97
106
|
- 0
|
98
|
-
hash:
|
107
|
+
hash: 492979357
|
99
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
109
|
none: false
|
101
110
|
requirements:
|
data/README.rdoc
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
= audible
|
2
|
-
|
3
|
-
Description goes here.
|
4
|
-
|
5
|
-
== Contributing to audible
|
6
|
-
|
7
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
8
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
9
|
-
* Fork the project.
|
10
|
-
* Start a feature/bugfix branch.
|
11
|
-
* Commit and push until you are happy with your contribution.
|
12
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
-
|
15
|
-
== Copyright
|
16
|
-
|
17
|
-
Copyright (c) 2013 Ben Biddington. See LICENSE.txt for
|
18
|
-
further details.
|
19
|
-
|