【问题标题】:Is there a simple way to test if a Moose attribute is read-only?有没有一种简单的方法来测试 Moose 属性是否是只读的?
【发布时间】:2010-04-01 18:41:21
【问题描述】:

我目前使用块eval 来测试我已将属性设置为只读。有没有更简单的方法来做到这一点?

工作代码示例:

#Test that sample_for is ready only
eval { $snp_obj->sample_for('t/sample_manifest2.txt');};
like($@, qr/read-only/xms, "'sample_for' is read-only");



更新

感谢 Friedo、Ether 和 Robert P 的回答,感谢 Ether、Robert P 和 jrockway 的 cmets。

我喜欢 Ether 的答案如何通过用 ! 否定它来确保 $is_read_only 只是一个真值或假值(即但绝不是 coderef)。 Double negation 也提供了这一点。因此,您可以在 is() 函数中使用 $is_read_only,而无需打印出 coderef。

有关最完整的答案,请参阅下面 Robert P 的答案。每个人都非常乐于助人,并建立在彼此的答案和 cmets 之上。总的来说,我认为他对我的帮助最大,因此他现在被标记为已接受的答案。再次感谢 Ether、Robert P、frido 和 jrockway。



如果您可能想知道,就像我一开始所做的那样,这里是关于 get_attributefind_attribute_by_name (from Class::MOP::Class) 之间区别的文档:

$metaclass->get_attribute($attribute_name)

    This will return a Class::MOP::Attribute for the specified $attribute_name. If the 
    class does not have the specified attribute, it returns undef.

    NOTE that get_attribute does not search superclasses, for that you need to use
    find_attribute_by_name.

【问题讨论】:

  • 最好写成ok($snp_obj->meta->get_attribute('sample_for')->get_write_method(), "'sample_for' is read-only"); -- 在测试失败时,is() 打印第二个参数(这将是一个代码引用).. 更不用说你有第一个和第二个参数颠倒了:is($has, $expected, $test_name).
  • 如果你的@attribute_names 数组是精心构造的,你应该没问题;但如果该属性不存在,你会爆炸:)
  • +1 用于注意如何在超类中定位属性

标签: perl testing tdd attributes moose


【解决方案1】:

从技术上讲,属性不需要具有读取或写入方法。 大多数情况下会,但并非总是如此。下面是一个例子(从jrockway's comment 偷来的):

has foo => ( 
    isa => 'ArrayRef', 
    traits => ['Array'], 
    handles => { add_foo => 'push', get_foo => 'pop' }
)

此属性将存在,​​但没有标准的读取器和写入器。

因此,要在每种情况下测试属性已定义为is => 'RO',您需要同时检查写入和读取方法。你可以用这个子程序来做:

# returns the read method if it exists, or undef otherwise.
sub attribute_is_read_only {
    my ($obj, $attribute_name) = @_;
    my $attribute = $obj->meta->get_attribute($attribute_name);

    return unless defined $attribute;
    return (! $attribute->get_write_method() && $attribute->get_read_method());
}

或者,您可以在最后一个 return 之前添加双重否定来布尔化返回值:

return !! (! $attribute->get_write_method() && $attribute->get_read_method());

【讨论】:

    【解决方案2】:

    Class::MOP::Attribute 中所述:

    my $attr = $this->meta->find_attribute_by_name($attr_name);
    my $is_read_only = ! $attr->get_write_method();
    

    $attr->get_write_method() 将获取 writer 方法(您创建的一个或生成的一个),如果没有,则为 undef。

    【讨论】:

    • 谢谢!知道它返回 undef 允许进行单行测试(我尝试在此处发布它,但看起来不太漂亮)。
    • 好吧,实际上...这测试它是否有一个 write 方法。不过,这并不能测试它是否有 read 方法。从技术上讲,它也不需要。如果没有它不是一个非常有用的属性,但你可以拥有它!
    • @Robert:是的,严格来说,它会检查属性是否“不可写”(不是 isa => 'rw'),这与“只读”(isa => '罗')。
    • 没有阅读器的属性非常有用。考虑has foo => ( isa => 'ArrayRef', traits => ['Array'], handles => { add_foo => 'push', get_foo => 'pop' }) 的情况。无需阅读器!
    • @jrockway 这是没有读者或作者的属性的一个很好的例子。谢谢!
    【解决方案3】:

    你应该可以从对象的元类中得到这个:

    unless ( $snp_obj->meta->get_attribute( 'sample_for' )->get_write_method ) { 
        # no write method, so it's read-only
    }
    

    请参阅Class::MOP::Attribute 了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-15
      • 2010-11-19
      • 2021-06-27
      • 2017-02-19
      • 1970-01-01
      • 1970-01-01
      • 2010-10-30
      • 1970-01-01
      相关资源
      最近更新 更多