mirror of
https://github.com/rjNemo/exercism-elixir
synced 2026-06-06 02:16:48 +00:00
date parser
This commit is contained in:
parent
d3487aa841
commit
0ab1fcaa3e
11 changed files with 861 additions and 0 deletions
22
date-parser/.exercism/config.json
Normal file
22
date-parser/.exercism/config.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"blurb": "Learn about regular expressions by parsing dates.",
|
||||
"authors": [
|
||||
"neenjaw"
|
||||
],
|
||||
"contributors": [
|
||||
"angelikatyborska",
|
||||
"Cohen-Carlisle"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/date_parser.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/date_parser_test.exs"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.ex"
|
||||
]
|
||||
},
|
||||
"language_versions": ">=1.10"
|
||||
}
|
||||
1
date-parser/.exercism/metadata.json
Normal file
1
date-parser/.exercism/metadata.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"track":"elixir","exercise":"date-parser","id":"3f650e7a4dd641cc8e2c6abdbea38850","url":"https://exercism.org/tracks/elixir/exercises/date-parser","handle":"rjNemo","is_requester":true,"auto_approve":false}
|
||||
4
date-parser/.formatter.exs
Normal file
4
date-parser/.formatter.exs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
date-parser/.gitignore
vendored
Normal file
24
date-parser/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# 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").
|
||||
regular_expressions-*.tar
|
||||
|
||||
75
date-parser/HELP.md
Normal file
75
date-parser/HELP.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
From the terminal, change to the base directory of the exercise then execute the tests with:
|
||||
|
||||
```bash
|
||||
$ mix test
|
||||
```
|
||||
|
||||
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
|
||||
|
||||
Documentation:
|
||||
|
||||
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
|
||||
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
|
||||
|
||||
## Pending tests
|
||||
|
||||
In test suites of practice exercises, all but the first test have been tagged to be skipped.
|
||||
|
||||
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
|
||||
|
||||
For example:
|
||||
|
||||
```elixir
|
||||
# @tag :pending
|
||||
test "shouting" do
|
||||
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
|
||||
end
|
||||
```
|
||||
|
||||
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
|
||||
|
||||
```bash
|
||||
$ mix test --include pending
|
||||
```
|
||||
|
||||
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
|
||||
|
||||
```elixir
|
||||
# ExUnit.configure(exclude: :pending, trace: true)
|
||||
```
|
||||
|
||||
## Useful `mix test` options
|
||||
|
||||
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
|
||||
* `--failed` - runs only tests that failed the last time they ran
|
||||
* `--max-failures` - the suite stops evaluating tests when this number of test failures
|
||||
is reached
|
||||
* `--seed 0` - disables randomization so the tests in a single file will always be ran
|
||||
in the same order they were defined in
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit lib/date_parser.ex` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
|
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.
|
||||
If you can't find what you're looking for in the documentation, feel free to ask help in the Exercism's BEAM [gitter channel](https://gitter.im/exercism/xerlang).
|
||||
52
date-parser/HINTS.md
Normal file
52
date-parser/HINTS.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- Review regular expression patterns from the introduction. Remember, when creating the pattern a string, you must escape some characters.
|
||||
- Read about the [`Regex` module][regex-docs] in the documentation.
|
||||
- Read about the [regular expression sigil][sigils-regex] in the Getting Started guide.
|
||||
- Check out this website about regular expressions: [Regular-Expressions.info][website-regex-info].
|
||||
- Check out this website about regular expressions: [Rex Egg -The world's most tyrannosauical regex tutorial][website-rexegg].
|
||||
- Check out this website about regular expressions: [RegexOne - Learn Regular Expressions with simple, interactive exercises.][website-regexone].
|
||||
- Check out this website about regular expressions: [Regular Expressions 101 - an online regex sandbox][website-regex-101].
|
||||
- Check out this website about regular expressions: [RegExr - an online regex sandbox][website-regexr].
|
||||
|
||||
## 1. Match the day, month, and year from a date
|
||||
|
||||
- Remember to return a string representing the regular expression pattern.
|
||||
- Review how to create _character classes_ or use _shorthand character classes_.
|
||||
- Review _quantifiers_.
|
||||
- A day is one or two digits.
|
||||
- A month is one or two digits.
|
||||
- A year is four digits.
|
||||
|
||||
## 2. Match the day of the week and the month of the year
|
||||
|
||||
- Review how to write a pattern to match _string literals_.
|
||||
- Review _alternations_.
|
||||
- Wrap the whole expression in a _group_.
|
||||
|
||||
## 3. Capture the day, month, and year
|
||||
|
||||
- Review how to write patterns for captures and named captures.
|
||||
- Reuse the `day/0`, `month/0`, `year/0`, `day_names/0`, and `month_names/0` functions that you already implemented.
|
||||
|
||||
## 4. Combine the captures to capture the whole date
|
||||
|
||||
- Remember, string interpolation may be used to join strings.
|
||||
- Reuse the `capture_day/0`, `capture_month/0`, `capture_year/0`, `capture_day_name/0`, and `capture_month_name/0` functions that you already implemented.
|
||||
|
||||
## 5. Narrow the capture to match only on the date
|
||||
|
||||
- Remembers, _anchors_ help to match the pattern to the **whole line**.
|
||||
- String interpolation may be used in the regular expression sigil syntax.
|
||||
- Reuse the `capture_numeric_date/0`, `capture_month_name_date/0`, and `capture_day_month_name_date/0` functions that you already implemented.
|
||||
|
||||
[regex-docs]: https://hexdocs.pm/elixir/Regex.html
|
||||
[sigils-regex]: https://elixir-lang.org/getting-started/sigils.html#regular-expressions
|
||||
[website-regex-info]: https://www.regular-expressions.info
|
||||
[website-rexegg]: https://www.rexegg.com/
|
||||
[website-regexone]: https://regexone.com/
|
||||
[website-regex-101]: https://regex101.com/
|
||||
[website-regexr]: https://regexr.com/
|
||||
[website-regex-crossword]: https://regexcrossword.com/
|
||||
196
date-parser/README.md
Normal file
196
date-parser/README.md
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
# Date Parser
|
||||
|
||||
Welcome to Date Parser on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||
|
||||
## Introduction
|
||||
|
||||
## Regular Expressions
|
||||
|
||||
Regular expressions (regex) are a powerful tool for working with strings in Elixir. Regular expressions in Elixir follow the **PCRE** specification (**P**erl **C**ompatible **R**egular **E**xpressions). String patterns representing the regular expression's meaning are first compiled then used for matching all or part of a string.
|
||||
|
||||
In Elixir, the most common way to create regular expressions is using the `~r` sigil. Sigils provide _syntactic sugar_ shortcuts for common tasks in Elixir. To match a _string literal_, we can use the string itself as a pattern following the sigil.
|
||||
|
||||
```elixir
|
||||
~r/test/
|
||||
```
|
||||
|
||||
The `=~/2` operator is useful to perform a regex match on a string to return a `boolean` result.
|
||||
|
||||
```elixir
|
||||
"this is a test" =~ ~r/test/
|
||||
# => true
|
||||
```
|
||||
|
||||
Two notes about using sigils:
|
||||
|
||||
- many different delimiters may be used depending on your requirements rather than `/`
|
||||
- string patterns are already _escaped_, when writing the pattern as a string not using a regex, you will have to _escape_ backslashes (`\`)
|
||||
|
||||
### Character classes
|
||||
|
||||
Matching a range of characters using square brackets `[]` defines a _character class_. This will match any one character to the characters in the class. You can also specify a range of characters like `a-z`, as long as the start and end represent a contiguous range of code points.
|
||||
|
||||
```elixir
|
||||
regex = ~r/[a-z][ADKZ][0-9][!?]/
|
||||
"jZ5!" =~ regex
|
||||
# => true
|
||||
"jB5?" =~ regex
|
||||
# => false
|
||||
```
|
||||
|
||||
_Shorthand character classes_ make the pattern more concise. For example:
|
||||
|
||||
- `\d` short for `[0-9]` (any digit)
|
||||
- `\w` short for `[A-Za-z0-9_]` (any 'word' character)
|
||||
- `\s` short for `[ \t\r\n\f]` (any whitespace character)
|
||||
|
||||
When a _shorthand character class_ is used outside of a sigil, it must be escaped: `"\\d"`
|
||||
|
||||
### Alternations
|
||||
|
||||
_Alternations_ use `|` as a special character to denote matching one _or_ another
|
||||
|
||||
```elixir
|
||||
regex = ~r/cat|bat/
|
||||
"bat" =~ regex
|
||||
# => true
|
||||
"cat" =~ regex
|
||||
# => true
|
||||
```
|
||||
|
||||
### Quantifiers
|
||||
|
||||
_Quantifiers_ allow for a repeating pattern in the regex. They affect the group preceding the quantifier.
|
||||
|
||||
- `{N, M}` where `N` is the minimum number of repetitions, and `M` is the maximum
|
||||
- `{N,}` match `N` or more repetitions
|
||||
- `{0,}` may also be written as `*`: match zero-or-more repetitions
|
||||
- `{1,}` may also be written as `+`: match one-or-more repetitions
|
||||
- `{,N}` match up to `N` repetitions
|
||||
|
||||
### Groups
|
||||
|
||||
Round brackets `()` are used to denote _groups_ and _captures_. The group may also be _captured_ in some instances to be returned for use. In Elixir, these may be named or un-named. Captures are named by appending `?<name>` after the opening parenthesis. Groups function as a single unit, like when followed by _quantifiers_.
|
||||
|
||||
```elixir
|
||||
regex = ~r/(h)at/
|
||||
Regex.replace(regex, "hat", "\\1op")
|
||||
# => "hop"
|
||||
|
||||
regex = ~r/(?<letter_b>b)/
|
||||
Regex.scan(regex, "blueberry", capture: :all_names)
|
||||
# => [["b"], ["b"]]
|
||||
```
|
||||
|
||||
### Anchors
|
||||
|
||||
_Anchors_ are used to tie the regular expression to the beginning or end of the string to be matched:
|
||||
|
||||
- `^` anchors to the beginning of the string
|
||||
- `$` anchors to the end of the string
|
||||
|
||||
### Interpolation
|
||||
|
||||
Because the `~r` is a shortcut for `"pattern" |> Regex.escape() |> Regex.compile!()`, you may also use string interpolation to dynamically build a regular expression pattern:
|
||||
|
||||
```elixir
|
||||
anchor = "$"
|
||||
regex = ~r/end of the line#{anchor}/
|
||||
"end of the line?" =~ regex
|
||||
# => false
|
||||
"end of the line" =~ regex
|
||||
# => true
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
You have been tasked to write a service which ingests events. Each event has a date associated with it, but you notice that 3 different formats are being submitted to your service's endpoint:
|
||||
|
||||
- `"01/01/1970"`
|
||||
- `"January 1, 1970"`
|
||||
- `"Thursday, January 1, 1970"`
|
||||
|
||||
You can see there are some similarities between each of them, and decide to write some composable regular expression patterns.
|
||||
|
||||
## 1. Match the day, month, and year from a date
|
||||
|
||||
Implement `day/0`, `month/0`, and `year/0` to return a string pattern which, when compiled, would match the numeric components in `"01/01/1970"` (`dd/mm/yyyy`). The day and month may appear as `1` or `01` (left padded with zeroes).
|
||||
|
||||
```elixir
|
||||
"31" =~ DateParser.day() |> Regex.compile!()
|
||||
# => true
|
||||
"12" =~ DateParser.month() |> Regex.compile!()
|
||||
# => true
|
||||
"1970" =~ DateParser.year() |> Regex.compile!()
|
||||
# => true
|
||||
```
|
||||
|
||||
## 2. Match the day of the week and the month of the year
|
||||
|
||||
Implement `day_names/0` and `month_names/0` to return a string pattern which, when compiled, would match the named day of the week and the named month of the year respectively.
|
||||
|
||||
```elixir
|
||||
"Tuesday" =~ DateParser.day_names() |> Regex.compile!()
|
||||
# => true
|
||||
"June" =~ DateParser.month_names() |> Regex.compile!()
|
||||
# => true
|
||||
```
|
||||
|
||||
## 3. Capture the day, month, and year
|
||||
|
||||
Implement `capture_day/0`, `capture_month/0`, `capture_year/0`, `capture_day_name/0`, `capture_month_name/0` to return a string pattern which captures the respective components to the names: `"day"`, `"month"`, `"year"`, `"day_name"`, `"month_name"`
|
||||
|
||||
```elixir
|
||||
DateParser.capture_month_name()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("December")
|
||||
# => %{"month_name" => "December"}
|
||||
```
|
||||
|
||||
## 4. Combine the captures to capture the whole date
|
||||
|
||||
Implement `capture_numeric_date/0`, `capture_month_name_date()`, and `capture_day_month_name_date/0` to return a string pattern which captures the components from part 3 using the respective date format:
|
||||
|
||||
- numeric date - `"01/01/1970"`
|
||||
- month name date - `"January 1, 1970"`
|
||||
- day month name date - `"Thursday, January 1, 1970"`
|
||||
|
||||
```elixir
|
||||
DateParser.capture_numeric_date()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("01/01/1970")
|
||||
# => %{"day" => "01", "month" => "01", "year" => "1970"}
|
||||
```
|
||||
|
||||
## 5. Narrow the capture to match only on the date
|
||||
|
||||
Implement `match_numeric_date/0`, `match_month_name_date/0`, and `match_day_month_name_date/0` to return a compiled regular expression that only matches the date, and which can also capture the components.
|
||||
|
||||
```elixir
|
||||
"Thursday, January 1, 1970 was the Unix epoch." =~ DateParser.match_day_month_name_date()
|
||||
# => false
|
||||
"Thursday, January 1, 1970" =~ DateParser.match_day_month_name_date()
|
||||
# => true
|
||||
|
||||
DateParser.match_day_month_name_date()
|
||||
|> Regex.named_captures("Thursday, January 1, 1970")
|
||||
# => %{
|
||||
# "day" => "1",
|
||||
# "day_name" => "Thursday",
|
||||
# "month_name" => "January",
|
||||
# "year" => "1970"
|
||||
# }
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @neenjaw
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @angelikatyborska
|
||||
- @Cohen-Carlisle
|
||||
34
date-parser/lib/date_parser.ex
Normal file
34
date-parser/lib/date_parser.ex
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
defmodule DateParser do
|
||||
def day(), do: "\\d{1,2}"
|
||||
|
||||
def month(), do: "\\d{1,2}"
|
||||
|
||||
def year(), do: "\\d{4}"
|
||||
|
||||
def day_names(), do: "(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)"
|
||||
|
||||
def month_names(),
|
||||
do: "(January|February|March|April|May|June|July|August|September|October|November|December)"
|
||||
|
||||
def capture_day(), do: "(?<day>#{day()})"
|
||||
|
||||
def capture_month(), do: "(?<month>#{month()})"
|
||||
|
||||
def capture_year(), do: "(?<year>#{year()})"
|
||||
|
||||
def capture_day_name(), do: "(?<day_name>#{day_names()})"
|
||||
|
||||
def capture_month_name(), do: "(?<month_name>#{month_names()})"
|
||||
|
||||
def capture_numeric_date(), do: "#{capture_day()}/#{capture_month()}/#{capture_year()}"
|
||||
|
||||
def capture_month_name_date(), do: "#{capture_month_name()} #{capture_day()}, #{capture_year()}"
|
||||
|
||||
def capture_day_month_name_date(), do: "#{capture_day_name()}, #{capture_month_name_date()}"
|
||||
|
||||
def match_numeric_date(), do: ~r/^#{capture_numeric_date()}$/
|
||||
|
||||
def match_month_name_date(), do: ~r/^#{capture_month_name_date()}$/
|
||||
|
||||
def match_day_month_name_date(), do: ~r/^#{capture_day_month_name_date()}$/
|
||||
end
|
||||
28
date-parser/mix.exs
Normal file
28
date-parser/mix.exs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
defmodule DateParser.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :date_parser,
|
||||
version: "0.1.0",
|
||||
# elixir: "~> 1.10",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps()
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[
|
||||
# {:dep_from_hexpm, "~> 0.3.0"},
|
||||
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
|
||||
]
|
||||
end
|
||||
end
|
||||
423
date-parser/test/date_parser_test.exs
Normal file
423
date-parser/test/date_parser_test.exs
Normal file
|
|
@ -0,0 +1,423 @@
|
|||
defmodule DateParserTest do
|
||||
use ExUnit.Case
|
||||
|
||||
@tag task_id: 1
|
||||
test "numeric pattern for day is a string" do
|
||||
assert DateParser.day() |> is_binary()
|
||||
end
|
||||
|
||||
describe "numeric pattern for day matches" do
|
||||
@tag task_id: 1
|
||||
test "un-padded days" do
|
||||
assert "1" =~ Regex.compile!(DateParser.day())
|
||||
assert "2" =~ Regex.compile!(DateParser.day())
|
||||
assert "3" =~ Regex.compile!(DateParser.day())
|
||||
assert "4" =~ Regex.compile!(DateParser.day())
|
||||
assert "5" =~ Regex.compile!(DateParser.day())
|
||||
assert "6" =~ Regex.compile!(DateParser.day())
|
||||
assert "7" =~ Regex.compile!(DateParser.day())
|
||||
assert "8" =~ Regex.compile!(DateParser.day())
|
||||
assert "9" =~ Regex.compile!(DateParser.day())
|
||||
assert "10" =~ Regex.compile!(DateParser.day())
|
||||
assert "11" =~ Regex.compile!(DateParser.day())
|
||||
assert "12" =~ Regex.compile!(DateParser.day())
|
||||
assert "13" =~ Regex.compile!(DateParser.day())
|
||||
assert "14" =~ Regex.compile!(DateParser.day())
|
||||
assert "15" =~ Regex.compile!(DateParser.day())
|
||||
assert "16" =~ Regex.compile!(DateParser.day())
|
||||
assert "17" =~ Regex.compile!(DateParser.day())
|
||||
assert "18" =~ Regex.compile!(DateParser.day())
|
||||
assert "19" =~ Regex.compile!(DateParser.day())
|
||||
assert "20" =~ Regex.compile!(DateParser.day())
|
||||
assert "21" =~ Regex.compile!(DateParser.day())
|
||||
assert "22" =~ Regex.compile!(DateParser.day())
|
||||
assert "23" =~ Regex.compile!(DateParser.day())
|
||||
assert "24" =~ Regex.compile!(DateParser.day())
|
||||
assert "25" =~ Regex.compile!(DateParser.day())
|
||||
assert "26" =~ Regex.compile!(DateParser.day())
|
||||
assert "27" =~ Regex.compile!(DateParser.day())
|
||||
assert "28" =~ Regex.compile!(DateParser.day())
|
||||
assert "29" =~ Regex.compile!(DateParser.day())
|
||||
assert "30" =~ Regex.compile!(DateParser.day())
|
||||
assert "31" =~ Regex.compile!(DateParser.day())
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "padded days" do
|
||||
assert "01" =~ Regex.compile!(DateParser.day())
|
||||
assert "02" =~ Regex.compile!(DateParser.day())
|
||||
assert "03" =~ Regex.compile!(DateParser.day())
|
||||
assert "04" =~ Regex.compile!(DateParser.day())
|
||||
assert "05" =~ Regex.compile!(DateParser.day())
|
||||
assert "06" =~ Regex.compile!(DateParser.day())
|
||||
assert "07" =~ Regex.compile!(DateParser.day())
|
||||
assert "08" =~ Regex.compile!(DateParser.day())
|
||||
assert "09" =~ Regex.compile!(DateParser.day())
|
||||
end
|
||||
end
|
||||
|
||||
describe "numeric pattern for day doesn't match" do
|
||||
@tag task_id: 1
|
||||
test "too few digits", do: refute("" =~ Regex.compile!("^#{DateParser.day()}$"))
|
||||
@tag task_id: 1
|
||||
test "too many digits", do: refute("111" =~ Regex.compile!("^#{DateParser.day()}$"))
|
||||
@tag task_id: 1
|
||||
test "one letter", do: refute("a" =~ Regex.compile!(DateParser.day()))
|
||||
@tag task_id: 1
|
||||
test "two letters", do: refute("bb" =~ Regex.compile!(DateParser.day()))
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "numeric pattern for month is a string" do
|
||||
assert DateParser.month() |> is_binary()
|
||||
end
|
||||
|
||||
describe "numeric pattern for month matches" do
|
||||
@tag task_id: 1
|
||||
test "un-padded months" do
|
||||
assert "1" =~ Regex.compile!(DateParser.month())
|
||||
assert "2" =~ Regex.compile!(DateParser.month())
|
||||
assert "3" =~ Regex.compile!(DateParser.month())
|
||||
assert "4" =~ Regex.compile!(DateParser.month())
|
||||
assert "5" =~ Regex.compile!(DateParser.month())
|
||||
assert "6" =~ Regex.compile!(DateParser.month())
|
||||
assert "7" =~ Regex.compile!(DateParser.month())
|
||||
assert "8" =~ Regex.compile!(DateParser.month())
|
||||
assert "9" =~ Regex.compile!(DateParser.month())
|
||||
assert "10" =~ Regex.compile!(DateParser.month())
|
||||
assert "11" =~ Regex.compile!(DateParser.month())
|
||||
assert "12" =~ Regex.compile!(DateParser.month())
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "padded months" do
|
||||
assert "01" =~ Regex.compile!(DateParser.month())
|
||||
assert "02" =~ Regex.compile!(DateParser.month())
|
||||
assert "03" =~ Regex.compile!(DateParser.month())
|
||||
assert "04" =~ Regex.compile!(DateParser.month())
|
||||
assert "05" =~ Regex.compile!(DateParser.month())
|
||||
assert "06" =~ Regex.compile!(DateParser.month())
|
||||
assert "07" =~ Regex.compile!(DateParser.month())
|
||||
assert "08" =~ Regex.compile!(DateParser.month())
|
||||
assert "09" =~ Regex.compile!(DateParser.month())
|
||||
end
|
||||
end
|
||||
|
||||
describe "numeric pattern for month doesn't match" do
|
||||
@tag task_id: 1
|
||||
test "too few digits", do: refute("" =~ Regex.compile!("^#{DateParser.month()}$"))
|
||||
@tag task_id: 1
|
||||
test "too many digits", do: refute("111" =~ Regex.compile!("^#{DateParser.month()}$"))
|
||||
@tag task_id: 1
|
||||
test "one letter", do: refute("a" =~ Regex.compile!(DateParser.month()))
|
||||
@tag task_id: 1
|
||||
test "two letters", do: refute("bb" =~ Regex.compile!(DateParser.month()))
|
||||
@tag task_id: 1
|
||||
test "short month name", do: refute("Jan" =~ Regex.compile!(DateParser.month()))
|
||||
@tag task_id: 1
|
||||
test "long month name", do: refute("January" =~ Regex.compile!(DateParser.month()))
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "numeric pattern for year is a string" do
|
||||
assert DateParser.year() |> is_binary()
|
||||
end
|
||||
|
||||
describe "numeric pattern for year" do
|
||||
@tag task_id: 1
|
||||
test "matches 4 digits", do: assert("1970" =~ Regex.compile!("^#{DateParser.year()}$"))
|
||||
@tag task_id: 1
|
||||
test "doesn't match short year", do: refute("84" =~ Regex.compile!("^#{DateParser.year()}$"))
|
||||
@tag task_id: 1
|
||||
test "doesn't match letters", do: refute("198A" =~ Regex.compile!("^#{DateParser.year()}$"))
|
||||
@tag task_id: 1
|
||||
test "doesn't match too few", do: refute("198" =~ Regex.compile!("^#{DateParser.year()}$"))
|
||||
@tag task_id: 1
|
||||
test "doesn't match too many", do: refute("19701" =~ Regex.compile!("^#{DateParser.year()}$"))
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "pattern for day names is a string" do
|
||||
assert DateParser.day_names() |> is_binary()
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "day names match" do
|
||||
assert "Sunday" =~ Regex.compile!(DateParser.day_names())
|
||||
assert "Monday" =~ Regex.compile!(DateParser.day_names())
|
||||
assert "Tuesday" =~ Regex.compile!(DateParser.day_names())
|
||||
assert "Wednesday" =~ Regex.compile!(DateParser.day_names())
|
||||
assert "Thursday" =~ Regex.compile!(DateParser.day_names())
|
||||
assert "Friday" =~ Regex.compile!(DateParser.day_names())
|
||||
assert "Saturday" =~ Regex.compile!(DateParser.day_names())
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "day names don't match with trailing or leading whitespace" do
|
||||
refute " Sunday " =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
refute " Monday " =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
refute " Tuesday " =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
refute " Wednesday " =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
refute " Thursday " =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
refute " Friday " =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
refute " Saturday " =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
end
|
||||
|
||||
describe "day names don't match" do
|
||||
@tag task_id: 2
|
||||
test "combined" do
|
||||
refute "TuesdayWednesday" =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "short name" do
|
||||
refute "Sun" =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "numeric day of the week (0-indexed)" do
|
||||
refute "0" =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "numeric day of the week (1-indexed)" do
|
||||
refute "1" =~ Regex.compile!("^#{DateParser.day_names()}$")
|
||||
end
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "pattern for month names is a string" do
|
||||
assert DateParser.month_names() |> is_binary()
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "month names match" do
|
||||
assert "January" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "February" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "March" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "April" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "May" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "June" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "July" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "August" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "September" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "October" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "November" =~ Regex.compile!(DateParser.month_names())
|
||||
assert "December" =~ Regex.compile!(DateParser.month_names())
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "month names don't match with trailing or leading whitespace" do
|
||||
refute " January " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " February " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " March " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " April " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " May " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " June " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " July " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " August " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " September " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " October " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " November " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
refute " December " =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
end
|
||||
|
||||
describe "month names don't match" do
|
||||
@tag task_id: 2
|
||||
test "combined" do
|
||||
refute "JanuaryFebruary" =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "short name" do
|
||||
refute "Jan" =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "numeric month of the year (0-indexed)" do
|
||||
refute "0" =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "numeric month of the year (1-indexed)" do
|
||||
refute "1" =~ Regex.compile!("^#{DateParser.month_names()}$")
|
||||
end
|
||||
end
|
||||
|
||||
describe "capture" do
|
||||
@tag task_id: 3
|
||||
test "numeric month" do
|
||||
assert DateParser.capture_month() |> is_binary()
|
||||
|
||||
assert %{"month" => "01"} =
|
||||
DateParser.capture_month()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("01")
|
||||
end
|
||||
|
||||
@tag task_id: 3
|
||||
test "numeric day" do
|
||||
assert DateParser.capture_day() |> is_binary()
|
||||
|
||||
assert %{"day" => "01"} =
|
||||
DateParser.capture_day()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("01")
|
||||
end
|
||||
|
||||
@tag task_id: 3
|
||||
test "numeric year" do
|
||||
assert DateParser.capture_year() |> is_binary()
|
||||
|
||||
assert %{"year" => "1970"} =
|
||||
DateParser.capture_year()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("1970")
|
||||
end
|
||||
|
||||
@tag task_id: 3
|
||||
test "capture day name" do
|
||||
assert DateParser.capture_day_name() |> is_binary()
|
||||
|
||||
assert %{"day_name" => "Monday"} =
|
||||
DateParser.capture_day_name()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("Monday")
|
||||
end
|
||||
|
||||
@tag task_id: 3
|
||||
test "capture month name" do
|
||||
assert DateParser.capture_month_name() |> is_binary()
|
||||
|
||||
assert %{"month_name" => "February"} =
|
||||
DateParser.capture_month_name()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("February")
|
||||
end
|
||||
|
||||
@tag task_id: 4
|
||||
test "numeric date" do
|
||||
assert DateParser.capture_numeric_date() |> is_binary()
|
||||
|
||||
assert %{"year" => "1970", "month" => "02", "day" => "01"} =
|
||||
DateParser.capture_numeric_date()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("01/02/1970")
|
||||
end
|
||||
|
||||
@tag task_id: 4
|
||||
test "month named date" do
|
||||
assert DateParser.capture_month_name_date() |> is_binary()
|
||||
|
||||
assert %{"year" => "1970", "month_name" => "January", "day" => "1"} =
|
||||
DateParser.capture_month_name_date()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("January 1, 1970")
|
||||
end
|
||||
|
||||
@tag task_id: 4
|
||||
test "day and month named date" do
|
||||
assert DateParser.capture_day_month_name_date() |> is_binary()
|
||||
|
||||
assert %{
|
||||
"year" => "1970",
|
||||
"month_name" => "January",
|
||||
"day" => "1",
|
||||
"day_name" => "Thursday"
|
||||
} =
|
||||
DateParser.capture_day_month_name_date()
|
||||
|> Regex.compile!()
|
||||
|> Regex.named_captures("Thursday, January 1, 1970")
|
||||
end
|
||||
end
|
||||
|
||||
describe "regex match" do
|
||||
@tag task_id: 5
|
||||
test "pattern to match numeric date is a regex" do
|
||||
assert match?(%Regex{}, DateParser.match_numeric_date())
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "numeric date matches" do
|
||||
assert DateParser.match_numeric_date() |> Regex.match?("01/02/1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "numeric date has named captures" do
|
||||
assert %{"year" => "1970", "month" => "02", "day" => "01"} =
|
||||
DateParser.match_numeric_date()
|
||||
|> Regex.named_captures("01/02/1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "numeric date with a prefix doesn't match" do
|
||||
refute DateParser.match_numeric_date() |> Regex.match?("The day was 01/02/1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "numeric date with a suffix doesn't match" do
|
||||
refute DateParser.match_numeric_date() |> Regex.match?("01/02/1970 was the day")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "pattern to match month name date is a regex" do
|
||||
assert match?(%Regex{}, DateParser.match_month_name_date())
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "month named date matches" do
|
||||
assert DateParser.match_month_name_date() |> Regex.match?("January 1, 1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "month named date has named captures" do
|
||||
assert %{"year" => "1970", "month_name" => "January", "day" => "1"} =
|
||||
DateParser.match_month_name_date()
|
||||
|> Regex.named_captures("January 1, 1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "month named date with a prefix doesn't match" do
|
||||
refute DateParser.match_month_name_date() |> Regex.match?("The day was January 1, 1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "month named date with a suffix doesn't match" do
|
||||
refute DateParser.match_month_name_date() |> Regex.match?("January 1, 1970 was the day")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "pattern to match day month name date is a regex" do
|
||||
assert match?(%Regex{}, DateParser.match_day_month_name_date())
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "day and month names date matches" do
|
||||
assert DateParser.match_day_month_name_date() |> Regex.match?("Thursday, January 1, 1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "day and month names date has named captures" do
|
||||
assert %{
|
||||
"year" => "1970",
|
||||
"month_name" => "January",
|
||||
"day" => "1",
|
||||
"day_name" => "Thursday"
|
||||
} =
|
||||
DateParser.match_day_month_name_date()
|
||||
|> Regex.named_captures("Thursday, January 1, 1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "day and month names date with a prefix doesn't match" do
|
||||
refute DateParser.match_day_month_name_date()
|
||||
|> Regex.match?("The day way Thursday, January 1, 1970")
|
||||
end
|
||||
|
||||
@tag task_id: 5
|
||||
test "day and month names date with a suffix doesn't match" do
|
||||
refute DateParser.match_day_month_name_date()
|
||||
|> Regex.match?("Thursday, January 1, 1970 was the day")
|
||||
end
|
||||
end
|
||||
end
|
||||
2
date-parser/test/test_helper.exs
Normal file
2
date-parser/test/test_helper.exs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true, seed: 0)
|
||||
Loading…
Reference in a new issue