pdl / Test-Proto

OO test script golf sugar
1 stars 1 forks source link

Have one function for construction. #28

Open schwern opened 11 years ago

schwern commented 11 years ago

I have an idea, rather than have one function for each type of Test::Proto object, how about have one function which returns an object which you can ask for the appropriate test object?

proto->String->is_like(...);

This makes the interface simpler, it doesn't pollute the user's namespace with a dozen little functions, and it lets Test::Proto export the one function by default.

pdl commented 11 years ago

Good point! I'll think about what makes sense.

The exact implementation depends on whether I end up create one class for all prototypes and then import methods (or preferably roles) at runtime, or whether I have a few general subclasses (Hashref, Arrayref, Scalar) and the rest are roles, etc.

Ideally, I'd also still like to be able to do proto(qr/dwim/).

NB: I'm rewriting as Test::Proto::Base2 in the Moo branch.

schwern commented 11 years ago

I don't think this is something to be done with roles. You're testing different types of data structures and they each require different code. You can't, for example, apply like to an array. You're still going to want HashRef, ArrayRef, String, etc...

However, you can likely get rid of Test::Proto::Base. It can be disintegrated into roles like Test::Proto::DoesClone, DoesOk, DoesFail, DoesException and DoesTry which apply to all the data structure classes. Much of the rest is type specific. is_eq, is_like, _cmp are all String stuff. It may make sense to then rebuild a base class out of the roles which all the data structure classes are expected to have.

pdl commented 11 years ago

Hm, ok, the user story that is in my head looks something like this:

I have an object $obj, and I am validating it against $object_prototype, and I want to see what it does when overloaded as a string. Which is better:

a) $object_prototype->is_like(qr/foo/) b) $object_prototype->String->is_like(qr/foo/) c) $object_prototype->overload('""', proto->String->is_like(qr/foo/) ) d) $object_prototype->is_also( proto->String->is_like(qr/foo/) )

a) implies a base class as now which reports an exception if you try to stringify it. (But fails if you try to use array methods, so this is not a good solution) b) imports the String methods as a role c) creates a subtest by stringifying and validating the result against a completely different prorotype: probably the most dependable but cumbersome to write. d) creates a subtest against a completely different prorotype, but means that proto->Array can't check if it's a real array, only that you can treat it as if it were an array.

schwern commented 11 years ago

Having Test::Proto::Object take in the String role makes sense. In fact, it makes so much sense that Test::Proto::Object might have the String role already. All objects stringify. For the specific case of an object, the A syntax but with the B explanation.

# Get a Test::Proto::Object
my $obj_proto = p->Object;

# Check the type
$obj_proto->is_a("Foo");

# Check stringification (via Test::Proto::String role)
$obj_proto->is_like(qr/bar/);

Since objects also overload, its possible Test::Proto::Object would also have the ArrayRef and HashRef roles... and Number. Hmm, Objects start to get everything. I'd like to avoid the user having to declare what extra types of overload test method they want to add, but it might get ridiculous otherwise. OTOH what's the harm? OT3H what's the value in making the user declare their object has certain types of overloading vs just checking the behavior directly?

pdl commented 11 years ago

Hm, thinking some more I'm pretty sure at some point it will need a ->overload_with($operator, $parameter, $result_prototype) method, but for general use, maybe something more like this: $object_prototype->as_string(p->String->eq('foo'))->ok($object) is good enough?

schwern commented 11 years ago

On 3/5/13 1:31 PM, pdl wrote:

Hm, thinking some more I'm pretty sure at some point it will need a |->overload_with($operator, $parameter, $result_prototype)| method, but for general use, maybe something more like this: |$object_prototype->as_string(p->String->eq('foo'))->ok($object)| is good enough?

What does that buy you over this?

$object_proto->eq('foo')->ok($object);

Why cast it as a string and create a whole new string prototype? We don't do that in Perl, you just use a thing as a string. You might not even know its an object, which is the point.

Is it differently beneficial in testing to add all that verbosity?