<% var singularName = resource.name,
pluralName = plural(singularName), mixins = { task: ["AttachmentUploading", "EventSubscription"], project: ["EventSubscription"] }, skip = { attachment: ["createOnTask"] }, formatComment = function formatComment(text, indentation) { var indent = Array(indentation + 1).join(" ") return text.trim().split("\n").map(function(line) { return indent + (line.length > 0 ? "# " : "#") + line }).join("\n") }
function Action(action) {
var that = this this.action = action this.collection = action.collection == true this.requiresData = action.method == "POST" || action.method == "PUT" this.isInstanceAction = (action.method == "PUT" || action.method == "DELETE") this.method = action.method this.methodName = snake(action.name) this.clientMethod = action.method.toLowerCase() this.returnsUpdatedRecord = action.method == 'PUT' || action.comment.match(/Returns[a-z\W]+updated/) !== null this.returnsNothing = action.comment.match(/Returns an empty/) !== null // Params and idParams var params = action.params || [] this.idParams = _.filter(params, function(p) { return p.type == "Id" }) // If it looks like an instance action but it's not, make it one if (!this.isInstanceAction) { var mainIdParam = _.find(this.idParams, function(p) { return p.name == singularName }) if (mainIdParam !== undefined && !action.name.match(/Id/)) { this.isInstanceAction = true this.mainIdParam = mainIdParam } } if (this.idParams.length == 1 && action.path.match(/%d/) && (action.name.match(/Id/) || (this.isInstanceAction && this.mainIdParam == undefined))) { var mainIdParam = this.idParams[0] this.mainIdParam = mainIdParam this.inferredReturnType = this.isInstanceAction ? 'self.class' : 'self' } if (mainIdParam !== undefined) { this.params = _.reject(params, function(p) { return p.name == mainIdParam.name }) } else { this.params = params } if (!this.inferredReturnType) { // Infer return type var name = action.path.match(/\/([a-zA-Z]+)$/) if (name !== null) { name = name[1] // Desugarize 'addProject' to 'project' var camelCaseTail = name.match(/.*([A-Z][a-z]+)$/) if (camelCaseTail !== null) { name = decap(camelCaseTail[1]) } name = single(name) var explicit = _.find(resources, function(p) { return p == name }) if (name == singularName || name == 'parent' || name == 'children' || name.match(/^sub/) !== null) { this.inferredReturnType = this.isInstanceAction ? 'self.class' : 'self' } else if (explicit !== undefined) { this.inferredReturnType = cap(explicit) } else { this.inferredReturnType = 'Resource' } } else { this.inferredReturnType = 'Resource' } } // Endpoint path this.path = _.reduce(this.idParams, function(acc, id) { var localName = that.mainIdParam == id ? "id" : id.name return acc.replace("\%d", "#{" + localName + "}") }, action.path) // Extra params (not in the URL) to be passed in the body of the call this.extraParams = _.reject(this.params, function(p) { return that.path.match(new RegExp("#{" + p.name + "}")) }) // Params processing var paramsLocal = "data" if (this.collection) { this.extraParams.push({ name: "per_page", apiParamName: "limit" }) } if (this.extraParams.length > 0) { var paramNames = _.map(this.extraParams, function(p) { return (p.apiParamName || p.name) + ": " + p.name }) if (this.requiresData) { var paramsProcessing = "with_params = data.merge(" + paramNames.join(", ") + ")" paramsLocal = "with_params" } else { var paramsProcessing = "params = { " + paramNames.join(", ") + " }" paramsLocal = "params" } paramsProcessing += ".reject { |_,v| v.nil? || Array(v).empty? }" } this.paramsProcessing = paramsProcessing this.paramsLocal = paramsLocal // Method argument names var argumentNames = Array() if (!this.isInstanceAction) { argumentNames.push("client") } if (this.mainIdParam !== undefined && !this.isInstanceAction) { argumentNames.push("id") } _.forEach(this.params, function(param) { argumentNames.push(param.name + ":" + (param.required ? " required(\"" + param.name + "\")" : " nil")) }) if (this.collection) { argumentNames.push("per_page: 20") } if (this.method != 'DELETE') { argumentNames.push("options: {}") } if (this.requiresData) { argumentNames.push("**data") } this.argumentNames = argumentNames // API request params var requestParams = Array() requestParams.push('"' + this.path + '"') if (this.paramsProcessing || this.argumentNames.indexOf("**data") != -1) { var argument = this.requiresData ? "body" : "params" requestParams.push(argument + ": " + paramsLocal) } if (this.method != 'DELETE') { requestParams.push("options: options") } this.requestParams = requestParams this.documentation = this.renderDocumentation() // Constructor this.constructor = function(body) { var pre = '', post = '' var wrapWithParsing = function(body) { var pre = '', post = '' if (!that.returnsNothing) { pre = 'parse(' post = ')' + (that.collection ? '' : '.first') } return pre + body + post } if (!that.returnsNothing) { if (that.isInstanceAction && that.returnsUpdatedRecord) { pre = "refresh_with(" post = ')' } else { pre = that.collection ? "Collection.new(" : that.inferredReturnType + ".new(" post = (that.collection ? ', type: ' + that.inferredReturnType : '') + ', client: client)' } } else { post = ' && true' } return pre + wrapWithParsing(body) + post } this.request = this.constructor("client." + this.clientMethod + "(" + this.requestParams.join(", ") + ")")
}
Action.prototype.renderDocumentation = function () {
var formatParamNotes = function(params) { var trimmed = _.flatten(_.map(params, function(p) { return _.map(p.notes, function(note) { return note.trim() }) })) return (trimmed.length > 0 ? "\nNotes:\n\n" + trimmed.join("\n\n") : "") } var formatParam = function(p, name) { return (name !== undefined ? name : p.name) + " - [" + p.type + "] " + p.comment } var lines = _.map(this.params, function(p) { return formatParam(p) }) if (this.mainIdParam !== undefined && !this.isInstanceAction) { lines.unshift(formatParam(this.mainIdParam, "id")) } if (this.collection) { lines.push("per_page - [Integer] the number of records to fetch per page.") } if (this.method != 'DELETE') { lines.push("options - [Hash] the request I/O options.") } if (this.requiresData) { lines.push("data - [Hash] the attributes to post.") } return this.action.comment + "\n" + lines.join("\n") + formatParamNotes(this.params)
}
var actionsToSkip = skip || [] var actionsToGen = _.reject(resource.actions, function(action) {
return actionsToSkip.indexOf(action.name) != -1
})
var allActions = _.map(actionsToGen, function(action) { return new Action(action) }),
instanceActions = _.filter(allActions, function(action) { return action.isInstanceAction }), classActions = _.reject(allActions, function(action) { return action.isInstanceAction })
var mixinsToInclude = mixins || []
%>### WARNING: This file is auto-generated by the asana-api-meta repo. Do not ### edit it manually.
module Asana
module Resources
<%= formatComment(resource.comment, 4) %>
class <%= cap(singularName) %> < Resource
<% _.forEach(mixinsToInclude, function(mixin) { %>
include <%= mixin %>
<% }) %> <% _.forEach(resource.properties, function(property) { %>
attr_reader :<%= property.name %>
<% }) %>
class << self # Returns the plural name of the resource. def plural_name '<%= pluralName %>' end
<% _.forEach(classActions, function(action) { %> <%= formatComment(action.documentation, 8) %>
def <%= action.methodName %>(<%= action.argumentNames.join(", ") %>)
<% if (action.paramsProcessing) { %> <%= action.paramsProcessing %><% } %>
<%= action.request %> end
<% }) %> end <% _.forEach(instanceActions, function(action) { %> <%= formatComment(action.documentation, 6) %>
def <%= action.methodName %>(<%= action.argumentNames.join(", ") %>)
<% if (action.paramsProcessing) { %> <%= action.paramsProcessing %><% } %>
<%= action.request %> end
<% }) %>
end end
end