diff options
author | matthewt <matthewt@03d0b0b2-0e1a-0410-a411-fdb2f4bd65d7> | 2008-07-24 01:42:34 +0000 |
---|---|---|
committer | matthewt <matthewt@03d0b0b2-0e1a-0410-a411-fdb2f4bd65d7> | 2008-07-24 01:42:34 +0000 |
commit | 8139388160b0a38002b22ff95c3fee3d8380f156 (patch) | |
tree | d7610c5db84c2c996107adb36bca1fe8a2b0b7cb /lib/Reaction/UI/ViewPort/Field | |
parent | 2a4c89335368295f0fc55f79d2c8fd5e33afd212 (diff) | |
download | reaction-8139388160b0a38002b22ff95c3fee3d8380f156.tar.gz reaction-8139388160b0a38002b22ff95c3fee3d8380f156.zip |
rclass stuff ripped out of everything but widget classes
Diffstat (limited to 'lib/Reaction/UI/ViewPort/Field')
30 files changed, 695 insertions, 644 deletions
diff --git a/lib/Reaction/UI/ViewPort/Field/.ToDo/File.pm b/lib/Reaction/UI/ViewPort/Field/.ToDo/File.pm index c06f1a3..4df820d 100644 --- a/lib/Reaction/UI/ViewPort/Field/.ToDo/File.pm +++ b/lib/Reaction/UI/ViewPort/Field/.ToDo/File.pm @@ -3,23 +3,27 @@ package Reaction::UI::ViewPort::InterfaceModel::Field::File; use Reaction::Class; use Reaction::Types::File; -class File is 'Reaction::UI::ViewPort::InterfaceModel::Field', which { +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::InterfaceModel::Field'; - has '+value' => (isa => 'File', required => 0); - override apply_our_events => sub { - my ($self, $ctx, $events) = @_; - my $value_key = join(':', $self->location, 'value'); - if (my $upload = $ctx->req->upload($value_key)) { - local $events->{$value_key} = $upload; - return super(); - } else { - return super(); - } - }; +has '+value' => (isa => 'File', required => 0); + +override apply_our_events => sub { + my ($self, $ctx, $events) = @_; + my $value_key = join(':', $self->location, 'value'); + if (my $upload = $ctx->req->upload($value_key)) { + local $events->{$value_key} = $upload; + return super(); + } else { + return super(); + } }; +__PACKAGE__->meta->make_immutable; + + 1; =head1 NAME diff --git a/lib/Reaction/UI/ViewPort/Field/.ToDo/TimeRange.pm b/lib/Reaction/UI/ViewPort/Field/.ToDo/TimeRange.pm index 9d65f2e..b411152 100644 --- a/lib/Reaction/UI/ViewPort/Field/.ToDo/TimeRange.pm +++ b/lib/Reaction/UI/ViewPort/Field/.ToDo/TimeRange.pm @@ -6,89 +6,88 @@ use DateTime; use DateTime::SpanSet; use Time::ParseDate (); -class TimeRange is 'Reaction::UI::ViewPort::InterfaceModel::Field', which { - - has '+value' => (isa => 'DateTime::SpanSet'); - - #has '+layout' => (default => 'timerange'); - - has value_string => - (isa => 'Str', is => 'rw', lazy_fail => 1, trigger_adopt('value_string')); - - has delete_label => ( - isa => 'Str', is => 'rw', required => 1, default => sub { 'Delete' }, - ); - - has parent => ( - isa => 'Reaction::UI::ViewPort::TimeRangeCollection', - is => 'ro', - required => 1, - is_weak_ref => 1 - ); - - implements _build_value_string => as { - my $self = shift; - #return '' unless $self->has_value; - #return $self->value_string; - }; - - implements value_array => as { - my $self = shift; - return split(',', $self->value_string); - }; - - implements adopt_value_string => as { - my ($self) = @_; - my @values = $self->value_array; - for my $idx (0 .. 3) { # last value is repeat - if (length $values[$idx]) { - my ($epoch) = Time::ParseDate::parsedate($values[$idx], UK => 1); - $values[$idx] = DateTime->from_epoch( epoch => $epoch ); - } +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::InterfaceModel::Field'; + + + +has '+value' => (isa => 'DateTime::SpanSet'); + +#has '+layout' => (default => 'timerange'); + +has value_string => + (isa => 'Str', is => 'rw', lazy_fail => 1, trigger_adopt('value_string')); + +has delete_label => ( + isa => 'Str', is => 'rw', required => 1, default => sub { 'Delete' }, +); + +has parent => ( + isa => 'Reaction::UI::ViewPort::TimeRangeCollection', + is => 'ro', + required => 1, + is_weak_ref => 1 +); +sub _build_value_string { + my $self = shift; + #return '' unless $self->has_value; + #return $self->value_string; +}; +sub value_array { + my $self = shift; + return split(',', $self->value_string); +}; +sub adopt_value_string { + my ($self) = @_; + my @values = $self->value_array; + for my $idx (0 .. 3) { # last value is repeat + if (length $values[$idx]) { + my ($epoch) = Time::ParseDate::parsedate($values[$idx], UK => 1); + $values[$idx] = DateTime->from_epoch( epoch => $epoch ); } - $self->value($self->range_to_spanset(@values)); - }; - - implements range_to_spanset => as { - my ($self, $time_from, $time_to, $repeat_from, $repeat_to, $pattern) = @_; - my $spanset = DateTime::SpanSet->empty_set; - if (!$pattern || $pattern eq 'none') { - my $span = DateTime::Span->from_datetimes( - start => $time_from, end => $time_to - ); - $spanset = $spanset->union( $span ); - } else { - my $duration = $time_to - $time_from; - my %args = ( days => $time_from->day + 2, - hours => $time_from->hour, - minutes => $time_from->minute, - seconds => $time_from->second ); - - delete $args{'days'} if ($pattern eq 'daily'); - delete @args{qw/hours days/} if ($pattern eq 'hourly'); - $args{'days'} = $time_from->day if ($pattern eq 'monthly'); - my $start_set = DateTime::Event::Recurrence->$pattern( %args ); - my $iter = $start_set->iterator( start => $repeat_from, end => $repeat_to ); - while ( my $dt = $iter->next ) { - my $endtime = $dt + $duration; - my $new_span = DateTime::Span->from_datetimes( - start => $dt, - end => $endtime - ); - $spanset = $spanset->union( $new_span ); - } + } + $self->value($self->range_to_spanset(@values)); +}; +sub range_to_spanset { + my ($self, $time_from, $time_to, $repeat_from, $repeat_to, $pattern) = @_; + my $spanset = DateTime::SpanSet->empty_set; + if (!$pattern || $pattern eq 'none') { + my $span = DateTime::Span->from_datetimes( + start => $time_from, end => $time_to + ); + $spanset = $spanset->union( $span ); + } else { + my $duration = $time_to - $time_from; + my %args = ( days => $time_from->day + 2, + hours => $time_from->hour, + minutes => $time_from->minute, + seconds => $time_from->second ); + + delete $args{'days'} if ($pattern eq 'daily'); + delete @args{qw/hours days/} if ($pattern eq 'hourly'); + $args{'days'} = $time_from->day if ($pattern eq 'monthly'); + my $start_set = DateTime::Event::Recurrence->$pattern( %args ); + my $iter = $start_set->iterator( start => $repeat_from, end => $repeat_to ); + while ( my $dt = $iter->next ) { + my $endtime = $dt + $duration; + my $new_span = DateTime::Span->from_datetimes( + start => $dt, + end => $endtime + ); + $spanset = $spanset->union( $new_span ); } - return $spanset; - }; + } + return $spanset; +}; +sub delete { + my ($self) = @_; + $self->parent->remove_range_vp($self); +}; - implements delete => as { - my ($self) = @_; - $self->parent->remove_range_vp($self); - }; +override accept_events => sub { ('value_string', 'delete', super()) }; - override accept_events => sub { ('value_string', 'delete', super()) }; +__PACKAGE__->meta->make_immutable; -}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Array.pm b/lib/Reaction/UI/ViewPort/Field/Array.pm index 92a735e..82e01d2 100644 --- a/lib/Reaction/UI/ViewPort/Field/Array.pm +++ b/lib/Reaction/UI/ViewPort/Field/Array.pm @@ -4,22 +4,24 @@ use Reaction::Class; use Scalar::Util 'blessed'; use aliased 'Reaction::UI::ViewPort::Field'; -class Array is Field, which { - has '+value' => (isa => 'ArrayRef'); +use namespace::clean -except => [ qw(meta) ]; +extends Field; - has value_names => (isa => 'ArrayRef', is => 'ro', lazy_build => 1); - has value_map_method => ( - isa => 'Str', is => 'ro', required => 1, default => sub { 'display_name' }, - ); - implements _build_value_names => as { - my $self = shift; - my $meth = $self->value_map_method; - my @names = map { blessed($_) ? $_->$meth : $_ } @{ $self->value }; - return [ sort @names ]; - }; +has '+value' => (isa => 'ArrayRef'); - implements _empty_value => as { [] }; +has value_names => (isa => 'ArrayRef', is => 'ro', lazy_build => 1); +has value_map_method => ( + isa => 'Str', is => 'ro', required => 1, default => sub { 'display_name' }, +); +sub _build_value_names { + my $self = shift; + my $meth = $self->value_map_method; + my @names = map { blessed($_) ? $_->$meth : $_ } @{ $self->value }; + return [ sort @names ]; }; +sub _empty_value { [] }; +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Boolean.pm b/lib/Reaction/UI/ViewPort/Field/Boolean.pm index cb6695e..53356ef 100644 --- a/lib/Reaction/UI/ViewPort/Field/Boolean.pm +++ b/lib/Reaction/UI/ViewPort/Field/Boolean.pm @@ -3,10 +3,14 @@ package Reaction::UI::ViewPort::Field::Boolean; use Reaction::Class; use aliased 'Reaction::UI::ViewPort::Field'; -class Boolean, is Field, which { - has '+value' => (isa => 'Bool'); +use namespace::clean -except => [ qw(meta) ]; +extends Field; + + +has '+value' => (isa => 'Bool'); + +override _empty_string_value => sub { 0 }; +__PACKAGE__->meta->make_immutable; - override _empty_string_value => sub { 0 }; -}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Collection.pm b/lib/Reaction/UI/ViewPort/Field/Collection.pm index b772e02..02dfa75 100644 --- a/lib/Reaction/UI/ViewPort/Field/Collection.pm +++ b/lib/Reaction/UI/ViewPort/Field/Collection.pm @@ -4,20 +4,23 @@ use Reaction::Class; use Scalar::Util 'blessed'; use aliased 'Reaction::UI::ViewPort::Field::Array'; -class Collection is Array, which { +use namespace::clean -except => [ qw(meta) ]; +extends Array; - has value => ( - is => 'rw', lazy_build => 1, - isa => 'Reaction::InterfaceModel::Collection' - ); - implements _build_value_names => as { - my $self = shift; - my $meth = $self->value_map_method; - my @names = map { blessed($_) ? $_->$meth : $_ } $self->value->members; - return [ sort @names ]; - }; +has value => ( + is => 'rw', lazy_build => 1, + isa => 'Reaction::InterfaceModel::Collection' +); +sub _build_value_names { + my $self = shift; + my $meth = $self->value_map_method; + my @names = map { blessed($_) ? $_->$meth : $_ } $self->value->members; + return [ sort @names ]; }; +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/DateTime.pm b/lib/Reaction/UI/ViewPort/Field/DateTime.pm index bb896c7..46fbb60 100644 --- a/lib/Reaction/UI/ViewPort/Field/DateTime.pm +++ b/lib/Reaction/UI/ViewPort/Field/DateTime.pm @@ -5,20 +5,24 @@ use Reaction::Class; use Reaction::Types::DateTime (); use aliased 'Reaction::UI::ViewPort::Field'; -class DateTime is Field, which { - has '+value' => (isa => Reaction::Types::DateTime::DateTime()); +use namespace::clean -except => [ qw(meta) ]; +extends Field; - has value_string_default_format => ( - isa => 'Str', is => 'rw', required => 1, default => sub { "%F %H:%M:%S" } - ); - around _value_string_from_value => sub { - my $orig = shift; - my $self = shift; - my $format = $self->value_string_default_format; - return $self->$orig(@_)->strftime($format); - }; +has '+value' => (isa => Reaction::Types::DateTime::DateTime()); +has value_string_default_format => ( + isa => 'Str', is => 'rw', required => 1, default => sub { "%F %H:%M:%S" } +); + +around _value_string_from_value => sub { + my $orig = shift; + my $self = shift; + my $format = $self->value_string_default_format; + return $self->$orig(@_)->strftime($format); }; +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/File.pm b/lib/Reaction/UI/ViewPort/Field/File.pm index dfe4dac..5d731e6 100644 --- a/lib/Reaction/UI/ViewPort/Field/File.pm +++ b/lib/Reaction/UI/ViewPort/Field/File.pm @@ -3,25 +3,27 @@ package Reaction::UI::ViewPort::Field::File; use Reaction::Class; use Reaction::Types::File; -class File is 'Reaction::UI::ViewPort::Field', which { +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field'; - has '+value' => (isa => Reaction::Types::File::File()); - has uri => ( is => 'rw', lazy_build => 1); - has action => (isa => 'CodeRef', is => 'rw', required => 1); +has '+value' => (isa => Reaction::Types::File::File()); - implements _build_uri => as{ - my $self = shift; - my $c = $self->ctx; - my ($c_name, $a_name, @rest) = @{ $self->action->($self->model, $c) }; - $c->uri_for($c->controller($c_name)->action_for($a_name),@rest); - }; +has uri => ( is => 'rw', lazy_build => 1); - implements _value_string_from_value => as { - shift->value->stringify; - }; - +has action => (isa => 'CodeRef', is => 'rw', required => 1); +sub _build_uri { + my $self = shift; + my $c = $self->ctx; + my ($c_name, $a_name, @rest) = @{ $self->action->($self->model, $c) }; + $c->uri_for($c->controller($c_name)->action_for($a_name),@rest); }; +sub _value_string_from_value { + shift->value->stringify; +}; + +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Integer.pm b/lib/Reaction/UI/ViewPort/Field/Integer.pm index d3681cb..7064edb 100644 --- a/lib/Reaction/UI/ViewPort/Field/Integer.pm +++ b/lib/Reaction/UI/ViewPort/Field/Integer.pm @@ -3,8 +3,12 @@ package Reaction::UI::ViewPort::Field::Integer; use Reaction::Class; use aliased 'Reaction::UI::ViewPort::Field'; -class Integer is Field, which { - has '+value' => (isa => 'Int'); -}; +use namespace::clean -except => [ qw(meta) ]; +extends Field; + + +has '+value' => (isa => 'Int'); +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Array.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Array.pm index 0bf0104..6f5129c 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Array.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Array.pm @@ -2,17 +2,20 @@ package Reaction::UI::ViewPort::Field::Mutable::Array; use Reaction::Class; -class Array is 'Reaction::UI::ViewPort::Field::Array', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::Array'; - around value => sub { - my $orig = shift; - my $self = shift; - return $orig->($self) unless @_; - my $value = defined $_[0] ? $_[0] : []; - $orig->($self, (ref $value eq 'ARRAY' ? $value : [ $value ])); - }; +with 'Reaction::UI::ViewPort::Field::Role::Mutable'; + +around value => sub { + my $orig = shift; + my $self = shift; + return $orig->($self) unless @_; + my $value = defined $_[0] ? $_[0] : []; + $orig->($self, (ref $value eq 'ARRAY' ? $value : [ $value ])); }; +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Boolean.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Boolean.pm index dfd936e..9063fca 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Boolean.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Boolean.pm @@ -2,19 +2,20 @@ package Reaction::UI::ViewPort::Field::Mutable::Boolean; use Reaction::Class; -class Boolean is 'Reaction::UI::ViewPort::Field::Boolean', which{ - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::Boolean'; - implements adopt_value_string => as { - my ($self) = @_; - $self->value($self->value_string); - }; +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +sub adopt_value_string { + my ($self) = @_; + $self->value($self->value_string); +}; +sub BUILD { + my($self) = @_; + $self->value(0) unless $self->_model_has_value; +}; - implements BUILD => as { - my($self) = @_; - $self->value(0) unless $self->_model_has_value; - }; +__PACKAGE__->meta->make_immutable; -}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm index b3dca44..0833c73 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm @@ -7,77 +7,76 @@ my $listify = sub{ return ref $_[0] eq 'ARRAY' ? $_[0] : [$_[0]]; }; -class ChooseMany is 'Reaction::UI::ViewPort::Field', which { - - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; - does 'Reaction::UI::ViewPort::Field::Role::Choices'; - - #MUST BE HERE, BELOW THE 'does', OR THE TRIGGER WILL NOT HAPPEN! - has '+value' => (isa => 'ArrayRef'); - - around value => sub { - my $orig = shift; - my $self = shift; - return $orig->($self) unless @_; - my $value = $listify->(shift); - $_ = $self->str_to_ident($_) for @$value; - my $checked = $self->attribute->check_valid_value($self->model, $value); - # i.e. fail if any of the values fail - confess "Not a valid set of values" - if (@$checked < @$value || grep { !defined($_) } @$checked); - $orig->($self, $checked); - }; - - - around _value_string_from_value => sub { - my $orig = shift; - my $self = shift; - join(", ", (map {$self->obj_to_name($_->{value}) } @{ $self->current_value_choices })); - }; - - implements is_current_value => as { - my ($self, $check_value) = @_; - return unless $self->_model_has_value; - my @our_values = @{$self->value || []}; - $check_value = $self->obj_to_str($check_value) if ref($check_value); - return grep { $self->obj_to_str($_) eq $check_value } @our_values; - }; - - implements current_value_choices => as { - my $self = shift; - my @all = grep { $self->is_current_value($_->{value}) } @{$self->value_choices}; - return [ @all ]; - }; - - implements available_value_choices => as { - my $self = shift; - my @all = grep { !$self->is_current_value($_->{value}) } @{$self->value_choices}; - return [ @all ]; - }; - - around handle_events => sub { - my $orig = shift; - my ($self, $events) = @_; - $events->{value} = [] if $events->{no_current_value}; - my $ev_value = $listify->($events->{value}); - if (delete $events->{add_all_values}) { - $events->{value} = [map {$self->obj_to_str($_)} @{$self->valid_values}]; - } elsif (exists $events->{add_values} && delete $events->{do_add_values}) { - my $add = $listify->(delete $events->{add_values}); - $events->{value} = [ @{$ev_value}, @$add ]; - } elsif (delete $events->{remove_all_values}) { - $events->{value} = []; - }elsif (exists $events->{remove_values} && delete $events->{do_remove_values}) { - my $remove = $listify->(delete $events->{remove_values}); - my %r = map { ($_ => 1) } @$remove; - $events->{value} = [ grep { !$r{$_} } @{$ev_value} ]; - } - - return $orig->(@_); - }; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field'; + +with 'Reaction::UI::ViewPort::Field::Role::Mutable'; +with 'Reaction::UI::ViewPort::Field::Role::Choices'; + +#MUST BE HERE, BELOW THE 'does', OR THE TRIGGER WILL NOT HAPPEN! +has '+value' => (isa => 'ArrayRef'); + +around value => sub { + my $orig = shift; + my $self = shift; + return $orig->($self) unless @_; + my $value = $listify->(shift); + $_ = $self->str_to_ident($_) for @$value; + my $checked = $self->attribute->check_valid_value($self->model, $value); + # i.e. fail if any of the values fail + confess "Not a valid set of values" + if (@$checked < @$value || grep { !defined($_) } @$checked); + $orig->($self, $checked); +}; + +around _value_string_from_value => sub { + my $orig = shift; + my $self = shift; + join(", ", (map {$self->obj_to_name($_->{value}) } @{ $self->current_value_choices })); +}; +sub is_current_value { + my ($self, $check_value) = @_; + return unless $self->_model_has_value; + my @our_values = @{$self->value || []}; + $check_value = $self->obj_to_str($check_value) if ref($check_value); + return grep { $self->obj_to_str($_) eq $check_value } @our_values; +}; +sub current_value_choices { + my $self = shift; + my @all = grep { $self->is_current_value($_->{value}) } @{$self->value_choices}; + return [ @all ]; +}; +sub available_value_choices { + my $self = shift; + my @all = grep { !$self->is_current_value($_->{value}) } @{$self->value_choices}; + return [ @all ]; }; +around handle_events => sub { + my $orig = shift; + my ($self, $events) = @_; + $events->{value} = [] if $events->{no_current_value}; + my $ev_value = $listify->($events->{value}); + if (delete $events->{add_all_values}) { + $events->{value} = [map {$self->obj_to_str($_)} @{$self->valid_values}]; + } elsif (exists $events->{add_values} && delete $events->{do_add_values}) { + my $add = $listify->(delete $events->{add_values}); + $events->{value} = [ @{$ev_value}, @$add ]; + } elsif (delete $events->{remove_all_values}) { + $events->{value} = []; + }elsif (exists $events->{remove_values} && delete $events->{do_remove_values}) { + my $remove = $listify->(delete $events->{remove_values}); + my %r = map { ($_ => 1) } @$remove; + $events->{value} = [ grep { !$r{$_} } @{$ev_value} ]; + } + + return $orig->(@_); +}; + +__PACKAGE__->meta->make_immutable; + + 1; =head1 NAME diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseOne.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseOne.pm index f6b679a..dba1a6d 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseOne.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseOne.pm @@ -3,45 +3,45 @@ package Reaction::UI::ViewPort::Field::Mutable::ChooseOne; use Reaction::Class; use Scalar::Util (); -class ChooseOne is 'Reaction::UI::ViewPort::Field', which { - - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; - does 'Reaction::UI::ViewPort::Field::Role::Choices'; - - implements adopt_value_string => as { - my ($self) = @_; - my $value = $self->value_string; - $value = $self->str_to_ident($value) if (!ref $value); - my $attribute = $self->attribute; - my $checked = $attribute->check_valid_value($self->model, $value); - unless (defined $checked) { - require Data::Dumper; - my $serialised = Data::Dumper->new([ $value ])->Indent(0)->Dump; - $serialised =~ s/^\$VAR1 = //; $serialised =~ s/;$//; - confess "${serialised} is not a valid value for ${\$attribute->name} on " - ."${\$attribute->associated_class->name}"; - } - $self->value($checked); - }; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field'; + +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +with 'Reaction::UI::ViewPort::Field::Role::Choices'; +sub adopt_value_string { + my ($self) = @_; + my $value = $self->value_string; + $value = $self->str_to_ident($value) if (!ref $value); + my $attribute = $self->attribute; + my $checked = $attribute->check_valid_value($self->model, $value); + unless (defined $checked) { + require Data::Dumper; + my $serialised = Data::Dumper->new([ $value ])->Indent(0)->Dump; + $serialised =~ s/^\$VAR1 = //; $serialised =~ s/;$//; + confess "${serialised} is not a valid value for ${\$attribute->name} on " + ."${\$attribute->associated_class->name}"; + } + $self->value($checked); +}; - around _value_string_from_value => sub { - my $orig = shift; - my $self = shift; - my $value = $self->$orig(@_); - return $self->obj_to_name($value->{value}) if Scalar::Util::blessed($value); - return $self->obj_to_name($value) if blessed $value; - return "$value"; # force stringify. might work. probably won't. - }; +around _value_string_from_value => sub { + my $orig = shift; + my $self = shift; + my $value = $self->$orig(@_); + return $self->obj_to_name($value->{value}) if Scalar::Util::blessed($value); + return $self->obj_to_name($value) if blessed $value; + return "$value"; # force stringify. might work. probably won't. +}; +sub is_current_value { + my ($self, $check_value) = @_; + return unless $self->_model_has_value; + my $our_value = $self->value; + return unless defined($our_value); + $check_value = $self->obj_to_str($check_value) if ref($check_value); + return $self->obj_to_str($our_value) eq $check_value; +}; - implements is_current_value => as { - my ($self, $check_value) = @_; - return unless $self->_model_has_value; - my $our_value = $self->value; - return unless defined($our_value); - $check_value = $self->obj_to_str($check_value) if ref($check_value); - return $self->obj_to_str($our_value) eq $check_value; - }; +__PACKAGE__->meta->make_immutable; -}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/DateTime.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/DateTime.pm index 654f0d8..27181f5 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/DateTime.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/DateTime.pm @@ -4,25 +4,25 @@ use Reaction::Class; use Time::ParseDate; use DateTime; -class 'Reaction::UI::ViewPort::Field::Mutable::DateTime', - is 'Reaction::UI::ViewPort::Field::DateTime', which { - - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; - - implements adopt_value_string => as { - my ($self) = @_; - my $value = $self->value_string; - my ($epoch) = Time::ParseDate::parsedate($value); - if (defined $epoch) { - my $dt = 'DateTime'->from_epoch( epoch => $epoch ); - $self->value($dt); - } else { - $self->value($self->value_string); - } - }; - +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::DateTime'; + +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +sub adopt_value_string { + my ($self) = @_; + my $value = $self->value_string; + my ($epoch) = Time::ParseDate::parsedate($value); + if (defined $epoch) { + my $dt = 'DateTime'->from_epoch( epoch => $epoch ); + $self->value($dt); + } else { + $self->value($self->value_string); + } }; +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/File.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/File.pm index ffbcbc9..d6d05c2 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/File.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/File.pm @@ -3,29 +3,30 @@ package Reaction::UI::ViewPort::Field::Mutable::File; use Reaction::Types::File qw/Upload/; use Reaction::Class; -class File is 'Reaction::UI::ViewPort::Field', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; - - has '+value' => (isa => Upload); - - override apply_our_events => sub { - my ($self, $ctx, $events) = @_; - my $value_key = $self->event_id_for('value_string'); - if (my $upload = $ctx->req->upload($value_key)) { - local $events->{$value_key} = $upload; - return super(); - } else { - return super(); - } - }; - - implements adopt_value_string => sub { - my($self) = @_; - $self->value($self->value_string) if $self->value_string; - }; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field'; + +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; + +has '+value' => (isa => Upload); + +override apply_our_events => sub { + my ($self, $ctx, $events) = @_; + my $value_key = $self->event_id_for('value_string'); + if (my $upload = $ctx->req->upload($value_key)) { + local $events->{$value_key} = $upload; + return super(); + } else { + return super(); + } +}; +sub adopt_value_string { + my($self) = @_; + $self->value($self->value_string) if $self->value_string; +}; +override _value_string_from_value => sub { '' }; - overrides _value_string_from_value => sub { '' }; +__PACKAGE__->meta->make_immutable; -}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/HiddenArray.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/HiddenArray.pm index e55836f..fa75e3c 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/HiddenArray.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/HiddenArray.pm @@ -2,26 +2,27 @@ package Reaction::UI::ViewPort::Field::Mutable::HiddenArray; use Reaction::Class; -class HiddenArray is 'Reaction::UI::ViewPort::Field', which { - - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; - - has '+value' => (isa => 'ArrayRef'); - - around value => sub { - my $orig = shift; - my $self = shift; - if (@_) { - #this hsould be done with coercions - $orig->($self, (ref $_[0] eq 'ARRAY' ? $_[0] : [ $_[0] ])); - $self->sync_to_action; - } else { - $orig->($self); - } - }; - - implements _empty_value => as { [] }; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field'; + +with 'Reaction::UI::ViewPort::Field::Role::Mutable'; + +has '+value' => (isa => 'ArrayRef'); + +around value => sub { + my $orig = shift; + my $self = shift; + if (@_) { + #this hsould be done with coercions + $orig->($self, (ref $_[0] eq 'ARRAY' ? $_[0] : [ $_[0] ])); + $self->sync_to_action; + } else { + $orig->($self); + } }; +sub _empty_value { [] }; +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Integer.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Integer.pm index 958150a..452e2ab 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Integer.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Integer.pm @@ -2,14 +2,16 @@ package Reaction::UI::ViewPort::Field::Mutable::Integer; use Reaction::Class; -class Integer is 'Reaction::UI::ViewPort::Field::Integer', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; - - implements adopt_value_string => as { - my ($self) = @_; - $self->value($self->value_string); - }; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::Integer'; +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +sub adopt_value_string { + my ($self) = @_; + $self->value($self->value_string); }; +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/MatchingPasswords.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/MatchingPasswords.pm index 6d9d8aa..0685f87 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/MatchingPasswords.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/MatchingPasswords.pm @@ -3,38 +3,41 @@ package Reaction::UI::ViewPort::Field::Mutable::MatchingPasswords; use Reaction::Class; use aliased 'Reaction::UI::ViewPort::Field::Mutable::Password'; -class MatchingPasswords is Password, which { - - has check_value => (is => 'rw', isa => 'Str', ); - has check_label => (is => 'rw', isa => 'Str', lazy_build => 1); - - implements _build_check_label => as { - my $orig_label = shift->label; - return "Confirm ${orig_label}"; - }; - - #maybe both check_value and value_string should have triggers ? - #that way if one even happens before the other it would still work? - around adopt_value_string => sub { - my $orig = shift; - my ($self) = @_; - return $orig->(@_) if $self->check_value eq $self->value_string; - $self->message("Passwords do not match"); - return; - }; - - #order is important check_value should happen before value here ... - #i don't like how this works, it's unnecessarily fragile, but how else ? - around accept_events => sub { ('check_value', shift->(@_)) }; - - around can_sync_to_action => sub { - my $orig = shift; - my ($self) = @_; - return $orig->(@_) if $self->check_value eq $self->value_string; - $self->message("Passwords do not match"); - return; - }; +use namespace::clean -except => [ qw(meta) ]; +extends Password; + + +has check_value => (is => 'rw', isa => 'Str', ); +has check_label => (is => 'rw', isa => 'Str', lazy_build => 1); +sub _build_check_label { + my $orig_label = shift->label; + return "Confirm ${orig_label}"; }; +#maybe both check_value and value_string should have triggers ? +#that way if one even happens before the other it would still work? +around adopt_value_string => sub { + my $orig = shift; + my ($self) = @_; + return $orig->(@_) if $self->check_value eq $self->value_string; + $self->message("Passwords do not match"); + return; +}; + +#order is important check_value should happen before value here ... +#i don't like how this works, it's unnecessarily fragile, but how else ? +around accept_events => sub { ('check_value', shift->(@_)) }; + +around can_sync_to_action => sub { + my $orig = shift; + my ($self) = @_; + return $orig->(@_) if $self->check_value eq $self->value_string; + $self->message("Passwords do not match"); + return; +}; + +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Number.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Number.pm index d2be595..31416e4 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Number.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Number.pm @@ -2,13 +2,15 @@ package Reaction::UI::ViewPort::Field::Mutable::Number; use Reaction::Class; -class Number is 'Reaction::UI::ViewPort::Field::Number', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::Number'; - implements adopt_value_string => as { - my ($self) = @_; - $self->value($self->value_string); - }; +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +sub adopt_value_string { + my ($self) = @_; + $self->value($self->value_string); }; +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Password.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Password.pm index d009698..b89cc76 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Password.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Password.pm @@ -2,14 +2,16 @@ package Reaction::UI::ViewPort::Field::Mutable::Password; use Reaction::Class; -class Password is 'Reaction::UI::ViewPort::Field::String', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; - - implements adopt_value_string => as { - my ($self) = @_; - $self->value($self->value_string); - }; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::String'; +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +sub adopt_value_string { + my ($self) = @_; + $self->value($self->value_string); }; +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/String.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/String.pm index 11d5d14..ca6d73a 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/String.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/String.pm @@ -2,14 +2,16 @@ package Reaction::UI::ViewPort::Field::Mutable::String; use Reaction::Class; -class String is 'Reaction::UI::ViewPort::Field::String', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; - - implements adopt_value_string => as { - my ($self) = @_; - $self->value($self->value_string); - }; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::String'; +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +sub adopt_value_string { + my ($self) = @_; + $self->value($self->value_string); }; +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Text.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Text.pm index 09d2127..d4e6935 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Text.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Text.pm @@ -2,14 +2,16 @@ package Reaction::UI::ViewPort::Field::Mutable::Text; use Reaction::Class; -class Text is 'Reaction::UI::ViewPort::Field::Text', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; - - implements adopt_value_string => as { - my ($self) = @_; - $self->value($self->value_string); - }; +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::Text'; +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; +sub adopt_value_string { + my ($self) = @_; + $self->value($self->value_string); }; +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Number.pm b/lib/Reaction/UI/ViewPort/Field/Number.pm index a5725fa..a7ccc55 100644 --- a/lib/Reaction/UI/ViewPort/Field/Number.pm +++ b/lib/Reaction/UI/ViewPort/Field/Number.pm @@ -3,8 +3,12 @@ package Reaction::UI::ViewPort::Field::Number; use Reaction::Class; use aliased 'Reaction::UI::ViewPort::Field'; -class Number is Field, which { - has '+value' => (isa => 'Num'); -}; +use namespace::clean -except => [ qw(meta) ]; +extends Field; + + +has '+value' => (isa => 'Num'); +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Password.pm b/lib/Reaction/UI/ViewPort/Field/Password.pm index a80e71a..edb8fd2 100644 --- a/lib/Reaction/UI/ViewPort/Field/Password.pm +++ b/lib/Reaction/UI/ViewPort/Field/Password.pm @@ -4,12 +4,16 @@ use Reaction::Class; use Reaction::Types::Core qw(SimpleStr); -class Password is 'Reaction::UI::ViewPort::Field::String', which { +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field::String'; - has '+value' => (isa => SimpleStr); - #has '+layout' => (default => 'password'); -}; + +has '+value' => (isa => SimpleStr); +#has '+layout' => (default => 'password'); + +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/RelatedObject.pm b/lib/Reaction/UI/ViewPort/Field/RelatedObject.pm index 3a3354f..ec5c883 100644 --- a/lib/Reaction/UI/ViewPort/Field/RelatedObject.pm +++ b/lib/Reaction/UI/ViewPort/Field/RelatedObject.pm @@ -3,19 +3,23 @@ package Reaction::UI::ViewPort::Field::RelatedObject; use Reaction::Class; use Scalar::Util 'blessed'; -class RelatedObject is 'Reaction::UI::ViewPort::Field', which { +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field'; - has value_map_method => ( - isa => 'Str', is => 'ro', required => 1, default => sub { 'display_name' }, - ); - around _value_string_from_value => sub { - my $orig = shift; - my $self = shift; - my $meth = $self->value_map_method; - return $self->$orig(@_)->$meth; - }; +has value_map_method => ( + isa => 'Str', is => 'ro', required => 1, default => sub { 'display_name' }, +); + +around _value_string_from_value => sub { + my $orig = shift; + my $self = shift; + my $meth = $self->value_map_method; + return $self->$orig(@_)->$meth; }; +__PACKAGE__->meta->make_immutable; + + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Role/Choices.pm b/lib/Reaction/UI/ViewPort/Field/Role/Choices.pm index df8615d..fa329b7 100644 --- a/lib/Reaction/UI/ViewPort/Field/Role/Choices.pm +++ b/lib/Reaction/UI/ViewPort/Field/Role/Choices.pm @@ -4,51 +4,47 @@ use Reaction::Role; use URI; use Scalar::Util 'blessed'; -role Choices, which { - - has valid_values => (isa => 'ArrayRef', is => 'ro', lazy_build => 1); - has value_choices => (isa => 'ArrayRef', is => 'ro', lazy_build => 1); - has value_map_method => ( - isa => 'Str', is => 'ro', required => 1, default => sub { 'display_name' }, - ); - - implements str_to_ident => as { - my ($self, $str) = @_; - my $u = URI->new('','http'); - $u->query($str); - return ($u->query_keywords ? ($u->query_keywords)[0] : { $u->query_form }); - }; - - implements obj_to_str => as { - my ($self, $obj) = @_; - return $obj unless ref($obj); - confess "${obj} not an object" unless blessed($obj); - my $ident = $obj->ident_condition; #XXX DBIC ism that needs to go away - my $u = URI->new('', 'http'); - $u->query_form(%$ident); - return $u->query; - }; - - implements obj_to_name => as { - my ($self, $obj) = @_; - return $obj unless ref($obj); - confess "${obj} not an object" unless blessed($obj); - my $meth = $self->value_map_method; - return $obj->$meth; - }; - - implements _build_valid_values => as { - my $self = shift; - return [ $self->attribute->all_valid_values($self->model) ]; - }; +use namespace::clean -except => [ qw(meta) ]; + + +has valid_values => (isa => 'ArrayRef', is => 'ro', lazy_build => 1); +has value_choices => (isa => 'ArrayRef', is => 'ro', lazy_build => 1); +has value_map_method => ( + isa => 'Str', is => 'ro', required => 1, default => sub { 'display_name' }, +); +sub str_to_ident { + my ($self, $str) = @_; + my $u = URI->new('','http'); + $u->query($str); + return ($u->query_keywords ? ($u->query_keywords)[0] : { $u->query_form }); +}; +sub obj_to_str { + my ($self, $obj) = @_; + return $obj unless ref($obj); + confess "${obj} not an object" unless blessed($obj); + my $ident = $obj->ident_condition; #XXX DBIC ism that needs to go away + my $u = URI->new('', 'http'); + $u->query_form(%$ident); + return $u->query; +}; +sub obj_to_name { + my ($self, $obj) = @_; + return $obj unless ref($obj); + confess "${obj} not an object" unless blessed($obj); + my $meth = $self->value_map_method; + return $obj->$meth; +}; +sub _build_valid_values { + my $self = shift; + return [ $self->attribute->all_valid_values($self->model) ]; +}; +sub _build_value_choices { + my $self = shift; + my @pairs = map{{value => $self->obj_to_str($_), name => $self->obj_to_name($_)}} + @{ $self->valid_values }; + return [ sort { $a->{name} cmp $b->{name} } @pairs ]; +}; - implements _build_value_choices => sub{ - my $self = shift; - my @pairs = map{{value => $self->obj_to_str($_), name => $self->obj_to_name($_)}} - @{ $self->valid_values }; - return [ sort { $a->{name} cmp $b->{name} } @pairs ]; - }; -}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm b/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm index e2304ef..b73114c 100644 --- a/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm +++ b/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm @@ -5,92 +5,89 @@ use Reaction::Role; use aliased 'Reaction::InterfaceModel::Action'; use aliased 'Reaction::Meta::InterfaceModel::Action::ParameterAttribute'; -role Mutable, which { - has model => (is => 'ro', isa => Action, required => 1); - has attribute => (is => 'ro', isa => ParameterAttribute, required => 1); - - has value => ( - is => 'rw', lazy_build => 1, trigger_adopt('value'), - clearer => 'clear_value', - ); - has needs_sync => (is => 'rw', isa => 'Int', default => 0); - #predicates are autmagically generated for lazy and non-required attrs - has message => (is => 'rw', isa => 'Str', clearer => 'clear_message'); - - after clear_value => sub { - my $self = shift; - $self->clear_message if $self->has_message; - $self->needs_sync(1); - }; - - implements adopt_value => as { - my ($self) = @_; - $self->clear_message if $self->has_message; - $self->needs_sync(1); # if $self->has_attribute; - }; - - implements can_sync_to_action => as { - my $self = shift; - return 1 unless $self->needs_sync; - my $attr = $self->attribute; - - if ($self->has_value) { - my $value = $self->value; - if (my $tc = $attr->type_constraint) { - $value = $tc->coercion->coerce($value) if ($tc->has_coercion); - if (defined (my $error = $tc->validate($value))) { - $self->message($error); - return; - } +use namespace::clean -except => [ qw(meta) ]; + +has model => (is => 'ro', isa => Action, required => 1); +has attribute => (is => 'ro', isa => ParameterAttribute, required => 1); + +has value => ( + is => 'rw', lazy_build => 1, trigger_adopt('value'), + clearer => 'clear_value', +); +has needs_sync => (is => 'rw', isa => 'Int', default => 0); +#predicates are autmagically generated for lazy and non-required attrs +has message => (is => 'rw', isa => 'Str', clearer => 'clear_message'); + +after clear_value => sub { + my $self = shift; + $self->clear_message if $self->has_message; + $self->needs_sync(1); +}; +sub adopt_value { + my ($self) = @_; + $self->clear_message if $self->has_message; + $self->needs_sync(1); # if $self->has_attribute; +}; +sub can_sync_to_action { + my $self = shift; + return 1 unless $self->needs_sync; + my $attr = $self->attribute; + + if ($self->has_value) { + my $value = $self->value; + if (my $tc = $attr->type_constraint) { + $value = $tc->coercion->coerce($value) if ($tc->has_coercion); + if (defined (my $error = $tc->validate($value))) { + $self->message($error); + return; } - } else { - return if $attr->is_required; } - return 1; - }; - - implements sync_to_action => as { - my ($self) = @_; - return unless $self->needs_sync; - return unless $self->can_sync_to_action; - - my $attr = $self->attribute; - - if ($self->has_value) { - my $value = $self->value; - if (my $tc = $attr->type_constraint) { - #this will go away when we have moose dbic. until then though... - $value = $tc->coercion->coerce($value) if ($tc->has_coercion); - } - my $writer = $attr->get_write_method; - confess "No writer for attribute" unless defined($writer); - $self->model->$writer($value); - } else { - my $predicate = $attr->get_predicate_method; - confess "No predicate for attribute" unless defined($predicate); - if ($self->model->$predicate) { - my $clearer = $attr->get_clearer_method; - confess "${predicate} returned true but no clearer for attribute" - unless defined($clearer); - $self->model->$clearer; - } + } else { + return if $attr->is_required; + } + return 1; +}; +sub sync_to_action { + my ($self) = @_; + return unless $self->needs_sync; + return unless $self->can_sync_to_action; + + my $attr = $self->attribute; + + if ($self->has_value) { + my $value = $self->value; + if (my $tc = $attr->type_constraint) { + #this will go away when we have moose dbic. until then though... + $value = $tc->coercion->coerce($value) if ($tc->has_coercion); } - $self->needs_sync(0); - }; - - implements sync_from_action => as { - my ($self) = @_; - return unless !$self->needs_sync; # && $self->has_attribute; - if( !$self->has_message ){ - if(my $error = $self->model->error_for($self->attribute) ){ - $self->message( $error ); - } + my $writer = $attr->get_write_method; + confess "No writer for attribute" unless defined($writer); + $self->model->$writer($value); + } else { + my $predicate = $attr->get_predicate_method; + confess "No predicate for attribute" unless defined($predicate); + if ($self->model->$predicate) { + my $clearer = $attr->get_clearer_method; + confess "${predicate} returned true but no clearer for attribute" + unless defined($clearer); + $self->model->$clearer; + } + } + $self->needs_sync(0); +}; +sub sync_from_action { + my ($self) = @_; + return unless !$self->needs_sync; # && $self->has_attribute; + if( !$self->has_message ){ + if(my $error = $self->model->error_for($self->attribute) ){ + $self->message( $error ); } - }; + } +}; + +around accept_events => sub { ('value', shift->(@_)) }; - around accept_events => sub { ('value', shift->(@_)) }; -}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm b/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm index 4244b31..e41f264 100644 --- a/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm +++ b/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm @@ -4,35 +4,34 @@ use Reaction::Role; use aliased 'Reaction::UI::ViewPort::Field::Role::Mutable'; -role Simple which { - - does Mutable; - - has value_string => ( - is => 'rw', lazy_build => 1, trigger_adopt('value_string'), - clearer => 'clear_value', - ); +use namespace::clean -except => [ qw(meta) ]; +with Mutable; + +has value_string => ( + is => 'rw', lazy_build => 1, trigger_adopt('value_string'), + clearer => 'clear_value', +); + +around value_string => sub { + my $orig = shift; + my $self = shift; + if (@_ && defined($_[0]) && !ref($_[0]) && $_[0] eq '' + && !$self->value_is_required) { + $self->clear_value; + return undef; + } + return $self->$orig(@_); +}; - around value_string => sub { - my $orig = shift; - my $self = shift; - if (@_ && defined($_[0]) && !ref($_[0]) && $_[0] eq '' - && !$self->value_is_required) { - $self->clear_value; - return undef; - } - return $self->$orig(@_); - }; +# the user needs to implement this because, honestly, you're always going +# to need to do something custom and the only common thing really is +# "you probably set $self->value at the end" +requires 'adopt_value_string'; - # the user needs to implement this because, honestly, you're always going - # to need to do something custom and the only common thing really is - # "you probably set $self->value at the end" - requires 'adopt_value_string'; +around accept_events => sub { ('value_string', shift->(@_)) }; - around accept_events => sub { ('value_string', shift->(@_)) }; +around force_events => sub { (value_string => '', shift->(@_)) }; - around force_events => sub { (value_string => '', shift->(@_)) }; -}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/String.pm b/lib/Reaction/UI/ViewPort/Field/String.pm index 9935ae5..ec7e295 100644 --- a/lib/Reaction/UI/ViewPort/Field/String.pm +++ b/lib/Reaction/UI/ViewPort/Field/String.pm @@ -3,8 +3,12 @@ package Reaction::UI::ViewPort::Field::String; use Reaction::Class; use aliased 'Reaction::UI::ViewPort::Field'; -class String is Field, which { - has '+value' => (isa => 'Str'); -}; +use namespace::clean -except => [ qw(meta) ]; +extends Field; + + +has '+value' => (isa => 'Str'); +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Text.pm b/lib/Reaction/UI/ViewPort/Field/Text.pm index 3d19047..b0c90da 100644 --- a/lib/Reaction/UI/ViewPort/Field/Text.pm +++ b/lib/Reaction/UI/ViewPort/Field/Text.pm @@ -3,8 +3,12 @@ package Reaction::UI::ViewPort::Field::Text; use Reaction::Class; use aliased 'Reaction::UI::ViewPort::Field'; -class Text is Field, which { - has '+value' => (isa => 'Str'); -}; +use namespace::clean -except => [ qw(meta) ]; +extends Field; + + +has '+value' => (isa => 'Str'); +__PACKAGE__->meta->make_immutable; + 1; diff --git a/lib/Reaction/UI/ViewPort/Field/TimeRange.pm b/lib/Reaction/UI/ViewPort/Field/TimeRange.pm index ccf6e65..f227203 100644 --- a/lib/Reaction/UI/ViewPort/Field/TimeRange.pm +++ b/lib/Reaction/UI/ViewPort/Field/TimeRange.pm @@ -6,89 +6,88 @@ use DateTime; use DateTime::SpanSet; use Time::ParseDate (); -class TimeRange is 'Reaction::UI::ViewPort::Field', which { - - has '+value' => (isa => SpanSet); - - #has '+layout' => (default => 'timerange'); - - has value_string => - (isa => 'Str', is => 'rw', lazy_fail => 1, trigger_adopt('value_string')); - - has delete_label => ( - isa => 'Str', is => 'rw', required => 1, default => sub { 'Delete' }, - ); - - has parent => ( - isa => 'Reaction::UI::ViewPort::TimeRangeCollection', - is => 'ro', - required => 1, - is_weak_ref => 1 - ); - - implements _build_value_string => as { - my $self = shift; - #return '' unless $self->has_value; - #return $self->value_string; - }; - - implements value_array => as { - my $self = shift; - return split(',', $self->value_string); - }; - - implements adopt_value_string => as { - my ($self) = @_; - my @values = $self->value_array; - for my $idx (0 .. 3) { # last value is repeat - if (length $values[$idx]) { - my ($epoch) = Time::ParseDate::parsedate($values[$idx], UK => 1); - $values[$idx] = DateTime->from_epoch( epoch => $epoch ); - } +use namespace::clean -except => [ qw(meta) ]; +extends 'Reaction::UI::ViewPort::Field'; + + + +has '+value' => (isa => SpanSet); + +#has '+layout' => (default => 'timerange'); + +has value_string => + (isa => 'Str', is => 'rw', lazy_fail => 1, trigger_adopt('value_string')); + +has delete_label => ( + isa => 'Str', is => 'rw', required => 1, default => sub { 'Delete' }, +); + +has parent => ( + isa => 'Reaction::UI::ViewPort::TimeRangeCollection', + is => 'ro', + required => 1, + is_weak_ref => 1 +); +sub _build_value_string { + my $self = shift; + #return '' unless $self->has_value; + #return $self->value_string; +}; +sub value_array { + my $self = shift; + return split(',', $self->value_string); +}; +sub adopt_value_string { + my ($self) = @_; + my @values = $self->value_array; + for my $idx (0 .. 3) { # last value is repeat + if (length $values[$idx]) { + my ($epoch) = Time::ParseDate::parsedate($values[$idx], UK => 1); + $values[$idx] = DateTime->from_epoch( epoch => $epoch ); } - $self->value($self->range_to_spanset(@values)); - }; - - implements range_to_spanset => as { - my ($self, $time_from, $time_to, $repeat_from, $repeat_to, $pattern) = @_; - my $spanset = DateTime::SpanSet->empty_set; - if (!$pattern || $pattern eq 'none') { - my $span = DateTime::Span->from_datetimes( - start => $time_from, end => $time_to - ); - $spanset = $spanset->union( $span ); - } else { - my $duration = $time_to - $time_from; - my %args = ( days => $time_from->day + 2, - hours => $time_from->hour, - minutes => $time_from->minute, - seconds => $time_from->second ); - - delete $args{'days'} if ($pattern eq 'daily'); - delete @args{qw/hours days/} if ($pattern eq 'hourly'); - $args{'days'} = $time_from->day if ($pattern eq 'monthly'); - my $start_set = DateTime::Event::Recurrence->$pattern( %args ); - my $iter = $start_set->iterator( start => $repeat_from, end => $repeat_to ); - while ( my $dt = $iter->next ) { - my $endtime = $dt + $duration; - my $new_span = DateTime::Span->from_datetimes( - start => $dt, - end => $endtime - ); - $spanset = $spanset->union( $new_span ); - } + } + $self->value($self->range_to_spanset(@values)); +}; +sub range_to_spanset { + my ($self, $time_from, $time_to, $repeat_from, $repeat_to, $pattern) = @_; + my $spanset = DateTime::SpanSet->empty_set; + if (!$pattern || $pattern eq 'none') { + my $span = DateTime::Span->from_datetimes( + start => $time_from, end => $time_to + ); + $spanset = $spanset->union( $span ); + } else { + my $duration = $time_to - $time_from; + my %args = ( days => $time_from->day + 2, + hours => $time_from->hour, + minutes => $time_from->minute, + seconds => $time_from->second ); + + delete $args{'days'} if ($pattern eq 'daily'); + delete @args{qw/hours days/} if ($pattern eq 'hourly'); + $args{'days'} = $time_from->day if ($pattern eq 'monthly'); + my $start_set = DateTime::Event::Recurrence->$pattern( %args ); + my $iter = $start_set->iterator( start => $repeat_from, end => $repeat_to ); + while ( my $dt = $iter->next ) { + my $endtime = $dt + $duration; + my $new_span = DateTime::Span->from_datetimes( + start => $dt, + end => $endtime + ); + $spanset = $spanset->union( $new_span ); } - return $spanset; - }; + } + return $spanset; +}; +sub delete { + my ($self) = @_; + $self->parent->remove_range_vp($self); +}; - implements delete => as { - my ($self) = @_; - $self->parent->remove_range_vp($self); - }; +override accept_events => sub { ('value_string', 'delete', super()) }; - override accept_events => sub { ('value_string', 'delete', super()) }; +__PACKAGE__->meta->make_immutable; -}; 1; |