Randy W. Sims wrote: > Florian Gross wrote: >> 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. This sounds like a quite good idea -- currently the setup needs to be done in the example -- this is okay for most cases, but you don't want to set up a new instance in every piece of sample code for Classes that need other resources to be instantiated. If support for this were to be added to RDoc it would be nice if there were some kind of marker like "[Setup code hidden]" that could be clicked to blend in the rest of the code. I think I've seen something similar used in an online Ruby book already. Can you think of a way to do this that would not need changes of the RDoc Ruby code parser? I'll be willing to add support to test-extract, but I think it is useless when the syntax doesn't work with RDoc. (If we can't find a way to hide the setup code from RDoc we could maybe make the syntax self-explanatory so that it can be understood even without knowing about it.) > 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. This is possible already: (Sorry for the long sample.) # Causes a pattern which would otherwise match # greedily to match non-greedily. # # This can only be applied to #count and #optional # based constructs. # # re_greedy = Regexp::English.new do # literal("<") + something + literal(">") # end # re_non_greedy = Regexp::English.new do # literal("<") + something.minimal + literal(">") # end # str = "<html><body>" # re_greedy.match(str)[0] # => "<html><body>" # re_non_greedy.match(str)[0] # => "<html>" # # This method will do nothing when applied to a Node # which is already minimal: # # re_minimal = Regexp::English.something.minimal # re_minimal.minimal == re_minimal # => true # # However, it will raise a NameError Exception when # you try to call it on a Regexp Node that can't be # made non-greedy: # # re = Regexp::English.literal("foo") # re.minimal # raises NameError def minimal if self.is_a?(Repeat) if self.minimal_flag return self else result = self.clone result.minimal_flag = true return result end else raise(NameError, "Can't apply minimal") end end You can use the following notations: # obj.method # raises Exception # obj.method # raise Exception # obj.method # ~> Exception I think the first one is the most clear one. Another notation that I might add in the future is this one: # puts "foo" # outputs "foo" or maybe: # puts "foo" # outputs foo I'm not sure about it yet and it will need a bit more work than the other specification methods, but I think it can be quite useful. Thanks a lot for giving me feedback on this. It would be great if sample code as test cases would be commonly adapted. Regards, Florian Gross