cosell 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ pkg/
2
+ doc/
3
+ rdoc/
4
+ *.swp
@@ -0,0 +1,3 @@
1
+ == 0.0.1 / 2009-07-07
2
+
3
+ * initial release
@@ -0,0 +1,190 @@
1
+ cosell
2
+
3
+ by {Steven Swerling}[http://tab-a.slot-z.net]
4
+
5
+ {rdoc}[http://tab-a.slot-z.net] | {github}[http://www.github.com/swerling/cosell]
6
+
7
+
8
+ == DESCRIPTION:
9
+
10
+ Cosell is a minimal implementation of the 'Announcements' observer
11
+ framework, originally introduced in VisualWorks Smalltalk as a
12
+ replacement for 'triggerEvent' style of event notification. Instead of
13
+ triggering events identified by symbols, the events are first class
14
+ objects. For rationale, please see the original blog posting by Vassili
15
+ Bykov (refs below).
16
+
17
+ *Lineage*
18
+
19
+ This implementation is loosely based on Lukas Renggli's tweak of Colin Putney's
20
+ Squeak implementation of Vassili Bykov's Announcements framework for
21
+ VisualWorks Smalltalk. (Specifically Announcements-lr.13.mcz was used as
22
+ a reference.)
23
+
24
+ Liberties where taken during the port. In particular, the Announcer class
25
+ in the Smalltalk version is implemented here as a ruby module which can be
26
+ mixed into any object. Also, in this implementation any object (or class)
27
+ can serve as an announcement, so no Announcement class is implemented.
28
+
29
+ The ability to queue announcements in the background is built into cosell.
30
+
31
+ <b>The Name 'Cosell'</b>
32
+
33
+ I chose the name 'Cosell' because
34
+
35
+ a. Howard Cosell is an iconic event announcer
36
+ b. Googling for 'Ruby Announcements', 'Ruby Event Announcements', etc., produced scads of results about ruby meetups, conferences, and the like. So I went with something a bit cryptic but hopefully a little more searchable.
37
+
38
+ *See*
39
+
40
+ * {Original blog posting describing Announcments by Vassili Bykov}[http://www.cincomsmalltalk.com/userblogs/vbykov/blogView?entry=3310034894]
41
+ * {More info on the Announcements Framework}[http://wiki.squeak.org/squeak/5734]
42
+
43
+ == FEATURE
44
+
45
+ * Announcements-style event observer framework
46
+ * Synchronous announcements and asynchronous announcements (using a background thread with a queue)
47
+
48
+ == PROBLEMS
49
+
50
+ * None known. Should work in ruby 1.8 and 1.9.
51
+
52
+ == SYNOPSIS:
53
+
54
+
55
+ (this example is in the [gem]/example/basic_example.rb file)
56
+
57
+ #
58
+ # Will produce the following output:
59
+ #
60
+ # And now a word from our sponsor: 'the'
61
+ # End of round 1
62
+ # End of round 2
63
+ # End of round 3
64
+ # End of round 4
65
+ # End of round 5
66
+ # End of round 6
67
+ # End of round 7
68
+ # End of round 8
69
+ # End of round 9
70
+ # End of round 10
71
+ # End of round 11
72
+ # End of round 12
73
+ # End of round 13
74
+ # End of round 14
75
+ # TKO!
76
+
77
+ require 'rubygems'
78
+ require 'cosell'
79
+
80
+ # An announcer
81
+ class Howard
82
+ include Cosell
83
+ end
84
+
85
+ # a receiver of the announcements
86
+ class Television
87
+ def show(ann, opts={})
88
+ puts ann.to_s(opts)
89
+ end
90
+ end
91
+
92
+ # Some announcements
93
+ class Announcement
94
+ def to_s(opts={})
95
+ self.class.to_s + '!'
96
+ end
97
+ end
98
+ class WordFromOurSponsor < Announcement
99
+ attr_accessor :word
100
+ def to_s(opts={})
101
+ "And now a word from our sponsor: '#{word}'"
102
+ end
103
+ end
104
+ class EndOfRound < Announcement
105
+ def to_s(opts={})
106
+ "End of round #{opts[:round]}"
107
+ end
108
+ end
109
+ class KnockOut < Announcement; end
110
+ class TKO < KnockOut; end
111
+
112
+
113
+ # ------- Start announcing -------
114
+
115
+ # Create an announcer, and a subscriber
116
+ round = 1
117
+ howard = Howard.new
118
+ tv = Television.new
119
+ howard.when_announcing(WordFromOurSponsor, KnockOut) { |ann| tv.show(ann) }
120
+
121
+ # Make an announcement
122
+ announcement = WordFromOurSponsor.new
123
+ announcement.word = 'the'
124
+ howard.announce(announcement)
125
+ # => And know a word from our sponsors: 'the'
126
+
127
+ # Make another announcement
128
+ howard.announce(EndOfRound)
129
+ # => nothing, you haven't subscribed yet to EndOfRound. Tree fell, nobody heard. Didn't happen.
130
+
131
+ # Create a second subscription
132
+ eor_subscription = lambda do |ann|
133
+ tv.show(ann, :round => round)
134
+ round += 1
135
+ end
136
+ howard.when_announcing(EndOfRound, &eor_subscription)
137
+
138
+ # Tell the announcer to use a background announcments queue
139
+ # Only allow the announcer to broadcast 5 announcments at a time
140
+ # before going to sleep for 0.05 seconds
141
+ howard.queue_announcements!(:sleep_time => 0.05, :announcements_per_cycle => 5)
142
+
143
+ # Start making announcments (they will be queueud in the background)
144
+ 14.times {howard.announce(EndOfRound)}
145
+
146
+ sleep 0.05 # announcements for the first 5 rounds appear
147
+ sleep 0.05 # announcements for the next 5 rounds
148
+ sleep 0.05 # announcements for end of the next 4 rounds (there is not 15th round
149
+ sleep 0.05 # no announcements, all the announcements have been announced
150
+
151
+ # queue the final announcment
152
+ howard.announce(TKO)
153
+ # => TKO!
154
+
155
+ sleep 0.05 # the TKO is broadcast
156
+
157
+ == REQUIREMENTS:
158
+
159
+ * ruby, rubygems
160
+
161
+ == INSTALL:
162
+
163
+
164
+ gem install swerling-cosell --source http://gems.github.com
165
+
166
+
167
+ == LICENSE:
168
+
169
+ (The MIT License)
170
+
171
+ Copyright (c) 2009
172
+
173
+ Permission is hereby granted, free of charge, to any person obtaining
174
+ a copy of this software and associated documentation files (the
175
+ 'Software'), to deal in the Software without restriction, including
176
+ without limitation the rights to use, copy, modify, merge, publish,
177
+ distribute, sublicense, and/or sell copies of the Software, and to
178
+ permit persons to whom the Software is furnished to do so, subject to
179
+ the following conditions:
180
+
181
+ The above copyright notice and this permission notice shall be
182
+ included in all copies or substantial portions of the Software.
183
+
184
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
185
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
186
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
187
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
188
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
189
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
190
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,65 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ begin
10
+ load 'tasks/setup.rb'
11
+ rescue LoadError
12
+ raise RuntimeError, '### please install the "bones" gem ###'
13
+ end
14
+ end
15
+
16
+ ensure_in_path 'lib'
17
+ require 'cosell'
18
+
19
+ task :default => 'spec:run'
20
+
21
+ PROJ.name = 'cosell'
22
+ PROJ.authors = 'Steven Swerling'
23
+ PROJ.email = 'sswerling@yahoo.com'
24
+ PROJ.url = 'http://github.com/swerling/TODO'
25
+ PROJ.version = Cosell::VERSION
26
+ PROJ.rubyforge.name = 'cosell'
27
+ PROJ.readme_file = 'README.rdoc'
28
+
29
+ PROJ.spec.opts << '--color'
30
+
31
+ PROJ.rdoc.opts = ["--inline-source", "-o rdoc", "--format=html", "-T hanna"]
32
+
33
+
34
+
35
+ require 'fileutils'
36
+ def this_dir; File.join(File.dirname(__FILE__)); end
37
+ def doc_dir; File.join(this_dir, 'rdoc'); end
38
+ def tab_a_doc_dir; File.join(this_dir, '../tab-a/public/cosell/rdoc'); end
39
+ task :myclobber => [:clobber] do
40
+ mydir = File.join(File.dirname(__FILE__))
41
+ sh "rm -rf #{File.join(mydir, 'pkg')}"
42
+ sh "rm -rf #{File.join(mydir, 'doc')}"
43
+ sh "rm -rf #{File.join(mydir, 'rdoc')}"
44
+ sh "rm -rf #{File.join(mydir, 'ext/*.log')}"
45
+ sh "rm -rf #{File.join(mydir, 'ext/*.o')}"
46
+ sh "rm -rf #{File.join(mydir, 'ext/*.so')}"
47
+ sh "rm -rf #{File.join(mydir, 'ext/Makefile')}"
48
+ sh "rm -rf #{File.join(mydir, 'ext/Makefile')}"
49
+ end
50
+ task :mypackage => [:myclobber] do
51
+ Rake::Task['gem:package'].invoke
52
+ end
53
+ task :mydoc => [:myclobber] do
54
+ FileUtils.rm_f doc_dir()
55
+ sh "cd #{this_dir()} && rdoc -o rdoc --inline-source --format=html -T hanna README.rdoc lib/**/*.rb"
56
+ end
57
+ task :taba => [:mydoc] do
58
+ this_dir = File.join(File.dirname(__FILE__))
59
+ FileUtils.rm_rf tab_a_doc_dir
60
+ FileUtils.cp_r doc_dir, tab_a_doc_dir
61
+ end
62
+
63
+ task :mygemspec => [:myclobber] do
64
+ Rake::Task['gem:spec'].invoke
65
+ end
@@ -0,0 +1,65 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{cosell}
5
+ s.version = "0.0.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Steven Swerling"]
9
+ s.date = %q{2009-08-09}
10
+ s.description = %q{Cosell is a minimal implementation of the 'Announcements' observer
11
+ framework, originally introduced in VisualWorks Smalltalk as a
12
+ replacement for 'triggerEvent' style of event notification. Instead of
13
+ triggering events identified by symbols, the events are first class
14
+ objects. For rationale, please see the original blog posting by Vassili
15
+ Bykov (refs below).
16
+
17
+ *Lineage*
18
+
19
+ This implementation is loosely based on Lukas Renggli's tweak of Colin Putney's
20
+ Squeak implementation of Vassili Bykov's Announcements framework for
21
+ VisualWorks Smalltalk. (Specifically Announcements-lr.13.mcz was used as
22
+ a reference.)
23
+
24
+ Liberties where taken during the port. In particular, the Announcer class
25
+ in the Smalltalk version is implemented here as a ruby module which can be
26
+ mixed into any object. Also, in this implementation any object (or class)
27
+ can serve as an announcement, so no Announcement class is implemented.
28
+
29
+ The ability to queue announcements in the background is built into cosell.
30
+
31
+ <b>The Name 'Cosell'</b>
32
+
33
+ I chose the name 'Cosell' because
34
+
35
+ a. Howard Cosell is an iconic event announcer
36
+ b. Googling for 'Ruby Announcements', 'Ruby Event Announcements', etc., produced scads of results about ruby meetups, conferences, and the like. So I went with something a bit cryptic but hopefully a little more searchable.
37
+
38
+ *See*
39
+
40
+ * {Original blog posting describing Announcments by Vassili Bykov}[http://www.cincomsmalltalk.com/userblogs/vbykov/blogView?entry=3310034894]
41
+ * {More info on the Announcements Framework}[http://wiki.squeak.org/squeak/5734]}
42
+ s.email = %q{sswerling@yahoo.com}
43
+ s.extra_rdoc_files = ["History.txt", "README.rdoc"]
44
+ s.files = [".gitignore", "History.txt", "README.rdoc", "Rakefile", "cosell.gemspec", "example/basic_example.rb", "example/cat_whisperer.rb", "lib/cosell.rb", "lib/cosell/announcer.rb", "lib/cosell/monkey.rb", "spec/cosell_spec.rb", "spec/spec_helper.rb"]
45
+ s.has_rdoc = true
46
+ s.homepage = %q{http://github.com/swerling/TODO}
47
+ s.rdoc_options = ["--inline-source", "-o rdoc", "--format=html", "-T hanna", "--main", "README.rdoc"]
48
+ s.require_paths = ["lib"]
49
+ s.rubyforge_project = %q{cosell}
50
+ s.rubygems_version = %q{1.3.2}
51
+ s.summary = %q{Cosell is a minimal implementation of the 'Announcements' observer framework, originally introduced in VisualWorks Smalltalk as a replacement for 'triggerEvent' style of event notification}
52
+
53
+ if s.respond_to? :specification_version then
54
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
58
+ s.add_development_dependency(%q<bones>, [">= 2.5.1"])
59
+ else
60
+ s.add_dependency(%q<bones>, [">= 2.5.1"])
61
+ end
62
+ else
63
+ s.add_dependency(%q<bones>, [">= 2.5.1"])
64
+ end
65
+ end
@@ -0,0 +1,99 @@
1
+ #
2
+ # Will produce the following output:
3
+ #
4
+ # And now a word from our sponsor: 'the'
5
+ # End of round 1
6
+ # End of round 2
7
+ # End of round 3
8
+ # End of round 4
9
+ # End of round 5
10
+ # End of round 6
11
+ # End of round 7
12
+ # End of round 8
13
+ # End of round 9
14
+ # End of round 10
15
+ # End of round 11
16
+ # End of round 12
17
+ # End of round 13
18
+ # End of round 14
19
+ # TKO!
20
+
21
+ require 'rubygems'
22
+ require 'cosell'
23
+
24
+ # An announcer
25
+ class Howard
26
+ include Cosell
27
+ end
28
+
29
+ # a receiver of the announcements
30
+ class Television
31
+ def show(ann, opts={})
32
+ puts ann.to_s(opts)
33
+ end
34
+ end
35
+
36
+ # Some announcements
37
+ class Announcement
38
+ def to_s(opts={})
39
+ self.class.to_s + '!'
40
+ end
41
+ end
42
+ class WordFromOurSponsor < Announcement
43
+ attr_accessor :word
44
+ def to_s(opts={})
45
+ "And now a word from our sponsor: '#{word}'"
46
+ end
47
+ end
48
+ class EndOfRound < Announcement
49
+ def to_s(opts={})
50
+ "End of round #{opts[:round]}"
51
+ end
52
+ end
53
+ class KnockOut < Announcement; end
54
+ class TKO < KnockOut; end
55
+
56
+
57
+ # ------- Start announcing -------
58
+
59
+ # Create an announcer, and a subscriber
60
+ round = 1
61
+ howard = Howard.new
62
+ tv = Television.new
63
+ howard.when_announcing(WordFromOurSponsor, KnockOut) { |ann| tv.show(ann) }
64
+
65
+ # Make an announcement
66
+ announcement = WordFromOurSponsor.new
67
+ announcement.word = 'the'
68
+ howard.announce(announcement)
69
+ # => And know a word from our sponsors: 'the'
70
+
71
+ # Make another announcement
72
+ howard.announce(EndOfRound)
73
+ # => nothing, you haven't subscribed yet to EndOfRound. Tree fell, nobody heard. Didn't happen.
74
+
75
+ # Create a second subscription
76
+ eor_subscription = lambda do |ann|
77
+ tv.show(ann, :round => round)
78
+ round += 1
79
+ end
80
+ howard.when_announcing(EndOfRound, &eor_subscription)
81
+
82
+ # Tell the announcer to use a background announcments queue
83
+ # Only allow the announcer to broadcast 5 announcments at a time
84
+ # before going to sleep for 0.05 seconds
85
+ howard.queue_announcements!(:sleep_time => 0.05, :announcements_per_cycle => 5)
86
+
87
+ # Start making announcments (they will be queueud in the background)
88
+ 14.times {howard.announce(EndOfRound)}
89
+
90
+ sleep 0.05 # announcements for the first 5 rounds appear
91
+ sleep 0.05 # announcements for the next 5 rounds
92
+ sleep 0.05 # announcements for end of the next 4 rounds (there is not 15th round
93
+ sleep 0.05 # no announcements, all the announcements have been announced
94
+
95
+ # queue the final announcment
96
+ howard.announce(TKO)
97
+ # => TKO!
98
+
99
+ sleep 0.05 # the TKO is broadcast
@@ -0,0 +1,87 @@
1
+ #
2
+ # Sits by window, talks to cats
3
+ #
4
+ class CatWhisperer
5
+ include Cosell::Announcer
6
+ end
7
+
8
+ #
9
+ # events that occur in the home
10
+ #
11
+ class SomeoneEnteringHome
12
+ attr_accessor :who_is_entering
13
+ end
14
+ class OwnerEnteringHome < SomeoneEnteringHome; end
15
+ class BurglerEnteringHome < SomeoneEnteringHome; end
16
+ class DogEnteringHome < SomeoneEnteringHome; end
17
+ class BirdEnteringHome < SomeoneEnteringHome; end
18
+
19
+ #
20
+ # participants
21
+ #
22
+ class Cat
23
+ end
24
+ class NormalSizedCat < Cat
25
+ def deal_with_dog(dog)
26
+ if dog.running_at_cat?(self)
27
+ puts "run to bookshelf; climb bookshelf; feign indifference"
28
+ else
29
+ puts "feign indifference; saunter to bookshelf; climb bookshelf; feign indifference"
30
+ end
31
+ end
32
+ def deal_with_burgler(burgler)
33
+ puts "feign indifference"
34
+ end
35
+ def deal_with_owner(owner)
36
+ puts "feign indifference while slowly sauntering towards owner; " \
37
+ + "nuzzle owner; receive affection; try to feign indifference; break down and start purring"
38
+ end
39
+
40
+ end
41
+
42
+ class ReallyBigCat < Cat
43
+ def eat(who)
44
+ puts "Really big cat eats #{who}"
45
+ end
46
+ def deal_with_burgler(burgler)
47
+ eat('burgler')
48
+ end
49
+ def deal_with_owner(owner)
50
+ eat('owner')
51
+ end
52
+ def deal_with_dog(owner)
53
+ eat('dog')
54
+ end
55
+ end
56
+
57
+ cat_whisperer = CatWhisperer.new
58
+ really_big_cat = ReallyBigCat.new
59
+ regular_cat = NormalSizedCat.new
60
+
61
+ #
62
+ # wire up events
63
+ #
64
+ cat_whisperer.when_announcing(DogEnteringHome) do |event|
65
+ cat.deal_with_dog(event.who_is_entering)
66
+ rally_big_cat.deal_with_dog(event.who_is_entering)
67
+ end
68
+ cat_whisperer.when_announcing(DogEnteringHome, :send => |event|
69
+ cat.deal_with_dog(event.who_is_entering)
70
+ rally_big_cat.deal_with_dog(event.who_is_entering)
71
+ end
72
+
73
+ cat_whisperer.when_announcing(OwnerEnteringHome) do |event|
74
+ cat.deal_with_person(dog_entering_event.who_is_entering)
75
+ rally_big_cat.deal_with_dog(dog_entering_event.who_is_entering)
76
+ end
77
+
78
+ cat_whisperer.when_announcing(BurglerEnteringHome) do |event|
79
+ cat.deal_with_person(event.who_is_entering)
80
+ rally_big_cat.deal_with_dog(event.who_is_entering)
81
+ end
82
+
83
+ #
84
+ # Mayhem ensues
85
+ #
86
+ cat_whisperer.announce(OwnerEnteringHome.new)
87
+ # =>