Skip to content
This repository has been archived by the owner on Mar 19, 2019. It is now read-only.

Commit

Permalink
Inherit/merge parameters from prototype #646
Browse files Browse the repository at this point in the history
  • Loading branch information
kipz committed Jul 12, 2017
1 parent 64e1040 commit edba527
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 5 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Parameter and MappedParameter decorated properties from super classes are now inherited
by sub-classes [#646][646]

- Added `GITHUB_DEFAULT_REPO_VISIBILITY` mapped parameter that determines
repository visibility based on organization GitHub plan

### Fixed

- Ensure default values for optional parameters to Rug Functions
are used, instead of null. Primitives are converted to 0 or false

[646]: https://github.com/atomist/rug/issues/646

## [1.0.0-m.5] - 2017-07-11

[1.0.0-m.5]: https://github.com/atomist/rug/compare/1.0.0-m.4...1.0.0-m.5
Expand Down
51 changes: 47 additions & 4 deletions src/main/typescript/rug/operations/Decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ function set_metadata(obj: any, key: string, value: any) {
}

function get_metadata(obj: any, key: string) {
if (obj == null) {
return null;
}
let desc = Object.getOwnPropertyDescriptor(obj, key);
if ((desc == null || desc === undefined) && (obj.prototype !== undefined)) {
desc = Object.getOwnPropertyDescriptor(obj.prototype, key);
if ((desc == null || desc === undefined) && (Object.getPrototypeOf(obj) !== undefined)) {
desc = get_metadata(Object.getPrototypeOf(obj), key);
}
if (desc != null || desc !== undefined) {
if (desc != null && desc !== undefined) {
return desc.value;
}
return null;
Expand All @@ -37,14 +40,34 @@ export function Parameter(details: BaseParameter) {
}

export function declareParameter(target: any, propertyKey: string, details: BaseParameter) {
let params = get_metadata(target, "__parameters");
let params: any[] = get_metadata(target, "__parameters");
if (params == null) {
params = [];
} else {
// remove any that have the same name already (i.e. if folk are calling declareParameter)
// use a cheeky method so that we can reuse the same array
const found: any[] = params.filter((p) => p.name === propertyKey);
if (found != null && found.length > 0) {
const index = params.indexOf(found[0]);
params.splice(index, 1);
}
}
const copy: any = { ...details };
copy.name = propertyKey;
copy.decorated = true;
params.push(copy);

// merge parameters from parent if it has some
const protoParams: any[] = get_metadata(Object.getPrototypeOf(target), "__parameters");
if (protoParams != null) {
protoParams.forEach((protoParam) => {
// if we don't already have a parameter with the same name
if (!params.some((param) => param.name === protoParam.name)) {
params.push(protoParam);
}
});
}

set_metadata(target, "__parameters", params);
return target;
}
Expand All @@ -61,9 +84,29 @@ export function declareMappedParameter(target: any, localKey: string, foreignKey
let params = get_metadata(target, "__mappedParameters");
if (params == null) {
params = [];
} else {
// remove any that have the same name already (i.e. if folk are calling declareParameter)
// use a cheeky method so that we can reuse the same array
const found: any[] = params.filter((p) => p.localKey === localKey);
if (found != null && found.length > 0) {
const index = params.indexOf(found[0]);
params.splice(index, 1);
}
}
const param = { localKey, foreignKey };
params.push(param);

// merge parameters from parent if it has some
const protoParams: any[] = get_metadata(Object.getPrototypeOf(target), "__mappedParameters");
if (protoParams != null) {
protoParams.forEach((protoParam) => {
// if we don't already have a parameter with the same name
if (!params.some((p) => p.localKey === protoParam.localKey)) {
params.push(protoParam);
}
});
}

set_metadata(target, "__mappedParameters", params);
return target;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {HandleCommand, Instruction, Response, HandlerContext, CommandPlan, DirectedMessage, UserAddress} from '@atomist/rug/operations/Handlers'
import {CommandHandler, MappedParameter, declareMappedParameter, Parameter, declareParameter, Tags, Intent} from '@atomist/rug/operations/Decorators'
import {Build} from "@atomist/rug/cortex/stub/Build"

let config = {description: "desc", pattern: "@any"}

@CommandHandler("Uses same config object")
class ParentHandler implements HandleCommand{

@Parameter(config)
foo: number

@Parameter(config)
bar: number

@MappedParameter("blah-parent")
blah: string

@MappedParameter("quz-parent")
quz: string

handle(ctx: HandlerContext) {
return new CommandPlan();
}
}

export let parent = new ParentHandler();


@CommandHandler("Child with overrides")
class ChildHandler extends ParentHandler {

@Parameter({description: "child", pattern: "@any"})
foo: number

@Parameter(config)
baz: number

@MappedParameter("blah-child")
blah: string

@MappedParameter("really-child")
really: string

handle(ctx: HandlerContext) {
return new CommandPlan();
}
}
const child = new ChildHandler();
declareParameter(child, "baz", {description: "dup", pattern: "@any"})
declareMappedParameter(child, "really", "manual")

export { child };

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.atomist.rug.runtime.js

import com.atomist.project.archive.{AtomistConfig, DefaultAtomistConfig}
import com.atomist.rug.RugArchiveReader
import com.atomist.rug.TestUtils.contentOf
import com.atomist.rug.ts.TypeScriptBuilder
import com.atomist.source.{SimpleFileBasedArtifactSource, StringFileArtifact}
import org.scalatest.{FunSpec, Matchers}

class JavaScriptUtilsTest extends FunSpec with Matchers {

val atomistConfig: AtomistConfig = DefaultAtomistConfig

val parameterInherritance = StringFileArtifact(atomistConfig.handlersRoot + "/Handler.ts",
contentOf(this, "HandlerWithInherritedParameters.ts"))

it("should inherit parameters from the prototype") {
val rugArchive = TypeScriptBuilder.compileWithExtendedModel(
SimpleFileBasedArtifactSource(parameterInherritance))
val rugs = RugArchiveReader(rugArchive)
val handler = rugs.commandHandlers.head
val params = handler.parameters
assert(params.size === 3)
assert(params(1).name === "foo")
assert(params(1).description === "child")
assert(params(2).name === "bar")
assert(params.head.name === "baz")
assert(params.head.description === "dup")
}

it("should inherit mapped parameters from the prototype") {
val rugArchive = TypeScriptBuilder.compileWithExtendedModel(
SimpleFileBasedArtifactSource(parameterInherritance))
val rugs = RugArchiveReader(rugArchive)
val handler = rugs.commandHandlers.head
val params = handler.mappedParameters
assert(params.size === 3)
assert(params.head.localKey === "really")
assert(params.head.foreignKey === "manual")
assert(params(1).localKey === "blah")
assert(params(1).foreignKey === "blah-child")
assert(params(2).localKey === "quz")
assert(params(2).foreignKey === "quz-parent")
}
}

0 comments on commit edba527

Please sign in to comment.