mochiweb 源码阅读(三)

  大家好,周末总是过的那么快,周六跟北京几个Erlang开发者去森林公园玩了一天,打打三国杀,下下象棋,聊聊天。能多出去走走,认识认识其他的Erlang开发者,还是挺爽的一件事。晚上闲下来,静下心来跟大家继续分享mochiweb源码。

  在上一篇,我们简单了学习了几个Erlang的系统函数,以及mochiweb_example_deps:deps_on_path/0 函数,这一篇我们继续从mochiweb_example_deps:new_siblings/1 函数往下看:

%% @spec new_siblings(Module) -> [Dir]
%% @doc Find new siblings paths relative to Module that aren't already on the
%%      code path.
new_siblings(Module) ->
    Existing = deps_on_path(),
    SiblingEbin = filelib:wildcard(local_path(["deps", "*", "ebin"], Module)),
    Siblings = [filename:dirname(X) || X <- SiblingEbin,
                           ordsets:is_element(
                             filename:basename(filename:dirname(X)),
                             Existing) =:= false],
    lists:filter(fun filelib:is_dir/1,
                 lists:append([[filename:join([X, "ebin"]),
                                filename:join([X, "include"])] ||
                                  X <- Siblings])).

  这里我们从上一篇知道了mochiweb_example_deps:deps_on_path/0 函数返回的值为:Existing = []。我们继续往下看,先看下mochiweb_example_deps:local_path/2 函数:

%% @spec local_path([string()], Module) -> string()
%% @doc Return an application-relative directory from Module's application.
local_path(Components, Module) ->
    filename:join([get_base_dir(Module) | Components]).

  这里两个参数的值为:

  < Components = ["deps","*","ebin"]
  < Module = mochiweb_example_deps

  这个函数就一行代码,首先调用 mochiweb_example_deps:get_base_dir/2 函数,传递参数 Module

%% @spec get_base_dir(Module) -> string()
%% @doc Return the application directory for Module. It assumes Module is in
%%      a standard OTP layout application in the ebin or src directory.
get_base_dir(Module) ->
    {file, Here} = code:is_loaded(Module),
    filename:dirname(filename:dirname(Here)).

  从注释来看,大意是:返回模块所在的应用程序目录,它假定模块在一个标准的OTP应用程序的ebin或src目录。

  我们先看下函数 code:is_loaded/1,检查该模块是否加载,如果已加载,返回{file, Loader};否则返回false, erlang doc 地址:http://www.erlang.org/doc/man/code.html#is_loaded-1,如下图:

mochiweb 源码阅读(三)_第1张图片

  这里:< Here = "/home/administrator/workplace/mochiweb_example/ebin/mochiweb_example_deps.beam",而 filename:dirname/1 这个函数前一篇我们已经讲过了:Returns the directory part of Filename

  我们对这个函数稍加修改来看下执行过程具体获得到的值,如下图:

  mochiweb 源码阅读(三)_第2张图片

  从上面这个图,我们能很明白的看到整个函数执行的每一步,这里主要跟大家提下,filename:dirname/1 这个函数接受的参数不一定是文件路径,也有可能是目录路径,如果是目录路径,则返回的是上一层目录的路径,如D2的值。

  知道了这个函数的作用,我们接着回到mochiweb_example_deps:local_path/2 函数,这里把mochiweb_example_deps:get_base_dir/2 函数返回的值和Components组合成一个List,传递给函数:filename:join/1,这个函数的erlang doc 地址:http://www.erlang.org/doc/man/filename.html#join-1,如下图:

mochiweb 源码阅读(三)_第3张图片

  这个方法也很简单,拼接路径,我们看下:

  filename:join(["/home/administrator/workplace/mochiweb_example" | ["deps","*","ebin"]]).

  = "/home/administrator/workplace/mochiweb_example/deps/*/ebin".

  回到mochiweb_example_deps:new_siblings/1 函数往下看,这里我们看下函数:filelib:wildcard/1,erlang doc 地址:http://www.erlang.org/doc/man/filelib.html#wildcard-1,如下图:

mochiweb 源码阅读(三)_第4张图片

mochiweb 源码阅读(三)_第5张图片

mochiweb 源码阅读(三)_第6张图片

  这个方法也挺简单的,按照一定的规则去模式匹配并返回匹配的文件列表,我做了写测试,如下图:

  mochiweb 源码阅读(三)_第7张图片

  mochiweb 源码阅读(三)_第8张图片

  我们看下:

  SiblingEbin = filelib:wildcard(local_path(["deps", "*", "ebin"], Module))

  = filelib:wildcard("/home/administrator/workplace/mochiweb_example/deps/*/ebin")

  = ["/home/administrator/workplace/mochiweb_example/deps/mochiweb/ebin"]

  继续往下看:

Siblings = [filename:dirname(X) || X <- SiblingEbin,
                           ordsets:is_element(
                             filename:basename(filename:dirname(X)),
                             Existing) =:= false],

  我们先看下函数:ordsets:is_element/2,判断Element是否是Ordset的元素,是则返回true, 否则返回flase。erlang doc 地址:http://www.erlang.org/doc/man/ordsets.html#is_element-2,如下图:

mochiweb 源码阅读(三)_第9张图片

  从上来文,我们知道:

  < Existing = []
  < SiblingEbin = ["/home/administrator/workplace/mochiweb_example/deps/mochiweb/ebin"]

  所以得到:

  < Siblings = ["/home/administrator/workplace/mochiweb_example/deps/mochiweb"]

  如下图:

  mochiweb 源码阅读(三)_第10张图片

  好了,这一篇就到这了,下一篇我们从下面代码处继续往下看:

    lists:filter(fun filelib:is_dir/1,
                 lists:append([[filename:join([X, "ebin"]),
                                filename:join([X, "include"])] ||
                                  X <- Siblings])).

  最后,谢谢大家的耐心阅读,咱们下一篇再见。

  

你可能感兴趣的:(Web)