LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> Perl (110) - Moose - meta API

Perl V Moose máme speciální aplikační rozhraní, díky němuž jsme schopni v jistém ohledu modifikovat samotný objektový systém.

16.5.2010 00:00 | Jiří Václavík | Články autora | přečteno 5773×

Pomocí rozhraní meta API lze nastavovat základní vlastnosti objektového systému a ovlivňovat věci jako chování metod, atributů a tříd.

Získání metadat

Základní metodou pro práci s vlastnostmi objektového systému je meta, která zpřístupňuje metadata dané třídy. Zde je příklad užití. Takto lze získat seznam metod nebo atributů s vlastnostmi.

  $meta = MojeTrida->meta();

  for $atribut ($meta->get_all_attributes){
      print "Atribut: ", $atribut->name(), " ";
      print $atribut->type_constraint->name if $atribut->has_type_constraint;
      print "\n";
  }

  for $method ($meta->get_all_methods){
      print $method->name," ";
  }

Poznamenejme, že namísto MojeTrida na prvním řádku můžeme použít slovo __PACKAGE__, které vyjadřuje jméno aktuálního balíku.

$meta = __PACKAGE__->meta;

Podobně lze získat metodou linearized_isa seznam rodičovských tříd a pomocí subclasses podtřídy.

Modifikace tříd pomocí metadat

Pro zajímavost uveďme, že třídy lze upravovat přímo pomocí změny metadat. Ukažme si, jak lze přidávat metody a atributy. Máme zde k dispozici metody add_method a add_attribute, kterým předáme příslušné parametry.

$meta = __PACKAGE__->meta;
$meta->add_method("nova_metoda" => sub{udelej_neco(@_)});
$meta->add_attribute(
    name => "novy_atribut",
    is   => "rw",
    isa  => "Int"
);

Toto chování lze vypnout pomocí metody make_immutable (případně zapnout pomocí make_mutable). V takovém případě bude při pokusu o změnu třídy pomocí metadat vyvolána výjimka.

$meta->make_immutable;

Fyzická reprezentace atributů

Atribut v Moose je ve skutečnosti objekt typu Moose::Meta::Attribute. To zásadně mění náš pohled na ně.

K těmto objektům lze samozřejmě přistupovat. K tomu slouží metoda get_attribute("jméno atributu"). Například objekt reprezentující atribut nazev získáme následovně.

$nazev = $meta->get_attribute("nazev")

Tento objekt má k dispozici několik metod. Pro příklad uvedeme metodu, která vrátí název datového typu.

print $nazev->type_constraint;

Abychom lépe nahlédli na strukturu, uvědomme si, že místo předchozích volání lze typ získat jedním příkazem.

print MojeTrida->meta->get_attribute("nazev")->type_constraint;

Modifikace fyzické reprezentace atributů, metaatributy

Celá situace je o to zajímavější, že strukturu třídy reprezentující atribut lze měnit. Můžeme například přidávat atributy k atributům. Jinými slovy chceme převzít řízení toho, jaký vliv na chování bude mít hash předávaný při vytváření atributu.

Ukážeme si, jak k atributu přidat popisek. Tedy chceme v řídícím hashi vytvořit nový klíč popisek. Názorněji, požadujeme, aby fungoval následující kód.

package MojeTrida::Main;
use Moose;

has "atribut_s_popiskem" => (
    is        => "rw",
    isa       => "Str",
    popisek   => "Toto je meta-popisek atributu atribut_s_popiskem",
);

Je dobré si zde uvědomit, že zde opravdu má smysl chtít vytvářet atributy. Popisek je totiž vlastností našeho atributu a proto by nemělo smysl ho uvádět kamkoliv jinam (například do metod naší třídy).

Této funkcionality se dosáhne tak, že definujeme vlastní metatřídu. Každý atribut je objekt typu Moose::Meta::Attribute. My ji potřebujeme přetížit. To znamená, že vytvoříme třídu, kterou nazveme MojeTrida::Meta::Attribute::Popisek, která bude dědit od Moose::Meta::Attribute. V této nové třídě definujeme nový atribut. Zároveň bude třeba někde uvést, že se daný atribut má řídit naší třídou MojeTrida::Meta::Attribute::Popisek (nikoliv standardní třídou Moose::Meta::Attribute).

Poslední požadavek (nastavení metatřídy) se vyřeší přidáním klíče metaclass. Definici našeho atributu tedy lehce upravíme tím, že přidáme jeden řádek.

has "atribut_s_popiskem" => (
    metaclass => "MojeTrida::Meta::Attribute::Popisek",
    is        => "rw",
    isa       => "Str",
    popisek   => "Toto je meta-popisek atributu atribut_s_popiskem",
);

Nyní již Moose ví, že chceme přetěžovat. Zbývá tedy pouze vytvořit třídu MojeTrida::Meta::Attribute::Popisek, která zdědí vše od Moose::Meta::Attribute. Vložíme sem navíc nový atribut popisek. Pomocí predicate=>je_popisek navíc přidáme detektor, protože bude časem potřeba.

package MojeTrida::Meta::Attribute::Popisek;
use Moose;
extends "Moose::Meta::Attribute";

has "popisek" => (
      is        => "rw",
      isa       => "Str",
      predicate => "je_popisek"
);

Nyní můžeme standardně pracovat s objekty typu MojeTrida::Main. Podívejme se pro zajímavost, jak získáme text popisku.

package main;
print MojeTrida::Main->meta->get_attribute("atribut_s_popiskem")->popisek;

Lze sem samozřejmě přistupovat i pomocí objektu.

$a = MojeTrida::Main->new(atribut_s_popiskem=>"hodnota");
print $a->meta->get_attribute("atribut_s_popiskem")->popisek;

Pro přehlednost napíšeme v MojeTrida::Main ještě metodu metainfo, která nám vytiskne informace o všech atributech a jejich popiscích. Odlišíme tak hodnotu atributu a popisek. Metoda metainfo může vypadat takto.

sub metainfo {
      my $self = shift;
      my $info = "";

      for my $a ($self->meta->get_attribute_list){
          my $atribut = $self->meta->get_attribute($a);
          $info .= $atribut->name. ":\n";
          $info .= "  popisek: ".$atribut->popisek."\n"
  if $atribut->isa("MojeTrida::Meta::Attribute::Popisek") and $atribut->je_popisek;
          $info .= "  hodnota: ". $self->{$atribut->get_read_method}. "\n";
      }

      return $info;
}

V našem příkladu bychom po zavolání print $a->metainfo; obdrželi následující výstup.

atribut_s_popiskem:
  popisek: Toto je meta-popisek atributu atribut_s_popiskem
  hodnota: hodnota

Více popisků pro atribut

Budeme-li chtít pro každý atribut vytvořit více různých atributů, pak se stává naznačený postup nečitelný - lze totiž sice podobně jako pro popisek vytvářet další a další podtřídy, avšak po jisté době se každý zamyslí, zda-li je kombinování nesourodých tříd opravdu nezbytné.

Řešení nabízejí role. Klíčové slovo has totiž přijímá jako parametr mimo jiné i traits=>[qw(role1 role2 ...)]. Trait je speciální role, která se použije na objekt a od běžných rolí se jinak ničím neliší.

Modifikujme tedy předchozí příklad tak, aby dělal to samé, ale využil přitom rolí.

Nejprve definujme parametry pro atribut_s_popiskem. Zde vložíme klíč traits, do kterého nyní zadáme pouze jednoprvkový seznam (ačkoliv bychom zde mohli použít více rolí).

has "atribut_s_popiskem" => (
    traits    => ["MojeTrida::Meta::Attribute::Trait::Popisek"],
    is        => "rw",
    isa       => "Str",
    popisek   => "Toto je meta-popisek atributu atribut_s_popiskem",
);

Podtřídu MojeTrida::Meta::Attribute::Popisek nahradíme naši novou rolí MojeTrida::Meta::Attribute::Trait::Popisek. Celkem bude vypadat následovně.

package MojeTrida::Meta::Attribute::Trait::Popisek;
use Moose::Role;

has "popisek" => (
      is        => "rw",
      isa       => "Str",
      predicate => "je_popisek"
);

V metodě metainfo pouze zaměníme volání metody isa na volání does. To proto, že metoda isa je vztah pro podtřídu, avšak nyní máme roli a tak použijeme does.

Vše ostatní může zůstat stejné. Nyní tedy pro přidání dalších atributů stačí do traits přidat MojeTrida::Meta::Attribute::Trait::Cokoliv a tuto roli implementovat podobně jako jsme to dělali u popisku.

Rozšíření Moose - MooseX

Jednou z aplikací meta API je též tzv. MooseX. Díky MooseX si každý může napsat vlastní Moose rozšíření. Řada rozšíření je již k dispozici na CPAN. Návod a možnosti pro rozšiřování je v dokumentaci.

Verze pro tisk

pridej.cz

 

DISKUZE

Nejsou žádné diskuzní příspěvky u dané položky.



Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

8.5.2016 17:19 /Redakce Linuxsoft.cz
PR: Dne 26.5.2016 proběhne v Praze konference Cloud computing v praxi. Tématy bude např. nejnovější trendy v oblasti cloudu a cloudových řešení, cloudové služby, infrastruktura cloudu, efektivní využití cloudu, možné nástrahy cloudů a jak se jim vyhnout
Přidat komentář

21.4.2016 8:01 /František Kučera
Spolek OpenAlt zve na 127. distribuovaný sraz příznivců svobodného softwaru a otevřených technologií (hardware, 3D tisk, SDR, DIY, makers…), který se bude konat ve čtvrtek 28. dubna od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

2.3.2016 22:41 /Ondřej Čečák
Letošní ročník konference InstallFest již tento víkend!
Přidat komentář

14.2.2016 16:39 /Redakce Linuxsoft.cz
O víkendu 5. a 6. března 2016 proběhne na pražském Strahově 8. ročník tradiční konference InstallFest. Celkem za dva dny uvidíte ​30 přednášek​ a ​6 workshopů.
Přidat komentář

5.2.2016 17:38 /Petr Ježek
Utilitka z XFce "xfce4-power-manager" nejen umožňuje nastavení lhůty pro uspání či hybernaci, ale i zapínání a vypínání prezentačního módu pro nerušené sledování videí. Stačí ji nastavit v každém vybavenějším panelu a v jakémkoli nontiled WM/DE.
Přidat komentář

10.1.2016 11:32 /Pavel `Goldenfish' Kysilka
LinuxMarket změnil provozovatele. Nově jej provozuje Marek Pszczolka. Více info a detaily #1 a #2.
Přidat komentář

29.12.2015 11:38 /Ondřej Čečák
Ještě posledních pár dní můžete přidávat příspěvky nebo nápady na Install Fest 2016, který se bude konat 5. a 6. března 2016.
Přidat komentář

8.12.2015 11:36 /Petr Ježek
Logické se stává realitou. LibreOffice a Thunderbird se mají dle článku na Redditu stát protiváhou MS řešení (MS Office a Outlook).
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

10.6.2016 21:10 / pavel riha
FreeBSD 10.3 a virtualizace

8.6.2016 21:56 / Milan Gallas
Nevalidní prefix m

7.5.2016 14:58 / Teodor Komárek
Soubory

20.4.2016 0:07 / Jakub Cleing
Sázkový panel PHP FUSION

9.4.2016 9:43 / jiwopene@gmail.com
Re: problém s dpkg a nemožností instalovat

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2016) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze