Hi,
I'm trying to write a CLI - calendar.
The problem is, when I send messages through IEx, the result is as expected. However, when I send those messages one by one in other function's receive block, the output shows as if one list(stored as a state in a process [i guess..?]) was empty. The code (example messages will follow):
First module
defmodule ConcCalendar.Formatter do
use Timex, TableRex
def print_month(days, month, year) do
header = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
months = %{1 => "January", 2 => "February", 3 => "March", 4 => "April", 5 => "May", 6 => "June", 7 => "July",
8 => "August", 9 => "September", 10 => "October", 11 => "November", 12 => "December"}
TableRex.quick_render!(days, header, months[month])
|> IO.puts()
end
def year_manager(year, months) do
receive do
{:create_months, sender} ->
months = for month <- 1..12 do spawn(ConcCalendar.Formatter, :month_manager, [month, year, [], []]) end
for month_id <- months do
send month_id, {:create_days}
end
year_manager(year, months)
{:print_month, month} ->
month_pid = Enum.at(months, month - 1)
send month_pid, {:create_printable}
send month_pid, {:set_printable}
send month_pid, {:print}
year_manager(year,months)
end
end
def month_manager(month, year, days, printable) do
receive do
{:ok, day} ->
printable = List.insert_at(printable, -1, day)
month_manager(month, year, days, printable)
{:create_days} ->
days_in_month = 1..:calendar.last_day_of_the_month(year, month)
days = Enum.map(days_in_month, &ConcCalendar.DayCreator.create_day_tuple/1)
month_manager(month, year, days, printable)
{:create_printable} ->
for day_id <- days do
send day_id, {:get_date, self()}
end
month_manager(month, year, days, printable)
{:set_printable} ->
Enum.sort(printable)
first = :calendar.day_of_the_week(year, month, 1)
offset = first - 1
offset_list = []
offset_list = for _x <- 1..offset do offset_list ++ [""] end
printable = offset_list ++ printable
printable = Enum.chunk_every(printable, 7)
month_manager(month, year, days, printable)
{:print} ->
#send self(), {:create_printable}
#send self(), {:set_printable}
print_month(printable, month, year)
month_manager(month, year, days, printable)
end
end
end
Second module
defmodule ConcCalendar.DayCreator do
use Timex
def create_day_tuple(day) do
day_data = {day, "", ""}
spawn(ConcCalendar.DayCreator, :day_tuple, [day_data])
end
def day_tuple(day_data) do
{day, schedule, note} = day_data
receive do
{:schedule_a_meeting, sender} ->
if schedule == "" do
send sender, {:ok, "Successfully created a meeting"}
else
send sender, {:ok, "There is a meeting scheduled already"}
end
day_tuple({day, "*", note})
{:cancel_a_meeting, sender} ->
send sender, {:ok, "The meeting was canceled"}
day_tuple({day, "", note})
{:make_a_note, new_note, sender} ->
send sender, {:ok, "Succesfully created a note"}
day_tuple({day, schedule, new_note})
{:delete_note, sender} ->
send sender, {:ok, "The note was deleted"}
day_tuple({day, schedule, ""})
{:get_note, sender} ->
send sender, {:ok, note}
day_tuple(day_data)
{:get_date, sender} ->
send sender, {:ok, day}
day_tuple(day_data)
end
end
end
Usage
So my goal is to create a year_manager
process and then print an example month.
This is what I get:
iex(1)> year1 = spawn(ConcCalendar.Formatter, :year_manager, [2021, []])
#PID<0.253.0>
iex(2)> send year1, {:create_months, self()}
{:create_months, #PID<0.251.0>}
iex(3)> send year1, {:print_month, 3}
{:print_month, 3}
+-----------------------------------------+
| March |
+-----+-----+-----+-----+-----+-----+-----+
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
+-----+-----+-----+-----+-----+-----+-----+
| | |
+-----+-----+-----+-----+-----+-----+-----+
When I try to do this "by hand", without using the year_manager
process the output is okay:
iex(1)> month1 = spawn(ConcCalendar.Formatter, :month_manager, [1, 2021, [], []])
#PID<0.241.0>
iex(2)> send month1, {:create_days}
{:create_days}
iex(3)> send month1, {:create_printable}
{:create_printable}
iex(4)> send month1, {:set_printable}
{:set_printable}
iex(5)> send month1, {:print}
{:print}
+-----------------------------------------+
| January |
+-----+-----+-----+-----+-----+-----+-----+
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
+-----+-----+-----+-----+-----+-----+-----+
| | | | | 1 | 2 | 3 |
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
+-----+-----+-----+-----+-----+-----+-----+
I also get an error if I try to uncomment the lines in {:print} ->
block in first module, meaning I'm trying to send {:create_printable}
and {:set_printable}
messages inside the last, {:print}
.
Any tips are welcome, including those not directly related to my question. I'm just a CS student fed up with ubiquitous OOP and I gave Elixir a try after taking Erlang course at my uni.
I'm aware that doing everything with just spawning processes is not the best approach but this is my first Elixir project and I prefer just to stay with that for now.