├── README.md ├── basic-types ├── with-match.exs ├── with-scope-fmt.exs └── with-scope.exs ├── control ├── case.ex ├── case1.exs ├── case2.exs ├── fizzbuzz.ex ├── fizzbuzz1.ex ├── fizzbuzz2.ex └── fizzbuzz3.ex ├── duper └── 1 │ └── duper │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── dups │ ├── lib │ ├── duper.ex │ └── duper │ │ ├── application.ex │ │ ├── gatherer.ex │ │ ├── path_finder.ex │ │ ├── results.ex │ │ ├── worker.ex │ │ └── worker_supervisor.ex │ ├── mix.exs │ ├── mix.lock │ └── test │ ├── duper │ └── results_test.exs │ ├── duper_test.exs │ └── test_helper.exs ├── enum ├── countdown.exs ├── longest_line.exs ├── pipeline.exs ├── stream1.exs ├── stream2.exs └── stream3.exs ├── exceptions ├── catch.ex ├── defexception.ex └── exception.ex ├── first_steps └── handle_open.exs ├── functions └── pin.exs ├── intro └── hello.exs ├── lists ├── mylist.exs ├── mylist1.exs ├── reduce.exs ├── swap.exs ├── weather.exs ├── weather2.exs └── weather3.exs ├── macros ├── dumper.exs ├── dumper1.exs ├── eg.exs ├── eg1.exs ├── eg2.exs ├── hygiene.ex ├── macro_binding.exs ├── macro_no_binding.exs ├── myif.ex └── operators.ex ├── maps ├── access1.exs ├── access2.exs ├── access3.exs ├── book_room.exs ├── defstruct.exs ├── defstruct1.exs ├── dynamic_nested.exs ├── get_in_func.exs ├── keywords.exs ├── nested.exs └── query.exs ├── mm ├── attributes.exs ├── attributes1.exs ├── default_params.exs ├── default_params1.exs ├── default_params2.exs ├── factorial1-bad.exs ├── factorial1.exs ├── factorial2.exs ├── guard.exs ├── import.exs ├── times.exs └── times1.exs ├── nodes └── ticker.ex ├── odds ├── color.exs ├── eval │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── apps │ │ ├── evaluator │ │ │ ├── .formatter.exs │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── lib │ │ │ │ └── evaluator.ex │ │ │ ├── mix.exs │ │ │ └── test │ │ │ │ ├── evaluator_test.exs │ │ │ │ └── test_helper.exs │ │ └── line_sigil │ │ │ ├── .formatter.exs │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── lib │ │ │ └── line_sigil.ex │ │ │ ├── mix.exs │ │ │ └── test │ │ │ ├── line_sigil_test.exs │ │ │ └── test_helper.exs │ ├── config │ │ └── config.exs │ └── mix.exs └── line_sigil.exs ├── otp-app ├── sequence │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ ├── sequence.ex │ │ └── sequence │ │ │ ├── application.ex │ │ │ ├── server.ex │ │ │ └── stash.ex │ ├── mix.exs │ └── test │ │ ├── sequence_test.exs │ │ └── test_helper.exs ├── sequence_v0 │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── config │ │ └── config.exs │ ├── lib │ │ ├── sequence.ex │ │ └── sequence │ │ │ ├── application.ex │ │ │ ├── server.ex │ │ │ └── stash.ex │ ├── mix.exs │ ├── mix.lock │ ├── rel │ │ ├── config.exs │ │ ├── plugins │ │ │ └── .gitignore │ │ └── vm.args │ └── test │ │ ├── sequence_test.exs │ │ └── test_helper.exs ├── sequence_v1 │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── config │ │ └── config.exs │ ├── lib │ │ ├── sequence.ex │ │ └── sequence │ │ │ ├── application.ex │ │ │ ├── server.ex │ │ │ └── stash.ex │ ├── mix.exs │ ├── mix.lock │ ├── rel │ │ ├── config.exs │ │ ├── plugins │ │ │ └── .gitignore │ │ └── vm.args │ └── test │ │ ├── sequence_test.exs │ │ └── test_helper.exs └── sequence_v2 │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── config │ └── config.exs │ ├── lib │ ├── sequence.ex │ └── sequence │ │ ├── application.ex │ │ ├── server.ex │ │ └── stash.ex │ ├── mix.exs │ ├── mix.lock │ ├── rel │ ├── config.exs │ ├── plugins │ │ └── .gitignore │ └── vm.args │ └── test │ ├── sequence_test.exs │ └── test_helper.exs ├── otp-server ├── 1 │ └── sequence │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ ├── sequence.ex │ │ └── sequence │ │ │ └── server.ex │ │ ├── mix.exs │ │ └── test │ │ ├── sequence_test.exs │ │ └── test_helper.exs ├── 2 │ └── sequence │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ ├── sequence.ex │ │ └── sequence │ │ │ └── server.ex │ │ ├── mix.exs │ │ └── test │ │ ├── sequence_test.exs │ │ └── test_helper.exs └── 3 │ └── sequence │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ ├── sequence.ex │ └── sequence │ │ ├── impl.ex │ │ └── server.ex │ ├── mix.exs │ └── test │ ├── sequence_test.exs │ └── test_helper.exs ├── otp-supervisor ├── 1 │ └── sequence │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ ├── sequence.ex │ │ └── sequence │ │ │ ├── application.ex │ │ │ └── server.ex │ │ ├── mix.exs │ │ └── test │ │ ├── sequence_test.exs │ │ └── test_helper.exs └── 2 │ └── sequence │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ ├── sequence.ex │ └── sequence │ │ ├── application.ex │ │ ├── server.ex │ │ └── stash.ex │ ├── mix.exs │ └── test │ ├── sequence_test.exs │ └── test_helper.exs ├── project ├── 0 │ └── issues │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ └── cli.ex │ │ ├── mix.exs │ │ └── test │ │ ├── issues_test.exs │ │ └── test_helper.exs ├── 1 │ └── issues │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ └── cli.ex │ │ ├── mix.exs │ │ └── test │ │ ├── cli_test.exs │ │ ├── issues_test.exs │ │ └── test_helper.exs ├── 2 │ └── issues │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ ├── cli.ex │ │ │ └── github_issues.ex │ │ ├── mix.exs │ │ ├── mix.lock │ │ └── test │ │ ├── cli_test.exs │ │ ├── issues_test.exs │ │ └── test_helper.exs ├── 3 │ └── issues │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ ├── cli.ex │ │ │ └── github_issues.ex │ │ ├── mix.exs │ │ ├── mix.lock │ │ └── test │ │ ├── cli_test.exs │ │ ├── issues_test.exs │ │ └── test_helper.exs ├── 4 │ └── issues │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── config │ │ └── config.exs │ │ ├── issues │ │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ ├── cli.ex │ │ │ ├── github_issues.ex │ │ │ └── table_formatter.ex │ │ ├── mix.exs │ │ ├── mix.lock │ │ └── test │ │ ├── cli_test.exs │ │ ├── issues_test.exs │ │ ├── table_formatter_test.exs │ │ └── test_helper.exs ├── 5 │ └── issues │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── config │ │ └── config.exs │ │ ├── doc │ │ ├── .build │ │ ├── 404.html │ │ ├── Issues.CLI.html │ │ ├── Issues.GithubIssues.html │ │ ├── Issues.TableFormatter.html │ │ ├── Issues.epub │ │ ├── Issues.html │ │ ├── api-reference.html │ │ ├── dist │ │ │ ├── app-f27ff079945e43879c46.js │ │ │ ├── elixir-a172fe91e725dcb259e2.css │ │ │ ├── html │ │ │ │ └── fonts │ │ │ │ │ ├── icomoon.eot │ │ │ │ │ ├── icomoon.svg │ │ │ │ │ ├── icomoon.ttf │ │ │ │ │ └── icomoon.woff │ │ │ ├── search_items-d6b809f7c6.js │ │ │ └── sidebar_items-cda1b4999b.js │ │ ├── index.html │ │ └── search.html │ │ ├── issues │ │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ ├── cli.ex │ │ │ ├── github_issues.ex │ │ │ └── table_formatter.ex │ │ ├── mix.exs │ │ ├── mix.lock │ │ └── test │ │ ├── cli_test.exs │ │ ├── doc_test.exs │ │ ├── issues_test.exs │ │ ├── table_formatter_test.exs │ │ └── test_helper.exs ├── 1a │ └── issues │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ ├── cli.ex │ │ │ └── github_issues.ex │ │ ├── mix.exs │ │ ├── mix.lock │ │ └── test │ │ ├── cli_test.exs │ │ ├── issues_test.exs │ │ └── test_helper.exs ├── 3a │ └── issues │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── config │ │ └── config.exs │ │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ ├── cli.ex │ │ │ └── github_issues.ex │ │ ├── mix.exs │ │ ├── mix.lock │ │ └── test │ │ ├── cli_test.exs │ │ ├── issues_test.exs │ │ └── test_helper.exs └── 3b │ └── issues │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── config │ └── config.exs │ ├── lib │ ├── issues.ex │ └── issues │ │ ├── cli.ex │ │ └── github_issues.ex │ ├── mix.exs │ ├── mix.lock │ └── test │ ├── cli_test.exs │ ├── issues_test.exs │ └── test_helper.exs ├── protocols ├── basic.exs ├── dueling-banjos.mid ├── is_collection.exs ├── midi.exs ├── midi_algebra.exs └── midi_inspect.exs ├── spawn ├── chain.exs ├── fact_tr.exs ├── fib.exs ├── fib_agent.exs ├── link1.exs ├── link2.exs ├── link3.exs ├── monitor1.exs ├── pmap.exs ├── pmap1.exs ├── spawn-basic.ex ├── spawn1.exs ├── spawn2.exs ├── spawn3.exs └── spawn4.exs ├── strings ├── parse.exs └── utf-iterate.ex ├── tasks ├── agent_dict.exs ├── anagrams.exs ├── anagrams_dist.exs ├── my_app │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ ├── my_app.ex │ │ └── my_app │ │ │ ├── application.ex │ │ │ └── my_task.ex │ ├── mix.exs │ └── test │ │ ├── my_app_test.exs │ │ └── test_helper.exs ├── tasks1.exs ├── tasks2.exs └── words │ ├── list1 │ ├── list2 │ ├── list3 │ └── list4 ├── tooling ├── buggy │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ └── buggy.ex │ ├── mix.exs │ └── test │ │ ├── buggy_test.exs │ │ └── test_helper.exs ├── issues │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── config │ │ └── config.exs │ ├── doc │ │ ├── .build │ │ ├── 404.html │ │ ├── Issues.CLI.html │ │ ├── Issues.GithubIssues.html │ │ ├── Issues.TableFormatter.html │ │ ├── Issues.epub │ │ ├── Issues.html │ │ ├── api-reference.html │ │ ├── dist │ │ │ ├── app-f27ff079945e43879c46.js │ │ │ ├── elixir-a172fe91e725dcb259e2.css │ │ │ ├── html │ │ │ │ └── fonts │ │ │ │ │ ├── icomoon.eot │ │ │ │ │ ├── icomoon.svg │ │ │ │ │ ├── icomoon.ttf │ │ │ │ │ └── icomoon.woff │ │ │ ├── search_items-d6b809f7c6.js │ │ │ └── sidebar_items-cda1b4999b.js │ │ ├── index.html │ │ └── search.html │ ├── issues │ ├── lib │ │ ├── issues.ex │ │ └── issues │ │ │ ├── cli.ex │ │ │ ├── github_issues.ex │ │ │ └── table_formatter.ex │ ├── mix.exs │ ├── mix.lock │ └── test │ │ ├── cli_test.exs │ │ ├── doc_test.exs │ │ ├── issues_test.exs │ │ ├── table_formatter_test.exs │ │ └── test_helper.exs └── pbt │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ ├── pbt.ex │ └── stats.ex │ ├── mix.exs │ ├── mix.lock │ └── test │ ├── describe.exs │ ├── pbt_test.exs │ ├── stats_property_test.exs │ └── test_helper.exs ├── typespecs ├── no_specs │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ │ └── no_specs.ex │ ├── mix.exs │ ├── mix.lock │ └── test │ │ ├── no_specs_test.exs │ │ └── test_helper.exs └── simple │ ├── .formatter.exs │ ├── .gitignore │ ├── README.md │ ├── lib │ ├── simple.ex │ └── simple │ │ └── client.ex │ ├── mix.exs │ ├── mix.lock │ └── test │ ├── simple_test.exs │ └── test_helper.exs └── use ├── tracer.ex ├── tracer1.ex ├── tracer2.ex ├── tracer3.ex └── tracer4.ex /README.md: -------------------------------------------------------------------------------- 1 | # programming-elixir-kr 2 | Example code of Programming Elixir (Korean Edition) 3 | -------------------------------------------------------------------------------- /basic-types/with-match.exs: -------------------------------------------------------------------------------- 1 | result = with {:ok, file} = File.open("/etc/passwd"), 2 | content = IO.read(file, :all), 3 | :ok = File.close(file), 4 | [_, uid, gid] <- Regex.run(~r/^xxx:.*?:(\d+):(\d+)/, content) 5 | do 6 | "Group: #{gid}, User: #{uid}" 7 | end 8 | IO.puts inspect(result) #=> nil 9 | -------------------------------------------------------------------------------- /basic-types/with-scope-fmt.exs: -------------------------------------------------------------------------------- 1 | content = "Now is the time" 2 | 3 | lp = 4 | with {:ok, file} = File.open("/etc/passwd"), 5 | content = IO.read(file, :all), 6 | :ok = File.close(file), 7 | [_, uid, gid] = Regex.run(~r/^_lp:.*?:(\d+):(\d+)/m, content) do 8 | "Group: #{gid}, User: #{uid}" 9 | end 10 | 11 | # => Group: 26, User: 26 12 | IO.puts(lp) 13 | # => Now is the time 14 | IO.puts(content) 15 | -------------------------------------------------------------------------------- /basic-types/with-scope.exs: -------------------------------------------------------------------------------- 1 | content = "Now is the time" 2 | 3 | lp = with {:ok, file} = File.open("/etc/passwd"), 4 | content = IO.read(file, :all), # 위와 같은 변수명 사용 5 | :ok = File.close(file), 6 | [_, uid, gid] = Regex.run(~r/^_lp:.*?:(\d+):(\d+)/m, content) 7 | do 8 | "Group: #{gid}, User: #{uid}" 9 | end 10 | 11 | IO.puts lp #=> Group: 26, User: 26 12 | IO.puts content #=> Now is the time 13 | -------------------------------------------------------------------------------- /control/case.ex: -------------------------------------------------------------------------------- 1 | case File.open("case.ex") do 2 | { :ok, file } -> 3 | IO.puts "First line: #{IO.read(file, :line)}" 4 | { :error, reason } -> 5 | IO.puts "Failed to open file: #{reason}" 6 | end 7 | -------------------------------------------------------------------------------- /control/case1.exs: -------------------------------------------------------------------------------- 1 | defmodule Users do 2 | dave = %{ name: "Dave", state: "TX", likes: "programming" } 3 | case dave do 4 | %{state: some_state} = person -> 5 | IO.puts "#{person.name} lives in #{some_state}" 6 | _ -> 7 | IO.puts "No matches" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /control/case2.exs: -------------------------------------------------------------------------------- 1 | defmodule Bouncer do 2 | dave = %{name: "Dave", age: 27} 3 | case dave do 4 | person = %{age: age} when is_number(age) and age >= 21 -> 5 | IO.puts "You are cleared to enter the Foo Bar, #{person.name}" 6 | _ -> 7 | IO.puts "Sorry, no admission" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /control/fizzbuzz.ex: -------------------------------------------------------------------------------- 1 | defmodule FizzBuzz do 2 | 3 | def upto(n) when n > 0, do: _upto(1, n, []) 4 | 5 | defp _upto(_current, 0, result), do: Enum.reverse result 6 | 7 | defp _upto(current, left, result) do 8 | next_answer = 9 | cond do 10 | rem(current, 3) == 0 and rem(current, 5) == 0 -> 11 | "FizzBuzz" 12 | rem(current, 3) == 0 -> 13 | "Fizz" 14 | rem(current, 5) == 0 -> 15 | "Buzz" 16 | true -> 17 | current 18 | end 19 | _upto(current+1, left-1, [ next_answer | result ]) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /control/fizzbuzz1.ex: -------------------------------------------------------------------------------- 1 | defmodule FizzBuzz do 2 | 3 | def upto(n) when n > 0, do: _downto(n, []) 4 | 5 | defp _downto(0, result), do: result 6 | defp _downto(current, result) do 7 | next_answer = 8 | cond do 9 | rem(current, 3) == 0 and rem(current, 5) == 0 -> 10 | "FizzBuzz" 11 | rem(current, 3) == 0 -> 12 | "Fizz" 13 | rem(current, 5) == 0 -> 14 | "Buzz" 15 | true -> 16 | current 17 | end 18 | _downto(current-1, [ next_answer | result ]) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /control/fizzbuzz2.ex: -------------------------------------------------------------------------------- 1 | defmodule FizzBuzz do 2 | def upto(n) when n > 0 do 3 | 1..n |> Enum.map(&fizzbuzz/1) 4 | end 5 | 6 | defp fizzbuzz(n) do 7 | cond do 8 | rem(n, 3) == 0 and rem(n, 5) == 0 -> 9 | "FizzBuzz" 10 | rem(n, 3) == 0 -> 11 | "Fizz" 12 | rem(n, 5) == 0 -> 13 | "Buzz" 14 | true -> 15 | n 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /control/fizzbuzz3.ex: -------------------------------------------------------------------------------- 1 | defmodule FizzBuzz do 2 | def upto(n) when n > 0, do: 1..n |> Enum.map(&fizzbuzz/1) 3 | 4 | defp fizzbuzz(n), do: _fizzword(n, rem(n, 3), rem(n, 5)) 5 | 6 | defp _fizzword(_n, 0, 0), do: "FizzBuzz" 7 | defp _fizzword(_n, 0, _), do: "Fizz" 8 | defp _fizzword(_n, _, 0), do: "Buzz" 9 | defp _fizzword( n, _, _), do: n 10 | end 11 | -------------------------------------------------------------------------------- /duper/1/duper/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /duper/1/duper/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | duper-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /duper/1/duper/README.md: -------------------------------------------------------------------------------- 1 | # Duper 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `duper` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:duper, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/duper](https://hexdocs.pm/duper). 21 | 22 | -------------------------------------------------------------------------------- /duper/1/duper/lib/duper.ex: -------------------------------------------------------------------------------- 1 | defmodule Duper do 2 | @moduledoc """ 3 | Documentation for `Duper`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Duper.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /duper/1/duper/lib/duper/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Duper.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | Duper.Results, 12 | {Duper.PathFinder, "./"}, 13 | Duper.WorkerSupervisor, 14 | {Duper.Gatherer, 2} 15 | ] 16 | 17 | # See https://hexdocs.pm/elixir/Supervisor.html 18 | # for other strategies and supported options 19 | opts = [strategy: :one_for_all, name: Duper.Supervisor] 20 | Supervisor.start_link(children, opts) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /duper/1/duper/lib/duper/gatherer.ex: -------------------------------------------------------------------------------- 1 | defmodule Duper.Gatherer do 2 | use GenServer 3 | 4 | @me Gatherer 5 | 6 | # api 7 | 8 | def start_link(worker_count) do 9 | GenServer.start_link(__MODULE__, worker_count, name: @me) 10 | end 11 | 12 | def done() do 13 | GenServer.cast(@me, :done) 14 | end 15 | 16 | def result(path, hash) do 17 | GenServer.cast(@me, { :result, path, hash }) 18 | end 19 | 20 | # 서버 21 | 22 | def init(worker_count) do 23 | Process.send_after(self(), :kickoff, 0) 24 | { :ok, worker_count } 25 | end 26 | 27 | def handle_info(:kickoff, worker_count) do 28 | 1..worker_count 29 | |> Enum.each(fn _ -> Duper.WorkerSupervisor.add_worker() end) 30 | { :noreply, worker_count } 31 | end 32 | 33 | def handle_cast(:done, _worker_count = 1) do 34 | report_results() 35 | System.halt(0) 36 | end 37 | 38 | def handle_cast(:done, worker_count) do 39 | { :noreply, worker_count - 1 } 40 | end 41 | 42 | def handle_cast({:result, path, hash}, worker_count) do 43 | Duper.Results.add_hash_for(path, hash) 44 | { :noreply, worker_count } 45 | end 46 | 47 | defp report_results() do 48 | IO.puts "Results:\n" 49 | Duper.Results.find_duplicates() 50 | |> Enum.each(&IO.inspect/1) 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /duper/1/duper/lib/duper/path_finder.ex: -------------------------------------------------------------------------------- 1 | defmodule Duper.PathFinder do 2 | use GenServer 3 | 4 | @me PathFinder 5 | 6 | def start_link(root) do 7 | GenServer.start_link(__MODULE__, root, name: @me) 8 | end 9 | 10 | def next_path() do 11 | GenServer.call(@me, :next_path) 12 | end 13 | 14 | def init(path) do 15 | DirWalker.start_link(path) 16 | end 17 | 18 | def handle_call(:next_path, _from, dir_walker) do 19 | path = case DirWalker.next(dir_walker) do 20 | [ path ] -> path 21 | other -> other 22 | end 23 | 24 | { :reply, path, dir_walker } 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /duper/1/duper/lib/duper/results.ex: -------------------------------------------------------------------------------- 1 | defmodule Duper.Results do 2 | 3 | use GenServer 4 | 5 | @me __MODULE__ 6 | 7 | 8 | # API 9 | 10 | def start_link(_) do 11 | GenServer.start_link(__MODULE__, :no_args, name: @me) 12 | end 13 | 14 | def add_hash_for(path, hash) do 15 | GenServer.cast(@me, { :add, path, hash }) 16 | end 17 | 18 | def find_duplicates() do 19 | GenServer.call(@me, :find_duplicates) 20 | end 21 | 22 | # 서버 23 | 24 | def init(:no_args) do 25 | { :ok, %{} } 26 | end 27 | 28 | def handle_cast({ :add, path, hash }, results) do 29 | results = 30 | Map.update( 31 | results, # 이 맵 안에서 32 | hash, # 이 키에 해당하는 항목을 찾는다 33 | [ path ], # 항목이 없으면 이 값을 저장하고 34 | fn existing -> # 항목이 있으면 이 함수의 결과로 항목을 갱신한다 35 | [ path | existing ] 36 | end) 37 | { :noreply, results } 38 | end 39 | 40 | def handle_call(:find_duplicates, _from, results) do 41 | { 42 | :reply, 43 | hashes_with_more_than_one_path(results), 44 | results 45 | } 46 | end 47 | 48 | defp hashes_with_more_than_one_path(results) do 49 | results 50 | |> Enum.filter(fn { _hash, paths } -> length(paths) > 1 end) 51 | |> Enum.map(&elem(&1, 1)) 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /duper/1/duper/lib/duper/worker.ex: -------------------------------------------------------------------------------- 1 | defmodule Duper.Worker do 2 | use GenServer, restart: :transient 3 | 4 | def start_link(_) do 5 | GenServer.start_link(__MODULE__, :no_args) 6 | end 7 | 8 | def init(:no_args) do 9 | Process.send_after(self(), :do_one_file, 0) 10 | { :ok, nil } 11 | end 12 | 13 | def handle_info(:do_one_file, _) do 14 | Duper.PathFinder.next_path() 15 | |> add_result() 16 | end 17 | 18 | defp add_result(nil) do 19 | Duper.Gatherer.done() 20 | {:stop, :normal, nil} 21 | end 22 | 23 | defp add_result(path) do 24 | Duper.Gatherer.result(path, hash_of_file_at(path)) 25 | send(self(), :do_one_file) 26 | { :noreply, nil } 27 | end 28 | 29 | defp hash_of_file_at(path) do 30 | File.stream!(path, [], 1024*1024) 31 | |> Enum.reduce( 32 | :crypto.hash_init(:md5), 33 | fn (block, hash) -> 34 | :crypto.hash_update(hash, block) 35 | end) 36 | |> :crypto.hash_final() 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /duper/1/duper/lib/duper/worker_supervisor.ex: -------------------------------------------------------------------------------- 1 | defmodule Duper.WorkerSupervisor do 2 | use DynamicSupervisor 3 | 4 | @me WorkerSupervisor 5 | 6 | def start_link(_) do 7 | DynamicSupervisor.start_link(__MODULE__, :no_args, name: @me) 8 | end 9 | 10 | def init(:no_args) do 11 | DynamicSupervisor.init(strategy: :one_for_one) 12 | end 13 | 14 | def add_worker() do 15 | {:ok, _pid} = DynamicSupervisor.start_child(@me, Duper.Worker) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /duper/1/duper/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Duper.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :duper, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger, :crypto], 18 | mod: {Duper.Application, []} 19 | ] 20 | end 21 | 22 | # Run "mix help deps" to learn about dependencies. 23 | defp deps do 24 | [ 25 | dir_walker: "~> 0.0.7" 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /duper/1/duper/mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "dir_walker": {:hex, :dir_walker, "0.0.8", "5332225074e4887e6e60ca0242af490215f296511ded4df18d554ae25394f727", [:mix], [], "hexpm", "2f4fb16e6427523700df9eb12eece5679ad4459aaefb1ca3cb580184bfc8d173"}, 3 | } 4 | -------------------------------------------------------------------------------- /duper/1/duper/test/duper/results_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Duper.ResultsTest do 2 | use ExUnit.Case 3 | alias Duper.Results 4 | 5 | test "can add entries to the results" do 6 | 7 | Results.add_hash_for("path1", 123) 8 | Results.add_hash_for("path2", 456) 9 | Results.add_hash_for("path3", 123) 10 | Results.add_hash_for("path4", 789) 11 | Results.add_hash_for("path5", 456) 12 | Results.add_hash_for("path6", 999) 13 | 14 | duplicates = Results.find_duplicates() 15 | 16 | assert length(duplicates) == 2 17 | 18 | assert ~w{path3 path1} in duplicates 19 | assert ~w{path5 path2} in duplicates 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /duper/1/duper/test/duper_test.exs: -------------------------------------------------------------------------------- 1 | defmodule DuperTest do 2 | use ExUnit.Case 3 | doctest Duper 4 | 5 | test "greets the world" do 6 | assert Duper.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /duper/1/duper/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /enum/countdown.exs: -------------------------------------------------------------------------------- 1 | defmodule Countdown do 2 | 3 | def sleep(seconds) do 4 | receive do 5 | after seconds*1000 -> nil 6 | end 7 | end 8 | 9 | def say(text) do 10 | spawn fn -> :os.cmd('say #{text}') end 11 | end 12 | 13 | def timer do 14 | Stream.resource( 15 | fn -> # 분 단위가 바뀔 때까지 남은 초를 계산한다 16 | {_h,_m,s} = :erlang.time 17 | 60 - s - 1 18 | end, 19 | 20 | fn # 1초 뒤 카운트다운 값을 반환한다 21 | 0 -> 22 | {:halt, 0} 23 | 24 | count -> 25 | sleep(1) 26 | { [inspect(count)], count - 1 } 27 | end, 28 | 29 | fn _ -> nil end # 할당 해제할 자원 없음 30 | ) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /enum/longest_line.exs: -------------------------------------------------------------------------------- 1 | IO.puts File.read!("/usr/share/dict/words") 2 | |> String.split 3 | |> Enum.max_by(&String.length/1) 4 | -------------------------------------------------------------------------------- /enum/pipeline.exs: -------------------------------------------------------------------------------- 1 | [ 1, 2, 3, 4, 5 ] 2 | #=> [ 1, 2, 3, 4, 5 ] 3 | |> Enum.map(&(&1*&1)) 4 | #=> [ 1, 4, 9, 16, 25 ] 5 | |> Enum.with_index 6 | #=> [ {1, 0}, {4, 1}, {9, 2}, {16, 3}, {25, 4} ] 7 | |> Enum.map(fn {value, index} -> value - index end) 8 | #=> [1, 3, 7, 13, 21] 9 | |> IO.inspect #=> [1, 3, 7, 13, 21] 10 | -------------------------------------------------------------------------------- /enum/stream1.exs: -------------------------------------------------------------------------------- 1 | [1,2,3,4] 2 | |> Stream.map(&(&1*&1)) 3 | |> Stream.map(&(&1+1)) 4 | |> Stream.filter(fn x -> rem(x,2) == 1 end) 5 | |> Enum.to_list 6 | -------------------------------------------------------------------------------- /enum/stream2.exs: -------------------------------------------------------------------------------- 1 | IO.puts File.open!("/usr/share/dict/words") 2 | |> IO.stream(:line) 3 | |> Enum.max_by(&String.length/1) 4 | -------------------------------------------------------------------------------- /enum/stream3.exs: -------------------------------------------------------------------------------- 1 | IO.puts File.stream!("/usr/share/dict/words") |> Enum.max_by(&String.length/1) 2 | -------------------------------------------------------------------------------- /exceptions/catch.ex: -------------------------------------------------------------------------------- 1 | defmodule Catch do 2 | def start(n) do 3 | try do 4 | incite(n) 5 | catch 6 | :exit, code -> "Exited with code #{inspect code}" 7 | :throw, value -> "throw called with #{inspect value}" 8 | what, value -> "Caught #{inspect what} with #{inspect value}" 9 | end 10 | end 11 | 12 | defp incite(1) do 13 | exit(:something_bad_happened) 14 | end 15 | 16 | defp incite(2) do 17 | throw {:animal, "wombat"} 18 | end 19 | 20 | defp incite(3) do 21 | :erlang.error "Oh no!" 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /exceptions/defexception.ex: -------------------------------------------------------------------------------- 1 | defmodule KinectProtocolError do 2 | defexception message: "Kinect protocol error", 3 | can_retry: false 4 | 5 | def full_message(me) do 6 | "Kinect failed: #{me.message}, retriable: #{me.can_retry}" 7 | end 8 | end 9 | 10 | defmodule B do 11 | def talk_to_kinect do 12 | raise KinectProtocolError, message: "usb unplugged", can_retry: true 13 | end 14 | 15 | def schedule_retry do 16 | IO.puts "Retrying in 10 seconds" 17 | end 18 | 19 | def start do 20 | #START:user 21 | try do 22 | talk_to_kinect() 23 | rescue 24 | error in [KinectProtocolError] -> 25 | IO.puts KinectProtocolError.full_message(error) 26 | if error.can_retry, do: schedule_retry() 27 | end 28 | #END:user 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /exceptions/exception.ex: -------------------------------------------------------------------------------- 1 | defmodule Boom do 2 | def start(n) do 3 | try do 4 | raise_error(n) 5 | rescue 6 | [ FunctionClauseError, RuntimeError ] -> 7 | IO.puts "no function match or runtime error" 8 | error in [ArithmeticError] -> 9 | IO.inspect error 10 | IO.puts "Uh-oh! Arithmetic error" 11 | reraise "too late, we're doomed", __STACKTRACE__ 12 | other_errors -> 13 | IO.puts "Disaster! #{inspect other_errors}" 14 | after 15 | IO.puts "DONE!" 16 | end 17 | end 18 | 19 | defp raise_error(0) do 20 | IO.puts "No error" 21 | end 22 | 23 | defp raise_error(val = 1) do 24 | IO.puts "About to divide by zero" 25 | 1 / (val-1) 26 | end 27 | 28 | defp raise_error(2) do 29 | IO.puts "About to call a function that doesn't exist" 30 | raise_error(99) 31 | end 32 | 33 | defp raise_error(3) do 34 | IO.puts "About to try creating a directory with no permission" 35 | File.mkdir!("/not_allowed") 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /first_steps/handle_open.exs: -------------------------------------------------------------------------------- 1 | handle_open = fn 2 | {:ok, file} -> "First line: #{IO.read(file, :line)}" 3 | {_, error} -> "Error: #{:file.format_error(error)}" 4 | end 5 | 6 | IO.puts handle_open.(File.open("Rakefile")) # 존재하는 파일을 연다. 7 | IO.puts handle_open.(File.open("nonexistent")) # 존재하지 않는 파일을 연다. 8 | -------------------------------------------------------------------------------- /functions/pin.exs: -------------------------------------------------------------------------------- 1 | defmodule Greeter do 2 | def for(name, greeting) do 3 | fn 4 | (^name) -> "#{greeting} #{name}" 5 | (_) -> "I don't know you" 6 | end 7 | end 8 | end 9 | 10 | mr_valim = Greeter.for("José", "Oi!") 11 | 12 | IO.puts mr_valim.("José") # => Oi! José 13 | IO.puts mr_valim.("Dave") # => I don't know you 14 | -------------------------------------------------------------------------------- /intro/hello.exs: -------------------------------------------------------------------------------- 1 | IO.puts "Hello, World!" 2 | -------------------------------------------------------------------------------- /lists/mylist.exs: -------------------------------------------------------------------------------- 1 | defmodule MyList do 2 | def len([]), do: 0 3 | def len([ head | tail ]), do: 1 + len(tail) 4 | end 5 | -------------------------------------------------------------------------------- /lists/mylist1.exs: -------------------------------------------------------------------------------- 1 | defmodule MyList do 2 | def len([]), do: 0 3 | def len([ _head | tail ]), do: 1 + len(tail) 4 | 5 | def square([]), do: [] 6 | def square([ head | tail ]), do: [ head*head | square(tail) ] 7 | 8 | def add_1([]), do: [] 9 | def add_1([ head | tail ]), do: [ head+1 | add_1(tail) ] 10 | 11 | def map([], _func), do: [] 12 | def map([ head | tail ], func), do: [ func.(head) | map(tail, func) ] 13 | end 14 | -------------------------------------------------------------------------------- /lists/reduce.exs: -------------------------------------------------------------------------------- 1 | defmodule MyList do 2 | def reduce([], value, _) do 3 | value 4 | end 5 | def reduce([head | tail], value, func) do 6 | reduce(tail, func.(head, value), func) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lists/swap.exs: -------------------------------------------------------------------------------- 1 | defmodule Swapper do 2 | def swap([]), do: [] 3 | def swap([ a, b | tail ]), do: [ b, a | swap(tail) ] 4 | def swap([_]), do: raise "Can't swap a list with an odd number of elements" 5 | end 6 | -------------------------------------------------------------------------------- /lists/weather.exs: -------------------------------------------------------------------------------- 1 | defmodule WeatherHistory do 2 | def test_data do 3 | [ 4 | [1366225622, 26, 15, 0.125], 5 | [1366225622, 27, 15, 0.45], 6 | [1366225622, 28, 21, 0.25], 7 | [1366229222, 26, 19, 0.081], 8 | [1366229222, 27, 17, 0.468], 9 | [1366229222, 28, 15, 0.60], 10 | [1366232822, 26, 22, 0.095], 11 | [1366232822, 27, 21, 0.05], 12 | [1366232822, 28, 24, 0.03], 13 | [1366236422, 26, 17, 0.025] 14 | ] 15 | end 16 | 17 | def for_location_27([]), do: [] 18 | def for_location_27([ [time, 27, temp, rain ] | tail]) do 19 | [ [time, 27, temp, rain] | for_location_27(tail) ] 20 | end 21 | def for_location_27([ _ | tail]), do: for_location_27(tail) 22 | end 23 | -------------------------------------------------------------------------------- /lists/weather2.exs: -------------------------------------------------------------------------------- 1 | defmodule WeatherHistory do 2 | def test_data do 3 | [ 4 | [1366225622, 26, 15, 0.125], 5 | [1366225622, 27, 15, 0.45], 6 | [1366225622, 28, 21, 0.25], 7 | [1366229222, 26, 19, 0.081], 8 | [1366229222, 27, 17, 0.468], 9 | [1366229222, 28, 15, 0.60], 10 | [1366232822, 26, 22, 0.095], 11 | [1366232822, 27, 21, 0.05], 12 | [1366232822, 28, 24, 0.03], 13 | [1366236422, 26, 17, 0.025] 14 | ] 15 | end 16 | 17 | def for_location([], _target_loc), do: [] 18 | def for_location([ [time, target_loc, temp, rain ] | tail], target_loc) do 19 | [ [time, target_loc, temp, rain] | for_location(tail, target_loc) ] 20 | end 21 | def for_location([ _ | tail], target_loc), do: for_location(tail, target_loc) 22 | end 23 | -------------------------------------------------------------------------------- /lists/weather3.exs: -------------------------------------------------------------------------------- 1 | defmodule WeatherHistory do 2 | def test_data do 3 | [ 4 | [1366225622, 26, 15, 0.125], 5 | [1366225622, 27, 15, 0.45], 6 | [1366225622, 28, 21, 0.25], 7 | [1366229222, 26, 19, 0.081], 8 | [1366229222, 27, 17, 0.468], 9 | [1366229222, 28, 15, 0.60], 10 | [1366232822, 26, 22, 0.095], 11 | [1366232822, 27, 21, 0.05], 12 | [1366232822, 28, 24, 0.03], 13 | [1366236422, 26, 17, 0.025] 14 | ] 15 | end 16 | 17 | def for_location([], _target_loc), do: [] 18 | def for_location([ head = [_, target_loc, _, _ ] | tail], target_loc) do 19 | [ head | for_location(tail, target_loc) ] 20 | end 21 | def for_location([ _ | tail], target_loc), do: for_location(tail, target_loc) 22 | end 23 | -------------------------------------------------------------------------------- /macros/dumper.exs: -------------------------------------------------------------------------------- 1 | defmodule My do 2 | defmacro macro(param) do 3 | IO.inspect param 4 | end 5 | end 6 | 7 | defmodule Test do 8 | require My 9 | 10 | # 이 값들은 내부 표현과 같다 11 | My.macro :atom #=> :atom 12 | My.macro 1 #=> 1 13 | My.macro 1.0 #=> 1.0 14 | My.macro [1,2,3] #=> [1,2,3] 15 | My.macro "binaries" #=> "binaries" 16 | My.macro { 1, 2 } #=> {1,2} 17 | My.macro do: 1 #=> [do: 1] 18 | 19 | # 다음 값들은 3-튜플로 표현된다 20 | 21 | My.macro { 1,2,3,4,5 } 22 | # => {:"{}",[line: 20],[1,2,3,4,5]} 23 | 24 | My.macro do: ( a = 1; a+a ) 25 | # => [do: 26 | # {:__block__,[], 27 | # [{:=,[line: 22],[{:a,[line: 22],nil},1]}, 28 | # {:+,[line: 22],[{:a,[line: 22],nil},{:a,[line: 22],nil}]}]}] 29 | 30 | My.macro do 31 | 1+2 32 | else 33 | 3+4 34 | end 35 | # => [do: {:+,[line: 24],[1,2]}, 36 | # else: {:+,[line: 26],[3,4]}] 37 | 38 | end 39 | -------------------------------------------------------------------------------- /macros/dumper1.exs: -------------------------------------------------------------------------------- 1 | defmodule My do 2 | defmacro macro(param) do 3 | IO.inspect param 4 | end 5 | end 6 | 7 | require My 8 | 9 | # 이 값들은 내부 표현과 같다 10 | My.macro :atom #=> :atom 11 | My.macro 1 #=> 1 12 | My.macro 1.0 #=> 1.0 13 | My.macro [1,2,3] #=> [1,2,3] 14 | My.macro "binaries" #=> "binaries" 15 | My.macro { 1, 2 } #=> {1,2} 16 | My.macro do: 1 #=> [do: 1] 17 | 18 | # 아래 값들은 3-튜플로 표현된다 19 | 20 | My.macro { 1,2,3,4,5 } 21 | # => {:"{}",[line: 20],[1,2,3,4,5]} 22 | 23 | My.macro do: ( a = 1; a+a ) 24 | # => [do: 25 | # {:__block__,[], 26 | # [{:=,[line: 22],[{:a,[line: 22],nil},1]}, 27 | # {:+,[line: 22],[{:a,[line: 22],nil},{:a,[line: 22],nil}]}]}] 28 | 29 | My.macro do 30 | 1+2 31 | else 32 | 3+4 33 | end 34 | # => [do: {:+,[line: 24],[1,2]}, 35 | # else: {:+,[line: 26],[3,4]}] 36 | -------------------------------------------------------------------------------- /macros/eg.exs: -------------------------------------------------------------------------------- 1 | defmodule My do 2 | defmacro macro(code) do 3 | IO.inspect code 4 | code 5 | end 6 | end 7 | 8 | defmodule Test do 9 | require My 10 | My.macro(IO.puts("hello")) 11 | end 12 | -------------------------------------------------------------------------------- /macros/eg1.exs: -------------------------------------------------------------------------------- 1 | defmodule My do 2 | defmacro macro(code) do 3 | IO.inspect code 4 | quote do: IO.puts "Different code" 5 | end 6 | end 7 | 8 | defmodule Test do 9 | require My 10 | My.macro(IO.puts("hello")) 11 | end 12 | -------------------------------------------------------------------------------- /macros/eg2.exs: -------------------------------------------------------------------------------- 1 | defmodule My do 2 | defmacro macro(code) do 3 | quote do 4 | IO.inspect(unquote(code)) 5 | end 6 | end 7 | end 8 | 9 | defmodule Test do 10 | require My 11 | My.macro(1 + 2) 12 | end 13 | -------------------------------------------------------------------------------- /macros/hygiene.ex: -------------------------------------------------------------------------------- 1 | defmodule Scope do 2 | defmacro update_local(val) do 3 | local = "some value" 4 | result = quote do 5 | local = unquote(val) 6 | IO.puts "End of macro body, local = #{local}" 7 | end 8 | IO.puts "In macro definition, local = #{local}" 9 | result 10 | end 11 | end 12 | 13 | defmodule Test do 14 | require Scope 15 | 16 | local = 123 17 | Scope.update_local("cat") 18 | IO.puts "On return, local = #{local}" 19 | end 20 | -------------------------------------------------------------------------------- /macros/macro_binding.exs: -------------------------------------------------------------------------------- 1 | defmodule My do 2 | defmacro mydef(name) do 3 | quote bind_quoted: [name: name] do 4 | def unquote(name)(), do: unquote(name) 5 | end 6 | end 7 | end 8 | 9 | defmodule Test do 10 | require My 11 | [ :fred, :bert ] |> Enum.each(&My.mydef(&1)) 12 | end 13 | 14 | IO.puts Test.fred #=> fred 15 | -------------------------------------------------------------------------------- /macros/macro_no_binding.exs: -------------------------------------------------------------------------------- 1 | defmodule My do 2 | defmacro mydef(name) do 3 | quote do 4 | def unquote(name)(), do: unquote(name) 5 | end 6 | end 7 | end 8 | 9 | defmodule Test do 10 | require My 11 | [ :fred, :bert ] |> Enum.each(&My.mydef(&1)) 12 | end 13 | 14 | IO.puts Test.fred 15 | -------------------------------------------------------------------------------- /macros/myif.ex: -------------------------------------------------------------------------------- 1 | defmodule My do 2 | defmacro if(condition, clauses) do 3 | do_clause = Keyword.get(clauses, :do, nil) 4 | else_clause = Keyword.get(clauses, :else, nil) 5 | quote do 6 | case unquote(condition) do 7 | val when val in [false, nil] -> unquote(else_clause) 8 | _ -> unquote(do_clause) 9 | end 10 | end 11 | end 12 | end 13 | 14 | defmodule Test do 15 | require My 16 | My.if 1==2 do 17 | IO.puts "1 == 2" 18 | else 19 | IO.puts "1 != 2" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /macros/operators.ex: -------------------------------------------------------------------------------- 1 | defmodule Operators do 2 | defmacro a + b do 3 | quote do 4 | to_string(unquote(a)) <> to_string(unquote(b)) 5 | end 6 | end 7 | end 8 | 9 | defmodule Test do 10 | IO.puts(123 + 456) #=> "579" 11 | import Kernel, except: [+: 2] 12 | import Operators 13 | IO.puts(123 + 456) #=> "123456" 14 | end 15 | 16 | IO.puts(123 + 456) #=> "579" 17 | -------------------------------------------------------------------------------- /maps/access1.exs: -------------------------------------------------------------------------------- 1 | cast = [ 2 | %{ 3 | character: "Buttercup", 4 | actor: %{ 5 | first: "Robin", 6 | last: "Wright" 7 | }, 8 | role: "princess" 9 | }, 10 | %{ 11 | character: "Westley", 12 | actor: %{ 13 | first: "Cary", 14 | last: "Elwes" 15 | }, 16 | role: "farm boy" 17 | } 18 | ] 19 | 20 | IO.inspect get_in(cast, [Access.all(), :character]) 21 | #=> ["Buttercup", "Westley"] 22 | 23 | IO.inspect get_in(cast, [Access.at(1), :role]) 24 | #=> "farm boy" 25 | 26 | IO.inspect get_and_update_in(cast, [Access.all(), :actor, :last], 27 | fn (val) -> {val, String.upcase(val)} end) 28 | #=> {["Wright", "Elwes"], 29 | # [%{actor: %{first: "Robin", last: "WRIGHT"}, character: "Buttercup", 30 | # role: "princess"}, 31 | # %{actor: %{first: "Cary", last: "ELWES"}, character: "Westley", 32 | # role: "farm boy"}]} 33 | -------------------------------------------------------------------------------- /maps/access2.exs: -------------------------------------------------------------------------------- 1 | cast = [ 2 | %{ 3 | character: "Buttercup", 4 | actor: {"Robin", "Wright"}, 5 | role: "princess" 6 | }, 7 | %{ 8 | character: "Westley", 9 | actor: {"Carey", "Elwes"}, 10 | role: "farm boy" 11 | } 12 | ] 13 | 14 | IO.inspect get_in(cast, [Access.all(), :actor, Access.elem(1)]) 15 | #=> ["Wright", "Elwes"] 16 | 17 | IO.inspect get_and_update_in(cast, [Access.all(), :actor, Access.elem(1)], 18 | fn (val) -> {val, String.reverse(val)} end) 19 | #=> {["Wright", "Elwes"], 20 | # [%{actor: {"Robin", "thgirW"}, character: "Buttercup", role: "princess"}, 21 | # %{actor: {"Carey", "sewlE"}, character: "Westley", role: "farm boy"}]} 22 | -------------------------------------------------------------------------------- /maps/access3.exs: -------------------------------------------------------------------------------- 1 | cast = %{ 2 | buttercup: %{ 3 | actor: {"Robin", "Wright"}, 4 | role: "princess" 5 | }, 6 | westley: %{ 7 | actor: {"Carey", "Elwes"}, 8 | role: "farm boy" 9 | } 10 | } 11 | 12 | IO.inspect get_in(cast, [Access.key(:westley), :actor, Access.elem(1)]) 13 | #=> "Elwes" 14 | 15 | IO.inspect get_and_update_in(cast, [Access.key(:buttercup), :role], 16 | fn (val) -> {val, "Queen"} end) 17 | #=> {"princess", 18 | # %{buttercup: %{actor: {"Robin", "Wright"}, role: "Queen"}, 19 | # westley: %{actor: {"Carey", "Elwes"}, role: "farm boy"}}} 20 | -------------------------------------------------------------------------------- /maps/book_room.exs: -------------------------------------------------------------------------------- 1 | people = [ 2 | %{ name: "Grumpy", height: 1.24 }, 3 | %{ name: "Dave", height: 1.88 }, 4 | %{ name: "Dopey", height: 1.32 }, 5 | %{ name: "Shaquille", height: 2.16 }, 6 | %{ name: "Sneezy", height: 1.28 } 7 | ] 8 | 9 | defmodule HotelRoom do 10 | 11 | def book(%{name: name, height: height}) 12 | when height > 1.9 do 13 | IO.puts "Need extra-long bed for #{name}" 14 | end 15 | 16 | def book(%{name: name, height: height}) 17 | when height < 1.3 do 18 | IO.puts "Need low shower controls for #{name}" 19 | end 20 | 21 | def book(person) do 22 | IO.puts "Need regular bed for #{person.name}" 23 | end 24 | 25 | end 26 | 27 | people |> Enum.each(&HotelRoom.book/1) 28 | 29 | #=> Need low shower controls for Grumpy 30 | # Need regular bed for Dave 31 | # Need regular bed for Dopey 32 | # Need extra-long bed for Shaquille 33 | # Need low shower controls for Sneezy 34 | -------------------------------------------------------------------------------- /maps/defstruct.exs: -------------------------------------------------------------------------------- 1 | defmodule Subscriber do 2 | defstruct name: "", paid: false, over_18: true 3 | end 4 | -------------------------------------------------------------------------------- /maps/defstruct1.exs: -------------------------------------------------------------------------------- 1 | defmodule Attendee do 2 | defstruct name: "", paid: false, over_18: true 3 | 4 | def may_attend_after_party(attendee = %Attendee{}) do 5 | attendee.paid && attendee.over_18 6 | end 7 | 8 | def print_vip_badge(%Attendee{name: name}) when name != "" do 9 | IO.puts "Very cheap badge for #{name}" 10 | end 11 | 12 | def print_vip_badge(%Attendee{}) do 13 | raise "missing name for badge" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /maps/dynamic_nested.exs: -------------------------------------------------------------------------------- 1 | nested = %{ 2 | buttercup: %{ 3 | actor: %{ 4 | first: "Robin", 5 | last: "Wright" 6 | }, 7 | role: "princess" 8 | }, 9 | westley: %{ 10 | actor: %{ 11 | first: "Cary", 12 | last: "Elwis" # 오타! 13 | }, 14 | role: "farm boy" 15 | } 16 | } 17 | 18 | IO.inspect get_in(nested, [:buttercup]) 19 | # => %{actor: %{first: "Robin", last: "Wright"}, role: "princess"} 20 | 21 | IO.inspect get_in(nested, [:buttercup, :actor]) 22 | # => %{first: "Robin", last: "Wright"} 23 | 24 | IO.inspect get_in(nested, [:buttercup, :actor, :first]) 25 | # => "Robin" 26 | 27 | IO.inspect put_in(nested, [:westley, :actor, :last], "Elwes") 28 | # => %{buttercup: %{actor: %{first: "Robin", last: "Wright"}, role: "princess"}, 29 | # => westley: %{actor: %{first: "Cary", last: "Elwes"}, role: "farm boy"}} 30 | -------------------------------------------------------------------------------- /maps/get_in_func.exs: -------------------------------------------------------------------------------- 1 | authors = [ 2 | %{ name: "José", language: "Elixir" }, 3 | %{ name: "Matz", language: "Ruby" }, 4 | %{ name: "Larry", language: "Perl" } 5 | ] 6 | 7 | languages_with_an_r = fn (:get, collection, next_fn) -> 8 | for row <- collection do 9 | if String.contains?(row.language, "r") do 10 | next_fn.(row) 11 | end 12 | end 13 | end 14 | 15 | IO.inspect get_in(authors, [languages_with_an_r, :name]) 16 | #=> [ "José", nil, "Larry" ] 17 | -------------------------------------------------------------------------------- /maps/keywords.exs: -------------------------------------------------------------------------------- 1 | defmodule Canvas do 2 | 3 | @defaults [ fg: "black", bg: "white", font: "Merriweather" ] 4 | 5 | def draw_text(text, options \\ []) do 6 | options = Keyword.merge(@defaults, options) 7 | IO.puts "Drawing text #{inspect(text)}" 8 | IO.puts "Foreground: #{options[:fg]}" 9 | IO.puts "Background: #{Keyword.get(options, :bg)}" 10 | IO.puts "Font: #{Keyword.get(options, :font)}" 11 | IO.puts "Pattern: #{Keyword.get(options, :pattern, "solid")}" 12 | IO.puts "Style: #{inspect Keyword.get_values(options, :style)}" 13 | end 14 | 15 | end 16 | 17 | Canvas.draw_text("hello", fg: "red", style: "italic", style: "bold") 18 | 19 | # => 20 | # Drawing text "hello" 21 | # Foreground: red 22 | # Background: white 23 | # Font: Merriweather 24 | # Pattern: solid 25 | # Style: ["italic", "bold"] 26 | -------------------------------------------------------------------------------- /maps/nested.exs: -------------------------------------------------------------------------------- 1 | defmodule Customer do 2 | defstruct name: "", company: "" 3 | end 4 | 5 | defmodule BugReport do 6 | defstruct owner: %Customer{}, details: "", severity: 1 7 | end 8 | -------------------------------------------------------------------------------- /maps/query.exs: -------------------------------------------------------------------------------- 1 | people = [ 2 | %{ name: "Grumpy", height: 1.24 }, 3 | %{ name: "Dave", height: 1.88 }, 4 | %{ name: "Dopey", height: 1.32 }, 5 | %{ name: "Shaquille", height: 2.16 }, 6 | %{ name: "Sneezy", height: 1.28 } 7 | ] 8 | 9 | IO.inspect(for person = %{ height: height } <- people, height > 1.5, do: person) 10 | -------------------------------------------------------------------------------- /mm/attributes.exs: -------------------------------------------------------------------------------- 1 | defmodule Example do 2 | @author "Dave Thomas" 3 | def get_author do 4 | @author 5 | end 6 | end 7 | IO.puts "Example was written by #{Example.get_author}" 8 | -------------------------------------------------------------------------------- /mm/attributes1.exs: -------------------------------------------------------------------------------- 1 | defmodule Example do 2 | @attr "one" 3 | def first, do: @attr 4 | @attr "two" 5 | def second, do: @attr 6 | end 7 | IO.puts "#{Example.second} #{Example.first}" # => two one 8 | -------------------------------------------------------------------------------- /mm/default_params.exs: -------------------------------------------------------------------------------- 1 | defmodule Example do 2 | def func(p1, p2 \\ 2, p3 \\ 3, p4) do 3 | IO.inspect [p1, p2, p3, p4] 4 | end 5 | end 6 | 7 | Example.func("a", "b") # => ["a",2,3,"b"] 8 | Example.func("a", "b", "c") # => ["a","b",3,"c"] 9 | Example.func("a", "b", "c", "d") # => ["a","b","c","d"] 10 | -------------------------------------------------------------------------------- /mm/default_params1.exs: -------------------------------------------------------------------------------- 1 | defmodule DefaultParams1 do 2 | def func(p1, p2 \\ 123) do 3 | IO.inspect [p1, p2] 4 | end 5 | 6 | def func(p1, 99) do 7 | IO.puts "you said 99" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /mm/default_params2.exs: -------------------------------------------------------------------------------- 1 | defmodule Params do 2 | 3 | def func(p1, p2 \\ 123) 4 | 5 | def func(p1, p2) when is_list(p1) do 6 | "You said #{p2} with a list" 7 | end 8 | 9 | def func(p1, p2) do 10 | "You passed in #{p1} and #{p2}" 11 | end 12 | 13 | end 14 | 15 | IO.puts Params.func(99) # You passed in 99 and 123 16 | IO.puts Params.func(99, "cat") # You passed in 99 and cat 17 | IO.puts Params.func([99]) # You said 123 with a list 18 | IO.puts Params.func([99], "dog") # You said dog with a list 19 | -------------------------------------------------------------------------------- /mm/factorial1-bad.exs: -------------------------------------------------------------------------------- 1 | defmodule BadFactorial do 2 | def of(n), do: n * of(n-1) 3 | def of(0), do: 1 4 | end 5 | -------------------------------------------------------------------------------- /mm/factorial1.exs: -------------------------------------------------------------------------------- 1 | defmodule Factorial do 2 | def of(0), do: 1 3 | def of(n), do: n * of(n-1) 4 | end 5 | -------------------------------------------------------------------------------- /mm/factorial2.exs: -------------------------------------------------------------------------------- 1 | defmodule Factorial do 2 | def of(0), do: 1 3 | def of(n) when is_integer(n) and n > 0 do 4 | n * of(n-1) 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /mm/guard.exs: -------------------------------------------------------------------------------- 1 | defmodule Guard do 2 | def what_is(x) when is_number(x) do 3 | IO.puts "#{x} is a number" 4 | end 5 | def what_is(x) when is_list(x) do 6 | IO.puts "#{inspect(x)} is a list" 7 | end 8 | def what_is(x) when is_atom(x) do 9 | IO.puts "#{x} is an atom" 10 | end 11 | end 12 | 13 | Guard.what_is(99) # => 99 is a number 14 | Guard.what_is(:cat) # => cat is an atom 15 | Guard.what_is([1,2,3]) # => [1,2,3] is a list 16 | -------------------------------------------------------------------------------- /mm/import.exs: -------------------------------------------------------------------------------- 1 | defmodule Example do 2 | def func1 do 3 | List.flatten [1,[2,3],4] 4 | end 5 | def func2 do 6 | import List, only: [flatten: 1] 7 | flatten [5,[6,7],8] 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /mm/times.exs: -------------------------------------------------------------------------------- 1 | defmodule Times do 2 | def double(n) do 3 | n * 2 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /mm/times1.exs: -------------------------------------------------------------------------------- 1 | defmodule Times do 2 | def double(n), do: n * 2 3 | end 4 | -------------------------------------------------------------------------------- /nodes/ticker.ex: -------------------------------------------------------------------------------- 1 | defmodule Ticker do 2 | @interval 2000 # 2초 3 | @name :ticker 4 | 5 | def start do 6 | pid = spawn(__MODULE__, :generator , [[]]) 7 | :global.register_name(@name, pid) 8 | end 9 | 10 | def register(client_pid) do 11 | send :global.whereis_name(@name), { :register , client_pid } 12 | end 13 | 14 | def generator(clients) do 15 | receive do 16 | { :register , pid } -> 17 | IO.puts "registering #{ inspect pid }" 18 | generator([pid|clients]) 19 | after 20 | @interval -> 21 | IO.puts "tick" 22 | Enum.each clients, fn client -> 23 | send client, { :tick } 24 | end 25 | generator(clients) 26 | end 27 | end 28 | end 29 | 30 | defmodule Client do 31 | def start do 32 | pid = spawn(__MODULE__, :receiver , []) 33 | Ticker.register(pid) 34 | end 35 | 36 | def receiver do 37 | receive do 38 | { :tick } -> 39 | IO.puts "tock in client" 40 | receiver() 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /odds/color.exs: -------------------------------------------------------------------------------- 1 | defmodule ColorSigil do 2 | @color_map [ 3 | rgb: [ red: 0xff0000, green: 0x00ff00, blue: 0x0000ff, # ... 4 | ], 5 | hsb: [ red: {0,100,100}, green: {120,100,100}, blue: {240,100,100} 6 | ] 7 | ] 8 | 9 | def sigil_c(color_name, []), do: _c(color_name, :rgb) 10 | def sigil_c(color_name, 'r'), do: _c(color_name, :rgb) 11 | def sigil_c(color_name, 'h'), do: _c(color_name, :hsb) 12 | 13 | 14 | defp _c(color_name, color_space) do 15 | @color_map[color_space][String.to_atom(color_name)] 16 | end 17 | 18 | defmacro __using__(_opts) do 19 | quote do 20 | import Kernel, except: [sigil_c: 2] 21 | import unquote(__MODULE__), only: [sigil_c: 2] 22 | end 23 | end 24 | end 25 | 26 | defmodule Example do 27 | use ColorSigil 28 | 29 | def rgb, do: IO.inspect ~c{red} 30 | def hsb, do: IO.inspect ~c{red}h 31 | end 32 | 33 | 34 | Example.rgb #=> 16711680 (== 0xff0000) 35 | Example.hsb #=> {0,100,100} 36 | -------------------------------------------------------------------------------- /odds/eval/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["mix.exs", "config/*.exs"], 4 | subdirectories: ["apps/*"] 5 | ] 6 | -------------------------------------------------------------------------------- /odds/eval/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Temporary files, for example, from tests. 23 | /tmp/ 24 | -------------------------------------------------------------------------------- /odds/eval/README.md: -------------------------------------------------------------------------------- 1 | # Eval 2 | 3 | **TODO: Add description** 4 | 5 | -------------------------------------------------------------------------------- /odds/eval/apps/evaluator/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /odds/eval/apps/evaluator/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | evaluator-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /odds/eval/apps/evaluator/README.md: -------------------------------------------------------------------------------- 1 | # Evaluator 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `evaluator` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:evaluator, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/evaluator](https://hexdocs.pm/evaluator). 21 | 22 | -------------------------------------------------------------------------------- /odds/eval/apps/evaluator/lib/evaluator.ex: -------------------------------------------------------------------------------- 1 | defmodule Evaluator do 2 | def eval(list_of_expressions) do 3 | { result, _final_binding } = 4 | Enum.reduce(list_of_expressions, 5 | {_result = [], _binding = binding()}, 6 | &evaluate_with_binding/2) 7 | Enum.reverse result 8 | end 9 | 10 | defp evaluate_with_binding(expression, { result, binding }) do 11 | { next_result, new_binding } = Code.eval_string(expression, binding) 12 | { [ "value> #{next_result}", "code> #{expression}" | result ], new_binding } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /odds/eval/apps/evaluator/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Evaluator.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :evaluator, 7 | version: "0.1.0", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | lockfile: "../../mix.lock", 12 | elixir: "~> 1.13", 13 | start_permanent: Mix.env() == :prod, 14 | deps: deps() 15 | ] 16 | end 17 | 18 | # Run "mix help compile.app" to learn about applications. 19 | def application do 20 | [ 21 | extra_applications: [:logger] 22 | ] 23 | end 24 | 25 | # Run "mix help deps" to learn about dependencies. 26 | defp deps do 27 | [ 28 | # {:dep_from_hexpm, "~> 0.3.0"}, 29 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, 30 | # {:sibling_app_in_umbrella, in_umbrella: true} 31 | ] 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /odds/eval/apps/evaluator/test/evaluator_test.exs: -------------------------------------------------------------------------------- 1 | defmodule EvaluatorTest do 2 | use ExUnit.Case 3 | import LineSigil 4 | 5 | test "일반 표현식 계산" do 6 | input = ~l""" 7 | 1 + 2 8 | """ 9 | output = ~l""" 10 | code> 1 + 2 11 | value> 3 12 | """ 13 | 14 | run_test input, output 15 | end 16 | 17 | test "변수 바인딩이 유지된다" do 18 | input = ~l""" 19 | a = 123 20 | a + 1 21 | """ 22 | output = ~l""" 23 | code> a = 123 24 | value> 123 25 | code> a + 1 26 | value> 124 27 | """ 28 | run_test input, output 29 | end 30 | 31 | defp run_test(lines, output) do 32 | assert output == Evaluator.eval(lines) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /odds/eval/apps/evaluator/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /odds/eval/apps/line_sigil/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /odds/eval/apps/line_sigil/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | line_sigil-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /odds/eval/apps/line_sigil/README.md: -------------------------------------------------------------------------------- 1 | # LineSigil 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `line_sigil` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:line_sigil, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/line_sigil](https://hexdocs.pm/line_sigil). 21 | 22 | -------------------------------------------------------------------------------- /odds/eval/apps/line_sigil/lib/line_sigil.ex: -------------------------------------------------------------------------------- 1 | defmodule LineSigil do 2 | @doc """ 3 | 여러 줄의 문자열을 받아 각 줄에 있는 문자열을 리스트로 반환하는 4 | `~l` 시길을 구현한다. 5 | 6 | ## 사용법 예제 7 | iex> import LineSigil 8 | LineSigil 9 | iex> ~l\""" 10 | ...> one 11 | ...> two 12 | ...> three 13 | ...> \""" 14 | ["one","two","three"] 15 | """ 16 | 17 | def sigil_l(lines, _opts) do 18 | lines |> String.trim_trailing |> String.split("\n") 19 | end 20 | 21 | end -------------------------------------------------------------------------------- /odds/eval/apps/line_sigil/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule LineSigil.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :line_sigil, 7 | version: "0.1.0", 8 | build_path: "../../_build", 9 | config_path: "../../config/config.exs", 10 | deps_path: "../../deps", 11 | lockfile: "../../mix.lock", 12 | elixir: "~> 1.13", 13 | start_permanent: Mix.env() == :prod, 14 | deps: deps() 15 | ] 16 | end 17 | 18 | # Run "mix help compile.app" to learn about applications. 19 | def application do 20 | [ 21 | extra_applications: [:logger] 22 | ] 23 | end 24 | 25 | # Run "mix help deps" to learn about dependencies. 26 | defp deps do 27 | [ 28 | # {:dep_from_hexpm, "~> 0.3.0"}, 29 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, 30 | # {:sibling_app_in_umbrella, in_umbrella: true} 31 | ] 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /odds/eval/apps/line_sigil/test/line_sigil_test.exs: -------------------------------------------------------------------------------- 1 | defmodule LineSigilTest do 2 | use ExUnit.Case 3 | doctest LineSigil 4 | end 5 | -------------------------------------------------------------------------------- /odds/eval/apps/line_sigil/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /odds/eval/config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your umbrella 2 | # and **all applications** and their dependencies with the 3 | # help of the Config module. 4 | # 5 | # Note that all applications in your umbrella share the 6 | # same configuration and dependencies, which is why they 7 | # all use the same configuration file. If you want different 8 | # configurations or dependencies per app, it is best to 9 | # move said applications out of the umbrella. 10 | import Config 11 | 12 | # Sample configuration: 13 | # 14 | # config :logger, :console, 15 | # level: :info, 16 | # format: "$date $time [$level] $metadata$message\n", 17 | # metadata: [:user_id] 18 | # 19 | -------------------------------------------------------------------------------- /odds/eval/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Eval.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | apps_path: "apps", 7 | version: "0.1.0", 8 | start_permanent: Mix.env() == :prod, 9 | deps: deps() 10 | ] 11 | end 12 | 13 | # Dependencies listed here are available only for this 14 | # project and cannot be accessed from applications inside 15 | # the apps folder. 16 | # 17 | # Run "mix help deps" for examples and options. 18 | defp deps do 19 | [] 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /odds/line_sigil.exs: -------------------------------------------------------------------------------- 1 | defmodule LineSigil do 2 | @doc """ 3 | 여러 줄의 문자열을 받아 각 줄에 있는 문자열을 리스트로 반환하는 4 | `~l` 시길을 구현한다. 5 | 6 | ## 사용법 예제 7 | iex> import LineSigil 8 | LineSigil 9 | iex> ~l\""" 10 | ...> one 11 | ...> two 12 | ...> three 13 | ...> \""" 14 | ["one","two","three"] 15 | """ 16 | def sigil_l(lines, _opts) do 17 | lines |> String.trim_trailing |> String.split("\n") 18 | end 19 | end 20 | 21 | defmodule Example do 22 | import LineSigil 23 | 24 | def lines do 25 | ~l""" 26 | line 1 27 | line 2 28 | and another line in #{__MODULE__} 29 | """ 30 | end 31 | end 32 | 33 | IO.inspect Example.lines 34 | -------------------------------------------------------------------------------- /otp-app/sequence/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-app/sequence/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-app/sequence/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-app/sequence/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | @moduledoc """ 3 | Documentation for `Sequence`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Sequence.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /otp-app/sequence/lib/sequence/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | {Sequence.Stash, Application.get_env(:sequence, :initial_number)}, 12 | {Sequence.Server, nil} 13 | ] 14 | 15 | # See https://hexdocs.pm/elixir/Supervisor.html 16 | # for other strategies and supported options 17 | opts = [strategy: :rest_for_one, name: Sequence.Supervisor] 18 | Supervisor.start_link(children, opts) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /otp-app/sequence/lib/sequence/server.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Server do 2 | use GenServer 3 | 4 | ##### 5 | # 외부 API 6 | 7 | def start_link(_) do 8 | GenServer.start_link(__MODULE__, nil, name: __MODULE__) 9 | end 10 | 11 | def next_number do 12 | GenServer.call __MODULE__, :next_number 13 | end 14 | 15 | def increment_number(delta) do 16 | GenServer.cast __MODULE__, {:increment_number, delta} 17 | end 18 | 19 | ##### 20 | # 젠서버 구현 21 | 22 | def init(_) do 23 | { :ok, Sequence.Stash.get() } 24 | end 25 | 26 | def handle_call(:next_number, _from, current_number) do 27 | { :reply, current_number, current_number+1 } 28 | end 29 | 30 | def handle_cast({:increment_number, delta}, current_number) do 31 | { :noreply, current_number + delta} 32 | end 33 | 34 | def terminate(_reason, current_number) do 35 | Sequence.Stash.update(current_number) 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /otp-app/sequence/lib/sequence/stash.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Stash do 2 | use GenServer 3 | 4 | @me __MODULE__ 5 | 6 | def start_link(initial_number) do 7 | GenServer.start_link(__MODULE__, initial_number, name: @me) 8 | end 9 | 10 | def get() do 11 | GenServer.call(@me, { :get }) 12 | end 13 | 14 | def update(new_number) do 15 | GenServer.cast(@me, { :update, new_number }) 16 | end 17 | 18 | # 서버 구현 19 | 20 | def init(initial_number) do 21 | { :ok, initial_number } 22 | end 23 | 24 | def handle_call({ :get }, _from, current_number ) do 25 | { :reply, current_number, current_number } 26 | end 27 | 28 | def handle_cast({ :update, new_number }, _current_number) do 29 | { :noreply, new_number } 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /otp-app/sequence/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | mod: { 18 | Sequence.Application, 456 19 | }, 20 | registered: [ 21 | Sequence.Server 22 | ], 23 | extra_applications: [:logger], 24 | env: [initial_number: 456] 25 | ] 26 | end 27 | 28 | # Run "mix help deps" to learn about dependencies. 29 | defp deps do 30 | [ 31 | # {:dep_from_hexpm, "~> 0.3.0"}, 32 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 33 | ] 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /otp-app/sequence/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-app/sequence/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/config/config.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | @moduledoc """ 3 | Documentation for `Sequence`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Sequence.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/lib/sequence/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | {Sequence.Stash, Application.get_env(:sequence, :initial_number)}, 12 | {Sequence.Server, nil} 13 | ] 14 | 15 | # See https://hexdocs.pm/elixir/Supervisor.html 16 | # for other strategies and supported options 17 | opts = [strategy: :rest_for_one, name: Sequence.Supervisor] 18 | Supervisor.start_link(children, opts) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/lib/sequence/server.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Server do 2 | use GenServer 3 | 4 | @vsn "0" 5 | 6 | ##### 7 | # 외부 API 8 | 9 | def start_link(_) do 10 | GenServer.start_link(__MODULE__, nil, name: __MODULE__) 11 | end 12 | 13 | def next_number do 14 | GenServer.call __MODULE__, :next_number 15 | end 16 | 17 | def increment_number(delta) do 18 | GenServer.cast __MODULE__, {:increment_number, delta} 19 | end 20 | 21 | ##### 22 | # 젠서버 구현 23 | 24 | def init(_) do 25 | { :ok, Sequence.Stash.get() } 26 | end 27 | 28 | def handle_call(:next_number, _from, current_number) do 29 | { :reply, current_number, current_number+1 } 30 | end 31 | 32 | def handle_cast({:increment_number, delta}, current_number) do 33 | { :noreply, current_number + delta} 34 | end 35 | 36 | def terminate(_reason, current_number) do 37 | Sequence.Stash.update(current_number) 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/lib/sequence/stash.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Stash do 2 | use GenServer 3 | 4 | @me __MODULE__ 5 | 6 | def start_link(initial_number) do 7 | GenServer.start_link(__MODULE__, initial_number, name: @me) 8 | end 9 | 10 | def get() do 11 | GenServer.call(@me, { :get }) 12 | end 13 | 14 | def update(new_number) do 15 | GenServer.cast(@me, { :update, new_number }) 16 | end 17 | 18 | # 서버 구현 19 | 20 | def init(initial_number) do 21 | { :ok, initial_number } 22 | end 23 | 24 | def handle_call({ :get }, _from, current_number ) do 25 | { :reply, current_number, current_number } 26 | end 27 | 28 | def handle_cast({ :update, new_number }, _current_number) do 29 | { :noreply, new_number } 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | mod: { 18 | Sequence.Application, 456 19 | }, 20 | registered: [ 21 | Sequence.Server 22 | ], 23 | extra_applications: [:logger], 24 | env: [initial_number: 456] 25 | ] 26 | end 27 | 28 | # Run "mix help deps" to learn about dependencies. 29 | defp deps do 30 | [ 31 | {:distillery, "~> 2.1", runtime: false} 32 | ] 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "artificery": {:hex, :artificery, "0.4.3", "0bc4260f988dcb9dda4b23f9fc3c6c8b99a6220a331534fdf5bf2fd0d4333b02", [:mix], [], "hexpm", "12e95333a30e20884e937abdbefa3e7f5e05609c2ba8cf37b33f000b9ffc0504"}, 3 | "distillery": {:hex, :distillery, "2.1.1", "f9332afc2eec8a1a2b86f22429e068ef35f84a93ea1718265e740d90dd367814", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm", "bbc7008b0161a6f130d8d903b5b3232351fccc9c31a991f8fcbf2a12ace22995"}, 4 | } 5 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/rel/plugins/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | !*.exs 3 | !.gitignore -------------------------------------------------------------------------------- /otp-app/sequence_v0/rel/vm.args: -------------------------------------------------------------------------------- 1 | ## This file provide the arguments provided to the VM at startup 2 | ## You can find a full list of flags and their behaviours at 3 | ## http://erlang.org/doc/man/erl.html 4 | 5 | ## Name of the node 6 | -name <%= release_name %>@127.0.0.1 7 | 8 | ## Cookie for distributed erlang 9 | -setcookie <%= release.profile.cookie %> 10 | 11 | ## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive 12 | ## (Disabled by default..use with caution!) 13 | ##-heart 14 | 15 | ## Enable kernel poll and a few async threads 16 | ##+K true 17 | ##+A 5 18 | ## For OTP21+, the +A flag is not used anymore, 19 | ## +SDio replace it to use dirty schedulers 20 | ##+SDio 5 21 | 22 | ## Increase number of concurrent ports/sockets 23 | ##-env ERL_MAX_PORTS 4096 24 | 25 | ## Tweak GC to run more often 26 | ##-env ERL_FULLSWEEP_AFTER 10 27 | 28 | # Enable SMP automatically based on availability 29 | # On OTP21+, this is not needed anymore. 30 | -smp auto 31 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-app/sequence_v0/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/config/config.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | @moduledoc """ 3 | Documentation for `Sequence`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Sequence.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/lib/sequence/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | {Sequence.Stash, Application.get_env(:sequence, :initial_number)}, 12 | {Sequence.Server, nil} 13 | ] 14 | 15 | # See https://hexdocs.pm/elixir/Supervisor.html 16 | # for other strategies and supported options 17 | opts = [strategy: :rest_for_one, name: Sequence.Supervisor] 18 | Supervisor.start_link(children, opts) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/lib/sequence/server.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Server do 2 | use GenServer 3 | 4 | @vsn "0" 5 | 6 | ##### 7 | # 외부 API 8 | 9 | def start_link(_) do 10 | GenServer.start_link(__MODULE__, nil, name: __MODULE__) 11 | end 12 | 13 | def next_number do 14 | with number = GenServer.call __MODULE__, :next_number do 15 | "다음 번호는 #{number}번입니다." 16 | end 17 | end 18 | 19 | def increment_number(delta) do 20 | GenServer.cast __MODULE__, {:increment_number, delta} 21 | end 22 | 23 | ##### 24 | # 젠서버 구현 25 | 26 | def init(_) do 27 | { :ok, Sequence.Stash.get() } 28 | end 29 | 30 | def handle_call(:next_number, _from, current_number) do 31 | { :reply, current_number, current_number+1 } 32 | end 33 | 34 | def handle_cast({:increment_number, delta}, current_number) do 35 | { :noreply, current_number + delta} 36 | end 37 | 38 | def terminate(_reason, current_number) do 39 | Sequence.Stash.update(current_number) 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/lib/sequence/stash.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Stash do 2 | use GenServer 3 | 4 | @me __MODULE__ 5 | 6 | def start_link(initial_number) do 7 | GenServer.start_link(__MODULE__, initial_number, name: @me) 8 | end 9 | 10 | def get() do 11 | GenServer.call(@me, { :get }) 12 | end 13 | 14 | def update(new_number) do 15 | GenServer.cast(@me, { :update, new_number }) 16 | end 17 | 18 | # 서버 구현 19 | 20 | def init(initial_number) do 21 | { :ok, initial_number } 22 | end 23 | 24 | def handle_call({ :get }, _from, current_number ) do 25 | { :reply, current_number, current_number } 26 | end 27 | 28 | def handle_cast({ :update, new_number }, _current_number) do 29 | { :noreply, new_number } 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.2.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | mod: { 18 | Sequence.Application, 456 19 | }, 20 | registered: [ 21 | Sequence.Server 22 | ], 23 | extra_applications: [:logger], 24 | env: [initial_number: 456] 25 | ] 26 | end 27 | 28 | # Run "mix help deps" to learn about dependencies. 29 | defp deps do 30 | [ 31 | {:distillery, "~> 2.1", runtime: false} 32 | ] 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "artificery": {:hex, :artificery, "0.4.3", "0bc4260f988dcb9dda4b23f9fc3c6c8b99a6220a331534fdf5bf2fd0d4333b02", [:mix], [], "hexpm", "12e95333a30e20884e937abdbefa3e7f5e05609c2ba8cf37b33f000b9ffc0504"}, 3 | "distillery": {:hex, :distillery, "2.1.1", "f9332afc2eec8a1a2b86f22429e068ef35f84a93ea1718265e740d90dd367814", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm", "bbc7008b0161a6f130d8d903b5b3232351fccc9c31a991f8fcbf2a12ace22995"}, 4 | } 5 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/rel/plugins/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | !*.exs 3 | !.gitignore -------------------------------------------------------------------------------- /otp-app/sequence_v1/rel/vm.args: -------------------------------------------------------------------------------- 1 | ## This file provide the arguments provided to the VM at startup 2 | ## You can find a full list of flags and their behaviours at 3 | ## http://erlang.org/doc/man/erl.html 4 | 5 | ## Name of the node 6 | -name <%= release_name %>@127.0.0.1 7 | 8 | ## Cookie for distributed erlang 9 | -setcookie <%= release.profile.cookie %> 10 | 11 | ## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive 12 | ## (Disabled by default..use with caution!) 13 | ##-heart 14 | 15 | ## Enable kernel poll and a few async threads 16 | ##+K true 17 | ##+A 5 18 | ## For OTP21+, the +A flag is not used anymore, 19 | ## +SDio replace it to use dirty schedulers 20 | ##+SDio 5 21 | 22 | ## Increase number of concurrent ports/sockets 23 | ##-env ERL_MAX_PORTS 4096 24 | 25 | ## Tweak GC to run more often 26 | ##-env ERL_FULLSWEEP_AFTER 10 27 | 28 | # Enable SMP automatically based on availability 29 | # On OTP21+, this is not needed anymore. 30 | -smp auto 31 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-app/sequence_v1/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/config/config.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | @moduledoc """ 3 | Documentation for `Sequence`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Sequence.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/lib/sequence/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | {Sequence.Stash, Application.get_env(:sequence, :initial_number)}, 12 | {Sequence.Server, nil} 13 | ] 14 | 15 | # See https://hexdocs.pm/elixir/Supervisor.html 16 | # for other strategies and supported options 17 | opts = [strategy: :rest_for_one, name: Sequence.Supervisor] 18 | Supervisor.start_link(children, opts) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/lib/sequence/stash.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Stash do 2 | use GenServer 3 | 4 | @me __MODULE__ 5 | 6 | def start_link(initial_number) do 7 | GenServer.start_link(__MODULE__, initial_number, name: @me) 8 | end 9 | 10 | def get() do 11 | GenServer.call(@me, { :get }) 12 | end 13 | 14 | def update(new_number) do 15 | GenServer.cast(@me, { :update, new_number }) 16 | end 17 | 18 | # 서버 구현 19 | 20 | def init(initial_number) do 21 | { :ok, initial_number } 22 | end 23 | 24 | def handle_call({ :get }, _from, current_number ) do 25 | { :reply, current_number, current_number } 26 | end 27 | 28 | def handle_cast({ :update, new_number }, _current_number) do 29 | { :noreply, new_number } 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.3.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | mod: { 18 | Sequence.Application, 456 19 | }, 20 | registered: [ 21 | Sequence.Server 22 | ], 23 | extra_applications: [:logger], 24 | env: [initial_number: 456] 25 | ] 26 | end 27 | 28 | # Run "mix help deps" to learn about dependencies. 29 | defp deps do 30 | [ 31 | {:distillery, "~> 2.1", runtime: false} 32 | ] 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "artificery": {:hex, :artificery, "0.4.3", "0bc4260f988dcb9dda4b23f9fc3c6c8b99a6220a331534fdf5bf2fd0d4333b02", [:mix], [], "hexpm", "12e95333a30e20884e937abdbefa3e7f5e05609c2ba8cf37b33f000b9ffc0504"}, 3 | "distillery": {:hex, :distillery, "2.1.1", "f9332afc2eec8a1a2b86f22429e068ef35f84a93ea1718265e740d90dd367814", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm", "bbc7008b0161a6f130d8d903b5b3232351fccc9c31a991f8fcbf2a12ace22995"}, 4 | } 5 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/rel/plugins/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | !*.exs 3 | !.gitignore -------------------------------------------------------------------------------- /otp-app/sequence_v2/rel/vm.args: -------------------------------------------------------------------------------- 1 | ## This file provide the arguments provided to the VM at startup 2 | ## You can find a full list of flags and their behaviours at 3 | ## http://erlang.org/doc/man/erl.html 4 | 5 | ## Name of the node 6 | -name <%= release_name %>@127.0.0.1 7 | 8 | ## Cookie for distributed erlang 9 | -setcookie <%= release.profile.cookie %> 10 | 11 | ## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive 12 | ## (Disabled by default..use with caution!) 13 | ##-heart 14 | 15 | ## Enable kernel poll and a few async threads 16 | ##+K true 17 | ##+A 5 18 | ## For OTP21+, the +A flag is not used anymore, 19 | ## +SDio replace it to use dirty schedulers 20 | ##+SDio 5 21 | 22 | ## Increase number of concurrent ports/sockets 23 | ##-env ERL_MAX_PORTS 4096 24 | 25 | ## Tweak GC to run more often 26 | ##-env ERL_FULLSWEEP_AFTER 10 27 | 28 | # Enable SMP automatically based on availability 29 | # On OTP21+, this is not needed anymore. 30 | -smp auto 31 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-app/sequence_v2/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /otp-server/1/sequence/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-server/1/sequence/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-server/1/sequence/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-server/1/sequence/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | @moduledoc """ 3 | Documentation for `Sequence`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Sequence.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /otp-server/1/sequence/lib/sequence/server.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Server do 2 | use GenServer 3 | 4 | def init(initial_number) do 5 | { :ok, initial_number } 6 | end 7 | 8 | def handle_call(:next_number, _from, current_number) do 9 | {:reply, current_number, current_number + 1} 10 | end 11 | 12 | def handle_cast({:increment_number, delta}, current_number) do 13 | { :noreply, current_number + delta } 14 | end 15 | 16 | def format_status(_reason, [ _pdict, state ]) do 17 | [data: [{'State', "My current state is '#{inspect state}', and I'm happy"}]] 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /otp-server/1/sequence/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | # {:dep_from_hexpm, "~> 0.3.0"}, 25 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /otp-server/1/sequence/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-server/1/sequence/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /otp-server/2/sequence/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-server/2/sequence/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-server/2/sequence/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-server/2/sequence/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | @moduledoc """ 3 | Documentation for `Sequence`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Sequence.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /otp-server/2/sequence/lib/sequence/server.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Server do 2 | use GenServer 3 | 4 | ##### 5 | # 외부 API 6 | def start_link(current_number) do 7 | GenServer.start_link(__MODULE__, current_number, name: __MODULE__) 8 | end 9 | 10 | def next_number do 11 | GenServer.call __MODULE__, :next_number 12 | end 13 | 14 | def increment_number(delta) do 15 | GenServer.cast __MODULE__, {:increment_number, delta} 16 | end 17 | 18 | ##### 19 | # 젠서버 구현 20 | def init(initial_number) do 21 | { :ok, initial_number } 22 | end 23 | 24 | def handle_call(:next_number, _from, current_number) do 25 | { :reply, current_number, current_number + 1} 26 | end 27 | 28 | def handle_cast({:increment_number, delta}, current_number) do 29 | { :noreply, current_number + delta} 30 | end 31 | 32 | def format_status(_reason, [ _pdict, state ]) do 33 | [data: [{'State', "My current state is '#{inspect state}', and I'm happy"}]] 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /otp-server/2/sequence/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | # {:dep_from_hexpm, "~> 0.3.0"}, 25 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /otp-server/2/sequence/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-server/2/sequence/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /otp-server/3/sequence/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-server/3/sequence/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-server/3/sequence/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-server/3/sequence/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | 3 | @server Sequence.Server 4 | 5 | def start_link(current_number) do 6 | GenServer.start_link(@server, current_number, name: @server) 7 | end 8 | 9 | def next_number do 10 | GenServer.call(@server, :next_number) 11 | end 12 | 13 | def increment_number(delta) do 14 | GenServer.cast(@server, {:increment_number, delta}) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /otp-server/3/sequence/lib/sequence/impl.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Impl do 2 | def next(number), do: number + 1 3 | def increment(number, delta), do: number + delta 4 | end 5 | -------------------------------------------------------------------------------- /otp-server/3/sequence/lib/sequence/server.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Server do 2 | use GenServer 3 | alias Sequence.Impl 4 | 5 | def init(initial_number) do 6 | { :ok, initial_number } 7 | end 8 | 9 | def handle_call(:next_number, _from, current_number) do 10 | { :reply, current_number, Impl.next(current_number) } 11 | end 12 | 13 | def handle_cast({:increment_number, delta}, current_number) do 14 | { :noreply, Impl.increment(current_number, delta) } 15 | end 16 | 17 | def format_status(_reason, [ _pdict, state ]) do 18 | [data: [{'State', "My current state is '#{inspect state}', and I'm happy"}]] 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /otp-server/3/sequence/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | # {:dep_from_hexpm, "~> 0.3.0"}, 25 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /otp-server/3/sequence/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-server/3/sequence/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | @moduledoc """ 3 | Documentation for `Sequence`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Sequence.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/lib/sequence/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | {Sequence.Server, 123} 12 | ] 13 | 14 | # See https://hexdocs.pm/elixir/Supervisor.html 15 | # for other strategies and supported options 16 | opts = [strategy: :one_for_one, name: Sequence.Supervisor] 17 | Supervisor.start_link(children, opts) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/lib/sequence/server.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Server do 2 | use GenServer 3 | 4 | ##### 5 | # 외부 API 6 | def start_link(current_number) do 7 | GenServer.start_link(__MODULE__, current_number, name: __MODULE__) 8 | end 9 | 10 | def next_number do 11 | GenServer.call __MODULE__, :next_number 12 | end 13 | 14 | def increment_number(delta) do 15 | GenServer.cast __MODULE__, {:increment_number, delta} 16 | end 17 | 18 | ##### 19 | # 젠서버 구현 20 | def init(initial_number) do 21 | { :ok, initial_number } 22 | end 23 | 24 | def handle_call(:next_number, _from, current_number) do 25 | { :reply, current_number, current_number + 1} 26 | end 27 | 28 | def handle_cast({:increment_number, delta}, current_number) do 29 | { :noreply, current_number + delta} 30 | end 31 | 32 | def format_status(_reason, [ _pdict, state ]) do 33 | [data: [{'State', "My current state is '#{inspect state}', and I'm happy"}]] 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger], 18 | mod: {Sequence.Application, []} 19 | ] 20 | end 21 | 22 | # Run "mix help deps" to learn about dependencies. 23 | defp deps do 24 | [ 25 | # {:dep_from_hexpm, "~> 0.3.0"}, 26 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 27 | ] 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-supervisor/1/sequence/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | sequence-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/README.md: -------------------------------------------------------------------------------- 1 | # Sequence 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `sequence` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:sequence, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/sequence](https://hexdocs.pm/sequence). 21 | 22 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/lib/sequence.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence do 2 | @moduledoc """ 3 | Documentation for `Sequence`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Sequence.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/lib/sequence/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | {Sequence.Stash, 123}, 12 | {Sequence.Server, nil} 13 | ] 14 | 15 | # See https://hexdocs.pm/elixir/Supervisor.html 16 | # for other strategies and supported options 17 | opts = [strategy: :rest_for_one, name: Sequence.Supervisor] 18 | Supervisor.start_link(children, opts) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/lib/sequence/server.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Server do 2 | use GenServer 3 | 4 | ##### 5 | # 외부 API 6 | 7 | def start_link(_) do 8 | GenServer.start_link(__MODULE__, nil, name: __MODULE__) 9 | end 10 | 11 | def next_number do 12 | GenServer.call __MODULE__, :next_number 13 | end 14 | 15 | def increment_number(delta) do 16 | GenServer.cast __MODULE__, {:increment_number, delta} 17 | end 18 | 19 | ##### 20 | # 젠서버 구현 21 | 22 | def init(_) do 23 | { :ok, Sequence.Stash.get() } 24 | end 25 | 26 | def handle_call(:next_number, _from, current_number) do 27 | { :reply, current_number, current_number+1 } 28 | end 29 | 30 | def handle_cast({:increment_number, delta}, current_number) do 31 | { :noreply, current_number + delta} 32 | end 33 | 34 | def terminate(_reason, current_number) do 35 | Sequence.Stash.update(current_number) 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/lib/sequence/stash.ex: -------------------------------------------------------------------------------- 1 | defmodule Sequence.Stash do 2 | use GenServer 3 | 4 | @me __MODULE__ 5 | 6 | def start_link(initial_number) do 7 | GenServer.start_link(__MODULE__, initial_number, name: @me) 8 | end 9 | 10 | def get() do 11 | GenServer.call(@me, { :get }) 12 | end 13 | 14 | def update(new_number) do 15 | GenServer.cast(@me, { :update, new_number }) 16 | end 17 | 18 | # 서버 구현 19 | 20 | def init(initial_number) do 21 | { :ok, initial_number } 22 | end 23 | 24 | def handle_call({ :get }, _from, current_number ) do 25 | { :reply, current_number, current_number } 26 | end 27 | 28 | def handle_cast({ :update, new_number }, _current_number) do 29 | { :noreply, new_number } 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Sequence.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :sequence, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger], 18 | mod: {Sequence.Application, []} 19 | ] 20 | end 21 | 22 | # Run "mix help deps" to learn about dependencies. 23 | defp deps do 24 | [ 25 | # {:dep_from_hexpm, "~> 0.3.0"}, 26 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 27 | ] 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/test/sequence_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SequenceTest do 2 | use ExUnit.Case 3 | doctest Sequence 4 | 5 | test "greets the world" do 6 | assert Sequence.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /otp-supervisor/2/sequence/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/0/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/0/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | issues-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /project/0/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/0/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/0/issues/lib/issues/cli.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.CLI do 2 | @default_count 4 3 | @moduledoc """ 4 | 커맨드 라인 파싱을 수행한 뒤, 각종 함수를 호출해 5 | 깃허브 프로젝트의 최근 _n_개 이슈를 표 형식으로 만들어 출력한다. 6 | """ 7 | def run(argv) do 8 | parse_args(argv) 9 | end 10 | 11 | @doc """ 12 | `argv`는 -h 또는 --help (이 경우 :help를 반환)이거나, 13 | 깃허브 사용자 이름, 프로젝트 이름, (선택적으로) 가져올 이슈 개수여야 한다. 14 | 15 | `{사용자명, 프로젝트명, 이슈 개수}` 또는 :help를 반환한다. 16 | """ 17 | def parse_args(argv) do 18 | parse = OptionParser.parse(argv, switches: [ help: :boolean], aliases: [ h: :help ]) 19 | case parse do 20 | { [ help: true ], _, _ } 21 | -> :help 22 | { _, [ user, project, count ], _ } 23 | -> { user, project, count } 24 | { _, [ user, project ], _ } 25 | -> { user, project, @default_count } 26 | _ -> :help 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /project/0/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | # {:dep_from_hexpm, "~> 0.3.0"}, 25 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /project/0/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/0/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/1/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/1/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | issues-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /project/1/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/1/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/1/issues/lib/issues/cli.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.CLI do 2 | @default_count 4 3 | @moduledoc """ 4 | 커맨드 라인 파싱을 수행한 뒤, 각종 함수를 호출해 5 | 깃허브 프로젝트의 최근 _n_개 이슈를 표 형식으로 만들어 출력한다. 6 | """ 7 | def run(argv) do 8 | parse_args(argv) 9 | end 10 | 11 | @doc """ 12 | `argv`는 -h 또는 --help (이 경우 :help를 반환)이거나, 13 | 깃허브 사용자 이름, 프로젝트 이름, (선택적으로) 가져올 이슈 개수여야 한다. 14 | 15 | `{사용자명, 프로젝트명, 이슈 개수}` 또는 :help를 반환한다. 16 | """ 17 | def parse_args(argv) do 18 | parse = OptionParser.parse(argv, switches: [ help: :boolean], 19 | aliases: [ h: :help ]) 20 | case parse do 21 | { [ help: true ], _, _ } -> :help 22 | { _, [ user, project, count ], _ } -> { user, project, String.to_integer(count) } 23 | { _, [ user, project ], _ } -> { user, project, @default_count } 24 | _ -> :help 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /project/1/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | # {:dep_from_hexpm, "~> 0.3.0"}, 25 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /project/1/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /project/1/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/1/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/1a/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/1a/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | issues-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /project/1a/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/1a/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/1a/issues/lib/issues/cli.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.CLI do 2 | @default_count 4 3 | @moduledoc """ 4 | 커맨드 라인 파싱을 수행한 뒤, 각종 함수를 호출해 5 | 깃허브 프로젝트의 최근 _n_개 이슈를 표 형식으로 만들어 출력한다. 6 | """ 7 | def run(argv) do 8 | argv 9 | |> parse_args 10 | |> process 11 | end 12 | 13 | @doc """ 14 | `argv`는 -h 또는 --help (이 경우 :help를 반환)이거나, 15 | 깃허브 사용자 이름, 프로젝트 이름, (선택적으로) 가져올 이슈 개수여야 한다. 16 | 17 | `{사용자명, 프로젝트명, 이슈 개수}` 또는 :help를 반환한다. 18 | """ 19 | def parse_args(argv) do 20 | OptionParser.parse(argv, switches: [ help: :boolean], 21 | aliases: [ h: :help ]) 22 | |> elem(1) 23 | |> args_to_internal_representation() 24 | end 25 | 26 | 27 | def args_to_internal_representation([user, project, count]) do 28 | { user, project, String.to_integer(count) } 29 | end 30 | 31 | def args_to_internal_representation([user, project]) do 32 | { user, project, @default_count } 33 | end 34 | 35 | def args_to_internal_representation(_) do # 잘못된 인자 또는 --help 36 | :help 37 | end 38 | 39 | def process(:help) do 40 | IO.puts """ 41 | usage: issues [ count | #{@default_count} ] 42 | """ 43 | System.halt(0) 44 | end 45 | 46 | def process({user, project, _count}) do 47 | Issues.GithubIssues.fetch(user, project) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /project/1a/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GithubIssues do 2 | @user_agent [ {"User-agent", "Elixir dave@pragprog.com"} ] 3 | def fetch(user, project) do 4 | issues_url(user, project) 5 | |> HTTPoison.get(@user_agent) 6 | |> handle_response 7 | end 8 | 9 | def issues_url(user, project) do 10 | "https://api.github.com/repos/#{user}/#{project}/issues" 11 | end 12 | def handle_response({ :ok, %{status_code: 200, body: body}}) do 13 | { :ok, body } 14 | end 15 | 16 | def handle_response({ _, %{status_code: _, body: body}}) do 17 | { :error, body } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /project/1a/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | { :httpoison, "~> 1.0" } 25 | ] 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /project/1a/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /project/1a/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/1a/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/2/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/2/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | issues-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /project/2/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/2/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/2/issues/lib/issues/cli.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.CLI do 2 | @default_count 4 3 | @moduledoc """ 4 | 커맨드 라인 파싱을 수행한 뒤, 각종 함수를 호출해 5 | 깃허브 프로젝트의 최근 _n_개 이슈를 표 형식으로 만들어 출력한다. 6 | """ 7 | def run(argv) do 8 | argv 9 | |> parse_args 10 | |> process 11 | end 12 | 13 | @doc """ 14 | `argv`는 -h 또는 --help (이 경우 :help를 반환)이거나, 15 | 깃허브 사용자 이름, 프로젝트 이름, (선택적으로) 가져올 이슈 개수여야 한다. 16 | 17 | `{사용자명, 프로젝트명, 이슈 개수}` 또는 :help를 반환한다. 18 | """ 19 | def parse_args(argv) do 20 | OptionParser.parse(argv, switches: [ help: :boolean], 21 | aliases: [ h: :help ]) 22 | |> elem(1) 23 | |> args_to_internal_representation() 24 | end 25 | 26 | 27 | def args_to_internal_representation([user, project, count]) do 28 | { user, project, String.to_integer(count) } 29 | end 30 | 31 | def args_to_internal_representation([user, project]) do 32 | { user, project, @default_count } 33 | end 34 | 35 | def args_to_internal_representation(_) do # 잘못된 인자 또는 --help 36 | :help 37 | end 38 | 39 | def process(:help) do 40 | IO.puts """ 41 | usage: issues [ count | #{@default_count} ] 42 | """ 43 | System.halt(0) 44 | end 45 | 46 | def process({user, project, _count}) do 47 | Issues.GithubIssues.fetch(user, project) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /project/2/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GithubIssues do 2 | @user_agent [ {"User-agent", "Elixir dave@pragprog.com"} ] 3 | def fetch(user, project) do 4 | issues_url(user, project) 5 | |> HTTPoison.get(@user_agent) 6 | |> handle_response 7 | end 8 | 9 | def issues_url(user, project) do 10 | "https://api.github.com/repos/#{user}/#{project}/issues" 11 | end 12 | def handle_response({ :ok, %{status_code: 200, body: body}}) do 13 | { :ok, body } 14 | end 15 | 16 | def handle_response({ _, %{status_code: _, body: body}}) do 17 | { :error, body } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /project/2/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | { :httpoison, "~> 1.0" }, 25 | { :poison, "~> 5.0" } 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /project/2/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /project/2/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/2/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/3/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/3/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | issues-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /project/3/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/3/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/3/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GithubIssues do 2 | @user_agent [ {"User-agent", "Elixir dave@pragprog.com"} ] 3 | def fetch(user, project) do 4 | issues_url(user, project) 5 | |> HTTPoison.get(@user_agent) 6 | |> handle_response 7 | end 8 | 9 | def issues_url(user, project) do 10 | "https://api.github.com/repos/#{user}/#{project}/issues" 11 | end 12 | 13 | def handle_response({ _, %{status_code: status_code, body: body}}) do 14 | { 15 | status_code |> check_for_error(), 16 | body |> Poison.Parser.parse!(%{}) 17 | } 18 | end 19 | 20 | defp check_for_error(200), do: :ok 21 | defp check_for_error(_), do: :error 22 | end 23 | -------------------------------------------------------------------------------- /project/3/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | { :httpoison, "~> 1.0" }, 25 | { :poison, "~> 5.0" } 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /project/3/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /project/3/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/3/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/3a/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/3a/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | issues-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /project/3a/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/3a/issues/config/config.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | config :issues, github_url: "https://api.github.com" 3 | -------------------------------------------------------------------------------- /project/3a/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/3a/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GithubIssues do 2 | @user_agent [ {"User-agent", "Elixir dave@pragprog.com"} ] 3 | 4 | # 컴파일 타임에 값을 가져오기 위해 모듈 속성을 사용한다. 5 | @github_url Application.get_env(:issues, :github_url) 6 | 7 | def fetch(user, project) do 8 | issues_url(user, project) 9 | |> HTTPoison.get(@user_agent) 10 | |> handle_response 11 | end 12 | 13 | def issues_url(user, project) do 14 | "#{@github_url}/repos/#{user}/#{project}/issues" 15 | end 16 | 17 | def handle_response({ _, %{status_code: status_code, body: body}}) do 18 | { 19 | status_code |> check_for_error(), 20 | body |> Poison.Parser.parse!(%{}) 21 | } 22 | end 23 | 24 | defp check_for_error(200), do: :ok 25 | defp check_for_error(_), do: :error 26 | end 27 | -------------------------------------------------------------------------------- /project/3a/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | { :httpoison, "~> 1.0" }, 25 | { :poison, "~> 5.0" } 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /project/3a/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /project/3a/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/3a/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/3b/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/3b/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | issues-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /project/3b/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/3b/issues/config/config.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | config :issues, github_url: "https://api.github.com" 3 | -------------------------------------------------------------------------------- /project/3b/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/3b/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GithubIssues do 2 | @user_agent [ {"User-agent", "Elixir dave@pragprog.com"} ] 3 | 4 | # 컴파일 타임에 값을 가져오기 위해 모듈 속성을 사용한다. 5 | @github_url Application.get_env(:issues, :github_url) 6 | 7 | def fetch(user, project) do 8 | issues_url(user, project) 9 | |> HTTPoison.get(@user_agent) 10 | |> handle_response 11 | end 12 | 13 | def issues_url(user, project) do 14 | "#{@github_url}/repos/#{user}/#{project}/issues" 15 | end 16 | 17 | def handle_response({ _, %{status_code: status_code, body: body}}) do 18 | { 19 | status_code |> check_for_error(), 20 | body |> Poison.Parser.parse!(%{}) 21 | } 22 | end 23 | 24 | defp check_for_error(200), do: :ok 25 | defp check_for_error(_), do: :error 26 | end 27 | -------------------------------------------------------------------------------- /project/3b/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | { :httpoison, "~> 1.0" }, 25 | { :poison, "~> 5.0" } 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /project/3b/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1, sort_into_descending_order: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | 20 | test "내림차순 정렬이 잘 수행된다." do 21 | result = sort_into_descending_order(fake_created_at_list(["c", "a", "b"])) 22 | issues = for issue <- result, do: Map.get(issue, "created_at") 23 | assert issues == ~w{ c b a } 24 | end 25 | 26 | defp fake_created_at_list(values) do 27 | for value <- values, 28 | do: %{"created_at" => value, "other_data" => "xxx"} 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /project/3b/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/3b/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/4/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/4/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | issues-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /project/4/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/4/issues/config/config.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | config :issues, github_url: "https://api.github.com" 3 | -------------------------------------------------------------------------------- /project/4/issues/issues: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/project/4/issues/issues -------------------------------------------------------------------------------- /project/4/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/4/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GithubIssues do 2 | @user_agent [ {"User-agent", "Elixir dave@pragprog.com"} ] 3 | 4 | # 컴파일 타임에 값을 가져오기 위해 모듈 속성을 사용한다. 5 | @github_url Application.get_env(:issues, :github_url) 6 | 7 | def fetch(user, project) do 8 | issues_url(user, project) 9 | |> HTTPoison.get(@user_agent) 10 | |> handle_response 11 | end 12 | 13 | def issues_url(user, project) do 14 | "#{@github_url}/repos/#{user}/#{project}/issues" 15 | end 16 | 17 | def handle_response({ _, %{status_code: status_code, body: body}}) do 18 | { 19 | status_code |> check_for_error(), 20 | body |> Poison.Parser.parse!(%{}) 21 | } 22 | end 23 | 24 | defp check_for_error(200), do: :ok 25 | defp check_for_error(_), do: :error 26 | end 27 | -------------------------------------------------------------------------------- /project/4/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | escript: escript_config(), 8 | version: "0.1.0", 9 | elixir: "~> 1.13", 10 | start_permanent: Mix.env() == :prod, 11 | deps: deps() 12 | ] 13 | end 14 | 15 | # Run "mix help compile.app" to learn about applications. 16 | def application do 17 | [ 18 | extra_applications: [:logger] 19 | ] 20 | end 21 | 22 | # Run "mix help deps" to learn about dependencies. 23 | defp deps do 24 | [ 25 | { :httpoison, "~> 1.0" }, 26 | { :poison, "~> 5.0" } 27 | ] 28 | end 29 | 30 | defp escript_config do 31 | [ 32 | main_module: Issues.CLI 33 | ] 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /project/4/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1, sort_into_descending_order: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | 20 | test "내림차순 정렬이 잘 수행된다." do 21 | result = sort_into_descending_order(fake_created_at_list(["c", "a", "b"])) 22 | issues = for issue <- result, do: Map.get(issue, "created_at") 23 | assert issues == ~w{ c b a } 24 | end 25 | 26 | defp fake_created_at_list(values) do 27 | for value <- values, 28 | do: %{"created_at" => value, "other_data" => "xxx"} 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /project/4/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/4/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /project/5/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /project/5/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Ignore .fetch files in case you like to edit your project deps locally. 11 | /.fetch 12 | 13 | # If the VM crashes, it generates a dump, let's ignore it too. 14 | erl_crash.dump 15 | 16 | # Also ignore archive artifacts (built via "mix archive.build"). 17 | *.ez 18 | 19 | # Ignore package tarball (built via "mix hex.build"). 20 | issues-*.tar 21 | 22 | # Temporary files, for example, from tests. 23 | /tmp/ 24 | -------------------------------------------------------------------------------- /project/5/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /project/5/issues/config/config.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | config :issues, github_url: "https://api.github.com" 3 | config :logger, 4 | compile_time_purge_matching: [ 5 | [level_lower_than: :info] 6 | ] 7 | -------------------------------------------------------------------------------- /project/5/issues/doc/.build: -------------------------------------------------------------------------------- 1 | 404.html 2 | Issues.CLI.html 3 | Issues.GithubIssues.html 4 | Issues.TableFormatter.html 5 | Issues.html 6 | api-reference.html 7 | dist/app-f27ff079945e43879c46.js 8 | dist/elixir-a172fe91e725dcb259e2.css 9 | dist/html/fonts/icomoon.eot 10 | dist/html/fonts/icomoon.svg 11 | dist/html/fonts/icomoon.ttf 12 | dist/html/fonts/icomoon.woff 13 | dist/search_items-d6b809f7c6.js 14 | dist/sidebar_items-cda1b4999b.js 15 | index.html 16 | search.html 17 | -------------------------------------------------------------------------------- /project/5/issues/doc/Issues.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/project/5/issues/doc/Issues.epub -------------------------------------------------------------------------------- /project/5/issues/doc/dist/html/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/project/5/issues/doc/dist/html/fonts/icomoon.eot -------------------------------------------------------------------------------- /project/5/issues/doc/dist/html/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/project/5/issues/doc/dist/html/fonts/icomoon.ttf -------------------------------------------------------------------------------- /project/5/issues/doc/dist/html/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/project/5/issues/doc/dist/html/fonts/icomoon.woff -------------------------------------------------------------------------------- /project/5/issues/doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Issues v0.1.0 — Documentation 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /project/5/issues/issues: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/project/5/issues/issues -------------------------------------------------------------------------------- /project/5/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /project/5/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GithubIssues do 2 | require Logger 3 | 4 | @user_agent [ {"User-agent", "Elixir dave@pragprog.com"} ] 5 | 6 | # 컴파일 타임에 값을 가져오기 위해 모듈 속성을 사용한다. 7 | @github_url Application.get_env(:issues, :github_url) 8 | 9 | def fetch(user, project) do 10 | Logger.info("Fetching #{user}'s project #{project}") 11 | issues_url(user, project) 12 | |> HTTPoison.get(@user_agent) 13 | |> handle_response 14 | end 15 | 16 | def issues_url(user, project) do 17 | "#{@github_url}/repos/#{user}/#{project}/issues" 18 | end 19 | 20 | def handle_response({ _, %{status_code: status_code, body: body}}) do 21 | Logger.info("Got response: status code=#{status_code}") 22 | Logger.debug(fn -> inspect(body) end) 23 | { 24 | status_code |> check_for_error(), 25 | body |> Poison.Parser.parse!(%{}) 26 | } 27 | end 28 | 29 | defp check_for_error(200), do: :ok 30 | defp check_for_error(_), do: :error 31 | end 32 | -------------------------------------------------------------------------------- /project/5/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | escript: escript_config(), 8 | version: "0.1.0", 9 | elixir: "~> 1.13", 10 | start_permanent: Mix.env() == :prod, 11 | name: "Issues", 12 | source_url: "https://github.com/pragdave/issues", 13 | deps: deps() 14 | ] 15 | end 16 | 17 | # Run "mix help compile.app" to learn about applications. 18 | def application do 19 | [ 20 | extra_applications: [:logger] 21 | ] 22 | end 23 | 24 | # Run "mix help deps" to learn about dependencies. 25 | defp deps do 26 | [ 27 | { :httpoison, "~> 1.0" }, 28 | { :poison, "~> 5.0" }, 29 | { :ex_doc, "~> 0.25" }, 30 | { :earmark, "~> 1.4" }, 31 | ] 32 | end 33 | 34 | defp escript_config do 35 | [ 36 | main_module: Issues.CLI 37 | ] 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /project/5/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1, sort_into_descending_order: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | 20 | test "내림차순 정렬이 잘 수행된다." do 21 | result = sort_into_descending_order(fake_created_at_list(["c", "a", "b"])) 22 | issues = for issue <- result, do: Map.get(issue, "created_at") 23 | assert issues == ~w{ c b a } 24 | end 25 | 26 | defp fake_created_at_list(values) do 27 | for value <- values, 28 | do: %{"created_at" => value, "other_data" => "xxx"} 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /project/5/issues/test/doc_test.exs: -------------------------------------------------------------------------------- 1 | defmodule DocTest do 2 | use ExUnit.Case 3 | doctest Issues.TableFormatter 4 | end 5 | -------------------------------------------------------------------------------- /project/5/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /project/5/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /protocols/basic.exs: -------------------------------------------------------------------------------- 1 | defmodule Blob do 2 | defstruct content: nil 3 | end 4 | -------------------------------------------------------------------------------- /protocols/dueling-banjos.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/protocols/dueling-banjos.mid -------------------------------------------------------------------------------- /protocols/is_collection.exs: -------------------------------------------------------------------------------- 1 | defprotocol Collection do 2 | @fallback_to_any true 3 | def is_collection?(value) 4 | end 5 | 6 | defimpl Collection, for: [List, Tuple, BitString, Map] do 7 | def is_collection?(_), do: true 8 | end 9 | 10 | defimpl Collection, for: Any do 11 | def is_collection?(_), do: false 12 | end 13 | 14 | Enum.each [ 1, 1.0, [1,2], {1,2}, %{}, "cat" ], fn value -> 15 | IO.puts "#{inspect value}: #{Collection.is_collection?(value)}" 16 | end 17 | -------------------------------------------------------------------------------- /protocols/midi_inspect.exs: -------------------------------------------------------------------------------- 1 | Code.load_file("midi.exs") 2 | 3 | defimpl Inspect, for: Midi do 4 | def inspect(%Midi{content: <<>>}, _opts) do 5 | "#Midi[«empty»]" 6 | end 7 | 8 | def inspect(midi = %Midi{}, _opts) do 9 | content = 10 | Enum.map(midi, fn frame-> Kernel.inspect(frame) end) 11 | |> Enum.join("\n") 12 | "#Midi[\n#{content}\n]" 13 | end 14 | end 15 | 16 | defimpl Inspect, for: Midi.Frame do 17 | def inspect(%Midi.Frame{type: "MThd", 18 | length: 6, 19 | data: << 20 | format::integer-16, 21 | tracks::integer-16, 22 | division::bits-16 23 | >>}, 24 | _opts) do 25 | beats = decode(division) 26 | "#Midi.Header{Midi format: #{format}, tracks: #{tracks}, timing: #{beats}}" 27 | end 28 | 29 | def inspect(%Midi.Frame{type: "MTrk", length: length, data: data}, _opts) do 30 | "#Midi.Track{length: #{length}, data: #{Kernel.inspect(data)}" 31 | end 32 | 33 | defp decode(<< 0::1, beats::15>>) do 34 | "♩ = #{beats}" 35 | end 36 | 37 | defp decode(<< 1::1, fps::7, beats::8>>) do 38 | "#{-fps} fps, #{beats}/frame" 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spawn/chain.exs: -------------------------------------------------------------------------------- 1 | defmodule Chain do 2 | def counter(next_pid) do 3 | receive do 4 | n -> 5 | send next_pid, n + 1 6 | end 7 | end 8 | 9 | def create_processes(n) do 10 | code_to_run = fn (_,send_to) -> 11 | spawn(Chain, :counter, [send_to]) 12 | end 13 | 14 | last = Enum.reduce(1..n, self(), code_to_run) 15 | 16 | send(last, 0) # 마지막 프로세스에 0을 보내 카운트를 시작한다. 17 | 18 | receive do # 그리고 결과가 돌아올 때까지 기다린다. 19 | final_answer when is_integer(final_answer) -> 20 | "Result is #{inspect(final_answer)}" 21 | end 22 | end 23 | 24 | def run(n) do 25 | :timer.tc(Chain, :create_processes, [n]) 26 | |> IO.inspect 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spawn/fact_tr.exs: -------------------------------------------------------------------------------- 1 | defmodule TailRecursive do 2 | def factorial(n), do: _fact(n, 1) 3 | defp _fact(0, acc), do: acc 4 | defp _fact(n, acc), do: _fact(n-1, acc*n) 5 | end 6 | -------------------------------------------------------------------------------- /spawn/fib_agent.exs: -------------------------------------------------------------------------------- 1 | defmodule FibAgent do 2 | def start_link do 3 | Agent.start_link(fn -> %{ 0 => 0, 1 => 1 } end) 4 | end 5 | 6 | def fib(pid, n) when n >= 0 do 7 | Agent.get_and_update(pid, &do_fib(&1, n)) 8 | end 9 | 10 | defp do_fib(cache, n) do 11 | case cache[n] do 12 | nil -> 13 | { n_1, cache } = do_fib(cache, n-1) 14 | result = n_1 + cache[n-2] 15 | { result, Map.put(cache, n, result) } 16 | 17 | cached_value -> 18 | { cached_value , cache } 19 | end 20 | end 21 | end 22 | 23 | {:ok, agent} = FibAgent.start_link() 24 | IO.puts FibAgent.fib(agent, 2000) 25 | -------------------------------------------------------------------------------- /spawn/link1.exs: -------------------------------------------------------------------------------- 1 | defmodule Link1 do 2 | import :timer, only: [ sleep: 1 ] 3 | 4 | def sad_function do 5 | sleep 500 6 | exit(:boom) 7 | end 8 | 9 | def run do 10 | spawn(Link1, :sad_function, []) 11 | receive do 12 | msg -> 13 | IO.puts "MESSAGE RECEIVED: #{inspect msg}" 14 | after 1000 -> 15 | IO.puts "Nothing happened as far as I am concerned" 16 | end 17 | end 18 | end 19 | 20 | Link1.run 21 | -------------------------------------------------------------------------------- /spawn/link2.exs: -------------------------------------------------------------------------------- 1 | defmodule Link2 do 2 | import :timer, only: [ sleep: 1 ] 3 | 4 | def sad_function do 5 | sleep 500 6 | exit(:boom) 7 | end 8 | 9 | def run do 10 | spawn_link(Link2, :sad_function, []) 11 | receive do 12 | msg -> 13 | IO.puts "MESSAGE RECEIVED: #{inspect msg}" 14 | after 1000 -> 15 | IO.puts "Nothing happened as far as I am concerned" 16 | end 17 | end 18 | end 19 | 20 | Link2.run 21 | -------------------------------------------------------------------------------- /spawn/link3.exs: -------------------------------------------------------------------------------- 1 | defmodule Link3 do 2 | import :timer, only: [ sleep: 1 ] 3 | 4 | def sad_function do 5 | sleep 500 6 | exit(:boom) 7 | end 8 | 9 | def run do 10 | Process.flag(:trap_exit, true) 11 | spawn_link(Link3, :sad_function, []) 12 | receive do 13 | msg -> 14 | IO.puts "MESSAGE RECEIVED: #{inspect msg}" 15 | after 1000 -> 16 | IO.puts "Nothing happened as far as I am concerned" 17 | end 18 | end 19 | end 20 | 21 | Link3.run 22 | -------------------------------------------------------------------------------- /spawn/monitor1.exs: -------------------------------------------------------------------------------- 1 | defmodule Monitor1 do 2 | import :timer, only: [ sleep: 1 ] 3 | 4 | def sad_function do 5 | sleep 500 6 | exit(:boom) 7 | end 8 | 9 | def run do 10 | res = spawn_monitor(Monitor1, :sad_function, []) 11 | IO.puts inspect res 12 | receive do 13 | msg -> 14 | IO.puts "MESSAGE RECEIVED: #{inspect msg}" 15 | after 1000 -> 16 | IO.puts "Nothing happened as far as I am concerned" 17 | end 18 | end 19 | end 20 | 21 | Monitor1.run 22 | -------------------------------------------------------------------------------- /spawn/pmap.exs: -------------------------------------------------------------------------------- 1 | defmodule Parallel do 2 | def pmap(collection, fun) do 3 | me = self() 4 | collection 5 | |> Enum.map(fn (elem) -> 6 | spawn_link fn -> (send me, { self(), fun.(elem) }) end 7 | end) 8 | |> Enum.map(fn (pid) -> 9 | receive do { ^pid, result } -> result end 10 | end) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spawn/pmap1.exs: -------------------------------------------------------------------------------- 1 | defmodule Parallel do 2 | def pmap(collection, func) do 3 | collection 4 | |> Enum.map(&(Task.async(fn -> func.(&1) end))) 5 | |> Enum.map(&Task.await/1) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spawn/spawn-basic.ex: -------------------------------------------------------------------------------- 1 | defmodule SpawnBasic do 2 | def greet do 3 | IO.puts "Hello" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spawn/spawn1.exs: -------------------------------------------------------------------------------- 1 | defmodule Spawn1 do 2 | def greet do 3 | receive do 4 | {sender, msg} -> 5 | send sender, { :ok, "Hello, #{msg}" } 6 | end 7 | end 8 | end 9 | 10 | # 클라이언트 11 | pid = spawn(Spawn1, :greet, []) 12 | send pid, {self(), "World!"} 13 | 14 | receive do 15 | {:ok, message} -> 16 | IO.puts message 17 | end 18 | -------------------------------------------------------------------------------- /spawn/spawn2.exs: -------------------------------------------------------------------------------- 1 | defmodule Spawn2 do 2 | def greet do 3 | receive do 4 | {sender, msg} -> 5 | send sender, { :ok, "Hello, #{msg}" } 6 | end 7 | end 8 | end 9 | 10 | # 클라이언트 11 | pid = spawn(Spawn2, :greet, []) 12 | 13 | send pid, {self(), "World!"} 14 | receive do 15 | {:ok, message} -> 16 | IO.puts message 17 | end 18 | 19 | send pid, {self(), "Kermit!"} 20 | receive do 21 | {:ok, message} -> 22 | IO.puts message 23 | end 24 | -------------------------------------------------------------------------------- /spawn/spawn3.exs: -------------------------------------------------------------------------------- 1 | defmodule Spawn3 do 2 | def greet do 3 | receive do 4 | {sender, msg} -> 5 | send sender, { :ok, "Hello, #{msg}" } 6 | end 7 | end 8 | end 9 | 10 | # 클라이언트 11 | pid = spawn(Spawn3, :greet, []) 12 | 13 | send pid, {self(), "World!"} 14 | receive do 15 | {:ok, message} -> 16 | IO.puts message 17 | end 18 | 19 | send pid, {self(), "Kermit!"} 20 | receive do 21 | {:ok, message} -> 22 | IO.puts message 23 | after 500 -> 24 | IO.puts "The greeter has gone away" 25 | end 26 | -------------------------------------------------------------------------------- /spawn/spawn4.exs: -------------------------------------------------------------------------------- 1 | defmodule Spawn4 do 2 | def greet do 3 | receive do 4 | {sender, msg} -> 5 | send sender, { :ok, "Hello, #{msg}" } 6 | greet() 7 | end 8 | end 9 | end 10 | 11 | # 클라이언트 12 | pid = spawn(Spawn4, :greet, []) 13 | send pid, {self(), "World!"} 14 | receive do 15 | {:ok, message} -> 16 | IO.puts message 17 | end 18 | 19 | send pid, {self(), "Kermit!"} 20 | receive do 21 | {:ok, message} -> 22 | IO.puts message 23 | after 500 -> 24 | IO.puts "The greeter has gone away" 25 | end 26 | -------------------------------------------------------------------------------- /strings/parse.exs: -------------------------------------------------------------------------------- 1 | defmodule Parse do 2 | def number([ ?- | tail ]), do: _number_digits(tail, 0) * -1 3 | def number([ ?+ | tail ]), do: _number_digits(tail, 0) 4 | def number(str), do: _number_digits(str, 0) 5 | 6 | defp _number_digits([], value), do: value 7 | defp _number_digits([ digit | tail ], value) 8 | when digit in '0123456789' do 9 | _number_digits(tail, value*10 + digit - ?0) 10 | end 11 | defp _number_digits([ non_digit | _ ], _) do 12 | raise "Invalid digit '#{[non_digit]}'" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /strings/utf-iterate.ex: -------------------------------------------------------------------------------- 1 | defmodule Utf8 do 2 | def each(str, func) when is_binary(str), do: _each(str, func) 3 | 4 | defp _each(<< head :: utf8, tail :: binary >>, func) do 5 | func.(head) 6 | _each(tail, func) 7 | end 8 | 9 | defp _each(<<>>, _func), do: [] 10 | end 11 | 12 | Utf8.each "∂og", fn char -> IO.puts char end 13 | -------------------------------------------------------------------------------- /tasks/agent_dict.exs: -------------------------------------------------------------------------------- 1 | defmodule Frequency do 2 | def start_link do 3 | Agent.start_link(fn -> %{} end, name: __MODULE__) 4 | end 5 | 6 | 7 | def add_word(word) do 8 | Agent.update(__MODULE__, 9 | fn map -> 10 | Map.update(map, word, 1, &(&1+1)) 11 | end) 12 | end 13 | 14 | def count_for(word) do 15 | Agent.get(__MODULE__, fn map -> map[word] end) 16 | end 17 | 18 | def words do 19 | Agent.get(__MODULE__, fn map -> Map.keys(map) end) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /tasks/anagrams.exs: -------------------------------------------------------------------------------- 1 | defmodule Dictionary do 2 | @name __MODULE__ 3 | 4 | ## 5 | # 외부 API 6 | def start_link, 7 | do: Agent.start_link(fn -> %{} end, name: @name) 8 | 9 | def add_words(words), 10 | do: Agent.update(@name, &do_add_words(&1, words)) 11 | 12 | def anagrams_of(word), 13 | do: Agent.get(@name, &Map.get(&1, signature_of(word))) 14 | 15 | ## 16 | # 내부 구현 17 | defp do_add_words(map, words), 18 | do: Enum.reduce(words, map, &add_one_word(&1, &2)) 19 | 20 | defp add_one_word(word, map), 21 | do: Map.update(map, signature_of(word), [word], &[word|&1]) 22 | 23 | defp signature_of(word), 24 | do: word |> to_charlist |> Enum.sort |> to_string 25 | end 26 | 27 | defmodule WordlistLoader do 28 | def load_from_files(file_names) do 29 | file_names 30 | |> Stream.map(fn name -> Task.async(fn -> load_task(name) end) end) 31 | |> Enum.map(&Task.await/1) 32 | end 33 | 34 | defp load_task(file_name) do 35 | File.stream!(file_name, [], :line) 36 | |> Enum.map(&String.trim/1) 37 | |> Dictionary.add_words 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /tasks/anagrams_dist.exs: -------------------------------------------------------------------------------- 1 | defmodule Dictionary do 2 | @name {:global, __MODULE__} 3 | 4 | ## 5 | # 외부 API 6 | def start_link, 7 | do: Agent.start_link(fn -> %{} end, name: @name) 8 | 9 | def add_words(words), 10 | do: Agent.update(@name, &do_add_words(&1, words)) 11 | 12 | def anagrams_of(word), 13 | do: Agent.get(@name, &Map.get(&1, signature_of(word))) 14 | 15 | ## 16 | # 내부 구현 17 | defp do_add_words(map, words), 18 | do: Enum.reduce(words, map, &add_one_word(&1, &2)) 19 | 20 | defp add_one_word(word, map), 21 | do: Map.update(map, signature_of(word), [word], &[word|&1]) 22 | 23 | defp signature_of(word), 24 | do: word |> to_charlist |> Enum.sort |> to_string 25 | end 26 | 27 | defmodule WordlistLoader do 28 | def load_from_files(file_names) do 29 | file_names 30 | |> Stream.map(fn name -> Task.async(fn -> load_task(name) end) end) 31 | |> Enum.map(&Task.await/1) 32 | end 33 | 34 | defp load_task(file_name) do 35 | File.stream!(file_name, [], :line) 36 | |> Enum.map(&String.trim/1) 37 | |> Dictionary.add_words 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /tasks/my_app/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /tasks/my_app/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | my_app-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /tasks/my_app/README.md: -------------------------------------------------------------------------------- 1 | # MyApp 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `my_app` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:my_app, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/my_app](https://hexdocs.pm/my_app). 21 | 22 | -------------------------------------------------------------------------------- /tasks/my_app/lib/my_app.ex: -------------------------------------------------------------------------------- 1 | defmodule MyApp do 2 | @moduledoc """ 3 | Documentation for `MyApp`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> MyApp.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /tasks/my_app/lib/my_app/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MyApp.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | { MyApp.MyTask, 123 } 12 | ] 13 | 14 | # See https://hexdocs.pm/elixir/Supervisor.html 15 | # for other strategies and supported options 16 | opts = [strategy: :one_for_one, name: MyApp.Supervisor] 17 | Supervisor.start_link(children, opts) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /tasks/my_app/lib/my_app/my_task.ex: -------------------------------------------------------------------------------- 1 | defmodule MyApp.MyTask do 2 | use Task 3 | 4 | def start_link(param) do 5 | Task.start_link(__MODULE__, :thing_to_run, [ param ]) 6 | end 7 | 8 | def thing_to_run(param) do 9 | IO.puts "running task with #{param}" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /tasks/my_app/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule MyApp.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :my_app, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger], 18 | mod: {MyApp.Application, []} 19 | ] 20 | end 21 | 22 | # Run "mix help deps" to learn about dependencies. 23 | defp deps do 24 | [ 25 | # {:dep_from_hexpm, "~> 0.3.0"}, 26 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 27 | ] 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /tasks/my_app/test/my_app_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MyAppTest do 2 | use ExUnit.Case 3 | doctest MyApp 4 | 5 | test "greets the world" do 6 | assert MyApp.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /tasks/my_app/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /tasks/tasks1.exs: -------------------------------------------------------------------------------- 1 | defmodule Fib do 2 | def of(0), do: 0 3 | def of(1), do: 1 4 | def of(n), do: Fib.of(n-1) + Fib.of(n-2) 5 | end 6 | 7 | IO.puts "Start the task" 8 | worker = Task.async(fn -> Fib.of(20) end) 9 | IO.puts "Do something else" 10 | # ... 11 | IO.puts "Wait for the task" 12 | result = Task.await(worker) 13 | IO.puts "The result is #{result}" 14 | -------------------------------------------------------------------------------- /tasks/tasks2.exs: -------------------------------------------------------------------------------- 1 | defmodule Fib do 2 | def of(0), do: 0 3 | def of(1), do: 1 4 | def of(n), do: Fib.of(n-1) + Fib.of(n-2) 5 | end 6 | 7 | worker = Task.async(Fib, :of, [20]) 8 | result = Task.await(worker) 9 | IO.puts "The result is #{result}" 10 | -------------------------------------------------------------------------------- /tasks/words/list1: -------------------------------------------------------------------------------- 1 | angor 2 | argon 3 | caret 4 | carte 5 | cater 6 | crate 7 | creat 8 | creta 9 | 10 | -------------------------------------------------------------------------------- /tasks/words/list2: -------------------------------------------------------------------------------- 1 | ester 2 | estre 3 | goran 4 | grano 5 | groan 6 | leapt 7 | nagor 8 | orang 9 | 10 | 11 | -------------------------------------------------------------------------------- /tasks/words/list3: -------------------------------------------------------------------------------- 1 | palet 2 | patel 3 | pelta 4 | petal 5 | pleat 6 | react 7 | recta 8 | reest 9 | -------------------------------------------------------------------------------- /tasks/words/list4: -------------------------------------------------------------------------------- 1 | rogan 2 | ronga 3 | steer 4 | stere 5 | stree 6 | terse 7 | tsere 8 | tepal 9 | -------------------------------------------------------------------------------- /tooling/buggy/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /tooling/buggy/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | buggy-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /tooling/buggy/README.md: -------------------------------------------------------------------------------- 1 | # Buggy 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `buggy` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:buggy, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/buggy](https://hexdocs.pm/buggy). 21 | 22 | -------------------------------------------------------------------------------- /tooling/buggy/lib/buggy.ex: -------------------------------------------------------------------------------- 1 | defmodule Buggy do 2 | def parse_header( 3 | << 4 | format::integer-16, 5 | tracks::integer-16, 6 | division::integer-16 7 | >> 8 | ) do 9 | 10 | IO.puts "format: #{format}" 11 | IO.puts "tracks: #{tracks}" 12 | IO.puts "division: #{decode(division)}" 13 | end 14 | 15 | def decode(<< 1::1, beats::15 >>) do 16 | "♩ = #{beats}" 17 | end 18 | 19 | def decode(<< 0::1, fps::7, beats::8 >>) do 20 | "#{-fps} fps, #{beats}/frame" 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /tooling/buggy/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Buggy.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :buggy, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | # {:dep_from_hexpm, "~> 0.3.0"}, 25 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 26 | ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /tooling/buggy/test/buggy_test.exs: -------------------------------------------------------------------------------- 1 | defmodule BuggyTest do 2 | use ExUnit.Case 3 | doctest Buggy 4 | 5 | test "greets the world" do 6 | assert Buggy.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /tooling/buggy/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /tooling/issues/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /tooling/issues/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Ignore .fetch files in case you like to edit your project deps locally. 11 | /.fetch 12 | 13 | # If the VM crashes, it generates a dump, let's ignore it too. 14 | erl_crash.dump 15 | 16 | # Also ignore archive artifacts (built via "mix archive.build"). 17 | *.ez 18 | 19 | # Ignore package tarball (built via "mix hex.build"). 20 | issues-*.tar 21 | 22 | # Temporary files, for example, from tests. 23 | /tmp/ 24 | -------------------------------------------------------------------------------- /tooling/issues/README.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `issues` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:issues, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/issues](https://hexdocs.pm/issues). 21 | 22 | -------------------------------------------------------------------------------- /tooling/issues/config/config.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | config :issues, github_url: "https://api.github.com" 3 | config :logger, 4 | compile_time_purge_matching: [ 5 | [level_lower_than: :info] 6 | ] 7 | -------------------------------------------------------------------------------- /tooling/issues/doc/.build: -------------------------------------------------------------------------------- 1 | 404.html 2 | Issues.CLI.html 3 | Issues.GithubIssues.html 4 | Issues.TableFormatter.html 5 | Issues.html 6 | api-reference.html 7 | dist/app-f27ff079945e43879c46.js 8 | dist/elixir-a172fe91e725dcb259e2.css 9 | dist/html/fonts/icomoon.eot 10 | dist/html/fonts/icomoon.svg 11 | dist/html/fonts/icomoon.ttf 12 | dist/html/fonts/icomoon.woff 13 | dist/search_items-d6b809f7c6.js 14 | dist/sidebar_items-cda1b4999b.js 15 | index.html 16 | search.html 17 | -------------------------------------------------------------------------------- /tooling/issues/doc/Issues.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/tooling/issues/doc/Issues.epub -------------------------------------------------------------------------------- /tooling/issues/doc/dist/html/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/tooling/issues/doc/dist/html/fonts/icomoon.eot -------------------------------------------------------------------------------- /tooling/issues/doc/dist/html/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/tooling/issues/doc/dist/html/fonts/icomoon.ttf -------------------------------------------------------------------------------- /tooling/issues/doc/dist/html/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/tooling/issues/doc/dist/html/fonts/icomoon.woff -------------------------------------------------------------------------------- /tooling/issues/doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Issues v0.1.0 — Documentation 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tooling/issues/issues: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walnut-kwon/programming-elixir-kr/dc1ad79b85dcf701e77dc767c54f712a95f96bf8/tooling/issues/issues -------------------------------------------------------------------------------- /tooling/issues/lib/issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues do 2 | @moduledoc """ 3 | Documentation for `Issues`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Issues.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /tooling/issues/lib/issues/github_issues.ex: -------------------------------------------------------------------------------- 1 | defmodule Issues.GithubIssues do 2 | require Logger 3 | 4 | @user_agent [ {"User-agent", "Elixir dave@pragprog.com"} ] 5 | 6 | # 컴파일 타임에 값을 가져오기 위해 모듈 속성을 사용한다. 7 | @github_url Application.get_env(:issues, :github_url) 8 | 9 | def fetch(user, project) do 10 | Logger.info("Fetching #{user}'s project #{project}") 11 | issues_url(user, project) 12 | |> HTTPoison.get(@user_agent) 13 | |> handle_response 14 | end 15 | 16 | def issues_url(user, project) do 17 | "#{@github_url}/repos/#{user}/#{project}/issues" 18 | end 19 | 20 | def handle_response({ _, %{status_code: status_code, body: body}}) do 21 | Logger.info("Got response: status code=#{status_code}") 22 | Logger.debug(fn -> inspect(body) end) 23 | { 24 | status_code |> check_for_error(), 25 | body |> Poison.Parser.parse!(%{}) 26 | } 27 | end 28 | 29 | defp check_for_error(200), do: :ok 30 | defp check_for_error(_), do: :error 31 | end 32 | -------------------------------------------------------------------------------- /tooling/issues/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Issues.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :issues, 7 | escript: escript_config(), 8 | version: "0.1.0", 9 | elixir: "~> 1.13", 10 | start_permanent: Mix.env() == :prod, 11 | name: "Issues", 12 | source_url: "https://github.com/pragdave/issues", 13 | test_coverage: [tool: ExCoveralls], 14 | preferred_cli_env: [ 15 | "coveralls": :test, 16 | "coveralls.detail": :test, 17 | "coveralls.post": :test, 18 | "coveralls.html": :test 19 | ], 20 | deps: deps() 21 | ] 22 | end 23 | 24 | # Run "mix help compile.app" to learn about applications. 25 | def application do 26 | [ 27 | extra_applications: [:logger] 28 | ] 29 | end 30 | 31 | # Run "mix help deps" to learn about dependencies. 32 | defp deps do 33 | [ 34 | { :httpoison, "~> 1.0" }, 35 | { :poison, "~> 5.0" }, 36 | { :ex_doc, "~> 0.25" }, 37 | { :earmark, "~> 1.4" }, 38 | { :excoveralls, "~> 0.14", only: :test } 39 | ] 40 | end 41 | 42 | defp escript_config do 43 | [ 44 | main_module: Issues.CLI 45 | ] 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /tooling/issues/test/cli_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CliTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | import Issues.CLI, only: [parse_args: 1, sort_into_descending_order: 1] 6 | 7 | test "-h나 --help가 옵션으로 파싱되면 :help가 반환된다." do 8 | assert parse_args(["-h", "anything"]) == :help 9 | assert parse_args(["--help", "anything"]) == :help 10 | end 11 | 12 | test "값을 3개 전달하면 값 3개가 반환된다." do 13 | assert parse_args(["user", "project", "99"]) == {"user", "project", 99} 14 | end 15 | 16 | test "값을 2개 전달하면 개수에 기본값을 사용한다." do 17 | assert parse_args(["user", "project"]) == {"user", "project", 4} 18 | end 19 | 20 | test "내림차순 정렬이 잘 수행된다." do 21 | result = sort_into_descending_order(fake_created_at_list(["c", "a", "b"])) 22 | issues = for issue <- result, do: Map.get(issue, "created_at") 23 | assert issues == ~w{ c b a } 24 | end 25 | 26 | defp fake_created_at_list(values) do 27 | for value <- values, 28 | do: %{"created_at" => value, "other_data" => "xxx"} 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /tooling/issues/test/doc_test.exs: -------------------------------------------------------------------------------- 1 | defmodule DocTest do 2 | use ExUnit.Case 3 | doctest Issues.TableFormatter 4 | end 5 | -------------------------------------------------------------------------------- /tooling/issues/test/issues_test.exs: -------------------------------------------------------------------------------- 1 | defmodule IssuesTest do 2 | use ExUnit.Case 3 | doctest Issues 4 | 5 | test "greets the world" do 6 | assert Issues.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /tooling/issues/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /tooling/pbt/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /tooling/pbt/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | pbt-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /tooling/pbt/README.md: -------------------------------------------------------------------------------- 1 | # Pbt 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `pbt` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:pbt, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/pbt](https://hexdocs.pm/pbt). 21 | 22 | -------------------------------------------------------------------------------- /tooling/pbt/lib/pbt.ex: -------------------------------------------------------------------------------- 1 | defmodule Pbt do 2 | @moduledoc """ 3 | Documentation for `Pbt`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Pbt.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /tooling/pbt/lib/stats.ex: -------------------------------------------------------------------------------- 1 | defmodule Stats do 2 | def sum(vals), do: vals |> Enum.reduce(0, &+/2) 3 | def count(vals), do: vals |> length 4 | def average(vals), do: sum(vals) / count(vals) 5 | end 6 | -------------------------------------------------------------------------------- /tooling/pbt/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Pbt.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :pbt, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | { :stream_data, ">= 0.0.0" }, 25 | ] 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /tooling/pbt/mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "stream_data": {:hex, :stream_data, "0.5.0", "b27641e58941685c75b353577dc602c9d2c12292dd84babf506c2033cd97893e", [:mix], [], "hexpm", "012bd2eec069ada4db3411f9115ccafa38540a3c78c4c0349f151fc761b9e271"}, 3 | } 4 | -------------------------------------------------------------------------------- /tooling/pbt/test/pbt_test.exs: -------------------------------------------------------------------------------- 1 | defmodule PbtTest do 2 | use ExUnit.Case 3 | doctest Pbt 4 | 5 | test "greets the world" do 6 | assert Pbt.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /tooling/pbt/test/stats_property_test.exs: -------------------------------------------------------------------------------- 1 | defmodule StatsPropertyTest do 2 | use ExUnit.Case 3 | use ExUnitProperties 4 | 5 | describe "정수 리스트" do 6 | property "count 함수가 음수를 반환해서는 안 된다" do 7 | check all l <- list_of(integer()) do 8 | assert Stats.count(l) >= 0 9 | end 10 | end 11 | 12 | property "항목 1개짜리 리스트의 값의 합은 항목의 값과 같다" do 13 | check all number <- integer() do 14 | assert Stats.sum([number]) == number 15 | end 16 | end 17 | 18 | property "합은 평균과 항목 개수의 곱과 같다 (nonempty)" do 19 | check all l <- list_of(integer()) |> nonempty do 20 | assert_in_delta( 21 | Stats.sum(l), 22 | Stats.count(l)*Stats.average(l), 23 | 1.0e-6 24 | ) 25 | end 26 | end 27 | 28 | property "합은 평균과 항목 개수의 곱과 같다 (min_length)" do 29 | check all l <- list_of(integer(), min_length: 1) do 30 | assert_in_delta( 31 | Stats.sum(l), 32 | Stats.count(l)*Stats.average(l), 33 | 1.0e-6 34 | ) 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /tooling/pbt/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /typespecs/no_specs/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /typespecs/no_specs/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | no_specs-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /typespecs/no_specs/README.md: -------------------------------------------------------------------------------- 1 | # NoSpecs 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `no_specs` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:no_specs, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/no_specs](https://hexdocs.pm/no_specs). 21 | 22 | -------------------------------------------------------------------------------- /typespecs/no_specs/lib/no_specs.ex: -------------------------------------------------------------------------------- 1 | defmodule NoSpecs do 2 | def length_plus_n(list, n) do 3 | length(list) + n 4 | end 5 | 6 | def call_it do 7 | length_plus_n([1, 2], :c) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /typespecs/no_specs/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule NoSpecs.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :no_specs, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | { :dialyxir, "~> 1.0", only: [:dev], runtime: false } 25 | ] 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /typespecs/no_specs/mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, 3 | "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, 4 | } 5 | -------------------------------------------------------------------------------- /typespecs/no_specs/test/no_specs_test.exs: -------------------------------------------------------------------------------- 1 | defmodule NoSpecsTest do 2 | use ExUnit.Case 3 | doctest NoSpecs 4 | 5 | test "greets the world" do 6 | assert NoSpecs.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /typespecs/no_specs/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /typespecs/simple/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /typespecs/simple/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | simple-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /typespecs/simple/README.md: -------------------------------------------------------------------------------- 1 | # Simple 2 | 3 | **TODO: Add description** 4 | 5 | ## Installation 6 | 7 | If [available in Hex](https://hex.pm/docs/publish), the package can be installed 8 | by adding `simple` to your list of dependencies in `mix.exs`: 9 | 10 | ```elixir 11 | def deps do 12 | [ 13 | {:simple, "~> 0.1.0"} 14 | ] 15 | end 16 | ``` 17 | 18 | Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) 19 | and published on [HexDocs](https://hexdocs.pm). Once published, the docs can 20 | be found at [https://hexdocs.pm/simple](https://hexdocs.pm/simple). 21 | 22 | -------------------------------------------------------------------------------- /typespecs/simple/lib/simple.ex: -------------------------------------------------------------------------------- 1 | defmodule Simple do 2 | @type atom_list :: list(atom) 3 | @spec count_atoms(atom_list) :: non_neg_integer 4 | def count_atoms(list) do 5 | length list 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /typespecs/simple/lib/simple/client.ex: -------------------------------------------------------------------------------- 1 | defmodule Client do 2 | @spec other_function() :: non_neg_integer 3 | def other_function do 4 | Simple.count_atoms [:a, :b, :c] 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /typespecs/simple/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Simple.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :simple, 7 | version: "0.1.0", 8 | elixir: "~> 1.13", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | { :dialyxir, "~> 1.0", only: [:dev], runtime: false } 25 | ] 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /typespecs/simple/mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, 3 | "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, 4 | } 5 | -------------------------------------------------------------------------------- /typespecs/simple/test/simple_test.exs: -------------------------------------------------------------------------------- 1 | defmodule SimpleTest do 2 | use ExUnit.Case 3 | doctest Simple 4 | 5 | test "greets the world" do 6 | assert Simple.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /typespecs/simple/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /use/tracer.ex: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use Tracer 3 | def puts_sum_three(a,b,c), do: IO.inspect(a+b+c) 4 | def add_list(list), do: Enum.reduce(list, 0, &(&1+&2)) 5 | end 6 | 7 | Test.puts_sum_three(1,2,3) 8 | Test.add_list([5,6,7,8]) 9 | -------------------------------------------------------------------------------- /use/tracer1.ex: -------------------------------------------------------------------------------- 1 | defmodule Tracer do 2 | defmacro def(definition, do: _content) do 3 | IO.inspect definition 4 | quote do: {} 5 | end 6 | end 7 | 8 | defmodule Test do 9 | import Kernel, except: [def: 2] 10 | import Tracer, only: [def: 2] 11 | 12 | def puts_sum_three(a,b,c), do: IO.inspect(a+b+c) 13 | def add_list(list), do: Enum.reduce(list, 0, &(&1+&2)) 14 | end 15 | 16 | Test.puts_sum_three(1,2,3) 17 | Test.add_list([5,6,7,8]) 18 | -------------------------------------------------------------------------------- /use/tracer2.ex: -------------------------------------------------------------------------------- 1 | defmodule Tracer do 2 | defmacro def(definition, do: content) do 3 | quote do 4 | Kernel.def(unquote(definition)) do 5 | unquote(content) 6 | end 7 | end 8 | end 9 | end 10 | 11 | defmodule Test do 12 | import Kernel, except: [def: 2] 13 | import Tracer, only: [def: 2] 14 | 15 | 16 | def puts_sum_three(a,b,c), do: IO.inspect(a+b+c) 17 | def add_list(list), do: Enum.reduce(list, 0, &(&1+&2)) 18 | end 19 | 20 | Test.puts_sum_three(1,2,3) 21 | Test.add_list([5,6,7,8]) 22 | -------------------------------------------------------------------------------- /use/tracer3.ex: -------------------------------------------------------------------------------- 1 | defmodule Tracer do 2 | def dump_args(args) do 3 | args |> Enum.map(&inspect/1) |> Enum.join(", ") 4 | end 5 | 6 | def dump_defn(name, args) do 7 | "#{name}(#{dump_args(args)})" 8 | end 9 | 10 | defmacro def(definition={name,_,args}, do: content) do 11 | quote do 12 | Kernel.def(unquote(definition)) do 13 | IO.puts "==> call: #{Tracer.dump_defn(unquote(name), unquote(args))}" 14 | result = unquote(content) 15 | IO.puts "<== result: #{result}" 16 | result 17 | end 18 | end 19 | end 20 | end 21 | 22 | defmodule Test do 23 | import Kernel, except: [def: 2] 24 | import Tracer, only: [def: 2] 25 | 26 | def puts_sum_three(a,b,c), do: IO.inspect(a+b+c) 27 | def add_list(list), do: Enum.reduce(list, 0, &(&1+&2)) 28 | end 29 | 30 | 31 | Test.puts_sum_three(1,2,3) 32 | Test.add_list([5,6,7,8]) 33 | -------------------------------------------------------------------------------- /use/tracer4.ex: -------------------------------------------------------------------------------- 1 | defmodule Tracer do 2 | def dump_args(args) do 3 | args |> Enum.map(&inspect/1) |> Enum.join(", ") 4 | end 5 | 6 | def dump_defn(name, args) do 7 | "#{name}(#{dump_args(args)})" 8 | end 9 | 10 | defmacro def(definition={name,_,args}, do: content) do 11 | quote do 12 | Kernel.def(unquote(definition)) do 13 | IO.puts "==> call: #{Tracer.dump_defn(unquote(name), unquote(args))}" 14 | result = unquote(content) 15 | IO.puts "<== result: #{result}" 16 | result 17 | end 18 | end 19 | end 20 | 21 | defmacro __using__(_opts) do 22 | quote do 23 | import Kernel, except: [def: 2] 24 | import unquote(__MODULE__), only: [def: 2] 25 | end 26 | end 27 | end 28 | 29 | defmodule Test do 30 | use Tracer 31 | def puts_sum_three(a,b,c), do: IO.inspect(a+b+c) 32 | def add_list(list), do: Enum.reduce(list, 0, &(&1+&2)) 33 | end 34 | 35 | Test.puts_sum_three(1,2,3) 36 | Test.add_list([5,6,7,8]) 37 | --------------------------------------------------------------------------------