cosell 0.0.2

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.
@@ -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
+ # =>