The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Mock::Data - Extensible toolkit for generating mock data

SYNOPSIS

  my $mock= Mock::Data->new(
    generators => {
      # Select random element of an array
      business_suffix => [qw( Inc. llc. gmbh. )],
      industry        => [qw( Construction Towing Landscaping )],
      
      # Weighted random selection
      surname => {
        Smith => 24, Johnson => 19, Williams => 16, Brown => 14, Jones => 14,
        Nelson => .4, Baker => .4, Hall => .4, Rivera => .4,
      },
      
      # All strings can be templates
      business_name => [
        '{surname} {industry} {business_suffix}',
        '{surname} and {surname} {business_suffix}',
      ],
      
      # Generate strings that match a regex
      email => qr/(\w+)@(\w+)(\.com|\.org|\.net|\.co\.uk)/,
      
      # Or just code your own generators
      real_address => sub($mock) { $db->resultset("Address")->rand->single },
      address_json => sub($mock) { encode_json($mock->real_address) },
    },
    
    # load plugins
    plugins => ['Text'],  # Mock::Data::Plugin::Text
  );

  # Put all your generators into a plugin for easy access
  my $mock= Mock::Data->new(['MyCollection']);
  
  # Call generators
  say $mock->call('email');
  say $mock->email;              # uses AUTOLOAD
  say $mock->wrap('email')->();  # coderef for repeated calling
  
  # Pass parameters to generators
  say $mock->words({ count => 50 });
  say $mock->words(50);
  say $mock->call(words => 50);

DESCRIPTION

This module is a generator of mock data. It takes good ideas seen in Data::Faker, Mock::Populate, and other similar modules, and combines them into a cohesive extensible design.

Each mock data generator is called as a method on an instance of Mock::Data. This allows generators to store persistent state between calls. It also allows them to be configured with per-instance settings.

CONSTRUCTOR

new

  $mock= Mock::Data->new(\@package_list);
  $mock= Mock::Data->new({
    generators => \%generator_set,
    plugins    => \@package_list,
  });

Construct a new instance of Mock::Data. If called as a method of an object, this will clone the existing instance, applying generators on top of the set already present.

Arguments:

plugins => \@package_list

This lets you specify a list of packages whose generators should be pulled into the new object. The plugins may also change the class of the object returned.

generators => \%set

This specifies a set of generators that should be added after any generators that get added by plugins (or any that were carried over from the old instance if new is being called on an instance instead of on the class).

clone

  $mock2= $mock->clone;

Calling clone on a Mock::Data instance returns a new Mock::Data of the same class with the same plugins and a deep-clone of the "generator_state" and a shallow clone of the "generators" set. This may not have the desied effect if one of your generators is storing state outside of the "generator_state" hashref.

clone does not take any arguments. If you wish to modify the object at the same time as cloning a previous one, call "new" on the previous object instance.

ATTRIBUTES

This module defines a minimal number of attributes, to leave most of the method namespace available for the generators themselves. All subclasses and custom generators should attempt to use the existing attributes instead of defining new ones.

generators

  my $generator= $mock->generators->{$name};
  $mock->generators( $new_hashref );  # clears cache, coerces values

This is a hashref of Mock::Data::Generator objects. Do not modify the contents of this attribute directly, as compiled versions of each generator are cached, but you may assign a new hashref to it.

When assigning, the values of the supplied hash will each get coerced into a generator via "coerce_generator" in Mock::Data::Util.

generator_state

  sub my_generator($mock, @params) {
    $mock->generator_state->{__PACKAGE__.'.something'}= $my_state;
  }

This is a hashref where generators store state data. If the instance of Mock::Data is cloned, this hashref will be deep-cloned. Other hashref fields of the Mock::Data object are not deep-cloned, aside from the generators field which is cloned one level deep.

Keys in this hash should be prefixed with either the name of the generator or name of the package the generator was implemented from.

METHODS

Note: All generators may be called as methods, thanks to AUTOLOAD.

load_plugin

  $mock= $mock->load_plugin($name);

This method loads the plugin Mock::Data::Plugin::${name} if it was not loaded already, and performs whatever initialization that package wants to perform, which may return a completely different instance of Mock::Data. Always use the return value and assume the initial reference is gone. If you want a clone, call $mock->new first to clone it.

add_generators

  $mock->add_generators( $name => $spec, ... )

Set one or more named generators. Arguments can be given as a hashref or a list of key/value pairs. $spec can be a coderef, an arrayref (of options) or an instance of Mock::Data::Generator. If a previous generator existed by the same name, it will be replaced.

If the $name of the generator is a package-qualified name, the generator is added under both the long and short name. For example, combine_generators( 'MyPlugin::gen' => \&gen ) will register \&gen as both 'MyPlugin::gen' and an alias of 'gen'. However, 'gen' will only be added if it didn't already exist. This allows plugins to refer to eachother's names without collisions.

Returns $mock, for chaining.

Use this method instead of directly modifying the generators hashref so that this module can perform proper cache management.

combine_generators

  $mock->combine_generators( $name => $spec, ... )

Same as "add_generators", but if a generator of that name already exists, replace it with a generator that returns both possible sets of results. If the old generator was a coderef, it will be replaced with a new generator that calls the old coderef 50% of the time. If the old generator and new generator are both Sets, the merged generator will be a concatenation of the sets.

Returns $mock, for chaining.

Use this method instead of directly modifying the generators hashref so that this module can perform proper cache management.

call

  $mock->call($name, \%named_params, @positional_params);

This is a more direct way to invoke a generator. The more convenient way of calling the generator name as a method of the object uses AUTOLOAD to call this method. The return value is whatever the generator returns.

wrap

  my $sub= $mock->wrap($name, \%named_params, @positional_params);
  say $sub->();

This creates an anonymous sub that wraps the complete call to the generator, including the instance of $mock and any parameters you supply. This is intended for efficiency if you plan to make lots of calls to the generator.

EXPORTS

Mock::Data can export symbols from Mock::Data::Util. See that module for a complete reference for each function.

uniform_set(@items)
weighted_set($item => $weight, ...)
charset($regex_set_notation)
template($string)
inflate_template($string)
coerce_generator($specification)
mock_data_subclass($class_or_object, @class_list)

SEE ALSO

AUTHOR

Michael Conrad <mike@nrdvana.net>

VERSION

version 0.03

COPYRIGHT AND LICENSE

This software is copyright (c) 2021 by Michael Conrad.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.