Packages

Fast, customizable anagram generator

Current section

Files

Jump to
swappy lib mix tasks generate.ex
Raw

lib/mix/tasks/generate.ex

defmodule Mix.Tasks.GenerateAnagrams do
use Mix.Task
use Swappy
@shortdoc "Simple task to generate anagrams for a phrase"
@moduledoc """
Generates anagrams using the default dictionary and outputs to STDOUT. Usage:
mix generate_anagrams input_phrase [limit] [required_words]
## Simple
mix generate_anagrams "hoverboard fever"
## With Limit
If you give a second argument, it will be taken as a limit for the number of anagrams to generate. Eg:
mix generate_anagrams "hoverboard fever" 10
If the limit can't be interpreted as an integer, it will be ignored. Eg:
mix generate_anagrams "hoverboard fever" infinity
## With Required Words
If you give a third argument, it will be treated as words the anagram must include. Eg:
mix generate_anagrams "hoverboard fever" infinity "rob drove"
This can be used to work toward something funny - if you see a word or words
you like, start requiring them, run again, and repeat.
"""
def run([phrase]) do
print_warning "No limit given - using #{default_limit}. Use 'infinity' to find all anagrams"
anagrams_of(phrase, %{limit: default_limit}) |> Enum.each(&(puts_unless_pipe_closed(&1)))
end
def run([phrase, limit]) do
anagrams_of(phrase, %{limit: parse_int(limit)}) |> Enum.each(&(puts_unless_pipe_closed(&1)))
end
def run([phrase, limit, without]) do
alphagrams = [phrase, without] |> Enum.map(&Swappy.Alphagram.to_alphagram/1)
case apply(Swappy.Alphagram, :without, alphagrams) do
{:ok, remaining_alphagram, _without} ->
remaining_phrase = Swappy.Alphagram.to_string(remaining_alphagram)
anagrams_of(remaining_phrase, %{limit: parse_int(limit)}) |> Enum.each(fn (anagram_without) ->
puts_unless_pipe_closed [without, " ", anagram_without]
end)
end
end
# For example, if user is piping STDOUT to `head -10`
defp puts_unless_pipe_closed(data) do
try do
IO.puts(data)
rescue
ErlangError -> exit(:shutdown)
end
end
defp parse_int(limit) when is_binary(limit) do
case Integer.parse(limit) do
:error ->
print_warning "'#{limit}' is not a valid limit; ignoring"
:infinity
{val, _} -> val
end
end
defp parse_int(_limit), do: :infinity
defp default_limit, do: 100
defp print_warning(message) do
IO.puts :stderr, "WARNING: #{message}"
end
end