Open krlmlr opened 4 years ago
Do you have an example package with a structure like you want?
assuming you have cloned fledge on your machine and are in the root of the package directory
library(ggraph)
library(igraph)
x <- foreman::unpack()
x_rel <- foreman::relationship(x)
x_rel_df <- as.data.frame(x_rel)
graph <- igraph::graph_from_data_frame(x_rel_df,directed = TRUE)
igraph::V(graph)$parents <- names(igraph::V(graph))
ggraph(graph) +
geom_edge_link(
aes(colour = file),
arrow = grid::arrow(length = unit(0.05, "inches"))) +
geom_node_text(aes(label = parents),size = 3) +
labs(title = 'fledge function map') +
ggplot2::theme(legend.position = 'bottom')
The file directional relationship is indicated in the colours.
This info is also in x_rel_df where can you create any output you want.
Very nice, thanks a lot!
I'm looking for evil circles like this. Here I'm interested in the relationship between files: ideally the directed graph should be cycle-free. This means that it must have a topological sort order. To detect the cycles, I'm computing the strongly connected components -- those with size > 1 are clusters of nodes that can be reached mutually in the connected graph, there must be a cycle in such a cluster. (Can't use igraph::girth()
here, its's only for undirected graphs.)
Maybe a variant of this code could find its place here?
library(ggraph)
library(igraph)
library(tidyverse)
setwd("~/git/R/fledge")
x <- foreman::unpack()
#> Warning: No functions found in
#> /home/kirill/git/R/fledge/R/import.R
x_rel <- foreman::relationship(x)
x_rel_df <- as_tibble(as.data.frame(x_rel))
fun_file <-
x %>%
map(names) %>%
enframe("file", "fun") %>%
unnest(fun)
child_file <-
fun_file %>%
rename(child = fun, child_file = file)
x_file_rel_df <-
x_rel_df %>%
left_join(child_file) %>%
count(file, child_file)
#> Joining, by = "child"
graph <- igraph::graph_from_data_frame(x_file_rel_df, directed = TRUE)
scc <- igraph::components(graph, "strong")
circle_comp <- which(scc$csize > 1)[[1]]
circle_files <- names(scc$membership)[scc$membership == circle_comp]
x_file_rel_df %>%
filter(file %in% circle_files & child_file %in% circle_files) %>%
filter(file != child_file)
#> # A tibble: 5 x 3
#> file child_file n
#> <chr> <chr> <int>
#> 1 api-bump-version.R api-update-version.R 1
#> 2 api-bump-version.R bump-version.R 1
#> 3 api-update-version.R update-version.R 1
#> 4 bump-version.R api-update-version.R 1
#> 5 update-version.R api-bump-version.R 1
plot(igraph::induced_subgraph(graph, circle_files))
Created on 2020-10-23 by the reprex package (v0.3.0)
(FWIW, this is a false positive for fledge -- there's a call of the form desc$bump_version(which)
that seems to be detected as a call to fledge::bump_version()
. If I remove that call, the cycle vanishes.)
library(ggraph)
library(igraph)
library(tidyverse)
setwd("~/git/R/fledge")
x <- foreman::unpack()
#> Warning: No functions found in
#> /home/kirill/git/R/fledge/R/import.R
x_rel <- foreman::relationship(x)
x_rel_df <- as_tibble(as.data.frame(x_rel))
fun_file <-
x %>%
map(names) %>%
enframe("file", "fun") %>%
unnest(fun)
child_file <-
fun_file %>%
rename(child = fun, child_file = file)
x_file_rel_df <-
x_rel_df %>%
left_join(child_file) %>%
select(file, child_file, label = child) %>%
filter(file != child_file)
#> Joining, by = "child"
graph <- igraph::graph_from_data_frame(x_file_rel_df, directed = TRUE)
scc <- igraph::components(graph, "strong")
circle_comp <- which(scc$csize > 1)[[1]]
circle_files <- names(scc$membership)[scc$membership == circle_comp]
x_file_rel_df %>%
filter(file %in% circle_files & child_file %in% circle_files) %>%
filter(file != child_file)
#> # A tibble: 5 x 3
#> file child_file label
#> <chr> <chr> <chr>
#> 1 api-bump-version.R api-update-version.R check_which
#> 2 api-bump-version.R bump-version.R bump_version_impl
#> 3 api-update-version.R update-version.R update_version_impl
#> 4 bump-version.R api-update-version.R update_version
#> 5 update-version.R api-bump-version.R bump_version
plot(igraph::induced_subgraph(graph, circle_files))
Created on 2020-10-23 by the reprex package (v0.3.0)
In R packages, I try to organize the code in .R files so that if a function in
a.R
calls a function inb.R
, no function fromb.R
calls back toa.R
, also not indirectly. How can foreman help verify or visualize this?Can we do a graphviz visualization with subgraphs -- each file creates a subgraph, each node is a function?
Can we create an igraph object, search for cycles, remove one edge, search again, ... to summarize? (We could label the edges so that they are named by the caller, to identify which function creates the cycle.)
I haven't tried the package yet, appreciate any pointers. Thanks!