Skip to content

Instantly share code, notes, and snippets.

@stijnmoreels
Last active November 15, 2019 09:09
Show Gist options
  • Save stijnmoreels/634d98ac2e63e59041f77e6b3a980b2d to your computer and use it in GitHub Desktop.
Save stijnmoreels/634d98ac2e63e59041f77e6b3a980b2d to your computer and use it in GitHub Desktop.
public class Author
{
private readonly string _name;
private Author(string name) { _name = name; }
public static ValidationResult<Author> Create(string author)
{
const string name = @"[A-Z]{1}[a-z]*\.?";
string pattern = $@"^({name})( {name})*$";
return Spec.Of<string>()
.NotNullOrWhiteSpace("author name should not be blank")
.Add(s => s.Length > 1, "author name should at least be a single character")
.Matches(pattern, $"author name should match regular expression: {pattern}")
.CreateModel(author, validated => new Author(validated));
}
}
public class ISBN13
{
private readonly string _code;
private ISBN13(string code) { _code = code; }
public static ValidationResult<ISBN13> Create(string code)
{
const string pattern = "^[0-9]+$";
return Spec.Of<string>()
.NotNullOrWhiteSpace("ISBN13 number should not be blank")
.Add(s => s.Length == 13, "ISBN13 number should be 13 characters long")
.Matches(pattern, $"ISBN13 number should match regular expression: {pattern}")
.StartsWith("978", "ISBN13 number should start with '978'")
.Add(Checksum, "ISBN13 checksum was invalid")
.CreateModel(code, validated => new ISBN13(validated));
}
private static bool Checksum(string code)
{
IEnumerable<int> numbers =
code.ToCharArray()
.Select(c => Int32.Parse(c.ToString()));
int sumNumbers =
numbers.Take(12)
.Select((n, i) => i % 2 != 0 ? n * 3 : n)
.Sum();
int remaining = sumNumbers % 10;
int checksum = remaining != 0 ? 10 - remaining : remaining;
int lastNumber = numbers.Last();
return checksum == lastNumber;
}
}
public class Int1000
{
private readonly int _value;
private Int1000(int value) { _value = value; }
public static ValidationResult<Int1000> Create(int value)
{
return Spec.Of<int>()
.InclusiveBetween(1, 1000, "integer number must be between 1-1000")
.CreateModel(value, validated => new Int1000(validated));
}
}
public class Book
{
private readonly Author _author;
private readonly ISBN13 _isbn13;
private readonly Int1000 _pages;
private Book(Author author, ISBN13 isbn13, Int1000 pages)
{
_author = author;
_isbn13 = isbn13;
_pages = pages;
}
public static ValidationResult<Book> Create(string author, string isbn13, int pages)
{
ValidationResult<Author> authorResult = Author.Create(author);
ValidationResult<ISBN13> isbn13Result = ISBN13.Create(isbn13);
ValidationResult<Int1000> pagesResult = Int1000.Create(pages);
return ValidationResult.Combine(authorResult, isbn13Result, pagesResult, (auth, isbn, ps) => new Book(auth, isbn, ps));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment