diff --git a/repository/Brea-Tests/BreaPageTest.class.st b/repository/Brea-Tests/BreaPageTest.class.st new file mode 100644 index 0000000..5e38b9c --- /dev/null +++ b/repository/Brea-Tests/BreaPageTest.class.st @@ -0,0 +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 := +' + + + + + {{title}} + + +

{{title}}

+

+ {{#show}} You should see me. {{/show}} +

+

+ {{#unhide}} You should not see me. {{/unhide}} +

+ {{{ contents }}} + +'. + + 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 [ + ^ '

Level one header

+

And paragraph contents with emphasis and strong emphasis.

+' +] + +{ #category : #'as yet unclassified' } +BreaPageTest >> htmlOutput [ + ^ ' + + + + + This is a test + + +

This is a test

+

+ You should see me. +

+

+ +

+ ', self htmlBodyContents, +' + +' +] + +{ #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) +] diff --git a/repository/Brea-Tests/BreaQueryTest.class.st b/repository/Brea-Tests/BreaQueryTest.class.st new file mode 100644 index 0000000..46ad356 --- /dev/null +++ b/repository/Brea-Tests/BreaQueryTest.class.st @@ -0,0 +1,21 @@ +" +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 +] diff --git a/repository/Brea-Tests/package.st b/repository/Brea-Tests/package.st new file mode 100644 index 0000000..2cda3c5 --- /dev/null +++ b/repository/Brea-Tests/package.st @@ -0,0 +1 @@ +Package { #name : #'Brea-Tests' } diff --git a/repository/Brea/Airtable.class.st b/repository/Brea/Airtable.class.st new file mode 100644 index 0000000..84d70ad --- /dev/null +++ b/repository/Brea/Airtable.class.st @@ -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 ] + +] diff --git a/repository/Brea/BlockClosure.extension.st b/repository/Brea/BlockClosure.extension.st new file mode 100644 index 0000000..32b11da --- /dev/null +++ b/repository/Brea/BlockClosure.extension.st @@ -0,0 +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' ] +] diff --git a/repository/Brea/BreaQuery.class.st b/repository/Brea/BreaQuery.class.st new file mode 100644 index 0000000..b60cfe5 --- /dev/null +++ b/repository/Brea/BreaQuery.class.st @@ -0,0 +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: + inputs: + name: + + + 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 +] diff --git a/repository/Brea/BreaTheme.class.st b/repository/Brea/BreaTheme.class.st index 5413050..a919260 100644 --- a/repository/Brea/BreaTheme.class.st +++ b/repository/Brea/BreaTheme.class.st @@ -27,11 +27,12 @@ Class { #superclass : #Object, #instVars : [ 'name', + 'folder', 'provider', 'url', 'preview', 'license', - 'folder', + 'queries', 'customizations' ], #category : #Brea @@ -101,6 +102,16 @@ BreaTheme class >> downloadLinks [ ^ 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 @@ -148,7 +159,7 @@ BreaTheme >> license: anObject [ license := anObject ] -{ #category : #'as yet unclassified' } +{ #category : #operation } BreaTheme >> loadConfiguration [ | config | config := self folder / 'brea.yaml'. @@ -193,6 +204,16 @@ 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. ]