Skip to content

Commit

Permalink
Move helper functions to a better place. [#70]
Browse files Browse the repository at this point in the history
  • Loading branch information
marnen committed Mar 8, 2018
1 parent 3efa22b commit 20c33de
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 24 deletions.
6 changes: 3 additions & 3 deletions phoenix/contraq/lib/contraq_web/cells/gig/template.html.haml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
- container! @gig do
%h1.name= link_to @gig
- for field <- fields do
- field_class = dasherize(field)
%div{class: field_class}= apply(__MODULE__, field, [@gig])
- for field_name <- fields do
- field_class = dasherize(field_name)
%div{class: field_class}= field @gig, field_name
16 changes: 5 additions & 11 deletions phoenix/contraq/lib/contraq_web/cells/gig/view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,16 @@ defmodule ContraqWeb.GigCell do
end
end

# TODO: Some of these seem like they belong elsewhere, but where? On Gig? On Gigs (the context)? On a helper module? GigView, maybe?
@spec location(%Gig{}) :: String.t
def location(%Gig{city: city, state: state}) do
[city, state] |> Enum.reject(&is_nil/1) |> Enum.join(", ")
end

@spec time_range(%Gig{}) :: String.t
def time_range(%Gig{start_time: start_time, end_time: end_time}) do
(for time <- [start_time, end_time], do: Timex.format!(time, Application.get_env(:contraq, ContraqWeb)[:datetime_format])) |> Enum.join("–")
end

@spec dasherize(atom | String.t) :: String.t
defp dasherize(string) do
string |> to_string |> String.replace("_", "-")
end

@spec field(%Gig{}, atom) :: String.t
defp field(%Gig{} = gig, name) do
apply(ContraqWeb.GigView, name, [gig])
end

@spec fields :: [atom]
defp fields do
[:time_range, :location]
Expand Down
13 changes: 13 additions & 0 deletions phoenix/contraq/lib/contraq_web/views/gig_view.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
defmodule ContraqWeb.GigView do
@dialyzer :no_return
use ContraqWeb, :view
alias Contraq.Gigs.Gig

@spec location(%Gig{}) :: String.t
def location(%Gig{city: city, state: state}) do
[city, state] |> Enum.reject(&is_nil/1) |> Enum.join(", ")
end

@spec time_range(%Gig{}) :: String.t
def time_range(%Gig{start_time: start_time, end_time: end_time}) do
for time <- [start_time, end_time] do
Timex.format!(time, Application.get_env(:contraq, ContraqWeb)[:datetime_format])
end |> Enum.join("–")
end
end
2 changes: 1 addition & 1 deletion phoenix/contraq/spec/contraq/gigs/gig_spec.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ defmodule Gigs.GigSpec do
import Map, only: [delete: 2]

context "validations" do
let :valid_attributes, do: Map.from_struct(Factory.insert! :gig)
let :valid_attributes, do: Map.from_struct(Factory.insert! :gig, required_only: true)
let :valid_changeset, do: Gig.changeset(%Gig{}, valid_attributes)

it "is valid with valid attributes" do
Expand Down
52 changes: 52 additions & 0 deletions phoenix/contraq/spec/contraq_web/views/gig_view_spec.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
defmodule ContraqWeb.GigViewSpec do
use ESpec.Phoenix, async: true, view: ContraqWeb.GigView
alias Contraq.Factory

let :attributes, do: %{}
let :gig, do: Factory.build(:gig, attributes)

describe ".location" do
subject do: described_module.location gig

context "city and state present" do
it "returns the city and state, joined with a comma" do
expect(subject).to eq "#{gig.city}, #{gig.state}"
end
end

context "city not present" do
let :attributes, do: %{city: nil}

it "returns the state" do
expect(subject).to eq gig.state
end
end

context "state not present" do
let :attributes, do: %{state: nil}

it "returns the city" do
expect(subject).to eq gig.city
end
end

context "no location" do
let :attributes, do: %{city: nil, state: nil}

it "returns an empty string" do
expect(subject).to eq ""
end
end
end

describe ".time_range" do
subject do: described_module.time_range gig

it "returns the starting and ending times for the gig, formatted and joined with an en-dash" do
formatted_times = for time <- [gig.start_time, gig.end_time] do
Timex.format! time, Application.get_env(:contraq, ContraqWeb)[:datetime_format]
end
expect(subject).to eq Enum.join(formatted_times, "–")
end
end
end
55 changes: 46 additions & 9 deletions phoenix/contraq/test/support/factory.ex
Original file line number Diff line number Diff line change
@@ -1,32 +1,48 @@
defmodule Contraq.Factory do
# Cribbed from http://blog.plataformatec.com.br/wp-content/uploads/2016/12/whats-new-in-ecto-2-0-1.pdf#page=39

@type factory :: atom

alias Contraq.Repo

@tags %{
gig: Contraq.Gigs.Gig,
user: Contraq.Coherence.User
}
@build_defaults [required_only: false]

@spec base(factory, keyword) :: struct
defp base(factory_name, opts \\ [])

defp base(:gig) do
%{
defp base(:gig, opts) do
[required_only: required_only] = Keyword.merge @build_defaults, opts
required = %{
name: Faker.Lorem.sentence,
start_time: Timex.to_datetime(Faker.Date.forward(100)), # TODO: randomize the time too?
end_time: &(Timex.shift &1[:start_time], minutes: :rand.uniform(4*60)),
user: fn _ -> build :user end
}
optional = %{
city: Faker.Address.city,
state: Faker.Address.state_abbr
}
if required_only, do: required, else: Map.merge optional, required
end

defp base(:user) do
%{
defp base(:user, opts) do
[required_only: required_only] = Keyword.merge @build_defaults, opts
required = %{
email: Faker.Internet.email,
password: Faker.Lorem.sentence,
password_confirmation: &(&1[:password])
}
optional = %{}
if required_only, do: required, else: Map.merge optional, required
end

def build(factory_name, attributes \\ %{}) do
base = base(factory_name)
@spec build(factory, map, keyword) :: struct
def build(factory_name, %{} = attributes, opts) do
base = base(factory_name, opts)
merged_attributes = Map.merge(base, attributes)
expanded_attributes = for {key, value} <- merged_attributes, into: %{} do
new_value = if is_function(value), do: value.(merged_attributes), else: value
Expand All @@ -35,10 +51,31 @@ defmodule Contraq.Factory do
struct Map.fetch!(@tags, factory_name), expanded_attributes
end

def insert!(factory_name, attributes \\ []) do
attributes_map = attributes |> Enum.into(%{})
record = build(factory_name, attributes_map)
@spec build(factory, map) :: struct
def build(factory_name, %{} = attributes), do: build(factory_name, attributes, [])

@spec build(factory, keyword) :: struct
def build(factory_name, opts), do: build(factory_name, %{}, opts)

@spec build(factory) :: struct
def build(factory_name), do: build(factory_name, %{}, [])

@spec insert!(factory, map, keyword) :: struct
def insert!(factory_name, %{} = attributes, opts) do
record = build(factory_name, attributes, opts)
tag = record.__struct__
Repo.insert! tag.changeset(struct(tag), Map.from_struct record)
end

@spec insert!(factory, map) :: struct
def insert!(factory_name, %{} = attributes), do: insert!(factory_name, attributes, [])

@spec insert!(factory, map) :: struct
def insert!(factory_name, %{} = attributes), do: insert!(factory_name, attributes, [])

@spec insert!(factory, keyword) :: struct
def insert!(factory_name, opts), do: insert!(factory_name, %{}, opts)

@spec insert!(factory) :: struct
def insert!(factory_name), do: build(factory_name, %{}, [])
end

0 comments on commit 20c33de

Please sign in to comment.