File Coverage

blib/lib/Glib/Ex/TieProperties.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # Copyright 2009, 2010, 2011, 2012, 2014 Kevin Ryde
2              
3             # This file is part of Glib-Ex-ObjectBits.
4             #
5             # Glib-Ex-ObjectBits is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Glib-Ex-ObjectBits is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Glib-Ex-ObjectBits. If not, see .
17              
18              
19             package Glib::Ex::TieProperties;
20 2     2   1295 use 5.008;
  2         6  
  2         76  
21 2     2   8 use strict;
  2         3  
  2         50  
22 2     2   9 use warnings;
  2         3  
  2         47  
23 2     2   10 use Carp;
  2         3  
  2         182  
24 2     2   3494 use Glib;
  0            
  0            
25              
26             our $VERSION = 16;
27              
28             use constant DEBUG => 0;
29              
30             sub new {
31             tie my(%hash), shift, @_;
32             return \%hash;
33             }
34             sub in_object {
35             my ($class, $obj, %option) = @_;
36             $option{'weak'} = 1;
37             my $field = delete $option{'field'};
38             if (! defined $field) { $field = 'property'; }
39             tie my(%hash), $class, $obj, %option;
40             return ($obj->{$field} = \%hash);
41             }
42             sub object {
43             return $_[0]->[0];
44             }
45              
46             # $self is an arrayref, created as one element just for _OBJ, with a second
47             # for _KEYS on-demand..
48             #
49             # $self->[_OBJ] is the target Glib::Object
50             #
51             # $self->[_KEYS] is an arrayref of keys (string property names) to return
52             # from FIRSTKEY/NEXTKEY, with NEXTKEY shifting off one per call.
53             #
54             use constant { _OBJ => 0,
55             _KEYS => 1 };
56              
57             # Think about:
58             # error_on_fetch
59             # error_on_store
60             #
61             sub TIEHASH {
62             my ($class, $obj, %option) = @_;
63             (ref $obj) || croak "$class needs an object to tie";
64             my $self = bless [ $obj ], $class;
65             if ($option{'weak'}) {
66             require Scalar::Util;
67             Scalar::Util::weaken ($self->[_OBJ]);
68             }
69             return $self;
70             }
71             sub FETCH {
72             my ($self, $key) = @_;
73             if (my $obj = $self->[_OBJ]) { # when not weakened away
74             if (my $pspec = $obj->find_property ($key)) { # when known property
75             if ($pspec->{'flags'} >= 'readable') { # when readable
76             return $obj->get_property($key);
77             }
78             }
79             }
80             return undef; # otherwise
81             }
82             sub STORE {
83             my ($self, $key, $value) = @_;
84             my $obj = $self->[_OBJ] || return; # do nothing if weakened away
85             $obj->set_property ($key, $value);
86             }
87             sub EXISTS {
88             my ($self, $key) = @_;
89             my $obj = $self->[_OBJ] || return 0; # if weakened away
90             return defined ($obj->find_property($key));
91             }
92             sub DELETE { croak 'Cannot delete object properties' }
93             BEGIN {
94             no warnings;
95             *CLEAR = \&DELETE;
96             }
97              
98             sub FIRSTKEY {
99             my ($self) = @_;
100             my $obj = $self->[_OBJ] || return undef; # if weakened away
101             @{$self->[_KEYS]} = map {$_->{'name'}} $obj->list_properties;
102             goto &NEXTKEY;
103             }
104             sub NEXTKEY {
105             return shift @{$_[0]->[_KEYS]};
106             }
107              
108             # Return true if at least one property, this new in 5.8.3.
109             # Mimic the "8/8" bucket of a real hash because it's easy enough to do.
110             #
111             # It's pretty wasteful getting the full list of pspecs then throwing them
112             # away, but g_object_class_list_properties() is about the only way to check
113             # if there's any, and $obj->list_properties() is the only interface to that
114             # function.
115             #
116             sub SCALAR {
117             my ($self) = @_;
118             if (my $obj = $self->[_OBJ]) { # when not weakened away
119             my @pspecs = $obj->list_properties;
120             if (my $len = scalar(@pspecs)) { # buckets only if not empty
121             return "$len/$len";
122             }
123             }
124             return 0; # false for no properties
125             }
126              
127             1;
128             __END__