--------------------------------------------------------------------------------
-- Title: WikiDiffService.lua
-- Description: Like a square peg in a round hole
-- Author: Raphaël Szwarc http://alt.textdrive.com/lua/
-- Creation Date: January 30, 2007
-- Legal: Copyright (C) 2007 Raphaël Szwarc
-- Under the terms of the MIT License
-- http://www.opensource.org/licenses/mit-license.html
--------------------------------------------------------------------------------
-- import dependencies
local HTTP = require( 'HTTP' )
local Template = require( 'Template' )
local WikiContent = require( 'WikiContent' )
local WikiService = require( 'WikiService' )
local BaseLink = WikiService.BaseLink
local DateLink = WikiService.DateLink
local FeedLink = WikiService.FeedLink
local IndexLink = WikiService.IndexLink
local Encode = WikiService.Encode
local Path = WikiService.Path
local os = require( 'os' )
local getfenv = getfenv
local getmetatable = getmetatable
local require = require
local setfenv = setfenv
local setmetatable = setmetatable
local tostring = tostring
--------------------------------------------------------------------------------
-- WikiDiffService
--------------------------------------------------------------------------------
module( 'WikiDiffService' )
_VERSION = '1.0'
local self = setmetatable( _M, {} )
local meta = getmetatable( self )
--------------------------------------------------------------------------------
-- Utilities
--------------------------------------------------------------------------------
local function Title( self, isLong )
local aTitle = ''
if isLong then
aTitle = self.content.data.title
aTitle = aTitle .. ' — '
end
aTitle = aTitle .. '№ '
aTitle = aTitle .. self.content.version
aTitle = aTitle .. ' Δ № '
aTitle = aTitle .. self.version
return aTitle
end
local function TitleHandler()
local anEnvironment = {}
local aFunction = function( aType, aValue )
if aType == '+' then
local anInsert = anEnvironment.insert or 0
anEnvironment.insert = anInsert + 1
return ( ' %s ' ):format( aValue )
elseif aType == '-' then
local aDelete = anEnvironment.delete or 0
anEnvironment.delete = aDelete + 1
return ( ' %s ' ):format( aValue )
end
return ( ' %s ' ):format( aValue )
end
setfenv( aFunction, anEnvironment )
return aFunction
end
local function TextHandler()
local anEnvironment = {}
local aFunction = function( aType, aValue )
if aType == '+' then
local anInsert = anEnvironment.insert or 0
anEnvironment.insert = anInsert + 1
return ( '
%s
' ):format( aValue ) elseif aType == '-' then local aDelete = anEnvironment.delete or 0 anEnvironment.delete = aDelete + 1 return ( '%s
%s
' ):format( aValue ) end setfenv( aFunction, anEnvironment ) return aFunction end local function Delta( aText, anotherText, aHandler, aPattern ) local Diff = require( 'Diff' ) local anEnvironment = getfenv( aHandler ) local aDiff, hasMore = Diff( aText, anotherText, aHandler, aPattern ) return aDiff, anEnvironment.insert or 0, anEnvironment.delete or 0, hasMore end local function Description( anInsert, aDelete, hasMore, aVersion, aNewVersion ) local aCount = anInsert + aDelete local aBetween = ( 'between № %d and № %d' ):format( aVersion, aNewVersion ) if aCount > 0 then local aDescription = '' if hasMore then aDescription = aDescription .. 'Partial comparison. Around ' end if aCount == 1 then aDescription = aDescription .. '1 difference ' .. aBetween .. ' — ' elseif aCount > 1 then aDescription = aDescription .. aCount .. ' differences ' .. aBetween .. ' — ' end if aDelete == 0 then aDescription = aDescription .. 'no delete and ' elseif aDelete == 1 then aDescription = aDescription .. '1 delete and ' elseif aDelete > 1 then aDescription = aDescription .. aDelete .. ' deletes and ' end if anInsert == 0 then aDescription = aDescription .. 'no insert' elseif anInsert == 1 then aDescription = aDescription .. '1 insert' elseif anInsert > 1 then aDescription = aDescription .. anInsert .. ' inserts' end return aDescription end return 'No visible differences ' .. aBetween end -------------------------------------------------------------------------------- -- Service methods -------------------------------------------------------------------------------- function self:get() local aVersion = self.version if aVersion then local aContent = self.content local aNewContent = WikiContent( aContent.name, aVersion ) if aNewContent.exists then local aLayoutTemplate = Template[ 'WikiLayout.txt' ] local aTemplate = Template[ 'WikiDiffService.txt' ] local aDate = os.date( '!*t', aContent.creation ) local aDateLink = DateLink( aDate.year, aDate.month, aDate.day ) local aTitle = Encode( aContent.data.title ) local aNewTitle = Encode( aNewContent.data.title ) local aTitleDelta, aTitleInsert, aTitleDelete = Delta( aTitle, aNewTitle, TitleHandler(), '([%S]+)' ) local aText = Encode( self.content.text ) local aNewText = Encode( aNewContent.text ) local aTextDelta, aTextInsert, aTextDelete, hasMore = Delta( aText, aNewText, TextHandler() ) local anInsert = aTitleInsert + aTextInsert local aDelete = aTitleDelete + aTextDelete local aDescription = Description( anInsert, aDelete, hasMore, aContent.version, aNewContent.version ) aTemplate[ 'title' ] = aTitleDelta or Encode( aContent.data.title ) aTemplate[ 'description' ] = Encode( aDescription ) aTemplate[ 'content' ] = aTextDelta or Encode( aContent.text ):gsub( '(%c%c)', '