our
%new_PARAMS
= (
source
=>
undef
,
dest
=>
undef
,
);
sub
new {
my
$either
=
shift
;
verify_args( \
%new_PARAMS
,
@_
) or confess $@;
my
$self
=
bless
{
parser
=> Boilerplater::Parser->new,
trees
=> {},
files
=> {},
%new_PARAMS
,
@_
,
},
ref
(
$either
) ||
$either
;
for
(
qw( source dest)
) {
confess(
"Missing required param '$_'"
)
unless
$self
->{
$_
};
}
return
$self
;
}
sub
get_source {
shift
->{source} }
sub
get_dest {
shift
->{dest} }
sub
ordered_classes {
my
$self
=
shift
;
my
@all
;
for
my
$tree
(
values
%{
$self
->{trees} } ) {
push
@all
,
$tree
->tree_to_ladder;
}
return
@all
;
}
sub
files {
values
%{
shift
->{files} } }
sub
build {
my
$self
=
shift
;
$self
->_parse_bp_files;
$_
->grow_tree
for
values
%{
$self
->{trees} };
}
sub
_parse_bp_files {
my
$self
=
shift
;
my
$source
=
$self
->{source};
my
@all_source_paths
;
find(
{
wanted
=>
sub
{
if
(
$File::Find::name
=~ /\.bp$/ ) {
push
@all_source_paths
,
$File::Find::name
unless
/
}
},
no_chdir
=> 1,
follow
=> 1,
},
$source
,
);
my
%classes
;
for
my
$source_path
(
@all_source_paths
) {
my
$source_class
=
$source_path
;
$source_class
=~ s/\.bp$//;
$source_class
=~ s/^\Q
$source
\E\W*//
or
die
"'$source_path' doesn't start with '$source'"
;
$source_class
=~ s/\W/::/g;
my
$content
= slurp_file(
$source_path
);
$content
=
$self
->{parser}->strip_plain_comments(
$content
);
my
$file
=
$self
->{parser}
->file(
$content
, 0,
source_class
=>
$source_class
, );
confess(
"parse error for $source_path"
)
unless
defined
$file
;
$self
->{files}{
$source_class
} =
$file
;
for
my
$class
(
$file
->classes ) {
my
$class_name
=
$class
->get_class_name;
confess
"$class_name already defined"
if
exists
$classes
{
$class_name
};
$classes
{
$class_name
} =
$class
;
}
}
while
(
my
(
$class_name
,
$class
) =
each
%classes
) {
my
$parent_name
=
$class
->get_parent_class_name;
if
(
defined
$parent_name
) {
if
( not
exists
$classes
{
$parent_name
} ) {
confess(
"parent class '$parent_name' not defined "
.
"for class '$class_name'"
);
}
$classes
{
$parent_name
}->add_child(
$class
);
}
else
{
$self
->{trees}{
$class_name
} =
$class
;
}
}
}
sub
propagate_modified {
my
(
$self
,
$modified
) =
@_
;
my
$somebody_is_modified
;
for
my
$tree
(
values
%{
$self
->{trees} } ) {
next
unless
$self
->_propagate_modified(
$tree
,
$modified
);
$somebody_is_modified
= 1;
}
return
$somebody_is_modified
;
}
sub
_propagate_modified {
my
(
$self
,
$class
,
$modified
) =
@_
;
my
$file
=
$self
->{files}{
$class
->get_source_class };
my
$source_path
=
$file
->bp_path(
$self
->{source} );
my
$h_path
=
$file
->h_path(
$self
->{dest} );
if
( !current(
$source_path
,
$h_path
) ) {
$modified
= 1;
}
if
(
$modified
) {
$file
->set_modified(
$modified
);
}
my
$somebody_is_modified
=
$modified
;
for
my
$kid
(
$class
->children ) {
if
(
$class
->final ) {
confess(
"Attempt to inherit from final class "
.
$class
->get_class_name .
" by "
.
$kid
->get_class_name );
}
if
(
$self
->_propagate_modified(
$kid
,
$modified
) ) {
$somebody_is_modified
= 1;
}
}
return
$somebody_is_modified
;
}
1;