Moonpick é um linter alternativo para Moonscript. Embora o moonscript seja fornecido com um linter integrado, atualmente ele é limitado no que pode detectar. O linter integrado irá, por exemplo, detectar variáveis não utilizadas, mas apenas para um subconjunto de todas as declarações não utilizadas possíveis. Ele não detectará variáveis de importação não utilizadas, variáveis de decomposição, funções não utilizadas, etc. Moonpick nasceu na tentativa de detectar o acima e muito mais.
Moonpick pode ser instalado via Luarocks:
$ luarocks install moonpick
Ele pode então ser executado a partir da linha de comando:
$ moonpick < path-to-file >
A saída imita de perto a saída do linter integrado do Moonscript.
Também é facilmente agrupado em um aplicativo independente, pois sua única dependência é o moonscript. Consulte a seção API para obter mais informações sobre como executá-la programaticamente.
Moonpick detecta variáveis não utilizadas em todas as suas formas, sejam elas explicitamente usadas como variáveis por meio de atribuições ou criadas implicitamente como parte de uma instrução import
, instrução de decomposição de tabela, etc.
Moonpick também pode detectar e reclamar de parâmetros de função declarados, mas não utilizados. Isso não está habilitado por padrão, pois é muito comum ter parâmetros não utilizados. Por exemplo, uma função pode seguir uma API externa e ainda querer indicar os parâmetros disponíveis, mesmo que nem todos sejam usados. Para habilitar isso, defina a opção de configuração report_params
como true
.
Moonpick vem com uma configuração padrão que coloca na lista de permissões qualquer parâmetro começando com '_', fornecendo uma maneira de manter os aspectos documentais de uma função e ainda agradar o linter.
Variáveis de loop não utilizadas são detectadas. É possível desabilitar isso completamente na configuração ou fornecer uma lista de permissões explícita apenas para variáveis de loop. Moonpick vem com uma configuração padrão que coloca na lista de permissões os argumentos 'i' e 'j', ou qualquer variável começando com '_'.
Semelhante ao linter integrado, Moonpick detecta referências indefinidas.
O sombreamento de declaração ocorre sempre que uma declaração sombreia uma declaração anterior com o mesmo nome. Considere o seguinte código:
my_mod = require ' my_mod '
-- [.. more code in between.. ]
for my_mod in get_modules ( ' foo ' )
my_mod . bar!
Embora no exemplo acima esteja bastante claro que o my_mod
declarado no loop é diferente do nível superior my_mod
, isso pode rapidamente se tornar menos claro caso mais código seja inserido entre a declaração for e o uso posterior. Nesse ponto, o código se torna ambíguo. O sombreamento de declaração ajuda nisso, garantindo que cada variável seja definida no máximo uma vez, de maneira inequívoca.
A detecção pode ser desativada completamente definindo a variável de configuração report_shadowing
como falsa, e a lista de permissões pode ser configurada especificando uma lista de configuração whitelist_shadowing
.
Observe que para versões do Moonscript anteriores a 0.5, esse tipo de sombras apenas reutilizaria a declaração anterior, levando a erros facilmente ignorados e confusos.
A reatribuição de uma variável previamente definida contendo um valor de função raramente é desejada e geralmente é o resultado do esquecimento de uma declaração anterior.
-- with the following declaration and usage
done = ( x ) -> x . foo and x . bar
done ( {} )
-- one might mistakenly reuse the name further down
i = 1
-- [..]
done = i == 10
Isso pode causar problemas difíceis de depurar, principalmente se a reatribuição for feita apenas em um caminho de código que nem sempre é exercido.
A detecção pode ser desativada completamente definindo a variável de configuração report_fndef_reassignments
como falsa, e a lista de permissões pode ser configurada especificando uma lista de configuração whitelist_fndef_reassignments
.
A reatribuição de uma variável de nível superior de dentro de uma função ou método pode às vezes ser a causa de bugs não óbvios e elusivos, por exemplo:
module = require ' lib.module '
-- [..] much further down
get_foo = ( y ) ->
module = y match ( ' %w+ ' ) lower! -- mistakenly reusing the `module` var
return " #{module}_bar "
Caso get_foo
acima seja chamado apenas condicionalmente, isso pode fazer com que bugs sérios passem despercebidos.
Ao contrário das outras detecções, esta detecção não está habilitada por padrão. A detecção pode ser ativada definindo a variável de configuração report_top_level_reassignments
como true, e a lista de permissões pode ser configurada especificando uma lista de configuração whitelist_top_level_reassignments
. No entanto, é altamente recomendável habilitar isso.
A razão pela qual isso não está habilitado por padrão é que não é incomum ter código legítimo que manipula variáveis de nível superior dentro de subfunções ou métodos. Para evitar reclamações do linter, seria necessário configurar a lista de permissões ou adotar um estilo diferente de codificação onde as variáveis de nível superior não fossem reatribuídas (por exemplo, usando uma tabela para manter o estado do módulo).
Moonpick suporta um superconjunto do mesmo arquivo de configuração e formato do linter integrado.
Ele fornece opções de configuração adicionais, adicionando suporte para configurar linting de parâmetros de função e variáveis de loop, e também permite padrões Lua em todas as listas de permissões. Os arquivos de configuração do Linter podem ser escritos em Lua ou Moonscript ( lint_config.lua
e lint_config.moon
respectivamente).
Veja o exemplo abaixo (lint_config.moon, usando a sintaxe Moonscript):
{
whitelist_globals : {
-- whitelist for all files
[ " . " ] : { ' always_ignore ' } ,
-- whitelist for files matching 'spec'
spec : { ' test_helper ' } ,
}
whitelist_params : {
-- whitelist params for all files
[ " . " ] : { ' my_param ' } ,
-- ignore unused param for files in api
api : { ' extra_info ' } ,
}
whitelist_loop_variables : {
-- always allow loop variables 'i', 'j', 'k', as well as any
-- variable starting with '_' (using a Lua pattern)
[ " . " ] : { ' i ' , ' j ' , ' k ' , ' ^_ ' } ,
}
-- general whitelist for unused variables if desired for
-- some reason
whitelist_unused : {
[ " . " ] : {} ,
}
-- below you'll see the boolean switches controlling the
-- linting, shown with the default value
-- report_loop_variables: true
-- report_params: true
-- report_shadowing: true
-- report_fndef_reassignments: true
-- report_top_level_reassignments: false
}
Um item da lista de permissões será tratado como um padrão se consistir em algo diferente de caracteres alfanuméricos.
local moonpick = require ( ' moonpick ' )
Lints o código fornecido em code
, retornando uma tabela de inspeções de linting. config
é a configuração de linting a ser usada para o arquivo e pode conter versões simples dos elementos normalmente encontrados em um arquivo de configuração ( whitelist_globals
, whitelist_params
, whitelist_loop_variables
, whitelist_unused
, report_params
, report_loop_variables
).
Exemplo de tabela de configuração (sintaxe Lua):
local moonpick = require ( ' moonpick ' )
local code = ' a = 2 '
moonpick . lint ( code , {
whitelist_globals = { ' foo ' , ' bar ' , }
whitelist_params = { ' ^_+ ' , ' other_+ ' }
})
A tabela de inspeções devolvidas ficaria assim no exemplo acima:
{
{
line = 1 ,
pos = 1 ,
msg = ' declared but unused - `a` ' ,
code = ' a = 2 '
}
}
Lints o file
fornecido, retornando uma tabela de inspeções de linting. opts
pode conter atualmente um valor, lint_config
, que especifica o arquivo de configuração do qual carregar a configuração.
local moonpick_config = require ( ' moonpick.config ' )
Retorna o caminho do arquivo de configuração relevante para path
ou nil
se nenhum for encontrado.
Carrega a configuração do linting para o file
do arquivo de configuração fornecido por config_path
. A configuração retornada será uma tabela de opções de configuração simplificada para file
.
Retorna uma instância de avaliador para as opções de linting fornecidas (por exemplo, conforme retornado por load_config_from
). A instância do avaliador fornece as seguintes funções (observe que são funções que devem ser invocadas usando o operador ponto comum .
):
allow_global_access
, allow_unused_param
, allow_unused_loop_variable
, allow_unused
, allow_fndef_reassignment
, allow_top_level_reassignment
.
Todos eles tomam como primeiro argumento um símbolo (como string) e retornam true
ou false
dependendo se o símbolo passa pelo linting ou não.
Observe que o Moonpick é bastante jovem neste estágio e, embora tenha sido executado com sucesso em bases de código maiores, pode muito bem produzir falsos positivos e relatórios incorretos. Se você encontrar isso, abra um problema com um exemplo de código que ilustra o comportamento incorreto.
Direitos autorais 2016-2017 Nils Nordman
Moonpick é lançado sob a licença MIT (consulte o arquivo LICENSE para obter detalhes completos).
Os testes requerem busted
para serem executados, assim como o módulo pl
(Penlight - luarock install penlight
). Basta executar busted
no diretório raiz do projeto.
Execute com um LUA_PATH especificado apontando para o diretório src
local. Presumindo um local de checkout de ~/code/moonpick
:
LUA_PATH= " $HOME /code/moonpick/src/?.lua; $HOME /code/moonpick/src/?/init.lua; $( lua -e ' print(package.path) ' ) " ~ /code/moonpick/bin/moonpick * .moon