Skip to content

Commit

Permalink
Premium License, Datasets, and Extensibility Refactoring (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
bchavez authored Feb 27, 2018
1 parent 5ab4317 commit 672a002
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 40 deletions.
3 changes: 2 additions & 1 deletion HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* Added improved XML doc comments and parameter names on `Lorem.Paragraph`.
* UK extension method `.ShortCode()` renamed to `.SortCode()` as originally intended.
* Marked `DataSet.Get/.GetObject/BObject` methods as `protected internal`. Reducing API surface noise.
* Added new `.OrNull` in `Bogus.Extensions` to help create randomly null values. Example: `.RuleFor(x=>x.Prop, f=>f.Random.Word().OrNull(f))`
* Added new `.OrNull` in `Bogus.Extensions` to help create randomly null values. Example: `.RuleFor(x=>x.Prop, f=>f.Random.Word().OrNull(f))`.
* New groundwork for extending Bogus with premium (paid) data sets and tooling.

## v22.0.2
* Issue 121: Fixes the inability to `.Ignore(...)` a property or field after a rule had already been set.
Expand Down
22 changes: 22 additions & 0 deletions Source/Bogus/BogusException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;

namespace Bogus
{
/// <summary>
/// General exception for Bogus.
/// </summary>
public class BogusException : Exception
{
public BogusException()
{
}

public BogusException(string message) : base(message)
{
}

public BogusException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
24 changes: 16 additions & 8 deletions Source/Bogus/DataSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ public DataSet(string locale = "en")
this.Category = ResolveCategory(this.GetType());
}

protected SeedNotifier<DataSet> Notifier = new SeedNotifier<DataSet>();
/// <summary>
/// See <see cref="SeedNotifier"/>
/// </summary>
protected SeedNotifier Notifier = new SeedNotifier();

private Randomizer randomizer;

Expand All @@ -47,6 +50,11 @@ public Randomizer Random
}
}

SeedNotifier IHasRandomizer.GetNotifier()
{
return this.Notifier;
}

/// <summary>
/// The category name inside the locale
/// </summary>
Expand All @@ -61,15 +69,15 @@ public Randomizer Random
/// Returns a BSON value given a JSON path into the data set. Only simple "." dotted JSON paths are supported.
/// </summary>
/// <param name="path">path/key in the category</param>
protected internal BValue Get(string path)
protected internal virtual BValue Get(string path)
{
return Database.Get(this.Category, path, this.Locale);
}

/// <summary>
/// Determines if a key exists in the locale.
/// </summary>
protected bool HasKey(string path, bool includeFallback = true)
protected internal virtual bool HasKey(string path, bool includeFallback = true)
{
if( includeFallback )
return Database.HasKey(this.Category, path, this.Locale);
Expand All @@ -82,7 +90,7 @@ protected bool HasKey(string path, bool includeFallback = true)
/// </summary>
/// <param name="path">key in the category</param>
/// <returns></returns>
protected internal BArray GetArray(string path)
protected internal virtual BArray GetArray(string path)
{
return (BArray)Get(path);
}
Expand All @@ -91,7 +99,7 @@ protected internal BArray GetArray(string path)
/// Returns a BSON object given a JSON path into the data set. Only simple "." dotted JSON paths are supported.
/// </summary>
/// <param name="path">path/key in the category</param>
protected internal BObject GetObject(string path)
protected internal virtual BObject GetObject(string path)
{
return (BObject)Get(path);
}
Expand All @@ -100,7 +108,7 @@ protected internal BObject GetObject(string path)
/// Picks a random string inside a BSON array. Only simple "." dotted JSON paths are supported.
/// </summary>
/// <param name="path">key in the category</param>
protected internal string GetRandomArrayItem(string path, int? min = null, int? max = null)
protected internal virtual string GetRandomArrayItem(string path, int? min = null, int? max = null)
{
var arr = GetArray(path);
if( !arr.HasValues ) return string.Empty;
Expand All @@ -110,7 +118,7 @@ protected internal string GetRandomArrayItem(string path, int? min = null, int?
/// <summary>
/// Picks a random BObject inside an array.
/// </summary>
protected internal BObject GetRandomBObject(string path)
protected internal virtual BObject GetRandomBObject(string path)
{
var arr = GetArray(path);
if( !arr.HasValues ) return null;
Expand All @@ -121,7 +129,7 @@ protected internal BObject GetRandomBObject(string path)
/// Picks a random string inside a BSON array, then formats it. Only simple "." dotted JSON paths are supported.
/// </summary>
/// <param name="path">key in the category</param>
protected internal string GetFormattedValue(string path)
protected internal virtual string GetFormattedValue(string path)
{
var value = GetRandomArrayItem(path);

Expand Down
74 changes: 53 additions & 21 deletions Source/Bogus/Database.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
Expand Down Expand Up @@ -40,31 +39,16 @@ private static ConcurrentDictionary<string, BObject> Initialize()
{
//Just lazy load English only.
var d = new ConcurrentDictionary<string, BObject>();
d.TryAdd("en", InitLocale("en"));
d.TryAdd("en", DeserializeLocale("en"));
return d;
}


internal static BObject InitLocale(string locale)
internal static BObject DeserializeLocale(string locale)
{
var asm = typeof(Database).GetAssembly();
var resourceName = $"Bogus.data.{locale}.locale.bson";

return ReadResource(asm, resourceName) as BObject;
}

/// <summary>
/// Reads a BSON resource from an assembly.
/// </summary>
public static BValue ReadResource(System.Reflection.Assembly assembly, string resourceName)
{
using( var s = assembly.GetManifestResourceStream(resourceName) )
using( var ms = new MemoryStream() )
{
s.CopyTo(ms);

return Bson.Bson.Load(ms.ToArray());
}
return ResourceHelper.ReadBObjectResource(asm, resourceName);
}

/// <summary>
Expand All @@ -75,7 +59,7 @@ public static BObject GetLocale(string locale)
{
if( !Data.Value.TryGetValue(locale, out BObject l) )
{
l = InitLocale(locale);
l = DeserializeLocale(locale);
Data.Value.TryAdd(locale, l);
}

Expand All @@ -88,7 +72,7 @@ public static BObject GetLocale(string locale)
/// </summary>
public static void ResetLocale(string locale)
{
Data.Value[locale] = InitLocale(locale);
Data.Value[locale] = DeserializeLocale(locale);
}

/// <summary>
Expand Down Expand Up @@ -157,4 +141,52 @@ private static BValue Select(string category, string path, BValue localeRoot)
}
}
}

/// <summary>
/// Helper utility class to read resource manifest streams.
/// </summary>
public static class ResourceHelper
{
/// <summary>
/// Reads a byte[] resource from an assembly.
/// </summary>
public static byte[] ReadResource(System.Reflection.Assembly assembly, string resourceName)
{
using( var s = assembly.GetManifestResourceStream(resourceName) )
using( var ms = new MemoryStream() )
{
s.CopyTo(ms);

return ms.ToArray();
}
}

/// <summary>
/// Reads a BSON <see cref="BValue"/> resource from an assembly.
/// </summary>
public static BValue ReadBValueResource(System.Reflection.Assembly assembly, string resourceName)
{
using( var s = assembly.GetManifestResourceStream(resourceName) )
using( var ms = new MemoryStream() )
{
s.CopyTo(ms);

return Bson.Bson.Load(ms.ToArray());
}
}

/// <summary>
/// Reads a BSON <see cref="BObject"/> resource from an assembly.
/// </summary>
public static BObject ReadBObjectResource(System.Reflection.Assembly assembly, string resourceName)
{
using( var s = assembly.GetManifestResourceStream(resourceName) )
using( var ms = new MemoryStream() )
{
s.CopyTo(ms);

return Bson.Bson.Load(ms.ToArray());
}
}
}
}
16 changes: 13 additions & 3 deletions Source/Bogus/Faker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Bogus
/// <summary>
/// A hub of all the categories merged into a single class to ease fluent syntax API.
/// </summary>
public class Faker : ILocaleAware
public class Faker : ILocaleAware, IHasRandomizer, IHasContext
{
/// <summary>
/// The default mode to use when generating objects. Strict mode ensures that all properties have rules.
Expand All @@ -22,7 +22,7 @@ public class Faker : ILocaleAware
public Faker(string locale = "en")
{
Locale = locale;

this.Address = this.Notifier.Flow(new Address(locale));
this.Company = this.Notifier.Flow(new Company(locale));
this.Date = this.Notifier.Flow(new Date {Locale = locale});
Expand All @@ -42,7 +42,17 @@ public Faker(string locale = "en")
this.Hashids = new Hashids();
}

protected SeedNotifier<DataSet> Notifier = new SeedNotifier<DataSet>();
Dictionary<string, object> IHasContext.Context { get; } = new Dictionary<string, object>();

/// <summary>
/// See <see cref="SeedNotifier"/>
/// </summary>
protected SeedNotifier Notifier = new SeedNotifier();

SeedNotifier IHasRandomizer.GetNotifier()
{
return this.Notifier;
}

private Randomizer randomizer;

Expand Down
10 changes: 10 additions & 0 deletions Source/Bogus/ILocaleAware.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Collections.Generic;

namespace Bogus
{
/// <summary>
Expand All @@ -10,4 +12,12 @@ public interface ILocaleAware
/// </summary>
string Locale { get; set; }
}

/// <summary>
/// Marker interface for objects that have a context storage property.
/// </summary>
public interface IHasContext
{
Dictionary<string, object> Context { get; }
}
}
11 changes: 9 additions & 2 deletions Source/Bogus/Person.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ namespace Bogus
/// <summary>
/// Uses Faker to generate a person with contextually relevant fields.
/// </summary>
public class Person : IHasRandomizer
public class Person : IHasRandomizer, IHasContext
{
//context variable to store state from Bogus.Extensions so, they
//keep returning the result on each person.
internal Dictionary<string, object> context = new Dictionary<string, object>();

Dictionary<string, object> IHasContext.Context => this.context;

public class CardAddress
{
public class CardGeo
Expand Down Expand Up @@ -104,7 +106,7 @@ protected internal virtual void Populate()
};
}

protected SeedNotifier<DataSet> Notifier = new SeedNotifier<DataSet>();
protected SeedNotifier Notifier = new SeedNotifier();

private Randomizer randomizer;

Expand All @@ -118,6 +120,11 @@ public Randomizer Random
}
}

SeedNotifier IHasRandomizer.GetNotifier()
{
return this.Notifier;
}

public Name.Gender Gender;
public string FirstName;
public string LastName;
Expand Down
2 changes: 1 addition & 1 deletion Source/Bogus/Platform/ExtensionsForType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Bogus.Platform
{
internal static class ExtensionsForType
public static class ExtensionsForType
{
public static T GetCustomAttributeX<T>(this Type type) where T : Attribute
{
Expand Down
32 changes: 32 additions & 0 deletions Source/Bogus/Premium/ContextHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

using System;

namespace Bogus.Premium
{
public static class ContextHelper
{
public static T GetOrSet<T>(string key, Faker f, Func<T> factory) where T : DataSet, new()
{
var context = (f as IHasContext).Context;

if( context.TryGetValue(key, out var t) )
{
return t as T;
}

var dataset = factory();
var notifier = (f as IHasRandomizer).GetNotifier();
notifier.Flow(dataset);

context[key] = dataset;
return dataset;
}

public static T GetOrSet<T>(Faker f, Func<T> factory) where T : DataSet, new()
{
var key = typeof(T).Name.ToLower();
return GetOrSet($"__{key}", f, factory);
}
}
}
8 changes: 8 additions & 0 deletions Source/Bogus/Premium/License.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Bogus.Premium
{
public class License
{
public static string LicenseTo { get; set; }
public static string LicenseKey { get; set; }
}
}
Loading

0 comments on commit 672a002

Please sign in to comment.