problem importing from sub-modules #487

Closed
plugh212 opened this Issue Oct 2, 2013 · 7 comments

Comments

Projects
None yet
5 participants
@plugh212

plugh212 commented Oct 2, 2013

Hello Dancers,

First I'd like to thank the Dancer devel team - great concept, fun to work with.

I started porting a project from Dancer to Dancer2 and ran into this problem:

Odd number of elements in hash assignment at /usr/local/share/perl/Dancer2.pm line 104.

It happens when I import things from a sub-module that also 'use's Dancer2. Here is some test code. First, the script dancer2_test.pl:

!/usr/bin/perl

use Dancer2Sub qw( test );
use Dancer2;
print test(), "\n";

And the sub-module, Dancer2Sub.pm:

package Dancer2Sub;

use parent 'Exporter';
our @EXPORT_OK = qw( test );
use Dancer2;

sub test { 'test'; }
1;

Putting EXPORT_OK inside a BEGIN block doesn't help.

The problem seems to be that _set_import_method_to_caller in Dancer2.pm overwrites Dancer2Sub's normal import method. This makes it difficult to (e.g.) make a function-oriented Utils sub-module that uses Dancer[2]
syntax (params, session, etc).

My environment is

This is perl 5, version 12, subversion 4 (v5.12.4) built for x86_64-linux-thread-multi

running on Fedora release 15 (Lovelock):

Linux tove 2.6.43.8-1.fc15.x86_64 #1 SMP Mon Jun 4 20:33:44 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

and running Dancer2 v0.010 (which, wrt _set_import_method_to_caller, seems to be the same as the latest on GitHub).

Regards,
reid

@jbolila

This comment has been minimized.

Show comment Hide comment
@jbolila

jbolila Nov 2, 2013

The sub test doesn't return a Dancer App. In your example just remove the use Dancer2; from Dancer2Sub.pm.

package Dancer2Sub;                                                                                     
use parent 'Exporter';                                                                                  
our @EXPORT_OK = qw( test );                                                                            

sub test { 'test'; }                                                                                    
1;

and in dancer2_test.pl do something like:

use Dancer2;                                                                                          
use Dancer2Sub qw( test );                                                                         

get '/' => sub { test() };                                                                         

dance;

jbolila commented Nov 2, 2013

The sub test doesn't return a Dancer App. In your example just remove the use Dancer2; from Dancer2Sub.pm.

package Dancer2Sub;                                                                                     
use parent 'Exporter';                                                                                  
our @EXPORT_OK = qw( test );                                                                            

sub test { 'test'; }                                                                                    
1;

and in dancer2_test.pl do something like:

use Dancer2;                                                                                          
use Dancer2Sub qw( test );                                                                         

get '/' => sub { test() };                                                                         

dance;
@plugh212

This comment has been minimized.

Show comment Hide comment
@plugh212

plugh212 Nov 4, 2013

Hello João,

On Sat, 02 Nov 2013, João Bolila wrote:

The sub test doesn't return a Dancer App.

Correct.  Dancer2Sub represents a module containing utility functions
common to my Dancer2 app.  It is meant to be 'use'd by other modules of
the app.

In your example just remove the use Dancer2; from Dancer2Sub.pm.

That means I can't use any of the Dancer syntax in Dancer2Sub.

That in turn means I can't build (well, I can build it, I just can't
use it) a module containing a set of common utility functions that need
the Dancer2 syntax.

Note: this architecture works with no problem in Dancer(1).

Regards,

                                        reid
package Dancer2Sub;
use parent 'Exporter';
our @EXPORT_OK = qw( test );

sub test { 'test'; }
1;

and in dancer2_test.pl do something like:

use Dancer2;
use Dancer2Sub qw( test );

get '/' => sub { test() };

dance;

Reply to this email directly or view it on GitHub:
#487 (comment)

plugh212 commented Nov 4, 2013

Hello João,

On Sat, 02 Nov 2013, João Bolila wrote:

The sub test doesn't return a Dancer App.

Correct.  Dancer2Sub represents a module containing utility functions
common to my Dancer2 app.  It is meant to be 'use'd by other modules of
the app.

In your example just remove the use Dancer2; from Dancer2Sub.pm.

That means I can't use any of the Dancer syntax in Dancer2Sub.

That in turn means I can't build (well, I can build it, I just can't
use it) a module containing a set of common utility functions that need
the Dancer2 syntax.

Note: this architecture works with no problem in Dancer(1).

Regards,

                                        reid
package Dancer2Sub;
use parent 'Exporter';
our @EXPORT_OK = qw( test );

sub test { 'test'; }
1;

and in dancer2_test.pl do something like:

use Dancer2;
use Dancer2Sub qw( test );

get '/' => sub { test() };

dance;

Reply to this email directly or view it on GitHub:
#487 (comment)

@xsawyerx

This comment has been minimized.

Show comment Hide comment
@xsawyerx

xsawyerx Dec 8, 2013

Owner

The problem is that calling "use Dancer2" plays with your import. That's on purpose.

I think you could fix this with a role behavior, or using callbacks.

Dancer1 has use Dancer ':syntax' but in Dancer2 it became superfluous.

Owner

xsawyerx commented Dec 8, 2013

The problem is that calling "use Dancer2" plays with your import. That's on purpose.

I think you could fix this with a role behavior, or using callbacks.

Dancer1 has use Dancer ':syntax' but in Dancer2 it became superfluous.

@plugh212

This comment has been minimized.

Show comment Hide comment
@plugh212

plugh212 Dec 9, 2013

Hello Sawyer,

On Sun, 08 Dec 2013, Sawyer X wrote:

The problem is that calling "use Dancer2" plays with your import. That's on purpose.

Yes, I noticed.  I'm wondering if that's really what you want to do :-)

I think you could fix this with a role behavior, or using callbacks.

Dancer1 has use Dancer ':syntax' but in Dancer2 it became superfluous.

Superfluous?  Do you mean that this:

package ABC;

don't need to call Dancer2 ':syntax';

my $p = params->{foo};
var xyz => $p;

1;

will compile and run as expected?

Or do you mean that params and var, etc. no longer do what they do in
Dancer[1]?

Somehow I don't think you mean either of those.  Could you be a bit
more explicit?

Regards,

                                    reid

plugh212 commented Dec 9, 2013

Hello Sawyer,

On Sun, 08 Dec 2013, Sawyer X wrote:

The problem is that calling "use Dancer2" plays with your import. That's on purpose.

Yes, I noticed.  I'm wondering if that's really what you want to do :-)

I think you could fix this with a role behavior, or using callbacks.

Dancer1 has use Dancer ':syntax' but in Dancer2 it became superfluous.

Superfluous?  Do you mean that this:

package ABC;

don't need to call Dancer2 ':syntax';

my $p = params->{foo};
var xyz => $p;

1;

will compile and run as expected?

Or do you mean that params and var, etc. no longer do what they do in
Dancer[1]?

Somehow I don't think you mean either of those.  Could you be a bit
more explicit?

Regards,

                                    reid
@DavsX

This comment has been minimized.

Show comment Hide comment
@DavsX

DavsX Sep 15, 2014

Well, my 2 cents (so we can maybe wrap this up)

  • First, @xsawyerx ment I think, that with Dancer2, you no longer have "use Dancer2 ':syntax';", because now you just simply say "use Dancer2;" -> afaik the ':syntax' part is now ignored/obsolete
  • Second, I think having a utility module that uses Dancer2 is a bad idea/bad design. I'd eighter go with some roles, as @xsawyerx said, but maybe rather pass those informations into the utility object thus reducing coupling between those two (which is generally a good thing).
    If you would like to set 'var xyz' inside that utility function, then I'd warn you about the danger of side effects and action-at-distance (mainly when it comes to debugging a program). Much better would be to make the utility function calculate the value you want to set 'var xyz' to, and the set it inside the route handler -> less coupling, less surprises, better code.

DavsX commented Sep 15, 2014

Well, my 2 cents (so we can maybe wrap this up)

  • First, @xsawyerx ment I think, that with Dancer2, you no longer have "use Dancer2 ':syntax';", because now you just simply say "use Dancer2;" -> afaik the ':syntax' part is now ignored/obsolete
  • Second, I think having a utility module that uses Dancer2 is a bad idea/bad design. I'd eighter go with some roles, as @xsawyerx said, but maybe rather pass those informations into the utility object thus reducing coupling between those two (which is generally a good thing).
    If you would like to set 'var xyz' inside that utility function, then I'd warn you about the danger of side effects and action-at-distance (mainly when it comes to debugging a program). Much better would be to make the utility function calculate the value you want to set 'var xyz' to, and the set it inside the route handler -> less coupling, less surprises, better code.
@racke

This comment has been minimized.

Show comment Hide comment
@racke

racke Nov 27, 2014

Owner

I would recommend to write your own plugin for utility functions. This gives you access to Dancer2 DSL and you "export" your functions with register. No need to mimic that with Exporter.

Owner

racke commented Nov 27, 2014

I would recommend to write your own plugin for utility functions. This gives you access to Dancer2 DSL and you "export" your functions with register. No need to mimic that with Exporter.

@xsawyerx

This comment has been minimized.

Show comment Hide comment
@xsawyerx

xsawyerx Nov 28, 2014

Owner

Dancer2 applications are web applications, and should not be used to store utility functions for other Dancer2 applications.

This is simply not something that should work to begin with. I hope the suggestions we offered were helpful.

Owner

xsawyerx commented Nov 28, 2014

Dancer2 applications are web applications, and should not be used to store utility functions for other Dancer2 applications.

This is simply not something that should work to begin with. I hope the suggestions we offered were helpful.

@xsawyerx xsawyerx closed this Nov 28, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment