Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elixir Implementation #23

Merged
merged 35 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3c0d6e2
Implement Pika Elixir
ArtieFuzzz Feb 16, 2024
8650e85
Fix Elixir tests
ArtieFuzzz Feb 16, 2024
0345a8b
Fix encoding
ArtieFuzzz Feb 16, 2024
54e0cf1
Update Elixir readme
ArtieFuzzz Feb 16, 2024
7c58453
Fix tests
ArtieFuzzz Feb 16, 2024
80ec132
Update secure id
ArtieFuzzz Feb 16, 2024
2db83d7
Update Elixir package details
ArtieFuzzz Feb 16, 2024
2f73ffc
Update Elixir package details (again)
ArtieFuzzz Feb 16, 2024
db1ad8d
Update cases in `gen/1`
ArtieFuzzz Feb 16, 2024
94cb604
Add credo
ArtieFuzzz Feb 17, 2024
0030e36
Refactor code
ArtieFuzzz Feb 17, 2024
0934a55
Add benchmark
ArtieFuzzz Feb 17, 2024
591a1d0
Add example in README
ArtieFuzzz Feb 17, 2024
d8ca6a1
Pattern match instead of using `unless`
ArtieFuzzz Feb 17, 2024
67e49f6
Add documentation
ArtieFuzzz Feb 17, 2024
d1b1797
Update README
ArtieFuzzz Feb 17, 2024
7048b23
Add CI workflow
ArtieFuzzz Feb 17, 2024
d2728b9
Fix Snowflake blocking
ArtieFuzzz Feb 17, 2024
8a1047b
Fix error when parsing non-integer snowflakes
ArtieFuzzz Feb 17, 2024
03b0669
Include `_` in regex
ArtieFuzzz Feb 19, 2024
674f190
Lower Elixir version
ArtieFuzzz Feb 19, 2024
c65bea3
Add `ex_doc`
ArtieFuzzz Feb 19, 2024
34dd6a8
Update documentation
ArtieFuzzz Feb 19, 2024
d60c1fc
Fix Supervision of `Pika.Snowflake`
ArtieFuzzz Feb 19, 2024
653c85e
Fix README in docs?
ArtieFuzzz Feb 19, 2024
1096594
fix(snowflake): Handle `start_link/0`
ArtieFuzzz Feb 20, 2024
ecc2412
chore: Let compiler catch `gen/0`
ArtieFuzzz Feb 20, 2024
533ebd9
refactor: Fix `credo` warning
ArtieFuzzz Feb 20, 2024
117e745
chore(mix): Bump
ArtieFuzzz Feb 20, 2024
ee0e190
fix(workflows): Fix Elixir test not being picked up by Runners
ArtieFuzzz Feb 20, 2024
b960ec6
fix(docs): `gen/0` -> `gen/1`
ArtieFuzzz Feb 20, 2024
c6ffaf2
fix(README): Fix example mentioning `Pika.gen/0`
ArtieFuzzz Feb 20, 2024
59455fe
refactor: Update `Pika.Snowflake.start_link([])` to call `start_link/0`
ArtieFuzzz Feb 21, 2024
a5e308d
fix: Attempt to fix empty `:hwaddr` on interfaces
ArtieFuzzz Feb 21, 2024
2d3e43f
fix(workflow): Fix OTP compatibility and properly specify OTP version…
ArtieFuzzz Feb 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/pr-ex-test.yml
ArtieFuzzz marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Test Elixir implementation

on:
pull_request:
branches:
- main
paths:
- "impl/ex/**"
- ".github/workflows/pr-ex-test.yml"

jobs:
credo:
runs-on: ubuntu
steps:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
elixir-version: "1.16.1"
- name: Run credo
run: |
cd impl/ex

mix deps.get && mix deps.compile

mix credo

test:
runs-on: ubuntu
name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}}
strategy:
matrix:
otp: ["25", "26"]
elixir: ["1.16.1", "1.15.7", "1.14.0"]
steps:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}
- name: Run Tests
run: |
cd impl/ex

mix deps.get && mix deps.compile

mix test

169 changes: 169 additions & 0 deletions impl/ex/.credo.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
%{
configs: [
%{
name: "default",
files: %{
included: [
"lib/",
"src/",
"test/",
"web/"
],
excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"]
},
plugins: [],
requires: [],
strict: true,
parse_timeout: 5000,
color: false,
checks: %{
enabled: [
#
## Consistency Checks
#
{Credo.Check.Consistency.ExceptionNames, []},
{Credo.Check.Consistency.LineEndings, []},
{Credo.Check.Consistency.ParameterPatternMatching, []},
{Credo.Check.Consistency.SpaceAroundOperators, []},
{Credo.Check.Consistency.SpaceInParentheses, []},
{Credo.Check.Consistency.TabsOrSpaces, []},

#
## Design Checks
#
# You can customize the priority of any check
# Priority values are: `low, normal, high, higher`
#
{Credo.Check.Design.AliasUsage,
[priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]},
{Credo.Check.Design.TagFIXME, []},
# You can also customize the exit_status of each check.
# If you don't want TODO comments to cause `mix credo` to fail, just
# set this value to 0 (zero).
#
{Credo.Check.Design.TagTODO, [exit_status: 2]},

#
## Readability Checks
#
{Credo.Check.Readability.AliasOrder, []},
{Credo.Check.Readability.FunctionNames, []},
{Credo.Check.Readability.LargeNumbers, []},
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
{Credo.Check.Readability.ModuleAttributeNames, []},
{Credo.Check.Readability.ModuleDoc, []},
{Credo.Check.Readability.ModuleNames, []},
{Credo.Check.Readability.ParenthesesInCondition, []},
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, []},
{Credo.Check.Readability.PipeIntoAnonymousFunctions, []},
{Credo.Check.Readability.PredicateFunctionNames, []},
{Credo.Check.Readability.PreferImplicitTry, []},
{Credo.Check.Readability.RedundantBlankLines, []},
{Credo.Check.Readability.Semicolons, []},
{Credo.Check.Readability.SpaceAfterCommas, []},
{Credo.Check.Readability.StringSigils, []},
{Credo.Check.Readability.TrailingBlankLine, []},
{Credo.Check.Readability.TrailingWhiteSpace, []},
{Credo.Check.Readability.UnnecessaryAliasExpansion, []},
{Credo.Check.Readability.VariableNames, []},
{Credo.Check.Readability.WithSingleClause, []},

#
## Refactoring Opportunities
#
{Credo.Check.Refactor.Apply, []},
{Credo.Check.Refactor.CondStatements, []},
{Credo.Check.Refactor.CyclomaticComplexity, []},
{Credo.Check.Refactor.FilterCount, []},
{Credo.Check.Refactor.FilterFilter, []},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.LongQuoteBlocks, []},
{Credo.Check.Refactor.MapJoin, []},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
{Credo.Check.Refactor.Nesting, []},
{Credo.Check.Refactor.RedundantWithClauseResult, []},
{Credo.Check.Refactor.RejectReject, []},
{Credo.Check.Refactor.UnlessWithElse, []},
{Credo.Check.Refactor.WithClauses, []},

#
## Warnings
#
{Credo.Check.Warning.ApplicationConfigInModuleAttribute, []},
{Credo.Check.Warning.BoolOperationOnSameValues, []},
{Credo.Check.Warning.Dbg, []},
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
{Credo.Check.Warning.IExPry, []},
{Credo.Check.Warning.IoInspect, []},
{Credo.Check.Warning.MissedMetadataKeyInLoggerConfig, []},
{Credo.Check.Warning.OperationOnSameValues, []},
{Credo.Check.Warning.OperationWithConstantResult, []},
{Credo.Check.Warning.RaiseInsideRescue, []},
{Credo.Check.Warning.SpecWithStruct, []},
{Credo.Check.Warning.UnsafeExec, []},
{Credo.Check.Warning.UnusedEnumOperation, []},
{Credo.Check.Warning.UnusedFileOperation, []},
{Credo.Check.Warning.UnusedKeywordOperation, []},
{Credo.Check.Warning.UnusedListOperation, []},
{Credo.Check.Warning.UnusedPathOperation, []},
{Credo.Check.Warning.UnusedRegexOperation, []},
{Credo.Check.Warning.UnusedStringOperation, []},
{Credo.Check.Warning.UnusedTupleOperation, []},
{Credo.Check.Warning.WrongTestFileExtension, []}
],
disabled: [
#
# Checks scheduled for next check update (opt-in for now)
{Credo.Check.Refactor.UtcNowTruncate, []},

#
# Controversial and experimental checks (opt-in, just move the check to `:enabled`
# and be sure to use `mix credo --strict` to see low priority checks)
#
{Credo.Check.Consistency.MultiAliasImportRequireUse, []},
{Credo.Check.Consistency.UnusedVariableNames, []},
{Credo.Check.Design.DuplicatedCode, []},
{Credo.Check.Design.SkipTestWithoutComment, []},
{Credo.Check.Readability.AliasAs, []},
{Credo.Check.Readability.BlockPipe, []},
{Credo.Check.Readability.ImplTrue, []},
{Credo.Check.Readability.MultiAlias, []},
{Credo.Check.Readability.NestedFunctionCalls, []},
{Credo.Check.Readability.OneArityFunctionInPipe, []},
{Credo.Check.Readability.OnePipePerLine, []},
{Credo.Check.Readability.SeparateAliasRequire, []},
{Credo.Check.Readability.SingleFunctionToBlockPipe, []},
{Credo.Check.Readability.SinglePipe, []},
{Credo.Check.Readability.Specs, []},
{Credo.Check.Readability.StrictModuleLayout, []},
{Credo.Check.Readability.WithCustomTaggedTuple, []},
{Credo.Check.Refactor.ABCSize, []},
{Credo.Check.Refactor.AppendSingleItem, []},
{Credo.Check.Refactor.DoubleBooleanNegation, []},
{Credo.Check.Refactor.FilterReject, []},
{Credo.Check.Refactor.IoPuts, []},
{Credo.Check.Refactor.MapMap, []},
{Credo.Check.Refactor.ModuleDependencies, []},
{Credo.Check.Refactor.NegatedIsNil, []},
{Credo.Check.Refactor.PassAsyncInTestCases, []},
{Credo.Check.Refactor.PipeChainStart, []},
{Credo.Check.Refactor.RejectFilter, []},
{Credo.Check.Refactor.VariableRebinding, []},
{Credo.Check.Warning.LazyLogging, []},
{Credo.Check.Warning.LeakyEnvironment, []},
{Credo.Check.Warning.MapGetUnsafePass, []},
{Credo.Check.Warning.MixEnv, []},
{Credo.Check.Warning.UnsafeToAtom, []}

# {Credo.Check.Refactor.MapInto, []},

#
# Custom checks can be created using `mix credo.gen.check`.
#
]
}
}
]
}
4 changes: 4 additions & 0 deletions impl/ex/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
26 changes: 26 additions & 0 deletions impl/ex/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
pika-*.tar

# Temporary files, for example, from tests.
/tmp/
60 changes: 60 additions & 0 deletions impl/ex/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Pika

> Elixir implementation of Pika

Combine Stripe IDs with Snowflakes you get Pika! The last ID system you'll ever need!
Combining pragmatism with functionality

## Features

- Written in pure Elixir
- Zero Dependencies

## Installation

The package can be installed by adding `pika` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:pika, "~> 0.1.0"}
]
end
```

In your `config.exs`:

```elixir
config :pika,
prefixes: [
%{prefix: "user", description: "User IDs"},
%{prefix: "server", description: "Server IDs", secure: true},
# ...
]
```

## Example

`Pika.Snowflake` should be started under a `Supervisor` or `Application` before you start using
`Pika.gen/0` or `Pika.deconstruct/1`

```elixir
defmodule MyApp.Application do
use Application

def start(_type, _args) do
children = [Pika.Snowflake]

Supervisor.start_link(children, strategy: :one_for_one)
end
end
```

Somewhere in your application:

```elixir
# ...
Pika.gen("user") # or Pika.gen!("user")

{:ok, "user_MjgyNDQ2NjY1OTk3MjEzNjk3"}
```
16 changes: 16 additions & 0 deletions impl/ex/benchmarks/generation.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
defmodule Generation do
def id(), do: Pika.gen("user")
def id_secure(), do: Pika.gen("server")
def snowflake(), do: Pika.Snowflake.generate()
end

Pika.Snowflake.start_link()

Benchee.run(
%{
"Generate IDs" => fn -> Generation.id() end,
"Generate Secure IDs" => fn -> Generation.id_secure() end,
"Generate Snowflakes" => fn -> Generation.snowflake() end
},
time: 5
)
9 changes: 9 additions & 0 deletions impl/ex/config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Config

case config_env() do
:docs ->
:ok

_ ->
import_config "#{Mix.env()}.exs"
end
7 changes: 7 additions & 0 deletions impl/ex/config/dev.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Config

config :pika,
prefixes: [
%{prefix: "user", description: "User IDs"},
%{prefix: "server", description: "Server IDs", secure: true}
]
7 changes: 7 additions & 0 deletions impl/ex/config/test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Config

config :pika,
prefixes: [
%{prefix: "user", description: "User IDs"},
%{prefix: "server", description: "Server IDs", secure: true}
]
Loading
Loading