Use {List,Sub}::Util instead of List::MoreUtils and Sub::Name
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Utils.pm
CommitLineData
cc4f11a2 1package # hide from PAUSE
2 DBIx::Class::Schema::Loader::Utils;
3
4use strict;
5use warnings;
1ad8e8c3 6use Test::More;
ea3b8f03 7use String::CamelCase 'wordsplit';
112415f1 8use Carp::Clan qw/^DBIx::Class/;
50b95db6 9use Scalar::Util 'looks_like_number';
1ad8e8c3 10use namespace::clean;
cc4f11a2 11use Exporter 'import';
ea3b8f03 12use Data::Dumper ();
cc4f11a2 13
ecf22f0a 14our @EXPORT_OK = qw/split_name dumper dumper_squashed eval_package_without_redefine_warnings class_path no_warnings warnings_exist warnings_exist_silent slurp_file write_file array_eq sigwarn_silencer apply firstidx uniq/;
cc4f11a2 15
ea3b8f03 16use constant BY_CASE_TRANSITION_V7 =>
cc4f11a2 17 qr/(?<=[[:lower:]\d])[\W_]*(?=[[:upper:]])|[\W_]+/;
18
19use constant BY_NON_ALPHANUM =>
20 qr/[\W_]+/;
21
fcf328c7 22my $LF = "\x0a";
23my $CRLF = "\x0d\x0a";
24
ea3b8f03 25sub split_name($;$) {
26 my ($name, $v) = @_;
27
28 my $is_camel_case = $name =~ /[[:upper:]]/ && $name =~ /[[:lower:]]/;
29
30 if ((not $v) || $v >= 8) {
31 return map split(BY_NON_ALPHANUM, $_), wordsplit($name);
32 }
cc4f11a2 33
ea3b8f03 34 return split $is_camel_case ? BY_CASE_TRANSITION_V7 : BY_NON_ALPHANUM, $name;
cc4f11a2 35}
36
15efd63a 37sub dumper($) {
38 my $val = shift;
39
40 my $dd = Data::Dumper->new([]);
41 $dd->Terse(1)->Indent(1)->Useqq(1)->Deparse(1)->Quotekeys(0)->Sortkeys(1);
42 return $dd->Values([ $val ])->Dump;
43}
44
45sub dumper_squashed($) {
46 my $val = shift;
47
48 my $dd = Data::Dumper->new([]);
49 $dd->Terse(1)->Indent(1)->Useqq(1)->Deparse(1)->Quotekeys(0)->Sortkeys(1)->Indent(0);
50 return $dd->Values([ $val ])->Dump;
51}
52
cfaae7fc 53# copied from DBIx::Class::_Util, import from there once it's released
54sub sigwarn_silencer {
83bce685 55 my $pattern = shift;
cfaae7fc 56
83bce685 57 croak "Expecting a regexp" if ref $pattern ne 'Regexp';
cfaae7fc 58
83bce685 59 my $orig_sig_warn = $SIG{__WARN__} || sub { CORE::warn(@_) };
cfaae7fc 60
83bce685 61 return sub { &$orig_sig_warn unless $_[0] =~ $pattern };
cfaae7fc 62}
63
ecf22f0a 64# Copied with stylistic adjustments from List::MoreUtils::PP
65sub firstidx (&@) {
66 my $f = shift;
67 foreach my $i (0..$#_) {
68 local *_ = \$_[$i];
69 return $i if $f->();
70 }
71 return -1;
72}
73
74sub uniq (@) {
75 my %seen = ();
76 grep { not $seen{$_}++ } @_;
77}
78
79sub apply (&@) {
80 my $action = shift;
81 $action->() foreach my @values = @_;
82 wantarray ? @values : $values[-1];
83}
84
0f21885a 85sub eval_package_without_redefine_warnings {
86 my ($pkg, $code) = @_;
c38ec663 87
cfaae7fc 88 local $SIG{__WARN__} = sigwarn_silencer(qr/^Subroutine \S+ redefined/);
0f21885a 89
90 # This hairiness is to handle people using "use warnings FATAL => 'all';"
91 # in their custom or external content.
92 my @delete_syms;
93 my $try_again = 1;
94
95 while ($try_again) {
96 eval $code;
97
98 if (my ($sym) = $@ =~ /^Subroutine (\S+) redefined/) {
99 delete $INC{ +class_path($pkg) };
100 push @delete_syms, $sym;
101
102 foreach my $sym (@delete_syms) {
103 no strict 'refs';
104 undef *{"${pkg}::${sym}"};
105 }
106 }
107 elsif ($@) {
108 die $@ if $@;
109 }
110 else {
111 $try_again = 0;
112 }
113 }
114}
115
116sub class_path {
117 my $class = shift;
118
119 my $class_path = $class;
120 $class_path =~ s{::}{/}g;
121 $class_path .= '.pm';
122
123 return $class_path;
c38ec663 124}
125
12b86f07 126sub no_warnings(&;$) {
127 my ($code, $test_name) = @_;
128
129 my $failed = 0;
130
131 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
132 local $SIG{__WARN__} = sub {
133 $failed = 1;
134 $warn_handler->(@_);
135 };
136
137 $code->();
138
139 ok ((not $failed), $test_name);
140}
141
1ad8e8c3 142sub warnings_exist(&$$) {
143 my ($code, $re, $test_name) = @_;
144
145 my $matched = 0;
146
147 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
148 local $SIG{__WARN__} = sub {
149 if ($_[0] =~ $re) {
150 $matched = 1;
151 }
152 else {
153 $warn_handler->(@_)
154 }
155 };
156
157 $code->();
158
159 ok $matched, $test_name;
160}
161
162sub warnings_exist_silent(&$$) {
163 my ($code, $re, $test_name) = @_;
164
165 my $matched = 0;
166
167 local $SIG{__WARN__} = sub { $matched = 1 if $_[0] =~ $re; };
168
169 $code->();
170
171 ok $matched, $test_name;
172}
173
fcf328c7 174sub slurp_file($) {
112415f1 175 my $file_name = shift;
176
177 open my $fh, '<:encoding(UTF-8)', $file_name,
178 or croak "Can't open '$file_name' for reading: $!";
179
a79e1189 180 my $data = do { local $/; <$fh> };
112415f1 181
a79e1189 182 close $fh;
fcf328c7 183
184 $data =~ s/$CRLF|$LF/\n/g;
185
186 return $data;
187}
1ad8e8c3 188
b564fc4b 189sub write_file($$) {
112415f1 190 my $file_name = shift;
191
192 open my $fh, '>:encoding(UTF-8)', $file_name,
193 or croak "Can't open '$file_name' for writing: $!";
194
b564fc4b 195 print $fh shift;
196 close $fh;
197}
198
50b95db6 199sub array_eq($$) {
200 no warnings 'uninitialized';
201 my ($a, $b) = @_;
202
203 return unless @$a == @$b;
204
205 for (my $i = 0; $i < @$a; $i++) {
206 if (looks_like_number $a->[$i]) {
207 return unless $a->[$i] == $b->[$i];
208 }
209 else {
210 return unless $a->[$i] eq $b->[$i];
211 }
212 }
213 return 1;
214}
215
cc4f11a2 2161;
217# vim:et sts=4 sw=4 tw=0: