Skip to content

Instantly share code, notes, and snippets.

@sandeshsoni
Last active December 29, 2015 08:14
Show Gist options
  • Save sandeshsoni/ae62bb4b2e8824eb3bbf to your computer and use it in GitHub Desktop.
Save sandeshsoni/ae62bb4b2e8824eb3bbf to your computer and use it in GitHub Desktop.
Elixir code sample. Functions, anonymous function
defmodule Setup do
def process vehicle do
root_path = fn ->
Car.folder_path vehicle
end
generate_labels root_path.(), vehicle
create_sheets root_path.(), vehicle.sheets
end
def generate_labels directory_root, vehicle do
File.mkdir_p Path.join(directory_root, "trims")
sub_folder_path = fn(lab) ->
directory_root
|> Path.join("labels")
|> Path.join(Atom.to_string(lab))
|> Path.join(Map.get(vehicle,lab))
end
[
:name,
:brand,
:region
]
|> Enum.map( fn property -> sub_folder_path.(property) end)
|> Enum.each( fn path -> File.mkdir_p!(path) end)
end
defp create_sheets(directory_root, sheets \\ []) do
create_sheets_directory = fn() ->
File.mkdir_p Path.join(directory_root, "Sheets")
end
process_sheet = fn
x when is_bitstring(x) ->
Specifico.download(x, directory_root)
x when is_atom(x) ->
Specifico.download(Atom.to_string(x),directory_root)
{ url, f_name } when is_tuple({ url, f_name }) ->
Specifico.download(url, directory_root, f_name)
x ->
IO.puts x
end
create_sheets_directory.()
sheets
|> Enum.each(fn(sheet) -> process_sheet.(sheet) end)
end
end
@KronicDeth
Copy link

If you have a zero-argument anonymous function that you're not immediately passing to another function, but instead calling and then passing the return value, you should just use a local variable because then you're not going through the overhead of a function definition and call. In your code this would have these changes:

Before

defmodule Setup do
  def process vehicle do
    root_path = fn ->
      Car.folder_path vehicle
    end

    generate_labels root_path.(), vehicle
    create_sheets root_path.(), vehicle.sheets
  end
end

After

defmodule Setup do
  def process vehicle do
    root_path = Car.folder_path vehicle

    generate_labels root_path, vehicle
    create_sheets root_path, vehicle.sheets
  end
end

@KronicDeth
Copy link

For create_sheets_directory, I would just make it a full function since you're naming it anyway and its name still makes sense outside the context of create_sheets:

Before

defmodule Setup do
  defp create_sheets(directory_root, sheets \\ []) do
    create_sheets_directory = fn() ->
      File.mkdir_p Path.join(directory_root, "Sheets")
    end

    process_sheet = fn
      x when is_bitstring(x) ->
        Specifico.download(x, directory_root)
      x when is_atom(x) ->
        Specifico.download(Atom.to_string(x),directory_root)
      { url, f_name } when is_tuple({ url, f_name }) ->
        Specifico.download(url, directory_root, f_name)
      x ->
        IO.puts x
    end

    create_sheets_directory.()
    sheets
    |> Enum.each(fn(sheet) -> process_sheet.(sheet) end)
  end
end

After

defmodule Setup do
  defp create_sheets(directory_root, sheets \\ []) do
    process_sheet = fn
      x when is_bitstring(x) ->
        Specifico.download(x, directory_root)
      x when is_atom(x) ->
        Specifico.download(Atom.to_string(x),directory_root)
      { url, f_name } when is_tuple({ url, f_name }) ->
        Specifico.download(url, directory_root, f_name)
      x ->
        IO.puts x
    end

    create_sheets_directory(directory_root)

    sheets
    |> Enum.each(fn(sheet) -> process_sheet.(sheet) end)
  end

  defp create_sheets_directory(parent_directory) do
    File.mkdir_p Path.join(parent_directory, "Sheets")
  end
end

I also put a blank line between the call to create_sheets_directory and the pipeline because when I first read the code I though create_sheets_directory was part of the pipeline.

@KronicDeth
Copy link

In addition to the Path.join/2 you used, there is a Path.join/1 that takes a list. This is probably more efficient than the pipe line of Path.join/2 calls:

Before

defmodule Setup do
  def generate_labels directory_root, vehicle do
    File.mkdir_p Path.join(directory_root, "trims")
    sub_folder_path = fn(lab) ->
      directory_root
      |> Path.join("labels")
      |> Path.join(Atom.to_string(lab))
      |> Path.join(Map.get(vehicle,lab))
    end

    [
      :name,
      :brand,
      :region
    ]
  |> Enum.map( fn property -> sub_folder_path.(property) end)
  |> Enum.each( fn path -> File.mkdir_p!(path) end)
  end
end

After

defmodule Setup do
  def generate_labels directory_root, vehicle do
    File.mkdir_p Path.join(directory_root, "trims")
    sub_folder_path = fn(lab) ->
      Path.join([directory_root, "labels", Atom.to_string(lab), Map.get(vehicle, lab))
    end

    [
      :name,
      :brand,
      :region
    ]
  |> Enum.map( fn property -> sub_folder_path.(property) end)
  |> Enum.each( fn path -> File.mkdir_p!(path) end)
  end
end

@sandeshsoni
Copy link
Author

Thanks for your feedback.
Previously I used Path.join/1.
Just to make code look beautiful, i made change to use Path.join/2 with pipe operator.
If it is a cost, will make the change.

Also tried to take care of Tell Don't Ask principle. Below code example as well as create_sheets.
In generate_labels() i have to send whole object of vehicle; Not sure if i missed any principle.

def create_sample_dictionary(root_dir, trims) do
  trim_dictionary_path = fn(trim) ->
    root_dir
    |> Path.join("raw")
    |> Path.join("sample_dictionary")
    |> Path.join( "__" <> String.strip(trim) <> "__" <> String.strip(trim))
  end

  root_dir
  |> Path.join("raw")
  |> Path.join("sample_dictionary")
  |> File.mkdir_p

  trims ++ ~w(key1 key2)
  |> Enum.map(fn trim -> trim_dictionary_path.(trim) end)
  |> Enum.each(fn path -> File.touch path end)
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment