Как может я патч обезьяны метод экземпляра в Perl?

Предпочтительный подход

В Swift 2.0 Apple добавила проверку доступности с использованием гораздо более удобного синтаксиса (подробнее здесь ). Теперь вы можете проверить версию ОС с помощью более чистого синтаксиса:

if #available(iOS 9, *) {
    // Then we are on iOS 9
} else {
    // iOS 8 or earlier
}

Это предпочтительная проверка respondsToSelector и т. Д. ( Что нового в Swift ). Теперь компилятор всегда предупреждает вас, если вы не охраняете свой код должным образом.


Pre Swift 2.0

Новое в iOS 8 - NSProcessInfo, позволяющее улучшить семантическое управление версиями проверки.

Развертывание на iOS 8 и выше

Для минимальных целей развертывания iOS 8.0 или выше используйте NSProcessInfo operatingSystemVersion или isOperatingSystemAtLeastVersion.

blockquote>

Это даст следующее:

let minimumVersion = NSOperatingSystemVersion(majorVersion: 8, minorVersion: 1, patchVersion: 2)
if NSProcessInfo().isOperatingSystemAtLeastVersion(minimumVersion) {
    //current version is >= (8.1.2)
} else {
    //current version is < (8.1.2)
}

Развертывание на iOS 7

Для минимальных целей развертывания iOS 7.1 или ниже , используйте сравнение с NSStringCompareOptions.NumericSearch на UIDevice systemVersion.

blockquote>

Это даст:

let minimumVersionString = "3.1.3"
let versionComparison = UIDevice.currentDevice().systemVersion.compare(minimumVersionString, options: .NumericSearch)
switch versionComparison {
    case .OrderedSame, .OrderedDescending:
        //current version is >= (3.1.3)
        break
    case .OrderedAscending:
        //current version is < (3.1.3)
        fallthrough
    default:
        break;
}

Подробнее читается в NSHipster .

22
задан cdleary 17 January 2009 в 00:30
поделиться

7 ответов

Если динамический контекст (использование local) не является удовлетворительным, можно автоматизировать пользовательский метод переблагословения пакета:

MONKEY_PATCH_INSTANCE:
{
  my $counter = 1; # could use a state var in perl 5.10

  sub monkey_patch_instance
  {
    my($instance, $method, $code) = @_;
    my $package = ref($instance) . '::MonkeyPatch' . $counter++;
    no strict 'refs';
    @{$package . '::ISA'} = (ref($instance));
    *{$package . '::' . $method} = $code;
    bless $_[0], $package; # sneaky re-bless of aliased argument
  }
}

Использование в качестве примера:

package Dog;
sub new { bless {}, shift }
sub speak { print "woof!\n" }

...

package main;

my $dog1 = Dog->new;
my $dog2 = Dog->new;

monkey_patch_instance($dog2, speak => sub { print "yap!\n" });

$dog1->speak; # woof!
$dog2->speak; # yap!
16
ответ дан 29 November 2019 в 04:12
поделиться

Как ответил Fayland Lam , правильный синтаксис:

    local *LWP::UserAgent::get_basic_credentials = sub {
        return ( $username, $password );
    };

, Но это исправляет (динамично ограниченный по объему) целый класс и не только экземпляр. Можно, вероятно, сойти с рук это в случае.

, Если Вы действительно хотите влиять просто на экземпляр, используйте разделение на подклассы, Вы описали. Это может быть сделано 'на лету' как это:

{
   package My::LWP::UserAgent;
   our @ISA = qw/LWP::UserAgent/;
   sub get_basic_credentials {
      return ( $username, $password );
   };

   # ... and rebless $agent into current package
   $agent = bless $agent;
}
20
ответ дан Community 29 November 2019 в 04:12
поделиться
sub _user_agent_get_basic_credentials_patch {
  return ($username, $password);
}

my $agent = LWP::UserAgent->new();
$agent->get_basic_credentials = _user_agent_get_basic_credentials_patch;

Вы не имеете 1, но 2 проблемы здесь, потому что это - то, что Вы делаете:

( $agent->get_basic_credentials() ) = _user_agent_get_basic_credentials_patch(); 

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

assign the result of 
              '_user_agent_get_basic_credentials_patch' 
to the value that was returned from
              'get_basic_credentials';

Эквивалентная логика:

{
   package FooBar; 
   sub foo(){ 
         return 5; 
   }
   1;
}
my $x =  bless( {}, "FooBar" ); 
sub baz(){ 
      return 1; 
}
$x->foo() = baz(); 
#   5 = 1;  

Так ее неудивительное его жалоба.

Ваш "фиксированный" код в Вашем ответе является также неправильным, по той же причине, с другой проблемой, которую Вы не можете понять:

 $agent->{get_basic_credentials} = _user_agent_get_basic_credentials_patch;

Это скорее испорчено логика, думая, что она работает как Вы, думают, что она делает.

то, Что это действительно делает:

1. Dereference $agent, which is a HashRef
2. Set the hash-key 'get_basic_credentials' to the result from _user_agent_get_basic_credentials_patch

Вы не присваивали функции вообще.

{
package FooBar; 
sub foo(){ 
     return 5; 
} 
1;
}
my $x =  bless( {}, "FooBar" ); 
sub baz(){ 
  return 1; 
}
$x->{foo} = baz(); 
#  $x is now  = ( bless{ foo => 1 }, "FooBar" ); 
#  $x->foo(); # still returns 5
#  $x->{foo}; # returns 1; 

исправление Обезьяны является довольно злым, конечно, и я самостоятельно не видел, как переопределить метод на исключительном экземпляре чего-то как этот.

Однако то, что можно сделать, является этим:

  {
     no strict 'refs'; 
     *{'LWP::UserAgent::get_basic_credentials'} = sub { 
         # code here 

     }; 
  }

, Который глобально заменит get_basic_credentials поведение секций кода (я мог бы быть неправым несколько, кто-то исправляет меня)

, Если Вы действительно потребность сделать это на основе на экземпляр Вы могли бы, вероятно, сделать немного наследования классов и просто создать производный класс вместо этого, и/или динамично создать новые пакеты.

6
ответ дан Kent Fredric 29 November 2019 в 04:12
поделиться

Perl думает, что Вы пытаетесь назвать подпрограмму слева от присвоения, которое является, почему это жалуется. Я думаю, что можно быть в состоянии бить таблицу символов Perl непосредственно (использующий *LWP::UserAgent::get_basic_credentials или что-то), но я испытываю недостаток в Perl-fu для корректного создания того колдовства.

2
ответ дан Greg Hewgill 29 November 2019 в 04:12
поделиться

Редактирование: Это было неправильной попыткой решения, которое я сохраняю для потомства. Посмотрите на ответы upvoted/accepted.:-)

А-ч, я просто понял, что синтаксису нужна определенная корректировка:

$agent->{get_basic_credentials} = _user_agent_get_basic_credentials_patch;

Без эти {} разделители это похоже на вызов метода (который не был бы допустимым l-значением).

я все еще хотел бы знать, как метод экземпляра связывается/смотрится через этот синтаксис. TIA!

-1
ответ дан 2 revs 29 November 2019 в 04:12
поделиться

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

Я НЕ рекомендую Вам, на самом деле делая это в любом коде, который кто-либо еще должен будет поддерживать, отладить или зависеть от (как Вы, сказал, соглашающиеся взрослые):

#!/usr/bin/perl

use strict;
use warnings;
{

    package Monkey;

    sub new { return bless {}, shift }
    sub bar { return 'you called ' . __PACKAGE__ . '::bar' }
}

use Scalar::Util qw(refaddr);

my $f = Monkey->new;
my $g = Monkey->new;
my $h = Monkey->new;

print $f->bar, "\n";    # prints "you called Monkey::bar"

monkey_patch( $f, 'bar', sub { "you, sir, are an ape" } );
monkey_patch( $g, 'bar', sub { "you, also, are an ape" } );

print $f->bar, "\n";    # prints "you, sir, are an ape"
print $g->bar, "\n";    # prints "you, also, are an ape"
print $h->bar, "\n";    # prints "you called Monkey::bar"

my %originals;
my %monkeys;

sub monkey_patch {
    my ( $obj, $method, $new ) = @_;
    my $package = ref($obj);
    $originals{$method} ||= $obj->can($method) or die "no method $method in $package";
    no strict 'refs';
    no warnings 'redefine';
    $monkeys{ refaddr($obj) }->{$method} = $new;
    *{ $package . '::' . $method } = sub {
        if ( my $monkey_patch = $monkeys{ refaddr( $_[0] ) }->{$method} ) {
            return $monkey_patch->(@_);
        } else {
            return $originals{$method}->(@_);
        }
    };
}
7
ответ дан 29 November 2019 в 04:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: