[ANN] Copland to Needle article on RubyGarden

For those not subscribed to RubyGarden's rss feed[1], Jamis Buck has
written a new feature piece discussing his journey from
dependency-injection-novice to two-time-IoC-frameworker. He also
discusses the (unusual) decision to start over on a framework that is
less than a year old and demonstrates the differences between these
two frameworks (Copland and Needle). Big thanks go to Jamis for his
fascinating contribution.

The article is available on RubyGarden's front page or at:
http://rubygarden.org/index.cgi/Libraries/copland-to-needle.rdoc

Request: If you'd like to write an article or tutorial or conduct an
interview to be published on RubyGarden.org, please send me an email
directly. I'm working to establish a rhythm of new content releases,
so if you're interested in contributing I would love to hear from you.

Thanks,
Chad Fowler

[1] http://rubygarden.org/index.cgi/index.rss

In article <a2347a04041112044531ad44b1@mail.gmail.com>,

For those not subscribed to RubyGarden's rss feed[1], ...

[1] http://rubygarden.org/index.cgi/index.rss

I've been meaning to get 'into' this RSS thing for a while now, but
haven't thought too seriously about it until the last couple of weeks.

So for those of us who are only just now figuring out that there's a
party going on out there (which has apparently been going on for quite a
while now - so I guess I'm fashionably late :), how does one get in?
What is the secret handshake? I know that one needs a thingy called an
aggregator. This sounds a bit like a combination of a news reader and an
email client. What are the recommended aggregators (esp. for Linux and OS X)?
Why is it that web pages will have an RSS link which only brings up a bunch
of XML in your browser when clicked? Do some browsers double as aggregators
and thus allow you to subscribe by clicking on the 'RSS' link? Do these
'aggregations' get emailed to you or do you start up a tool that goes and
looks for them? What if you're wanting to get these RSS feeds on multiple
machines in different locations?

....I feel so out of it.

Phil

···

Chad Fowler <chadfowler@gmail.com> wrote:

Chad Fowler wrote:

For those not subscribed to RubyGarden's rss feed[1], Jamis Buck has
written a new feature piece discussing his journey from
dependency-injection-novice to two-time-IoC-frameworker. He also
discusses the (unusual) decision to start over on a framework that is
less than a year old and demonstrates the differences between these
two frameworks (Copland and Needle). Big thanks go to Jamis for his
fascinating contribution.

The article is available on RubyGarden's front page or at:
http://rubygarden.org/index.cgi/Libraries/copland-to-needle.rdoc

Request: If you'd like to write an article or tutorial or conduct an
interview to be published on RubyGarden.org, please send me an email
directly. I'm working to establish a rhythm of new content releases,
so if you're interested in contributing I would love to hear from you.

Thanks,
Chad Fowler

[1] http://rubygarden.org/index.cgi/index.rss

Jamis Buck's and Jim Weirich's articles are great. I could never get
through the Java-oriented discussion of this subject, and now that the
subject is presented for rubyists a dim bulb is finally going on in my
head.

What really helps me think about this is to reduce it to some simple,
standard Ruby idioms, which don't provide as many features as Needle,
but are close enough to code that I've actually written to make it all
seem meaningful.

Let's take Jim's example[1], which is clear, rubified, and explicit
about DI constructs, and translate it into some concrete,
mundane ruby code without those constructs. Here's the original:

   def create_application
     container = DI::Container.new
     container.register(:logfilename) { "logfile.log" }
     container.register(:db_user) { "jim" }
     container.register(:db_password) { "secret" }
     container.register(:dbi_string) { "DBI:Pg:example_data" }

     container.register(:app) { |c|
       app = WebApp.new(c.quotes, c.authenticator, c.database)
       app.logger = c.logger
       app.set_error_handler c.error_handler
       app
     }

     container.register(:quotes) { |c|
       StockQuotes.new(c.error_handler, c.logger)
     }

     container.register(:authenticator) { |c|
       Authenticator.new(c.database, c.logger, c.error_handler)
     }

     container.register(:database) { |c|
       DBI.connect(c.dbi_string, c.db_user, c.db_password)
     }

     container.register(:logger) { |c| Logger.new(c.logfilename) }
     container.register(:error_handler) { |c|
       errh = ErrorHandler.new
       errh.logger = c.logger
       errh
     }
   end

And here's a rewrite that functions in about the same way, but without
being explicit about containers and services.

   class Application
     def logfilename
       @logfilename ||= "logfile.log"
     end

     def db_user
       @db_user ||= "jim"
     end

     def db_password
       @db_password ||= "secret"
     end

     def dbi_string
       @dbi_string ||= "DBI:Pg:example_data"
     end

     def app
       @app ||= WebApp.new(quotes, authenticator, database)
     end

     def quotes
       @quotes ||= StockQuotes.new(error_handler, logger)
     end

     def authenticator
       @authenticator ||=
         Authenticator.new(database, logger, error_handler)
     end

     def database
       @database ||= DBI.connect(dbi_string, db_user, db_password)
     end

     def logger
       @logger ||= Logger.new(logfilename)
     end

     def error_handler
       @errh ||= (
         ErrorHandler.new
         @errh.logger = logger
         @errh
       )
     end
   end

   def create_application
     Application.new
   end

So we're using the Application class itself as the container, and
we're using the instance methods of this class as the service points.
The methods return the services, and also store them in instance
variables. A service is registered using "def". Instead of using the
block parameter to pass the container to the service definitions, you
just use self. The familiar ||= idiom provides the singleton service
model.

It's quick and dirty, and it obscures the conceptual structure, but if
you're familiar with ruby, you can see immediately what is going on.
You've probably even written code a little like this. Why would you
want to "upgrade" your code to a more explicit form of DI? There are
several disadvantages to this implicit DI style, aside from the
implicitness itself:

- It doesn't help much with things like interceptors, although you
   could bring in your favorite AOP library.

- It mixes your service namespace with the namespace inherited from
   Object and Kernel: maybe you want a service called "dup" or "puts",
   but then you cannot call the Object and Kernel implementation of
   these methods from within methods of the Application class.

- Reflection must be done using standard ruby reflection on classes,
   so you have to, for example, filter out methods that are not really
   services.

OTOH, you can use class inheritance and module inclusion to build
trees of container definitions in a very natural and familiar way,
emulating some of the functionality of Needle:

   module LoggingServices
     def logger; ...; end
   end

   module GUIServices
   end

   module DatabaseServices
   end

   class MyServiceContainer
     include LoggingServices
     include GUIServices
     include DatabaseServices

     def app
       MyApp.new(logger, gui, database)
     end
   end

The other service models besides the singleton model are also easy to
implement with quick and dirty ruby code:

- Threaded:

   def per_thread_logger
     @per_thread_logger ||= {}
     @per_thread_logger[Thread.current] ||= Logger.new
   end

- Prototype:

   def gui_button
     MyButtonClass.new
   end

- Deferred (ok, this one gets a little messy, and the details should
   be abstracted away by some fancy metaprogramming):

   def big_resource
     @big_resource || big_resource_proxy
   end

   def big_resource_proxy
     @big_resource_proxy ||= (
       proxy = [proc {|br| @big_resource = br}]
       def proxy.method_missing(*args, &block)
         big_resource = BigResource.new
         at(0).call(big_resource)
         big_resource.send(*args, &block)
       end
       proxy
     )
   end
   private :big_resource_proxy

There are other service models that are very easy to construct with
methods, but I'm not aware of an equivalent construct in Needle:

   def printer(kind)
     @printers ||= {}
     @printers[kind] = Printer.new(kind)
   end

   def printer_for_code_files
     @printer_for_code_files ||= printer(:monochrome)
   end

   def printer_for_images
     @printer_for_images ||= printer(:color)
   end

It might be possible to do the above in Needle using Pipelines.[2]

Namespaces, if I understand the Needle docs correctly, work something
like this:

   class PictureApp
     class ColorNamespace
       def red; PrimaryColor(:red); end
       def green; PrimaryColor(:green); end
       def yellow; @yellow ||= red+green; end
     end

     def colors
       @colors ||= ColorNamespace.new
     end

     def picture
       @picture ||= Picture.new(:background => colors.yellow)
     end
   end

Alternately, if you want color instances to shared by all PictureApps,
you might want to define the colors service like this:

     def colors
       @@colors ||= ColorNamespace.new
     end

I hope there aren't too many inaccuracies in the above, and that this
helps other folks move from older ruby idioms to the new idioms
that Needle gives us.

···

--

[1] http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc

[2] Anybody know? Or are parameterized services a misuse of the DI
     pattern?

I've been meaning to get 'into' this RSS thing for a while now, but
haven't thought too seriously about it until the last couple of weeks.

So for those of us who are only just now figuring out that there's a
party going on out there (which has apparently been going on for quite a
while now - so I guess I'm fashionably late :), how does one get in?

Start by getting yourself an aggregator. There are tons of free apps around, you might want to pick one from the list at RSS Readers (RSS Info) or just Google around. I'm a Mac head, and my aggregator of choice is NetNewsWire Lite.

Alternately, you can setup an account on a web-based aggregation service, like http://bloglines.com/ . Same thing, only on a web site.

Use the various RSS URIs ( like http://rubygarden.org/index.cgi/index.rss ) to subscribe to a few starter feeds. You could start with the list at http://rubygarden.org/ruby?RssFeeds , though that misses quite a lot, too. You'll find yourself reading entries that refer to other sites, then subscribing to those new sites' RSS feeds. Typically my subscription list slowly grows, and then from time to time I get disgusted with my info bingeing and I try to pare down the subscription list. (I have the same problem with magazines.)

Why is it that web pages will have an RSS link which only brings up a bunch
of XML in your browser when clicked?

What I do with those (using Safari on Mac) is right-click those links, select "Copy Link to Clipboard", and then switch to NNW and subscribe to that feed. Yeah, you're not really meant to read it in a browser, though some browsers make it easier to scan through XML files than others.

Do some browsers double as aggregators
and thus allow you to subscribe by clicking on the 'RSS' link?

Don't know of any yet, but I believe that browser from both Apple and Microsoft will have more RSS integration in their next major versions.

Do these
'aggregations' get emailed to you or do you start up a tool that goes and
looks for them?

Usually you start up the tool. You can get them emailed to you, but that usually gives you less control over your time. Besides ruby-talk, I'm not actively involved in a lot of email lists. I prefer blogish conversations more, because I get to make a harder separation between personal messages (email) and group messages (blogs). When I'm trying to focus, I shut down my aggregator and only have the email running in the background.

What if you're wanting to get these RSS feeds on multiple
machines in different locations?

Then a web-based service, like bloglines, is probably a better match for you.

One cool thing is that RSS has all sorts of bizarre uses besides just content from a single author. PubSub Concepts, for example, is a company that has lightning-fast, free searching of millions of data sources, and you can make URIs that represent feeds for strings you're looking for. For example, this URI gives me every time it finds the string "Francis Hwang", usually within hours of the content being posted:

http://rss.pubsub.com/e7/93/819df23244dbc3a86c3fa46306.xml

Sw33t.

F.

···

On Nov 12, 2004, at 11:53 PM, Phil Tomson wrote:

Joel VanderWerf wrote:

Jamis Buck's and Jim Weirich's articles are great. I could never get
through the Java-oriented discussion of this subject, and now that the
subject is presented for rubyists a dim bulb is finally going on in my
head.

Yay! :slight_smile:

What really helps me think about this is to reduce it to some simple,
standard Ruby idioms, which don't provide as many features as Needle,
but are close enough to code that I've actually written to make it all
seem meaningful.

Excellent approach, Joel. You've hit the nail right on the head. DI is nothing new--most of us have been doing something at least similar to it for a long time. It's like any of the design patterns--it's not that they are new, so much as they've been given a name so that they can be communicated better.

As far as the DI frameworks are concerned (like Needle and Copland), they don't let you do anything you couldn't before. They just make it so that you don't have to reimplement a DI framework yourself for every project you create. Plus, they are tested and stable, so you can focus on your application logic instead of your own custom DI infrastructure.

There are other service models that are very easy to construct with
methods, but I'm not aware of an equivalent construct in Needle:

  def printer(kind)
    @printers ||= {}
    @printers[kind] = Printer.new(kind)
  end

  def printer_for_code_files
    @printer_for_code_files ||= printer(:monochrome)
  end

  def printer_for_images
    @printer_for_images ||= printer(:color)
  end

It might be possible to do the above in Needle using Pipelines.[2]

Hmm. I wouldn't call this a service model so much as a factory service. In fact, I have a new favorite way of doing this kind of thing, as of this morning. To complicate things a bit, suppose that the Printer class needs to be dependency injected (with a logger instance, for example), and the following approach really shines:

   reg.define do |b|
     b.printer do |ctr,info|
       logger = ctr[:logs].get( info )
       lambda { |kind| Printer.new( logger, kind ) }
     end

     b.code_printer { |ctr,| ctr.printer.call( :monochrome ) }
     b.image_printer { |ctr,| ctr.printer.call( :color ) }
   end

I've actually incorporated this approach into various places in the upcoming new release of Net::SSH, and it works beautifully.

I hope there aren't too many inaccuracies in the above, and that this
helps other folks move from older ruby idioms to the new idioms
that Needle gives us.

Excellent write-up, Joel. You ought to publish this somewhere on a website...although the fact that you posted it _here_ means it will be archived in the ruby-talk archives, which is probably good enough.

Thanks!

- Jamis

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

i think i've used all the free ones. i needed to test out my own rss
feed so i'm made it a point to check a good number of them out.

the ones i liked:

amphetadesk (perl/any browser, cross-platform)
abilon
newzspider
nttp//rss (java/ any newsreader, cross-platform)
newzie
sage (firefox plugin, cross-platform)
thunderbird (built in rss support, cross-platform)

ones i didn't like:

feedreader
blogmatrix (python based, cross-platform
bottomfeeder (java based)
any .net based ones

i use the sage plugin for firefox, as i invevitably want to click on a
a link anyway...
http://home.cogeco.ca/~tsummerfelt1
telnet://ventedspleen.dyndns.org

···

On Sat, 13 Nov 2004 13:53:26 +0900, you wrote:

I've been meaning to get 'into' this RSS thing for a while now, but
haven't thought too seriously about it until the last couple of weeks.

Hello,

I am using Test::Unit for couple of days.

I have a script something like this:

class TestClass < Test::Unit::TestCase

   def setup
      @foo = Foo.new
      @run = Foo.run(@foo.key)
      @rerun = Foo.rerun(@run.key)
   end

   def test_run
      assert_equal(@foo.key, @run.key)
   end

   def test_rerun
      assert_equal(@run.key, @rerun.key)
   end

end

If I run the above script without any option, would #setup be executed twice, once for #test_run and once for #test_rerun.

Thanks in advance,
Mohammad

···

--

[mkhan@localhost local]$ make love
make: *** No rule to make target `love'. Stop.

Francis Hwang wrote:

One cool thing is that RSS has all sorts of bizarre uses besides just
content from a single author. PubSub Concepts, for example, is a
company that has lightning-fast, free searching of millions of data
sources, and you can make URIs that represent feeds for strings you're
looking for. For example, this URI gives me every time it finds the
string "Francis Hwang", usually within hours of the content being
posted:

http://rss.pubsub.com/e7/93/819df23244dbc3a86c3fa46306.xml

I've been a longtime RSS user and have used many different readers over the
years. But I was unaware of PubSub. It looks like a fantastic resource --
thanks!

Also, linked off of the PubSub home page is an RSS client called Gush that I
also had not hear of. It has a very interesting mix of features and looks
very promising. I'm downloading it right now and it may replace my current
reader. So, thanks again!

Curt

PS
   For those that want to check it out, here is the home page for Gush:

       http://www.2entwine.com/

   Be sure to read the "About Us" page... these guys have a great sense of
humor.

Excellent write-up, Joel. You ought to publish this somewhere on a website...although the fact that you posted it _here_ means it will be archived in the ruby-talk archives, which is probably good enough.

Publish on Rubymine (rubymine.org), its one of the other points of the site is to bring all news together kind of like a slashdot for the ruby community without all the fuzz of other topics. :wink:

David Ross

Jamis Buck wrote:

Joel VanderWerf wrote:

...

There are other service models that are very easy to construct with
methods, but I'm not aware of an equivalent construct in Needle:

  def printer(kind)
    @printers ||= {}
    @printers[kind] = Printer.new(kind)
  end

  def printer_for_code_files
    @printer_for_code_files ||= printer(:monochrome)
  end

  def printer_for_images
    @printer_for_images ||= printer(:color)
  end

It might be possible to do the above in Needle using Pipelines.[2]

Hmm. I wouldn't call this a service model so much as a factory service. In fact, I have a new favorite way of doing this kind of thing, as of this morning. To complicate things a bit, suppose that the Printer class needs to be dependency injected (with a logger instance, for example), and the following approach really shines:

  reg.define do |b|
    b.printer do |ctr,info|
      logger = ctr[:logs].get( info )
      lambda { |kind| Printer.new( logger, kind ) }
    end

    b.code_printer { |ctr,| ctr.printer.call( :monochrome ) }
    b.image_printer { |ctr,| ctr.printer.call( :color ) }
  end

I've actually incorporated this approach into various places in the upcoming new release of Net::SSH, and it works beautifully.

That captures the parameterization, but it doesn't capture the multiton[1] service model of my code. A unique instance is generated for each distinct argument list (distinct in the sense of hash keys, which is to say #eql?). What's the most natural way to do that with Needle?

···

--

[1] http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/67899
  (ruby-talk.org is down right now).

the ones i liked:

amphetadesk (perl/any browser, cross-platform)
abilon
newzspider
nttp//rss (java/ any newsreader, cross-platform)
newzie
sage (firefox plugin, cross-platform)
thunderbird (built in rss support, cross-platform)

Thanks for the roundup.

ones i didn't like:

feedreader
blogmatrix (python based, cross-platform
bottomfeeder (java based)

BottomFeeder is Smalltalk-based, actually.

any .net based ones

BloatWarePlus. But RSS Bandit is popular, Curt rated it, and it has a
cool name.

i use the sage plugin for firefox, as i invevitably want to click on a
a link anyway...

I use that too, but it could do with some work...

And besides, it's not very featureful. I keep wanting to get into a
decent RSS reader, but the "couldn't be bothered" factor is very high.

Gavin

···

On Monday, November 15, 2004, 8:17:24 AM, tony wrote:

If I run the above script without any option, would #setup be executed twice, once for #test_run and once for #test_rerun.

Just to be nitpicky, you would get errors about Foo not being defined ... :slight_smile:

I guess you meant:

require "test/unit"

class TestClass < Test::Unit::TestCase

    def setup
       puts "in setup"
    end

    def test_run
       assert_equal(true, true)
    end

    def test_rerun
       assert_equal(true, true)
    end

end

outputs:

>ruby test_setup.rb
Loaded suite test_setup
Started
in setup
.in setup
.
Finished in 0.0 seconds.

2 tests, 2 assertions, 0 failures, 0 errors
>Exit code: 0

Does that answer your question? :slight_smile:

regards,
Henrik

If you want to setup the variables once for the test case, you should use:

class TestClass < Test::Unit::TestCase
  def initialize
    super
    @foo = Foo.new
    @run = Foo.run(@foo.key)
    @rerun = Foo.rerun(@run.key)
  end

   def test_run
      assert_equal(@foo.key, @run.key)
   end

   def test_rerun
      assert_equal(@run.key, @rerun.key)
   end
end

Would fill each variable only once.

Regards,

Brian

···

On Tue, 16 Nov 2004 00:36:25 +0900 Mohammad Khan <mkhan@lextranet.com> wrote:

Hello,

I am using Test::Unit for couple of days.

I have a script something like this:

class TestClass < Test::Unit::TestCase

   def setup
      @foo = Foo.new
      @run = Foo.run(@foo.key)
      @rerun = Foo.rerun(@run.key)
   end

   def test_run
      assert_equal(@foo.key, @run.key)
   end

   def test_rerun
      assert_equal(@run.key, @rerun.key)
   end

end

--
Brian Schröder
http://www.brian-schroeder.de/

Curt Hibbs rote:

Francis Hwang wrote:
>
> One cool thing is that RSS has all sorts of bizarre uses besides just
> content from a single author. PubSub Concepts, for example, is a
> company that has lightning-fast, free searching of millions of data
> sources, and you can make URIs that represent feeds for strings you're
> looking for. For example, this URI gives me every time it finds the
> string "Francis Hwang", usually within hours of the content being
> posted:
>
> http://rss.pubsub.com/e7/93/819df23244dbc3a86c3fa46306.xml

I've been a longtime RSS user and have used many different
readers over the
years. But I was unaware of PubSub. It looks like a fantastic resource --
thanks!

Also, linked off of the PubSub home page is an RSS client called
Gush that I
also had not hear of. It has a very interesting mix of features and looks
very promising. I'm downloading it right now and it may replace my current
reader. So, thanks again!

Curt

PS
   For those that want to check it out, here is the home page for Gush:

       http://www.2entwine.com/

   Be sure to read the "About Us" page... these guys have a great sense of
humor.

Well... I didn't really like Gush all that much, so I just uninstalled it.
My favorite reader for Windows is still RSS Bandit
(RSS Bandit).

Curt

Joel VanderWerf wrote:

Jamis Buck wrote:

  reg.define do |b|
    b.printer do |ctr,info|
      logger = ctr[:logs].get( info )
      lambda { |kind| Printer.new( logger, kind ) }
    end

    b.code_printer { |ctr,| ctr.printer.call( :monochrome ) }
    b.image_printer { |ctr,| ctr.printer.call( :color ) }
  end

I've actually incorporated this approach into various places in the upcoming new release of Net::SSH, and it works beautifully.

That captures the parameterization, but it doesn't capture the multiton[1] service model of my code. A unique instance is generated for each distinct argument list (distinct in the sense of hash keys, which is to say #eql?). What's the most natural way to do that with Needle?

Actually, the example does--I just enforced the singleton (multiton?) constraint in the code_printer and image_printer services. The +printer+ service itself, though, will generate a new instance for each invocation.

However, you could also create a service factory. It would do just as you did, with a Hash for caching created instances.

   class Printer
     def self.get( name )
       @printers ||= Hash.new
       @printers[ name ] ||= new( name )
     end

     private_class_method :new
     def initialize( name )
       ...
     end
   end

   reg.define.printers { Printer }

   p1 = reg.printers.get( :monochrome )
   p2 = reg.printers.get( :monochrome )
   assert_same p1, p2

In fact, this is almost exactly how the log-factory service in Needle works, although the LogFactory is a distinct class from the Logger.

I'm still thinking through how to implement something like this in Needle itself. It'll probably wind up being, as you suggested, a pipeline element of some sort, although the parameterization issue goes a bit deeper.

- Jamis

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

BottomFeeder is Smalltalk-based, actually.

yeah, i forgot that...

any .net based ones

BloatWarePlus.

especially if you run win2k that doesn't have .net....

i use the sage plugin for firefox, as i invevitably want to click on a
a link anyway...

I use that too, but it could do with some work...
And besides, it's not very featureful.

the only real feature i could use with sage is keeping old items.
thunderbird's rss does that, same with any reader that actually pulls
in the feeds and not just the xml...

http://home.cogeco.ca/~tsummerfelt1
telnet://ventedspleen.dyndns.org

···

On Mon, 15 Nov 2004 07:41:25 +0900, you wrote:

>
>
> If I run the above script without any option, would #setup be executed twice, once for #test_run and once for #test_rerun.

Just to be nitpicky, you would get errors about Foo not being defined ... :slight_smile:

:slight_smile:

I guess you meant:

require "test/unit"

class TestClass < Test::Unit::TestCase

    def setup
       puts "in setup"
    end

    def test_run
       assert_equal(true, true)
    end

    def test_rerun
       assert_equal(true, true)
    end

end

I am confused about the '.' before the on second output 'in setup'.
what does that '.' mean?

Going back to my original example.
If I want to use @foo, @run, @rerun (already initiated) in #test_rerun,
what should I do?

Or, is there any convention something like, #setup_run (would be used by
only #test_run) or #setup_rerun (would be used by only #test_rerun)

Henrik, Thanks for you reply.

···

On Mon, 2004-11-15 at 10:55, Henrik Horneber wrote:

--
Mohammad

outputs:

>ruby test_setup.rb
Loaded suite test_setup
Started
in setup
.in setup
.
Finished in 0.0 seconds.

2 tests, 2 assertions, 0 failures, 0 errors
>Exit code: 0

Does that answer your question? :slight_smile:

regards,
Henrik

Brian,

It didn't work.

[mkhan@localhost temp]$ cat a.rb
#!/usr/bin/env ruby

require 'test/unit'

class TestClass < Test::Unit::TestCase

        def initialize
                super
                puts "in setup"
        end

        def test_run
                assert_equal(true, true)
        end

        def test_rerun
                assert_equal(true, true)
        end

        def test_rererun
                assert_equal(true, true)
        end

end
[mkhan@localhost temp]$ ruby a.rb
/usr/local/lib/ruby/1.8/test/unit/testcase.rb:51:in `initialize': wrong
number of arguments(1 for 0) (ArgumentError)
        from /usr/local/lib/ruby/1.8/test/unit/testcase.rb:51:in `new'
        from /usr/local/lib/ruby/1.8/test/unit/testcase.rb:51:in `suite'
        from /usr/local/lib/ruby/1.8/test/unit/testcase.rb:50:in `catch'
        from /usr/local/lib/ruby/1.8/test/unit/testcase.rb:50:in `suite'
        from /usr/local/lib/ruby/1.8/test/unit/testcase.rb:48:in `each'
        from /usr/local/lib/ruby/1.8/test/unit/testcase.rb:48:in `suite'
        from
/usr/local/lib/ruby/1.8/test/unit/collector/objectspace.rb:25:in
`collect'
        from
/usr/local/lib/ruby/1.8/test/unit/collector/objectspace.rb:23:in
`each_object'
        from
/usr/local/lib/ruby/1.8/test/unit/collector/objectspace.rb:23:in
`collect'
        from /usr/local/lib/ruby/1.8/test/unit/autorunner.rb:52
        from /usr/local/lib/ruby/1.8/test/unit/autorunner.rb:48:in `'
        from /usr/local/lib/ruby/1.8/test/unit/autorunner.rb:183:in
`run'
        from /usr/local/lib/ruby/1.8/test/unit/autorunner.rb:13:in `run'
        from /usr/local/lib/ruby/1.8/test/unit.rb:275
        from /usr/local/lib/ruby/1.8/test/unit.rb:275

···

On Mon, 2004-11-15 at 12:08, Brian Schröder wrote:

On Tue, 16 Nov 2004 00:36:25 +0900 > Mohammad Khan <mkhan@lextranet.com> wrote:

> Hello,
>
> I am using Test::Unit for couple of days.
>
> I have a script something like this:
>
> class TestClass < Test::Unit::TestCase
>
> def setup
> @foo = Foo.new
> @run = Foo.run(@foo.key)
> @rerun = Foo.rerun(@run.key)
> end
>
> def test_run
> assert_equal(@foo.key, @run.key)
> end
>
> def test_rerun
> assert_equal(@run.key, @rerun.key)
> end
>
> end

--
Mohammad

If you want to setup the variables once for the test case, you should use:

class TestClass < Test::Unit::TestCase
  def initialize
    super
    @foo = Foo.new
    @run = Foo.run(@foo.key)
    @rerun = Foo.rerun(@run.key)
  end

   def test_run
      assert_equal(@foo.key, @run.key)
   end

   def test_rerun
      assert_equal(@run.key, @rerun.key)
   end
end

Would fill each variable only once.

Regards,

Brian

--

[mkhan@localhost local]$ rm -Rf /bin/laden

That actually doesn't work, because the test class is instantiated once for each run. One way to solve this is like so:

   class TestClass < Test::Unit::TestCase
     @@foo = Foo.new
     @@run = Foo.run(@@foo.key)
     @@rerun = Foo.rerun(@run.key

     def test_run
       assert_equal(@@foo.key, @@run.key)
     end

     def test_rerun
       assert_equal(@run.key, @rerun.key)
     end
   end

Now, while I won't claim there's never a reason to do this, it seems like a major code smell to me. Might be time to break out the air freshener :slight_smile:

HTH,

Nathaniel
Terralien, Inc.

<:((><

···

On Nov 15, 2004, at 12:08, Brian Schröder wrote:

If you want to setup the variables once for the test case, you should use:

class TestClass < Test::Unit::TestCase
  def initialize
    super
    @foo = Foo.new
    @run = Foo.run(@foo.key)
    @rerun = Foo.rerun(@run.key)
  end

   def test_run
      assert_equal(@foo.key, @run.key)
   end

   def test_rerun
      assert_equal(@run.key, @rerun.key)
   end
end

Would fill each variable only once.

I tried out Gush (for OS X, I think it's mostly the same thing) and didn't like it either. Its polling model is quite interesting, though: It opens a Jabber connection to the PubSub server so it receives updates from PubSub instead of asking for them periodically. Bob Wyman (PubSub CTO, also I know him since he sits on the board of the non-profit I work at) writes about this issue quite a lot on his own blog. POP clients get updates every few minutes, and we should be able to get the same update rate with feeds like RSS and Atom.

F.

···

On Nov 13, 2004, at 2:06 AM, Curt Hibbs wrote:

Well... I didn't really like Gush all that much, so I just uninstalled it.
My favorite reader for Windows is still RSS Bandit
(RSS Bandit).

Curt