dotfiles/.aegisub/automation/include/a-mo/Statistics.moon

154 lines
3.9 KiB
Plaintext

local json, log
version = '0.1.3'
haveDepCtrl, DependencyControl = pcall require, 'l0.DependencyControl'
if haveDepCtrl
version = DependencyControl {
name: 'Statistics'
:version
description: 'A class for proving how cool you are.'
author: 'torque'
url: 'https://github.com/TypesettingTools/Aegisub-Motion'
moduleName: 'a-mo.Statistics'
feed: 'https://raw.githubusercontent.com/TypesettingTools/Aegisub-Motion/DepCtrl/DependencyControl.json'
{
{ 'json' }
{ 'a-mo.Log', version: '1.0.0' }
}
}
json, log = version\requireModules!
else
json = require 'json'
log = require 'a-mo.Log'
-- example = {
-- macroRunCount: {
-- Apply: 0
-- Trim: 0
-- Revert: 0
-- }
-- longestLine: 0
-- longestTrack: 0
-- largestOutput: 0
-- totalProduced: 0
-- uuid: 0
-- }
-- No way to migrate to different layouts. Seems like a pain in the ass.
-- Probably won't get implemented.
class Statistics
@version: version
new: ( @stats, fileName, filePath = aegisub.decode_path( '?user' ) ) =>
@fileName = ('%s/%s')\format filePath, fileName
@read!
merge = ( memory, disk, seenTables ) ->
unless seenTables[memory]
seenTables[memory] = true
for k, memVal in pairs memory
if ("table" == type( disk )) and (nil != disk[k])
diskVal = disk[k]
if ("table" == type( diskVal )) and ("table" == type( memVal ))
merge memVal, diskVal, seenTables
else
memory[k] = diskVal
read: =>
if fileHandle = io.open @fileName, 'r'
success, serializedStats = pcall json.decode, fileHandle\read '*a'
fileHandle\close!
unless success
log.warn "Couldn't parse stats from #{@filename} as valid json. This file will be overwritten."
@write!
return
if serializedStats
merge @stats, serializedStats, {}
else
@write!
write: =>
if fileHandle = io.open @fileName, 'w'
serializedStats = json.encode @stats
if serializedStats
fileHandle\write serializedStats
else
log.debug "Couldn't serialize stats."
fileHandle\close!
else
log.debug "Can't write statsfile: #{@fileName}"
fullFieldNamePriv = false
fieldBaseNamePriv = false
fieldNamePriv = false
fieldPriv = false
pushFieldPriv = ( fieldName ) =>
-- primary cache: nothing needs to change.
if fullFieldNamePriv == fieldName
return
-- secondary cache: fieldPriv doesn't need to change, nor does
-- fieldBaseNamePriv, but fullFieldNamePriv and fieldNamePriv do.
tempFieldName = fieldName\gsub ".+%.", ""
if fieldBaseNamePriv == fieldName\sub 0, -(#tempFieldName + 2)
fullFieldNamePriv = fieldName
fieldNamePriv = tempFieldName
return
-- Have to do everything from scratch.
fieldPriv = @stats
done = false
fieldNamePriv = fieldName\gsub "([^%.]+)%.", ( subName ) ->
if done
return nil
if "table" != type fieldPriv[subName]
done = true
return nil
fieldPriv = fieldPriv[subName]
return ""
-- Bad things will occur if fieldNamePriv has a '.' in it.
fullFieldNamePriv = fieldName
fieldBaseNamePriv = fieldName\sub 0, -(#fieldNamePriv + 2)
-- Accept syntax like 'macroRunCount.Apply' for fieldName.
-- `valueCb` is a function with the signature ( currentValue )
setValuePriv = ( fieldName, valueCb ) =>
pushFieldPriv @, fieldName
fieldPriv[fieldNamePriv] = valueCb fieldPriv[fieldNamePriv]
incrementValue: ( fieldName, amount = 1 ) =>
setValuePriv @, fieldName, ( value ) ->
value + amount
-- Convenience.
decrementValue: ( fieldName, amount = 1 ) =>
setValuePriv @, fieldName, ( value ) ->
value - amount
setValue: ( fieldName, newValue ) =>
setValuePriv @, fieldName, ( value ) ->
newValue
setMax: ( fieldName, amount ) =>
setValuePriv @, fieldName, ( value ) ->
math.max value, amount
setMin: ( fieldName, amount ) =>
setValuePriv @, fieldName, ( value ) ->
math.min value, amount
getValue: ( fieldName ) =>
pushFieldPriv @, fieldName
return fieldPriv[fieldNamePriv]
if haveDepCtrl
return version\register Statistics
else
return Statistics