Context::Singleton

Context::Singleton

Motivation

Basic features

frame

frame {
	proclaim 'foo' => 1; # success
	frame {
		proclaim 'foo' => 2; # success
		proclaim 'foo' => 3; # failure
	};
};

proclaim

proclaim name => $value;

deduce

frame { # depth 1
	proclaim 'foo' => 1;
	deduce 'foo'; # returns 1

	frame { # depth 2
		deduce 'foo+1'; # builds in depth 1 and returns 2
		proclaim 'foo' => 3; # fails
	};

	deduce 'foo+1'; # returns stored 2
};

contrive

Example: existing code

my $source_of_truth = Single::Source::Of::Truth->new (
	user_id => $user_id,
);
my $project_context = Project::Context->new (
	project_id => $project_id,
	user_id => $user_id,
	...
);
my $object_context => Object::Context->new(
	project_context => $project_context,
	object_id => $object_id,
	...
);

some_function (
	$request,
	$user_id,
	$source_of_truth,
	$project_context,
	$object_context,
);

Example: with Context::Singleton

proclaim request => $request;
proclaim user_id => $user_id,
proclaim project_id => $project_id;
proclaim object_id => $object_id;

some_function();
sub some_function {
	my $project_id = deduce 'project::id';
	...
}

Example: Net::GitHub::V3

contrive 'net::github' => (
	class => 'Net::GitHub::V3',
	dep => {
		login => 'github::login',
		password => 'github::password',
	},
);
contrive 'net::github::repository' => (
	dep => [ 'net::github', 'github::user', 'github::repository' ],
	as => sub {
		my ($connection, $user, $repository) = @_;

		my $repos = $connection->repos;
		$repos->set_default_user_repo( $user, $repository );
		$repos
	},
}
sub { ... ; my $gh = deduce 'net::github::repository'; ... }

Example: Net::GitHub::V3 (cont)

contrive 'net::github' => (
	class => 'Net::GitHub::V3',
	dep => { access_token => 'github::oauth_token' },
);
contrive 'github::user' => (
	dep => [ 'zuul::project' ], # user/repo
	as => { (split '/', $_[0])[0] }
);
contrive 'github::repository'' => (
	dep => [ 'zuul::project' ], # user/repo
	as => { (split '/', $_[0])[1] }
);
contrive 'github::login' => ( value => 'happy-barney');

Example: Circular dependencies

contrive 'single::source::of::truth' => (
	class => 'Single::Source::Of::Truth',
);

contrive 'project::id' => (
	deduce => 'project::info'
	builder => 'id',
);

contrive 'project::info' => (
	class => 'Project::Info',
	dep => [ 'project:struct' ],
);

contrive 'project::info' => (
	deduce => 'single::source::of::truth',
	builder => 'find_project',
	dep => [ 'project::id' ],
);

contrive 'project::struct' => (
	deduce => 'project::info',
	builder => 'as_struct',
);

Example: Dependency injection

Usage:
sub do_something_with_project {
	my $project_id = deduce 'project::id';
}

# will work with any of these line
proclaim 'project::struct' => value;
proclaim 'project::id' => value;
proclaim 'project::info' => value;
Testing:
proclaim 'Single::Source::Of::Truth' => 'Fiction';
proclaim 'single::source::of::truth' => Fiction->new;

Other features

Work in progress

Thanks