{"action":"created","comment":{"url":"https://api.github.com/repos/doomspork/elixir-school/pulls/comments/56755067","id":56755067,"diff_hunk":"@@ -0,0 +1,246 @@\n+---\n+layout: page\n+title: Metaprogramação\n+category: advanced\n+order: 7\n+lang: pt\n+---\n+\n+Metaprogramação é o processo de utilização de código para escrever código. Em Elixir isso nos dá a capacidade de estender a linguagem para se adequar às nossas necessidades e dinamicamente alterar o código. Vamos começar observando como Elixir é representado sob o capô, em seguida, como modificá-lo e, finalmente, como podemos usar esse conhecimento para estendê-lo.\n+\n+\n+Uma palavra de cautela: Metaprogramação é complicado e só deve ser usado quando for absolutamente necessário. O uso excessivo certamente levará a um código complexo que é difícil de entender e depurar.\n+\n+## Sumário\n+\n+- [Quote](#quote)\n+- [Unquote](#unquote)\n+- [Macros](#macros)\n+\t- [Macros Privados](#macros-privados)\n+\t- [Higienização de Macros](#macro-hygiene)\n+\t- [Binding](#binding)\n+\n+## </a>Quote\n+\n+O primeiro passo para metaprogramação é a compreensão de como as expressões são representadas. Em Elixir, a árvore de sintaxe abstrata (AST), a representação interna do nosso código, é composta de tuplas. Estas tuplas contêm três partes: o nome da função, metadados e argumentos da função.\n+\n+A fim de ver essas estruturas internas, Elixir fornece-nos a função `quote/2`. Usando `quote/2` podemos converter o código Elixir em sua representação subjacente:\n+\n+```elixir\n+iex> quote do: 42\n+42\n+iex> quote do: \"Hello\"\n+\"Hello\"\n+iex> quote do: :world\n+:world\n+iex> quote do: 1 + 2\n+{:+, [context: Elixir, import: Kernel], [1, 2]}\n+iex> quote do: if value, do: \"True\", else: \"False\"\n+{:if, [context: Elixir, import: Kernel],\n+ [{:value, [], Elixir}, [do: \"True\", else: \"False\"]]}\n+iex(6)>\n+```\n+\n+Notou que os três primeiros exemplos não retornaram tuplas? Existe cinco literais que retornam ele mesmo quando citados (quoted):\n+\n+```elixir\n+iex> :atom\n+:atom\n+iex> \"string\"\n+\"string\"\n+iex> 1 # All numbers\n+1\n+iex> [1, 2] # Lists\n+[1, 2]\n+iex> {\"hello\", :world} # 2 element tuples\n+{\"hello\", :world}\n+```\n+\n+## Unquote\n+\n+Agora que podemos recuperar a estrutura interna do nosso código, como podemos modificá-lo? Para injetar novo código ou valores usamos `unquote/1`. Quando *unquote* em uma expressão que vai ser avaliada e injetado no AST. Para demonstrar `unquote/1` vejamos alguns exemplos:\n+\n+```elixir\n+iex> denominator = 2\n+2\n+iex> quote do: divide(42, denominator)\n+{:divide, [], [42, {:denominator, [], Elixir}]}\n+iex> quote do: divide(42, unquote(denominator))\n+{:divide, [], [42, 2]}\n+```\n+\n+No primeiro exemplo, a variável `denominator` é citado de modo que AST resultante inclua um tuplo para aceder a variável. No `unquote/1` exemplo, o código resultante inclui o valor de `denominator` no lugar.\n+\n+## Macros\n+\n+Uma vez que entendemos `quote/2` e `unquote/1` estamos prontos para mergulhar em macros. É importante lembrar que macros, como todas as metaprogramações, devem ser usadas com moderação.\n+\n+No mais simples dos termos, macros são funções especiais destinadas a retornar uma expressão entre aspas que será inserido no nosso código do aplicativo. Imagine um macro substituído por uma expressão *quote*, em vez de chamada como uma função. Com macros temos tudo que é necessário para estender Elixir e dinamicamente adicionar código para nossas aplicações.\n+\n+Começamos por definir um macro usando `defmacro/2` que em si é uma macro, como grande parte do Elixir (deixar isso afundar). Como exemplo vamos implementar `unless` como uma macro. Lembre-se que a nosso macro precisa retornar uma expressão citada:\n+\n+```elixir\n+defmodule OurMacro do\n+  defmacro unless(expr, do: block) do\n+    quote do\n+      if !unquote(expr), do: unquote(block)\n+    end\n+  end\n+end\n+```\n+\n+Vamos exigir um módulo e testar a sua Macro:\n+\n+```elixir\n+iex> require OurMacro\n+nil\n+iex> OurMacro.unless true, do: \"Hi\"\n+nil\n+iex> OurMacro.unless false, do: \"Hi\"\n+\"Hi\"\n+```\n+\n+Porque com macros substituindo o código em nossa aplicação nós podemos controlar quando é compilado. Um exemplo disso pode ser encontrado no módulo `Logger`. Quando o log está desabilitado nenhum código é injetado e o aplicativo resultante não contém referências ou chamadas de função para registro. Isso é diferente de outras linguagens onde ainda existe a sobrecarga de uma chamada de função, mesmo quando a implementação é NOP.\n+\n+Para demonstrar isso, vamos fazer um logger simples que pode ser ativado ou desativado:\n+\n+```elixir\n+defmodule Logger do\n+  defmacro log(msg) do\n+    if Application.get_env(:logger, :enabled) do\n+      quote do\n+        IO.puts(\"Logged message: #{unquote(msg)}\")\n+      end\n+    end\n+  end\n+end\n+\n+defmodule Example do\n+  require Logger\n+\n+  def test do\n+    Logger.log(\"This is a log message\")\n+  end\n+end\n+```\n+\n+Com o registo ativado a nossa fuçao `test` resultaria em um código procurando algo parecido com isto:\n+\n+```elixir\n+def test do\n+  IO.puts(\"Logged message: #{\"This is a log message\"}\")\n+end\n+```\n+\n+Mas se desativarmos o log, o código resultante seria:\n+\n+```elixir\n+def test do\n+end\n+```\n+\n+### Macros Privados\n+\n+Embora não seja tão comum, Elixir suporta macros privadas. A macro privada é definida com `defmacro` e só pode ser chamado a partir do módulo no qual ele foi definido. macros privados devem ser definidas antes do código que as invoca.\n+\n+### <a name=\"higienizacao-do-macro\">Higienização do Macro ","path":"pt/lessons/advanced/metaprogramming.md","position":146,"original_position":146,"commit_id":"8b1fa2bb98240a541d59d78faa1583f6b7c7a065","original_commit_id":"8b1fa2bb98240a541d59d78faa1583f6b7c7a065","user":{"login":"pragmaticivan","id":301291,"avatar_url":"https://avatars.githubusercontent.com/u/301291?v=3","gravatar_id":"","url":"https://api.github.com/users/pragmaticivan","html_url":"https://github.com/pragmaticivan","followers_url":"https://api.github.com/users/pragmaticivan/followers","following_url":"https://api.github.com/users/pragmaticivan/following{/other_user}","gists_url":"https://api.github.com/users/pragmaticivan/gists{/gist_id}","starred_url":"https://api.github.com/users/pragmaticivan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pragmaticivan/subscriptions","organizations_url":"https://api.github.com/users/pragmaticivan/orgs","repos_url":"https://api.github.com/users/pragmaticivan/repos","events_url":"https://api.github.com/users/pragmaticivan/events{/privacy}","received_events_url":"https://api.github.com/users/pragmaticivan/received_events","type":"User","site_admin":false},"body":"Looks good here, but still need to use this one in the list of topics.","created_at":"2016-03-19T21:01:48Z","updated_at":"2016-03-19T21:01:48Z","html_url":"https://github.com/doomspork/elixir-school/pull/175#discussion_r56755067","pull_request_url":"https://api.github.com/repos/doomspork/elixir-school/pulls/175","_links":{"self":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/comments/56755067"},"html":{"href":"https://github.com/doomspork/elixir-school/pull/175#discussion_r56755067"},"pull_request":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/175"}}},"pull_request":{"url":"https://api.github.com/repos/doomspork/elixir-school/pulls/175","id":63164576,"html_url":"https://github.com/doomspork/elixir-school/pull/175","diff_url":"https://github.com/doomspork/elixir-school/pull/175.diff","patch_url":"https://github.com/doomspork/elixir-school/pull/175.patch","issue_url":"https://api.github.com/repos/doomspork/elixir-school/issues/175","number":175,"state":"open","locked":false,"title":"File metaprogramming.md for Portuguese(Brazil)","user":{"login":"DenysonSoares","id":3386365,"avatar_url":"https://avatars.githubusercontent.com/u/3386365?v=3","gravatar_id":"","url":"https://api.github.com/users/DenysonSoares","html_url":"https://github.com/DenysonSoares","followers_url":"https://api.github.com/users/DenysonSoares/followers","following_url":"https://api.github.com/users/DenysonSoares/following{/other_user}","gists_url":"https://api.github.com/users/DenysonSoares/gists{/gist_id}","starred_url":"https://api.github.com/users/DenysonSoares/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DenysonSoares/subscriptions","organizations_url":"https://api.github.com/users/DenysonSoares/orgs","repos_url":"https://api.github.com/users/DenysonSoares/repos","events_url":"https://api.github.com/users/DenysonSoares/events{/privacy}","received_events_url":"https://api.github.com/users/DenysonSoares/received_events","type":"User","site_admin":false},"body":"File metaprogramming.md - Translation complete","created_at":"2016-03-17T02:22:00Z","updated_at":"2016-03-19T21:01:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6b6dd6b58e49902410bd98dfbd249cffff93ed4d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/doomspork/elixir-school/pulls/175/commits","review_comments_url":"https://api.github.com/repos/doomspork/elixir-school/pulls/175/comments","review_comment_url":"https://api.github.com/repos/doomspork/elixir-school/pulls/comments{/number}","comments_url":"https://api.github.com/repos/doomspork/elixir-school/issues/175/comments","statuses_url":"https://api.github.com/repos/doomspork/elixir-school/statuses/8b1fa2bb98240a541d59d78faa1583f6b7c7a065","head":{"label":"DenysonSoares:metaprogramming.md","ref":"metaprogramming.md","sha":"8b1fa2bb98240a541d59d78faa1583f6b7c7a065","user":{"login":"DenysonSoares","id":3386365,"avatar_url":"https://avatars.githubusercontent.com/u/3386365?v=3","gravatar_id":"","url":"https://api.github.com/users/DenysonSoares","html_url":"https://github.com/DenysonSoares","followers_url":"https://api.github.com/users/DenysonSoares/followers","following_url":"https://api.github.com/users/DenysonSoares/following{/other_user}","gists_url":"https://api.github.com/users/DenysonSoares/gists{/gist_id}","starred_url":"https://api.github.com/users/DenysonSoares/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DenysonSoares/subscriptions","organizations_url":"https://api.github.com/users/DenysonSoares/orgs","repos_url":"https://api.github.com/users/DenysonSoares/repos","events_url":"https://api.github.com/users/DenysonSoares/events{/privacy}","received_events_url":"https://api.github.com/users/DenysonSoares/received_events","type":"User","site_admin":false},"repo":{"id":53699245,"name":"elixir-school","full_name":"DenysonSoares/elixir-school","owner":{"login":"DenysonSoares","id":3386365,"avatar_url":"https://avatars.githubusercontent.com/u/3386365?v=3","gravatar_id":"","url":"https://api.github.com/users/DenysonSoares","html_url":"https://github.com/DenysonSoares","followers_url":"https://api.github.com/users/DenysonSoares/followers","following_url":"https://api.github.com/users/DenysonSoares/following{/other_user}","gists_url":"https://api.github.com/users/DenysonSoares/gists{/gist_id}","starred_url":"https://api.github.com/users/DenysonSoares/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DenysonSoares/subscriptions","organizations_url":"https://api.github.com/users/DenysonSoares/orgs","repos_url":"https://api.github.com/users/DenysonSoares/repos","events_url":"https://api.github.com/users/DenysonSoares/events{/privacy}","received_events_url":"https://api.github.com/users/DenysonSoares/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/DenysonSoares/elixir-school","description":"Lessons about the Elixir programming language","fork":true,"url":"https://api.github.com/repos/DenysonSoares/elixir-school","forks_url":"https://api.github.com/repos/DenysonSoares/elixir-school/forks","keys_url":"https://api.github.com/repos/DenysonSoares/elixir-school/keys{/key_id}","collaborators_url":"https://api.github.com/repos/DenysonSoares/elixir-school/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/DenysonSoares/elixir-school/teams","hooks_url":"https://api.github.com/repos/DenysonSoares/elixir-school/hooks","issue_events_url":"https://api.github.com/repos/DenysonSoares/elixir-school/issues/events{/number}","events_url":"https://api.github.com/repos/DenysonSoares/elixir-school/events","assignees_url":"https://api.github.com/repos/DenysonSoares/elixir-school/assignees{/user}","branches_url":"https://api.github.com/repos/DenysonSoares/elixir-school/branches{/branch}","tags_url":"https://api.github.com/repos/DenysonSoares/elixir-school/tags","blobs_url":"https://api.github.com/repos/DenysonSoares/elixir-school/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/DenysonSoares/elixir-school/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/DenysonSoares/elixir-school/git/refs{/sha}","trees_url":"https://api.github.com/repos/DenysonSoares/elixir-school/git/trees{/sha}","statuses_url":"https://api.github.com/repos/DenysonSoares/elixir-school/statuses/{sha}","languages_url":"https://api.github.com/repos/DenysonSoares/elixir-school/languages","stargazers_url":"https://api.github.com/repos/DenysonSoares/elixir-school/stargazers","contributors_url":"https://api.github.com/repos/DenysonSoares/elixir-school/contributors","subscribers_url":"https://api.github.com/repos/DenysonSoares/elixir-school/subscribers","subscription_url":"https://api.github.com/repos/DenysonSoares/elixir-school/subscription","commits_url":"https://api.github.com/repos/DenysonSoares/elixir-school/commits{/sha}","git_commits_url":"https://api.github.com/repos/DenysonSoares/elixir-school/git/commits{/sha}","comments_url":"https://api.github.com/repos/DenysonSoares/elixir-school/comments{/number}","issue_comment_url":"https://api.github.com/repos/DenysonSoares/elixir-school/issues/comments{/number}","contents_url":"https://api.github.com/repos/DenysonSoares/elixir-school/contents/{+path}","compare_url":"https://api.github.com/repos/DenysonSoares/elixir-school/compare/{base}...{head}","merges_url":"https://api.github.com/repos/DenysonSoares/elixir-school/merges","archive_url":"https://api.github.com/repos/DenysonSoares/elixir-school/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/DenysonSoares/elixir-school/downloads","issues_url":"https://api.github.com/repos/DenysonSoares/elixir-school/issues{/number}","pulls_url":"https://api.github.com/repos/DenysonSoares/elixir-school/pulls{/number}","milestones_url":"https://api.github.com/repos/DenysonSoares/elixir-school/milestones{/number}","notifications_url":"https://api.github.com/repos/DenysonSoares/elixir-school/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/DenysonSoares/elixir-school/labels{/name}","releases_url":"https://api.github.com/repos/DenysonSoares/elixir-school/releases{/id}","deployments_url":"https://api.github.com/repos/DenysonSoares/elixir-school/deployments","created_at":"2016-03-11T22:00:03Z","updated_at":"2016-03-11T22:00:04Z","pushed_at":"2016-03-18T02:01:12Z","git_url":"git://github.com/DenysonSoares/elixir-school.git","ssh_url":"git@github.com:DenysonSoares/elixir-school.git","clone_url":"https://github.com/DenysonSoares/elixir-school.git","svn_url":"https://github.com/DenysonSoares/elixir-school","homepage":"https://elixirschool.com","size":731,"stargazers_count":0,"watchers_count":0,"language":"CSS","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"doomspork:master","ref":"master","sha":"b4449b37068ad63261eaf5369161718dd44dbc48","user":{"login":"doomspork","id":73386,"avatar_url":"https://avatars.githubusercontent.com/u/73386?v=3","gravatar_id":"","url":"https://api.github.com/users/doomspork","html_url":"https://github.com/doomspork","followers_url":"https://api.github.com/users/doomspork/followers","following_url":"https://api.github.com/users/doomspork/following{/other_user}","gists_url":"https://api.github.com/users/doomspork/gists{/gist_id}","starred_url":"https://api.github.com/users/doomspork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/doomspork/subscriptions","organizations_url":"https://api.github.com/users/doomspork/orgs","repos_url":"https://api.github.com/users/doomspork/repos","events_url":"https://api.github.com/users/doomspork/events{/privacy}","received_events_url":"https://api.github.com/users/doomspork/received_events","type":"User","site_admin":false},"repo":{"id":36616176,"name":"elixir-school","full_name":"doomspork/elixir-school","owner":{"login":"doomspork","id":73386,"avatar_url":"https://avatars.githubusercontent.com/u/73386?v=3","gravatar_id":"","url":"https://api.github.com/users/doomspork","html_url":"https://github.com/doomspork","followers_url":"https://api.github.com/users/doomspork/followers","following_url":"https://api.github.com/users/doomspork/following{/other_user}","gists_url":"https://api.github.com/users/doomspork/gists{/gist_id}","starred_url":"https://api.github.com/users/doomspork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/doomspork/subscriptions","organizations_url":"https://api.github.com/users/doomspork/orgs","repos_url":"https://api.github.com/users/doomspork/repos","events_url":"https://api.github.com/users/doomspork/events{/privacy}","received_events_url":"https://api.github.com/users/doomspork/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/doomspork/elixir-school","description":"Lessons about the Elixir programming language","fork":false,"url":"https://api.github.com/repos/doomspork/elixir-school","forks_url":"https://api.github.com/repos/doomspork/elixir-school/forks","keys_url":"https://api.github.com/repos/doomspork/elixir-school/keys{/key_id}","collaborators_url":"https://api.github.com/repos/doomspork/elixir-school/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/doomspork/elixir-school/teams","hooks_url":"https://api.github.com/repos/doomspork/elixir-school/hooks","issue_events_url":"https://api.github.com/repos/doomspork/elixir-school/issues/events{/number}","events_url":"https://api.github.com/repos/doomspork/elixir-school/events","assignees_url":"https://api.github.com/repos/doomspork/elixir-school/assignees{/user}","branches_url":"https://api.github.com/repos/doomspork/elixir-school/branches{/branch}","tags_url":"https://api.github.com/repos/doomspork/elixir-school/tags","blobs_url":"https://api.github.com/repos/doomspork/elixir-school/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/doomspork/elixir-school/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/doomspork/elixir-school/git/refs{/sha}","trees_url":"https://api.github.com/repos/doomspork/elixir-school/git/trees{/sha}","statuses_url":"https://api.github.com/repos/doomspork/elixir-school/statuses/{sha}","languages_url":"https://api.github.com/repos/doomspork/elixir-school/languages","stargazers_url":"https://api.github.com/repos/doomspork/elixir-school/stargazers","contributors_url":"https://api.github.com/repos/doomspork/elixir-school/contributors","subscribers_url":"https://api.github.com/repos/doomspork/elixir-school/subscribers","subscription_url":"https://api.github.com/repos/doomspork/elixir-school/subscription","commits_url":"https://api.github.com/repos/doomspork/elixir-school/commits{/sha}","git_commits_url":"https://api.github.com/repos/doomspork/elixir-school/git/commits{/sha}","comments_url":"https://api.github.com/repos/doomspork/elixir-school/comments{/number}","issue_comment_url":"https://api.github.com/repos/doomspork/elixir-school/issues/comments{/number}","contents_url":"https://api.github.com/repos/doomspork/elixir-school/contents/{+path}","compare_url":"https://api.github.com/repos/doomspork/elixir-school/compare/{base}...{head}","merges_url":"https://api.github.com/repos/doomspork/elixir-school/merges","archive_url":"https://api.github.com/repos/doomspork/elixir-school/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/doomspork/elixir-school/downloads","issues_url":"https://api.github.com/repos/doomspork/elixir-school/issues{/number}","pulls_url":"https://api.github.com/repos/doomspork/elixir-school/pulls{/number}","milestones_url":"https://api.github.com/repos/doomspork/elixir-school/milestones{/number}","notifications_url":"https://api.github.com/repos/doomspork/elixir-school/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/doomspork/elixir-school/labels{/name}","releases_url":"https://api.github.com/repos/doomspork/elixir-school/releases{/id}","deployments_url":"https://api.github.com/repos/doomspork/elixir-school/deployments","created_at":"2015-05-31T18:27:42Z","updated_at":"2016-03-19T15:07:58Z","pushed_at":"2016-03-19T18:48:19Z","git_url":"git://github.com/doomspork/elixir-school.git","ssh_url":"git@github.com:doomspork/elixir-school.git","clone_url":"https://github.com/doomspork/elixir-school.git","svn_url":"https://github.com/doomspork/elixir-school","homepage":"https://elixirschool.com","size":821,"stargazers_count":312,"watchers_count":312,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":74,"mirror_url":null,"open_issues_count":19,"forks":74,"open_issues":19,"watchers":312,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/175"},"html":{"href":"https://github.com/doomspork/elixir-school/pull/175"},"issue":{"href":"https://api.github.com/repos/doomspork/elixir-school/issues/175"},"comments":{"href":"https://api.github.com/repos/doomspork/elixir-school/issues/175/comments"},"review_comments":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/175/comments"},"review_comment":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/175/commits"},"statuses":{"href":"https://api.github.com/repos/doomspork/elixir-school/statuses/8b1fa2bb98240a541d59d78faa1583f6b7c7a065"}}}}