The ranking endpoints return a value for every day. This is rare, but it looks like sometimes this can be `null` (for example if you call http://bestgems.org/api/v1/gems/rack/daily_ranking.json the rank was `null` on `2013-07-02` ) and if the rank has _ever_ been `null` for a package in the past, the schema will fail validating the response. This modifies the schema to allow a `null` value and adds a case to handle if the rank is `null` today. closes #2647
110 lines
2.4 KiB
JavaScript
110 lines
2.4 KiB
JavaScript
'use strict'
|
|
|
|
const Joi = require('joi')
|
|
|
|
const BaseJsonService = require('../base-json')
|
|
const { floorCount: floorCountColor } = require('../../lib/color-formatters')
|
|
const { ordinalNumber } = require('../../lib/text-formatters')
|
|
const { InvalidResponse } = require('../errors')
|
|
|
|
const keywords = ['ruby']
|
|
|
|
const totalSchema = Joi.array()
|
|
.items(
|
|
Joi.object({
|
|
total_ranking: Joi.number()
|
|
.integer()
|
|
.min(0)
|
|
.allow(null),
|
|
})
|
|
)
|
|
.min(1)
|
|
.required()
|
|
const dailySchema = Joi.array()
|
|
.items(
|
|
Joi.object({
|
|
daily_ranking: Joi.number()
|
|
.integer()
|
|
.min(0)
|
|
.allow(null),
|
|
})
|
|
)
|
|
.min(1)
|
|
.required()
|
|
|
|
module.exports = class GemRank extends BaseJsonService {
|
|
async fetch({ period, gem }) {
|
|
let endpoint, schema
|
|
if (period === 'rt') {
|
|
endpoint = 'total_ranking.json'
|
|
schema = totalSchema
|
|
} else {
|
|
endpoint = 'daily_ranking.json'
|
|
schema = dailySchema
|
|
}
|
|
|
|
return this._requestJson({
|
|
url: `http://bestgems.org/api/v1/gems/${gem}/${endpoint}`,
|
|
schema,
|
|
})
|
|
}
|
|
|
|
static render({ period, rank }) {
|
|
const count = Math.floor(100000 / rank)
|
|
let message = ordinalNumber(rank)
|
|
message += period === 'rt' ? '' : ' daily'
|
|
return {
|
|
message,
|
|
color: floorCountColor(count, 10, 50, 100),
|
|
}
|
|
}
|
|
|
|
async handle({ period, gem }) {
|
|
const json = await this.fetch({ period, gem })
|
|
const rank = period === 'rt' ? json[0].total_ranking : json[0].daily_ranking
|
|
if (rank == null) {
|
|
throw new InvalidResponse({ prettyMessage: 'invalid rank' })
|
|
}
|
|
return this.constructor.render({ period, rank })
|
|
}
|
|
|
|
// Metadata
|
|
static get defaultBadgeData() {
|
|
return { label: 'rank' }
|
|
}
|
|
|
|
static get category() {
|
|
return 'downloads'
|
|
}
|
|
|
|
static get route() {
|
|
return {
|
|
base: 'gem',
|
|
pattern: ':period(rt|rd)/:gem',
|
|
}
|
|
}
|
|
|
|
static get examples() {
|
|
return [
|
|
{
|
|
title: 'Gem download rank',
|
|
pattern: 'rt/:gem',
|
|
namedParams: {
|
|
gem: 'puppet',
|
|
},
|
|
staticPreview: this.render({ period: 'rt', rank: 332 }),
|
|
keywords,
|
|
},
|
|
{
|
|
title: 'Gem download rank (daily)',
|
|
pattern: 'rd/:gem',
|
|
namedParams: {
|
|
gem: 'facter',
|
|
},
|
|
staticPreview: this.render({ period: 'rd', rank: 656 }),
|
|
keywords,
|
|
},
|
|
]
|
|
}
|
|
}
|