File Coverage

blib/lib/JSON/Karabiner/Manipulator.pm
Criterion Covered Total %
statement 198 218 90.8
branch 48 78 61.5
condition 15 21 71.4
subroutine 27 29 93.1
pod 4 11 36.3
total 292 357 81.7


line stmt bran cond sub pod time code
1             package JSON::Karabiner::Manipulator ;
2             $JSON::Karabiner::Manipulator::VERSION = '0.017';
3 19     19   262877 use strict;
  19         64  
  19         591  
4 19     19   98 use warnings;
  19         42  
  19         455  
5 19     19   92 use Carp;
  19         76  
  19         1038  
6 19     19   114 use Exporter;
  19         37  
  19         5165  
7             our @EXPORT = qw'new_manipulator add_action add_description add_condition add_parameter add_key_code
8             add_key_code add_any add_optional_modifiers add_mandatory_modifiers add_simultaneous add_simultaneous_options add_consumer_key_code add_pointing_button add_shell_command add_select_input_source add_set_variable add_mouse_key add_modifiers
9             add_identifier add_description add_value add_bundle_identifiers add_file_path add_input_source add_keyboard_types add_variable add_description _dump_json _fake_write_file write_file set_filename set_title set_rule_name set_save_dir';
10              
11             sub import {
12 2     2   28 strict->import;
13 2         27 warnings->import;
14 2         4426 goto &Exporter::import
15             }
16              
17             sub new_manipulator {
18 30     30 0 1218 my @caller = caller(0);
19 30 100       929 my $called_directly = $caller[0] eq 'main' ? 1 : 0;
20 30 100 100     146 if ($main::current_manip && $called_directly) {
21 1         5 write_file($main::file_title_written);
22             }
23 30         92 my $class = 'JSON::Karabiner::Manipulator';
24              
25             # trash the first arg if this is using the old school OO interface
26 30 100 66     270 shift if $_[0] && $_[0] =~ /^JSON::Karabiner::Manipulator$/;
27              
28 30         87 my @kb_obj_args = @_;
29              
30             # derive the filename from the called script
31 19     19   151 { no warnings 'once';
  19         63  
  19         4262  
  30         51  
32 30 100 66     568 if (!$main::save_to_file_name && $called_directly) {
33              
34 3         9 my $program_name = $0;
35 3         20 $program_name =~ s/^.*[\/\\]//;
36 3         15 $program_name =~ s/\..*$//;
37 3         7 $program_name = "$program_name.json";
38 3         8 push @kb_obj_args, $program_name;
39 3         7 $main::save_to_file_name = $program_name;
40             } else {
41 27 50       87 push @kb_obj_args, $main::save_to_file_name if $main::save_to_file_name;
42             }
43              
44 30 100       98 if ($called_directly) {
45 3 50       21 unshift @kb_obj_args, $main::rule_name if $main::rule_name;
46 3         7 my $save_to_dir = $main::save_to_dir;
47 3 50       9 if ($save_to_dir) {
48 0         0 push @kb_obj_args, { mod_file_dir => $save_to_dir };
49             }
50             }
51             }
52              
53              
54 30         139 my $self = {
55             actions => {},
56             _disable_validity_tests => 0,
57             _kb_obj_args => \@kb_obj_args,
58             _fake_write_flag => 0,
59             };
60 30         89 bless $self, $class;
61             {
62 19     19   154 no warnings 'once';
  19         45  
  19         3393  
  30         50  
63 30         73 $main::current_manip = $self;
64             }
65 30         126 return $self;
66             }
67              
68             sub set_filename {
69 0     0 0 0 my $fn = shift;
70 0 0       0 croak 'You must pass a file name' unless $fn;
71              
72 0 0       0 if ($fn !~ /\.json$/) {
73 0         0 $fn = $fn . '.json';
74             }
75              
76 0         0 $main::save_to_file_name = $fn;
77             }
78              
79             sub set_save_dir {
80 0     0 0 0 my $sd = shift;
81 0 0       0 croak 'You must pass a file name' unless $sd;
82 19     19   146 { no warnings 'once';
  19         45  
  19         2378  
  0         0  
83 0         0 $main::save_to_dir = $sd;
84             }
85             }
86              
87             sub set_title {
88 1     1 0 2116 my $title = shift;
89 1 50       5 croak 'You must pass a file name' unless $title;
90              
91 1         5 $main::file_title_written = $title;
92             }
93              
94             sub set_rule_name {
95 2     2 0 2431 my $rule_name = shift;
96 2 50       9 croak 'You must pass a rule name' unless $rule_name;
97              
98 19     19   138 { no warnings 'once';
  19         40  
  19         3269  
  2         4  
99 2         10 $main::rule_name = $rule_name;
100             }
101             }
102              
103             sub AUTOLOAD {
104 18     18   1985 our $AUTOLOAD;
105 18         41 my $program = $AUTOLOAD;
106 18         142 my ($func) = $program =~ /.*::(.*)$/;
107 18         92 my @action_functions = qw (add_key_code add_any add_optional_modifiers add_mandatory_modifiers add_simultaneous add_simultaneous_options add_consumer_key_code add_pointing_button add_shell_command add_select_input_source add_set_variable add_mouse_key add_modifiers);
108              
109 18         44 my $is_action_function = grep { $_ eq $func } @action_functions;
  234         413  
110 18 100       61 if ($is_action_function) {
111 6         10 my $current_action;
112             {
113 19     19   166 no warnings 'once';
  19         52  
  19         2268  
  6         10  
114 6         11 $current_action = $main::current_action;
115             }
116 6         26 $current_action->$func(@_);
117 6         24 return;
118             }
119              
120 12         57 my @condition_functions = qw(add_identifier add_description add_value add_bundle_identifiers add_file_path add_input_source add_keyboard_types add_variable add_description);
121              
122 12         27 my $is_condition_function = grep { $_ eq $func } @condition_functions;
  108         184  
123 12 50       710 if ($is_condition_function) {
124 0         0 my $current_condition;
125             {
126 19     19   165 no warnings 'once';
  19         44  
  19         23009  
  0         0  
127 0         0 $current_condition = $main::current_condition;
128             }
129 0         0 $current_condition->$func(@_);
130 0         0 return;
131             }
132              
133             }
134              
135             sub _get_args {
136 40     40   106 my @args = @_;
137 40 50       115 croak "No args passed" unless @args;
138              
139 40         80 my $s = shift;
140 40         81 my $type;
141 40 100       119 if (ref $s) {
142 34         84 $type = shift;
143             } else {
144 6         13 $type = $s;
145 6         12 $s = $main::current_manip;
146             }
147 40         135 return ($s, $type, @_);
148             }
149              
150             sub add_action {
151 31     31 1 3505 my ($s, $type) = _get_args(@_);
152 31 50       89 croak 'To add a action, you must tell me which kind you\'d like to add' if !$type;
153              
154 31         107 my $uctype = ucfirst($type);
155 31         93 my $package = "JSON::Karabiner::Manipulator::Actions::" . $uctype;
156 31         2283 eval "require $package";
157 31         270 my $action = $package->new($type);
158 30         60 my %hash = %{$s->{actions}};
  30         155  
159 30         73 $type = $action->{def_name};
160 30         78 $hash{$type} = $action->{data};
161 30         89 $s->{actions} = \%hash;
162 30         115 return $action;
163             }
164              
165             sub add_condition {
166 7     7 1 2203 my ($s, $type) = _get_args(@_);
167 7 50       20 croak 'To add a condition, you must tell me which kind you\'d like to add' if !$type;
168              
169 7         19 my $uctype = ucfirst($type);
170 7         19 my $package = "JSON::Karabiner::Manipulator::Conditions::" . $uctype;
171 7         472 eval "require $package";
172 7         72 my $condition = $package->new($type);
173 7 100       28 if (defined $s->{actions}{conditions}) {
174 5         7 push @{$s->{actions}{conditions}}, $condition;
  5         16  
175             } else {
176 2         9 $s->{actions}{conditions} = [ $condition ];
177             }
178 7         33 return $condition;
179             }
180              
181             sub add_description {
182 1     1 1 371 my ($s, $desc) = _get_args(@_);
183              
184 1 50       4 croak 'To add a description, you must provide one' if !$desc;
185 1         15 $s->{actions}{description} = $desc;
186             }
187              
188             sub add_parameter {
189 1     1 1 337 my ($s, $param, $value) = _get_args(@_);
190 1 50       3 croak 'To add a parameter, you must tell me which kind you\'d like to add' if !$param;
191 1 50       3 croak 'To add a parameter, you must provide a value' if !$value;
192              
193 1         4 my @acceptable_values = qw( to_if_alone_timeout_milliseconds
194             alone_timeout
195             alone
196             to_if_held_down_threshold_milliseconds
197             held_down_threshold
198             down_threshold
199             held_down
200             down
201             to_delayed_action_delay_milliseconds
202             delayed_action_delay
203             action_delay
204             delay
205             simultaneous_threshold_milliseconds
206             simultaneous_threshold
207             simultaneous
208             );
209              
210 1         3 my $param_exists = grep { $param eq $_ } @acceptable_values;
  15         25  
211 1 50       5 croak "'$param' in an unrecognzed parameter" unless $param_exists;
212              
213             # get param full name
214 1 50       5 if ($param =~ /alone/) {
    0          
    0          
    0          
215 1         3 $param = 'to_if_alone_timeout_milliseconds';
216             } elsif ($param =~ /down/) {
217 0         0 $param = 'to_if_held_down_threshold_milliseconds';
218             } elsif ($param =~ /delay/) {
219 0         0 $param = 'to_delayed_action_delay_milliseconds';
220             } elsif ($param =~ /simultaneous/) {
221 0         0 $param = 'simultaneous_threshold_milliseconds';
222             }
223              
224 1         11 $s->{actions}{parameters}{"basic.$param"} = $value;
225             }
226              
227             sub TO_JSON {
228 32     32 0 79 my $obj = shift;
229             #TODO: Change this under certain conditions
230 32         86 $obj->{actions}{type} = 'basic';
231 32 100       126 $obj->_do_validity_checks($obj->{actions}) unless $obj->{_disable_validity_tests};
232 29         514 return $obj->{actions};
233             }
234              
235             sub _do_validity_checks {
236 11     11   18 my $s = shift;
237 11         24 my $actions = shift;
238 11         30 my $from = $actions->{from};
239 11         27 $s->_do_from_validity_checks($from);
240             }
241              
242             sub _dump_json {
243 3     3   506 my $s = $main::current_manip;
244 3         7 my @kb_obj_args = @{$s->{_kb_obj_args}};
  3         8  
245 3 100       10 if (!@kb_obj_args) {
246 2         31 croak "The _dump_json method cannot be run on this manipulator.";
247             }
248              
249 1         8 require JSON::Karabiner;
250 1         3 my $little_title = shift @kb_obj_args;
251 1         3 unshift @kb_obj_args, 'SET WITH write_file METHOD';
252 1         4 my $kb_obj = JSON::Karabiner->new( @kb_obj_args );
253              
254 1         6 my $rule = $kb_obj->add_rule($little_title);
255 1         4 my $temp_manip = $rule->add_manipulator();
256 1         2 %{$temp_manip} = %{$s};
  1         5  
  1         4  
257 1         5 $kb_obj->_dump_json;
258             }
259              
260             sub write_file {
261 4     4 0 8 my $s = $main::current_manip;
262 4 100 66     39 shift if $_[0] && (ref $_[0]) =~ /^JSON::Karabiner::Manipulator$/;
263 4         7 my $title = shift;
264              
265 4         9 my $filename;
266 4 50 66     19 if ($title && $title =~ /\.json$/) {
267 0         0 $filename = $title;
268             } else {
269 4   66     20 $filename = shift || $main::save_to_file_name || $main::file_written;
270             }
271              
272 4         9 my @kb_obj_args = @{$s->{_kb_obj_args}};
  4         12  
273 4 50       12 if (!@kb_obj_args) {
274 0         0 croak "The _write_file method cannot be run on this manipulator.";
275             }
276              
277 4 50 66     14 croak 'You must supply a title for the first manipulator' if !$title && !$main::file_title_written;
278 4 100       11 if (!$title) {
279 1         3 $title = $main::file_title_written;
280             }
281              
282 4         1134 require JSON::Karabiner;
283 4         19 my $little_title = shift @kb_obj_args;
284 4         10 unshift @kb_obj_args, $title;
285 4         9 $kb_obj_args[1] = $filename;
286              
287 4         23 my $kb_obj = JSON::Karabiner->new( @kb_obj_args );
288 4 50       15 if ($s->{_fake_write_flag}) {
289 4         18 $kb_obj->{_fake_write_flag} = 1;
290             }
291 4         17 my $rule = $kb_obj->add_rule($little_title);
292 4         13 my $temp_manip = $rule->add_manipulator();
293 4         7 %{$temp_manip} = %{$s};
  4         18  
  4         12  
294 4         16 $kb_obj->write_file();
295 4         6 $kb_obj->{_fake_write_flag} = 0;
296             {
297 19     19   164 no warnings 'once';
  19         39  
  19         4898  
  4         10  
298 4         8 $main::file_written = $kb_obj_args[1];
299 4         36 $main::file_title_written = $kb_obj_args[0];
300             }
301              
302             }
303              
304             sub _fake_write_file {
305 5     5   1839 my $s = $main::current_manip;
306 5         10 my $title = shift;
307 5         8 my $file_name = shift;
308              
309 5         9 my @kb_obj_args = @{$s->{_kb_obj_args}};
  5         16  
310 5 100       16 if (!@kb_obj_args) {
311 2         24 croak "The _fake_write method cannot be run on this manipulator.";
312             }
313              
314 3         6 $s->{_fake_write_flag} = 1;
315 3         12 $s->write_file($title, $file_name);
316 3         21 $s->{_fake_write_flag} = 0;
317             }
318              
319             sub _do_from_validity_checks {
320 11     11   17 my $s = shift;
321 11         17 my $from = shift;
322              
323 11 100       41 if (! defined $from) {
324 2         24 croak "No 'from' action found in the manipulator. You must add a 'from' action.'";
325             }
326              
327 9 100       42 if (! %$from) {
328 1         10 croak "The 'from' action is empty. Perform methods on the 'from' action to tell it how to behave.";
329             }
330              
331 8         16 return;
332              
333             # my @from_keys = keys %$from;
334             # my $has_key_code = grep { $_ =~ /^any|consumer_key_code|key_code$/ } @from_keys;
335             # if (!$has_key_code && grep { $_ =~ /modifiers/ } @from_keys) {
336             # croak "You cannot have modifiers without anything to modify in a 'from' action.";
337             # }
338             }
339              
340             # ABSTRACT: manipulator object for containing and outputting its data
341              
342             1;
343              
344             __END__