यह मूस संरचित प्रकारों के बारे में मेरे previous question से चलता है। प्रश्न की लंबाई के लिए मैं क्षमा चाहता हूं। मैं यह सुनिश्चित करना चाहता था कि मैंने सभी आवश्यक विवरण शामिल किए हैं।मूस जबरन और बिल्डर्स
MyApp::Type::Field
संरचित प्रकार को परिभाषित करता है। मैं अपने विशेषता को Person
कक्षा से अधिक आसानी से सेट करने की अनुमति देने के लिए मजबूरता का उपयोग करता हूं (नीचे उदाहरण देखें)। ध्यान दें कि मेरे असली एप्लिकेशन में, जहां फ़ील्ड प्रकार का उपयोग किसी व्यक्ति के नाम से अधिक के लिए किया जाता है, मैं भी हैशफ से सहभागिता करता हूं।
मैं भी स्थापित करने की आवश्यकता MyApp::Type::Field
size
और required
केवल पढ़ने के लिए निर्माण समय में MyApp::Person
से जिम्मेदार बताते हैं। मैं इसे बिल्डर विधि का उपयोग करके कर सकता हूं, लेकिन अगर इसे मजबूर किया जाता है, तो इसे मजबूर नहीं किया जाता है, क्योंकि मेरा जबरदस्त बिल्डर विधि का उपयोग किए बिना सीधे एक नई वस्तु बनाता है।
मैं around
विधि संशोधक MyApp::Person
(नीचे उदाहरण देखें) जोड़कर इसे गोल कर सकता हूं, लेकिन यह गन्दा लगता है। around
विधि संशोधक को अक्सर बार कहा जाता है, लेकिन मुझे केवल पढ़ने-योग्य विशेषताओं को एक बार सेट करने की आवश्यकता होती है।
क्या ऐसा करने का कोई बेहतर तरीका है, जबकि अभी भी जबरन अनुमति है? MyApp::Type::Field
कक्षा size
और required
को डिफ़ॉल्ट या बिल्डरों के माध्यम से प्रारंभ नहीं कर सकती है, क्योंकि इसका कोई तरीका नहीं है कि मूल्य क्या होना चाहिए।
यह केवल मामला हो सकता है कि मैं around
संशोधक के पक्ष में मजबूरता से गुजरता हूं।
MyApp::Type::Field
coerce 'MyApp::Type::Field'
=> from 'Str'
=> via { MyApp::Type::Field->new(value => $_) };
has 'value' => (is => 'rw');
has 'size' => (is => 'ro', isa => 'Int', writer => '_set_size', predicate => 'has_size');
has 'required' => (is => 'ro', isa => 'Bool', writer => '_set_required', predicate => 'has_required');
MyApp::Person
has name => (is => 'rw', isa => 'MyApp::Type::Field', lazy => 1, builder => '_build_name', coerce => 1);
sub _build_name {
print "Building name\n";
return MyApp::Type::Field->new(size => 255, required => 1);
}
MyApp::Test
print "Create new person with coercion\n";
my $person = MyApp::Person->new();
print "Set name\n";
$person->name('Joe Bloggs');
print "Name set\n";
printf ("Name: %s [%d][%d]\n\n", $person->name->value, $person->name->size, $person->name->required);
print "Create new person without coercion\n";
$person = MyApp::Person->new();
print "Set name\n";
$person->name->value('Joe Bloggs');
print "Name set\n";
printf ("Name: %s [%d][%d]\n\n", $person->name->value, $person->name->size, $person->name->required);
प्रिंटों:
Create new person with coercion
Set name
Name set
Name: Joe Bloggs [0][0]
Create new person without coercion
Set name
Building name
Name set
Name: Joe Bloggs [255][2]
MyApp::Person
के लिए एक around
विधि आपरिवर्तक जोड़ें, और बदल बिल्डर इतना है कि यह निर्धारित नहीं करता है size
और required
:
around 'name' => sub {
my $orig = shift;
my $self = shift;
print "Around name\n";
unless ($self->$orig->has_size) {
print "Setting size\n";
$self->$orig->_set_size(255);
};
unless ($self->$orig->has_required) {
print "Setting required\n";
$self->$orig->_set_required(1);
};
$self->$orig(@_);
};
sub _build_name {
print "Building name\n";
return MyApp::Type::Field->new();
}
जब MyApp::Test
चलाया जाता है, size
और required
हैं दो बार सेट करें।
Create new person with coercion
Set name
Around name
Building name
Setting size
Setting required
Name set
Around name
Setting size
Setting required
Around name
Around name
Name: Joe Bloggs [255][3]
Create new person without coercion
Set name
Around name
Building name
Name set
Around name
Around name
Around name
Name: Joe Bloggs [255][4]
प्रस्तावित समाधान
daotoad's प्रत्येक MyApp::Person
विशेषता के लिए एक उप-प्रकार बनाने, और एक MyApp::Type::Field
कार्यों में एक Str
से कि उप-प्रकार coercing काफी अच्छी तरह से के सुझाव। मैं लूप में पूरे लॉट को लपेटकर कई उपप्रकार, जबरन और विशेषताओं को भी बना सकता हूं। यह समान गुणों के साथ कई विशेषताओं को बनाने के लिए बहुत उपयोगी है।
नीचे दिए गए उदाहरण में, मैंने handles
का उपयोग करके प्रतिनिधिमंडल स्थापित किया है, ताकि $person->get_first_name
का अनुवाद $person->first_name->value
पर किया जा सके।
package MyApp::Type::Field;
use Moose;
has 'value' => (
is => 'rw',
);
has 'size' => (
is => 'ro',
isa => 'Int',
writer => '_set_size',
);
has 'required' => (
is => 'ro',
isa => 'Bool',
writer => '_set_required',
);
__PACKAGE__->meta->make_immutable;
1;
package MyApp::Person;
use Moose;
use Moose::Util::TypeConstraints;
use namespace::autoclean;
{
my $attrs = {
title => { size => 5, required => 0 },
first_name => { size => 45, required => 1 },
last_name => { size => 45, required => 1 },
};
foreach my $attr (keys %{$attrs}) {
my $subtype = 'MyApp::Person::' . ucfirst $attr;
subtype $subtype => as 'MyApp::Type::Field';
coerce $subtype
=> from 'Str'
=> via { MyApp::Type::Field->new(
value => $_,
size => $attrs->{$attr}{'size'},
required => $attrs->{$attr}{'required'},
) };
has $attr => (
is => 'rw',
isa => $subtype,
coerce => 1,
writer => "set_$attr",
handles => { "get_$attr" => 'value' },
default => sub {
MyApp::Type::Field->new(
size => $attrs->{$attr}{'size'},
required => $attrs->{$attr}{'required'},
)
},
);
}
}
__PACKAGE__->meta->make_immutable;
1;
package MyApp::Test;
sub print_person {
my $person = shift;
printf "Title: %s [%d][%d]\n" .
"First name: %s [%d][%d]\n" .
"Last name: %s [%d][%d]\n",
$person->title->value || '[undef]',
$person->title->size,
$person->title->required,
$person->get_first_name || '[undef]',
$person->first_name->size,
$person->first_name->required,
$person->get_last_name || '[undef]',
$person->last_name->size,
$person->last_name->required;
}
my $person;
$person = MyApp::Person->new(
title => 'Mr',
first_name => 'Joe',
last_name => 'Bloggs',
);
print_person($person);
$person = MyApp::Person->new();
$person->set_first_name('Joe');
$person->set_last_name('Bloggs');
print_person($person);
1;
प्रिंटों: एक लेखक देता है, एक बराबर सेटर प्रदान करता है वर्ग काफी साफ करने के लिए इंटरफ़ेस बनाने जोड़ना
Title: Mr [5][0]
First name: Joe [45][6]
Last name: Bloggs [45][7]
Title: [undef] [5][0]
First name: Joe [45][8]
Last name: Bloggs [45][9]
फ़ील्ड एक मूसएक्स :: प्रकार :: मेटा-एट्रिब्यूट्स के साथ एक विशेषता से संरचित है। उपयोग का एक उदाहरण एक वेब फॉर्म है जहां प्रत्येक फ़ील्ड को एक मान, अधिकतम लंबाई (आकार) और एक आवश्यक ध्वज की आवश्यकता होती है। मॉडल (व्यक्ति वर्ग, इस उदाहरण में), आकार और आवश्यक ध्वज सेट करता है। इसलिए 'फील्ड', काफी सामान्य होने के लिए है, जबकि' व्यक्ति वर्ग 'अधिक विशिष्ट है। मैंने पहले मेटा-एट्रिब्यूट्स को देखा, लेकिन उदाहरण के लिए, वे ''$ person-> मेटा-> get_attribute (' name ') -> size()') तक पहुंचने के लिए थोड़ा अजीब हैं। एक उप प्रकार एक विकल्प हो सकता है। मैं इसे देख लूंगा ... – Mike
मैंने अभी एक उप प्रकार बनाने के साथ प्रयोग किया है, और लगता है कि यह एक अच्छा समाधान प्रदान कर सकता है। मैं कल कुछ और परीक्षण करूँगा ... धन्यवाद। – Mike
मैंने अपने उत्तर को एक प्रस्तावित समाधान के साथ अपडेट किया है जो आपके उप प्रकार के सुझाव का उपयोग करता है। आपके सुझाव के लिए धन्यवाद। – Mike