Compare commits

..

No commits in common. "master" and "Windows" have entirely different histories.

17 changed files with 1140 additions and 1188 deletions

View File

@ -16,27 +16,42 @@ BaselineOfBrea >> baseline: spec [
for: #common
do: [
"Dependencies"
self miniDocs: spec.
self grafoscopioUtils: spec.
spec
baseline: 'TaskIt' with: [ spec repository: 'github://pharo-contributions/taskit:v1.0' ]
"[ spec repository: 'github://noha/taskit:add-all-future' ]"
"Disabling Noha's Fork to make Brea installable.".
baseline: 'NeoJSON' with: [ spec repository: 'github://svenvc/NeoJSON/repository' ];
baseline: 'Mustache' with: [ spec repository: 'github://noha/mustache/repository' ];
baseline: 'TaskIt' with: [ spec repository: 'github://noha/taskit:add-all-future' ].
"Packages"
spec package: 'Brea' with: [ spec requires: #('MiniDocs' 'TaskIt') ].
spec package: 'Brea' with: [ spec requires: #('NeoJSON' 'Mustache' 'TaskIt' 'Grafoscopio-Utils') ].
]
]
{ #category : #baselines }
BaselineOfBrea >> miniDocs: spec [
| repo |
repo := ExoRepo new
repository: 'https://code.tupale.co/Offray/MiniDocs'.
repo
onConflict: [ :ex | ex useLoaded ];
onUpgrade: [ :ex | ex useLoaded ];
onDowngrade: [ :ex | ex useLoaded ];
onWarningLog;
BaselineOfBrea >> grafoscopioUtils: spec [
"I load the configuration of this package using a external Gitea repository."
"While more Git independient providers are implemented in Monticello, I will use Iceberg
to download the repository and load it from a local directory"
| location localRepo |
"Dependencies"
"Local and remote repo definition"
location := FileLocator localDirectory / 'iceberg' / 'Offray' / 'GrafoscopioUtils'.
location exists ifFalse: [
(IceRepositoryCreator new
location: location;
remote: (IceGitRemote url: 'https://code.tupale.co/Offray/GrafoscopioUtils.git');
createRepository)
register
].
"Package loading"
localRepo := 'gitlocal://', location fullName.
Metacello new
repository: localRepo;
baseline: 'GrafoscopioUtils';
load.
spec baseline: 'MiniDocs' with: [ spec repository: 'gitlocal://', repo local fullName ]
spec baseline: 'GrafoscopioUtils' with: [ spec repository: localRepo ].
spec package: 'Grafoscopio-Utils' with: [ spec repository: localRepo ].
]

View File

@ -1,204 +1,203 @@
"
A BreaPageTest is a test class for testing the behavior of BreaPage
"
Class {
#name : #BreaPageTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}
{ #category : #initialization }
BreaPageTest >> createHTMLTemplateFile [
| testFile contents |
testFile := FileLocator temp / 'template.mus.html'.
testFile ensureCreateFile.
contents :=
'<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
<p>
{{#show}} You should see me. {{/show}}
</p>
<p>
{{#unhide}} You should not see me. {{/unhide}}
</p>
{{{ contents }}}
</body>
</html>'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #initialization }
BreaPageTest >> createJSONFile [
| testFile contents |
testFile := self jsonTestFile.
testFile ensureCreateFile.
contents := '{ "title": "This is a test", "show": true, "unhide": false }'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #initialization }
BreaPageTest >> createMarkdownFile [
| testFile contents |
testFile := self markdownTestFile.
testFile ensureCreateFile.
contents :=
'---
title: This is a test
show: true
unhide: false
---
# Level one header
And paragraph contents with _emphasis_ and **strong emphasis**.'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> htmlBodyContents [
^ '<h1 id="level-one-header">Level one header</h1>
<p>And paragraph contents with <em>emphasis</em> and <strong>strong emphasis</strong>.</p>
'
]
{ #category : #'as yet unclassified' }
BreaPageTest >> htmlOutput [
^ '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>This is a test</title>
</head>
<body>
<h1>This is a test</h1>
<p>
You should see me.
</p>
<p>
</p>
', self htmlBodyContents,
'
</body>
</html>'
]
{ #category : #'as yet unclassified' }
BreaPageTest >> jsonTestFile [
^ FileLocator temp / 'test1.json'.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> markdownTestFile [
^ FileLocator temp / 'test.md'.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> setUp [
"I create disposable simple files for testing purposes."
super setUp.
self createMarkdownFile.
self createHTMLTemplateFile.
self createJSONFile
]
{ #category : #tests }
BreaPageTest >> testJSONMetadataExtraction [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test1';
folder: FileLocator temp.
self assert: page metadata equals: testMetadata
]
{ #category : #tests }
BreaPageTest >> testJSONPopulateMetadata [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test1';
folder: FileLocator temp.
page templateData at: 'extra' put: 'value'.
self assert: page populateMetadata equals: (testMetadata at: 'extra' put: 'value'; yourself)
]
{ #category : #tests }
BreaPageTest >> testMarkdownContentExtraction [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
self assert: page contents equals: self markdownTestFile contents.
]
{ #category : #tests }
BreaPageTest >> testMarkdownHTMLExport [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp;
template: 'template.mus.html';
bodyTag: 'contents'.
self assert: (page exportAsHTML contents) equals: self htmlOutput.
]
{ #category : #tests }
BreaPageTest >> testMarkdownMetadataExtraction [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
self assert: page metadata equals: testMetadata
]
{ #category : #tests }
BreaPageTest >> testMarkdownPopulateBody [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp;
bodyTag: 'contents'.
page populateTaggedBody.
self assert: (page templateData at: 'contents') equals: self htmlBodyContents.
]
{ #category : #tests }
BreaPageTest >> testMarkdownPopulateMetadata [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
page templateData at: 'extra' put: 'value'.
self assert: page populateMetadata equals: (testMetadata at: 'extra' put: 'value'; yourself)
]
"
A BreaPageTest is a test class for testing the behavior of BreaPage
"
Class {
#name : #BreaPageTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}
{ #category : #initialization }
BreaPageTest >> createHTMLTemplateFile [
| testFile contents |
testFile := FileLocator temp / 'template.mus.html'.
testFile ensureCreateFile.
contents :=
'<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
<p>
{{#show}} You should see me. {{/show}}
</p>
<p>
{{#unhide}} You should not see me. {{/unhide}}
</p>
{{{ contents }}}
</body>
</html>'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #initialization }
BreaPageTest >> createJSONFile [
| testFile contents |
testFile := self jsonTestFile.
testFile ensureCreateFile.
contents := '{ "title": "This is a test", "show": true, "unhide": false }'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #initialization }
BreaPageTest >> createMarkdownFile [
| testFile contents |
testFile := self markdownTestFile.
testFile ensureCreateFile.
contents :=
'---
title: This is a test
show: true
unhide: false
---
# Level one header
And paragraph contents with _emphasis_ and **strong emphasis**.'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> htmlBodyContents [
^ '<h1 id="level-one-header">Level one header</h1>
<p>And paragraph contents with <em>emphasis</em> and <strong>strong emphasis</strong>.</p>
'
]
{ #category : #'as yet unclassified' }
BreaPageTest >> htmlOutput [
^ '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>This is a test</title>
</head>
<body>
<h1>This is a test</h1>
<p>
You should see me.
</p>
<p>
</p>
', self htmlBodyContents,
'
</body>
</html>'
]
{ #category : #'as yet unclassified' }
BreaPageTest >> jsonTestFile [
^ FileLocator temp / 'test1.json'.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> markdownTestFile [
^ FileLocator temp / 'test.md'.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> setUp [
"I create disposable simple files for testing purposes."
super setUp.
self createMarkdownFile.
self createHTMLTemplateFile.
]
{ #category : #tests }
BreaPageTest >> testJSONMetadataExtraction [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test1';
folder: FileLocator temp.
self assert: page metadata equals: testMetadata
]
{ #category : #tests }
BreaPageTest >> testJSONPopulateMetadata [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test1';
folder: FileLocator temp.
page templateData at: 'extra' put: 'value'.
self assert: page populateMetadata equals: (testMetadata at: 'extra' put: 'value'; yourself)
]
{ #category : #tests }
BreaPageTest >> testMarkdownContentExtraction [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
self assert: page contents equals: self markdownTestFile contents.
]
{ #category : #tests }
BreaPageTest >> testMarkdownHTMLExport [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp;
template: 'template.mus.html';
bodyTag: 'contents'.
self assert: (page exportAsHTML contents) equals: self htmlOutput.
]
{ #category : #tests }
BreaPageTest >> testMarkdownMetadataExtraction [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
self assert: page metadata equals: testMetadata
]
{ #category : #tests }
BreaPageTest >> testMarkdownPopulateBody [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp;
bodyTag: 'contents'.
page populateTaggedBody.
self assert: (page templateData at: 'contents') equals: self htmlBodyContents.
]
{ #category : #tests }
BreaPageTest >> testMarkdownPopulateMetadata [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
page templateData at: 'extra' put: 'value'.
self assert: page populateMetadata equals: (testMetadata at: 'extra' put: 'value'; yourself)
]

View File

@ -1,21 +1,21 @@
"
A BreaQueryTest is a test class for testing the behavior of BreaQuery
"
Class {
#name : #BreaOperatorTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}
{ #category : #tests }
BreaOperatorTest >> testSTONSerialization [
| original store deserialized |
original := BreaOperator new
name: 'plus';
inputs: {'a' -> 3. 'b' -> 4} asDictionary;
codeBlock: [ :x :y | x + y ].
store := STON toString: original.
deserialized := (STONReader on: store readStream) next.
self assert: original execute equals: deserialized execute
]
"
A BreaQueryTest is a test class for testing the behavior of BreaQuery
"
Class {
#name : #BreaQueryTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}
{ #category : #tests }
BreaQueryTest >> testSTONSerialization [
| original store deserialized |
original := BreaQuery new
name: 'plus';
inputs: {'a' -> 3. 'b' -> 4} asDictionary;
codeBlock: [ :x :y | x + y ].
store := STON toString: original.
deserialized := (STONReader on: store readStream) next.
self assert: original execute equals: deserialized execute
]

View File

@ -1 +1 @@
Package { #name : #'Brea-Tests' }
Package { #name : #'Brea-Tests' }

View File

@ -0,0 +1,51 @@
"
I model an Airtable (https://airtable.com/) database (or Base as they call it).
"
Class {
#name : #Airtable,
#superclass : #Object,
#instVars : [
'id',
'apiKey'
],
#category : #Brea
}
{ #category : #accessing }
Airtable >> apiKey [
^ apiKey
]
{ #category : #accessing }
Airtable >> apiKey: aString [
apiKey := aString
]
{ #category : #accessing }
Airtable >> id [
^ id
]
{ #category : #accessing }
Airtable >> id: aString [
id := aString
]
{ #category : #'as yet unclassified' }
Airtable >> rawRecords [
(self id isNil or: [ self apiKey isNil ]) ifTrue: [ ^ self ].
^ ZnClient new
url: (self id);
headerAt: 'Authorization' put: 'Bearer ', (self apiKey);
get.
]
{ #category : #'as yet unclassified' }
Airtable >> records [
^ ((NeoJSONReader fromString: (self rawRecords)) at: 'records')
select: [ :each | (each at: 'fields') isNotEmpty ]
]

View File

@ -1,118 +1,118 @@
"
I model information of the items published on Internet Archive (https://archive.org/).
"
Class {
#name : #ArchiveOrgItem,
#superclass : #Object,
#instVars : [
'id',
'metadata'
],
#category : #Brea
}
{ #category : #utility }
ArchiveOrgItem >> archive [
^ 'https://archive.org'
]
{ #category : #utilities }
ArchiveOrgItem >> createHtmlImageGalleryList [
"IMPORTANT: This is just a draft snipped. Should become a proper test o be deleted."
self metadata ifNil: [ self getMetadata ].
^ '
<div id="nanogallery2"
/* gallery settings */
data-nanogallery2 = ''{
"thumbnailHeight": 150,
"thumbnailWidth": 150,
"itemsBaseURL": "', self galleryItemsBaseUrl ,'"
}'' >
<!-- gallery content -->
<a href = "primera 3.jpg" data-ngThumb = "primera 3_thumb.jpg" > </a>
<a href = "segunda.jpg" data-ngThumb = "segunda_thumb.jpg" > </a>
</div>'
]
{ #category : #utilities }
ArchiveOrgItem >> embeddedUrl [
^ 'https://archive.org/embed/', self id.
]
{ #category : #utilities }
ArchiveOrgItem >> galleryItemsBaseUrl [
"I create the place where all image would be located for creating a custom image gallery,
according with the requirements for nanogallery2."
^ 'https://', (self metadata at: 'd2'), (self metadata at: 'dir'), '/'.
]
{ #category : #operation }
ArchiveOrgItem >> getMetadata [
self id ifNil: [ ^ self ].
self metadata: (NeoJSONReader fromString: (self archive, '/metadata/', self id) asUrl retrieveContents)
]
{ #category : #accessing }
ArchiveOrgItem >> id [
^ id
]
{ #category : #accessing }
ArchiveOrgItem >> id: anObject [
id := anObject
]
{ #category : #utilities }
ArchiveOrgItem >> imagesGalleryList [
self metadata ifNil: [ self getMetadata ].
^ (self metadata at: 'files') select: [ :file | (file at: 'format') = 'JPEG Thumb' ]
]
{ #category : #utilities }
ArchiveOrgItem >> imagesGalleryListAsDictionary [
| galleryImages result |
self imagesGalleryList ifNil: [ ^ self ].
galleryImages := OrderedCollection new.
self imagesGalleryList do: [ :imgMetadata |
galleryImages
add: (Dictionary new
at: 'imgOriginal' put: (imgMetadata at: 'original');
at: 'imgThumb' put: (imgMetadata at: 'name');
yourself) ].
result := { 'archiveItemImages' -> galleryImages } asDictionary.
^ result
]
{ #category : #accessing }
ArchiveOrgItem >> metadata [
^ metadata
]
{ #category : #accessing }
ArchiveOrgItem >> metadata: anObject [
metadata := anObject
]
{ #category : #utilities }
ArchiveOrgItem >> subjectTags [
self id ifNil: [ ^ self ].
self metadata ifNil: [ self getMetadata ].
^ (self metadata at: 'metadata') at: 'subject'
]
{ #category : #utilities }
ArchiveOrgItem >> subjectTagsAsDictionary [
| tagList result |
self imagesGalleryList ifNil: [ ^ self ].
tagList := OrderedCollection new.
self subjectTags do: [ :tag |
tagList
add: (Dictionary new
at: 'tag' put: tag;
yourself) ].
result := { 'tagList' -> tagList } asDictionary.
^ result
]
"
I model information of the items published on Internet Archive (https://archive.org/).
"
Class {
#name : #ArchiveOrgItem,
#superclass : #Object,
#instVars : [
'id',
'metadata'
],
#category : #Brea
}
{ #category : #utility }
ArchiveOrgItem >> archive [
^ 'https://archive.org'
]
{ #category : #utilities }
ArchiveOrgItem >> createHtmlImageGalleryList [
"IMPORTANT: This is just a draft snipped. Should become a proper test o be deleted."
self metadata ifNil: [ self getMetadata ].
^ '
<div id="nanogallery2"
/* gallery settings */
data-nanogallery2 = ''{
"thumbnailHeight": 150,
"thumbnailWidth": 150,
"itemsBaseURL": "', self galleryItemsBaseUrl ,'"
}'' >
<!-- gallery content -->
<a href = "primera 3.jpg" data-ngThumb = "primera 3_thumb.jpg" > </a>
<a href = "segunda.jpg" data-ngThumb = "segunda_thumb.jpg" > </a>
</div>'
]
{ #category : #utilities }
ArchiveOrgItem >> embeddedUrl [
^ 'https://archive.org/embed/', self id.
]
{ #category : #utilities }
ArchiveOrgItem >> galleryItemsBaseUrl [
"I create the place where all image would be located for creating a custom image gallery,
according with the requirements for nanogallery2."
^ 'https://', (self metadata at: 'd2'), (self metadata at: 'dir'), '/'.
]
{ #category : #operation }
ArchiveOrgItem >> getMetadata [
self id ifNil: [ ^ self ].
self metadata: (NeoJSONReader fromString: (self archive, '/metadata/', self id) asUrl retrieveContents)
]
{ #category : #accessing }
ArchiveOrgItem >> id [
^ id
]
{ #category : #accessing }
ArchiveOrgItem >> id: anObject [
id := anObject
]
{ #category : #utilities }
ArchiveOrgItem >> imagesGalleryList [
self metadata ifNil: [ self getMetadata ].
^ (self metadata at: 'files') select: [ :file | (file at: 'format') = 'JPEG Thumb' ]
]
{ #category : #utilities }
ArchiveOrgItem >> imagesGalleryListAsDictionary [
| galleryImages result |
self imagesGalleryList ifNil: [ ^ self ].
galleryImages := OrderedCollection new.
self imagesGalleryList do: [ :imgMetadata |
galleryImages
add: (Dictionary new
at: 'imgOriginal' put: (imgMetadata at: 'original');
at: 'imgThumb' put: (imgMetadata at: 'name');
yourself) ].
result := { 'archiveItemImages' -> galleryImages } asDictionary.
^ result
]
{ #category : #accessing }
ArchiveOrgItem >> metadata [
^ metadata
]
{ #category : #accessing }
ArchiveOrgItem >> metadata: anObject [
metadata := anObject
]
{ #category : #utilities }
ArchiveOrgItem >> subjectTags [
self id ifNil: [ ^ self ].
self metadata ifNil: [ self getMetadata ].
^ (self metadata at: 'metadata') at: 'subject'
]
{ #category : #utilities }
ArchiveOrgItem >> subjectTagsAsDictionary [
| tagList result |
self imagesGalleryList ifNil: [ ^ self ].
tagList := OrderedCollection new.
self subjectTags do: [ :tag |
tagList
add: (Dictionary new
at: 'tag' put: tag;
yourself) ].
result := { 'tagList' -> tagList } asDictionary.
^ result
]

View File

@ -1,20 +1,20 @@
Extension { #name : #BlockClosure }
{ #category : #'*Brea' }
BlockClosure class >> fromSton: stonReader [
^ self compilerClass new
source: stonReader parseListSingleton;
evaluate
]
{ #category : #'*Brea' }
BlockClosure >> stonContainSubObjects [
^ false
]
{ #category : #'*Brea' }
BlockClosure >> stonOn: stonWriter [
self isClean
ifTrue: [ stonWriter writeObject: self listSingleton: self printString ]
ifFalse: [ stonWriter error: 'Only clean block can be serialized' ]
]
Extension { #name : #BlockClosure }
{ #category : #'*Brea' }
BlockClosure class >> fromSton: stonReader [
^ self compilerClass new
source: stonReader parseListSingleton;
evaluate
]
{ #category : #'*Brea' }
BlockClosure >> stonContainSubObjects [
^ false
]
{ #category : #'*Brea' }
BlockClosure >> stonOn: stonWriter [
self isClean
ifTrue: [ stonWriter writeObject: self listSingleton: self printString ]
ifFalse: [ stonWriter error: 'Only clean block can be serialized' ]
]

View File

@ -1,104 +0,0 @@
Class {
#name : #BreaApp,
#superclass : #Object,
#instVars : [
'name',
'folder',
'host',
'componets'
],
#category : #Brea
}
{ #category : #accessing }
BreaApp >> add: anObject [
anObject class = String ifFalse: [ ].
self body
nextPutAll: (Pandoc htmlStringToMarkdown: anObject); cr.
]
{ #category : #accessing }
BreaApp >> appName [
^ self name asCamelCase
]
{ #category : #accessing }
BreaApp >> at: key put: anObject [
self components at: key put: anObject.
]
{ #category : #accessing }
BreaApp >> components [
^ componets ifNil: [ componets := OrderedDictionary new]
]
{ #category : #accessing }
BreaApp >> componentsWebView [
| response |
response := '' writeStream.
self components ifEmpty: [ ^ response contents ].
self components valuesDo: [ :component |
response
nextPutAll: component webView; cr
].
^ response contents
]
{ #category : #accessing }
BreaApp >> defaultView [
^ '<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark" />
<link rel="stylesheet" href="css/pico.min.css">
<title>', self name, '</title>
</head>
<body>
<main class="container">
', self componentsWebView,'
</main>
</body>
</html>'
]
{ #category : #accessing }
BreaApp >> folder [
^ folder
]
{ #category : #accessing }
BreaApp >> folder: aFileDirectory [
folder := aFileDirectory
]
{ #category : #accessing }
BreaApp >> name [
^ name
]
{ #category : #accessing }
BreaApp >> name: aString [
name := aString
]
{ #category : #accessing }
BreaApp >> parentFolder: anObject [
self folder: anObject / self name asCamelCase
]
{ #category : #accessing }
BreaApp >> preview [
| defaultRoute |
defaultRoute := 'http://localhost:',self webHost server port asString, '/', self appName.
self webHost
GET: self appName -> [ self defaultView ].
GoogleChrome openWindowOn: defaultRoute
]
{ #category : #accessing }
BreaApp >> webHost [
^ host ifNil: [ host := Teapot allInstances detect: [ :each | each server isRunning ] ifNone: [ host := Teapot on. host server start ]]
]

View File

@ -1,78 +1,78 @@
"
I model the file where contents (data and/or metadata) for the Brea CSM pages are stored.
"
Class {
#name : #BreaFile,
#superclass : #Object,
#instVars : [
'folder',
'name'
],
#category : #Brea
}
{ #category : #'instance creation' }
BreaFile class >> fromShortName: nameString andFolder: aFileLocation [
"I create a new BreaFile assigning priorities to the filename discovery according to
their extension currently present in a particular folder."
| extensions |
extensions := #('md' 'json' 'yaml').
extensions do: [ :ext | | markupFile filename |
filename := nameString, '.', ext.
markupFile := aFileLocation / filename.
markupFile exists ifTrue: [ ^ self new name: filename; folder: aFileLocation ].
].
^ nil.
]
{ #category : #accessing }
BreaFile >> contentString [
self name ifNil: [ ^ nil ].
(self name endsWith: '.md') ifTrue: [ ^ self contents contents ].
(self name endsWith: '.json') ifTrue: [ ^ self contents asString ].
]
{ #category : #accessing }
BreaFile >> contents [
| file |
self name ifNil: [ ^ nil ].
file := self folder / self name.
(self name endsWith: '.md') ifTrue: [ ^ Markdown fromFile: file ].
(self name endsWith: '.json') ifTrue: [ ^ NeoJSONObject fromString: file contents ]
]
{ #category : #accessing }
BreaFile >> file [
self folder ifNil: [ ^ self ].
self name ifNil: [ ^ self ].
^ self folder / self name.
]
{ #category : #accessing }
BreaFile >> folder [
^ folder
]
{ #category : #accessing }
BreaFile >> folder: anObject [
folder := anObject
]
{ #category : #accessing }
BreaFile >> metadata [
self name ifNil: [ ^ nil ].
(self name endsWith: '.md') ifTrue: [ ^ self contents metadata ].
(self name endsWith: '.json') ifTrue: [ ^ self contents asDictionary ].
]
{ #category : #accessing }
BreaFile >> name [
^ name
]
{ #category : #accessing }
BreaFile >> name: anObject [
name := anObject
]
"
I model the file where contents (data and/or metadata) for the Brea CSM pages are stored.
"
Class {
#name : #BreaFile,
#superclass : #Object,
#instVars : [
'folder',
'name'
],
#category : #Brea
}
{ #category : #'instance creation' }
BreaFile class >> fromShortName: nameString andFolder: aFileLocation [
"I create a new BreaFile assigning priorities to the filename discovery according to
their extension currently present in a particular folder."
| extensions |
extensions := #('md' 'json' 'yaml').
extensions do: [ :ext | | markupFile filename |
filename := nameString, '.', ext.
markupFile := aFileLocation / filename.
markupFile exists ifTrue: [ ^ self new name: filename; folder: aFileLocation ].
].
^ nil.
]
{ #category : #accessing }
BreaFile >> contentString [
self name ifNil: [ ^ nil ].
(self name endsWith: '.md') ifTrue: [ ^ self contents contents ].
(self name endsWith: '.json') ifTrue: [ ^ self contents asString ].
]
{ #category : #accessing }
BreaFile >> contents [
| file |
self name ifNil: [ ^ nil ].
file := self folder / self name.
(self name endsWith: '.md') ifTrue: [ ^ Markdown fromFile: file ].
(self name endsWith: '.json') ifTrue: [ ^ NeoJSONObject fromString: file contents ]
]
{ #category : #accessing }
BreaFile >> file [
self folder ifNil: [ ^ self ].
self name ifNil: [ ^ self ].
^ self folder / self name.
]
{ #category : #accessing }
BreaFile >> folder [
^ folder
]
{ #category : #accessing }
BreaFile >> folder: anObject [
folder := anObject
]
{ #category : #accessing }
BreaFile >> metadata [
self name ifNil: [ ^ nil ].
(self name endsWith: '.md') ifTrue: [ ^ self contents metadata ].
(self name endsWith: '.json') ifTrue: [ ^ self contents asDictionary ].
]
{ #category : #accessing }
BreaFile >> name [
^ name
]
{ #category : #accessing }
BreaFile >> name: anObject [
name := anObject
]

View File

@ -1,255 +1,262 @@
"
I model a wiki page of a Brea site.
I am modelled after common wiki pages, where a document in a light markup laguage
is converted in HTML and is expected to access document history (I am helped by
FossilRepo for that).
I can be used for other types of publications, like blog post though.
"
Class {
#name : #BreaPage,
#superclass : #Object,
#instVars : [
'shortName',
'template',
'templateData',
'bodyTag',
'splitters',
'subpages',
'metadata',
'folder',
'file'
],
#category : #Brea
}
{ #category : #operation }
BreaPage >> bodyContentsAsHTML [
| sourcePage commandParameters |
self contentsFile ifNil: [ ^ self ].
sourcePage := self file file.
Smalltalk os isWindows ifTrue: [
^ Pandoc markdownToHtml: sourcePage
].
commandParameters := ' -f markdown+startnum+task_lists -t html '.
^ GtSubprocessWithInMemoryOutput new
shellCommand: 'pandoc', commandParameters, sourcePage fullName;
runAndWait;
stdout.
]
{ #category : #accessing }
BreaPage >> bodyTag [
^ bodyTag
]
{ #category : #accessing }
BreaPage >> bodyTag: aString [
"I represent the Mustache Template tag used to denote the body part of a page.
While the metadata is self describing via YAML metadata blocks in Markddown, so
they map where ever they are needed in a template, the Markdown file that will be converted
in HTML via a template doesn't know which part should occupy once the conversion is done.
I provide such knowledge. So if a page template puts the body content under the mustache tag
{{content}}, I should use bodyTag: 'content'.
bodyTag: is template dependant."
bodyTag := aString
]
{ #category : #accessing }
BreaPage >> contents [
| result |
self contentsFile ifNil: [ ^ nil ].
result := '' writeStream.
result nextPutAll: self contentsFile contentString.
self subpages ifNotNil: [
self subpages do: [ :sp | | markdownTempFile |
markdownTempFile := self folder / (sp, '.md').
result nextPutAll: (Markdown fromFile: markdownTempFile) contents.
]
].
^ result contents withInternetLineEndings.
]
{ #category : #operation }
BreaPage >> contentsFile [
self folder ifNil: [ ^ self ].
self shortName ifNil: [ ^ self ].
^ BreaFile fromShortName: self shortName andFolder: self folder.
]
{ #category : #'as yet unclassified' }
BreaPage >> exportAsHTML [
| htmlContents allActions actionsArray semaphore result |
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
actionsArray := { [ self populateMetadata ] future. }.
self splitters ifNotEmpty: [ actionsArray := actionsArray copyWith: [ self split ] future ].
self bodyTag ifNotNil: [
actionsArray := actionsArray copyWith: [ self populateBodyAs: self bodyTag ] future ].
allActions := TKTFuture fromCollectionOfFutures: actionsArray.
semaphore := Semaphore new.
allActions onSuccessDo: [ :values |
result := values last.
semaphore signal.
].
semaphore wait.
htmlContents := (MustacheTemplate on: result templateFile contents) value: result templateData.
^ MarkupFile exportAsFileOn: self folder / (self shortName, '.html' ) containing: htmlContents
]
{ #category : #accessing }
BreaPage >> file [
(self shortName isNil or: [ self folder isNil ]) ifTrue: [ ^ nil ].
^ file ifNil: [ ^ BreaFile fromShortName: self shortName andFolder: self folder ]
]
{ #category : #accessing }
BreaPage >> file: anObject [
file := anObject
]
{ #category : #accessing }
BreaPage >> folder [
^ folder
]
{ #category : #accessing }
BreaPage >> folder: folderFileReference [
folder := folderFileReference
]
{ #category : #'as yet unclassified' }
BreaPage >> htmlContents [
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ (MustacheTemplate on: self templateFile contents) value: self templateData.
]
{ #category : #accessing }
BreaPage >> metadata [
^ metadata ifNil: [ self contentsFile metadata ]
]
{ #category : #accessing }
BreaPage >> metadata: aDictionary [
"External place where page metadata is located (on Internet or the local file system) in JSON format.
If nil, is suposed that is placed in the Markdown file with the page contents."
metadata := aDictionary
]
{ #category : #'as yet unclassified' }
BreaPage >> populateBodyAs: key [
self templateData at: key put: self bodyContentsAsHTML.
^ self.
]
{ #category : #'as yet unclassified' }
BreaPage >> populateExternalMetadata [
self metadata ifNil: [ ^ self ].
self
]
{ #category : #operation }
BreaPage >> populateMetadata [
| metadataTemp |
self metadata
ifNotNil: [ metadataTemp := self metadata ]
ifNil: [ metadataTemp := self contentsFile metadata].
metadataTemp keysAndValuesDo: [ :key :value |
self templateData at: key put: value ].
^ self templateData
]
{ #category : #operation }
BreaPage >> populateTaggedBody [
self bodyTag ifNil: [ ^ self ].
^ self populateBodyAs: self bodyTag.
]
{ #category : #accessing }
BreaPage >> shortName [
^ shortName
]
{ #category : #accessing }
BreaPage >> shortName: aString [
"The name of the file tha contains the light markup to produce the web page, without file extension.
By default I work with Markdown files."
shortName := aString
]
{ #category : #'as yet unclassified' }
BreaPage >> split [
self splitters ifEmpty: [ ^ self ].
self splitters keysAndValuesDo: [ :key :value | self split: key with: value ].
]
{ #category : #'as yet unclassified' }
BreaPage >> split: key with: subkey [
"I split a comma separated collection of subkeys stored in the 'key' field and name each one as 'subkey'
to put it indiviudally in a Mustache template."
| allSubkeys cleaned data |
allSubkeys := (self populateMetadata at: key) splitOn: ','.
cleaned := allSubkeys collect: [ :item | item withBlanksCondensed ].
data := OrderedCollection new.
cleaned do: [ :item |
data add: { subkey -> item } asDictionary ].
self populateMetadata at: key put: data; yourself.
]
{ #category : #'as yet unclassified' }
BreaPage >> splitterAt: key with: subkey [
self splitters at: key put: subkey
]
{ #category : #accessing }
BreaPage >> splitters [
^ splitters ifNil: [ splitters := Dictionary new ]
]
{ #category : #accessing }
BreaPage >> splitters: aDictionary [
"I model the pattern where a Mustache template contains something like
{{# key}} {{value}} {{/ key}} and has data that needs to be split before injecting it in the template."
splitters := aDictionary
]
{ #category : #accessing }
BreaPage >> subpages [
^ subpages
]
{ #category : #accessing }
BreaPage >> subpages: shortNamesList [
"I am used when a page is composed of other subpages (for example with link aliases) that are shared
accross several pages."
subpages := shortNamesList
]
{ #category : #accessing }
BreaPage >> template [
^ template
]
{ #category : #accessing }
BreaPage >> template: mustacheFileName [
"Usually templates and their pages are located in the same folder."
template := mustacheFileName
]
{ #category : #accessing }
BreaPage >> templateData [
^ templateData ifNil: [ templateData := Dictionary new ]
]
{ #category : #accessing }
BreaPage >> templateData: aDictionary [
templateData := aDictionary
]
{ #category : #'as yet unclassified' }
BreaPage >> templateFile [
self folder ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ self folder / self template
]
"
I model a wiki page of a Brea site.
I am modelled after common wiki pages, where a document in a light markup laguage
is converted in HTML and is expected to access document history (I am helped by
FossilRepo for that).
I can be used for other types of publications, like blog post though.
"
Class {
#name : #BreaPage,
#superclass : #Object,
#instVars : [
'shortName',
'template',
'templateData',
'bodyTag',
'splitters',
'subpages',
'metadata',
'folder',
'file'
],
#category : #Brea
}
{ #category : #operation }
BreaPage >> bodyContentsAsHTML [
| sourcePage |
self contentsFile ifNil: [ ^ self ].
Smalltalk os isWindows ifTrue: [
^ Pandoc markdownToHtml: self file file
].
sourcePage := FileLocator temp / 'wikiPage.md'.
MarkupFile exportAsFileOn: sourcePage containing: self contents.
^ Pandoc markdownToHtml: sourcePage
]
{ #category : #accessing }
BreaPage >> bodyTag [
^ bodyTag
]
{ #category : #accessing }
BreaPage >> bodyTag: aString [
"I represent the Mustache Template tag used to denote the body part of a page.
While the metadata is self describing via YAML metadata blocks in Markddown, so
they map where ever they are needed in a template, the Markdown file that will be converted
in HTML via a template doesn't know which part should occupy once the conversion is done.
I provide such knowledge. So if a page template puts the body content under the mustache tag
{{content}}, I should use bodyTag: 'content'.
bodyTag: is template dependant."
bodyTag := aString
]
{ #category : #accessing }
BreaPage >> contents [
| result |
self contentsFile ifNil: [ ^ nil ].
result := '' writeStream.
result nextPutAll: self contentsFile contentString.
self subpages ifNotNil: [
self subpages do: [ :sp | | markdownTempFile |
markdownTempFile := self folder / (sp, '.md').
result nextPutAll: (Markdown fromFile: markdownTempFile) contents.
]
].
^ result contents.
]
{ #category : #operation }
BreaPage >> contentsFile [
self folder ifNil: [ ^ self ].
self shortName ifNil: [ ^ self ].
^ BreaFile fromShortName: self shortName andFolder: self folder.
]
{ #category : #'as yet unclassified' }
BreaPage >> exportAsHTML [
| htmlContents allActions actionsArray semaphore result |
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
actionsArray := { [ self populateMetadata ] future. }.
self splitters ifNotEmpty: [ actionsArray := actionsArray copyWith: [ self split ] future ].
self bodyTag ifNotNil: [
actionsArray := actionsArray copyWith: [ self populateBodyAs: self bodyTag ] future ].
allActions := TKTFuture all: actionsArray.
semaphore := Semaphore new.
allActions onSuccessDo: [ :values |
result := values last.
semaphore signal.
].
semaphore wait.
htmlContents := (MustacheTemplate on: result templateFile contents) value: result templateData.
^ MarkupFile exportAsFileOn: self folder / (self shortName, '.html' ) containing: htmlContents
]
{ #category : #accessing }
BreaPage >> file [
(self shortName isNil or: [ self folder isNil ]) ifTrue: [ ^ nil ].
^ file ifNil: [ ^ BreaFile fromShortName: self shortName andFolder: self folder ]
]
{ #category : #accessing }
BreaPage >> file: anObject [
file := anObject
]
{ #category : #accessing }
BreaPage >> folder [
^ folder
]
{ #category : #accessing }
BreaPage >> folder: folderFileReference [
folder := folderFileReference
]
{ #category : #'as yet unclassified' }
BreaPage >> htmlContents [
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ (MustacheTemplate on: self templateFile contents) value: self templateData.
]
{ #category : #accessing }
BreaPage >> metadata [
^ metadata ifNil: [ self contentsFile metadata ]
]
{ #category : #accessing }
BreaPage >> metadata: aDictionary [
"External place where page metadata is located (on Internet or the local file system) in JSON format.
If nil, is suposed that is placed in the Markdown file with the page contents."
metadata := aDictionary
]
{ #category : #'as yet unclassified' }
BreaPage >> populateBodyAs: key [
| allActions result semaphore |
allActions := TKTFuture all: {
[ self bodyContentsAsHTML ] future.
}.
semaphore := Semaphore new.
allActions onSuccessDo: [ :values |
result := values last.
semaphore signal ].
semaphore wait.
self templateData at: key put: result contents.
^ self.
]
{ #category : #'as yet unclassified' }
BreaPage >> populateExternalMetadata [
self metadata ifNil: [ ^ self ].
self
]
{ #category : #operation }
BreaPage >> populateMetadata [
| metadataTemp |
self metadata
ifNotNil: [ metadataTemp := self metadata ]
ifNil: [ metadataTemp := self contentsFile metadata].
metadataTemp keysAndValuesDo: [ :key :value |
self templateData at: key put: value ].
^ templateData
]
{ #category : #operation }
BreaPage >> populateTaggedBody [
self bodyTag ifNil: [ ^ self ].
^ self populateBodyAs: self bodyTag.
]
{ #category : #accessing }
BreaPage >> shortName [
^ shortName
]
{ #category : #accessing }
BreaPage >> shortName: aString [
"The name of the file tha contains the light markup to produce the web page, without file extension.
By default I work with Markdown files."
shortName := aString
]
{ #category : #'as yet unclassified' }
BreaPage >> split [
self splitters ifEmpty: [ ^ self ].
self splitters keysAndValuesDo: [ :key :value | self split: key with: value ].
]
{ #category : #'as yet unclassified' }
BreaPage >> split: key with: subkey [
"I split a comma separated collection of subkeys stored in the 'key' field and name each one as 'subkey'
to put it indiviudally in a Mustache template."
| allSubkeys cleaned data |
allSubkeys := (self populateMetadata at: key) splitOn: ','.
cleaned := allSubkeys collect: [ :item | item withBlanksCondensed ].
data := OrderedCollection new.
cleaned do: [ :item |
data add: { subkey -> item } asDictionary ].
self populateMetadata at: key put: data; yourself.
]
{ #category : #'as yet unclassified' }
BreaPage >> splitterAt: key with: subkey [
self splitters at: key put: subkey
]
{ #category : #accessing }
BreaPage >> splitters [
^ splitters ifNil: [ splitters := Dictionary new ]
]
{ #category : #accessing }
BreaPage >> splitters: aDictionary [
"I model the pattern where a Mustache template contains something like
{{# key}} {{value}} {{/ key}} and has data that needs to be split before injecting it in the template."
splitters := aDictionary
]
{ #category : #accessing }
BreaPage >> subpages [
^ subpages
]
{ #category : #accessing }
BreaPage >> subpages: shortNamesList [
"I am used when a page is composed of other subpages (for example with link aliases) that are shared
accross several pages."
subpages := shortNamesList
]
{ #category : #accessing }
BreaPage >> template [
^ template
]
{ #category : #accessing }
BreaPage >> template: mustacheFileName [
"Usually templates and their pages are located in the same folder."
template := mustacheFileName
]
{ #category : #accessing }
BreaPage >> templateData [
^ templateData ifNil: [ templateData := Dictionary new ]
]
{ #category : #accessing }
BreaPage >> templateData: aDictionary [
templateData := aDictionary
]
{ #category : #'as yet unclassified' }
BreaPage >> templateFile [
self folder ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ self folder / self template
]

View File

@ -1,95 +1,95 @@
"
I represent a operation that can be done on data inputs to produce and output by executing
a code block.
I can be used by BreaThemes to produce outpus reflected in a particular set of theme pages.
- (for bonus points) how to create instances.
One simple example is simply gorgeous.
Internal Representation and Key Implementation Points.
Instance Variables
codeBlock: <Object>
inputs: <Object>
name: <Object>
Implementation Points
"
Class {
#name : #BreaOperator,
#superclass : #Object,
#instVars : [
'name',
'inputs',
'codeBlock',
'cleanedInputs'
],
#category : #Brea
}
{ #category : #converting }
BreaOperator >> asSton [
^ STON toStringPretty: self
]
{ #category : #converting }
BreaOperator >> cleanInputs [
self cleanedInputs ifNil: [ ^ self ].
self cleanedInputs ifTrue: [
self inputs keysAndValuesDo: [ :k :v | | currentValue |
currentValue := self inputs at: k.
self inputs at: k put: currentValue class new
]
].
]
{ #category : #accessing }
BreaOperator >> cleanedInputs [
^ cleanedInputs
]
{ #category : #accessing }
BreaOperator >> cleanedInputs: aBoolean [
"I tell if the inputs should be cleaned when the query is serialized as STON, for
example when they contain sensible information, like API keys or passwords"
cleanedInputs := aBoolean
]
{ #category : #accessing }
BreaOperator >> codeBlock [
^ codeBlock
]
{ #category : #accessing }
BreaOperator >> codeBlock: anObject [
codeBlock := anObject
]
{ #category : #execution }
BreaOperator >> execute [
^ self codeBlock valueWithArguments: self inputs values.
]
{ #category : #accessing }
BreaOperator >> inputs [
^ inputs
]
{ #category : #accessing }
BreaOperator >> inputs: anOrderedDictionary [
inputs := anOrderedDictionary
]
{ #category : #accessing }
BreaOperator >> name [
^ name
]
{ #category : #accessing }
BreaOperator >> name: anObject [
name := anObject
]
"
I represent a operation that can be done on data inputs to produce and output by executing
a code block.
I can be used by BreaThemes to produce outpus reflected in a particular set of theme pages.
- (for bonus points) how to create instances.
One simple example is simply gorgeous.
Internal Representation and Key Implementation Points.
Instance Variables
codeBlock: <Object>
inputs: <Object>
name: <Object>
Implementation Points
"
Class {
#name : #BreaQuery,
#superclass : #Object,
#instVars : [
'name',
'inputs',
'codeBlock',
'cleanedInputs'
],
#category : #Brea
}
{ #category : #converting }
BreaQuery >> asSton [
^ STON toStringPretty: self
]
{ #category : #converting }
BreaQuery >> cleanInputs [
self cleanedInputs ifNil: [ ^ self ].
self cleanedInputs ifTrue: [
self inputs keysAndValuesDo: [ :k :v | | currentValue |
currentValue := self inputs at: k.
self inputs at: k put: currentValue class new
]
].
]
{ #category : #accessing }
BreaQuery >> cleanedInputs [
^ cleanedInputs
]
{ #category : #accessing }
BreaQuery >> cleanedInputs: aBoolean [
"I tell if the inputs should be cleaned when the query is serialized as STON, for
example when they contain sensible information, like API keys or passwords"
cleanedInputs := aBoolean
]
{ #category : #accessing }
BreaQuery >> codeBlock [
^ codeBlock
]
{ #category : #accessing }
BreaQuery >> codeBlock: anObject [
codeBlock := anObject
]
{ #category : #execution }
BreaQuery >> execute [
^ self codeBlock valueWithArguments: self inputs values.
]
{ #category : #accessing }
BreaQuery >> inputs [
^ inputs
]
{ #category : #accessing }
BreaQuery >> inputs: anOrderedDictionary [
inputs := anOrderedDictionary
]
{ #category : #accessing }
BreaQuery >> name [
^ name
]
{ #category : #accessing }
BreaQuery >> name: anObject [
name := anObject
]

View File

@ -1,229 +1,225 @@
"
I model a web theme.
For the Collaborators Part: State my main collaborators and one line about how I interact with them.
Public API and Key Messages
- message one
- message two
- (for bonus points) how to create instances.
One simple example is simply gorgeous.
Internal Representation and Key Implementation Points.
Instance Variables
name: <Object>
preview: <Object>
provider: <Object>
url: <Object>
Implementation Points
"
Class {
#name : #BreaTheme,
#superclass : #Object,
#instVars : [
'name',
'folder',
'provider',
'url',
'preview',
'license',
'operators'
],
#category : #Brea
}
{ #category : #accessing }
BreaTheme class >> availablePacks [
^ self downloadLinks keys
]
{ #category : #utilities }
BreaTheme class >> downloadLinks [
"Keys are the theme names and values are the url where it can be downloaded
as a zip file.
For the moment we work only with HTML5Up themes, but more could be added
and the code should be refactored accordingly."
| result providerUrl |
result := Dictionary new.
providerUrl := 'https://html5up.net'.
result
at: 'Paradigm Shift' put: providerUrl, '/paradigm-shift/download';
at: 'Massively' put: providerUrl, '/massively/download';
at: 'Ethereal' put: providerUrl, '/ethereal/download';
at: 'Story' put: providerUrl, '/story/download';
at: 'Dimension' put: providerUrl, '/dimension/download';
at: 'Editorial' put: providerUrl, '/editorial/download';
at: 'Forty' put: providerUrl, '/forty/download';
at: 'Stellar' put: providerUrl, '/stellar/download';
at: 'Multiverse' put: providerUrl, '/multiverse/download';
at: 'Phantom' put: providerUrl, '/phantom/download';
at: 'Hyperspace' put: providerUrl, '/hyperspace/download';
at: 'Future Imperfect' put: providerUrl, '/future-imperfect/download';
at: 'Solid State' put: providerUrl, '/solid-state/download';
at: 'Identity' put: providerUrl, '/identity/download';
at: 'Lens' put: providerUrl, '/lens/download';
at: 'Fractal' put: providerUrl, '/fractal/download';
at: 'Eventually' put: providerUrl, '/eventually/download';
at: 'Spectral' put: providerUrl, '/spectral/download';
at: 'Phonon' put: providerUrl, '/photon/download';
at: 'Highlights' put: providerUrl, '/highlights/download';
at: 'Landed' put: providerUrl, '/landed/download';
at: 'Strata' put: providerUrl, '/strata/download';
at: 'Read Only' put: providerUrl, '/read-only/download';
at: 'Alpha' put: providerUrl, '/alpha/download';
at: 'Directive' put: providerUrl, '/directive/download';
at: 'Aerial' put: providerUrl, '/aerial/download';
at: 'Twenty' put: providerUrl, '/twenty/download';
at: 'Big Picture' put: providerUrl, '/big-picture/download';
at: 'Tessellate' put: providerUrl, '/tessellate/download';
at: 'Overflow' put: providerUrl, 'overflow/download';
at: 'Prologue' put: providerUrl, '/prologue/download';
at: 'Helios' put: providerUrl, '/helios/download';
at: 'Telephasic' put: providerUrl, '/telephasic/download';
at: 'Strongly Typed' put: providerUrl, '/strongly-typed/download';
at: 'Parallelism' put: providerUrl, '/parallelism/download';
at: 'Escape Velocity' put: providerUrl, '/escape-velocity/download';
at: 'Astral' put: providerUrl, '/astral/download';
at: 'Striped' put: providerUrl, '/striped/download';
at: 'Dopetrope' put: providerUrl, '/dopetrope/download';
at: 'Miniport' put: providerUrl, '/miniport/download';
at: 'TXT' put: providerUrl, '/txt/download';
at: 'Verti' put: providerUrl, '/verti/download';
at: 'Zerofour' put: providerUrl, '/zerofour/download';
at: 'Arcana' put: providerUrl, '/arcana/download';
at: 'Halcyonic' put: providerUrl, '/halcyonic/download';
at: 'Minimaxing' put: providerUrl, '/minimaxing/download'.
^ result
]
{ #category : #operation }
BreaTheme >> addOperator: aBreaQuery [
self operators add: aBreaQuery cleanInputs
]
{ #category : #operation }
BreaTheme >> asSton [
^ STON toStringPretty: self
]
{ #category : #utilities }
BreaTheme >> dashedName [
^ self name asDashedLowercase
]
{ #category : #operation }
BreaTheme >> downloadInto: aFolder [
| tempName zippedFile |
self url ifNil: [ ^ self ].
tempName := self name.
zippedFile := aFolder / self dashedName , 'zip'.
aFolder ensureCreateDirectory.
GrafoscopioUtils
downloadingFrom: self url withMessage: 'Downloading ', tempName, '...' into: zippedFile.
self folder: aFolder.
^ zippedFile
]
{ #category : #accessing }
BreaTheme >> folder [
^ folder
]
{ #category : #accessing }
BreaTheme >> folder: anObject [
folder := anObject
]
{ #category : #installation }
BreaTheme >> installInto: aFolder [
| zippedFile |
self url ifNil: [ ^ self ].
zippedFile := FileLocator temp / 'download'.
zippedFile ensureDelete.
ZnClient new
url: self url;
downloadTo: FileLocator temp.
(ZipArchive new readFrom: zippedFile) extractAllTo: aFolder.
self folder: aFolder.
^ aFolder
]
{ #category : #accessing }
BreaTheme >> license [
^ license
]
{ #category : #accessing }
BreaTheme >> license: anObject [
license := anObject
]
{ #category : #operation }
BreaTheme >> loadConfiguration [
| config |
config := self folder / 'brea.yaml'.
config exists
ifTrue: [ ^ PPYAMLGrammar new parse: config contents ]
ifFalse: [ self inform:
'No configuration file found. A "brea.yaml" file should be located in the theme root folder.
please run "#updateCustomizations" after defining a theme name from the
"BreaTheme availablePacks".
If no configuration is defined for such theme name you can create and empty configuration
file by running "#createBaseConfiguration" and filing out the "brea.yaml" fields.
For more information or help ask at https://t.me/grafoscopio .' ]
]
{ #category : #accessing }
BreaTheme >> name [
^ name ifNil: [ name = 'unamed' ]
]
{ #category : #accessing }
BreaTheme >> name: anObject [
name := anObject
]
{ #category : #accessing }
BreaTheme >> operators [
^ operators ifNil: [ operators := OrderedCollection new ]
]
{ #category : #accessing }
BreaTheme >> operators: cleanedBreaQueriesCollection [
operators := cleanedBreaQueriesCollection
]
{ #category : #accessing }
BreaTheme >> preview [
^ preview
]
{ #category : #accessing }
BreaTheme >> preview: anObject [
preview := anObject
]
{ #category : #accessing }
BreaTheme >> provider [
^ provider
]
{ #category : #accessing }
BreaTheme >> provider: anObject [
provider := anObject
]
{ #category : #accessing }
BreaTheme >> url [
^ url ifNil: [ url := self class downloadLinks at: self name. ]
]
{ #category : #accessing }
BreaTheme >> url: anObject [
url := anObject
]
"
I model a web theme.
For the Collaborators Part: State my main collaborators and one line about how I interact with them.
Public API and Key Messages
- message one
- message two
- (for bonus points) how to create instances.
One simple example is simply gorgeous.
Internal Representation and Key Implementation Points.
Instance Variables
name: <Object>
preview: <Object>
provider: <Object>
url: <Object>
Implementation Points
"
Class {
#name : #BreaTheme,
#superclass : #Object,
#instVars : [
'name',
'folder',
'provider',
'url',
'preview',
'license',
'queries',
'customizations'
],
#category : #Brea
}
{ #category : #accessing }
BreaTheme class >> availablePacks [
^ self downloadLinks keys
]
{ #category : #utilities }
BreaTheme class >> downloadLinks [
"Keys are the theme names and values are the url where it can be downloaded
as a zip file.
For the moment we work only with HTML5Up themes, but more could be added
and the code should be refactored accordingly."
| result providerUrl |
result := Dictionary new.
providerUrl := 'https://html5up.net'.
result
at: 'Paradigm Shift' put: providerUrl, '/paradigm-shift/download';
at: 'Massively' put: providerUrl, '/massively/download';
at: 'Ethereal' put: providerUrl, '/ethereal/download';
at: 'Story' put: providerUrl, '/story/download';
at: 'Dimension' put: providerUrl, '/dimension/download';
at: 'Editorial' put: providerUrl, '/editorial/download';
at: 'Forty' put: providerUrl, '/forty/download';
at: 'Stellar' put: providerUrl, '/stellar/download';
at: 'Multiverse' put: providerUrl, '/multiverse/download';
at: 'Phantom' put: providerUrl, '/phantom/download';
at: 'Hyperspace' put: providerUrl, '/hyperspace/download';
at: 'Future Imperfect' put: providerUrl, '/future-imperfect/download';
at: 'Solid State' put: providerUrl, '/solid-state/download';
at: 'Identity' put: providerUrl, '/identity/download';
at: 'Lens' put: providerUrl, '/lens/download';
at: 'Fractal' put: providerUrl, '/fractal/download';
at: 'Eventually' put: providerUrl, '/eventually/download';
at: 'Spectral' put: providerUrl, '/spectral/download';
at: 'Phonon' put: providerUrl, '/photon/download';
at: 'Highlights' put: providerUrl, '/highlights/download';
at: 'Landed' put: providerUrl, '/landed/download';
at: 'Strata' put: providerUrl, '/strata/download';
at: 'Read Only' put: providerUrl, '/read-only/download';
at: 'Alpha' put: providerUrl, '/alpha/download';
at: 'Directive' put: providerUrl, '/directive/download';
at: 'Aerial' put: providerUrl, '/aerial/download';
at: 'Twenty' put: providerUrl, '/twenty/download';
at: 'Big Picture' put: providerUrl, '/big-picture/download';
at: 'Tessellate' put: providerUrl, '/tessellate/download';
at: 'Overflow' put: providerUrl, 'overflow/download';
at: 'Prologue' put: providerUrl, '/prologue/download';
at: 'Helios' put: providerUrl, '/helios/download';
at: 'Telephasic' put: providerUrl, '/telephasic/download';
at: 'Strongly Typed' put: providerUrl, '/strongly-typed/download';
at: 'Parallelism' put: providerUrl, '/parallelism/download';
at: 'Escape Velocity' put: providerUrl, '/escape-velocity/download';
at: 'Astral' put: providerUrl, '/astral/download';
at: 'Striped' put: providerUrl, '/striped/download';
at: 'Dopetrope' put: providerUrl, '/dopetrope/download';
at: 'Miniport' put: providerUrl, '/miniport/download';
at: 'TXT' put: providerUrl, '/txt/download';
at: 'Verti' put: providerUrl, '/verti/download';
at: 'Zerofour' put: providerUrl, '/zerofour/download';
at: 'Arcana' put: providerUrl, '/arcana/download';
at: 'Halcyonic' put: providerUrl, '/halcyonic/download';
at: 'Minimaxing' put: providerUrl, '/minimaxing/download'.
^ result
]
{ #category : #operation }
BreaTheme >> addQuery: aBreaQuery [
self queries add: aBreaQuery cleanInputs
]
{ #category : #operation }
BreaTheme >> asSton [
^ STON toStringPretty: self
]
{ #category : #utilities }
BreaTheme >> dashedName [
^ self name asDashedLowercase
]
{ #category : #operation }
BreaTheme >> downloadInto: aFolder [
| tempName zippedFile |
self url ifNil: [ ^ self ].
tempName := self name.
zippedFile := aFolder / self dashedName , 'zip'.
aFolder ensureCreateDirectory.
GrafoscopioUtils
downloadingFrom: self url withMessage: 'Downloading ', tempName, '...' into: zippedFile.
self folder: aFolder.
^ zippedFile
]
{ #category : #accessing }
BreaTheme >> folder [
^ folder
]
{ #category : #accessing }
BreaTheme >> folder: anObject [
folder := anObject
]
{ #category : #installation }
BreaTheme >> installInto: aFolder [
| zippedFile |
self url ifNil: [ ^ self ].
zippedFile := self downloadInto: FileLocator temp.
(ZipArchive new readFrom: zippedFile) extractAllTo: aFolder.
^ aFolder
]
{ #category : #accessing }
BreaTheme >> license [
^ license
]
{ #category : #accessing }
BreaTheme >> license: anObject [
license := anObject
]
{ #category : #operation }
BreaTheme >> loadConfiguration [
| config |
config := self folder / 'brea.yaml'.
config exists
ifTrue: [ ^ PPYAMLGrammar new parse: config contents ]
ifFalse: [ self inform:
'No configuration file found. A "brea.yaml" file should be located in the theme root folder.
please run "#updateCustomizations" after defining a theme name from the
"BreaTheme availablePacks".
If no configuration is defined for such theme name you can create and empty configuration
file by running "#createBaseConfiguration" and filing out the "brea.yaml" fields.
For more information or help ask at https://t.me/grafoscopio .' ]
]
{ #category : #accessing }
BreaTheme >> name [
^ name ifNil: [ name = 'unamed' ]
]
{ #category : #accessing }
BreaTheme >> name: anObject [
name := anObject
]
{ #category : #accessing }
BreaTheme >> preview [
^ preview
]
{ #category : #accessing }
BreaTheme >> preview: anObject [
preview := anObject
]
{ #category : #accessing }
BreaTheme >> provider [
^ provider
]
{ #category : #accessing }
BreaTheme >> provider: anObject [
provider := anObject
]
{ #category : #accessing }
BreaTheme >> queries [
^ queries ifNil: [ queries := OrderedCollection new ]
]
{ #category : #accessing }
BreaTheme >> queries: cleanedBreaQueriesCollection [
queries := cleanedBreaQueriesCollection
]
{ #category : #accessing }
BreaTheme >> url [
^ url ifNil: [ url := self class downloadLinks at: self name. ]
]
{ #category : #accessing }
BreaTheme >> url: anObject [
url := anObject
]

View File

@ -1,22 +1,22 @@
"
I provide common utilities for the use with the Brea CMS.
"
Class {
#name : #BreaUtils,
#superclass : #Object,
#category : #Brea
}
{ #category : #'as yet unclassified' }
BreaUtils class >> installSkeleton [
"I populate the folder and files structures for Brea documentation and customizations."
| skeleton destination |
GrafoscopioUtils
downloadingFrom: 'https://mutabit.com/repos.fossil/brea/zip'
withMessage: 'Dowloading files skeleton'
into: FileLocator temp.
skeleton := ZipArchive new readFrom: FileLocator temp / 'zip'.
destination := FileLocator home / '.local/share/Brea'.
destination ensureCreateDirectory.
skeleton extractAllTo: destination.
]
"
I provide common utilities for the use with the Brea CMS.
"
Class {
#name : #BreaUtils,
#superclass : #Object,
#category : #Brea
}
{ #category : #'as yet unclassified' }
BreaUtils class >> installSkeleton [
"I populate the folder and files structures for Brea documentation and customizations."
| skeleton destination |
GrafoscopioUtils
downloadingFrom: 'https://mutabit.com/repos.fossil/brea/zip'
withMessage: 'Dowloading files skeleton'
into: FileLocator temp.
skeleton := ZipArchive new readFrom: FileLocator temp / 'zip'.
destination := FileLocator home / '.local/share/Brea'.
destination ensureCreateDirectory.
skeleton extractAllTo: destination.
]

View File

@ -1,13 +1,13 @@
"
I store metadata for this package. These meta data are used by other tools such as the SmalllintManifestChecker and the critics Browser
"
Class {
#name : #ManifestBrea,
#superclass : #PackageManifest,
#category : #'Brea-Manifest'
}
{ #category : #'code-critics' }
ManifestBrea class >> ruleRBStringConcatenationRuleV1FalsePositive [
^ #(#(#(#RGMethodDefinition #(#BreaPage #contents #false)) #'2020-08-28T20:08:20.291489-05:00') #(#(#RGMethodDefinition #(#BreaFile #fromShortName:andFolder: #false)) #'2020-11-06T20:59:12.94748-05:00') #(#(#RGMethodDefinition #(#'BreaFile class' #fromShortName:andFolder: #true)) #'2020-11-06T21:02:25.564981-05:00') )
]
"
I store metadata for this package. These meta data are used by other tools such as the SmalllintManifestChecker and the critics Browser
"
Class {
#name : #ManifestBrea,
#superclass : #PackageManifest,
#category : #'Brea-Manifest'
}
{ #category : #'code-critics' }
ManifestBrea class >> ruleRBStringConcatenationRuleV1FalsePositive [
^ #(#(#(#RGMethodDefinition #(#BreaPage #contents #false)) #'2020-08-28T20:08:20.291489-05:00') #(#(#RGMethodDefinition #(#BreaFile #fromShortName:andFolder: #false)) #'2020-11-06T20:59:12.94748-05:00') #(#(#RGMethodDefinition #(#'BreaFile class' #fromShortName:andFolder: #true)) #'2020-11-06T21:02:25.564981-05:00') )
]

View File

@ -1,6 +0,0 @@
Extension { #name : #String }
{ #category : #'*Brea' }
String >> webView [
^ (Pandoc htmlStringToMarkdown: self) accentedCharactersCorrection
]

View File

@ -1,6 +0,0 @@
Extension { #name : #Teapot }
{ #category : #'*Brea' }
Teapot >> dynamicRoutes [
^ dynamicRouter routes
]

View File

@ -1 +1 @@
Package { #name : #Brea }
Package { #name : #Brea }