<div class="gmail_quote">On Fri, Jun 10, 2011 at 4:21 PM, Bill Moseley <span dir="ltr">&lt;<a href="mailto:moseley@hank.org">moseley@hank.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
I have an app &quot;Foo&quot; and would like to make a new application based on it called &quot;Bar&quot;.<div><br></div>Is there a better approach than making a copy and s/Foo/Bar/g in most directories (lib, t)?</blockquote>
<div><br clear="all"></div></div>This is probably not a full solution, but may get you on the path to one.<br><br>I had a similar problem at $work where we have a core Catalyst application, but also needed the ability to install customer-specific components (either completely new functionality, or overriding one of the core controllers), and didn&#39;t want this to turn into a management nightmare (like hand-replacing specific component files on certain customers&#39; systems and praying we remembered when upgrading them later, which is what we unfortunately did with our ancient CGI-script-based &quot;app&quot;).<br>
<br>Our Catalyst implementation looks something like this:<br><br><span style="font-family: courier new,monospace;">package My::App;</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">use Moose;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">use Catalyst;</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">__PACKAGE__-&gt;config(</span>    <br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">    customers =&gt; [qw/Initech/],<br>
    setup_components =&gt; {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">        except =&gt; qr/^My::App::(Controller|Model|View)::Customer::/,</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">    },</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">);</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">around locate_components =&gt; sub {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">    my $orig  = shift;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">    my $class = shift;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">    my @comps = $class-&gt;$orig(@_);</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">    foreach my $customer (@{$class-&gt;config-&gt;{customers}}) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">        my @paths = qw( ::Controller ::Model ::View );</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">        my $locator = Module::Pluggable::Object-&gt;new(</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">            search_path =&gt; [ map { s/^::(.*)/${class}::$1::Customer::${customer}/; $_; } @paths ],</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">        );</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">        foreach my $comp ($locator-&gt;plugins) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">            my $replace_class = $comp;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">            $replace_class =~ s/::Customer::${customer}//;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">            @comps = grep {$_ ne $replace_class} @comps;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">            push @comps, $comp;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">        }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">    }</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">    return @comps;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">};</span><br><br>The code above roughly does the following:<br>
<ul><li>Find all components as Catalyst normally does</li><li>For each customer identifier, search a customer-specific component tree (My::App::(C|M|V)::Customer::$cust)<br></li><li>For each component found there, append it to the list of components to load</li>
<li>If the customer-specific component shares its class path with a core component, remove the core component from the load list (i.e., ::Controller::Customer::Initech::Foo causes ::Controller::Foo to be skipped; the assumption is that the customer-specific module extends it or replaces it entirely)</li>
</ul>If I had to adapt your problem to my problem, the core application would be Foo, and our customer would be Bar.<br><br>I hope this gives you some ideas.<br><br>-- <br>Stephen Clouse &lt;<a href="mailto:stephenclouse@gmail.com">stephenclouse@gmail.com</a>&gt;<br>