Sunday 16 July 2017

Cpan Moving Average


Este capítulo apresenta os conceitos por trás das referências a módulos, pacotes e classes do Perl. Também mostra como criar alguns módulos de amostra. Um módulo Perl é um conjunto de código Perl que age como uma biblioteca de chamadas de função O módulo de termo em Perl é sinônimo da palavra package Os pacotes são uma característica do Perl 4, enquanto os módulos são predominantes no Perl 5. Você pode manter todo o seu código Perl reutilizável específico para um conjunto de tarefas em um módulo Perl. Portanto, toda a funcionalidade pertencente a um tipo Da tarefa está contida em um arquivo É mais fácil construir um aplicativo sobre estes blocos modulares Assim, o módulo de palavra aplica um pouco mais do que package. Here sa rápida introdução aos módulos Certos tópicos nesta seção serão abordados em detalhes durante todo o resto O livro Leia os seguintes parágrafos com cuidado para obter uma visão geral do que está à frente como você escrever e usar seus próprios módulos. O que é confuso é que os termos módulo e pacote são usados ​​de forma intercambiável em todo o documento Perl Ação, e estes dois termos significam a mesma coisa Então, quando ler documentos Perl, basta pensar pacote quando você vê o módulo e vice-versa. Assim, o que é a premissa para usar módulos Bem, os módulos estão lá para pacote perdão as variáveis ​​pun, símbolos , E itens de dados interconectados juntos Por exemplo, usando variáveis ​​globais com nomes muito comuns, como kj ou i em um programa geralmente não é uma boa idéia Além disso, um contador de loop, i deve ser autorizado a trabalhar de forma independente em duas partes diferentes do código Declarar i como uma variável global e, em seguida, incrementá-lo a partir de dentro de uma sub-rotina irá criar problemas não gerenciáveis ​​com o código do aplicativo, porque a sub-rotina pode ter sido chamado de dentro de um loop que também usa uma variável chamada i O uso de módulos em Perl permite variáveis ​​com o Mesmo nome a ser criado em diferentes lugares distintos no mesmo programa. Os símbolos definidos para suas variáveis ​​são armazenados em uma matriz associativa, referida como uma tabela de símbolos. Essa tabela de símbolos S são exclusivos de um pacote Portanto, as variáveis ​​do mesmo nome em dois pacotes diferentes podem ter valores diferentes. Cada módulo tem sua própria tabela de símbolos de todos os símbolos que são declarados dentro dele A tabela de símbolos basicamente isola nomes sinônimos em um módulo de outro O Assim, o uso de módulos, cada um com sua própria tabela de símbolos, impede que uma variável declarada em uma seção sobrescreva os valores de outras variáveis ​​com o mesmo nome declarado Em qualquer lugar no mesmo programa. Como uma questão de fato, todas as variáveis ​​no Perl pertencem a um pacote As variáveis ​​em um programa Perl pertencem ao pacote principal Todos os outros pacotes dentro de um programa Perl ou estão aninhados dentro deste pacote principal ou existem no mesmo Existem algumas variáveis ​​verdadeiramente globais, como a matriz de manipuladores de sinal SIG que estão disponíveis para todos os outros módulos em um programa aplicativo e não podem ser isoladas via namespaces Only th Ose variável identificadores começando com letras ou um sublinhado são mantidos em um módulo s tabela de símbolos Todos os outros símbolos, como os nomes STDIN STDOUT STDERR ARGV ARGVOUT ENV Inc e SIG são forçados a estar no pacote principal. Switching entre pacotes afeta apenas namespaces Tudo o que você Estão fazendo quando você usa um pacote ou outro está declarando qual tabela de símbolos para usar como a tabela de símbolos padrão para pesquisa de nomes de variáveis ​​Somente variáveis ​​dinâmicas são afetadas pelo uso de tabelas de símbolos As variáveis ​​declaradas pelo uso da palavra-chave my ainda são resolvidas com O bloco de código em que residem e não são referenciados através de tabelas de símbolos De fato, o escopo de uma declaração de pacote permanece ativo somente dentro do bloco de código é declarado em Portanto, se você alternar tabelas de símbolos usando um pacote dentro de uma sub-rotina, A tabela de símbolos original em vigor quando a chamada foi feita será restaurada quando a subrotina retorna. Tabelas de símbolos de comutação afeta apenas a pesquisa padrão de varia dinâmico Você ainda pode se referir explicitamente a variáveis, manipuladores de arquivos e assim por diante em um pacote específico, anexando um nome de pacote ao nome da variável Você viu o que era um contexto de pacote ao usar referências no Capítulo 3 Um contexto de pacote simplesmente implica o uso do Tabela de símbolos pelo interpretador Perl para resolver nomes de variáveis ​​em um programa Ao alternar tabelas de símbolos, você está alternando o contexto do pacote. Módulos podem ser aninhados dentro de outros módulos O módulo aninhado pode usar as variáveis ​​e funções do módulo que está aninhado dentro Para aninhado , Você teria que usar o nome do módulo nestedModuleName e assim por diante Usando o dois pontos dobro é sinônimo de usar uma citação de volta Entretanto, o duplo cólon é a maneira preferida, futuro de endereçamento de variáveis ​​dentro de módulos. O endereçamento explícito de variáveis ​​de módulo é sempre feito com um Referência completa Por exemplo, suponha que você tenha um módulo, Investimento que é o pacote padrão em uso, e você deseja endereço outro módulo, Bonds que É aninhado dentro do módulo de investimento Neste caso, você não pode usar Bond Em vez disso, você teria que usar Investment Bond para abordar variáveis ​​e funções dentro do módulo Bond Usando Bond implicaria o uso de um pacote Bond que está aninhado dentro do módulo principal e Não dentro do módulo de investimento. A tabela de símbolos para um módulo é realmente armazenada em uma matriz associativa de nomes de módulo s anexados com dois colons A tabela de símbolos para um módulo chamado Bond será referido como a matriz associativa Bond O nome para o símbolo A tabela para o módulo principal é principal e pode até mesmo ser encurtada Similarmente, todos os pacotes aninhados têm seus símbolos armazenados em matrizes associativas com dois pontos separando cada nível de aninhamento Por exemplo, no módulo Bond que está aninhado dentro do módulo de investimento, o array associativo Para os símbolos no módulo Bond será denominado Investment Bond. A typeglob é realmente um tipo global para um nome de símbolo Você pode executar operações de aliasing atribuindo a um Typeglob Uma ou mais entradas em uma matriz associativa para símbolos serão usadas quando uma atribuição através de um typeglob é usada. O valor real em cada entrada da matriz associativa é o que você está se referindo quando você usa a notação variableName. Assim, existem duas maneiras De se referir a nomes de variáveis ​​em um pacote Investimento dinheiro Notas de investimento. No primeiro método, você está se referindo às variáveis ​​através de uma referência typeglob O uso da tabela de símbolos, o investimento é implícito aqui, e Perl irá otimizar a pesquisa de símbolos dinheiro e Bills Esta é a maneira mais rápida e preferida de endereçar um símbolo O segundo método usa uma pesquisa para o valor de uma variável endereçada por dinheiro e contas na matriz associativa usada para símbolos, Investimento explicitamente Esta pesquisa será feita dinamicamente e não será otimizada Por Perl Portanto, a pesquisa será forçada a verificar a matriz associativa toda vez que a instrução é executada Como resultado, o segundo método não é eficiente e deve ser Usado apenas para demonstração de como a tabela de símbolos é implementada internamente. Um outro exemplo nessa declaração kamran husains. Usa variáveis, subrotinas e identificadores de arquivo que são nomeados através do símbolo kamran para também ser endereçado via o símbolo husain Ou seja, todas as entradas de símbolo Na tabela de símbolos atual com a chave kamran agora conterá referências aos símbolos endereçados pela chave husain Para evitar tal atribuição global, você pode usar referências explícitas Por exemplo, a seguinte instrução permitirá que você abordar o conteúdo de husain através da variável Kamran kamran husain. No entanto, quaisquer matrizes como kamran e husain não será o mesmo Somente as referências especificadas explicitamente serão alteradas Para resumir, quando você atribuir um typeglob a outro, você afeta todas as entradas em uma tabela de símbolos, independentemente do tipo Quando você atribui uma referência de um tipo de variável para outro, você está apenas afetando uma entrada na tabela de símbolos. Um módulo Perl Arquivo tem o seguinte pacote de formato ModuleName Inserir código de módulo 1.O nome de arquivo tem que ser chamado O nome de um módulo deve terminar na seqüência de caracteres por convenção A instrução de pacote é a primeira linha do arquivo A última linha do arquivo deve conter a linha Com a instrução 1 Isso, com efeito, retorna um valor verdadeiro para o programa aplicativo usando o módulo Não usando a instrução 1 não permitirá que o módulo seja carregado corretamente. A instrução package diz ao interpretador Perl para iniciar com um novo domínio de namespace Basicamente, Variáveis ​​em um script Perl pertencem a um pacote chamado principal Cada variável no pacote principal pode ser referido como variável principal. Aqui está a sintaxe para tais referências packageName variableName. A única citação é sinônimo do operador de dois pontos eu cubro mais usos de O operador no próximo capítulo Por enquanto, você deve se lembrar que as duas instruções a seguir são equivalentes nome_do_grupo nome_da_variável nome_do_com pacote nome_da_variável. O sistema Ntax é considerado padrão no mundo Perl. Portanto, para preservar a legibilidade, eu uso a sintaxe de dois pontos no restante deste livro, a menos que seja absolutamente necessário fazer exceções para provar um ponto. O uso padrão de um nome de variável difere para o Atual pacote ativo no momento da compilação Assim, se você estiver no pacote e especificar uma variável pv a variável é realmente igual a Finanças pv. Usar módulos Perl usar vs require. You incluir módulos Perl em seu programa usando o uso ou o Require statement Aqui está a maneira de usar qualquer uma dessas instruções use ModuleName require ModuleName. Note que a extensão não é usada no código mostrado acima Observe também que nenhuma instrução permite que um arquivo seja incluído mais de uma vez em um programa O valor retornado de True 1 como a última instrução é necessária para permitir Perl saber que um require d ou usar d módulo carregado corretamente e deixa o interpretador Perl ignorar qualquer recarrega Em geral, é melhor usar a instrução use Module do que th E exigir Módulo instrução em um programa Perl para permanecer compatível com versões futuras de módulos Perl. For, você pode querer considerar continuar a usar a instrução require Here s why A instrução use faz um pouco mais trabalho do que a instrução require em que ele Altera o namespace do módulo que inclui outro módulo Você deseja que esta atualização extra do namespace seja feita em um programa No entanto, ao escrever código para um módulo, você pode não querer que o namespace seja alterado a menos que seja explicitamente exigido Neste evento , Você usará a instrução require. A instrução require inclui o caminho completo de um arquivo no array Inc para que as funções e variáveis ​​no arquivo do módulo s estejam em um local conhecido durante o tempo de execução. Portanto, as funções importadas de um Módulo são importados através de uma referência de módulo explícita em tempo de execução com a instrução require A instrução use faz a mesma coisa que a instrução require porque atualiza a matriz Inc com o caminho completo Nomes de módulos carregados O código para a função de uso também vai um passo além e chama uma função de importação no módulo que está sendo usado d para carregar explicitamente a lista de funções exportadas em tempo de compilação, economizando assim o tempo necessário para uma resolução explícita de uma função Nome durante a execução. Basicamente, a instrução de uso é equivalente a exigir ModuleName importação ModuleName lista de funções importadas. O uso da instrução use altera o namespace do programa s porque os nomes de função importados são inseridos na tabela de símbolos A instrução require não altera O namespace do seu programa Portanto, a seguinte instrução use ModuleName. is equivalente a esta instrução requer ModuleName. Funções são importadas de um módulo através de uma chamada para uma função chamada import Você pode escrever sua própria função de importação em um módulo, ou você pode usar a função Exportador e use sua função de importação Em quase todos os casos, você usará o módulo Exportador para fornecer uma função de importação em vez de reinventar A roda Você vai aprender mais sobre isso na próxima seção Se você decidir não usar o módulo Exportador, você terá que escrever sua própria função de importação em cada módulo que você escreve É muito mais fácil simplesmente usar o módulo Exportador e deixar Perl Fazer o trabalho para você. O Módulo de Amostra. A melhor maneira de ilustrar a semântica de como um módulo é usado em Perl é escrever um módulo simples e mostrar como usá-lo. Vamos tomar o exemplo de um tubarão de empréstimo local, Rudious Maximus , Que está simplesmente cansado de digitar o mesmo pedido de cartas de pagamento Ser um ávido fã de computadores e Perl, Rudious leva a abordagem do programador preguiçoso e escreve um módulo Perl para ajudá-lo a gerar seus memorandos e letras. Agora, em vez de digitar dentro de campos Em um arquivo de modelo de memorando, tudo o que ele tem a fazer é digitar algumas linhas para produzir sua nota agradável e ameaçadora Lista 4 1 mostra o que ele tem que digitar Listagem 4 1 Usando o módulo Letter 1 usr bin perl - w 2 3 Descomente o Linha abaixo para incluir o dir atual em Inc 4 push Inc , Pwd 5 6 use Letter 7 8 Letra Mr Mr Gambling Man, O dinheiro para Lucky Dog, Race 2 9 Letra ClaimMoneyNice 10 Letra ThankDem 11 Letter Finish. A instrução Letter use está presente para forçar o interpretador Perl a incluir o código para o módulo No programa aplicativo O módulo deve estar localizado no diretório usr lib perl5, ou você pode colocá-lo em qualquer diretório listado na matriz Inc A matriz Inc é a lista de diretórios que o interpretador Perl irá procurar ao tentar carregar o código Para o módulo nomeado O número de linha comentado 4 mostra como adicionar o diretório de trabalho atual para incluir o caminho As próximas quatro linhas no arquivo geram o assunto para a letra. Aqui está a saída de usar o módulo Letter Para Mr Gambling Man Fm Rudious Maximus, Loan Shark Dt Qua Fev 7 10 35 51 CST 1996.Re O dinheiro para Lucky Dog, Corrida 2.It chegou à minha atenção que a sua conta é muito mais devido Você vai nos pagar em breve Ou você gostaria que eu venha Ovah. Thanks para o seu O arquivo do módulo Letter é mostrado na Listagem 4 2 O nome do pacote é declarado na primeira linha Como as funções deste módulo serão exportadas, eu uso o módulo Exportador. Portanto, o uso da instrução Exportador é obrigado a herdar a funcionalidade a partir do Módulo exportador Outra etapa necessária é colocar a palavra exportada na matriz ISA para permitir a pesquisa para. A matriz ISA é uma matriz especial dentro de cada pacote Cada item na matriz lista onde mais procurar um método se ele não pode ser encontrado no atual Package A ordem na qual os pacotes são listados na matriz ISA é a ordem na qual o Perl procura por símbolos não resolvidos Uma classe que está listada na matriz ISA é referida como a classe base daquela classe particular Perl armazenará em cache métodos ausentes encontrados na base Classes para referências futuras Modificando a matriz ISA irá liberar o cache e fazer com que o Perl procure todos os métodos novamente. Vamos agora olhar para o código para na Listagem 4 2 Listagem 4 2 O pacote do módulo 1 Carta 2 3 exigir exportador 4 ISA Exportador 5 6 head1 NOME 7 8 Carta - Módulo de amostra para gerar papel timbrado para você 9 10 head1 SINOPSE 11 12 use Carta 13 14 Carta Data 15 Carta Para nome, empresa, endereço 16 17 Então um dos seguintes 18 Letter ClaimMoneyNice 19 Letter ClaimMoney 20 Letter ThreatBreakLeg 21 22 Letra ThankDem 23 Letra Finish 24 25 head1 DESCRIÇÃO 26 27 Este módulo fornece um pequeno exemplo de gerar uma carta para um 28 vizinho amigo friendly loan shark 29 30 O código começa após a declaração de corte 31 corte 32 33 EXPORTAR qw Data, 34 Para, 35 ClaimMoney, 36 ClaimMoneyNice, 37 ThankDem, 38 Finish 39 40 41 Imprimir data de hoje s 42 43 sub Letter Data 44 data data 45 print n Hoje é a data 46 47 48 sub Letra para 49 nome local turno 50 mudança de assunto local 51 impressão n Para nomear 52 imprimir n Fm Rudious Maximus, Empréstimo Shark 53 imprimir n Dt, data 54 imprimir n Re assunto 55 imprimir nn 56 imprimir nn 57 58 sub Carta ClaimMoney 59 imprimir n Você me deve dinheiro Obtenha seu ato Juntos 60 impressão N Você quer que eu envie Bruno para 61 print n collect it ou você vai pagar 62 63 64 sub Letra ClaimMoneyNice 65 print n Cheguei à minha atenção que sua conta é 66 impressão n caminho devido 67 impressão n Você Vai nos pagar em breve 68 imprimir n ou você gostaria que eu viesse ovah 69 70 71 sub Letra ThreatBreakLeg 72 impressão n aparentemente cartas como estas não ajudam 73 impressão n Vou ter que fazer um exemplo de você 74 imprimir nn Vê-lo no hospital , Pal 75 76 77 sub Letra ThankDem 78 print nn Obrigado pela sua assistência 79 80 81 sub Carta Acabamento 82 printf nnnn Atenciosamente 83 printf n Rudious n 84 85 86 1.Linhas contendo o sinal de igual são usadas para a documentação Você deve documentar cada módulo para Sua própria referência módulos Perl não precisa ser documentado, mas é uma boa idéia para escrever algumas linhas sobre o que o seu código faz A poucos anos a partir de agora, você pode esquecer o que um módulo é sobre Boa documentação é sempre uma obrigação se você quiser Para lembrar o que você fez no passado. Para este módulo de exemplo, a instrução head1 começa a documentação Tudo até a instrução de corte é ignorada pelo interpretador de Perl. Em seguida, o módulo lista todas as funções exportadas por este módulo na seção EXPORT Array A matriz EXPORT define todos os nomes de função que podem ser chamados pelo código externo Se você não listar uma função nesta matriz EXPORT, ele won t ser visto por módulos de código externo. Seguindo a matriz EXPORT é o corpo do código, um Subrotina de cada vez Depois que todas as subrotinas são definidas, a instrução final 1 termina o arquivo de módulo 1 deve ser a última linha executável no arquivo. Vamos olhar algumas das funções definidas neste módulo A primeira função a ser observada é a Simples Função de data, linhas 43 a 46, que imprime a data ea hora atuais de UNIX Não há nenhum parâmetro a esta função, e não retorna qualquer coisa significativa para trás ao chamador. Observe o uso do meu antes da data var Iable na linha 44 A palavra-chave my é usada para limitar o escopo da variável para dentro da função Date. S curly braces Código entre chaves é referido como um bloco As variáveis ​​declaradas dentro de um bloco são limitadas no escopo dentro das chaves. E 50, as variáveis ​​locais nome e assunto são visíveis para todas as funções. Você também pode declarar variáveis ​​com o qualificador local O uso de local permite que uma variável esteja no escopo para o bloco atual, bem como para outros blocos de código chamado de dentro Este bloco Assim, um local x declarado dentro de um bloco é visível a todos os blocos subseqüentes chamados de dentro deste bloco e pode ser referenciado No código de exemplo a seguir, a variável de nome da função ToTitled pode ser acessada, mas não os dados no iphone 1 sub Letter ToTitled 2 nome local shift 3 my shift telefone. O código de exemplo para mostrou como extrair um parâmetro de cada vez A sub-rotina Para leva dois parâmetros para configurar o cabeçalho para o memo. Using funções dentro de um módulo é n Ot qualquer diferente de usar e definir módulos Perl dentro do mesmo arquivo de código Parâmetros são passados ​​por referência, salvo indicação em contrário Múltiplos arrays passados ​​em uma sub-rotina, se não explicitamente dereferenced usando a barra invertida, são concatenados. A matriz de entrada em uma função é sempre uma matriz De valores escalares Passando valores por referência é a maneira preferida em Perl para passar uma grande quantidade de dados em uma sub-rotina Consulte o Capítulo 3 Referências. Outra Módulo de Módulo Financeiro. O módulo Finanças, mostrado na Listagem 4 3, é usado para fornecer cálculos simples para Valores de empréstimo Usando o módulo de Finanças é direto Todas as funções são escritas com os mesmos parâmetros, como mostrado na fórmula para as funções. Vamos olhar como o valor futuro de um investimento pode ser calculado Por exemplo, se você investir alguns dólares, Pv em uma ligação que oferece uma taxa percentual fixa, r aplicada a intervalos conhecidos por n períodos de tempo, qual é o valor da ligação no momento da sua expiração Neste ca Se, você estará usando a seguinte fórmula fv pv 1 r n. A função para obter o valor futuro é declarada como FutureValue Consulte a Lista 4 3 para ver como usá-la Listagem 4 3 Usando o módulo Finance 1 usr bin perl - w 2 3 push Inc, pwd 4 use Financiamento 5 6 loan 5000 00 7 apr 3 5 ABRIL 8 ano 10 em anos 9 10 ------------------------ ---------------------------------------- 11 Calcule o valor no final do empréstimo Se o juro 12 for aplicado a cada ano 13 ------------------------------------------ ---------------------- 14 tempo ano 15 fv1 Finanças FutureValue empréstimo, apr, tempo 16 print n Se o juro é aplicado no final do ano 17 print n O futuro Valor para um empréstimo de empréstimo n 18 impressão em uma TAEG de, abril para, tempo, anos 19 printf é 8 2f n fv1 20 21 --------------------- ------------------------------------------- 22 Calcule o valor no final Do empréstimo se juros 23 é aplicado a cada mês 24 --------------------------------------- ------------------------- 25 rate abr 12 APR 26 vezes yea R 12 em meses 27 fv2 Financiamento FuturoValor empréstimo, taxa, tempo 28 29 impressão n Se o juro é aplicado no final de cada mês 30 imprimir n O valor futuro de um empréstimo de empréstimo n 31 imprimir numa TAEG de, Meses 32 printf é 8 2f n fv2 33 34 printf n A diferença de valor é 8 2f, fv2 - fv1 35 printf n Portanto, aplicando juros em períodos de tempo mais curtos 36 printf n estamos realmente recebendo mais dinheiro em interesse n. Here é amostra Entrada e saída da Listagem 4 3 testme. If juros é aplicado no final do ano O valor futuro para um empréstimo de 5000 em uma TAEG de 3 5 para 10 anos é 7052 99.If juros é aplicado no final de cada mês O valor futuro Para um empréstimo de 5000 em uma TAEG de 3 5 por 120 meses é 7091 72.A diferença de valor é 38 73 Portanto, aplicando juros em períodos de tempo mais curtos, estamos realmente recebendo mais dinheiro em interest. The revelação na saída é o resultado Da comparação de valores entre fv1 e fv2 O valor fv1 é calculado com a aplicação de i Nterest uma vez por ano ao longo da vida da obrigação fv2 é o valor se os juros são aplicados todos os meses à taxa de juros mensal equivalente. O pacote é mostrado na Listagem 4 4 em seus estágios iniciais de desenvolvimento Listagem 4 4 O pacote 1 pacote Finanças 2 3 exigem Exportador 4 ISA Exportador 5 6 head1 7 8 Calculadora financeira - Cálculos financeiros tornados mais fáceis com Perl 9 10 cabeça 2 11 utilização Finanças 12 13 pv 10000 0 14 15 taxa 12 5 12 TAEG por mês 16 17 tempo 360 meses para o empréstimo a maturidade 18 19 fv FutureValue 20 21 print fv 22 23 corte 24 25 EXPORTACAO qw FutureValue, 26 PresentValue, 27 FVofAnnuity, 28 AnnuityOfFV, 29 getLastAverage, 30 getMovingAverage, 31 SetInterest 32 33 34 Globais, se houver 35 36 37 local defaultInterest 5 0 38 39 Sub Finance SetInterest 40 minha taxa de mudança 41 defaultInterest taxa 42 printf n defaultResultado 43 44 45 -------------------------------- ------------------------------------ 46 Notas 47 1 A taxa de juros r é dada em um valor de 0-100 48 2 O n dado em Os termos são a taxa em que os juros 49 são aplicados 50 51 ------------------------------------ -------------------------------- 52 53 ---------------- -------------------------------------------------- - 54 Valor presente de um investimento dado 55 fv - um valor futuro 56 r - taxa por período 57 n - número do período 58 ---------------------- ---------------------------------------------- 59 sub Finance FutureValue 60 meu pv, r, n 61 meu fv pv 1 r 100 n 62 retorno fv 63 64 65 ----------------------------- --------------------------------------- 66 Valor presente de um investimento dado 67 fv - a Valor futuro 68 r - taxa por período 69 n - número do período 70 ----------------------------------- --------------------------------- 71 sub Finanças PresentValue 72 meu pv 73 meu fv, r, n 74 pv fv 1 r 100 n 75 retorno pv 76 77 78 79 --------------------------------------- ----------------------------- 80 Obter o valor futuro de uma anuidade dada 81 mp - Pagamento Mensal de Anuidade 82 r - taxa por Período 8 3 n - número do período 84 ------------------------------------------- ------------------------- 85 86 sub FVofAnnuity 87 meu fv 88 meu oneR 89 meu mp, r, n 90 91 oneR 1 rn 92 fv mp OneR - 1 r 93 return fv 94 95 96 ---------------------------------------- ---------------------------- 97 Obter a anuidade dos seguintes bits de informação 98 r - taxa por período 99 n - número de período 100 fv - Valor Futuro 101 -------------------------------------------- ------------------------ 102 103 sub AnnuityOfFV 104 meu mp mp - Pagamento Mensal de Anuidade 105 meu oneR 106 meu fv, r, n 107 108 oneR 1 rn 109 mp fv r 1R - 1 110 retorno mp 111 112 113 ----------------------------------- --------------------------------- 114 Obter a média dos últimos n valores em uma matriz 115 ---- -------------------------------------------------- -------------- 116 O último número de contagem de elementos da matriz em valores 117 O número total de elementos em valores está em número 118 119 sub getLastAverage 120 my count, n Umber, valores 121 my i 122 123 my a 0 124 retorno 0 se contagem 0 125 para i 0 i contagem i 126 um número de valores - i - 1 127 128 retorna uma contagem 129 130 131 ---------- -------------------------------------------------- -------- 132 Obter uma média móvel dos valores 133 --------------------------------- ----------------------------------- 134 O tamanho da janela é o primeiro parâmetro, o número de itens no 135 passado array é seguinte Isso pode ser facilmente calculado dentro da função 136 usando a função escalar, mas a subrotina mostrada aqui 137 também está sendo usada para ilustrar como passar ponteiros A referência à matriz de valores 138 é passada em seguida, Referência ao lugar 139 os valores de retorno devem ser armazenados 140 141 sub getMovingAve 142 minha contagem, número, valores, movingAve 143 meu i 144 meu a 0 145 my v 0 146 147 retorno 0 se contagem 0 148 retorno -1 se número de contagem 149 return -2 if count 2 150 151 movingAve 0 0 152 número do movingAve - 1 0 153 para i 0 i contagem i 154 v valores i 1 55 contagem de av 156 mover-se i 0 157 158 para i contagem i número i 159 v valores i 160 contagem de av 161 v valores i - contagem - 1 162 a - v contagem 163 deslocamento Anterior 164 165 retorno 0 166 167 168 1.Look at the Declaração da função FutureValue com Os três sinais de dólar juntos significam três números escalares sendo passados ​​para a função Este escopo extra está presente para validar o tipo de parâmetros passados ​​para a função Se você fosse passar uma seqüência de caracteres em vez de um número para a função , Você receberia uma mensagem muito semelhante a esta Muitos argumentos para Finance FutureValue na linha 15, perto do tempo Execução de abortado devido a erros de compilação. O uso de protótipos ao definir funções impede que você envie valores diferentes do que a função espera Use ou para passar em uma matriz de valores Se você estiver passando por referência, use ou para mostrar uma referência escalar para uma matriz ou hash, respectivamente. Se você não usar a barra invertida, todos os outros tipos no protótipo da lista de argumentos são Ignorado Outros tipos de desqualificadores incluem um e comercial para uma referência a uma função, um asterisco para qualquer tipo e um ponto e vírgula para indicar que todos os outros parâmetros são opcionais. Agora, vamos ver a declaração da função lastMovingAverage, que especifica dois inteiros no Front seguido por uma matriz A forma como os argumentos são usados ​​na função é atribuir um valor a cada um dos dois escalares, contagem e número, enquanto tudo o resto é enviado para a matriz Olhe para a função getMovingAverage para ver como duas matrizes são passadas em Para obter a média móvel em uma lista de valores. A maneira de chamar a função getMovingAverage é mostrada na Listagem 4 5 Listagem 4 5 Usando a função de média móvel 1 usr bin perl - w 2 3 empurrar Inc, pwd 4 usar Finanças 5 6 Valores 12,22,23,24,21,23,24,23,23,21,29,27,26,28 7 mv 0 8 valores escalares de tamanho 9 print n Valores para trabalhar com n 10 print Número de valores tamanho n 11 12 ------------------------------------------------ ---------------- 13 Calcule o a Veragem da função acima 14 -------------------------------------------- -------------------- 15 ave Finanças getLastAverage 5, tamanho, valores 16 print n Média dos últimos 5 dias ave n 17 18 Finanças getMovingAve 5, size, values, mv 19 print n Média Móvel com 5 dias de janela n n. Aqui está a saída da Listagem 4 5 Valores para trabalhar com Número de valores 14.Avergente dos últimos 5 dias 26 2.A função getMovingAverage leva dois escalares e depois duas referências a arrays como Scalars Dentro da função, os dois escalares para os arrays são dereferenciados para uso como arrays numéricos O conjunto de valores retornado é inserido na área passada como a segunda referência Se os parâmetros de entrada não foram especificados para cada array referenciado, o array movingAve A referência teria sido vazia e teria causado erros em tempo de execução Em outras palavras, a declaração a seguir não é correta sub getMovingAve. The resultante spew de mensagens de erro de um protótipo de função ruim é a seguinte Utilização de uninitialized Valor na linha 128 Utilização do valor não inicializado na linha 128 Utilização do valor não inicializado na linha 128 Utilização do valor não inicializado na linha 128 Utilização do valor não inicializado na linha 128 Utilização do valor não inicializado na linha 133 Utilização do valor não inicializado na linha 135 Utilização do valor não inicializado Na linha 133 Utilização do valor não inicializado na linha 135 Utilização do valor não inicializado na linha 133 Utilização do valor não inicializado na linha 135 Utilização do valor não inicializado na linha 133 Utilização do valor não inicializado na linha 135 Utilização do valor não inicializado na linha 133 Utilização do valor não inicializado na Linha 135 Uso do valor não inicializado na linha 133 Uso do valor não inicializado na linha 135 Uso do valor não inicializado na linha 133 Uso do valor não inicializado na linha 135 Uso do valor não inicializado na linha 133 Uso do valor não inicializado na linha 135 Uso do valor não inicializado na linha 133 Uso de valor não inicializado na linha 135.Aterativa dos últimos 5 dias 26 2.Moving Média com janela de 5 dias. Esta não é obviamente a saída correta Portanto, é crit Ical que você passa por referência ao enviar mais de uma array. Global variáveis ​​para uso dentro do pacote também pode ser declarado Olhe para o segmento de código a seguir do módulo para ver o que o valor padrão da variável de interesse seria se nada foi especificado Na entrada O módulo atual exige que o interesse seja passado, mas você pode mudar isto. Aqui está um pequeno fragmento de código que pode ser adicionado ao final do programa mostrado na Listagem 4 5 para adicionar a capacidade de definir as taxas de juros 20 Local defaultInterest 5 0 21 sub Finance SetInterest 22 minha taxa shift 23 taxa -1 se taxa 0 24 defaultInterest rate 25 printf n defaultInterest rate 26.A variável local defaultInterest é declarada na linha 20 A subrotina SetInterest para modificar a taxa é declarada nas linhas 21 through 26 The rate variable uses the values passed into the subroutine and simply assigns a positive value for it You can always add more error checking if necessary. To access the defaultInterest variable s value, you could define either a subroutine that returns the value or refer to the value directly with a call to the following in your application program Finance defaultInterest. The variable holding the return value from the module function is declared as my variable The scope of this variable is within the curly braces of the function only When the called subroutine returns, the reference to my variable is returned If the calling program uses this returned reference somewhere, the link counter on the variable is not zero therefore, the storage area containing the returned values is not freed to the memory pool Thus, the function that declares my pv. and then later returns the value of pv returns a reference to the value stored at that location If the calling routine performs a call like this one Finance FVofAnnuity monthly, rate, time. there is no variable specified here into which Perl stores the returned reference therefore, any returned value or a list of values is destroyed Instead , the call with the returned value assigned to a local variable, such as this one fv Finance FVofAnnuity monthly, rate, time. maintains the variable with the value Consider the example shown in Listing 4 6, which manipulates values returned by functions Listing 4 6 Sample usage of the my function 1 usr bin perl - w 2 3 push Inc, pwd 4 use Finance 5 6 monthly 400 7 rate 0 2 i e 6 APR 8 time 36 in months 9 10 print n ------------------------------------------------ 11 fv Finance FVofAnnuity monthly, rate, time 12 printf n For a monthly 8 2f at a rate of 6 2f for d periods , 13 monthly, rate, time 14 printf n you get a future value of 8 2f , fv 15 16 fv 1 1 allow 10 gain in the house value 17 18 mo Finance AnnuityOfFV fv, rate, time 19 20 printf n To get 10 percent more at the end, i e 8 2f , fv 21 printf n you need a monthly payment value of 8 2f , mo, fv 22 23 print n ------------------------------------------------ n. Here is sample input and output for this function testme ---------- -------------------------------------- For a monthly 400 00 at a rate of 0 20 for 36 periods you get a future value of 1415603 75 To get 10 percent more at the end, i e 1557164 12 you need a monthly payment value of 440 00.Modules implement classes in a Perl program that uses the object-oriented features of Perl Included in object-oriented features is the concept of inheritance You ll learn more on the object-oriented features of Perl in Chapter 5 Object-Oriented Programming in Perl Inheritance means the process with which a module inherits the functions from its base classes A module that is nested within another module inherits its parent modules functions So inheritance in Perl is accomplished with the construct Here s the basic syntax SuperClass NextSubClass ThisClass. The file for these is stored in SuperClass NextSubClass Each double colon indicates a lower-level directory in which to look for the module Each module, in turn, declares itself as a package with statements like the f ollowing package SuperClass NextSubClass package SuperClass NextSubClass EvenLower. For example, say that you really want to create a Money class with two subclasses, Stocks and Finance Here s how to structure the hierarchy, assuming you are in the usr lib perl5 directory. Create a Money directory under the usr lib perl5 directory. Copy the existing file into the Money subdirectory. Create the new file in the Money subdirectory. Edit the file to use the line package Money Finance instead of package Finance. Edit scripts to use Money Finance as the subroutine prefix instead of Finance. Create a file in the usr lib perl5 directory. The Perl script that gets the moving average for a series of numbers is presented in Listing 4 7 Listing 4 7 Using inheriting modules 1 usr bin perl - w 2 aa pwd 3 aa Money 4 push Inc, aa 5 use Money Finance 6 values 12,22,23,24,21,23,24,23,23,21,29,27,26,28 7 mv 0 8 size scalar values 9 print n Values to work with n 10 print Number of values size n 11 -------- -------------------------------------------------------- 12 Calculate the average of the above function 13 ---------------------------------------------------------------- 14 ave Money Finance getLastAverage 5, size, values 15 print n Average of last 5 days ave n 16 Money Finance getMovingAve 5, size, values, mv 17 foreach i values 18 print n Moving with 5 days window mv i n 19 20 print n Moving Average with 5 days window n n. Lines 2 through 4 add the path to the Money subdirectory The use statement in line 5 now addresses the file in the Money subdirectory The calls to the functions within are now called with the prefix Money Finance instead of Finance Therefore, a new subdirectory is shown via the symbol when Perl is searching for modules to load. The file is not required Even so, you should create a template for future use Actually, the file would be required to put any special requirements for initialization that the entire hierarchy of modules uses The code for initialization i s placed in the BEGIN function The sample file is shown in Listing 4 8 Listing 4 8 The superclass module for 1 package Money 2 require Exporter 3 4 BEGIN 5 printf n Hello Zipping into existence for you n 6 7 1.To see the line of output from the printf statement in line 5, you have to insert the following commands at the beginning of your Perl script use Money use Money Finance. To use the functions in the module, you use this line use Money Stocks. The file appears in the Money subdirectory and is defined in the same format as the file, with the exceptions that use Stocks is used instead of use Finance and the set of functions to export is different. A number of modules are included in the Perl distribution Check the usr lib perl5 lib directory for a complete listing after you install Perl There are two kinds of modules you should know about and look for in your Perl 5 release, Pragmatic and Standard modules. Pragmatic modules, which are also like pragmas in C compiler directives, tend to affect the compilation of your program They are similar in operation to the preprocessor elements of a C program Pragmas are locally scoped so that they can be turned off with the no command Thus, the command no POSIX. turns off the POSIX features in the script These features can be turned back on with the use statement. Standard modules bundled with the Perl package include several functioning packages of code for you to use Refer to appendix B, Perl Module Archives, for a complete list of these standard modules. To find out all the modules installed on your system, issue the following command If you get an error, add the usr lib perl5 directory to your path find usr lib perl5 - name perl - print. Extension modules are written in C or a mixture of Perl and C and are dynamically loaded into Perl if and when you need them These types of modules for dynamic loading require support in the kernel Solaris lets you use these modules For a Linux machine, check the installation pages on how to upgr ade to the ELF format binaries for your Linux kernel. The term CPAN Comprehensive Perl Archive Network refers to all the hosts containing copies of sets of data, documents, and Perl modules on the Net To find out about the CPAN site nearest you, search on the keyword CPAN in search engines such as Yahoo AltaVista, or Magellan A good place to start is the site. This chapter introduced you to Perl 5 modules and described what they have to offer A more comprehensive list is found on the Internet via the addresses shown in the Web sites and. A Perl package is a set of Perl code that looks like a library file A Perl module is a package that is defined in a library file of the same name A module is designed to be reusable You can do some type checking with Perl function prototypes to see whether parameters are being passed correctly A module has to export its functions with the EXPORT array and therefore requires the Exporter module Modules are searched for in the directories listed in the Inc array. Obviously, there is a lot more to writing modules for Perl than what is shown in this chapter The simple examples in this chapter show you how to get started with Perl modules In the rest of the book I cover the modules and their features, so hang in there. I cover Perl objects, classes, and related concepts in Chapter 5.CPAN is in the industry standards, technical specifications and software library and framework skills category The next table is for comparison with the above and provides summary statistics for all permanent job vacancies with a requirement for industry standards, technical specifications and software library and framework skills. Software Library Framework Skills. Permanent job vacancies with a requirement for industry standards, technical specifications and software library and framework skills. As of all permanent IT job vacancies advertised in the UK. Number of salaries quoted. Median salary change year-on-year.90 offered a salary of more than.10 offered a salary of more than. UK excluding London median salary. CPAN Job Vacancy Trend. The job posting trend of jobs advertised citing CPAN as a proportion of all permanent or contract IT jobs with a match in the Libraries, Frameworks Software Standards category. CPAN Salary Trend. This chart provides the 3-month moving average for salaries quoted in permanent IT jobs citing CPAN. CPAN Salary Histogram. The salary distribution of IT jobs citing CPAN over the 3 months to 14 March 2017.CPAN Top 4 Job Locations. The table below looks at the demand and provides a guide to the median salaries quoted in IT jobs citing CPAN within the UK over the 3 months to 14 March 2017 The Rank Change column provides an indication of the change in demand within each location based on the same 3 month period last year. Rank Change on Same Period Last Year. Matching Permanent IT Job Ads. Median Salary Last 3 Months. The belief that a change will be easy to do correctly makes it less likely that the change will be done correctly. An XP programmer writes a unit test to clarify his intentions before he makes a change We call this test-driven design TDD or test-first programming because an API s design and implementation are guided by its test cases The programmer writes the test the way he wants the API to work, and he implements the API to fulfill the expectations set out by the test. Test-driven design helps us invent testable and usable interfaces In many ways, testability and usability are one in the same If you can t write a test for an API, it ll probably be difficult to use, and vice-versa Test-driven design gives feedback on usability before time is wasted on the implementation of an awkward API As a bonus, the test documents how the API works, by example. All of the above are good things, and few would argue with them One obvious concern is that test-driven design might slow down development It does take time to write tests, but by writing the tests first, you gain insight into the implementation, which speeds development Debugging the implementation is faster, too, thanks to immediate and reproducible feedback that only an automated test can provide. Perhaps the greatest time savings from unit testing comes a few months or years after you write the test, when you need to extend the API The unit test not only provides you with reliable documentation for how the API works, but it also validates the assumptions that went into the design of the API You can be fairly sure a change didn t break anything if the change passes all the unit tests written before it Changes that fiddle with fundamental API assumptions cause the costliest defects to debug A comprehensive unit test suite is probably the most effective defense against such unwanted changes. This chapter introduces test-driven design through the implementation of an exponential moving average EMA , a simple but useful mathematical function This chapter also explains how to use the CPAN modules Test More and Test Exception. A unit test validat es the programmer s view of the application This is quite different from an acceptance test, which is written from the customer s perspective and tests end-user functionality, usually through the same interface that an ordinary user uses In constrast, a unit test exercises an API, formally known as a unit Usually, we test an entire Perl package with a single unit test. Perl has a strong tradition of unit testing, and virtually every CPAN module comes with one or more unit tests There are also many test frameworks available from CPAN This and subsequent chapters use Test More a popular and well documented test module 2 I also use Test Exception to test deviance cases that result in calls to die 3.Test First, By Intention. Test-driven design takes unit testing to the extreme Before you write the code, you write a unit test For example, here s the first test case for the EMA exponential moving average module. This is the minimal Test More test You tell Test More how many tests to expect, and you import the module with useok as the first test case The BEGIN ensures the module s prototypes and functions are available during compilation of the rest of the unit test. The next step is to run this test to make sure that it fails. At this stage, you might be thinking, Duh Of course, it fails Test-driven design does involve lots of duhs in the beginning The baby steps are important, because they help to put you in the mindset of writing a small test followed by just enough code to satisfy the test. If you have maintenance programming experience, you may already be familiar with this procedure Maintenance programmers know they need a test to be sure that their change fixes what they think is broken They write the test and run it before fixing anything to make sure they understand a failure and that their fix works Test-driven design takes this practice to the extreme by clarifying your understanding of all changes before you make them. Now that we have clarified the need for a module called EMA duh , we implement it. And, duh, the test passes. Yeeha Time to celebrate with a double cappuccino so we don t fall asleep. That s all there is to the test-driven design loop write a test, see it fail, satisfy the test, and watch it pass For brevity, the rest of the examples leave out the test execution steps and the concomitant duhs and yeehas However, it s important to remember to include these simple steps when test-first programming If you don t remember, your programming partner probably will 4.Exponential Moving Average. Our hypothetical customer for this example would like to maintain a running average of closing stock prices for her website An EMA is commonly used for this purpose, because it is an efficient way to compute a running average You can see why if you look at the basic computation for an EMA. today s price x weight yesterday s average x 1 - weight. This algorithm produces a weighted average that favors recent history The effect of a price on the average decays exponentially over time It s a simple function that only needs to maintain two values yesterday s average and the weight Most other types of moving averages, require more data storage and more complex computations. The weight, commonly called alpha is computed in terms of uniform time periods days, in this example.2 number of days 1.For efficiency, alpha is usually computed once, and stored along with the current value of the average I chose to use an object to hold these data and a single method to compute the average. Test Things That Might Break. Since the first cut design calls for a stateful object, we need to instantiate it to use it The next case tests object creation. I sometimes forget to return the instance self so the test calls ok to check that new returns some non-zero value This case tests what I think might break An alternative, more extensive test is. This case checks that new returns a blessed reference of class EMA To me, this test is unnecessarily complex If new returns s omething, it s probably an instance It s reasonable to rely on the simpler case on that basis alone Additionally, there will be other test cases that will use the instance, and those tests will fail if new doesn t return an instance of class EMA. This point is subtle but important, because the size of a unit test suite matters The larger and slower the suite, the less useful it will be A slow unit test suite means programmers will hesitate before running all the tests, and there will be more checkins which break unit and or acceptance tests Remember, programmers are lazy and impatient, and they don t like being held back by their programming environment When you test only what might break, your unit test suite will remain a lightweight and effective development tool. Please note that if you and your partner are new to test-driven design, it s probably better to err on the side of caution and to test too much With experience, you ll learn which tests are redundant and which are especially helpful There are no magic formulas here Testing is an art that takes time to master. Satisfy The Test, Don t Trick It. Returning to our example, the implementation of new that satisfies this case is. This is the minimal code which satisfies the above test length doesn t need to be stored, and we don t need to compute alpha We ll get to them when we need to. But wait, you say, wouldn t the following code satisfy the test, too. Yes, you can trick any test However, it s nice to treat programmers like grown-ups even though we don t always act that way No one is going to watch over your shoulder to make sure you aren t cheating your own test The first implementation of new is the right amount of code, and the test is sufficient to help guide that implementation The design calls for an object to hold state, and an object creation is what needed to be coded. Test Base Cases First. What we ve tested thus far are the base cases that is, tests that validate the basic assumptions of the API When we te st basic assumptions first, we work our way towards the full complexity of the complete implementation, and it also makes the test more readable Test-first design works best when the implementation grows along with the test cases. There are two base cases for the compute function The first base case is that the initial value of the average is just the number itself There s also the case of inputting a value equal to the average, which should leave the average unchanged These cases are coded as follows. The is function from Test More lets us compare scalar values Note the change to the instantiation test case that allows us to use the instance ema for subsequent cases Reusing results of previous tests shortens the test, and makes it easier to understand. The implementation that satisfies these cases is. The initialization of alpha was added to new because compute needs the value new initializes the state of the object, and compute implements the EMA algorithm self - is initially undef so tha t case can be detected. Even though the implementation looks finished, we aren t done testing The above code might be defective Both compute test cases use the same value, and the test would pass even if, for example, self - and value were accidentally switched We also need to test that the average changes when given different values The test as it stands is too static, and it doesn t serve as a good example of how an EMA works. Choose Self-Evident Data. In a test-driven environment, programmers use the tests to learn how the API works You may hear that XPers don t like documentation That s not quite true What we prefer is self-validating documentation in the form of tests We take care to write tests that are readable and demonstrate how to use the API. One way to create readable tests is to pick good test data However, we have a little bootstrapping problem To pick good test data, we need valid values from the results of an EMA computation, but we need an EMA implementation to give us thos e values One solution is to calculate the EMA values by hand Or, we could use another EMA implementation to come up with the values While either of these choices would work, a programmer reading the test cases would have to trust them or to recompute them to verify they are correct Not to mention that we d have to get the precision exactly right for our target platform. Use The Algorithm, Luke. A better alternative is to work backwards through the algorithm to figure out some self-evident test data 5 To accomplish this, we treat the EMA algorithm as two equations by fixing some values Our goal is to have integer values for the results so we avoid floating point precision issues In addition, integer values make it easier for the programmer to follow what is going on. When we look at the equations, we see alpha is the most constrained value. today s average today s price x alpha yesterday s average x 1 - alpha. alpha 2 length 1.Therefore it makes sense to try and figure out a value of alpha t hat can produce integer results given integer prices. Starting with length 1, the values of alpha decrease as follows 1, 2 3, 1 2, 2 5, 1 3, 2 7, and 1 4 The values 1, 1 2, and 2 5 are good candidates, because they can be represented exactly in binary floating point 1 is a degenerate case, the average of a single value is always itself 1 2 is not ideal, because alpha and 1 - alpha are identical, which creates a symmetry in the first equation. today s average today s price x 0 5 yesterday s average x 0 5.We want asymmetric weights so that defects, such as swapping today s price and yesterday s average, will be detected A length of 4 yields an alpha of 2 5 0 4 , and makes the equation asymmetric. today s average today s price x 0 4 yesterday s average x 0 6.With alpha fixed at 0 4, we can pick prices that make today s average an integer Specifically, multiples of 5 work nicely I like prices to go up, so I chose 10 for today s price and 5 for yesterday s average the initial price This makes today s average equal to 7, and our test becomes. Again, I revised the base cases to keep the test short Any value in the base cases will work so we might as well save testing time through reuse. Our test and implementation are essentially complete All paths through the code are tested, and EMA could be used in production if it is used properly That is, EMA is complete if all we care about is conformant behavior The implementation currently ignores what happens when new is given an invalid value for length. Although EMA is a small part of the application, it can have a great impact on quality For example, if new is passed a length of -1, Perl throws a divide-by-zero exception when alpha is computed For other invalid values for length such as -2, new silently accepts the errant value, and compute faithfully produces non-sensical values negative averages for positive prices We can t simply ignore these cases We need to make a decision about what to do when length is invalid. One approach wou ld be to assume garbage-in garbage-out If a caller supplies -2 for length it s the caller s problem Yet this isn t what Perl s divide function does, and it isn t what happens, say, when you try to de-reference a scalar which is not a reference The Perl interpreter calls die and I ve already mentioned in the Coding Style chapter that I prefer failing fast rather than waiting until the program can do some real damage In our example, the customer s web site would display an invalid moving average, and one her customers might make an incorrect investment decision based on this information That would be bad It is better for the web site to return a server error page than to display misleading and incorrect information. Nobody likes program crashes or server errors Yet calling die is an efficient way to communicate semantic limits couplings within the application The UI programmer, in our example, may not know that an EMA s length must be a positive integer He ll find out when the application dies He can then change the design of his code and the EMA class to make this limit visible to the end user Fail fast is an important feedback mechanism If we encounter an unexpected die it tells us the application design needs to be improved. Deviance Testing. In order to test for an API that fails fast, we need to be able to catch calls to die and then call ok to validate the call did indeed end in an exception The function diesok in the module Test Exception does this for us. Since this is our last group of test cases in this chapter, here s the entire unit test with the changeds for the new deviance cases highlighted. There are now 9 cases in the unit test The first deviance case validates that length can t be negative We already know -1 will die with a divide-by-zero exception so -2 is a better choice The zero case checks the boundary condition The first valid length is 1 Lengths must be integers, and 2 5 or any other floating point number is not allowed length has no explicit upper limit Perl automatically converts integers to floating point numbers if they are too large The test already checks that floating point numbers are not allowed so no explicit upper limit check is required. The implementation that satisfies this test follows. The only change is the addition of a call to die with an unless clause This simple fail fast clause doesn t complicate the code or slow down the API, and yet it prevents subtle errors by converting an assumption into an assertion. Only Test The New API. One of the most difficult parts of testing is to know when to stop Once you have been test-infected, you may want to keep on adding cases to be sure that the API is perfect For example, a interesting test case would be to pass a NaN Not a Number to compute but that s not a test of EMA The floating point implementation of Perl behaves in a particular way with respect to NaNs 6 and Bivio Math EMA will conform to that behavior Testing that NaNs are handled properly is a job for the Perl int erpreter s test suite. Every API relies on a tremendous amount of existing code There isn t enough time to test all the existing APIs and your new API as well Just as an API should separate concerns so must a test When testing a new API, your concern should be that API and no others. Solid Foundation. In XP, we do the simplest thing that could possibly work so we can deliver business value as quickly as possible Even as we write the test and implementation, we re sure the code will change When we encounter a new customer requirement, we refactor the code, if need be, to facilitate the additional function This iterative process is called continuous design which is the subject of the next chapter It s like renovating your house whenever your needs change 7.A system or house needs a solid foundation in order to support continuous renovation Unit tests are the foundation of an XP project When designing continuously, we make sure the house doesn t fall down by running unit tests to validate al l the assumptions about an implementation We also grow the foundation before adding new functions Our test suite gives us the confidence to embrace change. Quality Software Management Vol 1 Systems Thinking Gerald Weinberg, Dorset House, 1991, p 236.Part of the Test-Simple distribution, available at I used version 0 47 for this book. Just a friendly reminder to program in pairs, especially when trying something new. Thanks to Ion Yadigaroglu for teaching me this technique. In some implementations, use of NaNs will cause a run-time error In others, they will cause all subsequent results to be a NaN. Don t let the thought of continuous house renovation scare you off Programmers are much quieter and less messy than construction workers.

No comments:

Post a Comment