Improved multiplatform support and adding more replacements for Latin characters.

This commit is contained in:
Offray Vladimir Luna Cárdenas 2020-12-18 09:54:09 -08:00
parent d875029940
commit 5d68e79c2b
14 changed files with 1495 additions and 1492 deletions

View File

@ -1,201 +1,201 @@
"
I provide support for external helper apps for Grafoscopio, publishing, collaboration
and data management.
"
Class {
#name : #ExternalApp,
#superclass : #Object,
#instVars : [
'name',
'url',
'downloadUrl',
'description',
'sha1',
'md5',
'binaryLocation'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #installation }
ExternalApp class >> compareHashFor: aFileName with: aSHAString [
aSHAString = (SHA1 new hashMessage: aFileName asFileReference binaryReadStream contents) hex
ifFalse: [ ^ false ]
ifTrue: [ ^ true ].
]
{ #category : #configuration }
ExternalApp class >> configureFossil [
"Stablish where is located fossil according to the operative system and/or the input of the user"
| fileStream fossil |
fileStream := UIManager default fileOpen: 'Path to the fossil program binary'.
fileStream isNil ifTrue: [ ^nil ].
fossil := fileStream name asFileReference fullName.
]
{ #category : #configuration }
ExternalApp class >> configurePandoc [
"Stablish where is located pandoc according to the operative system and/or the input of the user"
| fileStream pandoc |
fileStream := UIManager default fileOpen: 'Path to pandoc program binary'.
fileStream isNil ifTrue: [ ^nil ].
pandoc := fileStream name asFileReference fullName.
]
{ #category : #installation }
ExternalApp class >> installSQLite32Bits [
"I dowload the SQLite binary for the hosting platform, uncompress it and made it available as with the name
NBSQLite is wating for"
| packageUrl sha1 localPath packageZipName unzippedFolder |
localPath := FileSystem disk workingDirectory parent / 'bin'.
Smalltalk platform name = 'unix'
ifTrue: [
packageUrl := 'http://sqlite.org/2016/sqlite-tools-linux-x86-3110100.zip'.
sha1 := '21a80cefa91d5de50256996fc55990a027c350fd'].
Smalltalk platform name = 'Win32'
ifTrue: [
packageUrl := 'http://sqlite.org/2016/sqlite-dll-win32-x86-3110100.zip'.
sha1 := 'cfd6f64ba1fb5de1ccf8321e29764c690c25e0a0'].
Smalltalk platform name = 'Mac OS'
ifTrue: [
packageUrl := 'http://sqlite.org/2016/sqlite-tools-osx-x86-3110100.zip'.
sha1 := 'c78b3b92bd37554694d2f73dbecfef1902c15ba7'].
self isSQLite32BitsInstalled
ifTrue: [ self inform: 'SQLite ya está instalado en el sistema' ]
ifFalse: [
GrafoscopioBrowser
downloadingFrom: packageUrl
withMessage: 'Descargando SQLite...'
into: localPath asFileReference.
packageZipName := (packageUrl splitOn: '/') last.
sha1 = (SHA1 new hashMessage: (localPath / packageZipName) asFileReference binaryReadStream contents) hex
ifFalse: [ self inform: 'SQLite: Descarga no exitosa.
Por favor intente el procedimiento de nuevo o manualmente']
ifTrue: [
ZipArchive new
readFrom: (localPath / packageZipName);
extractAllTo: localPath asFileReference.
unzippedFolder := packageZipName copyReplaceAll: '.zip' with: ''.
(localPath / unzippedFolder ) children do:
[:file | file moveTo: (localPath / file basenameWithIndicator)].
(localPath / 'sqlite3') copyTo: (localPath / 'libsqlite3.so').
(localPath / unzippedFolder ) deleteAll.
self inform: 'SQLite instalado existosammente!'
].
"Cleaning leftovers"
(localPath / packageZipName) delete
]
]
{ #category : #configuration }
ExternalApp class >> installSQLite32BitsUI [
"I verify if SQLite for 32 bits is installed in the proper location. If yes, I inform that. If not,
I made the installation"
| install |
install := (UIManager default
confirm: '¿Desea instalar el motor de base de datos (SQLite)?'
label: 'Instalar base de datos?').
install ifTrue: [self installSQLite32Bits]
]
{ #category : #installation }
ExternalApp class >> isSQLite32BitsInstalled [
"I verify if the SQLite binary for the hosting platform is installed"
^ (FileSystem disk workingDirectory parent / 'bin' / 'libsqlite3.so') asFileReference exists
]
{ #category : #configuration }
ExternalApp class >> pandoc [
"I define where the pandoc external app is located"
| app |
app := ExternalApp new
name: 'pandoc';
url: 'http://pandoc.org';
description: 'Pandoc is a free and open-source software document converter, widely used as a writing tool (especially by scholars) and as a basis for publishing workflows. It was originally created by John MacFarlane, a philosophy professor at the University of California, Berkeley. (from https://en.wikipedia.org/wiki/Pandoc)'.
app binaryLocation: '/usr/bin/pandoc' asFileReference.
^ app
]
{ #category : #accessing }
ExternalApp >> binaryLocation [
^ binaryLocation
]
{ #category : #accessing }
ExternalApp >> binaryLocation: anObject [
binaryLocation := anObject
]
{ #category : #accessing }
ExternalApp >> description [
^ description
]
{ #category : #accessing }
ExternalApp >> description: anObject [
description := anObject
]
{ #category : #accessing }
ExternalApp >> downloadUrl [
^ downloadUrl
]
{ #category : #accessing }
ExternalApp >> downloadUrl: anObject [
downloadUrl := anObject
]
{ #category : #accessing }
ExternalApp >> md5 [
^ md5
]
{ #category : #accessing }
ExternalApp >> md5: anObject [
md5 := anObject
]
{ #category : #accessing }
ExternalApp >> name [
^ name
]
{ #category : #accessing }
ExternalApp >> name: anObject [
name := anObject
]
{ #category : #accessing }
ExternalApp >> sha1 [
^ sha1
]
{ #category : #accessing }
ExternalApp >> sha1: anObject [
sha1 := anObject
]
{ #category : #accessing }
ExternalApp >> url [
^ url
]
{ #category : #accessing }
ExternalApp >> url: anObject [
url := anObject
]
"
I provide support for external helper apps for Grafoscopio, publishing, collaboration
and data management.
"
Class {
#name : #ExternalApp,
#superclass : #Object,
#instVars : [
'name',
'url',
'downloadUrl',
'description',
'sha1',
'md5',
'binaryLocation'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #installation }
ExternalApp class >> compareHashFor: aFileName with: aSHAString [
aSHAString = (SHA1 new hashMessage: aFileName asFileReference binaryReadStream contents) hex
ifFalse: [ ^ false ]
ifTrue: [ ^ true ].
]
{ #category : #configuration }
ExternalApp class >> configureFossil [
"Stablish where is located fossil according to the operative system and/or the input of the user"
| fileStream fossil |
fileStream := UIManager default fileOpen: 'Path to the fossil program binary'.
fileStream isNil ifTrue: [ ^nil ].
fossil := fileStream name asFileReference fullName.
]
{ #category : #configuration }
ExternalApp class >> configurePandoc [
"Stablish where is located pandoc according to the operative system and/or the input of the user"
| fileStream pandoc |
fileStream := UIManager default fileOpen: 'Path to pandoc program binary'.
fileStream isNil ifTrue: [ ^nil ].
pandoc := fileStream name asFileReference fullName.
]
{ #category : #installation }
ExternalApp class >> installSQLite32Bits [
"I dowload the SQLite binary for the hosting platform, uncompress it and made it available as with the name
NBSQLite is wating for"
| packageUrl sha1 localPath packageZipName unzippedFolder |
localPath := FileSystem disk workingDirectory parent / 'bin'.
Smalltalk platform name = 'unix'
ifTrue: [
packageUrl := 'http://sqlite.org/2016/sqlite-tools-linux-x86-3110100.zip'.
sha1 := '21a80cefa91d5de50256996fc55990a027c350fd'].
Smalltalk platform name = 'Win32'
ifTrue: [
packageUrl := 'http://sqlite.org/2016/sqlite-dll-win32-x86-3110100.zip'.
sha1 := 'cfd6f64ba1fb5de1ccf8321e29764c690c25e0a0'].
Smalltalk platform name = 'Mac OS'
ifTrue: [
packageUrl := 'http://sqlite.org/2016/sqlite-tools-osx-x86-3110100.zip'.
sha1 := 'c78b3b92bd37554694d2f73dbecfef1902c15ba7'].
self isSQLite32BitsInstalled
ifTrue: [ self inform: 'SQLite ya está instalado en el sistema' ]
ifFalse: [
GrafoscopioBrowser
downloadingFrom: packageUrl
withMessage: 'Descargando SQLite...'
into: localPath asFileReference.
packageZipName := (packageUrl splitOn: '/') last.
sha1 = (SHA1 new hashMessage: (localPath / packageZipName) asFileReference binaryReadStream contents) hex
ifFalse: [ self inform: 'SQLite: Descarga no exitosa.
Por favor intente el procedimiento de nuevo o manualmente']
ifTrue: [
ZipArchive new
readFrom: (localPath / packageZipName);
extractAllTo: localPath asFileReference.
unzippedFolder := packageZipName copyReplaceAll: '.zip' with: ''.
(localPath / unzippedFolder ) children do:
[:file | file moveTo: (localPath / file basenameWithIndicator)].
(localPath / 'sqlite3') copyTo: (localPath / 'libsqlite3.so').
(localPath / unzippedFolder ) deleteAll.
self inform: 'SQLite instalado existosammente!'
].
"Cleaning leftovers"
(localPath / packageZipName) delete
]
]
{ #category : #configuration }
ExternalApp class >> installSQLite32BitsUI [
"I verify if SQLite for 32 bits is installed in the proper location. If yes, I inform that. If not,
I made the installation"
| install |
install := (UIManager default
confirm: '¿Desea instalar el motor de base de datos (SQLite)?'
label: 'Instalar base de datos?').
install ifTrue: [self installSQLite32Bits]
]
{ #category : #installation }
ExternalApp class >> isSQLite32BitsInstalled [
"I verify if the SQLite binary for the hosting platform is installed"
^ (FileSystem disk workingDirectory parent / 'bin' / 'libsqlite3.so') asFileReference exists
]
{ #category : #configuration }
ExternalApp class >> pandoc [
"I define where the pandoc external app is located"
| app |
app := ExternalApp new
name: 'pandoc';
url: 'http://pandoc.org';
description: 'Pandoc is a free and open-source software document converter, widely used as a writing tool (especially by scholars) and as a basis for publishing workflows. It was originally created by John MacFarlane, a philosophy professor at the University of California, Berkeley. (from https://en.wikipedia.org/wiki/Pandoc)'.
app binaryLocation: '/usr/bin/pandoc' asFileReference.
^ app
]
{ #category : #accessing }
ExternalApp >> binaryLocation [
^ binaryLocation
]
{ #category : #accessing }
ExternalApp >> binaryLocation: anObject [
binaryLocation := anObject
]
{ #category : #accessing }
ExternalApp >> description [
^ description
]
{ #category : #accessing }
ExternalApp >> description: anObject [
description := anObject
]
{ #category : #accessing }
ExternalApp >> downloadUrl [
^ downloadUrl
]
{ #category : #accessing }
ExternalApp >> downloadUrl: anObject [
downloadUrl := anObject
]
{ #category : #accessing }
ExternalApp >> md5 [
^ md5
]
{ #category : #accessing }
ExternalApp >> md5: anObject [
md5 := anObject
]
{ #category : #accessing }
ExternalApp >> name [
^ name
]
{ #category : #accessing }
ExternalApp >> name: anObject [
name := anObject
]
{ #category : #accessing }
ExternalApp >> sha1 [
^ sha1
]
{ #category : #accessing }
ExternalApp >> sha1: anObject [
sha1 := anObject
]
{ #category : #accessing }
ExternalApp >> url [
^ url
]
{ #category : #accessing }
ExternalApp >> url: anObject [
url := anObject
]

View File

@ -1,199 +1,199 @@
"
I model a documentation object for Grafoscopio.
Documents are stored in a fossil repository and have
relative paths to it.
"
Class {
#name : #GrafoscopioDocumentation,
#superclass : #Object,
#instVars : [
'repository',
'documents',
'localPlace',
'name'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #updating }
GrafoscopioDocumentation class >> documents [
^ self newDefault documents
]
{ #category : #api }
GrafoscopioDocumentation class >> download: aFileName [
self newDefault download: aFileName
]
{ #category : #updating }
GrafoscopioDocumentation class >> listOutdatedDocs [
^ self newDefault listOutdatedDocs
]
{ #category : #updating }
GrafoscopioDocumentation class >> localPlace [
^ self newDefault localPlace
]
{ #category : #'instance creation' }
GrafoscopioDocumentation class >> newDefault [
^ self new
]
{ #category : #updating }
GrafoscopioDocumentation class >> update [
^ self newDefault update
]
{ #category : #updating }
GrafoscopioDocumentation class >> updateAll [
GfUIHelpers docsCollection do: [ :docs | docs update ]
]
{ #category : #updating }
GrafoscopioDocumentation class >> updateAllUI [
"Updates documentation (manual, tutorials) from the official repository for a given documentation."
| update |
update := (UIManager default
confirm: 'Do you wish to update the documentation?'
label: 'Update documentation').
update
ifTrue: [ self updateAll ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> addDocument: aFilePath [
"I add the document contained in aFilePath (a String) to the list of documents that belong
to this collection, taking care of avoiding repetitions"
(self documents includes: aFilePath) ifFalse: [ self documents add: aFilePath ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> documents [
^ documents ifNil: [ documents := OrderedCollection new ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> documents: anObject [
documents := anObject
]
{ #category : #updating }
GrafoscopioDocumentation >> download: fileNameWithRelativePath [
| fileName parentFolder sanitized lastVersion |
fileName := (fileNameWithRelativePath splitOn: $/) last.
sanitized := self repository sanitize: fileNameWithRelativePath.
lastVersion := self repository lastVersionPath: fileNameWithRelativePath.
parentFolder := GrafoscopioUtils
ensureCreateDirectory: sanitized into: self localPlace.
GrafoscopioUtils
downloadingFrom: self repository remote asString, lastVersion
withMessage: 'Downloading ', fileName
into: parentFolder
]
{ #category : #updating }
GrafoscopioDocumentation >> isFileUpdatedFor: relativeFilePath [
"I compare if the local and remote copies of a relativeFilePath are updated for the current
documentation and return true if they are and false in any other case"
| localFile |
localFile := self localPlace / relativeFilePath.
localFile exists
ifFalse: [ ^ false ]
ifTrue: [
^ ExternalApp
compareHashFor: localFile
with: (self repository lastHashNumberFor: relativeFilePath) ]
]
{ #category : #updating }
GrafoscopioDocumentation >> listOutdatedDocs [
"I return the list of all documentent where the local copy and the remote copy doesn't match"
^ self documents reject: [ :doc | (self isFileUpdatedFor: doc) ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> localPlace [
^ localPlace.
]
{ #category : #accessing }
GrafoscopioDocumentation >> localPlace: aFileDirectory [
localPlace := aFileDirectory.
self localPlace exists ifFalse: [ self localPlace ensureCreateDirectory ].
]
{ #category : #accessing }
GrafoscopioDocumentation >> name [
^ name
]
{ #category : #accessing }
GrafoscopioDocumentation >> name: anObject [
name := anObject
]
{ #category : #accessing }
GrafoscopioDocumentation >> openNotebookAt: index [
"I open a notebook included with the documentation, located at a given index (anInteger)"
| notebookTemp |
(index between: 1 and: self documents size)
ifFalse: [ ^ self ]
ifTrue: [
notebookTemp := (self localPlace fullName, '/', (self documents at: index)) asFileReference.
notebookTemp exists
ifTrue: [GrafoscopioNotebook new openFromFile: notebookTemp]
ifFalse: [ self updateUI ]]
]
{ #category : #updating }
GrafoscopioDocumentation >> registerIntoDockingBar [
"I detect if any of the documents that are part of my collection contains any metadata
indicating if they should be registered in the main docking bar, and in such case, I add them."
self documents
do: [ :doc | | metadata currentNotebook |
currentNotebook := GrafoscopioNotebook new loadFromFile: self localPlace / doc.
metadata := currentNotebook metadata.
metadata ifNotNil: [
metadata
at: 'showOnHelp'
ifPresent: [ self error:' missing class grafoscopio docking bar' "GrafoscopioDockingBar addToHelpMenu: currentNotebook" ] ] ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> repository [
^ repository
]
{ #category : #accessing }
GrafoscopioDocumentation >> repository: aFossilRepo [
repository := aFossilRepo
]
{ #category : #updating }
GrafoscopioDocumentation >> update [
(self listOutdatedDocs)
ifEmpty: [
self inform: 'All documents in the ', self name,' collection are already updated'.
^ self ]
ifNotEmpty: [:outdatedDocs |
outdatedDocs do: [ :eachDoc | self download: eachDoc ].
self inform: 'Updating of ', self name,' documentation finished.' ]
]
{ #category : #updating }
GrafoscopioDocumentation >> updateDocsPlaceUI [
self current localPlace: (UIManager default chooseDirectory: 'Path to the documentation folder')
]
{ #category : #updating }
GrafoscopioDocumentation >> updateUI [
"Updates documentation (manual, tutorials) from the official repository for a given documentation."
| update |
update := (UIManager default
confirm: 'Do you wish to update the ', self name,' documentation?'
label: 'Update ', self name, ' documentation').
update ifTrue: [ self update ]
]
"
I model a documentation object for Grafoscopio.
Documents are stored in a fossil repository and have
relative paths to it.
"
Class {
#name : #GrafoscopioDocumentation,
#superclass : #Object,
#instVars : [
'repository',
'documents',
'localPlace',
'name'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #updating }
GrafoscopioDocumentation class >> documents [
^ self newDefault documents
]
{ #category : #api }
GrafoscopioDocumentation class >> download: aFileName [
self newDefault download: aFileName
]
{ #category : #updating }
GrafoscopioDocumentation class >> listOutdatedDocs [
^ self newDefault listOutdatedDocs
]
{ #category : #updating }
GrafoscopioDocumentation class >> localPlace [
^ self newDefault localPlace
]
{ #category : #'instance creation' }
GrafoscopioDocumentation class >> newDefault [
^ self new
]
{ #category : #updating }
GrafoscopioDocumentation class >> update [
^ self newDefault update
]
{ #category : #updating }
GrafoscopioDocumentation class >> updateAll [
GfUIHelpers docsCollection do: [ :docs | docs update ]
]
{ #category : #updating }
GrafoscopioDocumentation class >> updateAllUI [
"Updates documentation (manual, tutorials) from the official repository for a given documentation."
| update |
update := (UIManager default
confirm: 'Do you wish to update the documentation?'
label: 'Update documentation').
update
ifTrue: [ self updateAll ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> addDocument: aFilePath [
"I add the document contained in aFilePath (a String) to the list of documents that belong
to this collection, taking care of avoiding repetitions"
(self documents includes: aFilePath) ifFalse: [ self documents add: aFilePath ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> documents [
^ documents ifNil: [ documents := OrderedCollection new ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> documents: anObject [
documents := anObject
]
{ #category : #updating }
GrafoscopioDocumentation >> download: fileNameWithRelativePath [
| fileName parentFolder sanitized lastVersion |
fileName := (fileNameWithRelativePath splitOn: $/) last.
sanitized := self repository sanitize: fileNameWithRelativePath.
lastVersion := self repository lastVersionPath: fileNameWithRelativePath.
parentFolder := GrafoscopioUtils
ensureCreateDirectory: sanitized into: self localPlace.
GrafoscopioUtils
downloadingFrom: self repository remote asString, lastVersion
withMessage: 'Downloading ', fileName
into: parentFolder
]
{ #category : #updating }
GrafoscopioDocumentation >> isFileUpdatedFor: relativeFilePath [
"I compare if the local and remote copies of a relativeFilePath are updated for the current
documentation and return true if they are and false in any other case"
| localFile |
localFile := self localPlace / relativeFilePath.
localFile exists
ifFalse: [ ^ false ]
ifTrue: [
^ ExternalApp
compareHashFor: localFile
with: (self repository lastHashNumberFor: relativeFilePath) ]
]
{ #category : #updating }
GrafoscopioDocumentation >> listOutdatedDocs [
"I return the list of all documentent where the local copy and the remote copy doesn't match"
^ self documents reject: [ :doc | (self isFileUpdatedFor: doc) ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> localPlace [
^ localPlace.
]
{ #category : #accessing }
GrafoscopioDocumentation >> localPlace: aFileDirectory [
localPlace := aFileDirectory.
self localPlace exists ifFalse: [ self localPlace ensureCreateDirectory ].
]
{ #category : #accessing }
GrafoscopioDocumentation >> name [
^ name
]
{ #category : #accessing }
GrafoscopioDocumentation >> name: anObject [
name := anObject
]
{ #category : #accessing }
GrafoscopioDocumentation >> openNotebookAt: index [
"I open a notebook included with the documentation, located at a given index (anInteger)"
| notebookTemp |
(index between: 1 and: self documents size)
ifFalse: [ ^ self ]
ifTrue: [
notebookTemp := (self localPlace fullName, '/', (self documents at: index)) asFileReference.
notebookTemp exists
ifTrue: [GrafoscopioNotebook new openFromFile: notebookTemp]
ifFalse: [ self updateUI ]]
]
{ #category : #updating }
GrafoscopioDocumentation >> registerIntoDockingBar [
"I detect if any of the documents that are part of my collection contains any metadata
indicating if they should be registered in the main docking bar, and in such case, I add them."
self documents
do: [ :doc | | metadata currentNotebook |
currentNotebook := GrafoscopioNotebook new loadFromFile: self localPlace / doc.
metadata := currentNotebook metadata.
metadata ifNotNil: [
metadata
at: 'showOnHelp'
ifPresent: [ self error:' missing class grafoscopio docking bar' "GrafoscopioDockingBar addToHelpMenu: currentNotebook" ] ] ]
]
{ #category : #accessing }
GrafoscopioDocumentation >> repository [
^ repository
]
{ #category : #accessing }
GrafoscopioDocumentation >> repository: aFossilRepo [
repository := aFossilRepo
]
{ #category : #updating }
GrafoscopioDocumentation >> update [
(self listOutdatedDocs)
ifEmpty: [
self inform: 'All documents in the ', self name,' collection are already updated'.
^ self ]
ifNotEmpty: [:outdatedDocs |
outdatedDocs do: [ :eachDoc | self download: eachDoc ].
self inform: 'Updating of ', self name,' documentation finished.' ]
]
{ #category : #updating }
GrafoscopioDocumentation >> updateDocsPlaceUI [
self current localPlace: (UIManager default chooseDirectory: 'Path to the documentation folder')
]
{ #category : #updating }
GrafoscopioDocumentation >> updateUI [
"Updates documentation (manual, tutorials) from the official repository for a given documentation."
| update |
update := (UIManager default
confirm: 'Do you wish to update the ', self name,' documentation?'
label: 'Update ', self name, ' documentation').
update ifTrue: [ self update ]
]

View File

@ -1,24 +1,24 @@
"
A GrafoscopioDocumentationTest is a test class for testing the behavior of GrafoscopioDocumentation
"
Class {
#name : #GrafoscopioDocumentationTest,
#superclass : #TestCase,
#category : #'Grafoscopio-Utils-Tests'
}
{ #category : #'tests-utility' }
GrafoscopioDocumentationTest >> defaultTestRepo [
"I create a default documentation repository, that is used for several test."
| testRepo |
testRepo := GrafoscopioDocumentation new.
testRepo repository: (FossilRepo new remote: 'http://mutabit.com/repos.fossil/grafoscopio');
localPlace: FileLocator temp asFileReference /'Grafoscopio';
name: 'test Repo'.
testRepo
addDocument: 'Docs/Es/Tutoriales/tutorial.ston';
addDocument: 'Docs/En/Books/Manual/manual.ston';
addDocument: 'Docs/En/Books/DataActivism/techniques-for-datactivism.ston'.
^ testRepo
]
"
A GrafoscopioDocumentationTest is a test class for testing the behavior of GrafoscopioDocumentation
"
Class {
#name : #GrafoscopioDocumentationTest,
#superclass : #TestCase,
#category : #'Grafoscopio-Utils-Tests'
}
{ #category : #'tests-utility' }
GrafoscopioDocumentationTest >> defaultTestRepo [
"I create a default documentation repository, that is used for several test."
| testRepo |
testRepo := GrafoscopioDocumentation new.
testRepo repository: (FossilRepo new remote: 'http://mutabit.com/repos.fossil/grafoscopio');
localPlace: FileLocator temp asFileReference /'Grafoscopio';
name: 'test Repo'.
testRepo
addDocument: 'Docs/Es/Tutoriales/tutorial.ston';
addDocument: 'Docs/En/Books/Manual/manual.ston';
addDocument: 'Docs/En/Books/DataActivism/techniques-for-datactivism.ston'.
^ testRepo
]

View File

@ -1,164 +1,164 @@
"
I contain simple general functionality used by Grafoscopio, Dataviz
or other related projects.
"
Class {
#name : #GrafoscopioUtils,
#superclass : #Object,
#category : #'Grafoscopio-Utils'
}
{ #category : #utilities }
GrafoscopioUtils class >> checksumFor: aFileReference [
^ (SHA1 new hashMessage: aFileReference binaryReadStream contents) hex.
]
{ #category : #updating }
GrafoscopioUtils class >> download: fileNameWithRelativePath from: urlString into: aFolder [
| fileName parentFolder |
fileName := (fileNameWithRelativePath splitOn: $/) last.
parentFolder := self ensureCreateDirectory: fileNameWithRelativePath into: aFolder.
self
downloadingFrom: urlString, fileNameWithRelativePath
withMessage: 'Downloading ', fileName
into: parentFolder
]
{ #category : #'graphical interface' }
GrafoscopioUtils class >> downloadingFrom: downloadUrl withMessage: aString into: location [
| fileName |
fileName := (self sanitize: downloadUrl) segments last.
(location / fileName) ensureDelete.
[: bar |
bar title: aString.
[ZnClient new
enforceHttpSuccess: true;
url: downloadUrl;
downloadTo: location;
signalProgress: true
]
on: HTTPProgress
do: [ :progress |
progress isEmpty ifFalse: [ bar current: progress percentage ].
progress resume ].
] asJob run.
^ (location / fileName) asFileReference
]
{ #category : #utilities }
GrafoscopioUtils class >> ensureCreateDirectory: fileNameWithRelativePath into: aFolder [
| relativePathFolders parentFolder newPath |
relativePathFolders := (fileNameWithRelativePath splitOn: $/) allButLast.
newPath := aFolder path.
relativePathFolders do: [ :folder | newPath := newPath / folder ].
parentFolder := newPath asFileReference.
parentFolder ensureCreateDirectory.
^ parentFolder
]
{ #category : #persistence }
GrafoscopioUtils class >> exportAsSton: anObject on: aFileReference [
aFileReference exists ifTrue: [ aFileReference ensureDelete ].
aFileReference ensureCreateFile.
aFileReference writeStreamDo: [ :stream |
(STON writer on: stream)
newLine: String crlf;
prettyPrint: true;
keepNewLines: true;
nextPut: anObject ].
]
{ #category : #'graphical interface' }
GrafoscopioUtils class >> getContentsFrom: url withMessage: aString [
| client |
[: bar |
bar title: aString.
[client := ZnClient new
enforceHttpSuccess: true;
get: (url);
signalProgress: true
]
on: HTTPProgress
do: [ :progress |
progress isEmpty ifFalse: [ bar current: progress percentage ].
progress resume ].
] asJob run.
^ client contents.
]
{ #category : #persistence }
GrafoscopioUtils class >> joinLinesFor: aCollection [
| joinedLines |
joinedLines := WriteStream on: ''.
aCollection do: [ :line | joinedLines nextPutAll: line; crlf ].
^ joinedLines contents
]
{ #category : #utilities }
GrafoscopioUtils class >> perform: aString on: anObject [
| msg |
msg := self selectorAndArgumentsFrom: aString.
msg
at: 'args'
ifPresent: [ ^ anObject perform: (msg at: 'selector') withArguments: (msg at: 'args') ]
ifAbsent: [ ^ anObject perform: (msg at: 'selector') ]
]
{ #category : #private }
GrafoscopioUtils class >> sanitize: url [
"I remove white spaces in url's and prepend 'http://' to urls when it is ommited, so
operations that rely on sane and well formed urls don't throw error messages."
| sanitized modUrl |
modUrl := url.
[modUrl asString endsWith: ' ']
whileTrue: [ modUrl := modUrl copyFrom: 1 to: (modUrl size - 1) ].
(url asString beginsWith: 'http') "http or https"
ifFalse: [ sanitized := ('http://', modUrl) asUrl ]
ifTrue: [ sanitized := modUrl asUrl ].
^ sanitized
]
{ #category : #utilities }
GrafoscopioUtils class >> selectorAndArgumentsFrom: aString [
"I return from aString a dictionary that contains a message and an array of arguments used
in such string. Notice that the keyword message must contain spaces between the ':' and its
respective argument.
See GrafoscopioUtilsTest for examples"
| msgArray answer keywords selector args |
answer := OrderedDictionary new.
msgArray := aString splitOn: ':'.
msgArray size = 1
ifTrue: [
^ answer
at: 'selector' put: (msgArray at: 1) asSymbol;
yourself ].
selector := ''.
args := OrderedCollection new.
aString
splitOn: Character space
do: [ :part |
part endsWithAColon
ifTrue: [ selector := selector, part ]
ifFalse: [ args add: part ] ].
answer
at: 'selector' put: selector asSymbol;
at: 'args' put: args asArray.
^ answer
]
{ #category : #updating }
GrafoscopioUtils class >> update [
"Updates GrafoscopioUtils with new versions of itself take from the source code repository."
Gofer new
smalltalkhubUser: 'Offray' project: 'Grafoscopio';
package: 'Grafoscopio-Utils';
load.
]
"
I contain simple general functionality used by Grafoscopio, Dataviz
or other related projects.
"
Class {
#name : #GrafoscopioUtils,
#superclass : #Object,
#category : #'Grafoscopio-Utils'
}
{ #category : #utilities }
GrafoscopioUtils class >> checksumFor: aFileReference [
^ (SHA1 new hashMessage: aFileReference binaryReadStream contents) hex.
]
{ #category : #updating }
GrafoscopioUtils class >> download: fileNameWithRelativePath from: urlString into: aFolder [
| fileName parentFolder |
fileName := (fileNameWithRelativePath splitOn: $/) last.
parentFolder := self ensureCreateDirectory: fileNameWithRelativePath into: aFolder.
self
downloadingFrom: urlString, fileNameWithRelativePath
withMessage: 'Downloading ', fileName
into: parentFolder
]
{ #category : #'graphical interface' }
GrafoscopioUtils class >> downloadingFrom: downloadUrl withMessage: aString into: location [
| fileName |
fileName := (self sanitize: downloadUrl) segments last.
(location / fileName) ensureDelete.
[: bar |
bar title: aString.
[ZnClient new
enforceHttpSuccess: true;
url: downloadUrl;
downloadTo: location;
signalProgress: true
]
on: HTTPProgress
do: [ :progress |
progress isEmpty ifFalse: [ bar current: progress percentage ].
progress resume ].
] asJob run.
^ (location / fileName) asFileReference
]
{ #category : #utilities }
GrafoscopioUtils class >> ensureCreateDirectory: fileNameWithRelativePath into: aFolder [
| relativePathFolders parentFolder newPath |
relativePathFolders := (fileNameWithRelativePath splitOn: $/) allButLast.
newPath := aFolder path.
relativePathFolders do: [ :folder | newPath := newPath / folder ].
parentFolder := newPath asFileReference.
parentFolder ensureCreateDirectory.
^ parentFolder
]
{ #category : #persistence }
GrafoscopioUtils class >> exportAsSton: anObject on: aFileReference [
aFileReference exists ifTrue: [ aFileReference ensureDelete ].
aFileReference ensureCreateFile.
aFileReference writeStreamDo: [ :stream |
(STON writer on: stream)
newLine: String crlf;
prettyPrint: true;
keepNewLines: true;
nextPut: anObject ].
]
{ #category : #'graphical interface' }
GrafoscopioUtils class >> getContentsFrom: url withMessage: aString [
| client |
[: bar |
bar title: aString.
[client := ZnClient new
enforceHttpSuccess: true;
get: (url);
signalProgress: true
]
on: HTTPProgress
do: [ :progress |
progress isEmpty ifFalse: [ bar current: progress percentage ].
progress resume ].
] asJob run.
^ client contents.
]
{ #category : #persistence }
GrafoscopioUtils class >> joinLinesFor: aCollection [
| joinedLines |
joinedLines := WriteStream on: ''.
aCollection do: [ :line | joinedLines nextPutAll: line; crlf ].
^ joinedLines contents
]
{ #category : #utilities }
GrafoscopioUtils class >> perform: aString on: anObject [
| msg |
msg := self selectorAndArgumentsFrom: aString.
msg
at: 'args'
ifPresent: [ ^ anObject perform: (msg at: 'selector') withArguments: (msg at: 'args') ]
ifAbsent: [ ^ anObject perform: (msg at: 'selector') ]
]
{ #category : #private }
GrafoscopioUtils class >> sanitize: url [
"I remove white spaces in url's and prepend 'http://' to urls when it is ommited, so
operations that rely on sane and well formed urls don't throw error messages."
| sanitized modUrl |
modUrl := url.
[modUrl asString endsWith: ' ']
whileTrue: [ modUrl := modUrl copyFrom: 1 to: (modUrl size - 1) ].
(url asString beginsWith: 'http') "http or https"
ifFalse: [ sanitized := ('http://', modUrl) asUrl ]
ifTrue: [ sanitized := modUrl asUrl ].
^ sanitized
]
{ #category : #utilities }
GrafoscopioUtils class >> selectorAndArgumentsFrom: aString [
"I return from aString a dictionary that contains a message and an array of arguments used
in such string. Notice that the keyword message must contain spaces between the ':' and its
respective argument.
See GrafoscopioUtilsTest for examples"
| msgArray answer keywords selector args |
answer := OrderedDictionary new.
msgArray := aString splitOn: ':'.
msgArray size = 1
ifTrue: [
^ answer
at: 'selector' put: (msgArray at: 1) asSymbol;
yourself ].
selector := ''.
args := OrderedCollection new.
aString
splitOn: Character space
do: [ :part |
part endsWithAColon
ifTrue: [ selector := selector, part ]
ifFalse: [ args add: part ] ].
answer
at: 'selector' put: selector asSymbol;
at: 'args' put: args asArray.
^ answer
]
{ #category : #updating }
GrafoscopioUtils class >> update [
"Updates GrafoscopioUtils with new versions of itself take from the source code repository."
Gofer new
smalltalkhubUser: 'Offray' project: 'Grafoscopio';
package: 'Grafoscopio-Utils';
load.
]

View File

@ -1,8 +1,8 @@
"
A GrafoscopioUtilsTest is a test class for testing the behavior of GrafoscopioUtils
"
Class {
#name : #GrafoscopioUtilsTest,
#superclass : #TestCase,
#category : #'Grafoscopio-Utils-Tests'
}
"
A GrafoscopioUtilsTest is a test class for testing the behavior of GrafoscopioUtils
"
Class {
#name : #GrafoscopioUtilsTest,
#superclass : #TestCase,
#category : #'Grafoscopio-Utils-Tests'
}

View File

@ -1,113 +1,113 @@
"
I model the interface between a CodiMD (https://demo.codimd.org) documentation
server and Grafoscopio.
I enable the interaction between Grafoscopio notebooks and CodiMD documents,
so one document can start online (as a CodiMD pad) and continue as a Grafoscopio
notebook or viceversa.
"
Class {
#name : #HedgeDoc,
#superclass : #Object,
#instVars : [
'server',
'pad',
'contents',
'url'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'as yet unclassified' }
HedgeDoc class >> newDefault [
^ self new
defaultServer.
]
{ #category : #accessing }
HedgeDoc >> contents [
^ contents
]
{ #category : #accessing }
HedgeDoc >> contents: anObject [
contents := anObject
]
{ #category : #'as yet unclassified' }
HedgeDoc >> defaultServer [
self server: 'https://docutopia.tupale.co'.
]
{ #category : #'as yet unclassified' }
HedgeDoc >> htmlUrl [
| link |
link := self url copy.
link segments insert: 's' before: 1.
^ link
]
{ #category : #'as yet unclassified' }
HedgeDoc >> importContents [
self contents: self retrieveContents
]
{ #category : #accessing }
HedgeDoc >> pad [
^ pad
]
{ #category : #accessing }
HedgeDoc >> pad: anObject [
pad := anObject
]
{ #category : #'as yet unclassified' }
HedgeDoc >> retrieveContents [
self url ifNil: [ ^ self ].
^ (self url addPathSegment: 'download') retrieveContents
]
{ #category : #'as yet unclassified' }
HedgeDoc >> retrieveHtmlContents [
| htmlContents |
self url ifNil: [ ^ self ].
htmlContents := self htmlUrl.
^ htmlContents retrieveContents
]
{ #category : #'as yet unclassified' }
HedgeDoc >> saveContentsToFile: aFileLocator [
self url ifNil: [ ^ self ].
^ (self url addPathSegment: 'download') saveContentsToFile: aFileLocator
]
{ #category : #'as yet unclassified' }
HedgeDoc >> saveHtmlContentsToFile: aFileLocator [
self url ifNil: [ ^ self ].
^ self htmlUrl saveContentsToFile: aFileLocator
]
{ #category : #accessing }
HedgeDoc >> server [
^ server
]
{ #category : #accessing }
HedgeDoc >> server: aUrlString [
server := aUrlString
]
{ #category : #accessing }
HedgeDoc >> url [
^ url asUrl
]
{ #category : #accessing }
HedgeDoc >> url: anObject [
url := anObject
]
{ #category : #visiting }
HedgeDoc >> visit [
WebBrowser openOn: self server, '/', self pad.
]
"
I model the interface between a CodiMD (https://demo.codimd.org) documentation
server and Grafoscopio.
I enable the interaction between Grafoscopio notebooks and CodiMD documents,
so one document can start online (as a CodiMD pad) and continue as a Grafoscopio
notebook or viceversa.
"
Class {
#name : #HedgeDoc,
#superclass : #Object,
#instVars : [
'server',
'pad',
'contents',
'url'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'as yet unclassified' }
HedgeDoc class >> newDefault [
^ self new
defaultServer.
]
{ #category : #accessing }
HedgeDoc >> contents [
^ contents
]
{ #category : #accessing }
HedgeDoc >> contents: anObject [
contents := anObject
]
{ #category : #'as yet unclassified' }
HedgeDoc >> defaultServer [
self server: 'https://docutopia.tupale.co'.
]
{ #category : #'as yet unclassified' }
HedgeDoc >> htmlUrl [
| link |
link := self url copy.
link segments insert: 's' before: 1.
^ link
]
{ #category : #'as yet unclassified' }
HedgeDoc >> importContents [
self contents: self retrieveContents
]
{ #category : #accessing }
HedgeDoc >> pad [
^ pad
]
{ #category : #accessing }
HedgeDoc >> pad: anObject [
pad := anObject
]
{ #category : #'as yet unclassified' }
HedgeDoc >> retrieveContents [
self url ifNil: [ ^ self ].
^ (self url addPathSegment: 'download') retrieveContents
]
{ #category : #'as yet unclassified' }
HedgeDoc >> retrieveHtmlContents [
| htmlContents |
self url ifNil: [ ^ self ].
htmlContents := self htmlUrl.
^ htmlContents retrieveContents
]
{ #category : #'as yet unclassified' }
HedgeDoc >> saveContentsToFile: aFileLocator [
self url ifNil: [ ^ self ].
^ (self url addPathSegment: 'download') saveContentsToFile: aFileLocator
]
{ #category : #'as yet unclassified' }
HedgeDoc >> saveHtmlContentsToFile: aFileLocator [
self url ifNil: [ ^ self ].
^ self htmlUrl saveContentsToFile: aFileLocator
]
{ #category : #accessing }
HedgeDoc >> server [
^ server
]
{ #category : #accessing }
HedgeDoc >> server: aUrlString [
server := aUrlString
]
{ #category : #accessing }
HedgeDoc >> url [
^ url asUrl
]
{ #category : #accessing }
HedgeDoc >> url: anObject [
url := anObject
]
{ #category : #visiting }
HedgeDoc >> visit [
WebBrowser openOn: self server, '/', self pad.
]

View File

@ -1,185 +1,185 @@
"
I model a Mardeep file as described in https://casual-effects.com/markdeep/
"
Class {
#name : #Markdeep,
#superclass : #Object,
#instVars : [
'tocStyle',
'comments',
'header',
'tail',
'body',
'language',
'markdownFile'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'as yet unclassified' }
Markdeep class >> fromMarkdownFile: aFileReference [
^ self new fromMarkdownFile: aFileReference.
]
{ #category : #accessing }
Markdeep >> body [
^ body
]
{ #category : #accessing }
Markdeep >> body: anObject [
body := anObject
]
{ #category : #accessing }
Markdeep >> comments [
^ comments ifNil: [ ^ comments := true ]
]
{ #category : #accessing }
Markdeep >> comments: aBoolean [
"I tell if comments are enabled by default or not."
comments := aBoolean
]
{ #category : #utilities }
Markdeep >> commentsProvider [
"I return the url of the default service that provides annotation support.
I am used to add such support in the contents of the Markdeep page."
^ 'https://hypothes.is'
]
{ #category : #utilities }
Markdeep >> commentsProviderStrings [
"I associate a comments service provider with the string that is required to be added
to the document to enable such provider."
| providers |
providers := Dictionary new.
providers at: 'https://hypothes.is' put: '<!-- Hypothesis -->
<script src="https://hypothes.is/embed.js" async></script>'.
^ providers
]
{ #category : #utilities }
Markdeep >> commentsSupport [
"I enable comments of the page."
self comments ifFalse: [ ^ self ].
^ self commentsProviderStrings at: self commentsProvider
]
{ #category : #'instance creation' }
Markdeep >> contents [
| output |
output := '' writeStream.
output
nextPutAll: self header; crlf;
nextPutAll: self body; crlf;
nextPutAll: self tail; crlf; crlf;
nextPutAll: self commentsSupport.
^ output contents.
]
{ #category : #persistence }
Markdeep >> exportAsFile [
| newFile |
self markdownFile ifNil: [ self inform: 'Define an input Markdown file or use #exportAsFileOn: instead.' ].
newFile := (self markdownFile fullName, '.html') asFileReference.
self exportAsFileOn: newFile.
]
{ #category : #persistence }
Markdeep >> exportAsFileOn: aFileReference [
aFileReference exists ifFalse: [ aFileReference ensureCreateFile ].
aFileReference writeStreamDo: [ :stream |
stream nextPutAll: self contents ].
self inform: 'Exported as: ', String cr, aFileReference fullName
]
{ #category : #utilities }
Markdeep >> fontAwesomeHeader [
"I enable the font awesome support in the document header"
^ ' <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
'
]
{ #category : #'instance creation' }
Markdeep >> fromMarkdownFile: aFileReference [
"I create a Markdeep document from a given Markdown file."
self processMarkdownFor: aFileReference.
^ self.
]
{ #category : #accessing }
Markdeep >> header [
^ self fontAwesomeHeader
]
{ #category : #accessing }
Markdeep >> header: anObject [
header := anObject
]
{ #category : #accessing }
Markdeep >> language [
^ language
]
{ #category : #accessing }
Markdeep >> language: anObject [
language := anObject
]
{ #category : #accessing }
Markdeep >> markdownFile [
^ markdownFile
]
{ #category : #accessing }
Markdeep >> markdownFile: aFileReference [
"I provide information about which Markdown file was used to generate the Markdeep body"
markdownFile := aFileReference
]
{ #category : #'instance creation' }
Markdeep >> processMarkdownFor: aFileReference [
"comment stating purpose of message"
| markdownContent |
self markdownFile: aFileReference.
markdownContent := Markdown fromFile: aFileReference.
self body: (markdownContent commentYAMLMetadata contents).
]
{ #category : #accessing }
Markdeep >> tail [
"I enable the document tail, which, in turn, enables a Markdeep document"
^ '
<!-- Markdeep: -->
<style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style>
<script>window.markdeepOptions = {tocStyle: "medium"}</script>
<script src="markdeep.min.js" charset="utf-8"></script>
<script
src="https://casual-effects.com/markdeep/latest/markdeep.min.js?"
charset="utf-8">
</script>
<!--<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>--> '
]
{ #category : #accessing }
Markdeep >> tail: anObject [
tail := anObject
]
{ #category : #accessing }
Markdeep >> tocStyle [
^ tocStyle
]
{ #category : #accessing }
Markdeep >> tocStyle: anObject [
tocStyle := anObject
]
"
I model a Mardeep file as described in https://casual-effects.com/markdeep/
"
Class {
#name : #Markdeep,
#superclass : #Object,
#instVars : [
'tocStyle',
'comments',
'header',
'tail',
'body',
'language',
'markdownFile'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'as yet unclassified' }
Markdeep class >> fromMarkdownFile: aFileReference [
^ self new fromMarkdownFile: aFileReference.
]
{ #category : #accessing }
Markdeep >> body [
^ body
]
{ #category : #accessing }
Markdeep >> body: anObject [
body := anObject
]
{ #category : #accessing }
Markdeep >> comments [
^ comments ifNil: [ ^ comments := true ]
]
{ #category : #accessing }
Markdeep >> comments: aBoolean [
"I tell if comments are enabled by default or not."
comments := aBoolean
]
{ #category : #utilities }
Markdeep >> commentsProvider [
"I return the url of the default service that provides annotation support.
I am used to add such support in the contents of the Markdeep page."
^ 'https://hypothes.is'
]
{ #category : #utilities }
Markdeep >> commentsProviderStrings [
"I associate a comments service provider with the string that is required to be added
to the document to enable such provider."
| providers |
providers := Dictionary new.
providers at: 'https://hypothes.is' put: '<!-- Hypothesis -->
<script src="https://hypothes.is/embed.js" async></script>'.
^ providers
]
{ #category : #utilities }
Markdeep >> commentsSupport [
"I enable comments of the page."
self comments ifFalse: [ ^ self ].
^ self commentsProviderStrings at: self commentsProvider
]
{ #category : #'instance creation' }
Markdeep >> contents [
| output |
output := '' writeStream.
output
nextPutAll: self header; crlf;
nextPutAll: self body; crlf;
nextPutAll: self tail; crlf; crlf;
nextPutAll: self commentsSupport.
^ output contents.
]
{ #category : #persistence }
Markdeep >> exportAsFile [
| newFile |
self markdownFile ifNil: [ self inform: 'Define an input Markdown file or use #exportAsFileOn: instead.' ].
newFile := (self markdownFile fullName, '.html') asFileReference.
self exportAsFileOn: newFile.
]
{ #category : #persistence }
Markdeep >> exportAsFileOn: aFileReference [
aFileReference exists ifFalse: [ aFileReference ensureCreateFile ].
aFileReference writeStreamDo: [ :stream |
stream nextPutAll: self contents ].
self inform: 'Exported as: ', String cr, aFileReference fullName
]
{ #category : #utilities }
Markdeep >> fontAwesomeHeader [
"I enable the font awesome support in the document header"
^ ' <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
'
]
{ #category : #'instance creation' }
Markdeep >> fromMarkdownFile: aFileReference [
"I create a Markdeep document from a given Markdown file."
self processMarkdownFor: aFileReference.
^ self.
]
{ #category : #accessing }
Markdeep >> header [
^ self fontAwesomeHeader
]
{ #category : #accessing }
Markdeep >> header: anObject [
header := anObject
]
{ #category : #accessing }
Markdeep >> language [
^ language
]
{ #category : #accessing }
Markdeep >> language: anObject [
language := anObject
]
{ #category : #accessing }
Markdeep >> markdownFile [
^ markdownFile
]
{ #category : #accessing }
Markdeep >> markdownFile: aFileReference [
"I provide information about which Markdown file was used to generate the Markdeep body"
markdownFile := aFileReference
]
{ #category : #'instance creation' }
Markdeep >> processMarkdownFor: aFileReference [
"comment stating purpose of message"
| markdownContent |
self markdownFile: aFileReference.
markdownContent := Markdown fromFile: aFileReference.
self body: (markdownContent commentYAMLMetadata contents).
]
{ #category : #accessing }
Markdeep >> tail [
"I enable the document tail, which, in turn, enables a Markdeep document"
^ '
<!-- Markdeep: -->
<style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style>
<script>window.markdeepOptions = {tocStyle: "medium"}</script>
<script src="markdeep.min.js" charset="utf-8"></script>
<script
src="https://casual-effects.com/markdeep/latest/markdeep.min.js?"
charset="utf-8">
</script>
<!--<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>--> '
]
{ #category : #accessing }
Markdeep >> tail: anObject [
tail := anObject
]
{ #category : #accessing }
Markdeep >> tocStyle [
^ tocStyle
]
{ #category : #accessing }
Markdeep >> tocStyle: anObject [
tocStyle := anObject
]

View File

@ -1,169 +1,169 @@
"
I model a Markdown document.
At some point the idea is to have a full native parser implemented to deal
with my syntax, but meanwhile I will be collaborating with external parsers,
particularly the ones provided by Pandoc and/or Lunamark.
"
Class {
#name : #Markdown,
#superclass : #Object,
#instVars : [
'contents',
'file'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'instance creation' }
Markdown class >> fromFile: aFileReference [
^ self new fromFile: aFileReference
]
{ #category : #utilities }
Markdown class >> yamlMetadataDelimiter [
^ '---'
]
{ #category : #operation }
Markdown >> commentYAMLMetadata [
| newContents |
self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream.
newContents nextPutAll: '<!--@yaml:'; crlf.
newContents nextPutAll: self extractYAMLMetadata.
newContents nextPutAll: String cr.
newContents nextPutAll: '-->'; crlf.
(self lines copyFrom: self locateYAMLMetadataClosing + 2 to: self lines size) do: [ :line |
newContents nextPutAll: line; crlf ].
self contents: newContents contents.
^ self contents
]
{ #category : #utilities }
Markdown >> containsYAMLMetadataClosing [
^ self locateYAMLMetadataClosing > 0
]
{ #category : #accessing }
Markdown >> contents [
^ contents
]
{ #category : #accessing }
Markdown >> contents: anObject [
contents := anObject
]
{ #category : #utilities }
Markdown >> detectYAMLMetadata [
| lines |
lines := self lines.
^ self startsWithYAMLMetadataDelimiter
and: [ lines allButFirst
detect: [ :currentLine | currentLine beginsWith: self class yamlMetadataDelimiter ]
ifFound: [ ^ true ] ifNone: [ ^ false ] ]
]
{ #category : #operation }
Markdown >> exportMetadataAsJson [
"TBD: Lua scripts should be checked and installed when missing. Maybe a shared location
in '.local/share/Grafoscopio/Scripts' should be developed in the near future."
| output luaScript |
luaScript := FileLocator home / '.local/share/Brea/scripts/meta-to-json.lua'.
Smalltalk platformName = 'unix' ifTrue: [
OSSUnixSubprocess new
workingDirectory: self file parent fullName;
command: 'pandoc';
arguments: { '--lua-filter=', luaScript fullName . self file basename };
redirectStdout;
redirectStdin;
runAndWaitOnExitDo: [ :process :outString :errString |
output := process isSuccess
ifTrue: [ outString ]
ifFalse: [ errString ]
]].
^ output correctAccentedCharacters
]
{ #category : #operation }
Markdown >> exportMetadataAsYaml [
| exportedFile |
exportedFile := FileLocator temp / 'metadata.yaml'.
MarkupFile exportAsFileOn: exportedFile containing: self yamlMetadataAsString.
^ exportedFile
]
{ #category : #operation }
Markdown >> extractYAMLMetadata [
| output yamlLines |
self detectYAMLMetadata ifFalse: [ ^ nil ].
yamlLines := self lines copyFrom: 2 to: (self locateYAMLMetadataClosing).
output := '' writeStream.
yamlLines do: [ :line |
output
nextPutAll: line;
nextPut: Character cr. ].
^ output contents
]
{ #category : #accessing }
Markdown >> file [
^ file
]
{ #category : #accessing }
Markdown >> file: aFileReference [
"I store the origen/destination of the Markdown contents."
file := aFileReference
]
{ #category : #'instance creation' }
Markdown >> fromFile: aFileReference [
self contents: aFileReference contents.
self file: aFileReference
]
{ #category : #utilities }
Markdown >> lines [
^ self contents lines.
]
{ #category : #utilities }
Markdown >> locateYAMLMetadataClosing [
"I return the line where the closing of the YAML metadata occurs or 0 if no closing is found."
| result |
self startsWithYAMLMetadataDelimiter ifFalse: [ ^ self ].
result := 0.
self lines allButFirst doWithIndex: [ :currentLine :i |
(currentLine beginsWith: self class yamlMetadataDelimiter) ifTrue: [ result := i ]].
^ result
]
{ #category : #accessing }
Markdown >> metadata [
| rawMeta |
rawMeta := PPYAMLGrammar new parse: self extractYAMLMetadata.
rawMeta associationsDo: [ :assoc |
assoc value = 'false' ifTrue: [ assoc value: false ].
assoc value = 'true' ifTrue: [ assoc value: true ] ].
^ rawMeta
]
{ #category : #utilities }
Markdown >> startsWithYAMLMetadataDelimiter [
^ self lines first beginsWith: self class yamlMetadataDelimiter
]
{ #category : #utilities }
Markdown >> yamlMetadataAsString [
| output |
self extractYAMLMetadata ifNil: [ ^ nil ].
output := String new writeStream.
output nextPutAll: self class yamlMetadataDelimiter; cr.
output nextPutAll: self extractYAMLMetadata.
output nextPutAll: self class yamlMetadataDelimiter; cr.
^ output contents.
]
"
I model a Markdown document.
At some point the idea is to have a full native parser implemented to deal
with my syntax, but meanwhile I will be collaborating with external parsers,
particularly the ones provided by Pandoc and/or Lunamark.
"
Class {
#name : #Markdown,
#superclass : #Object,
#instVars : [
'contents',
'file'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'instance creation' }
Markdown class >> fromFile: aFileReference [
^ self new fromFile: aFileReference
]
{ #category : #utilities }
Markdown class >> yamlMetadataDelimiter [
^ '---'
]
{ #category : #operation }
Markdown >> commentYAMLMetadata [
| newContents |
self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream.
newContents nextPutAll: '<!--@yaml:'; crlf.
newContents nextPutAll: self extractYAMLMetadata.
newContents nextPutAll: String cr.
newContents nextPutAll: '-->'; crlf.
(self lines copyFrom: self locateYAMLMetadataClosing + 2 to: self lines size) do: [ :line |
newContents nextPutAll: line; crlf ].
self contents: newContents contents.
^ self contents
]
{ #category : #utilities }
Markdown >> containsYAMLMetadataClosing [
^ self locateYAMLMetadataClosing > 0
]
{ #category : #accessing }
Markdown >> contents [
^ contents
]
{ #category : #accessing }
Markdown >> contents: anObject [
contents := anObject
]
{ #category : #utilities }
Markdown >> detectYAMLMetadata [
| lines |
lines := self lines.
^ self startsWithYAMLMetadataDelimiter
and: [ lines allButFirst
detect: [ :currentLine | currentLine beginsWith: self class yamlMetadataDelimiter ]
ifFound: [ ^ true ] ifNone: [ ^ false ] ]
]
{ #category : #operation }
Markdown >> exportMetadataAsJson [
"TBD: Lua scripts should be checked and installed when missing. Maybe a shared location
in '.local/share/Grafoscopio/Scripts' should be developed in the near future."
| output luaScript |
luaScript := FileLocator home / '.local/share/Brea/scripts/meta-to-json.lua'.
Smalltalk platformName = 'unix' ifTrue: [
OSSUnixSubprocess new
workingDirectory: self file parent fullName;
command: 'pandoc';
arguments: { '--lua-filter=', luaScript fullName . self file basename };
redirectStdout;
redirectStdin;
runAndWaitOnExitDo: [ :process :outString :errString |
output := process isSuccess
ifTrue: [ outString ]
ifFalse: [ errString ]
]].
^ output correctAccentedCharacters
]
{ #category : #operation }
Markdown >> exportMetadataAsYaml [
| exportedFile |
exportedFile := FileLocator temp / 'metadata.yaml'.
MarkupFile exportAsFileOn: exportedFile containing: self yamlMetadataAsString.
^ exportedFile
]
{ #category : #operation }
Markdown >> extractYAMLMetadata [
| output yamlLines |
self detectYAMLMetadata ifFalse: [ ^ nil ].
yamlLines := self lines copyFrom: 2 to: (self locateYAMLMetadataClosing).
output := '' writeStream.
yamlLines do: [ :line |
output
nextPutAll: line;
nextPut: Character cr. ].
^ output contents
]
{ #category : #accessing }
Markdown >> file [
^ file
]
{ #category : #accessing }
Markdown >> file: aFileReference [
"I store the origen/destination of the Markdown contents."
file := aFileReference
]
{ #category : #'instance creation' }
Markdown >> fromFile: aFileReference [
self contents: aFileReference contents.
self file: aFileReference
]
{ #category : #utilities }
Markdown >> lines [
^ self contents lines.
]
{ #category : #utilities }
Markdown >> locateYAMLMetadataClosing [
"I return the line where the closing of the YAML metadata occurs or 0 if no closing is found."
| result |
self startsWithYAMLMetadataDelimiter ifFalse: [ ^ self ].
result := 0.
self lines allButFirst doWithIndex: [ :currentLine :i |
(currentLine beginsWith: self class yamlMetadataDelimiter) ifTrue: [ result := i ]].
^ result
]
{ #category : #accessing }
Markdown >> metadata [
| rawMeta |
rawMeta := PPYAMLGrammar new parse: self extractYAMLMetadata.
rawMeta associationsDo: [ :assoc |
assoc value = 'false' ifTrue: [ assoc value: false ].
assoc value = 'true' ifTrue: [ assoc value: true ] ].
^ rawMeta
]
{ #category : #utilities }
Markdown >> startsWithYAMLMetadataDelimiter [
^ self lines first beginsWith: self class yamlMetadataDelimiter
]
{ #category : #utilities }
Markdown >> yamlMetadataAsString [
| output |
self extractYAMLMetadata ifNil: [ ^ nil ].
output := String new writeStream.
output nextPutAll: self class yamlMetadataDelimiter; cr.
output nextPutAll: self extractYAMLMetadata.
output nextPutAll: self class yamlMetadataDelimiter; cr.
^ output contents.
]

View File

@ -1,23 +1,23 @@
"
I model common operations made with several markup files.
"
Class {
#name : #MarkupFile,
#superclass : #Object,
#instVars : [
'file'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #persistence }
MarkupFile class >> exportAsFileOn: aFileReferenceOrFileName containing: text [
| file |
file := aFileReferenceOrFileName asFileReference.
file ensureDelete.
file exists ifFalse: [ file ensureCreateFile ].
file writeStreamDo: [ :stream |
stream nextPutAll: text withInternetLineEndings].
self inform: 'Exported as: ', String cr, file fullName.
^ file
]
"
I model common operations made with several markup files.
"
Class {
#name : #MarkupFile,
#superclass : #Object,
#instVars : [
'file'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #persistence }
MarkupFile class >> exportAsFileOn: aFileReferenceOrFileName containing: text [
| file |
file := aFileReferenceOrFileName asFileReference.
file ensureDelete.
file exists ifFalse: [ file ensureCreateFile ].
file writeStreamDo: [ :stream |
stream nextPutAll: text withInternetLineEndings].
self inform: 'Exported as: ', String cr, file fullName.
^ file
]

View File

@ -1,46 +1,46 @@
"
I provide some utilites to work with OrgMode files.
https://orgmode.org/
"
Class {
#name : #OrgMode,
#superclass : #Object,
#instVars : [
'contents',
'file'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'instance creation' }
OrgMode class >> fromFile: aFileReference [
^ self new contents: aFileReference contents.
]
{ #category : #accessing }
OrgMode >> contents [
^ contents
]
{ #category : #accessing }
OrgMode >> contents: anObject [
contents := anObject
]
{ #category : #accessing }
OrgMode >> file [
^ file
]
{ #category : #accessing }
OrgMode >> file: anObject [
file := anObject
]
{ #category : #utilities }
OrgMode >> selectHeadlines [
^ self contents lines select: [ :line |
line isOrgModeHeader ]
]
"
I provide some utilites to work with OrgMode files.
https://orgmode.org/
"
Class {
#name : #OrgMode,
#superclass : #Object,
#instVars : [
'contents',
'file'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'instance creation' }
OrgMode class >> fromFile: aFileReference [
^ self new contents: aFileReference contents.
]
{ #category : #accessing }
OrgMode >> contents [
^ contents
]
{ #category : #accessing }
OrgMode >> contents: anObject [
contents := anObject
]
{ #category : #accessing }
OrgMode >> file [
^ file
]
{ #category : #accessing }
OrgMode >> file: anObject [
file := anObject
]
{ #category : #utilities }
OrgMode >> selectHeadlines [
^ self contents lines select: [ :line |
line isOrgModeHeader ]
]

View File

@ -1,146 +1,146 @@
"
I model the interaction between Pandoc and Grafoscopio.
"
Class {
#name : #Pandoc,
#superclass : #Object,
#classInstVars : [
'executable'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'as yet unclassified' }
Pandoc class >> downloadLuaFilters [
self luaFilters do: [ :filter | | filterUrl |
filterUrl := filter asUrl.
(FileLocator temp asFileReference / (filterUrl segments last)) exists
ifFalse: [
ZnClient new
url: filterUrl;
downloadTo: FileLocator temp ] ]
]
{ #category : #accessing }
Pandoc class >> executable [
^ executable ifNil: [ self executableLocation ]
]
{ #category : #accessing }
Pandoc class >> executable: aFileReference [
executable := aFileReference
]
{ #category : #accessing }
Pandoc class >> executableLocation [
| location |
location := '/usr/bin/pandoc'.
location asFileReference exists
ifTrue: [ ^ location ]
ifFalse: [ self definePandocExecutable ]
]
{ #category : #utility }
Pandoc class >> extractImagesInUnixFor: aFileReference withFilter: aLuaFilter [
"I use Pandoc Lua scripting capabilities to extract al images links in aFileReference"
OSSUnixSubprocess new
command: 'pandoc';
arguments: {aFileReference fullName . '--lua-filter=',aLuaFilter fullName };
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [
^ ((Soup fromString: outString) findAllTags: 'td') collect: [ :each | each next ] ]
ifFalse: [
"OSSUnixProcessExitStatus has a nice #printOn: "
Transcript show: 'Command exit with error status: ', process exitStatusInterpreter printString; cr.
Transcript show: 'Stderr contents: ', errString.
]
]
]
{ #category : #converters }
Pandoc class >> htmlToMarkdown: inputFile [
| outputFile |
outputFile := FileLocator temp / 'body.md'.
outputFile ensureDelete.
outputFile ensureCreateFile.
OSSUnixSubprocess new
command: 'pandoc';
arguments: {'-f'. 'html'. '-t'. 'markdown'. '--atx-headers'. inputFile fullName.
'--output'. outputFile fullName };
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [ ^ outputFile contents ]
ifFalse: [ ^inputFile contents ]
]
]
{ #category : #'as yet unclassified' }
Pandoc class >> listImagesFrom: aFileReference [
"I provide a list of all images contained in aFile."
| filter commandString outputString |
filter := FileLocator temp asFileReference / 'image-links.lua'.
filter exists
ifFalse: [ self downloadLuaFilters ].
commandString := 'pandoc ' , aFileReference fullName
, ' --lua-filter=' , filter fullName.
^ self extractImagesInUnixFor: aFileReference withFilter: filter
]
{ #category : #utility }
Pandoc class >> luaFilters [
"I define the location of set of scripts, that allows to change the default behaviour of Pandoc
and/or the processing of supported markup languages.
For more information about Lua filters see:
https://pandoc.org/lua-filters.html
"
| filters |
filters := OrderedCollection new.
filters
add: 'http://mutabit.com/repos.fossil/dataweek/doc/tip/Artefactos/Scripts/image-links.lua'.
^ filters
]
{ #category : #converters }
Pandoc class >> markdownToHtml: inputFile [
(Smalltalk os isUnix or: [ Smalltalk os isMacOS ]) ifTrue: [ ^ self markdownToHtmlOnUnix: inputFile ].
Smalltalk os isWindows ifTrue: [ ^ self markdownToHtmlOnWindows: inputFile ].
]
{ #category : #converters }
Pandoc class >> markdownToHtmlOnUnix: inputFile [
| outputFile |
outputFile := FileLocator temp / (inputFile basenameWithoutExtension , '.html').
outputFile ensureDelete.
outputFile ensureCreateFile.
OSSUnixSubprocess new
command: 'pandoc';
arguments: {'-f'. 'markdown+startnum+task_lists'. '-t'. 'html'. inputFile fullName.
'--output'. outputFile fullName };
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [ ^ outputFile ]
ifFalse: [ ^ inputFile ]
]
]
{ #category : #converters }
Pandoc class >> markdownToHtmlOnWindows: inputFile [
^ LibC resultOfCommand: 'pandoc -f markdown+startnum+task_lists -t html', inputFile fullName.
]
"
I model the interaction between Pandoc and Grafoscopio.
"
Class {
#name : #Pandoc,
#superclass : #Object,
#classInstVars : [
'executable'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #'as yet unclassified' }
Pandoc class >> downloadLuaFilters [
self luaFilters do: [ :filter | | filterUrl |
filterUrl := filter asUrl.
(FileLocator temp asFileReference / (filterUrl segments last)) exists
ifFalse: [
ZnClient new
url: filterUrl;
downloadTo: FileLocator temp ] ]
]
{ #category : #accessing }
Pandoc class >> executable [
^ executable ifNil: [ self executableLocation ]
]
{ #category : #accessing }
Pandoc class >> executable: aFileReference [
executable := aFileReference
]
{ #category : #accessing }
Pandoc class >> executableLocation [
| location |
location := '/usr/bin/pandoc'.
location asFileReference exists
ifTrue: [ ^ location ]
ifFalse: [ self definePandocExecutable ]
]
{ #category : #utility }
Pandoc class >> extractImagesInUnixFor: aFileReference withFilter: aLuaFilter [
"I use Pandoc Lua scripting capabilities to extract al images links in aFileReference"
OSSUnixSubprocess new
command: 'pandoc';
arguments: {aFileReference fullName . '--lua-filter=',aLuaFilter fullName };
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [
^ ((Soup fromString: outString) findAllTags: 'td') collect: [ :each | each next ] ]
ifFalse: [
"OSSUnixProcessExitStatus has a nice #printOn: "
Transcript show: 'Command exit with error status: ', process exitStatusInterpreter printString; cr.
Transcript show: 'Stderr contents: ', errString.
]
]
]
{ #category : #converters }
Pandoc class >> htmlToMarkdown: inputFile [
| outputFile |
outputFile := FileLocator temp / 'body.md'.
outputFile ensureDelete.
outputFile ensureCreateFile.
OSSUnixSubprocess new
command: 'pandoc';
arguments: {'-f'. 'html'. '-t'. 'markdown'. '--atx-headers'. inputFile fullName.
'--output'. outputFile fullName };
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [ ^ outputFile contents ]
ifFalse: [ ^inputFile contents ]
]
]
{ #category : #'as yet unclassified' }
Pandoc class >> listImagesFrom: aFileReference [
"I provide a list of all images contained in aFile."
| filter commandString outputString |
filter := FileLocator temp asFileReference / 'image-links.lua'.
filter exists
ifFalse: [ self downloadLuaFilters ].
commandString := 'pandoc ' , aFileReference fullName
, ' --lua-filter=' , filter fullName.
^ self extractImagesInUnixFor: aFileReference withFilter: filter
]
{ #category : #utility }
Pandoc class >> luaFilters [
"I define the location of set of scripts, that allows to change the default behaviour of Pandoc
and/or the processing of supported markup languages.
For more information about Lua filters see:
https://pandoc.org/lua-filters.html
"
| filters |
filters := OrderedCollection new.
filters
add: 'http://mutabit.com/repos.fossil/dataweek/doc/tip/Artefactos/Scripts/image-links.lua'.
^ filters
]
{ #category : #converters }
Pandoc class >> markdownToHtml: inputFile [
(Smalltalk os isUnix or: [ Smalltalk os isMacOS ]) ifTrue: [ ^ self markdownToHtmlOnUnix: inputFile ].
Smalltalk os isWindows ifTrue: [ ^ self markdownToHtmlOnWindows: inputFile ].
]
{ #category : #converters }
Pandoc class >> markdownToHtmlOnUnix: inputFile [
| outputFile |
outputFile := FileLocator temp / (inputFile basenameWithoutExtension , '.html').
outputFile ensureDelete.
outputFile ensureCreateFile.
OSSUnixSubprocess new
command: 'pandoc';
arguments: {'-f'. 'markdown+startnum+task_lists'. '-t'. 'html'. inputFile fullName.
'--output'. outputFile fullName };
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [ ^ outputFile ]
ifFalse: [ ^ inputFile ]
]
]
{ #category : #converters }
Pandoc class >> markdownToHtmlOnWindows: inputFile [
"ToDo: This command still doesn't receive any arguments."
^ (LibC resultOfCommand: 'pandoc ', inputFile fullName) correctAccentedCharacters.
]

View File

@ -1,178 +1,178 @@
"
I model a work (book, booklet, web page, etc) in Pandoc, its table of contents, its metadata file to
control exportation and other elements.
I can be used to improve reproductibility of published works that use Pandoc.
By default it is supposed that a root folder contains the set of folders, organized by
language (following the ISO 639-1 two letters convetion) where the contents of the work
and their translations are located.
Chapters, subchapters, sections and subsections are contained there as Markdown files
and its order is stated as a ordered dictionary for each language.
A YAML metadata block is used in each file to map translations between files and languages
and other sources, synchronizations and meta data.
"
Class {
#name : #PandocWork,
#superclass : #Object,
#instVars : [
'language',
'contents',
'metadataFiles',
'rootFolder',
'manifests'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #utilities }
PandocWork >> buildManifestFileForLanguage: anISOCode on: aFileName [
"anISOCode is the ISO 639-1 two letters language code"
| manifestFile |
manifestFile := (self rootFolder / anISOCode / 'manifests' / aFileName ) asFileReference ensureCreateFile.
self buildManifestForLanguage: 'es'.
GrafoscopioUtils exportAsSton: (self manifests at: anISOCode) on: manifestFile.
^ manifestFile
]
{ #category : #utlity }
PandocWork >> buildManifestForLanguage: anISOCode [
self
metadataManifestForLanguage: anISOCode;
contentsManifestForLanguage: anISOCode.
^ self manifests
]
{ #category : #accessing }
PandocWork >> contents [
^ contents
]
{ #category : #accessing }
PandocWork >> contents: anOrderedDictionary [
"I model the table of contents of the work.
The key of the dictionary is the folder, inside the language folder (see the language variable)
where the files are stored, and the value is and ordered collection of the files on such folder
which are part ot the exported result, without the file extension (by default is supposed to be '.md')"
contents := anOrderedDictionary
]
{ #category : #utilities }
PandocWork >> contentsManifest [
| checksums |
checksums := OrderedDictionary new.
self contents keysDo: [ :folder |
(self contents at: folder) do: [ :fileName | | keyName contentFile |
keyName := fileName, self defaultFileExtension.
contentFile := self rootFolder / self language / folder / keyName.
checksums at: keyName put: (GrafoscopioUtils checksumFor: contentFile)].
self manifest at: folder put: checksums ].
^ self manifest
]
{ #category : #utilities }
PandocWork >> contentsManifestForLanguage: anISOCode [
| checksums |
checksums := OrderedDictionary new.
self contents keysDo: [ :folder |
(self contents at: folder) do: [ :fileName | | keyName contentFile |
keyName := fileName, self defaultFileExtension.
contentFile := self rootFolder / anISOCode / folder / keyName.
checksums at: keyName put: (GrafoscopioUtils checksumFor: contentFile)].
(self manifestForLanguage: anISOCode)
add: {folder -> checksums} asOrderedDictionary ].
^ self manifests at: anISOCode
]
{ #category : #utilities }
PandocWork >> defaultFileExtension [
^ '.md'
]
{ #category : #accessing }
PandocWork >> language [
^ language
]
{ #category : #accessing }
PandocWork >> language: aISOLangString [
"I model the lanaguage of a work as a ISO 639-1 two letters string.
I used to stablish the folder where the content is stored, following the convention a folder
by language."
language := aISOLangString
]
{ #category : #utlity }
PandocWork >> manifestForLanguage: anISOCode [
self manifests at: anISOCode ifAbsent: [
self manifests
at: anISOCode put: OrderedCollection new;
yourself].
^ self manifests at: anISOCode
]
{ #category : #accessing }
PandocWork >> manifests [
^ manifests ifNil: [ ^ manifests := OrderedDictionary new ]
]
{ #category : #accessing }
PandocWork >> manifests: anOrderedDictionary [
manifests := anOrderedDictionary
]
{ #category : #accessing }
PandocWork >> metadataFiles [
^ metadataFiles
]
{ #category : #accessing }
PandocWork >> metadataFiles: aCollection [
"I model the YAML metadata files that are used to control the output of the exportation.
I can have several files, controlling several outputs, one for PDF, one for HTML, one for EPUB
and so on.
This should be stated in the name of the metadatafile and by default will be controlling PDF
output."
metadataFiles := aCollection
]
{ #category : #utilities }
PandocWork >> metadataManifest [
| languageFolder |
languageFolder := self language.
"Could the similar parts of this and contentsManifest be refactored?"
self metadataFiles do: [ :fileName | | contentFile |
contentFile := self rootFolder / languageFolder / fileName.
self manifest at: languageFolder put: {fileName -> (GrafoscopioUtils checksumFor: contentFile)} asOrderedDictionary ].
^ self manifest
]
{ #category : #utilities }
PandocWork >> metadataManifestForLanguage: anISOCode [
"anISOCode is the ISO 639-1 two letters language code"
"Could the similar parts of this and contentsManifest be refactored?"
self metadataFiles do: [ :fileName | | contentFile |
contentFile := self rootFolder / anISOCode / fileName.
(self manifestForLanguage: anISOCode)
add: {fileName -> (GrafoscopioUtils checksumFor: contentFile)} asOrderedDictionary].
^ self manifests at: anISOCode
]
{ #category : #accessing }
PandocWork >> rootFolder [
^ rootFolder
]
{ #category : #accessing }
PandocWork >> rootFolder: aFileReference [
"I model the folder where the Markdown files are located."
rootFolder := aFileReference
]
"
I model a work (book, booklet, web page, etc) in Pandoc, its table of contents, its metadata file to
control exportation and other elements.
I can be used to improve reproductibility of published works that use Pandoc.
By default it is supposed that a root folder contains the set of folders, organized by
language (following the ISO 639-1 two letters convetion) where the contents of the work
and their translations are located.
Chapters, subchapters, sections and subsections are contained there as Markdown files
and its order is stated as a ordered dictionary for each language.
A YAML metadata block is used in each file to map translations between files and languages
and other sources, synchronizations and meta data.
"
Class {
#name : #PandocWork,
#superclass : #Object,
#instVars : [
'language',
'contents',
'metadataFiles',
'rootFolder',
'manifests'
],
#category : #'Grafoscopio-Utils'
}
{ #category : #utilities }
PandocWork >> buildManifestFileForLanguage: anISOCode on: aFileName [
"anISOCode is the ISO 639-1 two letters language code"
| manifestFile |
manifestFile := (self rootFolder / anISOCode / 'manifests' / aFileName ) asFileReference ensureCreateFile.
self buildManifestForLanguage: 'es'.
GrafoscopioUtils exportAsSton: (self manifests at: anISOCode) on: manifestFile.
^ manifestFile
]
{ #category : #utlity }
PandocWork >> buildManifestForLanguage: anISOCode [
self
metadataManifestForLanguage: anISOCode;
contentsManifestForLanguage: anISOCode.
^ self manifests
]
{ #category : #accessing }
PandocWork >> contents [
^ contents
]
{ #category : #accessing }
PandocWork >> contents: anOrderedDictionary [
"I model the table of contents of the work.
The key of the dictionary is the folder, inside the language folder (see the language variable)
where the files are stored, and the value is and ordered collection of the files on such folder
which are part ot the exported result, without the file extension (by default is supposed to be '.md')"
contents := anOrderedDictionary
]
{ #category : #utilities }
PandocWork >> contentsManifest [
| checksums |
checksums := OrderedDictionary new.
self contents keysDo: [ :folder |
(self contents at: folder) do: [ :fileName | | keyName contentFile |
keyName := fileName, self defaultFileExtension.
contentFile := self rootFolder / self language / folder / keyName.
checksums at: keyName put: (GrafoscopioUtils checksumFor: contentFile)].
self manifest at: folder put: checksums ].
^ self manifest
]
{ #category : #utilities }
PandocWork >> contentsManifestForLanguage: anISOCode [
| checksums |
checksums := OrderedDictionary new.
self contents keysDo: [ :folder |
(self contents at: folder) do: [ :fileName | | keyName contentFile |
keyName := fileName, self defaultFileExtension.
contentFile := self rootFolder / anISOCode / folder / keyName.
checksums at: keyName put: (GrafoscopioUtils checksumFor: contentFile)].
(self manifestForLanguage: anISOCode)
add: {folder -> checksums} asOrderedDictionary ].
^ self manifests at: anISOCode
]
{ #category : #utilities }
PandocWork >> defaultFileExtension [
^ '.md'
]
{ #category : #accessing }
PandocWork >> language [
^ language
]
{ #category : #accessing }
PandocWork >> language: aISOLangString [
"I model the lanaguage of a work as a ISO 639-1 two letters string.
I used to stablish the folder where the content is stored, following the convention a folder
by language."
language := aISOLangString
]
{ #category : #utlity }
PandocWork >> manifestForLanguage: anISOCode [
self manifests at: anISOCode ifAbsent: [
self manifests
at: anISOCode put: OrderedCollection new;
yourself].
^ self manifests at: anISOCode
]
{ #category : #accessing }
PandocWork >> manifests [
^ manifests ifNil: [ ^ manifests := OrderedDictionary new ]
]
{ #category : #accessing }
PandocWork >> manifests: anOrderedDictionary [
manifests := anOrderedDictionary
]
{ #category : #accessing }
PandocWork >> metadataFiles [
^ metadataFiles
]
{ #category : #accessing }
PandocWork >> metadataFiles: aCollection [
"I model the YAML metadata files that are used to control the output of the exportation.
I can have several files, controlling several outputs, one for PDF, one for HTML, one for EPUB
and so on.
This should be stated in the name of the metadatafile and by default will be controlling PDF
output."
metadataFiles := aCollection
]
{ #category : #utilities }
PandocWork >> metadataManifest [
| languageFolder |
languageFolder := self language.
"Could the similar parts of this and contentsManifest be refactored?"
self metadataFiles do: [ :fileName | | contentFile |
contentFile := self rootFolder / languageFolder / fileName.
self manifest at: languageFolder put: {fileName -> (GrafoscopioUtils checksumFor: contentFile)} asOrderedDictionary ].
^ self manifest
]
{ #category : #utilities }
PandocWork >> metadataManifestForLanguage: anISOCode [
"anISOCode is the ISO 639-1 two letters language code"
"Could the similar parts of this and contentsManifest be refactored?"
self metadataFiles do: [ :fileName | | contentFile |
contentFile := self rootFolder / anISOCode / fileName.
(self manifestForLanguage: anISOCode)
add: {fileName -> (GrafoscopioUtils checksumFor: contentFile)} asOrderedDictionary].
^ self manifests at: anISOCode
]
{ #category : #accessing }
PandocWork >> rootFolder [
^ rootFolder
]
{ #category : #accessing }
PandocWork >> rootFolder: aFileReference [
"I model the folder where the Markdown files are located."
rootFolder := aFileReference
]

View File

@ -1,35 +1,38 @@
Extension { #name : #String }
{ #category : #'*Grafoscopio-Utils' }
String >> asCapitalizedPhrase [
"I convert phrases like 'THIS IS A PHRASE' into 'This is a Phrase'."
^ Character space join: (self substrings collect: [:each | each asLowercase capitalized ])
]
{ #category : #'*Grafoscopio-Utils' }
String >> asDashedLowercase [
"I convert phrases like 'This is a phrase' into 'this-is-a-phrase'."
^ '-' join: (self substrings collect: [:each | each asLowercase ])
]
{ #category : #'*Grafoscopio-Utils' }
String >> correctAccentedCharacters [
| output |
output := self
copyReplaceAll: 'ó' with: 'ó'.
output := output copyReplaceAll: 'á' with: 'á'.
output := output copyReplaceAll: 'é' with: 'é'.
output := output copyReplaceAll: 'í' with: 'í'.
output := output copyReplaceAll: 'ú' with: 'ú'.
^ output
]
{ #category : #'*Grafoscopio-Utils' }
String >> isOrgModeHeader [
^ self beginsWithAnyOf: #('* ' '** ' '*** ' '**** ' '***** ' '***** ')
]
Extension { #name : #String }
{ #category : #'*Grafoscopio-Utils' }
String >> asCapitalizedPhrase [
"I convert phrases like 'THIS IS A PHRASE' into 'This is a Phrase'."
^ Character space join: (self substrings collect: [:each | each asLowercase capitalized ])
]
{ #category : #'*Grafoscopio-Utils' }
String >> asDashedLowercase [
"I convert phrases like 'This is a phrase' into 'this-is-a-phrase'."
^ '-' join: (self substrings collect: [:each | each asLowercase ])
]
{ #category : #'*Grafoscopio-Utils' }
String >> correctAccentedCharacters [
| output |
output := self
copyReplaceAll: 'ó' with: 'ó'.
output := output copyReplaceAll: 'á' with: 'á'.
output := output copyReplaceAll: 'é' with: 'é'.
output := output copyReplaceAll: 'í' with: 'í'.
output := output copyReplaceAll: 'ú' with: 'ú'.
output := output copyReplaceAll: 'ñ' with: 'ñ'.
output := output copyReplaceAll: '“' with: '“'.
output := output copyReplaceAll: '”' with: '”'.
^ output
]
{ #category : #'*Grafoscopio-Utils' }
String >> isOrgModeHeader [
^ self beginsWithAnyOf: #('* ' '** ' '*** ' '**** ' '***** ' '***** ')
]

View File

@ -1 +1 @@
Package { #name : #'Grafoscopio-Utils' }
Package { #name : #'Grafoscopio-Utils' }