Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
Open sidebar
CodeStats
code-stats
Commits
34b8d1b4
Commit
34b8d1b4
authored
Aug 30, 2020
by
Mikko Ahlroth
Browse files
Add typed struct implementation to simplify structs
parent
20515c03
Pipeline
#183591936
failed with stages
in 4 minutes and 45 seconds
Changes
3
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
117 additions
and
41 deletions
+117
-41
lib/code_stats/user/cache.ex
lib/code_stats/user/cache.ex
+22
-25
lib/code_stats/utils.ex
lib/code_stats/utils.ex
+83
-0
lib/code_stats_web/gravatar/proxy.ex
lib/code_stats_web/gravatar/proxy.ex
+12
-16
No files found.
lib/code_stats/user/cache.ex
View file @
34b8d1b4
...
...
@@ -3,38 +3,35 @@ defmodule CodeStats.User.Cache do
User cache is data stored in the user's cache JSON field.
"""
@doc
"""
Struct for storing user cache data when processing it. Data is read from DB in `db_t` form and
must be passed through `CacheUtils.unformat_cache_from_db/1` to get it in struct form.
"""
defstruct
languages:
%{},
machines:
%{},
dates:
%{},
hours:
%{},
caching_duration:
0.0
,
total_caching_duration:
0.0
import
CodeStats
.
Utils
.
TypedStruct
@type
languages_t
::
%{
optional
(
integer
)
=>
integer
}
@type
machines_t
::
%{
optional
(
integer
)
=>
integer
}
@type
dates_t
::
%{
optional
(
Date
.
t
())
=>
integer
}
@type
hours_t
::
%{
optional
(
integer
)
=>
integer
}
@type
t
::
%
__MODULE__
{
# Map of language total XPs, key is language ID
languages:
languages_t
,
# Map of machine total XPs, key is machine ID
machines:
machines_t
,
# Map of date total XPs, key is date (Date)
dates:
dates_t
,
# Map of hour total XPs, key is hour (integer)
hours:
hours_t
,
# How long in seconds it took to update cache partially
caching_duration:
float
,
# How long in seconds it took to update cache totally
total_caching_duration:
float
}
@typedoc
"""
Struct for storing user cache data when processing it. Data is read from DB in `db_t` form and
must be passed through `CacheUtils.unformat_cache_from_db/1` to get it in struct form.
"""
deftypedstruct
(%{
# Map of language total XPs, key is language ID
languages:
{
languages_t
(),
%{}},
# Map of machine total XPs, key is machine ID
machines:
{
machines_t
(),
%{}},
# Map of date total XPs, key is date (Date)
dates:
{
dates_t
(),
%{}},
# Map of hour total XPs, key is hour (integer)
hours:
{
hours_t
(),
%{}},
# How long in seconds it took to update cache partially
caching_duration:
{
float
(),
0.0
},
# How long in seconds it took to update cache totally
total_caching_duration:
{
float
(),
0.0
}
})
# Cache data as read from DB, with string keys
@typedoc
"""
Cache data as read from DB, with string keys
"""
@type
db_t
::
%{
optional
(
String
.
t
())
=>
integer
|
float
}
...
...
lib/code_stats/utils.ex
View file @
34b8d1b4
...
...
@@ -12,4 +12,87 @@ defmodule CodeStats.Utils do
def
get_conf
(
key
)
do
Application
.
get_env
(
:code_stats
,
key
)
end
defmodule
TypedStruct
do
@moduledoc
"""
A typed struct implementation to make them less painful.
"""
@type
typespec
::
any
()
@type
enforced
::
{
typespec
(),
:enforced
}
@type
has_default
::
{
typespec
(),
any
()}
@type
field_spec
::
typespec
()
|
enforced
()
|
has_default
()
@type
field_map
::
%{
optional
(
atom
())
=>
field_spec
()}
@spec
deftypedstruct
(
field_map
())
::
term
()
@doc
"""
Create typed struct with a type, default values, and enforced keys.
Input should be a map where the key names are names of the struct keys and values are the
field information. The value can be a typespec, in which case the field will be enforced, or
a 2-tuple of `{typespec, default_value}`, making the field unenforced.
To prevent ambiguity, a value of `{typespec, :ts_enforced}` will be interpreted as enforced,
this will allow you to typespec a 2-tuple.
NOTE: Due to the ambiguity removal technique above, `:ts_enforced` is not allowed as a default
value.
Example:
```elixir
deftypedstruct(%{
# Enforced with simple type
foo: integer(),
# Enforced 2-tuple typed field, written like this to remove ambiguity
bar: {{String.t(), integer()}, :ts_enforced},
# Non-enforced field with default value
baz: {any(), ""}
})
```
"""
defmacro
deftypedstruct
(
fields
)
do
fields_list
=
case
fields
do
{
:%{}
,
_
,
flist
}
->
flist
_
->
raise
ArgumentError
,
"Fields must be a map!"
end
enforced_list
=
fields_list
|>
Enum
.
filter
(
fn
{
_
,
{
_
,
:ts_enforced
}}
->
true
{
_
,
{
_
,
_
}}
->
false
{
_
,
_
}
->
true
end
)
|>
Enum
.
map
(
&
elem
(
&1
,
0
))
field_specs
=
Enum
.
map
(
fields_list
,
fn
{
field
,
{
typespec
,
:ts_enforced
}}
->
{
field
,
typespec
}
{
field
,
{
typespec
,
_
}}
->
{
field
,
typespec
}
{
field
,
typespec
}
->
{
field
,
typespec
}
end
)
field_vals
=
Enum
.
map
(
fields_list
,
fn
{
field
,
{
_
,
:ts_enforced
}}
->
field
{
field
,
{
_
,
default
}}
->
{
field
,
default
}
{
field
,
_
}
->
field
end
)
quote
do
@type
t
::
%
__MODULE__
{
unquote_splicing
(
field_specs
)}
@enforce_keys
unquote
(
enforced_list
)
defstruct
unquote
(
field_vals
)
end
end
end
end
lib/code_stats_web/gravatar/proxy.ex
View file @
34b8d1b4
...
...
@@ -13,6 +13,7 @@ defmodule CodeStatsWeb.Gravatar.Proxy do
require
Logger
import
Ex2ms
,
only:
[
fun:
1
]
import
CodeStats
.
Utils
.
TypedStruct
alias
CodeStatsWeb
.
Gravatar
.
Utils
...
...
@@ -29,28 +30,23 @@ defmodule CodeStatsWeb.Gravatar.Proxy do
@type
response
::
{
:ok
,
String
.
t
(),
binary
()}
|
:error
defmodule
Options
do
@type
t
::
%
__MODULE__
{
name:
GenServer
.
name
()
}
@enforce_keys
[
:name
]
defstruct
[
:name
]
deftypedstruct
(%{
name:
GenServer
.
name
()
})
end
defmodule
State
do
defmodule
FetchData
do
@type
t
::
%
__MODULE__
{
task:
Task
.
t
(),
listeners:
[
GenServer
.
from
()]
}
@enforce_keys
[
:task
]
defstruct
[
:task
,
listeners:
[]]
deftypedstruct
(%{
task:
Task
.
t
(),
listeners:
{[
GenServer
.
from
()],
[]}
})
end
@type
t
::
%
__MODULE__
{
fetches:
%{
optional
(
Utils
.
hash
())
=>
FetchData
.
t
()},
refs:
%{
optional
(
reference
())
=>
Utils
.
hash
()}
}
defstruct
fetches:
%{},
refs:
%{}
deftypedstruct
(%{
fetches:
{%{
optional
(
Utils
.
hash
())
=>
FetchData
.
t
()},
%{}},
refs:
{%{
optional
(
reference
())
=>
Utils
.
hash
()},
%{}}
})
end
### SERVER INTERFACE ###
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment