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 10 11 90.9
total 298 357 83.4


line stmt bran cond sub pod time code
1             package JSON::Karabiner::Manipulator ;
2             $JSON::Karabiner::Manipulator::VERSION = '0.018';
3 19     19   246913 use strict;
  19         78  
  19         570  
4 19     19   109 use warnings;
  19         38  
  19         463  
5 19     19   91 use Carp;
  19         52  
  19         1052  
6 19     19   154 use Exporter;
  19         52  
  19         4753  
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   27 strict->import;
13 2         26 warnings->import;
14 2         4270 goto &Exporter::import
15             }
16              
17             sub new_manipulator {
18 30     30 1 1224 my @caller = caller(0);
19 30 100       971 my $called_directly = $caller[0] eq 'main' ? 1 : 0;
20 30 100 100     179 if ($main::current_manip && $called_directly) {
21 1         3 write_file($main::file_title_written);
22             }
23 30         66 my $class = 'JSON::Karabiner::Manipulator';
24              
25             # trash the first arg if this is using the old school OO interface
26 30 100 66     241 shift if $_[0] && $_[0] =~ /^JSON::Karabiner::Manipulator$/;
27              
28 30         91 my @kb_obj_args = @_;
29              
30             # derive the filename from the called script
31 19     19   151 { no warnings 'once';
  19         54  
  19         4374  
  30         67  
32 30 100 66     159 if (!$main::save_to_file_name && $called_directly) {
33              
34 3         11 my $program_name = $0;
35 3         18 $program_name =~ s/^.*[\/\\]//;
36 3         17 $program_name =~ s/\..*$//;
37 3         8 $program_name = "$program_name.json";
38 3         8 push @kb_obj_args, $program_name;
39 3         6 $main::save_to_file_name = $program_name;
40             } else {
41 27 50       78 push @kb_obj_args, $main::save_to_file_name if $main::save_to_file_name;
42             }
43              
44 30 100       87 if ($called_directly) {
45 3 50       22 unshift @kb_obj_args, $main::rule_name if $main::rule_name;
46 3         8 my $save_to_dir = $main::save_to_dir;
47 3 50       10 if ($save_to_dir) {
48 0         0 push @kb_obj_args, { mod_file_dir => $save_to_dir };
49             }
50             }
51             }
52              
53              
54 30         154 my $self = {
55             actions => {},
56             _disable_validity_tests => 0,
57             _kb_obj_args => \@kb_obj_args,
58             _fake_write_flag => 0,
59             };
60 30         88 bless $self, $class;
61             {
62 19     19   157 no warnings 'once';
  19         40  
  19         3453  
  30         59  
63 30         63 $main::current_manip = $self;
64             }
65 30         130 return $self;
66             }
67              
68             sub set_filename {
69 0     0 1 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 1 0 my $sd = shift;
81 0 0       0 croak 'You must pass a file name' unless $sd;
82 19     19   160 { no warnings 'once';
  19         38  
  19         2305  
  0         0  
83 0         0 $main::save_to_dir = $sd;
84             }
85             }
86              
87             sub set_title {
88 1     1 1 2015 my $title = shift;
89 1 50       4 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 1 2380 my $rule_name = shift;
96 2 50       8 croak 'You must pass a rule name' unless $rule_name;
97              
98 19     19   133 { no warnings 'once';
  19         54  
  19         3217  
  2         4  
99 2         9 $main::rule_name = $rule_name;
100             }
101             }
102              
103             sub AUTOLOAD {
104 18     18   1873 our $AUTOLOAD;
105 18         37 my $program = $AUTOLOAD;
106 18         122 my ($func) = $program =~ /.*::(.*)$/;
107 18         91 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         394  
110 18 100       58 if ($is_action_function) {
111 6         11 my $current_action;
112             {
113 19     19   139 no warnings 'once';
  19         50  
  19         2205  
  6         9  
114 6         12 $current_action = $main::current_action;
115             }
116 6         25 $current_action->$func(@_);
117 6         27 return;
118             }
119              
120 12         49 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         25 my $is_condition_function = grep { $_ eq $func } @condition_functions;
  108         179  
123 12 50       705 if ($is_condition_function) {
124 0         0 my $current_condition;
125             {
126 19     19   150 no warnings 'once';
  19         42  
  19         23087  
  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   119 my @args = @_;
137 40 50       156 croak "No args passed" unless @args;
138              
139 40         90 my $s = shift;
140 40         75 my $type;
141 40 100       124 if (ref $s) {
142 34         79 $type = shift;
143             } else {
144 6         11 $type = $s;
145 6         13 $s = $main::current_manip;
146             }
147 40         143 return ($s, $type, @_);
148             }
149              
150             sub add_action {
151 31     31 1 3462 my ($s, $type) = _get_args(@_);
152 31 50       103 croak 'To add a action, you must tell me which kind you\'d like to add' if !$type;
153              
154 31         126 my $uctype = ucfirst($type);
155 31         95 my $package = "JSON::Karabiner::Manipulator::Actions::" . $uctype;
156 31         2464 eval "require $package";
157 31         315 my $action = $package->new($type);
158 30         60 my %hash = %{$s->{actions}};
  30         148  
159 30         74 $type = $action->{def_name};
160 30         72 $hash{$type} = $action->{data};
161 30         90 $s->{actions} = \%hash;
162 30         110 return $action;
163             }
164              
165             sub add_condition {
166 7     7 1 2132 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         20 my $uctype = ucfirst($type);
170 7         16 my $package = "JSON::Karabiner::Manipulator::Conditions::" . $uctype;
171 7         490 eval "require $package";
172 7         70 my $condition = $package->new($type);
173 7 100       27 if (defined $s->{actions}{conditions}) {
174 5         10 push @{$s->{actions}{conditions}}, $condition;
  5         16  
175             } else {
176 2         23 $s->{actions}{conditions} = [ $condition ];
177             }
178 7         33 return $condition;
179             }
180              
181             sub add_description {
182 1     1 1 338 my ($s, $desc) = _get_args(@_);
183              
184 1 50       7 croak 'To add a description, you must provide one' if !$desc;
185 1         16 $s->{actions}{description} = $desc;
186             }
187              
188             sub add_parameter {
189 1     1 1 348 my ($s, $param, $value) = _get_args(@_);
190 1 50       4 croak 'To add a parameter, you must tell me which kind you\'d like to add' if !$param;
191 1 50       2 croak 'To add a parameter, you must provide a value' if !$value;
192              
193 1         5 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         2 my $param_exists = grep { $param eq $_ } @acceptable_values;
  15         25  
211 1 50       4 croak "'$param' in an unrecognzed parameter" unless $param_exists;
212              
213             # get param full name
214 1 50       4 if ($param =~ /alone/) {
    0          
    0          
    0          
215 1         2 $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 84 my $obj = shift;
229             #TODO: Change this under certain conditions
230 32         85 $obj->{actions}{type} = 'basic';
231 32 100       119 $obj->_do_validity_checks($obj->{actions}) unless $obj->{_disable_validity_tests};
232 29         515 return $obj->{actions};
233             }
234              
235             sub _do_validity_checks {
236 11     11   16 my $s = shift;
237 11         17 my $actions = shift;
238 11         18 my $from = $actions->{from};
239 11         35 $s->_do_from_validity_checks($from);
240             }
241              
242             sub _dump_json {
243 3     3   585 my $s = $main::current_manip;
244 3         6 my @kb_obj_args = @{$s->{_kb_obj_args}};
  3         8  
245 3 100       8 if (!@kb_obj_args) {
246 2         33 croak "The _dump_json method cannot be run on this manipulator.";
247             }
248              
249 1         6 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         4 my $rule = $kb_obj->add_rule($little_title);
255 1         3 my $temp_manip = $rule->add_manipulator();
256 1         3 %{$temp_manip} = %{$s};
  1         4  
  1         4  
257 1         23 $kb_obj->_dump_json;
258             }
259              
260             sub write_file {
261 4     4 1 10 my $s = $main::current_manip;
262 4 100 66     31 shift if $_[0] && (ref $_[0]) =~ /^JSON::Karabiner::Manipulator$/;
263 4         8 my $title = shift;
264              
265 4         7 my $filename;
266 4 50 66     21 if ($title && $title =~ /\.json$/) {
267 0         0 $filename = $title;
268             } else {
269 4   66     19 $filename = shift || $main::save_to_file_name || $main::file_written;
270             }
271              
272 4         16 my @kb_obj_args = @{$s->{_kb_obj_args}};
  4         12  
273 4 50       13 if (!@kb_obj_args) {
274 0         0 croak "The _write_file method cannot be run on this manipulator.";
275             }
276              
277 4 50 66     13 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         1085 require JSON::Karabiner;
283 4         14 my $little_title = shift @kb_obj_args;
284 4         10 unshift @kb_obj_args, $title;
285 4         8 $kb_obj_args[1] = $filename;
286              
287 4         21 my $kb_obj = JSON::Karabiner->new( @kb_obj_args );
288 4 50       14 if ($s->{_fake_write_flag}) {
289 4         19 $kb_obj->{_fake_write_flag} = 1;
290             }
291 4         13 my $rule = $kb_obj->add_rule($little_title);
292 4         12 my $temp_manip = $rule->add_manipulator();
293 4         6 %{$temp_manip} = %{$s};
  4         17  
  4         14  
294 4         15 $kb_obj->write_file();
295 4         8 $kb_obj->{_fake_write_flag} = 0;
296             {
297 19     19   159 no warnings 'once';
  19         40  
  19         4798  
  4         6  
298 4         7 $main::file_written = $kb_obj_args[1];
299 4         37 $main::file_title_written = $kb_obj_args[0];
300             }
301              
302             }
303              
304             sub _fake_write_file {
305 5     5   1760 my $s = $main::current_manip;
306 5         11 my $title = shift;
307 5         10 my $file_name = shift;
308              
309 5         8 my @kb_obj_args = @{$s->{_kb_obj_args}};
  5         48  
310 5 100       18 if (!@kb_obj_args) {
311 2         22 croak "The _fake_write method cannot be run on this manipulator.";
312             }
313              
314 3         8 $s->{_fake_write_flag} = 1;
315 3         11 $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   20 my $s = shift;
321 11         17 my $from = shift;
322              
323 11 100       34 if (! defined $from) {
324 2         26 croak "No 'from' action found in the manipulator. You must add a 'from' action.'";
325             }
326              
327 9 100       30 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         15 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 json data to file
341              
342             1;
343              
344             __END__