Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inRequestScope decorator inversify/InversifyJS/issues/678 #151

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/interfaces/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace interfaces {

export interface ProvideInSyntax<T> extends ProvideDoneSyntax {
inSingletonScope(): ProvideWhenOnSyntax<T>;
inRequestScope(): ProvideWhenOnSyntax<T>;
inTransientScope(): ProvideWhenOnSyntax<T>;
}

Expand Down
22 changes: 13 additions & 9 deletions src/syntax/provide_in_syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,29 @@ class ProvideInSyntax<T> implements interfaces.ProvideInSyntax<T> {
public inSingletonScope(): interfaces.ProvideWhenOnSyntax<T> {
let bindingWhenOnSyntax = (bind: inversifyInterfaces.Bind, target: any) =>
this._bindingInSyntax(bind, target).inSingletonScope();
let inDoneSyntax = new ProvideDoneSyntax(bindingWhenOnSyntax);
let provideWhenSyntax = new ProvideWhenSyntax<T>(bindingWhenOnSyntax, inDoneSyntax);
let provideOnSyntax = new ProvideOnSyntax<T>(bindingWhenOnSyntax, inDoneSyntax);
return new ProvideWhenOnSyntax(provideWhenSyntax, provideOnSyntax);
return this.provideWhenOnSyntax(bindingWhenOnSyntax);
}

public inRequestScope(): interfaces.ProvideWhenOnSyntax<T> {
let bindingWhenOnSyntax = (bind: inversifyInterfaces.Bind, target: any) => this._bindingInSyntax(bind, target).inRequestScope();
return this.provideWhenOnSyntax(bindingWhenOnSyntax);
}

public inTransientScope(): interfaces.ProvideWhenOnSyntax<T> {
let bindingWhenOnSyntax = (bind: inversifyInterfaces.Bind, target: any) => this._bindingInSyntax(bind, target).inTransientScope();
let inDoneSyntax = new ProvideDoneSyntax(bindingWhenOnSyntax);

let provideWhenSyntax = new ProvideWhenSyntax<T>(bindingWhenOnSyntax, inDoneSyntax);
let provideOnSyntax = new ProvideOnSyntax<T>(bindingWhenOnSyntax, inDoneSyntax);
return new ProvideWhenOnSyntax(provideWhenSyntax, provideOnSyntax);
return this.provideWhenOnSyntax(bindingWhenOnSyntax);
}

public done(force?: boolean) {
return this._provideDoneSyntax.done(force);
}

private provideWhenOnSyntax(bindingWhenOnSyntax: interfaces.BindConstraint) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pulled this out to reduce duplicate code

let inDoneSyntax = new ProvideDoneSyntax(bindingWhenOnSyntax);
let provideWhenSyntax = new ProvideWhenSyntax<T>(bindingWhenOnSyntax, inDoneSyntax);
let provideOnSyntax = new ProvideOnSyntax<T>(bindingWhenOnSyntax, inDoneSyntax);
return new ProvideWhenOnSyntax(provideWhenSyntax, provideOnSyntax);
}
}

export default ProvideInSyntax;
4 changes: 4 additions & 0 deletions src/syntax/provide_in_when_on_syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ class ProvideInWhenOnSyntax<T> implements interfaces.ProvideInWhenOnSyntax<T> {
return this._provideInSyntax.inSingletonScope();
}

public inRequestScope(): interfaces.ProvideWhenOnSyntax<T> {
return this._provideInSyntax.inRequestScope();
}

public inTransientScope(): interfaces.ProvideWhenOnSyntax<T> {
return this._provideInSyntax.inTransientScope();
}
Expand Down
6 changes: 5 additions & 1 deletion test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ describe("inversify-binding-decorators", () => {
return fluentProvide(identifier).inSingletonScope().done();
};

let provideRequest = function (identifier: string) {
return fluentProvide(identifier).inRequestScope().done();
};

let provideTransient = function (identifier: string) {
return fluentProvide(identifier).inTransientScope().done();
};
Expand Down Expand Up @@ -244,7 +248,7 @@ describe("inversify-binding-decorators", () => {
}
}

@provideTransient(TYPE.ThrowableWeapon)
@provideRequest(TYPE.ThrowableWeapon)
class Shuriken implements ThrowableWeapon {
private _mark: any;
public constructor() {
Expand Down
69 changes: 24 additions & 45 deletions test/syntax/provide_in_syntax.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,50 +19,29 @@ describe("ProvideInSyntax", () => {
sandbox.restore();
});

it("Should be able to declare a binding with singleton scope", () => {

class Ninja { }
let inSingletonScopeExpectation = sinon.expectation.create("inSingletonScope");
let mockBindingInSyntax = { inSingletonScope: inSingletonScopeExpectation } as any as inversifyInterfaces.BindingInSyntax<any>;
let mockBind = sinon.expectation.create("bind");
let bindingInSyntaxFunction =
(bind: inversifyInterfaces.Bind, target: any) => {
bind<Ninja>("Ninja");
return mockBindingInSyntax;
};
let binding: inversifyInterfaces.Binding<any> = (<any>bindingInSyntaxFunction)._binding;
let provideDoneSyntax = new ProvideDoneSyntax(binding as any);

let provideInSyntax = new ProvideInSyntax(bindingInSyntaxFunction, provideDoneSyntax);

provideInSyntax.inSingletonScope().done()(Ninja);
let metadata = Reflect.getMetadata(METADATA_KEY.provide, Reflect)[0];
metadata.constraint(mockBind);
expect(inSingletonScopeExpectation.calledOnce).to.eql(true, "inSingletonScope was not called exactly once");
expect(mockBind.calledWith("Ninja")).to.be.eql(true, "mock bind was not called");

});
it("Should be able to declare a binding with transient scope", () => {

class Ninja { }
let inTransientScopeExpectation = sinon.expectation.create("inTransientScope");
let mockBindingInSyntax = { inTransientScope: inTransientScopeExpectation } as any as inversifyInterfaces.BindingInSyntax<any>;
let mockBind = sinon.expectation.create("bind");
let bindingInSyntaxFunction =
(bind: inversifyInterfaces.Bind, target: any) => {
bind<Ninja>("Ninja");
return mockBindingInSyntax;
};
let binding: inversifyInterfaces.Binding<any> = (<any>bindingInSyntaxFunction)._binding;
let provideDoneSyntax = new ProvideDoneSyntax(binding as any);

let provideInSyntax = new ProvideInSyntax(bindingInSyntaxFunction, provideDoneSyntax);

provideInSyntax.inTransientScope().done()(Ninja);
let metadata = Reflect.getMetadata(METADATA_KEY.provide, Reflect)[0];
metadata.constraint(mockBind);
expect(inTransientScopeExpectation.calledOnce).to.eql(true, "inTransientScope was not called exactly once");
expect(mockBind.calledWith("Ninja")).to.be.eql(true, "mock bind was not called");

["inSingletonScope", "inRequestScope", "inTransientScope"].forEach(scope => {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I combined the shared aspects of the code into one repeated test (the equivalent of a data provider).

The weirdest part was calling provideInSyntax.in[...]Scope(). I haven't called a string as a function in typescript so I ended up defining it as an object with string keys to get around the no-implicit-any compiler issue. I'm open to other approaches.

it(`Should be able to declare a binding with ${scope} scope`, () => {

class Ninja { }
let inScopeExpectation = sinon.expectation.create(scope);
let mockBindingInSyntax = { [scope]: inScopeExpectation } as any as inversifyInterfaces.BindingInSyntax<any>;
let mockBind = sinon.expectation.create("bind");
let bindingInSyntaxFunction =
(bind: inversifyInterfaces.Bind, target: any) => {
bind<Ninja>("Ninja");
return mockBindingInSyntax;
};
let binding: inversifyInterfaces.Binding<any> = (<any>bindingInSyntaxFunction)._binding;
let provideDoneSyntax = new ProvideDoneSyntax(binding as any);

let provideInSyntax: {[scope: string]: any} = new ProvideInSyntax(bindingInSyntaxFunction, provideDoneSyntax);

provideInSyntax[scope]().done()(Ninja);
let metadata = Reflect.getMetadata(METADATA_KEY.provide, Reflect)[0];
metadata.constraint(mockBind);
expect(inScopeExpectation.calledOnce).to.eql(true, `${scope} was not called exactly once`);
expect(mockBind.calledWith("Ninja")).to.be.eql(true, "mock bind was not called");

});
});
});