documentation as source

T

trans. (T. Onoma)

|
| class Adder
| include Testing
|
| # Adds two numbers
| example { assert_equal(2, Adder.new.add(1, 1)) }
| def add(a, b)
| a + b
| end
| end

Well, I say, I like the general idea of sub('::', '/') and all --making
testing a dialect, if you will. But I can't say that I would want to use the
above b/c

1. Adds a performance hit (albeit small).
2. Detracts from the code itself.
3. Not really an example, but a test.
4. There can be tens to hundreds of tests.
5. How does it know that example goes to that method,
other then occurring before it.
6. I would prefer to see improvement in test
"comprehension" over other changes.

To offer some contrast, here's is a sample concept inspired a bit by my AOP
work.

class Adder
# Adds two numbers
def add(a, b)
a + b
end
end

class Testing::Adder < Adder
def add
assert("add failure") { _equal 2, super(1, 1) }
end
end

Notice I did not have to specify 'include Testing'. It may be able to be can
be automatically included "behind the scenes" simply be using the Testing::
namespace.

It's not dialectic, but it does integrate better while still allowing good
SOC.

Just some thoughts,
T.
 
G

gabriele renzi

trans. (T. Onoma) ha scritto:

<snip>

this is interesting, but still requires a lot of typing from you.
I'd prefer florian gross' approach to extract data from embedded
comments. No performance hit, real samples, no extraneous code.
Ok we'd have to admit that python got his doctest module before us but,
hey not too bad :)
 
N

Nathaniel Talbott

|
| class Adder
| include Testing
|
| # Adds two numbers
| example { assert_equal(2, Adder.new.add(1, 1)) }
| def add(a, b)
| a + b
| end
| end

Well, I say, I like the general idea of sub('::', '/') and all --making
testing a dialect, if you will. But I can't say that I would want to
use the
above b/c

1. Adds a performance hit (albeit small).

Yup. It's miniscule, and I just don't care. If you do, you don't have
to eat my sandwich ;-)

2. Detracts from the code itself.
Why?


3. Not really an example, but a test.

But many tests are great examples, and I want to leverage that. And all
examples should be tests, because then you're sure they actually work.

4. There can be tens to hundreds of tests.

I should clarify: the bulk of tests will be elsewhere. This is
specifically for basic examples of tests, not full regression suites.

5. How does it know that example goes to that method,
other then occurring before it.

That's exactly how it knows. Any examples before a given method would
be assumed to correspond to that method, just as any comments before a
method are assumed (by RDoc) to correspond to that method.

6. I would prefer to see improvement in test
"comprehension" over other changes.

Not sure what you mean... care to elaborate?

To offer some contrast, here's is a sample concept inspired a bit by
my AOP
work.

class Adder
# Adds two numbers
def add(a, b)
a + b
end
end

class Testing::Adder < Adder
def add
assert("add failure") { _equal 2, super(1, 1) }
end
end

Notice I did not have to specify 'include Testing'. It may be able to
be can
be automatically included "behind the scenes" simply be using the
Testing::
namespace.

It's not dialectic, but it does integrate better while still allowing
good
SOC.

I guess I don't see any advantages of this over:

class AdderTest < Test::Unit::TestCase
def test_add
assert_equal(2, Adder.new.add(1, 1))
end
end

Besides the fact that the latter seems to be much more intention
revealing. Or perhaps even better:

suite "Adder" do
test :add do
assert_equal(2, Adder.new.add(1, 1))
end
end

Which is probably how you'd do it in test/unit2.


Nathaniel
Terralien, Inc.

<:((><
 
N

Nathaniel Talbott

this is interesting, but still requires a lot of typing from you.
I'd prefer florian gross' approach to extract data from embedded
comments. No performance hit, real samples, no extraneous code.

Florian's approach definitely has advantages... the one killer
advantage to me of the direction I'm taking is its simplicity on the
testing framework side. Parsing Ruby code is not something I want to do
in test/unit, so I'm going with an approach that doesn't require it. Of
course I'll have to parse some stuff in RDoc to get it integrated with
the documentation, but RDoc already does Ruby parsing.

Of course, I'll stop no one from using Florian's library... I think
it's a great idea that can peacefully coexist with test/unit2.

Thanks for the feedback,


Nathaniel
Terralien, Inc.

<:((><
 
T

trans. (T. Onoma)

On Friday 15 October 2004 06:59 am, gabriele renzi wrote:
| this is interesting, but still requires a lot of typing from you.
| I'd prefer florian gross' approach to extract data from embedded
| comments. No performance hit, real samples, no extraneous code.
| Ok we'd have to admit that python got his doctest module before us but,
| hey not too bad :)

I have three issues with using comments in this way.

1. Comments take on meaning. Comments with syntax errors? Ick.
2. Tests can be HUGE. Explanation comments already take up enough space.
3. SOC is important too.

T.
 
E

Eivind Eklund

|
| class Adder
| include Testing
|
| # Adds two numbers
| example { assert_equal(2, Adder.new.add(1, 1)) }
| def add(a, b)
| a + b
| end
| end [...]
2. Detracts from the code itself.

Why?

I'll take this one.

For me:
* My brain is conditioned to automatically "ignore" lines that start
with # - they're there as documentation, but they are very clearly
separate from code
* They're automatically highlighted "away" in my editor.

So far, I prefer Florian's approach - however, it may be this works
out OK in a highlighting editor (because def gets highlighted). In
black and white, Florian's is much easier to read, and less overhead,
though.

Eivind.
 
G

gabriele renzi

trans. (T. Onoma) ha scritto:
On Friday 15 October 2004 06:59 am, gabriele renzi wrote:
| this is interesting, but still requires a lot of typing from you.
| I'd prefer florian gross' approach to extract data from embedded
| comments. No performance hit, real samples, no extraneous code.
| Ok we'd have to admit that python got his doctest module before us but,
| hey not too bad :)

I have three issues with using comments in this way.

1. Comments take on meaning. Comments with syntax errors? Ick.

don't you expect to have correct samples and comments?
2. Tests can be HUGE. Explanation comments already take up enough space.

sure, I think just some of them would be put in as comments
3. SOC is important too.

Separation Of Concerns? Samples Only Code? Save Our Code?
Sorry, but I'm dumb and dunno what you mean :)
 
N

Nathaniel Talbott

For me:
* My brain is conditioned to automatically "ignore" lines that start
with # - they're there as documentation, but they are very clearly
separate from code
* They're automatically highlighted "away" in my editor.

Certainly possible complaints... but not enough to dissuade me from my
course. I personally look forward to people being able to use these,
because maybe more folks that are disinclined to write comments for
their libraries will at least plunk some examples in to them. I
personally would prefer a bit of working code over a comment that might
or might not describe the method's behavior well. Also, it might help
our Japanese friends to provide us with better documentation, since it
could all be written in Ruby :)

So far, I prefer Florian's approach - however, it may be this works
out OK in a highlighting editor (because def gets highlighted). In
black and white, Florian's is much easier to read, and less overhead,
though.

I think that if folks did use this a lot, we would quickly learn to
recognize it just like we recognize all the other things one can do
dynamically in the class definition.

And for those that would prefer to do it in the inverse manner
(comments becoming tests), they're certainly welcome to use Florian's
library. Hopefully it will be even easier in test/unit2 for him to
build the tests out of the comments.


Nathaniel
Terralien, Inc.

<:((><
 
N

Nathaniel Talbott

trans. (T. Onoma) ha scritto:


don't you expect to have correct samples and comments?

This is the key thing for me. Anything that helps us (automatically)
keep code and documentation in sync is a good thing. Also, anything
that lets us leverage code to automatically create documentation is a
good thing, too (this is why RDoc is so cool).

Separation Of Concerns? Samples Only Code? Save Our Code?
Sorry, but I'm dumb and dunno what you mean :)

Yah, I haven't figured this out, either. Sign Our Camel?


Nathaniel
Terralien, Inc.

<:((><
 
T

trans. (T. Onoma)

42, trans. (T. Onoma) wrote:
| > On Wednesday 13 October 2004 09:19 pm, Nathaniel Talbott wrote:
| > | Well, the current plan is to let you to do something like this:
| > |
| > | class Adder
| > | include Testing
| > |
| > | # Adds two numbers
| > | example { assert_equal(2, Adder.new.add(1, 1)) }
| > | def add(a, b)
| > | a + b
| > | end
| > | end
| >
| > Well, I say, I like the general idea of sub('::', '/') and all --making
| > testing a dialect, if you will. But I can't say that I would want to
| > use the
| > above b/c
| >
| > 1. Adds a performance hit (albeit small).
|
| Yup. It's miniscule, and I just don't care. If you do, you don't have
| to eat my sandwich ;-)

Unfortunately this is very much a case where I DO have to eat your sandwich. I
mean really, who is the example for? --Other people.

| > 2. Detracts from the code itself.
|
| Why?

Well one isn't a big deal. But a few or more, the code itself begins to get a
bit lost.

| > 3. Not really an example, but a test.
|
| But many tests are great examples, and I want to leverage that. And all
| examples should be tests, because then you're sure they actually work.

Sure, but it doesn't _look_ like a real example. I may be wrong but it seems
to me that the format of these will be structured for testing rather then
looking at them to understand their general usage. In other words testing and
examples can differ. For instance, you may have a method that is only meant
for use in a particular context. An example would provide a mock context, but
a test might not have the resources available to build an actual context.

| > 4. There can be tens to hundreds of tests.
|
| I should clarify: the bulk of tests will be elsewhere. This is
| specifically for basic examples of tests, not full regression suites.

Okay, that helps _a lot_. But b/c of this, I suspect that the above notation
will get little play. It won't be enough for solid testing, and it will be
too little for effective examples in RDoc. Of course, that's just my hunch, I
may be wrong.

| > 5. How does it know that example goes to that method,
| > other then occurring before it.
|
| That's exactly how it knows. Any examples before a given method would
| be assumed to correspond to that method, just as any comments before a
| method are assumed (by RDoc) to correspond to that method.

So the test suites do not use example { ... }. Okay.

| > 6. I would prefer to see improvement in test
| > "comprehension" over other changes.
|
| Not sure what you mean... care to elaborate?

Not that this is an easy thing to do mind you, but what I mean is making the
test system more intelligent. Might the test suite actually parse the code
itself? Look for potential errors in a deeper way then the Ruby interpretor?
Perhaps a method probe, even if it's not perfect, might be useful? I think I
read something about Mock object builder coming? Stuff like that. That's part
of the reason I was suggesting that a test (at least most tests) can be a
subclass of the actual class it's testing, hence being on the "inside" of
their objective. Perhaps that's not really useful, I'm just pushing in the
direction of the test "knowing" more about what it is actually trying to do
and therefore being able to do more of it on it's own --that's essentially
what I mean by comprehension.

| [snip my example]
|
| I guess I don't see any advantages of this over:
|
| class AdderTest < Test::Unit::TestCase
| def test_add
| assert_equal(2, Adder.new.add(1, 1))
| end
| end
|
| Besides the fact that the latter seems to be much more intention
| revealing. Or perhaps even better:
|
| suite "Adder" do
| test :add do
| assert_equal(2, Adder.new.add(1, 1))
| end
| end
|
| Which is probably how you'd do it in test/unit2.

Right, but my example does have an interesting potential advantage. The test
method is closer to --nearly inside of, the method it is testing. One could
do this for instance:

class Testing::Adder < Adder
def add(*args)
assert("add failure") { _equal 2, super(1, 1) }
super(*args)
end
end

Then have a moster control to have test classes sub in for regular classes,
and you could run the test suite through a real case scenario, while testing
at the same time. Of course not situations would be suitabel for this. But
like I said, I'm just pushing the limits in a general direction here to what
might come up.

It we got further into AOP-land there are other interesting things one might
do (like check local vars in mid execution). But since I (and partners) are
not finished our "AOP for Ruby" project yet, I hesitate to speculate further
at this time.

I'm not sure what kind of time track you're shooting for, so maybe this kind
of stuff is really the domain of _consideration_ for version 3, not 2.

T.
 
T

trans. (T. Onoma)

19, gabriele renzi wrote:
| > trans. (T. Onoma) ha scritto:
| >> I have three issues with using comments in this way.
| >> 1. Comments take on meaning. Comments with syntax errors? Ick.
| >
| > don't you expect to have correct samples and comments?
|
| This is the key thing for me. Anything that helps us (automatically)
| keep code and documentation in sync is a good thing. Also, anything
| that lets us leverage code to automatically create documentation is a
| good thing, too (this is why RDoc is so cool).
|
| >> 3. SOC is important too.
| >
| > Separation Of Concerns? Samples Only Code? Save Our Code?
| > Sorry, but I'm dumb and dunno what you mean :)
|
| Yah, I haven't figured this out, either. Sign Our Camel?

:) Lol. Funny guesses.

Sorry,

SOC == Separation Of Concern

But you answered my `concern` (about that) already ;)

T.
 
E

Eivind Eklund

Certainly possible complaints... but not enough to dissuade me from my
course. I personally look forward to people being able to use these,
because maybe more folks that are disinclined to write comments for
their libraries will at least plunk some examples in to them.

The _maybe_ is the important part of this sentence, I think.

And the same may be true of Florian's approach if made more easily
available (those comments could also be parsed out by Test::Unit
automatically...)
I think that if folks did use this a lot, we would quickly learn to
recognize it just like we recognize all the other things one can do
dynamically in the class definition.

Ah, you hit a nail on the head. Maybe a different one than you were
aiming for, though ;-)

These declarations are presently ugly to me. I think they're
presently ugly to a lot of other people, too. They may not be ugly
once I've become accustomed to them - but they will mean that Ruby
with them would be ugly to newcomers.

I also think the feeling of the declarations being ugly will result in
the Ruby community not adopting them.

Could people (excepting Nathaniel) that is likely to use the proposed
syntax please speak up? (If there's a lot of people that would use
it, I'm probably wrong.)

Eivind.
 
M

Massimiliano Mirra - bard

Eivind Eklund said:
Could people (excepting Nathaniel) that is likely to use the proposed
syntax please speak up? (If there's a lot of people that would use
it, I'm probably wrong.)

I'm for any syntax that favours a quick code-test-code cycle.

With `quick' I don't mean `edit test file, save test file, switch to
class file, edit class file, save test file, switch to shell, run
tests', and an `extract parts of the test file' somewhere in between
certainly doesn't make it quicker.

By `quick' I mean `edit test part, edit class part, run tests'.
Currently I do this by writing tests at the end of a class file,
wrapped in a:

if __FILE__ == $0 or (defined? $TESTING and $TESTING == true)
require "test/unit"
...
end

Just hitting C-c-c in Emacs at any given time will run the current
class's tests.

Back in August (<[email protected]>) I tried something
similar to what Nathaniel proposes, so it's no surprise that I favour
his approach. :)

Massimiliano
 
R

Richard Kilmer

I would use the syntax that Nathaniel is proposing...I would very much
welcome it, and I have written and have in production a LARGE body of Ruby
code.

-rich
 
M

Mauricio Fernández

I'm for any syntax that favours a quick code-test-code cycle.

With `quick' I don't mean `edit test file, save test file, switch to
class file, edit class file, save test file, switch to shell, run
tests', and an `extract parts of the test file' somewhere in between
certainly doesn't make it quicker.

That's not really the case because...
By `quick' I mean `edit test part, edit class part, run tests'.
Currently I do this by writing tests at the end of a class file,
wrapped in a:

if __FILE__ == $0 or (defined? $TESTING and $TESTING == true)
require "test/unit"
require "text-extract"
Extracter.process(__FILE__)
...
end

Just hitting C-c-c in Emacs at any given time will run the current
class's tests.

And it really is quicker *g*, for the code examples will not be parsed
normally.
 
R

Randy W. Sims

Florian said:
Bil said:
require 'test/unit'

Then code test-first and you'll have executable documentation.


I've coded up test-extract which lets you embed some of your test-cases
cloaked as sample code into your RDoc strings.

It looks like this in practice:
# Creates a Regexp which matches a literal string. In this
# string any special regular expression meta-characters will
# be escaped automatically.
#
# # This creates a Regexp which will match 3 "foo"s.
# re = Regexp::English.literal("foo" * 3)
# re.match("foofoofoo")[0] # => "foofoofoo"
def literal(text); Node::Literal.new(text); end


(Sample from Regexp::English)

I very much like the idea of being able to test examples embedded in the
source file's documentation. A couple of suggestions:

1. Is there some way to allow set-up code that is not part of the
viewable documentation? This would make for clearer examples. Eg. the
above might be changed to something like:

#--
# Init:
# foo = Foo.new(blah, blah);
#++
#
# An example of using Foo.bar()
#
# foo.bar(blek)

def bar(); ...

Well, that's not real pretty, but... the idea is that the example is
more focused for documentation purposes, and all the setup-code is
hidden away.

2. In addition to showing how something works, it is sometimes
instructive to show what doesn't work. Being able to create examples
that are expected to fail would be useful.

Randy.
 
E

Eivind Eklund

I'm for any syntax that favours a quick code-test-code cycle.

With `quick' I don't mean `edit test file, save test file, switch to
class file, edit class file, save test file, switch to shell, run
tests', and an `extract parts of the test file' somewhere in between
certainly doesn't make it quicker.

Are you by this saying you are going to abuse Nathaniel's syntax to
group as many of your tests there as you can?

I also liked your proposed syntax much better than Nathaniel's. You
limited your syntax to only support a single true/false check per
example. This avoids the problem of people putting entire tests in
the example (that should go in the test cases), and it makes the
examples much more readable.

I don't believe the readability of assert_equal and friends will go to
the same level as an infix operator (which both you and Florian used)
with "getting used to the syntax". If it did, we'd all be programming
in Lisp (and Paul Graham wouldn't say that "prefix operators for maths
still feels weird after 20 years of programming Lisp").

WRT the speed issue: I think this is easily resolvable by using a hack
over require and a cache, to make the scanning incremental. Doing the
scanning manually each time is certainly not a permanent solution.

Richard: Why do you prefer Nathaniel's syntax over Florian's?

Eivind.
 
E

Eivind Eklund

Can someone compare/contrast an example of each for the same scenario?

Sure. From a practical use of Florian's code (his sample from Regexp::English):

# Creates a Regexp which matches a literal string. In this
# string any special regular expression meta-characters will
# be escaped automatically.
#
# # This creates a Regexp which will match 3 "foo"s.
# re = Regexp::English.literal("foo" * 3)
# re.match("foofoofoo")[0] # => "foofoofoo"
def literal(text); Node::Literal.new(text); end

Translated to Nathaniel's syntax:

# Creates a Regexp which matches a literal string. In this
# string any special regular expression meta-characters will
# be escaped automatically.
example do
# This creates a Regexp which will match 3 "foo"s.
re = Regexp::English.literal("foo" * 3)
assert_equal("foofoofoo", re.match("foofoofoo")[0])
end
def literal(text); Node::Literal.new(text); end

Note that this will also presently break rdoc, though there is an
intention of later adding rdoc support. To avoid breaking with rdoc
presently, you'd need to move the example BEFORE the comment.

Eivind.
 
P

Peter Hickman

Eivind said:
From a practical use of Florian's code (his sample from Regexp::English):

# Creates a Regexp which matches a literal string. In this
# string any special regular expression meta-characters will
# be escaped automatically.
#
# # This creates a Regexp which will match 3 "foo"s.
# re = Regexp::English.literal("foo" * 3)
# re.match("foofoofoo")[0] # => "foofoofoo"
def literal(text); Node::Literal.new(text); end

Translated to Nathaniel's syntax:

# Creates a Regexp which matches a literal string. In this
# string any special regular expression meta-characters will
# be escaped automatically.
example do
# This creates a Regexp which will match 3 "foo"s.
re = Regexp::English.literal("foo" * 3)
assert_equal("foofoofoo", re.match("foofoofoo")[0])
end
def literal(text); Node::Literal.new(text); end

Note that this will also presently break rdoc, though there is an
intention of later adding rdoc support. To avoid breaking with rdoc
presently, you'd need to move the example BEFORE the comment.
If this were a voting thing I would go for Nathaniel's syntax as
Florian's looks like it is commented out and should not be run. Besides
how would you comment out something in Florian's syntax. I think
Nathaniel's is much more obvious.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,160
Messages
2,570,889
Members
47,420
Latest member
ZitaVos505

Latest Threads

Top