Perl: доступ к методам и json данным hashref через один и тот же объект в классе - PullRequest
1 голос
/ 12 февраля 2020

У меня есть класс объектов, который расширяет JSON функциональностью чтения и записи файлов. С точки зрения использования класса, я хочу использовать методы моего класса и обращаться к json ha sh с одним и тем же объектом.

Для примера я заменим обработку файла на from_ json и to_ json строки stati c, но принцип будет таким же.

Мой код "пользователя"

use Extended::JSON;
my $config = Extended::JSON->open('{"Data":{"Property":"Data in json"}}');
print "Data from json: " . $config->{Data}->{Property} . "\n";
$config->{Data}->{Property} = 'New Data in json';
$config->write();

Мой класс

use JSON;
package Extended::JSON;

sub open
{
  my $class = shift;
  my $data = shift;
  my self = { _jsonhash => from_json( $data ) };
  };
  bless $self, $class;
  return $self;
}
sub write
{
  my $self = shift;
  print to_json( $self->{_jsonhash} );
}

Как видите, код "пользователя" должен иметь возможность использовать атрибуты класса для непосредственного использования получить доступ и изменить значение ha sh из from_ json, но методы должны действовать как для класса. Я пропускаю, если есть возможность где-нибудь универсально "обернуть" атрибут доступа к методу класса, чтобы изменить json га sh, а не атрибуты объекта.

Спасибо вам! Christian

1 Ответ

4 голосов
/ 12 февраля 2020

Если у класса нет атрибутов (объектных переменных), вы можете использовать переменную, возвращаемую from_json в качестве объекта.

package Extended::JSON;

use strict;
use warnings;
use feature qw( say );

use JSON qw( from_json to_json );

sub open {
   my ($class, $json) = @_;
   return bless(from_json($json), $class);
}

sub write {
   my ($self) = @_;
   say to_json($self);
}

1;

Вы все равно можете использовать этот подход, если у класса есть атрибуты путем скрытия их, когда приходит время регенерировать JSON.

package Extended::JSON;

use strict;
use warnings;
use feature qw( say );

use JSON qw( from_json to_json );

sub open {
   my ($class, $json) = @_;
   my $self = bless(from_json($json), $class);
   # $self->{_foo} = ...;
   return $self;
}

sub write {
   my ($self) = @_;
   delete local @$self{ grep /^_/, keys(%$self) };
   say to_json($self);
}

1;

. Выше требуется, чтобы верхний уровень JSON был «объектом» (ха sh), и это предотвращает определенные ключи от использования в этом объекте. Чтобы избежать этих ограничений, мы можем использовать overload .

package Extended::JSON;

use strict;
use warnings;
use feature qw( say );

use JSON qw( from_json to_json );

use overload '%{}' => \&data;

sub open {
   my ($class, $json) = @_;
   my $self = bless(\{}, $class);
   $$self->{data} = from_json($json);
   # $$self->{foo} = ...;
   return $self;
}

sub write {
   my ($self) = @_;
   say to_json($$self->{data});
}

sub data {
   my ($self) = @_;
   return $$self->{data};
}

1;

Вышеописанное создает скалярный объект (в отличие от объекта на основе ха sh). При обработке ссылки как ссылки ha sh получаются данные, полученные из JSON, а при обработке ссылки как скалярной ссылки получается "реальный" объект.

$ perl -e'
   use Extended::JSON qw( );
   my $o = Extended::JSON->open(q{{"a":123}});
   CORE::say $o->{a};
   $o->write;
'
123
{"a":123}
...