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 CHANGED
@@ -5,6 +5,7 @@ rvm:
5
5
  branches:
6
6
  only:
7
7
  - master
8
+ - next
8
9
  gemfile: Gemfile
9
10
  notifications:
10
11
  recipients:
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
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.1.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 = "2013-07-11"
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.rdoc"
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.rdoc",
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/spec_helper.rb"
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"]
@@ -3,6 +3,11 @@ module Audible
3
3
  events.each{|e| attach(e, &block)}
4
4
  end
5
5
 
6
+ def relay(source, event, opts ={})
7
+ name = opts[:as] || event
8
+ source.on(event){|e,args| notify name, args.first}
9
+ end
10
+
6
11
  protected
7
12
 
8
13
  def attach(event,&block)
@@ -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
@@ -1,4 +1,5 @@
1
1
  require "rspec"
2
+ require File.join ".", "lib", "audible"
2
3
 
3
4
  Object.class_eval do
4
5
  alias :must :should
@@ -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.1.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: 2013-07-11 00:00:00.000000000 Z
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.rdoc
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.rdoc
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: 466976973
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
-