Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Bread-Board CPAN distribution.

Report information
The Basics
Id: 77229
Status: rejected
Priority: 0/
Queue: Bread-Board

People
Owner: Nobody in particular
Requestors: xenoterracide [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: params available to all objects, not just the requested
Date: Tue, 15 May 2012 17:50:28 -0500
To: bugs-bread-board [...] rt.cpan.org
From: Caleb Cushing <xenoterracide [...] gmail.com>
The general problem is that I need to pass a parameter to an object, that is a dependency of the one I'm requesting, and in fact it's several layers below. http://stackoverflow.com/questions/9917576/default-replacable-values-in-breadboard an example of this problem is my Business::CyberSource module which I'm starting to use BB to reduce my test boilerplate. I want to BB Authorization Responses. CyberSource uses predefined total values to allow you to send tests which will give you different responses. It'd be nice if parameters could either A) be available to every single service/container, or B I could have a way to say, this parameter is for this service. Maybe $c->resolve( service => '/response/authorization', parameters => { '/request/total' =>{ total => 3000.37 } } ); # this particular total will make the request return a REJECT due to expired credit card, irregardless of whether the card actually has an expired date. This code would only require me to have a parameter in total, that could have a default and I'd be ok with it being a block, but things that depend on it could still be a class. ... here's my code as it stands today so you can get an idea of what I'm talking about, currently it doesn't pass any parameters at all, because it was easier for me to leave the existing authorization that I'd created in my tests than try passing the parameter from block to block. package Test::Business::CyberSource; use Moose; use Bread::Board; extends 'Bread::Board::Container'; sub BUILD { my $self = shift; return container $self => as { container client => as { service username => "$ENV{PERL_BUSINESS_CYBERSOURCE_USERNAME}"; service password => "$ENV{PERL_BUSINESS_CYBERSOURCE_PASSWORD}"; service production => 0; service object => ( class => 'Business::CyberSource::Client', lifecycle => 'Singleton', dependencies => { username => depends_on('username'), password => depends_on('password'), production => depends_on('production'), }, ); }; container credit_card => as { service holder => 'Caleb Cushing'; service expiration => ( block => sub { return { month => 5, year => 2025 } }, ); service security_code => '1111'; service visa_test_number => '4111-1111-1111-1111'; service visa => ( class => 'Business::CyberSource::CreditCard', lifecycle => 'Singleton', dependencies => { account_number => depends_on('visa_test_number'), expiration => depends_on('expiration'), security_code => depends_on('security_code'), holder => depends_on('holder'), }, ); }; container request => as { service reference_code => ( lifecycle => 'Singleton', block => sub { return 'test-' . time }, ); service first_name => 'Caleb'; service last_name => 'Cushing'; service street => 'somewhere'; service city => 'Houston'; service state => 'TX'; service postal_code => '77064'; service country => 'USA'; service email => 'xenoterracide@gmail.com'; service ip_address => '192.168.100.2'; service total => 5.00; service currency => 'USD'; container authorization => as { service visa => ( class => 'Business::CyberSource::Request::Authorization', dependencies => { card => depends_on('/credit_card/visa'), reference_code => depends_on('../reference_code'), first_name => depends_on('../first_name'), last_name => depends_on('../last_name'), street => depends_on('../street'), city => depends_on('../city'), state => depends_on('../state'), postal_code => depends_on('../postal_code'), country => depends_on('../country'), email => depends_on('../email'), ip_address => depends_on('../ip_address'), total => depends_on('../total'), currency => depends_on('../currency'), }, ); }; }; container response => as { container authorization => as { service visa => ( block => sub { my $s = shift; return $s ->param('client') ->run_transaction( $s->param('auth') ); }, dependencies => { client => depends_on('/client/object'), auth => depends_on('/request/authorization/visa'), }, ); }; }; }; } has '+name' => ( default => sub { __PACKAGE__ }, ); __PACKAGE__->meta->make_immutable; 1; -- Caleb Cushing http://xenoterracide.com
Subject: Re: [rt.cpan.org #77229] params available to all objects, not just the requested
Date: Tue, 15 May 2012 19:41:00 -0400
To: bug-Bread-Board [...] rt.cpan.org
From: Stevan Little <stevan.little [...] iinteractive.com>
Caleb, So I see where you are going on this one, but I think the flaw in your design is in the response/authorization/visa service. You should not be doing the run_transaction inside of Bread::Board, that is application level code. This is sometimes one of the confusion points with Bread::Board, exactly where to draw the line. The key goal of Bread::Board, and of most IoC/DI frameworks, is to construct your objects. One of my favorite descriptions of this was that DI is like "the inverse of garbage collection". So, that said, I suggest you move the response/authorization/visa code into your application/tests and not try and do that in Bread::Board. If you do that, then your issue kind of disappears. Additionally, a few tricks I have learned. - You can add defaults to parameters (they accept the exact same form that MooseX::Params::Validate accepts), this would allow you to put in defaults, but make it possible to specify them when you need them. - You can have something be an optional parameter AND be a dependency. The result of this will be that if the parameter is specified then it will use that, otherwise it will use the dependency. This is basically another way to get the default, but honestly, it is kinda a hack and leads to some level of duplication in your parameters and dependencies. - You can pass parameters down to a lower level statically, here is an example: https://www.metacpan.org/source/STEVAN/Bread-Board-0.25/t/045_parameters_in_dependency.t this fixes the values passed in by parameter, which may or may not be helpful to you. Not sure how much any of those tricks would help you, but I think that changing your test code from: $c->resolve( service => '/response/authorization/visa' ); to: $c->resolve( service => '/client/object' )->run_transaction( $c->resolve( service => '/request/authorization/visa', parameters => { total => 500.00 } ) ); will not be too much additional boilerplate in comparison to the flexibility it will give you. NOTE: all this said, if you want to make deep parameter stuff, I would take a patch that supports something like: $c->resolve( service => '/response/authorization/visa', parameters => { '/request/authorization/visa/total' => 500.00 } ); Although I am not sure this will be possible giving the build order, but hey, you are welcome to try. Thanks, - Stevan On May 15, 2012, at 6:50 PM, Caleb Cushing via RT wrote: Show quoted text
> Tue May 15 18:50:43 2012: Request 77229 was acted upon. > Transaction: Ticket created by XENO > Queue: Bread-Board > Subject: params available to all objects, not just the requested > Broken in: (no value) > Severity: (no value) > Owner: Nobody > Requestors: xenoterracide@gmail.com > Status: new > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=77229 > > > > The general problem is that I need to pass a parameter to an object, > that is a dependency of the one I'm requesting, and in fact it's > several layers below. > > http://stackoverflow.com/questions/9917576/default-replacable-values-in-breadboard > > an example of this problem is my Business::CyberSource module which > I'm starting to use BB to reduce my test boilerplate. I want to BB > Authorization Responses. CyberSource uses predefined total values to > allow you to send tests which will give you different responses. > > > It'd be nice if parameters could either A) be available to every > single service/container, or B I could have a way to say, this > parameter is for this service. Maybe > > $c->resolve( service => '/response/authorization', parameters => { > '/request/total' =>{ total => 3000.37 } } ); # this particular total > will make the request return a REJECT due to expired credit card, > irregardless of whether the card actually has an expired date. This > code would only require me to have a parameter in total, that could > have a default and I'd be ok with it being a block, but things that > depend on it could still be a class. > > ... here's my code as it stands today so you can get an idea of what > I'm talking about, currently it doesn't pass any parameters at all, > because it was easier for me to leave the existing authorization that > I'd created in my tests than try passing the parameter from block to > block. > > package Test::Business::CyberSource; > use Moose; > use Bread::Board; > > extends 'Bread::Board::Container'; > > sub BUILD { > my $self = shift; > return container $self => as { > container client => as { > service username => "$ENV{PERL_BUSINESS_CYBERSOURCE_USERNAME}"; > service password => "$ENV{PERL_BUSINESS_CYBERSOURCE_PASSWORD}"; > service production => 0; > service object => ( > class => 'Business::CyberSource::Client', > lifecycle => 'Singleton', > dependencies => { > username => depends_on('username'), > password => depends_on('password'), > production => depends_on('production'), > }, > ); > }; > > container credit_card => as { > service holder => 'Caleb Cushing'; > service expiration => ( > block => sub { return { month => 5, year => 2025 } }, > ); > service security_code => '1111'; > service visa_test_number => '4111-1111-1111-1111'; > service visa => ( > class => 'Business::CyberSource::CreditCard', > lifecycle => 'Singleton', > dependencies => { > account_number => depends_on('visa_test_number'), > expiration => depends_on('expiration'), > security_code => depends_on('security_code'), > holder => depends_on('holder'), > }, > ); > }; > > container request => as { > service reference_code => ( > lifecycle => 'Singleton', > block => sub { return 'test-' . time }, > ); > service first_name => 'Caleb'; > service last_name => 'Cushing'; > service street => 'somewhere'; > service city => 'Houston'; > service state => 'TX'; > service postal_code => '77064'; > service country => 'USA'; > service email => 'xenoterracide@gmail.com'; > service ip_address => '192.168.100.2'; > service total => 5.00; > service currency => 'USD'; > container authorization => as { > service visa => ( > class => 'Business::CyberSource::Request::Authorization', > dependencies => { > card => depends_on('/credit_card/visa'), > reference_code => depends_on('../reference_code'), > first_name => depends_on('../first_name'), > last_name => depends_on('../last_name'), > street => depends_on('../street'), > city => depends_on('../city'), > state => depends_on('../state'), > postal_code => depends_on('../postal_code'), > country => depends_on('../country'), > email => depends_on('../email'), > ip_address => depends_on('../ip_address'), > total => depends_on('../total'), > currency => depends_on('../currency'), > }, > ); > }; > }; > > container response => as { > container authorization => as { > service visa => ( > block => sub { > my $s = shift; > > return $s > ->param('client') > ->run_transaction( $s->param('auth') ); > }, > dependencies => { > client => depends_on('/client/object'), > auth => depends_on('/request/authorization/visa'), > }, > ); > }; > }; > }; > } > > has '+name' => ( default => sub { __PACKAGE__ }, ); > > __PACKAGE__->meta->make_immutable; > 1; > > -- > Caleb Cushing > > http://xenoterracide.com >
I think this can be closed.