Как в trepl или luajit найти исходный код библиотеки, которую я использую?

Допустим, я работаю с библиотекой lua, которую я установил с помощью luarocks, и хочу увидеть определение функции из этой библиотеки. В ipython можно использовать

?? имя_функции

чтобы увидеть определение в терминале, в Matlab я мог бы использовать

какое имя_функции

затем используйте мой редактор, чтобы посмотреть путь, возвращаемый которым. Как я могу сделать что-то подобное, чтобы найти определение функции для библиотеки lua?


person sudo-nim    schedule 25.04.2015    source источник
comment
Может быть Easy help with: ? funcname (см. ссылку)   -  person Egor Skriptunoff    schedule 26.04.2015
comment
К сожалению? help не показывает путь, по крайней мере, в моей версии LuaJIT, 2.1.0-alpha.   -  person sudo-nim    schedule 26.04.2015


Ответы (1)


В "простом" Lua / JIT вы можете сказать _1 _ ( func ) и получит таблицу, содержащую (среди прочего) поля short_src, source и linedefined.

Для функций Lua short_src будет именем файла или stdin, если он был определен в REPL. (source имеет немного другой формат, имена файлов начинаются с префикса @, префикс = используется для функций C или прочего, определенного в интерактивном режиме, а для функций с loaded это будет фактическая строка, которая была загружена.)

Вы можете упаковать это в функцию вроде

function sourceof( f )
    local info = debug.getinfo( f, "S" )
    return info.short_src, info.linedefined
end

или, может быть, даже запустите редактор и укажите его там, например (для vim)

function viewsource( f )
    -- get info & check it's actually from a file
    local info = debug.getinfo( f, "S" )
    local src, line = info.source, info.linedefined
    if src == "=[C]"   then  return nil, "Is a C function."  end
    local path = src:match "^@(.*)$"
    if path then
        -- start vim (or an other editor if you adapt the format string)
        return os.execute( ("vim -fR %q +%d"):format( path, line ) )
    end
    return nil, "Was defined at run time."
end

И просто для удовольствия, вот еще одна версия, которая возвращает код, если он может где-то его найти. (Это также будет работать для функций, которые были сгенерированы во время выполнения, например, путем вызова load, и где исходный файл не существует. Вы также можете работать в другом направлении, выгрузив фрагмент loaded во временный файл и открыв его ...)

-- helper to extract the source block defining the function
local function funclines( str, line1, lineN, filename )
    -- if linedefined / lastlinedefined are 0, this is the main chunk's function
    if line1 == 0 and lineN == 0 then
        filename = filename and filename.." (main chunk)"
                             or "(chunk defined at runtime)"
        return "-- "..filename.."\n"..str
    end
    -- add line info to file name or use placeholder
    filename = filename and filename..":"..line1 or "(defined at runtime)"
    -- get the source block
    local phase, skip, grab = 1, line1-1, lineN-(line1-1)
    local ostart, oend -- these will be the start/end offsets
    if skip == 0 then  phase, ostart = 2, 0  end -- starts at first line
    for pos in str:gmatch "\n()" do
        if phase == 1 then -- find offset of linedefined
            skip = skip - 1 ; if skip == 0 then  ostart, phase = pos, 2  end 
        else -- phase == 2, find offset of lastlinedefined+1
            grab = grab - 1 ; if grab == 0 then  oend = pos-2 ; break  end
        end
    end
    return "-- "..filename.."\n"..str:sub( ostart, oend )
end

function dumpsource( f )
    -- get info & line numbers
    local info = debug.getinfo( f, "S" )
    local src, line, lastline = info.source, info.linedefined, info.lastlinedefined
    -- can't do anything for a C function
    if src == "=[C]" then  return nil, "Is a C function."  end
    if src == "=stdin" then  return nil, "Was defined interactively."  end
    -- for files, fetch the definition
    local path = src:match "^@(.*)$"
    if path then
        local f = io.open( path )
        local code = f:read '*a' 
        f:close( )
        return funclines( code, line, lastline, path )
    end
    -- otherwise `load`ed, so `source`/`src` _is_ the source
    return funclines( src, line, lastline )
end

Заключительное замечание: если вы вставляете код в Lua / JIT REPL, locals исчезают между определениями, потому что каждая строка (или минимальная полная группа строк) является отдельным фрагментом. Обычное исправление (которое вы, вероятно, знаете) - это обернуть все в блок как do * paste * end, но альтернативой является load[[ * paste * ]]() (возможно, с большим количеством =, таких как [===[ и ]===].) Если вы вставите таким образом, указанная выше dumpsource (или любая другая функция, использующая debug.getinfo) сможет получить источник функции (ей). Это также означает, что если вы определили красивую функцию, но она исчезла из истории и буфера прокрутки, вы можете восстановить ее таким способом (если вы определили ее с помощью loading, а не напрямую загрузили интерпретатор). Сохранение исходного кода в файле также будет возможно без копирования-вставки и не потребует редактирования >> подсказок.

person nobody    schedule 26.04.2015
comment
Отличный ответ! Эти функции были бы хорошим дополнением к TREPL. - person sudo-nim; 26.04.2015
comment
Чтобы функция view_source работала, мне нужно было добавить строку src = str.sub (src, 2, -1) после третьей строки функции. - person sudo-nim; 26.04.2015
comment
@ user1546029 Хм, интересно ... таблица, возвращаемая debug.getinfo, содержит два поля с именами source и short_src, где source имеет префикс @, если это файл, а short_src - нет. Так что этот должен работать (и для меня это работает в Linux + Mac OS в Lua 5.2 + 5.3 и LuaJIT, а также в Solaris в Lua 5.1). Какой символ нужно удалить? А какая у вас ОС? (ОС действительно не должна иметь значение, но я понятия не имею, почему это должно сломаться…) - person nobody; 26.04.2015
comment
Я использую Springdale Linux, дистрибутив Red Hat. short_src не работал как путь, потому что ему предшествовали три точки. source был путем от корня, которому предшествовал @, который я удалил. Извините, я забыл упомянуть, что перешел с использования short_src на источник в моем последнем комментарии. - person sudo-nim; 26.04.2015
comment
@ user1546029 А, приятно знать, что short_src ломается в некоторых системах, спасибо! Отредактировано для использования source сейчас (и добавлен еще один вариант ^^). - person nobody; 27.04.2015