├── source ├── Buoy-Math │ ├── package.st │ ├── PerMille.class.st │ └── Percentage.class.st ├── BaselineOfBuoy │ └── package.st ├── Buoy-Assertions │ ├── package.st │ ├── ObjectNotFound.class.st │ ├── InstanceCreationFailed.class.st │ ├── AssertionFailed.class.st │ ├── ConflictingObjectFound.class.st │ ├── RaiseOnFirstAssertionFailurePolicy.class.st │ ├── AssertionFailurePolicy.class.st │ ├── CollectingAssertionFailuresPolicy.class.st │ ├── AssertionCheckerBuilder.class.st │ ├── AssertionCheck.class.st │ └── Asserter.class.st ├── Buoy-Collections │ ├── package.st │ ├── Formatter.class.st │ └── CircularIterator.class.st ├── Buoy-Comparison │ ├── package.st │ ├── EqualityChecker.class.st │ ├── BitwiseExclusiveDisjunctionHashCombinator.class.st │ ├── SequenceableCollectionEqualityChecker.class.st │ ├── HashCombinator.class.st │ └── PropertyBasedEqualityChecker.class.st ├── Buoy-Conditions │ ├── package.st │ ├── Condition.class.st │ ├── NegatedCondition.class.st │ ├── ArithmeticCondition.class.st │ └── CompositeCondition.class.st ├── Buoy-Math-Tests │ └── package.st ├── Buoy-SUnit-Model │ ├── package.st │ ├── NaturalLanguageTranslator.extension.st │ └── TestAsserter.extension.st ├── Buoy-SUnit-Tests │ └── package.st ├── Buoy-Deprecated-V8 │ ├── package.st │ ├── LanguageRange.extension.st │ └── LanguageTag.extension.st ├── Buoy-Localization │ ├── package.st │ ├── CurrentLocale.class.st │ ├── ReverseSolidusEscapingRule.class.st │ ├── EscapingAlgorithm.class.st │ └── MonoglotNaturalLanguageTranslator.class.st ├── Buoy-Assertions-Tests │ ├── package.st │ ├── AssertionFailedTest.class.st │ └── AssertionCheckerTest.class.st ├── Buoy-Chronology-Tests │ ├── package.st │ ├── DateExtensionsTest.class.st │ ├── NumberChronologyExtensionsTest.class.st │ ├── DateAndTimeExtensionsTest.class.st │ └── DurationChronologyExtensionsTest.class.st ├── Buoy-Comparison-Tests │ ├── package.st │ ├── BuoyComparisonObjectExtensionsTest.class.st │ ├── SequenceableCollectionEqualityCheckerTest.class.st │ ├── ObjectUsingComparisonAffordances.class.st │ └── BitwiseExclusiveDisjunctionHashCombinatorTest.class.st ├── Buoy-Conditions-Tests │ ├── package.st │ ├── NegatedConditionTest.class.st │ └── ConditionExtensionsTest.class.st ├── Buoy-Dynamic-Binding │ ├── package.st │ ├── DefinedBinding.class.st │ ├── UndefinedBinding.class.st │ └── Binding.class.st ├── Buoy-Math-Extensions │ ├── package.st │ ├── Integer.extension.st │ ├── Fraction.extension.st │ └── Number.extension.st ├── Buoy-Metaprogramming │ ├── package.st │ ├── MessageSendingCollector.class.st │ ├── Interface.class.st │ ├── KeywordMessageSendingCollector.class.st │ ├── UnaryMessageSendingCollector.class.st │ └── Namespace.class.st ├── Buoy-Collections-Tests │ ├── package.st │ ├── StreamExtensionsTest.class.st │ ├── DictionaryExtensionsTest.class.st │ ├── BinarySearchAlgorithmTest.class.st │ └── CircularIteratorTest.class.st ├── Buoy-Development-Tools │ ├── package.st │ ├── Behavior.extension.st │ └── Namespace.extension.st ├── Buoy-GS64-Compatibility │ ├── package.st │ ├── String.extension.st │ ├── GemStoneError.class.st │ ├── Random.extension.st │ ├── Character.extension.st │ ├── Number.extension.st │ ├── Date.extension.st │ ├── GsNMethod.class.st │ ├── IndexManager.class.st │ ├── AbstractDictionary.class.st │ ├── CharacterCollection.class.st │ ├── OffsetError.class.st │ ├── ExecBlock.class.st │ ├── MultiByteString.class.st │ ├── ImproperOperation.class.st │ ├── LookupError.class.st │ ├── GsProcess.class.st │ ├── Process.extension.st │ ├── GsQuery.class.st │ ├── BinaryFloat.class.st │ ├── ClassOrganizer.class.st │ ├── GsIndexSpec.class.st │ ├── ArgumentError.class.st │ ├── WriteStreamPortable.class.st │ ├── ExitClientError.class.st │ ├── RcIdentitySet.class.st │ ├── DateAndTimeANSI.class.st │ ├── GsQueryOptions.class.st │ ├── GsCurrentSession.class.st │ ├── Collection.extension.st │ ├── GsIndexOptions.class.st │ ├── GsSocket.class.st │ ├── Integer.extension.st │ ├── GsFile.class.st │ └── System.class.st ├── Buoy-Localization-Tests │ ├── package.st │ └── StringEscapingRuleTest.class.st ├── Buoy-Assertions-Extensions │ ├── package.st │ └── Error.extension.st ├── Buoy-Comparison-Extensions │ ├── package.st │ └── Object.extension.st ├── Buoy-Conditions-Extensions │ ├── package.st │ ├── Boolean.extension.st │ └── BlockClosure.extension.st ├── Buoy-Dynamic-Binding-Tests │ ├── package.st │ └── BindingTest.class.st ├── Buoy-Math-GS64-Extensions │ ├── package.st │ ├── PerMille.extension.st │ ├── Percentage.extension.st │ └── PartsPerFraction.extension.st ├── Buoy-Math-Pharo-Extensions │ ├── package.st │ ├── PartsPerFraction.extension.st │ ├── PerMille.extension.st │ ├── Integer.extension.st │ └── Percentage.extension.st ├── Buoy-Metaprogramming-Tests │ ├── package.st │ ├── DynamicVariableForTesting.class.st │ ├── DynamicVariableTest.class.st │ ├── KeywordMessageSendingCollectorTest.class.st │ ├── InterfaceTest.class.st │ ├── BuoyMetaprogrammingExtensionsTest.class.st │ └── UnaryMessageSendingCollectorTest.class.st ├── Buoy-SUnit-GS64-Extensions │ ├── package.st │ └── TestCase.extension.st ├── Buoy-Collections-Extensions │ ├── package.st │ ├── SequenceableCollection.extension.st │ └── Collection.extension.st ├── Buoy-Exception-Handling-Tests │ ├── package.st │ └── ExitTest.class.st ├── Buoy-SUnit-Pharo-Extensions │ ├── package.st │ └── TestCase.extension.st ├── .properties ├── Buoy-Chronology-GS64-Extensions │ ├── package.st │ ├── DateAndTime.extension.st │ ├── Integer.extension.st │ ├── Date.extension.st │ ├── Number.extension.st │ ├── Time.extension.st │ ├── DateAndTimeANSI.extension.st │ └── Duration.extension.st ├── Buoy-Development-Tools-Pharo-12 │ ├── package.st │ ├── Formatter.extension.st │ ├── CircularIterator.extension.st │ ├── RBProgramNode.extension.st │ ├── SearchMethodsForLocalizationMessagesRule.class.st │ └── TonelWriterV3.extension.st ├── Buoy-Development-Tools-Pharo-13 │ ├── package.st │ ├── Formatter.extension.st │ ├── CircularIterator.extension.st │ ├── OCProgramNode.extension.st │ ├── SearchMethodsForLocalizationMessagesRule.class.st │ └── TonelWriterV3.extension.st ├── Buoy-Math-GS64-Base-Extensions │ ├── package.st │ ├── Number.extension.st │ ├── DomainError.class.st │ ├── Integer.extension.st │ └── BinaryFloat.extension.st ├── Buoy-Metaprogramming-Extensions │ ├── package.st │ └── Object.extension.st ├── Buoy-Chronology-Pharo-Extensions │ ├── package.st │ ├── Delay.extension.st │ └── Date.extension.st ├── Buoy-Collections-GS64-Extensions │ ├── package.st │ ├── IdentityBag.extension.st │ ├── Set.extension.st │ ├── PositionableStream.extension.st │ ├── OrderedCollection.extension.st │ ├── Object.extension.st │ ├── Interval.extension.st │ ├── Character.extension.st │ ├── LookupError.extension.st │ ├── OffsetError.extension.st │ ├── Array.extension.st │ └── AbstractDictionary.extension.st ├── Buoy-Collections-Pharo-Extensions │ ├── package.st │ ├── Character.extension.st │ └── SequenceableCollection.extension.st ├── Buoy-Conditions-Pharo-Extensions │ ├── package.st │ └── RegexCondition.class.st ├── Buoy-Exception-Handling-Extensions │ ├── package.st │ └── BlockClosure.extension.st ├── Buoy-Localization-GS64-Extensions │ ├── package.st │ ├── NaturalLanguageTranslator.class.st │ └── CharacterCollection.extension.st ├── Buoy-Localization-Pharo-Extensions │ ├── package.st │ ├── PolyglotNaturalLanguageTranslator.extension.st │ └── String.extension.st ├── Buoy-Math-Pharo-Extensions-Tests │ ├── package.st │ ├── PerMilleTest.extension.st │ └── PercentageTest.extension.st ├── Buoy-Metaprogramming-GS64-Extensions │ ├── package.st │ ├── ExecBlock.extension.st │ ├── GsNMethod.extension.st │ ├── Pragma.extension.st │ ├── Symbol.extension.st │ ├── Behavior.extension.st │ ├── Object.extension.st │ ├── Class.extension.st │ ├── GemStone64UnixPlatform.class.st │ └── DynamicVariable.class.st ├── Buoy-Conditions-Pharo-Extensions-Tests │ ├── package.st │ └── RegexConditionTest.class.st ├── Buoy-Exception-Handling-GS64-Extensions │ ├── package.st │ └── ExitClientError.extension.st └── Buoy-Metaprogramming-Pharo-Extensions │ ├── package.st │ ├── Symbol.extension.st │ ├── OSPlatform.extension.st │ ├── Behavior.extension.st │ └── PharoPlatform.class.st ├── .gitattributes ├── .project ├── rowan ├── specs │ ├── README.md │ ├── Buoy-Deployment.ston │ ├── Buoy-CI.ston │ └── Buoy-Dependent-SUnit-Extensions.ston ├── projects │ └── README.md ├── components │ ├── README.md │ ├── scripts │ │ ├── definePostLoadExceptionAliases.st │ │ └── defineClassAliases.st │ ├── Dependent-SUnit-Extensions.ston │ └── Tests.ston └── project.ston ├── .smalltalkci ├── .loading.tools.ston ├── .loading.deployment.ston ├── .unit-tests.ston ├── .loading.dependent-sunit-extensions.ston ├── .loading.tests.ston └── .loading.development.ston ├── docs ├── reference │ ├── ExceptionHandling.md │ ├── MOP.md │ ├── Namespaces.md │ ├── Interfaces.md │ ├── SUnit.md │ └── Baseline-groups.md ├── how-to │ ├── how-to-support-gs64-options.md │ ├── how-to-load-in-pharo.md │ └── how-to-use-as-dependency-in-pharo.md └── README.md ├── .github └── workflows │ ├── markdown-lint.yml │ ├── notify.yml │ ├── unit-tests-gs64.yml │ ├── unit-tests.yml │ ├── loading-groups.yml │ └── loading-gs64-components.yml ├── .gitignore ├── LICENSE └── CONTRIBUTING.md /source/Buoy-Math/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Math' } 2 | -------------------------------------------------------------------------------- /source/BaselineOfBuoy/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'BaselineOfBuoy' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Assertions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Collections/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Collections' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Comparison/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Comparison' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Conditions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Conditions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Math-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Math-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-SUnit-Model/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-SUnit-Model' } 2 | -------------------------------------------------------------------------------- /source/Buoy-SUnit-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-SUnit-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Deprecated-V8/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Deprecated-V8' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Localization/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Localization' } 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.st linguist-language=Smalltalk 2 | *.st eol=lf 3 | *.st text diff 4 | -------------------------------------------------------------------------------- /source/Buoy-Assertions-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Assertions-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Chronology-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Comparison-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Comparison-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Conditions-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Dynamic-Binding/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Dynamic-Binding' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Math-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Math-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Metaprogramming' } 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | { 2 | 'srcDirectory' : 'source', 3 | 'tags': [ 'Buenos Aires Smalltalk' ] 4 | } -------------------------------------------------------------------------------- /source/Buoy-Collections-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Collections-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Development-Tools' } 2 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-GS64-Compatibility' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Localization-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Localization-Tests' } 2 | -------------------------------------------------------------------------------- /rowan/specs/README.md: -------------------------------------------------------------------------------- 1 | # Specs 2 | 3 | This directory contains loading specs for this project 4 | -------------------------------------------------------------------------------- /source/Buoy-Assertions-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Assertions-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Comparison-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Comparison-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Conditions-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Dynamic-Binding-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Dynamic-Binding-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Math-GS64-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Math-Pharo-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Math-Pharo-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Metaprogramming-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-SUnit-GS64-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-SUnit-GS64-Extensions' } 2 | -------------------------------------------------------------------------------- /rowan/projects/README.md: -------------------------------------------------------------------------------- 1 | # Projects 2 | 3 | This directory contains loading specs for dependencies 4 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Collections-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Exception-Handling-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Exception-Handling-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-SUnit-Pharo-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-SUnit-Pharo-Extensions' } 2 | -------------------------------------------------------------------------------- /source/.properties: -------------------------------------------------------------------------------- 1 | { 2 | #format : 'tonel', 3 | #version: '3.0', 4 | #convention : 'Rowan' 5 | } 6 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-GS64-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Chronology-GS64-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-12/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Development-Tools-Pharo-12' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-13/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Development-Tools-Pharo-13' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Base-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Math-GS64-Base-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Metaprogramming-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-Pharo-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Chronology-Pharo-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Collections-GS64-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Pharo-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Collections-Pharo-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Pharo-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Conditions-Pharo-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Exception-Handling-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Exception-Handling-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Localization-GS64-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Localization-GS64-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Localization-Pharo-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Localization-Pharo-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Math-Pharo-Extensions-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Math-Pharo-Extensions-Tests' } 2 | -------------------------------------------------------------------------------- /rowan/components/README.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | This directory contains component definitions for the project 4 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Metaprogramming-GS64-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Pharo-Extensions-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Conditions-Pharo-Extensions-Tests' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Exception-Handling-GS64-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Exception-Handling-GS64-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Pharo-Extensions/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : 'Buoy-Metaprogramming-Pharo-Extensions' } 2 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/String.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'String' } 2 | 3 | { #category : '*Buoy-GS64-Compatibility' } 4 | String >> asUnicodeString [ 5 | 6 | ^WideString from: self 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GemStoneError.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'GemStoneError', 3 | #superclass : 'Object', 4 | #category : 'Buoy-GS64-Compatibility', 5 | #package : 'Buoy-GS64-Compatibility' 6 | } 7 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-GS64-Extensions/DateAndTime.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'DateAndTime' } 2 | 3 | { #category : '*Buoy-Chronology-GS64-Extensions' } 4 | DateAndTime >> asDateAndTime [ 5 | 6 | ^ self 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-12/Formatter.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Formatter' } 2 | 3 | { #category : '*Buoy-Development-Tools-Pharo-12' } 4 | Formatter class >> systemIconName [ 5 | 6 | ^ #string 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-13/Formatter.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Formatter' } 2 | 3 | { #category : '*Buoy-Development-Tools-Pharo-13' } 4 | Formatter class >> systemIconName [ 5 | 6 | ^ #string 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Pharo-Extensions/Symbol.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Symbol' } 2 | 3 | { #category : '*Buoy-Metaprogramming-Pharo-Extensions' } 4 | Symbol >> argumentCount [ 5 | 6 | ^self numArgs 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/IdentityBag.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'IdentityBag' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | IdentityBag >> removeAll [ 5 | 6 | ^ self removeAll: self 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Extensions/PerMille.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'PerMille' } 2 | 3 | { #category : '*Buoy-Math-GS64-Extensions' } 4 | PerMille >> printOn: stream [ 5 | 6 | super printOn: stream. 7 | stream nextPutAll: '‰' 8 | ] 9 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Extensions/Percentage.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Percentage' } 2 | 3 | { #category : '*Buoy-Math-GS64-Extensions' } 4 | Percentage >> printOn: stream [ 5 | 6 | super printOn: stream. 7 | stream nextPut: $% 8 | ] 9 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-12/CircularIterator.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'CircularIterator' } 2 | 3 | { #category : '*Buoy-Development-Tools-Pharo-12' } 4 | CircularIterator class >> systemIconName [ 5 | 6 | ^ #collection 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-13/CircularIterator.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'CircularIterator' } 2 | 3 | { #category : '*Buoy-Development-Tools-Pharo-13' } 4 | CircularIterator class >> systemIconName [ 5 | 6 | ^ #collection 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Math-Extensions/Integer.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Integer' } 2 | 3 | { #category : '*Buoy-Math-Extensions' } 4 | Integer >> adaptToInteger: anInteger andSend: selector [ 5 | 6 | ^ self perform: selector with: anInteger 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-Pharo-Extensions/Delay.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Delay' } 2 | 3 | { #category : '*Buoy-Chronology-Pharo-Extensions' } 4 | Delay class >> waitForMilliseconds: aNumber [ 5 | 6 | ^ (self forMilliseconds: aNumber) wait 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/Set.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Set' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | Set >> intersection: aCollection [ 5 | 6 | ^ aCollection select: [ :each | self includes: each ] 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Math-Extensions/Fraction.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Fraction' } 2 | 3 | { #category : '*Buoy-Math-Extensions' } 4 | Fraction >> adaptToFraction: aFraction andSend: selector [ 5 | 6 | ^self perform: selector with: aFraction 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Pharo-Extensions/Character.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Character' } 2 | 3 | { #category : '*Buoy-Collections-Pharo-Extensions' } 4 | Character class >> esc [ 5 | "Answer the ASCII ESC character" 6 | 7 | ^self value: 27 8 | ] 9 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/Random.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Random' } 2 | 3 | { #category : '*Buoy-GS64-Compatibility' } 4 | Random >> integerBetween: anInteger and: anInteger2 [ 5 | 6 | ^ anInteger2 atRandom: SharedRandom globalGenerator 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/ExecBlock.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'ExecBlock' } 2 | 3 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 4 | ExecBlock >> argumentNames [ 5 | 6 | ^ self argsAndTemps copyFirst: self numArgs 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/GsNMethod.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'GsNMethod' } 2 | 3 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 4 | GsNMethod >> argumentNames [ 5 | 6 | ^ self argsAndTemps copyFirst: self numArgs 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-Pharo-Extensions/Date.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Date' } 2 | 3 | { #category : '*Buoy-Chronology-Pharo-Extensions' } 4 | Date class >> newDay: day monthNumber: monthNumber year: year [ 5 | 6 | ^ self newDay: day month: monthNumber year: year 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/Character.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Character' } 2 | 3 | { #category : '*Buoy-GS64-Compatibility' } 4 | Character class >> withValue: anInteger [ 5 | "Answer the Character whose value is anInteger." 6 | 7 | ^self primitiveFailed 8 | ] 9 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/ObjectNotFound.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an exception expecting to be raised when someone tries to access an object and cannot be found 3 | " 4 | Class { 5 | #name : 'ObjectNotFound', 6 | #superclass : 'Error', 7 | #category : 'Buoy-Assertions', 8 | #package : 'Buoy-Assertions' 9 | } 10 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/PositionableStream.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'PositionableStream' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | PositionableStream >> isBinary [ 5 | "Return true if the receiver is a binary byte stream" 6 | ^collection class == ByteArray 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/Number.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Number' } 2 | 3 | { #category : '*Buoy-GS64-Compatibility' } 4 | Number class >> fromStream: aStream [ 5 | 6 | ^ [ ( NumberParser on: aStream ) nextNumber ] 7 | on: Error 8 | do: [ :error | ImproperOperation signal ] 9 | ] 10 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/InstanceCreationFailed.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an exception expecting to be raised when someone tries to create an invalid instance 3 | " 4 | Class { 5 | #name : 'InstanceCreationFailed', 6 | #superclass : 'Error', 7 | #category : 'Buoy-Assertions', 8 | #package : 'Buoy-Assertions' 9 | } 10 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/OrderedCollection.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'OrderedCollection' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | OrderedCollection class >> new: anInteger withAll: anObject [ 5 | 6 | ^ ( Array new: anInteger withAll: anObject ) asOrderedCollection 7 | ] 8 | -------------------------------------------------------------------------------- /rowan/specs/Buoy-Deployment.ston: -------------------------------------------------------------------------------- 1 | RwLoadSpecificationV2 { 2 | #specName: 'Buoy-CI', 3 | #projectName : 'Buoy', 4 | #diskUrl : '/opt/gemstone/projects/Buoy', 5 | #projectSpecFile : 'rowan/project.ston', 6 | #componentNames : [ 7 | 'Deployment' 8 | ], 9 | #comment : 'Loading spec for Deployment' 10 | } 11 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/AssertionFailed.class.st: -------------------------------------------------------------------------------- 1 | " 2 | AsssertionFailed is the default exception signaled when AssertionChecker fails to verifiy at least a condition. 3 | " 4 | Class { 5 | #name : 'AssertionFailed', 6 | #superclass : 'Error', 7 | #category : 'Buoy-Assertions', 8 | #package : 'Buoy-Assertions' 9 | } 10 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/Object.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Object' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | Object >> isArray [ 5 | 6 | ^ false 7 | ] 8 | 9 | { #category : '*Buoy-Collections-GS64-Extensions' } 10 | Object >> isDictionary [ 11 | 12 | ^ false 13 | ] 14 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/ConflictingObjectFound.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an exception expecting to be raised when someone tries to change some object in a conflicting way 3 | " 4 | Class { 5 | #name : 'ConflictingObjectFound', 6 | #superclass : 'Error', 7 | #category : 'Buoy-Assertions', 8 | #package : 'Buoy-Assertions' 9 | } 10 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/Interval.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Interval' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | Interval >> sorted [ 5 | 6 | ^ self increment >= 0 7 | ifTrue: [ self copy ] 8 | ifFalse: [ self last to: self first by: self increment negated ] 9 | ] 10 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-12/RBProgramNode.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'RBProgramNode' } 2 | 3 | { #category : '*Buoy-Development-Tools-Pharo-12' } 4 | RBProgramNode class >> formatters [ 5 | 6 | ^ (RBAbstractFormatter allSubclasses reject: [ :each | each isAbstract ]) 7 | sort: [ :a :b | a priority > b priority ] 8 | ] 9 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-13/OCProgramNode.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'OCProgramNode' } 2 | 3 | { #category : '*Buoy-Development-Tools-Pharo-13' } 4 | OCProgramNode class >> formatters [ 5 | 6 | ^ (RBAbstractFormatter allSubclasses reject: [ :each | each isAbstract ]) 7 | sort: [ :a :b | a priority > b priority ] 8 | ] 9 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Pharo-Extensions/SequenceableCollection.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'SequenceableCollection' } 2 | 3 | { #category : '*Buoy-Collections-Pharo-Extensions' } 4 | SequenceableCollection >> copyLast: n [ 5 | 6 | ^ [ self copyFrom: self size - n + 1 to: self size ] unless: n = 0 inWhichCase: [ self species new ] 7 | ] 8 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Extensions/Object.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Object' } 2 | 3 | { #category : '*Buoy-Metaprogramming-Extensions' } 4 | Object >> isA: aClass [ 5 | 6 | ^self isKindOf: aClass 7 | ] 8 | 9 | { #category : '*Buoy-Metaprogramming-Extensions' } 10 | Object >> isAn: aClass [ 11 | 12 | ^self isA: aClass 13 | ] 14 | -------------------------------------------------------------------------------- /.smalltalkci/.loading.tools.ston: -------------------------------------------------------------------------------- 1 | SmalltalkCISpec { 2 | #loading : [ 3 | SCIMetacelloLoadSpec { 4 | #baseline : 'Buoy', 5 | #directory : '../source', 6 | #load : [ 'Tools' ], 7 | #platforms : [ #pharo ], 8 | #failOn : [ #Warning ] 9 | } 10 | ], 11 | #testing : { 12 | #failOnZeroTests : false 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/Pragma.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Pragma' } 2 | 3 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 4 | Pragma >> methodSelector [ 5 | "Answer the selector of the method containing the pragma. 6 | Do not confuse this with the selector of the pragma's message pattern." 7 | 8 | ^method selector 9 | ] 10 | -------------------------------------------------------------------------------- /.smalltalkci/.loading.deployment.ston: -------------------------------------------------------------------------------- 1 | SmalltalkCISpec { 2 | #loading : [ 3 | SCIMetacelloLoadSpec { 4 | #baseline : 'Buoy', 5 | #directory : '../source', 6 | #load : [ 'Deployment' ], 7 | #platforms : [ #pharo ], 8 | #failOn : [ #Warning ] 9 | } 10 | ], 11 | #testing : { 12 | #failOnZeroTests : false 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/Symbol.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Symbol' } 2 | 3 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 4 | Symbol >> cull: anObject [ 5 | 6 | ^ anObject perform: self 7 | ] 8 | 9 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 10 | Symbol >> value: anObject [ 11 | 12 | ^ anObject perform: self 13 | ] 14 | -------------------------------------------------------------------------------- /.smalltalkci/.unit-tests.ston: -------------------------------------------------------------------------------- 1 | SmalltalkCISpec { 2 | #loading : [ 3 | SCIMetacelloLoadSpec { 4 | #baseline : 'Buoy', 5 | #directory : '../source', 6 | #load : [ 'CI' ], 7 | #platforms : [ #pharo ] 8 | } 9 | ], 10 | #testing : { 11 | #coverage : { 12 | #packages : [ 'Buoy*' ], 13 | #format: #lcov 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /source/Buoy-Comparison-Extensions/Object.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Object' } 2 | 3 | { #category : '*Buoy-Comparison-Extensions' } 4 | Object >> equalityChecker [ 5 | 6 | ^ PropertyBasedEqualityChecker on: self 7 | ] 8 | 9 | { #category : '*Buoy-Comparison-Extensions' } 10 | Object >> equalityHashCombinator [ 11 | 12 | ^ BitwiseExclusiveDisjunctionHashCombinator new 13 | ] 14 | -------------------------------------------------------------------------------- /docs/reference/ExceptionHandling.md: -------------------------------------------------------------------------------- 1 | # Exception handling 2 | 3 | - `on:except:do:` provides an extension to the exception handling allowing to 4 | ignore some subclass of the exception being handled. 5 | 6 | For example: 7 | 8 | ```smalltalk 9 | [ 1 / 0 ] on: Error except: ZeroDivide do: [ ... ] 10 | ``` 11 | 12 | will raise an exception even when `ZeroDivide` is a subclass of `Error` 13 | -------------------------------------------------------------------------------- /source/Buoy-Deprecated-V8/LanguageRange.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'LanguageRange' } 2 | 3 | { #category : '*Buoy-Deprecated-V8' } 4 | LanguageRange class >> from: aSubtagCollection [ 5 | 6 | self 7 | deprecated: 'Use composedOf: instead' 8 | transformWith: '`@receiver from: `@subtags' -> '`@receiver composedOf: `@subtags'. 9 | ^ self composedOf: aSubtagCollection 10 | ] 11 | -------------------------------------------------------------------------------- /source/Buoy-Deprecated-V8/LanguageTag.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'LanguageTag' } 2 | 3 | { #category : '*Buoy-Deprecated-V8' } 4 | LanguageTag class >> from: aSubtagCollection [ 5 | 6 | self 7 | deprecated: 'Use composedOf: instead' 8 | transformWith: '`@receiver from: `@subtags' -> '`@receiver composedOf: `@subtags'. 9 | 10 | ^ self composedOf: aSubtagCollection 11 | ] 12 | -------------------------------------------------------------------------------- /.smalltalkci/.loading.dependent-sunit-extensions.ston: -------------------------------------------------------------------------------- 1 | SmalltalkCISpec { 2 | #loading : [ 3 | SCIMetacelloLoadSpec { 4 | #baseline : 'Buoy', 5 | #directory : '../source', 6 | #load : [ 'Dependent-SUnit-Extensions' ], 7 | #platforms : [ #pharo ], 8 | #failOn : [ #Warning ] 9 | } 10 | ], 11 | #testing : { 12 | #failOnZeroTests : false 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docs/reference/MOP.md: -------------------------------------------------------------------------------- 1 | # Meta Object Protocol 2 | 3 | ## `Symbol` extensions for GS64 4 | 5 | - `value:` allows using a unary symbol as a replacement for a unary block 6 | 7 | ## `Class` extensions for GS64 8 | 9 | - `allLeafSubclasses` returns all the subclasses of the receiver that don't 10 | have further subclasses 11 | - `allSubclassesDo:` iterates over all the subclasses of the receiver 12 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Extensions/Boolean.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Boolean' } 2 | 3 | { #category : '*Buoy-Conditions-Extensions' } 4 | Boolean >> then: aBlock [ 5 | 6 | self ifTrue: aBlock 7 | ] 8 | 9 | { #category : '*Buoy-Conditions-Extensions' } 10 | Boolean >> then: aTrueBlock otherwise: aFalseBlock [ 11 | 12 | ^ self 13 | ifTrue: aTrueBlock 14 | ifFalse: aFalseBlock 15 | ] 16 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/Character.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Character' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | Character class >> escape [ 5 | "Answer the ASCII ESC character" 6 | 7 | ^self esc 8 | ] 9 | 10 | { #category : '*Buoy-Collections-GS64-Extensions' } 11 | Character class >> value: anInteger [ 12 | 13 | ^self withValue: anInteger 14 | ] 15 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/Date.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Date' } 2 | 3 | { #category : '*Buoy-GS64-Compatibility' } 4 | Date >> asStringUsingFormat: format [ 5 | 6 | ^ self printFormat: format 7 | ] 8 | 9 | { #category : '*Buoy-GS64-Compatibility' } 10 | Date class >> newDay: day month: month year: year [ 11 | 12 | ^ self starting: (DateAndTime year: year month: month day: day) 13 | ] 14 | -------------------------------------------------------------------------------- /rowan/specs/Buoy-CI.ston: -------------------------------------------------------------------------------- 1 | RwLoadSpecificationV2 { 2 | #specName: 'Buoy-CI', 3 | #projectName : 'Buoy', 4 | #diskUrl : '/opt/gemstone/projects/Buoy', 5 | #projectSpecFile : 'rowan/project.ston', 6 | #componentNames : [ 7 | 'Tests' 8 | ], 9 | #customConditionalAttributes : [ 10 | 'tests', 11 | 'sunit' 12 | ], 13 | #comment : 'Loading spec for the continuous integration setup' 14 | } 15 | -------------------------------------------------------------------------------- /.smalltalkci/.loading.tests.ston: -------------------------------------------------------------------------------- 1 | SmalltalkCISpec { 2 | #loading : [ 3 | SCIMetacelloLoadSpec { 4 | #baseline : 'Buoy', 5 | #directory : '../source', 6 | #load : [ 'Tests' ], 7 | #platforms : [ #pharo ], 8 | #failOn : [ #Warning ] 9 | } 10 | ], 11 | #testing : { 12 | #coverage : { 13 | #packages : [ 'Buoy*' ], 14 | #format: #lcov 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsNMethod.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, GsNMethod is a compiled form of a GemStone Smalltalk method. 3 | 4 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 5 | packages. 6 | " 7 | Class { 8 | #name : 'GsNMethod', 9 | #superclass : 'Object', 10 | #category : 'Buoy-GS64-Compatibility', 11 | #package : 'Buoy-GS64-Compatibility' 12 | } 13 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/IndexManager.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, IndexManager is used to configure the indexing support. 3 | 4 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 5 | packages. 6 | " 7 | Class { 8 | #name : 'IndexManager', 9 | #superclass : 'Object', 10 | #category : 'Buoy-GS64-Compatibility', 11 | #package : 'Buoy-GS64-Compatibility' 12 | } 13 | -------------------------------------------------------------------------------- /rowan/project.ston: -------------------------------------------------------------------------------- 1 | RwProjectSpecificationV2 { 2 | #specName : 'project', 3 | #projectSpecPath : 'rowan', 4 | #componentsPath : 'rowan/components', 5 | #packagesPath : 'source', 6 | #projectsPath : 'rowan/projects', 7 | #specsPath : 'rowan/specs', 8 | #packageFormat : 'tonel', 9 | #packageConvention : 'Rowan', 10 | #comment : 'This project aims to complement Pharo and GS64 adding useful extensions.' 11 | } 12 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Extensions/BlockClosure.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'BlockClosure' } 2 | 3 | { #category : '*Buoy-Conditions-Extensions' } 4 | BlockClosure >> unless: aBoolean [ 5 | 6 | aBoolean ifFalse: self 7 | ] 8 | 9 | { #category : '*Buoy-Conditions-Extensions' } 10 | BlockClosure >> unless: aBoolean inWhichCase: anAlternativeBlock [ 11 | 12 | ^ aBoolean then: anAlternativeBlock otherwise: self 13 | ] 14 | -------------------------------------------------------------------------------- /source/Buoy-SUnit-Model/NaturalLanguageTranslator.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'NaturalLanguageTranslator' } 2 | 3 | { #category : '*Buoy-SUnit-Model' } 4 | NaturalLanguageTranslator class >> use: translator during: block [ 5 | 6 | | currentTranslator | 7 | currentTranslator := self current. 8 | [ 9 | self current: translator. 10 | block value 11 | ] ensure: [ self current: currentTranslator ] 12 | ] 13 | -------------------------------------------------------------------------------- /.smalltalkci/.loading.development.ston: -------------------------------------------------------------------------------- 1 | SmalltalkCISpec { 2 | #loading : [ 3 | SCIMetacelloLoadSpec { 4 | #baseline : 'Buoy', 5 | #directory : '../source', 6 | #load : [ 'Development' ], 7 | #platforms : [ #pharo ], 8 | #failOn : [ #Warning ] 9 | } 10 | ], 11 | #testing : { 12 | #coverage : { 13 | #packages : [ 'Buoy*' ], 14 | #format: #lcov 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rowan/specs/Buoy-Dependent-SUnit-Extensions.ston: -------------------------------------------------------------------------------- 1 | RwLoadSpecificationV2 { 2 | #specName: 'Buoy-CI', 3 | #projectName : 'Buoy', 4 | #diskUrl : '/opt/gemstone/projects/Buoy', 5 | #projectSpecFile : 'rowan/project.ston', 6 | #componentNames : [ 7 | 'Dependent-SUnit-Extensions' 8 | ], 9 | #customConditionalAttributes : [ 10 | 'sunit' 11 | ], 12 | #comment : 'Loading spec for Dependent-SUnit-Extensions' 13 | } 14 | -------------------------------------------------------------------------------- /source/Buoy-SUnit-GS64-Extensions/TestCase.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'TestCase' } 2 | 3 | { #category : '*Buoy-SUnit-GS64-Extensions' } 4 | TestCase >> runOnlyInGemStone64: aBlock [ 5 | 6 | aBlock value 7 | ] 8 | 9 | { #category : '*Buoy-SUnit-GS64-Extensions' } 10 | TestCase >> runOnlyInPharo: aBlock [ 11 | 12 | ] 13 | 14 | { #category : '*Buoy-SUnit-GS64-Extensions' } 15 | TestCase >> runOnlyInVAST: aBlock [ 16 | 17 | ] 18 | -------------------------------------------------------------------------------- /source/Buoy-Exception-Handling-Extensions/BlockClosure.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'BlockClosure' } 2 | 3 | { #category : '*Buoy-Exception-Handling-Extensions' } 4 | BlockClosure >> on: selector except: exclusionSelector do: action [ 5 | 6 | ^ self 7 | on: selector 8 | do: [ :exception | 9 | (exclusionSelector handles: exception) 10 | ifTrue: [ exception pass ] 11 | ifFalse: [ action value: exception ] ] 12 | ] 13 | -------------------------------------------------------------------------------- /source/Buoy-SUnit-Pharo-Extensions/TestCase.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'TestCase' } 2 | 3 | { #category : '*Buoy-SUnit-Pharo-Extensions' } 4 | TestCase >> runOnlyInGemStone64: aBlock [ 5 | 6 | ] 7 | 8 | { #category : '*Buoy-SUnit-Pharo-Extensions' } 9 | TestCase >> runOnlyInPharo: aBlock [ 10 | 11 | aBlock value 12 | ] 13 | 14 | { #category : '*Buoy-SUnit-Pharo-Extensions' } 15 | TestCase >> runOnlyInVAST: aBlock [ 16 | 17 | 18 | ] 19 | -------------------------------------------------------------------------------- /source/Buoy-Math-Pharo-Extensions-Tests/PerMilleTest.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'PerMilleTest' } 2 | 3 | { #category : '*Buoy-Math-Pharo-Extensions-Tests' } 4 | PerMilleTest >> testStoreOnBase [ 5 | 6 | self 7 | assert: ( 0 perMille storeStringBase: 16 ) equals: '16r0 perMille'; 8 | assert: ( 1000 perMille storeStringBase: 16 ) equals: '16r3E8 perMille'; 9 | assert: ( ( PerMille of: 12 ) storeStringBase: 16 ) equals: '16rC perMille' 10 | ] 11 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/AbstractDictionary.class.st: -------------------------------------------------------------------------------- 1 | " 2 | AbstractDictionary is an abstract class in GS64, the superclass of all the Dictionary-like abstractions. 3 | This version is just a placeholder so we can easily create extension methods to load in GS64 specific 4 | packages. 5 | " 6 | Class { 7 | #name : 'AbstractDictionary', 8 | #superclass : 'Collection', 9 | #category : 'Buoy-GS64-Compatibility', 10 | #package : 'Buoy-GS64-Compatibility' 11 | } 12 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/CharacterCollection.class.st: -------------------------------------------------------------------------------- 1 | " 2 | CharacterCollection is an abstract class in GS64, the superclass of all the String-like abstractions. 3 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 4 | packages. 5 | " 6 | Class { 7 | #name : 'CharacterCollection', 8 | #superclass : 'Collection', 9 | #category : 'Buoy-GS64-Compatibility', 10 | #package : 'Buoy-GS64-Compatibility' 11 | } 12 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/Behavior.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Behavior' } 2 | 3 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 4 | Behavior >> >> selector [ 5 | "Answer the compiled method associated with the argument, selector (a 6 | Symbol), a message selector in the receiver's method dictionary. If the 7 | selector is not in the dictionary, create an error notification." 8 | 9 | ^self compiledMethodAt: selector 10 | ] 11 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/OffsetError.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, OffsetError is an ImproperOperation signaled when an invalid offset 3 | is used to attempt a lookup. 4 | 5 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 6 | packages. 7 | " 8 | Class { 9 | #name : 'OffsetError', 10 | #superclass : 'ImproperOperation', 11 | #category : 'Buoy-GS64-Compatibility', 12 | #package : 'Buoy-GS64-Compatibility' 13 | } 14 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Tests/DynamicVariableForTesting.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'DynamicVariableForTesting', 3 | #superclass : 'DynamicVariable', 4 | #category : 'Buoy-Metaprogramming-Tests', 5 | #package : 'Buoy-Metaprogramming-Tests' 6 | } 7 | 8 | { #category : 'accessing' } 9 | DynamicVariableForTesting class >> default [ 10 | 11 | ^ 3 12 | ] 13 | 14 | { #category : 'accessing' } 15 | DynamicVariableForTesting >> default [ 16 | 17 | ^ self class default 18 | ] 19 | -------------------------------------------------------------------------------- /source/Buoy-Math-Pharo-Extensions-Tests/PercentageTest.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'PercentageTest' } 2 | 3 | { #category : '*Buoy-Math-Pharo-Extensions-Tests' } 4 | PercentageTest >> testStoreOnBase [ 5 | 6 | self 7 | assert: ( Percentage zero storeStringBase: 16 ) equals: 'Percentage zero'; 8 | assert: ( Percentage oneHundred storeStringBase: 16 ) equals: 'Percentage oneHundred'; 9 | assert: ( ( Percentage of: 12 ) storeStringBase: 16 ) equals: 'Percentage of: 16rC' 10 | ] 11 | -------------------------------------------------------------------------------- /source/Buoy-Math-Pharo-Extensions/PartsPerFraction.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'PartsPerFraction' } 2 | 3 | { #category : '*Buoy-Math-Pharo-Extensions' } 4 | PartsPerFraction >> adaptToFraction: aFraction andSend: selector [ 5 | 6 | ^ aFraction adaptToFraction: ratio andSend: selector 7 | ] 8 | 9 | { #category : '*Buoy-Math-Pharo-Extensions' } 10 | PartsPerFraction >> adaptToInteger: anInteger andSend: aSymbol [ 11 | 12 | ^anInteger adaptToInteger: ratio andSend: aSymbol 13 | ] 14 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/ExecBlock.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, ExecBlock is the block class representing all kinds 3 | of executable blocks in the Gemstone64 virtual machine. 4 | 5 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 6 | packages. 7 | " 8 | Class { 9 | #name : 'ExecBlock', 10 | #superclass : 'BlockClosure', 11 | #type : 'variable', 12 | #category : 'Buoy-GS64-Compatibility', 13 | #package : 'Buoy-GS64-Compatibility' 14 | } 15 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/MultiByteString.class.st: -------------------------------------------------------------------------------- 1 | " 2 | MultiByteString is an abstract class in GS64 for representing strings 3 | for which each Character occupies more than one byte. 4 | 5 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 6 | packages. 7 | " 8 | Class { 9 | #name : 'MultiByteString', 10 | #superclass : 'CharacterCollection', 11 | #category : 'Buoy-GS64-Compatibility', 12 | #package : 'Buoy-GS64-Compatibility' 13 | } 14 | -------------------------------------------------------------------------------- /source/Buoy-Math-Pharo-Extensions/PerMille.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'PerMille' } 2 | 3 | { #category : '*Buoy-Math-Pharo-Extensions' } 4 | PerMille >> printOn: aStream base: anInteger [ 5 | 6 | self value printOn: aStream base: anInteger. 7 | aStream nextPut: $‰ 8 | ] 9 | 10 | { #category : '*Buoy-Math-Pharo-Extensions' } 11 | PerMille >> storeOn: aStream base: base [ 12 | 13 | self value storeOn: aStream base: base. 14 | aStream 15 | space; 16 | nextPutAll: 'perMille' 17 | ] 18 | -------------------------------------------------------------------------------- /.github/workflows/markdown-lint.yml: -------------------------------------------------------------------------------- 1 | name: Markdown Lint 2 | on: 3 | - push 4 | - pull_request 5 | - workflow_dispatch 6 | jobs: 7 | remark-lint: 8 | name: runner / markdownlint 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: markdownlint 13 | uses: reviewdog/action-markdownlint@v0 14 | with: 15 | github_token: ${{ secrets.GITHUB_TOKEN }} 16 | fail_on_error: true 17 | reporter: github-pr-review 18 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/ImproperOperation.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, ImproperOperation is a superclass for a variety of Smalltalk coding 3 | errors, such as passing an invalid or out of range argument to a method. 4 | 5 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 6 | packages. 7 | " 8 | Class { 9 | #name : 'ImproperOperation', 10 | #superclass : 'Error', 11 | #category : 'Buoy-GS64-Compatibility', 12 | #package : 'Buoy-GS64-Compatibility' 13 | } 14 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/LookupError.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, LookupError is an ImproperOperation that is signaled when a lookup is 3 | made and not found. The key instance variable holds the missing key. 4 | 5 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 6 | packages. 7 | " 8 | Class { 9 | #name : 'LookupError', 10 | #superclass : 'ImproperOperation', 11 | #category : 'Buoy-GS64-Compatibility', 12 | #package : 'Buoy-GS64-Compatibility' 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/notify.yml: -------------------------------------------------------------------------------- 1 | name: Release Notifications 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | notify: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Notify about a new release 10 | uses: ba-st-actions/email-release-notification@v3.1.2 11 | env: 12 | SENDGRID_API_TOKEN: ${{ secrets.SENDGRID_API_TOKEN }} 13 | RECIPIENTS_URL: ${{ secrets.RECIPIENTS_URL }} 14 | DISTRIBUTION_LISTS: ${{ secrets.DISTRIBUTION_LISTS }} 15 | SENDER_EMAIL: ${{ secrets.SENDER_EMAIL }} 16 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsProcess.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, a GsProcess represents a suspended or active GemStone Smalltalk green-thread process. 3 | The in-memory state of a committed GsProcess is not changed by a transaction abort. 4 | 5 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 6 | packages. 7 | " 8 | Class { 9 | #name : 'GsProcess', 10 | #superclass : 'Object', 11 | #category : 'Buoy-GS64-Compatibility', 12 | #package : 'Buoy-GS64-Compatibility' 13 | } 14 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/Process.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Process' } 2 | 3 | { #category : '*Buoy-GS64-Compatibility' } 4 | Process >> environmentAt: object ifAbsent: block [ 5 | 6 | | index | 7 | index := Process allocatePSKey: object. 8 | ^ (self psValueAt: index) ifNil: block 9 | ] 10 | 11 | { #category : '*Buoy-GS64-Compatibility' } 12 | Process >> environmentAt: object put: anotherObject [ 13 | 14 | | index | 15 | index := Process allocatePSKey: object. 16 | ^ self psValueAt: index put: anotherObject 17 | ] 18 | -------------------------------------------------------------------------------- /source/Buoy-Math-Pharo-Extensions/Integer.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Integer' } 2 | 3 | { #category : '*Buoy-Math-Pharo-Extensions' } 4 | Integer >> asHexStringPaddedTo: minimum [ 5 | 6 | ^ String streamContents: [ :s | 7 | self 8 | printOn: s 9 | base: 16 10 | length: minimum 11 | padded: true ] 12 | ] 13 | 14 | { #category : '*Buoy-Math-Pharo-Extensions' } 15 | Integer class >> readFromHex: string ifFail: failBlock [ 16 | 17 | ^ ( NumberParser on: string ) nextIntegerBase: 16 ifFail: failBlock 18 | ] 19 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsQuery.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, a GsQuery is a programmatic way to define a query, allowing you to easily abstract, store 3 | and reuse various aspects of the query. 4 | 5 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 6 | packages. 7 | " 8 | Class { 9 | #name : 'GsQuery', 10 | #superclass : 'Object', 11 | #instVars : [ 12 | 'results', 13 | 'queryString' 14 | ], 15 | #category : 'Buoy-GS64-Compatibility', 16 | #package : 'Buoy-GS64-Compatibility' 17 | } 18 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/BinaryFloat.class.st: -------------------------------------------------------------------------------- 1 | " 2 | BinaryFloat is an abstract class in GS64, the superclass of different implementations of Binary 3 | floating point. 4 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 5 | packages. 6 | " 7 | Class { 8 | #name : 'BinaryFloat', 9 | #superclass : 'Number', 10 | #classInstVars : [ 11 | 'MinusInfinity', 12 | 'MinusQuietNaN', 13 | 'PlusInfinity' 14 | ], 15 | #category : 'Buoy-GS64-Compatibility', 16 | #package : 'Buoy-GS64-Compatibility' 17 | } 18 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/ClassOrganizer.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, a `ClassOrganizer` can answer queries about classes in the image, provides tools and reports 3 | on information on classes and methods and can perform cross-referencing and fileout. 4 | 5 | This version is just a placeholder so we can easily create extension methods referencing this class 6 | in GS64 specific packages. 7 | " 8 | Class { 9 | #name : 'ClassOrganizer', 10 | #superclass : 'Object', 11 | #category : 'Buoy-GS64-Compatibility', 12 | #package : 'Buoy-GS64-Compatibility' 13 | } 14 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Tests/StreamExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'StreamExtensionsTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Collections-Tests', 5 | #package : 'Buoy-Collections-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | StreamExtensionsTest >> testIsBinary [ 10 | 11 | self 12 | assert: #[ 1 2 ] readStream isBinary; 13 | deny: '123' readStream isBinary; 14 | deny: #( ) readStream isBinary; 15 | assert: #[ 1 2 ] writeStream isBinary; 16 | deny: '123' writeStream isBinary; 17 | deny: #( ) writeStream isBinary 18 | ] 19 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsIndexSpec.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, creating an index involves creating an instance of GsIndexSpec and sending messages to 3 | define the index and the parameters and options for that index, then use this spec to create 4 | indexes on a specific collection. 5 | 6 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 7 | packages. 8 | " 9 | Class { 10 | #name : 'GsIndexSpec', 11 | #superclass : 'Object', 12 | #category : 'Buoy-GS64-Compatibility', 13 | #package : 'Buoy-GS64-Compatibility' 14 | } 15 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/LookupError.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'LookupError' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | LookupError class >> signalFor: key [ 5 | 6 | ^ self new 7 | key: key; 8 | signal: ('Key <1p> not found.' expandMacrosWith: key) 9 | ] 10 | 11 | { #category : '*Buoy-Collections-GS64-Extensions' } 12 | LookupError class >> signalFor: key in: collection [ 13 | 14 | ^ self new 15 | key: key; 16 | signal: ('Key <1p> not found in <2p>.' 17 | expandMacrosWith: key 18 | with: collection class) 19 | ] 20 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-GS64-Extensions/Integer.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Integer' } 2 | 3 | { #category : '*Buoy-Chronology-GS64-Extensions' } 4 | Integer >> day [ 5 | 6 | ^ self days 7 | ] 8 | 9 | { #category : '*Buoy-Chronology-GS64-Extensions' } 10 | Integer >> days [ 11 | 12 | ^ Duration days: self 13 | ] 14 | 15 | { #category : '*Buoy-Chronology-GS64-Extensions' } 16 | Integer >> milliSecond [ 17 | 18 | ^ self milliSeconds 19 | ] 20 | 21 | { #category : '*Buoy-Chronology-GS64-Extensions' } 22 | Integer >> milliSeconds [ 23 | 24 | ^ Duration milliSeconds: self 25 | ] 26 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/ArgumentError.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, ArgumentError identifies a situation in which an argument to a method is invalid. 3 | The type of the argument may be valid (else it would be an ArgumentTypeError) 4 | but there is something else incorrect about an argument. 5 | 6 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 7 | packages. 8 | " 9 | Class { 10 | #name : 'ArgumentError', 11 | #superclass : 'ImproperOperation', 12 | #category : 'Buoy-GS64-Compatibility', 13 | #package : 'Buoy-GS64-Compatibility' 14 | } 15 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/WriteStreamPortable.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, WriteStreamPortable is an ANSI compliant implementation of 3 | WriteStream, a PositionableStream that allows its objects to be written, 4 | but not read. 5 | 6 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 7 | packages. 8 | " 9 | Class { 10 | #name : 'WriteStreamPortable', 11 | #superclass : 'Stream', 12 | #instVars : [ 13 | 'position', 14 | 'readLimit' 15 | ], 16 | #category : 'Buoy-GS64-Compatibility', 17 | #package : 'Buoy-GS64-Compatibility' 18 | } 19 | -------------------------------------------------------------------------------- /source/Buoy-Assertions-Extensions/Error.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Error' } 2 | 3 | { #category : '*Buoy-Assertions-Extensions' } 4 | Error >> failures [ 5 | 6 | ^ tag 7 | ] 8 | 9 | { #category : '*Buoy-Assertions-Extensions' } 10 | Error class >> signal: aFailureExplanation [ 11 | 12 | ^ self new 13 | tag: {aFailureExplanation}; 14 | signal: aFailureExplanation 15 | ] 16 | 17 | { #category : '*Buoy-Assertions-Extensions' } 18 | Error class >> signalAll: failureExplanations [ 19 | 20 | ^ self new 21 | tag: failureExplanations; 22 | signal: ('. ' join: failureExplanations) 23 | ] 24 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/OffsetError.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'OffsetError' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | OffsetError class >> signalFor: subscript [ 5 | 6 | ^ self signal: ('<1p> is out of bounds' expandMacrosWith: subscript) 7 | ] 8 | 9 | { #category : '*Buoy-Collections-GS64-Extensions' } 10 | OffsetError class >> signalFor: subscript lowerBound: lowerBound upperBound: upperBound [ 11 | 12 | ^ self signal: ('<1p> is not between <2p> and <3p>' 13 | expandMacrosWith: subscript 14 | with: lowerBound 15 | with: upperBound) 16 | ] 17 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools/Behavior.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Behavior' } 2 | 3 | { #category : '*Buoy-Development-Tools' } 4 | Behavior >> inspectionGs64Options: builder [ 5 | 6 | 7 | ^ builder newTable 8 | addColumn: ( SpStringTableColumn title: 'Option' evaluated: [ :option | option ] ); 9 | items: ( self propertyAt: #gs_options ); 10 | yourself 11 | ] 12 | 13 | { #category : '*Buoy-Development-Tools' } 14 | Behavior >> inspectionGs64OptionsContext: aContext [ 15 | 16 | aContext active: ( self hasProperty: #gs_options ) 17 | ] 18 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/ExitClientError.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, ExitClientError is a subclass of Error, 3 | signalled when the application wants topaz (or other Gci client) to exit the 4 | client process with a specified exit status. Not a fatal error ; 5 | client process should call GciLogout before exiting. 6 | 7 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 8 | packages. 9 | " 10 | Class { 11 | #name : 'ExitClientError', 12 | #superclass : 'Error', 13 | #category : 'Buoy-GS64-Compatibility', 14 | #package : 'Buoy-GS64-Compatibility' 15 | } 16 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/RcIdentitySet.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, RcIdentitySet is similar to IdentitySet, but no conflict occurs when multiple users 3 | add objects to an RcIdentitySet. If a conflict with other update operations on the 4 | RcIdentitySet occur, the add is replayed so that the commit can succeed. 5 | 6 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 7 | packages. 8 | " 9 | Class { 10 | #name : 'RcIdentitySet', 11 | #superclass : 'IdentitySet', 12 | #category : 'Buoy-GS64-Compatibility', 13 | #package : 'Buoy-GS64-Compatibility' 14 | } 15 | -------------------------------------------------------------------------------- /source/Buoy-Localization/CurrentLocale.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'CurrentLocale', 3 | #superclass : 'DynamicVariable', 4 | #category : 'Buoy-Localization', 5 | #package : 'Buoy-Localization' 6 | } 7 | 8 | { #category : 'accessing' } 9 | CurrentLocale class >> default [ 10 | 11 | ^ 'en' asLanguageTag 12 | ] 13 | 14 | { #category : 'configuring' } 15 | CurrentLocale class >> use: languageTagOrString during: aBlock [ 16 | 17 | ^ self value: languageTagOrString asLanguageTag during: aBlock 18 | ] 19 | 20 | { #category : 'accessing' } 21 | CurrentLocale >> default [ 22 | 23 | ^ self class default 24 | ] 25 | -------------------------------------------------------------------------------- /source/Buoy-Math/PerMille.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A per mille is a number or ratio expressed as a fraction of 1000. It is often denoted using the per mille sign, ""‰"". A per mille is a dimensionless number 3 | " 4 | Class { 5 | #name : 'PerMille', 6 | #superclass : 'PartsPerFraction', 7 | #category : 'Buoy-Math', 8 | #package : 'Buoy-Math' 9 | } 10 | 11 | { #category : 'private' } 12 | PerMille class >> fraction [ 13 | 14 | ^ 1000 15 | ] 16 | 17 | { #category : 'printing' } 18 | PerMille >> storeOn: aStream [ 19 | 20 | self storeValueOn: aStream. 21 | aStream 22 | space; 23 | nextPutAll: 'perMille' 24 | ] 25 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/DateAndTimeANSI.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, this protocol describes the behavior that is common to date 3 | time objects. Date time objects represent individual points 4 | in Coordinated Universal Time (UTC) as represented in an 5 | implementation defined local time, with a default resolution 6 | of seconds. 7 | 8 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 9 | packages. 10 | " 11 | Class { 12 | #name : 'DateAndTimeANSI', 13 | #superclass : 'Magnitude', 14 | #category : 'Buoy-GS64-Compatibility', 15 | #package : 'Buoy-GS64-Compatibility' 16 | } 17 | -------------------------------------------------------------------------------- /source/Buoy-Comparison/EqualityChecker.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an abstract class defining the interface for equality checking. 3 | My intent is to provide a way of compare two objects. 4 | " 5 | Class { 6 | #name : 'EqualityChecker', 7 | #superclass : 'Object', 8 | #category : 'Buoy-Comparison', 9 | #package : 'Buoy-Comparison' 10 | } 11 | 12 | { #category : 'testing' } 13 | EqualityChecker >> check: aBaseObject against: aTargetObject [ 14 | 15 | ^ self subclassResponsibility 16 | ] 17 | 18 | { #category : 'testing' } 19 | EqualityChecker >> is: aBaseObject identicalTo: aTargetObject [ 20 | 21 | ^ aBaseObject == aTargetObject 22 | ] 23 | -------------------------------------------------------------------------------- /source/Buoy-Math-Pharo-Extensions/Percentage.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Percentage' } 2 | 3 | { #category : '*Buoy-Math-Pharo-Extensions' } 4 | Percentage >> printOn: aStream base: anInteger [ 5 | 6 | self value printOn: aStream base: anInteger. 7 | aStream nextPut: $% 8 | ] 9 | 10 | { #category : '*Buoy-Math-Pharo-Extensions' } 11 | Percentage >> storeOn: aStream base: base [ 12 | 13 | self isWellKnown ifTrue: [ self storeOn: aStream ] 14 | ifFalse: [ 15 | aStream 16 | nextPutAll: self class name asString; 17 | space; 18 | nextPutAll: 'of:'; 19 | space. 20 | self value storeOn: aStream base: base 21 | ] 22 | ] 23 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools/Namespace.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Namespace' } 2 | 3 | { #category : '*Buoy-Development-Tools' } 4 | Namespace >> gtInspectorItemsIn: composite [ 5 | 6 | 7 | ^ bindings gtInspectorItemsIn: composite 8 | ] 9 | 10 | { #category : '*Buoy-Development-Tools' } 11 | Namespace >> inspectionItems: builder [ 12 | 13 | 14 | ^ bindings inspectionItems: builder 15 | ] 16 | 17 | { #category : '*Buoy-Development-Tools' } 18 | Namespace >> spotterForKeysFor: aStep [ 19 | 20 | 21 | 22 | ^ bindings spotterForKeysFor: aStep 23 | ] 24 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsQueryOptions.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, GsQueryOptions is part of the Indexing and Querying subsystem. This class encapsulates the optional refinements that may be used when creating a particular query. Each GsQuery has an associated instance of GsQueryOptions, either the default one or an instance that is created and included in the GsQuery specification method. 3 | 4 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 5 | packages. 6 | " 7 | Class { 8 | #name : 'GsQueryOptions', 9 | #superclass : 'Object', 10 | #category : 'Buoy-GS64-Compatibility', 11 | #package : 'Buoy-GS64-Compatibility' 12 | } 13 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsCurrentSession.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, GsCurrentSession provides a public interface to the current GemStone session. 3 | There is only one instance of GsCurrentSession in each GemStone session. 4 | The GemStone server creates it automatically when a user logs into GemStone. 5 | The instance is transient and cannot be accessed after the user logs out of 6 | GemStone. 7 | 8 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 9 | packages. 10 | " 11 | Class { 12 | #name : 'GsCurrentSession', 13 | #superclass : 'Object', 14 | #category : 'Buoy-GS64-Compatibility', 15 | #package : 'Buoy-GS64-Compatibility' 16 | } 17 | -------------------------------------------------------------------------------- /rowan/components/scripts/definePostLoadExceptionAliases.st: -------------------------------------------------------------------------------- 1 | | symbolDictionary assignmentCommand | 2 | symbolDictionary := Rowan image 3 | symbolDictNamed: 'Buoy' 4 | ifAbsent: [ 5 | Error signal: 'Missing Buoy symbol dictionary' 6 | ]. 7 | assignmentCommand := [ :key :contentBlock | 8 | symbolDictionary 9 | at: key 10 | ifPresent: [ :current | 11 | current ifNil: [ symbolDictionary at: key put: contentBlock value ] ] 12 | ifAbsentPut: contentBlock 13 | ]. 14 | 15 | assignmentCommand value: #AssertionFailure value: [AssertionFailed]. 16 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Extensions/PartsPerFraction.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'PartsPerFraction' } 2 | 3 | { #category : '*Buoy-Math-GS64-Extensions' } 4 | PartsPerFraction >> _coerce: aNumber [ 5 | 6 | ^ self class ratio: ( ratio _coerce: aNumber ) 7 | ] 8 | 9 | { #category : '*Buoy-Math-GS64-Extensions' } 10 | PartsPerFraction >> _generality [ 11 | 12 | ^ ratio _generality + 1 13 | ] 14 | 15 | { #category : '*Buoy-Math-GS64-Extensions' } 16 | PartsPerFraction >> printOn: stream [ 17 | 18 | self value printOn: stream 19 | ] 20 | 21 | { #category : '*Buoy-Math-GS64-Extensions' } 22 | PartsPerFraction >> printString [ 23 | 24 | ^ String streamContents: [ :stream | self printOn: stream ] 25 | ] 26 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-GS64-Extensions/Date.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Date' } 2 | 3 | { #category : '*Buoy-Chronology-GS64-Extensions' } 4 | Date >> asDateAndTime [ 5 | 6 | ^ DateAndTime year: self year month: self monthIndex day: self dayOfMonth 7 | ] 8 | 9 | { #category : '*Buoy-Chronology-GS64-Extensions' } 10 | Date class >> year: year month: month day: day [ 11 | 12 | ^ self newDay: day monthNumber: month year: year 13 | ] 14 | 15 | { #category : '*Buoy-Chronology-GS64-Extensions' } 16 | Date >> yyyymmdd [ 17 | "Format the date in ISO 8601 standard like '2002-10-22' 18 | The result is of fixed size 10 characters long." 19 | 20 | ^ self asStringUsingFormat: #( 3 2 1 $- 1 1 2 $: false ) 21 | ] 22 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/Collection.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Collection' } 2 | 3 | { #category : '*Buoy-GS64-Compatibility' } 4 | Collection >> any [ 5 | 6 | "Answer a representative sample of the receiver. It raises an error when the collection is empty. This method can be helpful when needing to preinfer the nature of the contents of semi-homogeneous collections." 7 | 8 | self emptyCheck. 9 | self do: [ :each | ^ each ] 10 | ] 11 | 12 | { #category : '*Buoy-GS64-Compatibility' } 13 | Collection >> sortAscending [ 14 | 15 | ^self asArray sorted 16 | ] 17 | 18 | { #category : '*Buoy-GS64-Compatibility' } 19 | Collection >> sortWithBlock: block [ 20 | 21 | ^self asArray sorted: block 22 | ] 23 | -------------------------------------------------------------------------------- /rowan/components/Dependent-SUnit-Extensions.ston: -------------------------------------------------------------------------------- 1 | RwSimpleProjectLoadComponentV2 { 2 | #name : 'Dependent-SUnit-Extensions', 3 | #condition : 'sunit', 4 | #projectNames : [ ], 5 | #componentNames : [ 6 | 'Deployment' 7 | ], 8 | #packageNames : [ 9 | 'Buoy-SUnit-Model', 10 | 'Buoy-SUnit-GS64-Extensions' 11 | ], 12 | #conditionalPackageMapSpecs : { 13 | 'gemstone' : { 14 | 'allusers' : { 15 | #packageNameToPlatformPropertiesMap : { 16 | 'Buoy-SUnit-Model' : { 'symbolDictName' : 'Globals' }, 17 | 'Buoy-SUnit-GS64-Extensions' : { 'symbolDictName' : 'Globals' } 18 | } 19 | } 20 | } 21 | }, 22 | #comment : 'Extensions to TestAsserter' 23 | } 24 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/Object.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Object' } 2 | 3 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 4 | Object >> assert: aBlock [ 5 | 6 | self assert: aBlock description: 'Assertion failed' 7 | ] 8 | 9 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 10 | Object >> assert: aBlock description: aBlockOrString [ 11 | 12 | aBlock value == true ifFalse: [ 13 | AssertionFailed signal: aBlockOrString value ] 14 | ] 15 | 16 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 17 | Object >> isNotNil [ 18 | 19 | ^ self notNil 20 | ] 21 | 22 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 23 | Object class >> new [ 24 | 25 | ^ super new initialize 26 | ] 27 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Pharo-Extensions/OSPlatform.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'OSPlatform' } 2 | 3 | { #category : '*Buoy-Metaprogramming-Pharo-Extensions' } 4 | OSPlatform >> environmentAt: aVariableName ifPresent: aBlock ifAbsent: anAbsentBlock [ 5 | 6 | ^ self environment 7 | at: aVariableName 8 | ifPresent: aBlock 9 | ifAbsent: anAbsentBlock 10 | ] 11 | 12 | { #category : '*Buoy-Metaprogramming-Pharo-Extensions' } 13 | OSPlatform >> environmentAt: variableName put: value [ 14 | 15 | self environment at: variableName put: value 16 | ] 17 | 18 | { #category : '*Buoy-Metaprogramming-Pharo-Extensions' } 19 | OSPlatform >> removeEnvironmentKey: variableName [ 20 | 21 | self environment removeKey: variableName 22 | ] 23 | -------------------------------------------------------------------------------- /source/Buoy-Collections/Formatter.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an abstract class for formatters. 3 | 4 | A formatter is an object that knows how to convert a given object into a string representation. 5 | " 6 | Class { 7 | #name : 'Formatter', 8 | #superclass : 'Object', 9 | #category : 'Buoy-Collections', 10 | #package : 'Buoy-Collections' 11 | } 12 | 13 | { #category : 'testing' } 14 | Formatter class >> isAbstract [ 15 | 16 | ^ self = Formatter 17 | ] 18 | 19 | { #category : 'formatting' } 20 | Formatter >> format: aCollection [ 21 | 22 | ^ String streamContents: [ :stream | self format: aCollection on: stream ] 23 | ] 24 | 25 | { #category : 'formatting' } 26 | Formatter >> format: object on: stream [ 27 | 28 | self subclassResponsibility 29 | ] 30 | -------------------------------------------------------------------------------- /docs/reference/Namespaces.md: -------------------------------------------------------------------------------- 1 | # Namespaces 2 | 3 | A namespace is responsible for binding a set of symbols to objects of various 4 | kinds, so that these objects may be referred to by name. 5 | 6 | You can instantiate a namespace and start binding names to any kind of object: 7 | 8 | ```smalltalk 9 | | cssConstants | 10 | cssConstants := Namespace new. 11 | cssConstants 12 | bind: #inherit to: 'inherit'; 13 | bind: #white to: Color white 14 | ``` 15 | 16 | By default, you can't bind a name already bound, but you can use the `rebind:to:` 17 | message to accomplish that. 18 | 19 | Now it's possible to access the object bound by name: 20 | 21 | ```smalltalk 22 | cssConstants >> #white 23 | ``` 24 | 25 | will return an object representing the white color. 26 | -------------------------------------------------------------------------------- /.github/workflows/unit-tests-gs64.yml: -------------------------------------------------------------------------------- 1 | name: 'GS64 Unit Tests' 2 | on: 3 | - push 4 | - pull_request 5 | - workflow_dispatch 6 | 7 | jobs: 8 | unit-tests-3_7_0: 9 | runs-on: ubuntu-latest 10 | name: GS64 3.7.0 Unit Tests 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Load Image and Run Tests 14 | uses: ba-st-actions/gs64-ci@v2 15 | with: 16 | project_name: 'Buoy' 17 | run_tests: 'true' 18 | unit-tests-3_7_1: 19 | runs-on: ubuntu-latest 20 | name: GS64 3.7.1 Unit Tests 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Load Image and Run Tests 24 | uses: ba-st-actions/gs64-ci@v3 25 | with: 26 | project_name: 'Buoy' 27 | run_tests: 'true' 28 | -------------------------------------------------------------------------------- /source/Buoy-Comparison/BitwiseExclusiveDisjunctionHashCombinator.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a HashCombinator that uses bitXor: as the operation combinator. 3 | " 4 | Class { 5 | #name : 'BitwiseExclusiveDisjunctionHashCombinator', 6 | #superclass : 'HashCombinator', 7 | #classInstVars : [ 8 | 'uniqueInstance' 9 | ], 10 | #category : 'Buoy-Comparison', 11 | #package : 'Buoy-Comparison' 12 | } 13 | 14 | { #category : 'instance creation' } 15 | BitwiseExclusiveDisjunctionHashCombinator class >> new [ 16 | 17 | uniqueInstance ifNil: [ uniqueInstance := super new ]. 18 | ^ uniqueInstance 19 | ] 20 | 21 | { #category : 'combining' } 22 | BitwiseExclusiveDisjunctionHashCombinator >> combine: acumulatedHashValue with: hashValue [ 23 | 24 | ^ acumulatedHashValue bitXor: hashValue 25 | ] 26 | -------------------------------------------------------------------------------- /source/Buoy-Localization-GS64-Extensions/NaturalLanguageTranslator.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A NaturalLanguageTranslator is a placeholder for a language translator. 3 | 4 | " 5 | Class { 6 | #name : 'NaturalLanguageTranslator', 7 | #superclass : 'Object', 8 | #classVars : [ 9 | 'Current' 10 | ], 11 | #category : 'Buoy-Localization-GS64-Extensions', 12 | #package : 'Buoy-Localization-GS64-Extensions' 13 | } 14 | 15 | { #category : 'accessing' } 16 | NaturalLanguageTranslator class >> current [ 17 | "Return the currently registered translator" 18 | 19 | ^Current 20 | ] 21 | 22 | { #category : 'accessing' } 23 | NaturalLanguageTranslator class >> current: aTranslator [ 24 | "Register a translator that should receiver the translation messages" 25 | 26 | Current := aTranslator 27 | ] 28 | -------------------------------------------------------------------------------- /source/Buoy-Localization-Tests/StringEscapingRuleTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A StringEscapingRuleTest is a test class for testing the behavior of StringEscapingRule 3 | " 4 | Class { 5 | #name : 'StringEscapingRuleTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Localization-Tests', 8 | #package : 'Buoy-Localization-Tests' 9 | } 10 | 11 | { #category : 'tests' } 12 | StringEscapingRuleTest >> testIsAbstract [ 13 | 14 | self assert: StringEscapingRule isAbstract 15 | ] 16 | 17 | { #category : 'tests' } 18 | StringEscapingRuleTest >> testPriority [ 19 | 20 | self 21 | assert: ReverseSolidusEscapingRule new priority > ControlCharactersEscapingRule new priority; 22 | assert: ControlCharactersEscapingRule new priority > UnicodeCharacterEscapingRule new priority 23 | ] 24 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/Array.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Array' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | Array >> fillFrom: aCollection with: aBlock [ 5 | 6 | | index | 7 | index := 0. 8 | aCollection do: [ :each | 9 | self at: (index := index + 1) put: (aBlock value: each) ] 10 | ] 11 | 12 | { #category : '*Buoy-Collections-GS64-Extensions' } 13 | Array >> isArray [ 14 | 15 | ^ true 16 | ] 17 | 18 | { #category : '*Buoy-Collections-GS64-Extensions' } 19 | Array class >> newFrom: aCollection [ 20 | "Answer an instance of me containing the same elements as aCollection." 21 | 22 | | newArray | 23 | newArray := self new: aCollection size. 24 | 1 to: aCollection size do: [ :i | 25 | newArray at: i put: (aCollection at: i) ]. 26 | ^ newArray 27 | ] 28 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Tests/NegatedConditionTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'NegatedConditionTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Conditions-Tests', 5 | #package : 'Buoy-Conditions-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | NegatedConditionTest >> testIsSatisfied [ 10 | 11 | | condition | 12 | 13 | condition := NegatedCondition with: (ArithmeticCondition toBeEqualTo: 10). 14 | 15 | self 16 | assert: (condition isSatisfiedBy: 8); 17 | deny: (condition isSatisfiedBy: 10) 18 | ] 19 | 20 | { #category : 'tests' } 21 | NegatedConditionTest >> testShortcut [ 22 | 23 | | condition | 24 | 25 | condition := (ArithmeticCondition toBeEqualTo: 10) negated. 26 | 27 | self 28 | assert: (condition isSatisfiedBy: 8); 29 | deny: (condition isSatisfiedBy: 10) 30 | ] 31 | -------------------------------------------------------------------------------- /source/Buoy-Dynamic-Binding/DefinedBinding.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I represent a binding to some object, so I can return a content. 3 | " 4 | Class { 5 | #name : 'DefinedBinding', 6 | #superclass : 'Binding', 7 | #instVars : [ 8 | 'content' 9 | ], 10 | #category : 'Buoy-Dynamic-Binding', 11 | #package : 'Buoy-Dynamic-Binding' 12 | } 13 | 14 | { #category : 'Instance Creation' } 15 | DefinedBinding class >> connectedTo: anObject [ 16 | 17 | ^ self new initializeConnectedTo: anObject 18 | ] 19 | 20 | { #category : 'Accessing' } 21 | DefinedBinding >> content [ 22 | 23 | ^ content 24 | ] 25 | 26 | { #category : 'initialize' } 27 | DefinedBinding >> initializeConnectedTo: anObject [ 28 | 29 | content := anObject 30 | ] 31 | 32 | { #category : 'testing' } 33 | DefinedBinding >> isDefined [ 34 | 35 | ^ true 36 | ] 37 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsIndexOptions.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, an instance of GsIndexOptions specifies features that will be used when creating a particular index on a collection. GsIndexSpec index definition methods all have variants that accept an instance of GsIndexOptions, although some override certain settings. If no GsIndexOptions is explicitly provided, the session or repository default is used. 3 | The GsIndexOptions defines if the index is a legacy index or a btreePlus index, as well as other important indexing features. 4 | 5 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 6 | packages. 7 | " 8 | Class { 9 | #name : 'GsIndexOptions', 10 | #superclass : 'Object', 11 | #category : 'Buoy-GS64-Compatibility', 12 | #package : 'Buoy-GS64-Compatibility' 13 | } 14 | -------------------------------------------------------------------------------- /source/Buoy-Conditions/Condition.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a Condition. 3 | I'm an abstract class. 4 | 5 | I test if a provided value is valid against me. 6 | 7 | " 8 | Class { 9 | #name : 'Condition', 10 | #superclass : 'Object', 11 | #category : 'Buoy-Conditions', 12 | #package : 'Buoy-Conditions' 13 | } 14 | 15 | { #category : 'composing' } 16 | Condition >> and: aCondition [ 17 | 18 | ^ CompositeCondition satisfying: self and: aCondition 19 | ] 20 | 21 | { #category : 'testing' } 22 | Condition >> isSatisfiedBy: aValue [ 23 | 24 | self subclassResponsibility 25 | ] 26 | 27 | { #category : 'negating' } 28 | Condition >> negated [ 29 | 30 | ^ NegatedCondition with: self. 31 | ] 32 | 33 | { #category : 'composing' } 34 | Condition >> or: aCondition [ 35 | 36 | ^ CompositeCondition satisfying: self or: aCondition 37 | ] 38 | -------------------------------------------------------------------------------- /source/Buoy-Localization-Pharo-Extensions/PolyglotNaturalLanguageTranslator.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'PolyglotNaturalLanguageTranslator' } 2 | 3 | { #category : '*Buoy-Localization-Pharo-Extensions' } 4 | PolyglotNaturalLanguageTranslator >> cleanUp [ 5 | "Just for Pharo compatibility. 6 | We don't re-initialize, so that any translations installed are kept when preparing the image for deployment." 7 | 8 | 9 | ] 10 | 11 | { #category : '*Buoy-Localization-Pharo-Extensions' } 12 | PolyglotNaturalLanguageTranslator >> translate: string [ 13 | "Just for Pharo compatibility" 14 | 15 | ^ string 16 | ] 17 | 18 | { #category : '*Buoy-Localization-Pharo-Extensions' } 19 | PolyglotNaturalLanguageTranslator >> translate: string toLocale: localeID [ 20 | "Just for Pharo compatibility" 21 | 22 | ^ self translate: string 23 | ] 24 | -------------------------------------------------------------------------------- /docs/reference/Interfaces.md: -------------------------------------------------------------------------------- 1 | # Interfaces 2 | 3 | An interface is useful for declaring a set of messages to be understood by the 4 | objects implementing it. 5 | 6 | > It's not intended to be used as some kind of static type check, but to 7 | > document an expected protocol. 8 | 9 | Once you have an interface you can ask it if some object is implementing it: 10 | 11 | ```smalltalk 12 | | interface | 13 | interface := Interface named: 'Assertable' declaring: #( #assert: #deny: ). 14 | interface isImplementedBy: 1 15 | ``` 16 | 17 | will return `false` 18 | 19 | You can also ask it if an instance of some class will implement it: 20 | 21 | ```smalltalk 22 | | interface | 23 | interface := Interface named: 'Assertable' declaring: #( #assert: #deny: ). 24 | interface isImplementedByInstancesOf: TestCase 25 | ``` 26 | 27 | will return `true` 28 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsSocket.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, GsSocket provides the means for creating and binding TCP sockets through the 3 | operating system of the machine that is running the session's Gem process, and 4 | for communicating across those sockets. 5 | When the current GsProcess is suspended until a socket is ready to read or write, 6 | other GsProcess that are ready to run will be run by the process scheduler. 7 | Methods that suspend the current GsProcess until the socket operation completes 8 | are interruptable by a hard break. 9 | 10 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 11 | packages. 12 | " 13 | Class { 14 | #name : 'GsSocket', 15 | #superclass : 'Object', 16 | #category : 'Buoy-GS64-Compatibility', 17 | #package : 'Buoy-GS64-Compatibility' 18 | } 19 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/Class.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Class' } 2 | 3 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 4 | Class >> allLeafSubclasses [ 5 | 6 | | leafs | 7 | leafs := OrderedCollection new. 8 | (ClassOrganizer new allSubclassesOf: self) do: [ :class | 9 | class subclasses ifEmpty: [ leafs add: class ] ]. 10 | ^ leafs 11 | ] 12 | 13 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 14 | Class >> allSubclassesDo: aBlock [ 15 | "Evaluate the argument, aBlock, for each of the receiver's subclasses." 16 | 17 | self allSubclasses do: aBlock 18 | ] 19 | 20 | { #category : '*Buoy-Metaprogramming-GS64-Extensions' } 21 | Class >> subclassesDo: aBlock [ 22 | "Evaluate the argument, aBlock, for each of the receiver's immediate subclasses." 23 | 24 | self subclasses do: aBlock 25 | ] 26 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming/MessageSendingCollector.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'MessageSendingCollector', 3 | #superclass : 'Object', 4 | #category : 'Buoy-Metaprogramming', 5 | #package : 'Buoy-Metaprogramming' 6 | } 7 | 8 | { #category : 'private' } 9 | MessageSendingCollector >> filterBlock [ 10 | 11 | ^ self subclassResponsibility 12 | ] 13 | 14 | { #category : 'private' } 15 | MessageSendingCollector >> matchingSelectorsCollect: aTransformationBlock [ 16 | 17 | ^ self receiver class allSelectors asSortedCollection 18 | select: self filterBlock 19 | thenCollect: aTransformationBlock 20 | ] 21 | 22 | { #category : 'private' } 23 | MessageSendingCollector >> receiver [ 24 | 25 | ^ self subclassResponsibility 26 | ] 27 | 28 | { #category : 'evaluating' } 29 | MessageSendingCollector >> value [ 30 | 31 | ^ self subclassResponsibility 32 | ] 33 | -------------------------------------------------------------------------------- /docs/how-to/how-to-support-gs64-options.md: -------------------------------------------------------------------------------- 1 | # How to support GS64 class options 2 | 3 | GemStone/S 64 includes some options during class creation that change the 4 | behavior of instances of that class. 5 | 6 | Rowan has support to specify these options using the Tonel format 7 | by filling the `gs_options` metadata in the class creation section. However, 8 | Pharo will be default remove this metadata when committing code, which loses these 9 | options. To avoid this behavior and retain the options, load the `Tool` group 10 | and send in a post load script one of the following messages to the class: 11 | 12 | - `makeInstancesDbTransient` 13 | - `makeInstancesInvariant` 14 | - `makeInstancesNonPersistent` 15 | 16 | This will configure the options as class properties in Pharo, which will then be 17 | used by the Tonel Writer to set these options to the metadata. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/Integer.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Integer' } 2 | 3 | { #category : '*Buoy-GS64-Compatibility' } 4 | Integer >> asHexString [ 5 | 6 | ^ self printStringBase: 16 7 | ] 8 | 9 | { #category : '*Buoy-GS64-Compatibility' } 10 | Integer >> asHexStringWithLength: minimum [ 11 | 12 | ^ String streamContents: [ :s | 13 | self 14 | printOn: s 15 | base: 16 16 | length: minimum 17 | padded: true ] 18 | ] 19 | 20 | { #category : '*Buoy-GS64-Compatibility' } 21 | Integer class >> fromStream: aStream [ 22 | 23 | ^ (NumberParser on: aStream) 24 | nextIntegerBase: 10 25 | ifFail: [ ImproperOperation signal ] 26 | ] 27 | 28 | { #category : '*Buoy-GS64-Compatibility' } 29 | Integer class >> fromString: aString [ 30 | 31 | ^ (NumberParser on: aString) 32 | nextIntegerBase: 10 33 | ifFail: [ ImproperOperation signal ] 34 | ] 35 | -------------------------------------------------------------------------------- /rowan/components/scripts/defineClassAliases.st: -------------------------------------------------------------------------------- 1 | | symbolDictionary | 2 | symbolDictionary := Rowan image 3 | symbolDictNamed: 'Buoy' 4 | ifAbsent: [ 5 | Rowan image symbolList createDictionaryNamed: 'Buoy' at: Rowan image symbolList size + 1. 6 | Rowan image symbolDictNamed: 'Buoy' 7 | ]. 8 | 9 | symbolDictionary at: #ArithmeticError ifAbsentPut: [NumericError]. 10 | symbolDictionary at: #KeyNotFound ifAbsentPut: [LookupError]. 11 | symbolDictionary at: #NotFound ifAbsentPut: [LookupError]. 12 | symbolDictionary at: #SubscriptOutOfBounds ifAbsentPut: [OffsetError]. 13 | symbolDictionary at: #SmallDictionary ifAbsentPut: [Dictionary]. 14 | symbolDictionary at: #Exit ifAbsentPut: [ExitClientError]. 15 | symbolDictionary at: #CollectionIsEmpty ifAbsentPut: [ImproperOperation]. 16 | "Temporary, it will be fixed in a post load script" 17 | symbolDictionary at: #AssertionFailure ifAbsentPut: [nil]. 18 | -------------------------------------------------------------------------------- /source/Buoy-Comparison-Tests/BuoyComparisonObjectExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'BuoyComparisonObjectExtensionsTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Comparison-Tests', 5 | #package : 'Buoy-Comparison-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | BuoyComparisonObjectExtensionsTest >> testEqual [ 10 | 11 | self 12 | assert: ( ObjectUsingComparisonAffordances with: 1 and: 2 ) 13 | equals: ( ObjectUsingComparisonAffordances with: 1 and: 2 ); 14 | deny: ( ObjectUsingComparisonAffordances with: 1 and: 2 ) 15 | equals: ( ObjectUsingComparisonAffordances with: 2 and: 1 ); 16 | deny: ( ObjectUsingComparisonAffordances with: 1 and: 2 ) equals: self 17 | ] 18 | 19 | { #category : 'tests' } 20 | BuoyComparisonObjectExtensionsTest >> testHash [ 21 | 22 | self 23 | assert: (ObjectUsingComparisonAffordances with: 1 and: 2) hash 24 | equals: (1 hash bitXor: 2 hash) 25 | ] 26 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/RaiseOnFirstAssertionFailurePolicy.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an assertion policy that raises and exception on the first assertion failure (failing fast) 3 | " 4 | Class { 5 | #name : 'RaiseOnFirstAssertionFailurePolicy', 6 | #superclass : 'AssertionFailurePolicy', 7 | #instVars : [ 8 | 'errorClass' 9 | ], 10 | #category : 'Buoy-Assertions', 11 | #package : 'Buoy-Assertions' 12 | } 13 | 14 | { #category : 'Instance Creation' } 15 | RaiseOnFirstAssertionFailurePolicy class >> raising: anErrorClass [ 16 | 17 | ^ self new initializeRaising: anErrorClass 18 | ] 19 | 20 | { #category : 'notifying' } 21 | RaiseOnFirstAssertionFailurePolicy >> assertionFailedBecause: aFailureExplanation [ 22 | 23 | errorClass signal: aFailureExplanation 24 | ] 25 | 26 | { #category : 'initialization' } 27 | RaiseOnFirstAssertionFailurePolicy >> initializeRaising: anErrorClass [ 28 | 29 | errorClass := anErrorClass 30 | ] 31 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/AssertionFailurePolicy.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I represent an assertion failure policy that applies to some asserter. My purpose is to define how to handle an assertion failure. 3 | " 4 | Class { 5 | #name : 'AssertionFailurePolicy', 6 | #superclass : 'Object', 7 | #category : 'Buoy-Assertions', 8 | #package : 'Buoy-Assertions' 9 | } 10 | 11 | { #category : 'Accessing' } 12 | AssertionFailurePolicy class >> defaultErrorToSignal [ 13 | 14 | ^ AssertionFailed 15 | ] 16 | 17 | { #category : 'Instance Creation' } 18 | AssertionFailurePolicy class >> raising: anErrorClass [ 19 | 20 | ^ self subclassResponsibility 21 | ] 22 | 23 | { #category : 'applying' } 24 | AssertionFailurePolicy >> applyTo: anAsserter [ 25 | 26 | anAsserter checkApplying: self 27 | ] 28 | 29 | { #category : 'notifying' } 30 | AssertionFailurePolicy >> assertionFailedBecause: aFailureExplanation [ 31 | 32 | self subclassResponsibility 33 | ] 34 | -------------------------------------------------------------------------------- /source/Buoy-Conditions/NegatedCondition.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a Condition. 3 | I'm a NegatedCondition 4 | 5 | I test the opposite of the condition I was created with. 6 | 7 | Example: 8 | (ArithmeticCondition toBeEqualTo: 1) negated. 9 | 10 | Behaves like: 11 | (ArithmeticCondition toBeDifferentTo: 1) 12 | 13 | " 14 | Class { 15 | #name : 'NegatedCondition', 16 | #superclass : 'Condition', 17 | #instVars : [ 18 | 'condition' 19 | ], 20 | #category : 'Buoy-Conditions', 21 | #package : 'Buoy-Conditions' 22 | } 23 | 24 | { #category : 'instance creation' } 25 | NegatedCondition class >> with: aCondition [ 26 | 27 | ^ self new initializeWith: aCondition 28 | ] 29 | 30 | { #category : 'initialize-release' } 31 | NegatedCondition >> initializeWith: aCondition [ 32 | 33 | condition := aCondition 34 | ] 35 | 36 | { #category : 'testing' } 37 | NegatedCondition >> isSatisfiedBy: aValue [ 38 | 39 | ^ (condition isSatisfiedBy: aValue) not 40 | ] 41 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-Tests/DateExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'DateExtensionsTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Chronology-Tests', 5 | #package : 'Buoy-Chronology-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | DateExtensionsTest >> testAsDateAndTime [ 10 | 11 | | date dateAndTime | 12 | date := Date newDay: 5 monthNumber: 4 year: 2023. 13 | dateAndTime := date asDateAndTime. 14 | 15 | self 16 | assert: date year equals: dateAndTime year; 17 | assert: date monthIndex equals: dateAndTime monthIndex; 18 | assert: date dayOfMonth equals: dateAndTime dayOfMonth; 19 | assert: dateAndTime hour isZero; 20 | assert: dateAndTime minute isZero; 21 | assert: dateAndTime second isZero 22 | ] 23 | 24 | { #category : 'tests' } 25 | DateExtensionsTest >> testCreation [ 26 | 27 | | date | 28 | date := Date newDay: 5 monthNumber: 4 year: 2023. 29 | 30 | self assert: date yyyymmdd equals: '2023-04-05' 31 | ] 32 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/GsFile.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, GsFile provides the means for creating and accessing files. These 3 | files reside in the file system on either the machine that is running the 4 | current session's Gem process (the server machine) or the machine that is 5 | running the client application (the client machine). The files may be of any 6 | type, textual or binary, though separate protocol is provided for reading and 7 | writing these types of data. File contents are in bytes and writing kinds of 8 | String that require multiple bytes per code pint, the contents must be 9 | explicitly encoded before write, or written using nextPutAllUtf8:. 10 | 11 | This version is just a placeholder so we can easily create extension methods to load in GS64 specific 12 | packages. 13 | " 14 | Class { 15 | #name : 'GsFile', 16 | #superclass : 'Object', 17 | #category : 'Buoy-GS64-Compatibility', 18 | #package : 'Buoy-GS64-Compatibility' 19 | } 20 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Pharo-Extensions/RegexCondition.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a Condition. 3 | I'm a RegexCondition 4 | 5 | I test a regex pattern against a provided string. 6 | 7 | Example: 8 | RegexCondition matching: 'I...' 9 | 10 | For more examples, besides the provided test, check Regular expressions framework documentation on Pharo help. 11 | " 12 | Class { 13 | #name : 'RegexCondition', 14 | #superclass : 'Condition', 15 | #instVars : [ 16 | 'pattern' 17 | ], 18 | #category : 'Buoy-Conditions-Pharo-Extensions', 19 | #package : 'Buoy-Conditions-Pharo-Extensions' 20 | } 21 | 22 | { #category : 'instance creation' } 23 | RegexCondition class >> matching: aPattern [ 24 | 25 | ^ self new initializeMatching: aPattern 26 | ] 27 | 28 | { #category : 'initialization' } 29 | RegexCondition >> initializeMatching: aPattern [ 30 | 31 | pattern := aPattern asRegex 32 | ] 33 | 34 | { #category : 'testing' } 35 | RegexCondition >> isSatisfiedBy: aString [ 36 | 37 | ^ pattern matches: aString 38 | ] 39 | -------------------------------------------------------------------------------- /source/Buoy-Localization-Pharo-Extensions/String.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'String' } 2 | 3 | { #category : '*Buoy-Localization-Pharo-Extensions' } 4 | String >> asLanguageRange [ 5 | 6 | ^ LanguageRange fromString: self 7 | ] 8 | 9 | { #category : '*Buoy-Localization-Pharo-Extensions' } 10 | String >> asLanguageTag [ 11 | 12 | ^ LanguageTag fromString: self 13 | ] 14 | 15 | { #category : '*Buoy-Localization-Pharo-Extensions' } 16 | String >> escaped [ 17 | 18 | ^ EscapingAlgorithm new escape: self 19 | ] 20 | 21 | { #category : '*Buoy-Localization-Pharo-Extensions' } 22 | String >> localized [ 23 | 24 | ^ self localizedWithAll: #( ) 25 | ] 26 | 27 | { #category : '*Buoy-Localization-Pharo-Extensions' } 28 | String >> localizedWithAll: collection [ 29 | 30 | ^ NaturalLanguageTranslator current localize: self withAll: collection to: CurrentLocale value 31 | ] 32 | 33 | { #category : '*Buoy-Localization-Pharo-Extensions' } 34 | String >> unescaped [ 35 | 36 | ^ EscapingAlgorithm new unescape: self 37 | ] 38 | -------------------------------------------------------------------------------- /source/Buoy-GS64-Compatibility/System.class.st: -------------------------------------------------------------------------------- 1 | " 2 | In GS64, System is an abstract class that has no instances. It implements class 3 | methods for object locking and for operations that are usually found in 4 | traditional operating systems. The data curator may restrict user access to 5 | these messages. 6 | 7 | This version is just a placeholder so we can easily create extensions methods to load in GS64 specific 8 | packages. 9 | " 10 | Class { 11 | #name : 'System', 12 | #superclass : 'Object', 13 | #category : 'Buoy-GS64-Compatibility', 14 | #package : 'Buoy-GS64-Compatibility' 15 | } 16 | 17 | { #category : 'accessing' } 18 | System class >> commandLineArguments [ 19 | 20 | | arguments documentPath | 21 | arguments := OrderedCollection withAll: Smalltalk arguments. 22 | documentPath := Smalltalk vm documentPath. 23 | documentPath isEmptyOrNil ifFalse: [ 24 | arguments addFirst: documentPath ]. 25 | ^ arguments 26 | ] 27 | 28 | { #category : 'accessing' } 29 | System class >> timeGmt [ 30 | 31 | ^ Time millisecondClockValue 32 | ] 33 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-GS64-Extensions/Number.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Number' } 2 | 3 | { #category : '*Buoy-Chronology-GS64-Extensions' } 4 | Number >> asDuration [ 5 | 6 | ^ Duration seconds: self asInteger 7 | ] 8 | 9 | { #category : '*Buoy-Chronology-GS64-Extensions' } 10 | Number >> hour [ 11 | 12 | ^ self hours 13 | ] 14 | 15 | { #category : '*Buoy-Chronology-GS64-Extensions' } 16 | Number >> hours [ 17 | 18 | ^ Duration hours: self 19 | ] 20 | 21 | { #category : '*Buoy-Chronology-GS64-Extensions' } 22 | Number >> minute [ 23 | 24 | ^ self minutes 25 | ] 26 | 27 | { #category : '*Buoy-Chronology-GS64-Extensions' } 28 | Number >> minutes [ 29 | 30 | ^ Duration minutes: self 31 | ] 32 | 33 | { #category : '*Buoy-Chronology-GS64-Extensions' } 34 | Number >> second [ 35 | "1 second printString >>> '0:00:00:01'" 36 | "(1 minute + 1 second) printString >>> '0:00:01:01'" 37 | 38 | ^ self seconds 39 | ] 40 | 41 | { #category : '*Buoy-Chronology-GS64-Extensions' } 42 | Number >> seconds [ 43 | 44 | ^ Duration seconds: self 45 | ] 46 | -------------------------------------------------------------------------------- /.github/workflows/unit-tests.yml: -------------------------------------------------------------------------------- 1 | name: Pharo Unit Tests 2 | on: 3 | - push 4 | - pull_request 5 | - workflow_dispatch 6 | 7 | jobs: 8 | unit-tests: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | smalltalk: 13 | - Pharo64-9.0 14 | - Pharo64-10 15 | - Pharo64-11 16 | - Pharo64-12 17 | - Pharo64-13 18 | name: ${{ matrix.smalltalk }} 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: hpi-swa/setup-smalltalkCI@v1 22 | with: 23 | smalltalk-image: ${{ matrix.smalltalk }} 24 | - name: Load Image and Run Tests 25 | run: smalltalkci -s ${{ matrix.smalltalk }} .smalltalkci/.unit-tests.ston 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | timeout-minutes: 15 29 | - name: Upload coverage to Codecov 30 | uses: codecov/codecov-action@v5 31 | with: 32 | name: Unit-Tests-${{matrix.smalltalk}} 33 | token: ${{ secrets.CODECOV_TOKEN }} 34 | flags: unit 35 | -------------------------------------------------------------------------------- /.github/workflows/loading-groups.yml: -------------------------------------------------------------------------------- 1 | name: Baseline groups 2 | on: 3 | - push 4 | - pull_request 5 | - workflow_dispatch 6 | 7 | jobs: 8 | group-loading: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | smalltalk: 14 | - Pharo64-9.0 15 | - Pharo64-10 16 | - Pharo64-11 17 | - Pharo64-12 18 | - Pharo64-13 19 | load-spec: 20 | - development 21 | - dependent-sunit-extensions 22 | - deployment 23 | - tests 24 | - tools 25 | name: ${{ matrix.smalltalk }} + ${{ matrix.load-spec }} 26 | steps: 27 | - uses: actions/checkout@v4 28 | - uses: hpi-swa/setup-smalltalkCI@v1 29 | with: 30 | smalltalk-image: ${{ matrix.smalltalk }} 31 | - name: Load group in image 32 | run: smalltalkci -s ${{ matrix.smalltalk }} .smalltalkci/.loading.${{ matrix.load-spec }}.ston 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | timeout-minutes: 15 36 | -------------------------------------------------------------------------------- /source/Buoy-Dynamic-Binding/UndefinedBinding.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I represent an unbound object and will raise an error when asked about my contents 3 | " 4 | Class { 5 | #name : 'UndefinedBinding', 6 | #superclass : 'Binding', 7 | #instVars : [ 8 | 'errorClass', 9 | 'explanations' 10 | ], 11 | #category : 'Buoy-Dynamic-Binding', 12 | #package : 'Buoy-Dynamic-Binding' 13 | } 14 | 15 | { #category : 'Instance Creation' } 16 | UndefinedBinding class >> explainedByAll: anExplanationCollection raising: anErrorClass [ 17 | 18 | ^ self new initializeExplainedByAll: anExplanationCollection raising: anErrorClass 19 | ] 20 | 21 | { #category : 'Accessing' } 22 | UndefinedBinding >> content [ 23 | 24 | ^errorClass signalAll: explanations 25 | ] 26 | 27 | { #category : 'initialize' } 28 | UndefinedBinding >> initializeExplainedByAll: anExplanationCollection raising: anErrorClass [ 29 | 30 | explanations := anExplanationCollection. 31 | errorClass := anErrorClass 32 | ] 33 | 34 | { #category : 'testing' } 35 | UndefinedBinding >> isDefined [ 36 | 37 | ^ false 38 | ] 39 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-Tests/NumberChronologyExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'NumberChronologyExtensionsTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Chronology-Tests', 5 | #package : 'Buoy-Chronology-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | NumberChronologyExtensionsTest >> testDays [ 10 | 11 | self 12 | assert: 1 day equals: (Duration days: 1); 13 | assert: 2 days equals: (Duration days: 2) 14 | ] 15 | 16 | { #category : 'tests' } 17 | NumberChronologyExtensionsTest >> testHours [ 18 | 19 | self 20 | assert: 1 hour equals: (Duration hours: 1); 21 | assert: 2 hours equals: (Duration hours: 2) 22 | ] 23 | 24 | { #category : 'tests' } 25 | NumberChronologyExtensionsTest >> testMilliSeconds [ 26 | 27 | self 28 | assert: 1000 milliSeconds equals: 1 second; 29 | assert: 2000 milliSeconds equals: 2 seconds 30 | ] 31 | 32 | { #category : 'tests' } 33 | NumberChronologyExtensionsTest >> testSeconds [ 34 | 35 | self 36 | assert: 1 second equals: (Duration seconds: 1); 37 | assert: 2 seconds equals: (Duration seconds: 2) 38 | ] 39 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Tests/DynamicVariableTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'DynamicVariableTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Metaprogramming-Tests', 5 | #package : 'Buoy-Metaprogramming-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | DynamicVariableTest >> testDynamicVariableBlockReturnValue [ 10 | 11 | | returnValue | 12 | returnValue := DynamicVariableForTesting 13 | value: 10 14 | during: [ DynamicVariableForTesting value + 1 ]. 15 | self assert: returnValue equals: 11 16 | ] 17 | 18 | { #category : 'tests' } 19 | DynamicVariableTest >> testDynamicVariableDefault [ 20 | 21 | self 22 | assert: DynamicVariableForTesting new default equals: 3; 23 | assert: DynamicVariableForTesting value equals: 3 24 | ] 25 | 26 | { #category : 'tests' } 27 | DynamicVariableTest >> testDynamicVariableRemovedAfterUse [ 28 | 29 | DynamicVariableForTesting value: 8 during: [ ]. 30 | 31 | self 32 | assert: DynamicVariableForTesting default equals: 3; 33 | assert: DynamicVariableForTesting value equals: 3 34 | ] 35 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Pharo-Extensions-Tests/RegexConditionTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'RegexConditionTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Conditions-Pharo-Extensions-Tests', 5 | #package : 'Buoy-Conditions-Pharo-Extensions-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | RegexConditionTest >> testIsSatisfied [ 10 | 11 | | condition | 12 | 13 | condition := RegexCondition matching: 'ab*'. 14 | 15 | self 16 | assert: (condition isSatisfiedBy: 'abbb'); 17 | deny: (condition isSatisfiedBy: 'abab'). 18 | 19 | condition := RegexCondition matching: '(ab)*'. 20 | 21 | self 22 | assert: (condition isSatisfiedBy: 'abab'); 23 | deny: (condition isSatisfiedBy: 'abcab'). 24 | 25 | condition := RegexCondition matching: '[01]'. 26 | 27 | self 28 | assert: (condition isSatisfiedBy: '0'); 29 | deny: (condition isSatisfiedBy: '3'); 30 | deny: (condition isSatisfiedBy: '11'). 31 | 32 | condition := RegexCondition matching: '[01]+'. 33 | 34 | self 35 | assert: (condition isSatisfiedBy: '10010100'); 36 | deny: (condition isSatisfiedBy: '10001210') 37 | ] 38 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-Tests/DateAndTimeExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'DateAndTimeExtensionsTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Chronology-Tests', 5 | #package : 'Buoy-Chronology-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | DateAndTimeExtensionsTest >> testPrintHMS [ 10 | 11 | | dateAndTime | 12 | dateAndTime := DateAndTime 13 | year: 2023 14 | month: 2 15 | day: 1 16 | hour: 4 17 | minute: 6 18 | second: 1. 19 | 20 | self 21 | assert: (String streamContents: [ :s | dateAndTime printHMSOn: s ]) 22 | equals: '04:06:01' 23 | ] 24 | 25 | { #category : 'tests' } 26 | DateAndTimeExtensionsTest >> testPrintYMD [ 27 | 28 | | dateAndTime | 29 | dateAndTime := DateAndTime 30 | year: 2023 31 | month: 2 32 | day: 1 33 | hour: 4 34 | minute: 6 35 | second: 1. 36 | 37 | self 38 | assert: (String streamContents: [ :s | dateAndTime printYMDOn: s ]) 39 | equals: '2023-02-01' 40 | ] 41 | -------------------------------------------------------------------------------- /source/Buoy-Comparison-Tests/SequenceableCollectionEqualityCheckerTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A SequenceableCollectionEqualityCheckerTest is a test class for testing the behavior of SequenceableCollectionEqualityChecker 3 | " 4 | Class { 5 | #name : 'SequenceableCollectionEqualityCheckerTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Comparison-Tests', 8 | #package : 'Buoy-Comparison-Tests' 9 | } 10 | 11 | { #category : 'tests' } 12 | SequenceableCollectionEqualityCheckerTest >> testCheckAgainst [ 13 | 14 | | checker base | 15 | 16 | base := #( 1 2 3 4 ). 17 | checker := SequenceableCollectionEqualityChecker new. 18 | 19 | self 20 | assert: ( checker check: base against: #( 1 2 3 4 ) ); 21 | assert: ( checker check: base against: #( 1 2 3 4 ) asOrderedCollection ); 22 | deny: ( checker check: base against: #( 1 2 3 ) ); 23 | deny: ( checker check: base against: #( 0 2 3 4 ) ); 24 | deny: ( checker check: base against: #( 1 0 3 4 ) ); 25 | deny: ( checker check: base against: #( 1 2 0 4 ) ); 26 | deny: ( checker check: base against: #( 1 2 3 0 ) ); 27 | deny: ( checker check: base against: 1 ) 28 | ] 29 | -------------------------------------------------------------------------------- /source/Buoy-Localization-GS64-Extensions/CharacterCollection.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'CharacterCollection' } 2 | 3 | { #category : '*Buoy-Localization-GS64-Extensions' } 4 | CharacterCollection >> asLanguageRange [ 5 | 6 | ^ LanguageRange fromString: self 7 | ] 8 | 9 | { #category : '*Buoy-Localization-GS64-Extensions' } 10 | CharacterCollection >> asLanguageTag [ 11 | 12 | ^ LanguageTag fromString: self 13 | ] 14 | 15 | { #category : '*Buoy-Localization-GS64-Extensions' } 16 | CharacterCollection >> escaped [ 17 | 18 | ^ EscapingAlgorithm new escape: self 19 | ] 20 | 21 | { #category : '*Buoy-Localization-GS64-Extensions' } 22 | CharacterCollection >> localized [ 23 | 24 | ^ self localizedWithAll: #( ) 25 | ] 26 | 27 | { #category : '*Buoy-Localization-GS64-Extensions' } 28 | CharacterCollection >> localizedWithAll: collection [ 29 | 30 | ^ NaturalLanguageTranslator current localize: self withAll: collection to: CurrentLocale value 31 | ] 32 | 33 | { #category : '*Buoy-Localization-GS64-Extensions' } 34 | CharacterCollection >> unescaped [ 35 | 36 | ^ EscapingAlgorithm new unescape: self 37 | ] 38 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-GS64-Extensions/Time.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Time' } 2 | 3 | { #category : '*Buoy-Chronology-GS64-Extensions' } 4 | Time class >> milliseconds: currentTime since: lastTime [ 5 | "Answer the elapsed time since last recorded in milliseconds. 6 | Compensate for rollover." 7 | 8 | | delta | 9 | delta := currentTime - lastTime. 10 | ^ delta < 0 11 | ifTrue: [SmallInteger maximumValue + delta] 12 | ifFalse: [delta] 13 | ] 14 | 15 | { #category : '*Buoy-Chronology-GS64-Extensions' } 16 | Time class >> millisecondsSince: lastTime [ 17 | "Answer the elapsed time since last recorded in milliseconds. 18 | Compensate for rollover." 19 | 20 | ^self milliseconds: self millisecondClockValue since: lastTime 21 | ] 22 | 23 | { #category : '*Buoy-Chronology-GS64-Extensions' } 24 | Time class >> millisecondsToRun: timedBlock [ 25 | 26 | ^ self millisecondsElapsedTime: timedBlock 27 | ] 28 | 29 | { #category : '*Buoy-Chronology-GS64-Extensions' } 30 | Time class >> totalSeconds [ 31 | "Answer the total seconds ellapsed since the epoch: 1 January 1901 00:00 UTC" 32 | 33 | ^ System timeGmt 34 | ] 35 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Extensions/SequenceableCollection.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'SequenceableCollection' } 2 | 3 | { #category : '*Buoy-Collections-Extensions' } 4 | SequenceableCollection >> copyFirst: n [ 5 | 6 | ^ [ self copyFrom: 1 to: n ] unless: n = 0 inWhichCase: [ self species new ] 7 | ] 8 | 9 | { #category : '*Buoy-Collections-Extensions' } 10 | SequenceableCollection >> copyNoMoreThanFirst: n [ 11 | 12 | ^ self copyFirst: ( self size min: n ) 13 | ] 14 | 15 | { #category : '*Buoy-Collections-Extensions' } 16 | SequenceableCollection >> copyNoMoreThanLast: n [ 17 | 18 | ^ self copyLast: ( n min: self size ) 19 | ] 20 | 21 | { #category : '*Buoy-Collections-Extensions' } 22 | SequenceableCollection >> equalityChecker [ 23 | 24 | ^ SequenceableCollectionEqualityChecker new 25 | ] 26 | 27 | { #category : '*Buoy-Collections-Extensions' } 28 | SequenceableCollection >> withoutFirst [ 29 | 30 | ^self withoutFirst: 1 31 | ] 32 | 33 | { #category : '*Buoy-Collections-Extensions' } 34 | SequenceableCollection >> withoutFirst: n [ 35 | 36 | (self size <= n) ifTrue: [^self species new]. 37 | ^self copyFrom: n + 1 to: self size 38 | ] 39 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/CollectingAssertionFailuresPolicy.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an assertion policy that collect the failure explanations, and try to keep evaluating the following conditions. 3 | " 4 | Class { 5 | #name : 'CollectingAssertionFailuresPolicy', 6 | #superclass : 'AssertionFailurePolicy', 7 | #instVars : [ 8 | 'failures', 9 | 'errorClass' 10 | ], 11 | #category : 'Buoy-Assertions', 12 | #package : 'Buoy-Assertions' 13 | } 14 | 15 | { #category : 'Instance Creation' } 16 | CollectingAssertionFailuresPolicy class >> raising: anErrorClass [ 17 | 18 | ^ self new initializeRaising: anErrorClass 19 | ] 20 | 21 | { #category : 'applying' } 22 | CollectingAssertionFailuresPolicy >> applyTo: anAsserter [ 23 | 24 | super applyTo: anAsserter. 25 | failures ifNotEmpty: [ errorClass signalAll: failures ] 26 | ] 27 | 28 | { #category : 'notifying' } 29 | CollectingAssertionFailuresPolicy >> assertionFailedBecause: aFailureExplanation [ 30 | 31 | failures add: aFailureExplanation 32 | ] 33 | 34 | { #category : 'initialization' } 35 | CollectingAssertionFailuresPolicy >> initializeRaising: anErrorClass [ 36 | 37 | errorClass := anErrorClass. 38 | failures := OrderedCollection new 39 | ] 40 | -------------------------------------------------------------------------------- /.github/workflows/loading-gs64-components.yml: -------------------------------------------------------------------------------- 1 | name: 'GS64 Components Loading' 2 | on: 3 | - push 4 | - pull_request 5 | - workflow_dispatch 6 | 7 | jobs: 8 | component-loading-3_7_0: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | load-spec: 14 | - Dependent-SUnit-Extensions 15 | - Deployment 16 | name: GS64 v3.7.0 + ${{ matrix.load-spec }} 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Load component in image 20 | uses: ba-st-actions/gs64-ci@v2 21 | with: 22 | project_name: 'Buoy' 23 | load_spec: 'Buoy-${{ matrix.load-spec }}' 24 | component-loading-3_7_1: 25 | runs-on: ubuntu-latest 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | load-spec: 30 | - Dependent-SUnit-Extensions 31 | - Deployment 32 | name: GS64 v3.7.1 + ${{ matrix.load-spec }} 33 | steps: 34 | - uses: actions/checkout@v4 35 | - name: Load component in image 36 | uses: ba-st-actions/gs64-ci@v3 37 | with: 38 | project_name: 'Buoy' 39 | load_spec: 'Buoy-${{ matrix.load-spec }}' 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2025 Gabriel Cotelli, Maximiliano Tabacman and Buenos Aires Smalltalk Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /source/Buoy-Math-Extensions/Number.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Number' } 2 | 3 | { #category : '*Buoy-Math-Extensions' } 4 | Number >> decreasedBy: aPercentage [ 5 | 6 | AssertionChecker 7 | enforce: [ aPercentage between: 0 and: 1 ] 8 | because: 'A number can''t be decreased by a percentage greater than 100% and lesser than 0%' 9 | raising: ArithmeticError. 10 | 11 | ^ self * (Percentage oneHundred - aPercentage) 12 | ] 13 | 14 | { #category : '*Buoy-Math-Extensions' } 15 | Number >> increasedBy: aPercentage [ 16 | 17 | AssertionChecker 18 | enforce: [ aPercentage positive ] 19 | because: 'A number can''t be increased by a negative percentage' 20 | raising: ArithmeticError. 21 | 22 | ^ self * (Percentage oneHundred + aPercentage) 23 | ] 24 | 25 | { #category : '*Buoy-Math-Extensions' } 26 | Number >> isPercentage [ 27 | 28 | ^false 29 | ] 30 | 31 | { #category : '*Buoy-Math-Extensions' } 32 | Number >> perMille [ 33 | 34 | ^ PerMille of: self 35 | ] 36 | 37 | { #category : '*Buoy-Math-Extensions' } 38 | Number >> percent [ 39 | 40 | ^ Percentage of: self 41 | ] 42 | 43 | { #category : '*Buoy-Math-Extensions' } 44 | Number >> productWithPartsPerFractionRatio: ratio [ 45 | 46 | ^ ratio * self asNumber 47 | ] 48 | -------------------------------------------------------------------------------- /source/Buoy-Localization/ReverseSolidusEscapingRule.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an escaping rule implementing escaping for the Reverse Solidus character (the backslash) \\. 3 | 4 | " 5 | Class { 6 | #name : 'ReverseSolidusEscapingRule', 7 | #superclass : 'StringEscapingRule', 8 | #category : 'Buoy-Localization', 9 | #package : 'Buoy-Localization' 10 | } 11 | 12 | { #category : 'class initialization' } 13 | ReverseSolidusEscapingRule class >> initialize [ 14 | 15 | 16 | StringEscapingRule registerRule: self new 17 | ] 18 | 19 | { #category : 'escaping' } 20 | ReverseSolidusEscapingRule >> escape: character on: stream [ 21 | 22 | stream nextPutAll: '\\' 23 | ] 24 | 25 | { #category : 'testing' } 26 | ReverseSolidusEscapingRule >> handlesEscapeOf: character [ 27 | 28 | ^ character == $\ 29 | ] 30 | 31 | { #category : 'testing' } 32 | ReverseSolidusEscapingRule >> handlesUnescapeOf: controlCharacter [ 33 | 34 | ^ controlCharacter == $\ 35 | ] 36 | 37 | { #category : 'accessing' } 38 | ReverseSolidusEscapingRule >> priority [ 39 | 40 | ^ 100 41 | ] 42 | 43 | { #category : 'escaping' } 44 | ReverseSolidusEscapingRule >> unescape: character from: sourceStream on: targetStream [ 45 | 46 | targetStream nextPut: $\ 47 | ] 48 | -------------------------------------------------------------------------------- /source/Buoy-Comparison/SequenceableCollectionEqualityChecker.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a checker used to compare sequenceable collections. 3 | " 4 | Class { 5 | #name : 'SequenceableCollectionEqualityChecker', 6 | #superclass : 'EqualityChecker', 7 | #classInstVars : [ 8 | 'uniqueInstance' 9 | ], 10 | #category : 'Buoy-Comparison', 11 | #package : 'Buoy-Comparison' 12 | } 13 | 14 | { #category : 'instance creation' } 15 | SequenceableCollectionEqualityChecker class >> new [ 16 | 17 | uniqueInstance ifNil: [ uniqueInstance := super new ]. 18 | ^ uniqueInstance 19 | ] 20 | 21 | { #category : 'testing' } 22 | SequenceableCollectionEqualityChecker >> check: base against: target [ 23 | 24 | ^ ( self is: base identicalTo: target ) or: [ 25 | base isSequenceable and: [ 26 | target isCollection and: [ 27 | target isSequenceable and: [ self has: base theSameElementsThan: target ] ] 28 | ] 29 | ] 30 | ] 31 | 32 | { #category : 'private' } 33 | SequenceableCollectionEqualityChecker >> has: base theSameElementsThan: target [ 34 | 35 | ^ base size = target size 36 | and: [ base 37 | with: target 38 | do: [ :first :second | 39 | first = second 40 | ifFalse: [ ^ false ] 41 | ]. 42 | true 43 | ] 44 | ] 45 | -------------------------------------------------------------------------------- /source/Buoy-Dynamic-Binding/Binding.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an abstract class representing a binding. 3 | " 4 | Class { 5 | #name : 'Binding', 6 | #superclass : 'Object', 7 | #category : 'Buoy-Dynamic-Binding', 8 | #package : 'Buoy-Dynamic-Binding' 9 | } 10 | 11 | { #category : 'Instance Creation' } 12 | Binding class >> to: anObject [ 13 | 14 | ^DefinedBinding connectedTo: anObject 15 | ] 16 | 17 | { #category : 'Instance Creation' } 18 | Binding class >> undefinedExplainedBy: anExplanation [ 19 | 20 | ^ self undefinedExplainedBy: anExplanation raising: AssertionFailed 21 | ] 22 | 23 | { #category : 'Instance Creation' } 24 | Binding class >> undefinedExplainedBy: anExplanation raising: anErrorClass [ 25 | 26 | ^ self undefinedExplainedByAll: {anExplanation} raising: anErrorClass 27 | ] 28 | 29 | { #category : 'Instance Creation' } 30 | Binding class >> undefinedExplainedByAll: anExplanationCollection raising: anErrorClass [ 31 | 32 | ^ UndefinedBinding explainedByAll: anExplanationCollection raising: anErrorClass 33 | ] 34 | 35 | { #category : 'accessing' } 36 | Binding >> content [ 37 | 38 | self subclassResponsibility 39 | ] 40 | 41 | { #category : 'testing' } 42 | Binding >> isDefined [ 43 | 44 | ^ self subclassResponsibility 45 | ] 46 | -------------------------------------------------------------------------------- /docs/how-to/how-to-load-in-pharo.md: -------------------------------------------------------------------------------- 1 | # How to load Buoy in a Pharo image 2 | 3 | ## Using Metacello 4 | 5 | 1. Download a [Pharo VM and image](https://pharo.org/download) 6 | 2. Open your Pharo image 7 | 3. Open a Playground 8 | 4. Evaluate: 9 | 10 | ```smalltalk 11 | Metacello new 12 | baseline: 'Buoy'; 13 | repository: 'github://ba-st/Buoy:release-candidate'; 14 | load: 'Development'. 15 | ``` 16 | 17 | > Change `release-candidate` to some released version if you want a pinned version 18 | 19 | ## Using Iceberg 20 | 21 | 1. Download [pharo VM and image](https://pharo.org/download) 22 | 2. Open your Pharo image 23 | 3. Open Iceberg 24 | 4. Click the *Add* repository button 25 | 5. Select *Clone from github.com* and enter `ba-st` as owner name and `Buoy` 26 | as project name 27 | 6. Click *Ok* 28 | 7. Select the repository in the main Iceberg window 29 | 8. Open the contextual menu and select 30 | *Metacello → Install baseline of Buoy ...* 31 | 9. Type `Development` and click *Ok* 32 | 33 | > After Iceberg cloned a repository, it will be checked-out at the default 34 | > branch (in this case `release-candidate`). If you want to work on a different 35 | > branch or commit, perform the checkout before the baseline installation step. 36 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Extensions/Collection.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Collection' } 2 | 3 | { #category : '*Buoy-Collections-Extensions' } 4 | Collection >> asOrderedSet [ 5 | 6 | ^ self as: OrderedSet 7 | ] 8 | 9 | { #category : '*Buoy-Collections-Extensions' } 10 | Collection >> includesIdenticalTo: anObject [ 11 | 12 | self do: [ :each | anObject == each ifTrue: [ ^ true ] ]. 13 | ^ false 14 | ] 15 | 16 | { #category : '*Buoy-Collections-Extensions' } 17 | Collection >> maxUsing: aBlock [ 18 | 19 | ^ self maxUsing: aBlock ifEmpty: [ self errorEmptyCollection ] 20 | ] 21 | 22 | { #category : '*Buoy-Collections-Extensions' } 23 | Collection >> maxUsing: aBlock ifEmpty: ifEmptyBlock [ 24 | 25 | ^ self ifEmpty: ifEmptyBlock ifNotEmpty: [ self inject: ( aBlock value: self anyOne ) into: [ :max :each | max max: ( aBlock value: each ) ] ] 26 | ] 27 | 28 | { #category : '*Buoy-Collections-Extensions' } 29 | Collection >> minUsing: aBlock [ 30 | 31 | ^ self minUsing: aBlock ifEmpty: [ self errorEmptyCollection ] 32 | ] 33 | 34 | { #category : '*Buoy-Collections-Extensions' } 35 | Collection >> minUsing: aBlock ifEmpty: ifEmptyBlock [ 36 | 37 | ^ self ifEmpty: ifEmptyBlock ifNotEmpty: [ self inject: ( aBlock value: self anyOne ) into: [ :max :each | max min: ( aBlock value: each ) ] ] 38 | ] 39 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Tests/KeywordMessageSendingCollectorTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A KeywordMessageSendingCollectorTest is a test class for testing the behavior of KeywordMessageSendingCollector 3 | " 4 | Class { 5 | #name : 'KeywordMessageSendingCollectorTest', 6 | #superclass : 'TestCase', 7 | #instVars : [ 8 | 'arguments' 9 | ], 10 | #category : 'Buoy-Metaprogramming-Tests', 11 | #package : 'Buoy-Metaprogramming-Tests' 12 | } 13 | 14 | { #category : 'initialization' } 15 | KeywordMessageSendingCollectorTest >> setUp [ 16 | 17 | super setUp. 18 | arguments := OrderedCollection new 19 | ] 20 | 21 | { #category : 'tests-evaluating' } 22 | KeywordMessageSendingCollectorTest >> testValue [ 23 | 24 | (KeywordMessageSendingCollector sendingAllMessagesBeginningWith: 'zzzTest' andEndingWith: 'Add:' to: self with: 1) value. 25 | 26 | self 27 | assert: arguments size equals: 1; 28 | assert: arguments includes: 1 29 | ] 30 | 31 | { #category : 'private' } 32 | KeywordMessageSendingCollectorTest >> zzzTestAdd: anArgument [ 33 | 34 | arguments add: anArgument 35 | ] 36 | 37 | { #category : 'private' } 38 | KeywordMessageSendingCollectorTest >> zzzTestAdd: anArgument testAdd: aSecondArgument [ 39 | 40 | 41 | "This methods must exist but not be executed" 42 | self fail 43 | ] 44 | -------------------------------------------------------------------------------- /source/Buoy-Exception-Handling-Tests/ExitTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'ExitTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Exception-Handling-Tests', 5 | #package : 'Buoy-Exception-Handling-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | ExitTest >> testFailure [ 10 | 11 | self 12 | should: [ Exit signalFailure ] 13 | raise: Exit 14 | withExceptionDo: [ :error | self deny: error isSuccess ]; 15 | should: [ Exit signalFailure: 'Bye bye' ] 16 | raise: Exit 17 | withExceptionDo: [ :error | 18 | self 19 | deny: error isSuccess; 20 | assert: error messageText equals: 'Bye bye' ] 21 | ] 22 | 23 | { #category : 'tests' } 24 | ExitTest >> testResume [ 25 | 26 | | returnValue | 27 | 28 | returnValue := [ Exit signalSuccess + 1 ] 29 | on: Exit 30 | do: [ :exit | exit resume: 1 ]. 31 | 32 | self assert: returnValue equals: 2 33 | ] 34 | 35 | { #category : 'tests' } 36 | ExitTest >> testSuccess [ 37 | 38 | self 39 | should: [ Exit signalSuccess ] 40 | raise: Exit 41 | withExceptionDo: [ :error | self assert: error isSuccess ]; 42 | should: [ Exit signalSuccess: 'Bye bye' ] 43 | raise: Exit 44 | withExceptionDo: [ :error | 45 | self 46 | assert: error isSuccess; 47 | assert: error messageText equals: 'Bye bye' ] 48 | ] 49 | -------------------------------------------------------------------------------- /source/Buoy-Comparison-Tests/ObjectUsingComparisonAffordances.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an example used for testing purposes 3 | " 4 | Class { 5 | #name : 'ObjectUsingComparisonAffordances', 6 | #superclass : 'Object', 7 | #instVars : [ 8 | 'first', 9 | 'second' 10 | ], 11 | #category : 'Buoy-Comparison-Tests', 12 | #package : 'Buoy-Comparison-Tests' 13 | } 14 | 15 | { #category : 'instance creation' } 16 | ObjectUsingComparisonAffordances class >> with: anInteger and: anInteger2 [ 17 | 18 | ^ self new initializeWith: anInteger and: anInteger2 19 | ] 20 | 21 | { #category : 'comparing' } 22 | ObjectUsingComparisonAffordances >> = anObject [ 23 | 24 | ^ self equalityChecker 25 | compareAll: #(#first #second); 26 | checkAgainst: anObject 27 | ] 28 | 29 | { #category : 'accessing' } 30 | ObjectUsingComparisonAffordances >> first [ 31 | ^ first 32 | ] 33 | 34 | { #category : 'comparing' } 35 | ObjectUsingComparisonAffordances >> hash [ 36 | 37 | ^ self equalityHashCombinator combineHashOf: first with: second 38 | ] 39 | 40 | { #category : 'initialization' } 41 | ObjectUsingComparisonAffordances >> initializeWith: anInteger and: anInteger2 [ 42 | 43 | first := anInteger. 44 | second := anInteger2 45 | ] 46 | 47 | { #category : 'accessing' } 48 | ObjectUsingComparisonAffordances >> second [ 49 | ^ second 50 | ] 51 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/GemStone64UnixPlatform.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'GemStone64UnixPlatform', 3 | #superclass : 'Object', 4 | #classInstVars : [ 5 | 'Current' 6 | ], 7 | #category : 'Buoy-Metaprogramming-GS64-Extensions', 8 | #package : 'Buoy-Metaprogramming-GS64-Extensions' 9 | } 10 | 11 | { #category : 'accessing' } 12 | GemStone64UnixPlatform class >> current [ 13 | 14 | ^ Current 15 | ] 16 | 17 | { #category : 'class initialization' } 18 | GemStone64UnixPlatform class >> initialize [ 19 | 20 | Current := self new 21 | ] 22 | 23 | { #category : 'accessing' } 24 | GemStone64UnixPlatform >> environmentAt: aVariableName ifPresent: aBlock ifAbsent: anAbsentBlock [ 25 | 26 | ^ (System gemEnvironmentVariable: aVariableName) 27 | ifNil: anAbsentBlock 28 | ifNotNil: [ :variableValue | aBlock value: variableValue ] 29 | ] 30 | 31 | { #category : 'accessing' } 32 | GemStone64UnixPlatform >> environmentAt: variableName put: value [ 33 | 34 | ^ System gemEnvironmentVariable: variableName put: value 35 | ] 36 | 37 | { #category : 'accessing' } 38 | GemStone64UnixPlatform >> lineEnding [ 39 | 40 | ^ String lf 41 | ] 42 | 43 | { #category : 'accessing' } 44 | GemStone64UnixPlatform >> removeEnvironmentKey: variableName [ 45 | 46 | ^ self environmentAt: variableName put: '' 47 | ] 48 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Tests/DictionaryExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'DictionaryExtensionsTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Collections-Tests', 5 | #package : 'Buoy-Collections-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | DictionaryExtensionsTest >> testAtIfPresentIfAbsentPut [ 10 | 11 | | dictionary wasPresent | 12 | dictionary := Dictionary new. 13 | dictionary at: #one ifPresent: [ self fail ] ifAbsentPut: [ 1 ]. 14 | self assert: (dictionary at: #one) equals: 1. 15 | wasPresent := false. 16 | dictionary 17 | at: #one 18 | ifPresent: [ :one | 19 | wasPresent := true. 20 | self assert: one equals: 1 ] 21 | ifAbsentPut: [ self fail ]. 22 | self assert: wasPresent 23 | ] 24 | 25 | { #category : 'tests' } 26 | DictionaryExtensionsTest >> testNewFromPairs [ 27 | 28 | | dictionary | 29 | dictionary := Dictionary newFromPairs: #( one 1 two 2 ). 30 | 31 | self 32 | assert: dictionary size equals: 2; 33 | assert: (dictionary at: #one) equals: 1; 34 | assert: (dictionary at: #two) equals: 2 35 | ] 36 | 37 | { #category : 'tests' } 38 | DictionaryExtensionsTest >> testRemoveAll [ 39 | 40 | | dictionary | 41 | dictionary := Dictionary newFromPairs: #( one 1 two 2 ). 42 | 43 | self assert: dictionary size equals: 2. 44 | 45 | dictionary removeAll. 46 | self assert: dictionary isEmpty 47 | ] 48 | -------------------------------------------------------------------------------- /source/Buoy-Exception-Handling-GS64-Extensions/ExitClientError.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'ExitClientError' } 2 | 3 | { #category : '*Buoy-Exception-Handling-GS64-Extensions' } 4 | ExitClientError class >> failure [ 5 | 6 | ^ self status: 1 7 | ] 8 | 9 | { #category : '*Buoy-Exception-Handling-GS64-Extensions' } 10 | ExitClientError >> isSuccess [ 11 | 12 | ^ self status = 0 13 | ] 14 | 15 | { #category : '*Buoy-Exception-Handling-GS64-Extensions' } 16 | ExitClientError class >> signalFailure [ 17 | 18 | ^ self failure signal 19 | ] 20 | 21 | { #category : '*Buoy-Exception-Handling-GS64-Extensions' } 22 | ExitClientError class >> signalFailure: aMessage [ 23 | 24 | ^ self failure signal: aMessage 25 | ] 26 | 27 | { #category : '*Buoy-Exception-Handling-GS64-Extensions' } 28 | ExitClientError class >> signalSuccess [ 29 | 30 | ^ self success signal 31 | ] 32 | 33 | { #category : '*Buoy-Exception-Handling-GS64-Extensions' } 34 | ExitClientError class >> signalSuccess: aMessage [ 35 | 36 | ^ self success signal: aMessage 37 | ] 38 | 39 | { #category : '*Buoy-Exception-Handling-GS64-Extensions' } 40 | ExitClientError class >> status: status [ 41 | 42 | ^ self new 43 | _resumable: true; 44 | status: status; 45 | yourself 46 | ] 47 | 48 | { #category : '*Buoy-Exception-Handling-GS64-Extensions' } 49 | ExitClientError class >> success [ 50 | 51 | ^ self status: 0 52 | ] 53 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Tests/BinarySearchAlgorithmTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a test case for BinarySearchAlgorithm 3 | " 4 | Class { 5 | #name : 'BinarySearchAlgorithmTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Collections-Tests', 8 | #package : 'Buoy-Collections-Tests' 9 | } 10 | 11 | { #category : 'private' } 12 | BinarySearchAlgorithmTest >> assertExpectedInsertionIndexFor: key in: collection is: expectedIndex [ 13 | 14 | self assert: ( BinarySearchAlgorithm searchFor: key in: collection using: [ :number | number ] ) execute equals: expectedIndex 15 | ] 16 | 17 | { #category : 'tests' } 18 | BinarySearchAlgorithmTest >> testExecute [ 19 | 20 | self assertExpectedInsertionIndexFor: 1 in: #(1 2 3) is: 2. 21 | self assertExpectedInsertionIndexFor: 1 in: #(1 1 1 2 3 4 5) is: 4. 22 | self assertExpectedInsertionIndexFor: 3 in: #(1 1 1 2 3 3 4 5) is: 7. 23 | self assertExpectedInsertionIndexFor: 5 in: #(1 2 3 4 5) is: 6. 24 | self assertExpectedInsertionIndexFor: 5 in: #(1 2 3 4 5 5) is: 7. 25 | 26 | self assertExpectedInsertionIndexFor: 4 in: #(1 5) is: 2. 27 | self assertExpectedInsertionIndexFor: 0 in: #(1 5) is: 1. 28 | self assertExpectedInsertionIndexFor: 6 in: #(1 5) is: 3 29 | ] 30 | 31 | { #category : 'tests' } 32 | BinarySearchAlgorithmTest >> testExecuteWithSymbol [ 33 | 34 | self assert: ( BinarySearchAlgorithm searchFor: 1 in: #(#(1) #(2 1) #(3)) using: #first ) execute equals: 2 35 | ] 36 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-Tests/DurationChronologyExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'DurationChronologyExtensionsTest', 3 | #superclass : 'TestCase', 4 | #category : 'Buoy-Chronology-Tests', 5 | #package : 'Buoy-Chronology-Tests' 6 | } 7 | 8 | { #category : 'tests' } 9 | DurationChronologyExtensionsTest >> testIsZero [ 10 | 11 | self 12 | assert: 0 seconds isZero; 13 | deny: 1 second isZero 14 | ] 15 | 16 | { #category : 'tests' } 17 | DurationChronologyExtensionsTest >> testTotalSeconds [ 18 | 19 | self assert: 0 seconds totalSeconds equals: 0. 20 | self assert: 1 second totalSeconds equals: 1. 21 | self assert: 100 second totalSeconds equals: 100. 22 | self assert: 500 milliSeconds totalSeconds equals: 1 / 2. 23 | self assert: 1500 milliSeconds totalSeconds equals: 3 / 2. 24 | self assert: 2500 milliSeconds totalSeconds equals: 5 / 2. 25 | self assert: 1 second negated totalSeconds equals: -1 26 | ] 27 | 28 | { #category : 'tests' } 29 | DurationChronologyExtensionsTest >> testWait [ 30 | 31 | | ms | 32 | 33 | ms := Time millisecondsToRun: [ 2 seconds wait ]. 34 | self assert: ms >= 2000 35 | ] 36 | 37 | { #category : 'tests' } 38 | DurationChronologyExtensionsTest >> testWholeSeconds [ 39 | 40 | self 41 | assert: 1.002003004 seconds wholeMilliseconds equals: 2; 42 | assert: 1.002003004 seconds wholeMicroseconds equals: 3; 43 | assert: 1.002003004 seconds wholeNanoseconds equals: 4 44 | ] 45 | -------------------------------------------------------------------------------- /source/Buoy-Comparison/HashCombinator.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an abstract class defining the interface for hash combination. My intent is to provide a way of generate a hash by combining the hash of other objects. 3 | " 4 | Class { 5 | #name : 'HashCombinator', 6 | #superclass : 'Object', 7 | #category : 'Buoy-Comparison', 8 | #package : 'Buoy-Comparison' 9 | } 10 | 11 | { #category : 'combining' } 12 | HashCombinator >> combine: acumulatedHashValue with: hashValue [ 13 | 14 | self subclassResponsibility 15 | ] 16 | 17 | { #category : 'combining' } 18 | HashCombinator >> combineAll: hashes [ 19 | 20 | ^ self combineAll: hashes doing: [ :hash | hash ] 21 | ] 22 | 23 | { #category : 'combining' } 24 | HashCombinator >> combineAll: aCollection doing: aMonadycBlock [ 25 | 26 | AssertionChecker 27 | enforce: [ aCollection notEmpty ] 28 | because: 'Cannot combine an empty collection of hashes'. 29 | 30 | ^ aCollection withoutFirst 31 | inject: ( aMonadycBlock value: aCollection first ) 32 | into: [ :combined :each | self combine: combined with: ( aMonadycBlock value: each ) ] 33 | ] 34 | 35 | { #category : 'combining' } 36 | HashCombinator >> combineHashOf: anObject with: anotherObject [ 37 | 38 | ^ self combine: anObject hash with: anotherObject hash 39 | ] 40 | 41 | { #category : 'combining' } 42 | HashCombinator >> combineHashesOfAll: aCollection [ 43 | 44 | ^ self combineAll: aCollection doing: [ :object | object hash ] 45 | ] 46 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-GS64-Extensions/DynamicVariable.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'DynamicVariable', 3 | #superclass : 'Object', 4 | #category : 'Buoy-Metaprogramming-GS64-Extensions', 5 | #package : 'Buoy-Metaprogramming-GS64-Extensions' 6 | } 7 | 8 | { #category : 'accessing' } 9 | DynamicVariable class >> default [ 10 | "Answer the default value for the variable. The default for the default value is nil." 11 | 12 | ^ nil 13 | ] 14 | 15 | { #category : 'testing' } 16 | DynamicVariable class >> isInheritable [ 17 | 18 | ^ false 19 | ] 20 | 21 | { #category : 'accessing' } 22 | DynamicVariable class >> soleInstance [ 23 | 24 | ^ self 25 | ] 26 | 27 | { #category : 'evaluating' } 28 | DynamicVariable class >> value [ 29 | "Answer the current value for this variable in the current context." 30 | 31 | ^ Processor activeProcess 32 | environmentAt: self soleInstance 33 | ifAbsent: [ self soleInstance default ] 34 | ] 35 | 36 | { #category : 'evaluating' } 37 | DynamicVariable class >> value: anObject during: aBlock [ 38 | 39 | | activeProcess oldValue | 40 | activeProcess := Processor activeProcess. 41 | oldValue := activeProcess 42 | environmentAt: self soleInstance 43 | ifAbsent: [ self soleInstance default ]. 44 | ^ [ 45 | activeProcess environmentAt: self put: anObject. 46 | aBlock value ] ensure: [ 47 | activeProcess environmentAt: self soleInstance put: oldValue ] 48 | ] 49 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming/Interface.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an interface declaring a set of messages to be understood by the objects implementing me. 3 | 4 | I'm not intended to be used as some kind of static type check, but to document an expected protocol. 5 | " 6 | Class { 7 | #name : 'Interface', 8 | #superclass : 'Object', 9 | #instVars : [ 10 | 'name', 11 | 'messages' 12 | ], 13 | #category : 'Buoy-Metaprogramming', 14 | #package : 'Buoy-Metaprogramming' 15 | } 16 | 17 | { #category : 'instance creation' } 18 | Interface class >> named: aName declaring: aSelectorCollection [ 19 | 20 | AssertionChecker refuse: [ aSelectorCollection isEmpty ] because: 'An interface must declare at least one message.' raising: InstanceCreationFailed. 21 | 22 | ^ self new initializeNamed: aName declaring: aSelectorCollection 23 | ] 24 | 25 | { #category : 'initialization' } 26 | Interface >> initializeNamed: aName declaring: aSelectorCollection [ 27 | 28 | name := aName. 29 | messages := aSelectorCollection 30 | ] 31 | 32 | { #category : 'testing' } 33 | Interface >> isImplementedBy: anObject [ 34 | 35 | ^ messages allSatisfy: [ :message | anObject respondsTo: message ] 36 | ] 37 | 38 | { #category : 'testing' } 39 | Interface >> isImplementedByInstancesOf: aClass [ 40 | 41 | ^ messages allSatisfy: [ :message | aClass canUnderstand: message ] 42 | ] 43 | 44 | { #category : 'printing' } 45 | Interface >> printOn: aStream [ 46 | 47 | aStream nextPutAll: name 48 | ] 49 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-12/SearchMethodsForLocalizationMessagesRule.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'SearchMethodsForLocalizationMessagesRule', 3 | #superclass : 'RBParseTreeLintRule', 4 | #instVars : [ 5 | 'stringsToTranslate' 6 | ], 7 | #category : 'Buoy-Development-Tools-Pharo-12', 8 | #package : 'Buoy-Development-Tools-Pharo-12' 9 | } 10 | 11 | { #category : 'instance creation' } 12 | SearchMethodsForLocalizationMessagesRule class >> collectingTranslationsIn: aCollection [ 13 | 14 | ^ self new initializeCollectingTranslationsIn: aCollection 15 | ] 16 | 17 | { #category : 'testing' } 18 | SearchMethodsForLocalizationMessagesRule class >> isVisible [ 19 | 20 | ^ false 21 | ] 22 | 23 | { #category : 'initialization' } 24 | SearchMethodsForLocalizationMessagesRule >> initialize [ 25 | 26 | super initialize. 27 | stringsToTranslate := OrderedCollection new. 28 | matcher 29 | matches: '`#string localized' 30 | do: [ :node :answer | stringsToTranslate add: node receiver value ]; 31 | matches: '`#string localizedWithAll: `@values' 32 | do: [ :node :answer | stringsToTranslate add: node receiver value ] 33 | ] 34 | 35 | { #category : 'initialization' } 36 | SearchMethodsForLocalizationMessagesRule >> initializeCollectingTranslationsIn: aCollection [ 37 | 38 | stringsToTranslate := aCollection 39 | ] 40 | 41 | { #category : 'accessing' } 42 | SearchMethodsForLocalizationMessagesRule >> name [ 43 | 44 | ^ 'Search methods for localization messages' 45 | ] 46 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-13/SearchMethodsForLocalizationMessagesRule.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'SearchMethodsForLocalizationMessagesRule', 3 | #superclass : 'RBParseTreeLintRule', 4 | #instVars : [ 5 | 'stringsToTranslate' 6 | ], 7 | #category : 'Buoy-Development-Tools-Pharo-13', 8 | #package : 'Buoy-Development-Tools-Pharo-13' 9 | } 10 | 11 | { #category : 'instance creation' } 12 | SearchMethodsForLocalizationMessagesRule class >> collectingTranslationsIn: aCollection [ 13 | 14 | ^ self new initializeCollectingTranslationsIn: aCollection 15 | ] 16 | 17 | { #category : 'testing' } 18 | SearchMethodsForLocalizationMessagesRule class >> isVisible [ 19 | 20 | ^ false 21 | ] 22 | 23 | { #category : 'initialization' } 24 | SearchMethodsForLocalizationMessagesRule >> initialize [ 25 | 26 | super initialize. 27 | stringsToTranslate := OrderedCollection new. 28 | matcher 29 | matches: '`#string localized' 30 | do: [ :node :answer | stringsToTranslate add: node receiver value ]; 31 | matches: '`#string localizedWithAll: `@values' 32 | do: [ :node :answer | stringsToTranslate add: node receiver value ] 33 | ] 34 | 35 | { #category : 'initialization' } 36 | SearchMethodsForLocalizationMessagesRule >> initializeCollectingTranslationsIn: aCollection [ 37 | 38 | stringsToTranslate := aCollection 39 | ] 40 | 41 | { #category : 'accessing' } 42 | SearchMethodsForLocalizationMessagesRule >> name [ 43 | 44 | ^ 'Search methods for localization messages' 45 | ] 46 | -------------------------------------------------------------------------------- /source/Buoy-Assertions-Tests/AssertionFailedTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | An AssertionFailedTest is a test class for testing the behavior of AssertionFailed 3 | " 4 | Class { 5 | #name : 'AssertionFailedTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Assertions-Tests', 8 | #package : 'Buoy-Assertions-Tests' 9 | } 10 | 11 | { #category : 'tests-Accessing' } 12 | AssertionFailedTest >> testFailures [ 13 | 14 | | explanation | 15 | 16 | explanation := 'Testing failures'. 17 | self 18 | should: [ AssertionFailed signal: explanation ] 19 | raise: AssertionFailed 20 | withExceptionDo: [ :exception | 21 | self 22 | assert: exception messageText equals: explanation; 23 | assert: exception failures size equals: 1; 24 | assert: exception failures first equals: explanation ] 25 | ] 26 | 27 | { #category : 'tests-Accessing' } 28 | AssertionFailedTest >> testSignalAll [ 29 | 30 | | firstExplanation secondExplanation | 31 | 32 | firstExplanation := 'Testing failures'. 33 | secondExplanation := 'More failures'. 34 | self 35 | should: [ 36 | AssertionFailed signalAll: { 37 | firstExplanation. 38 | secondExplanation } 39 | ] 40 | raise: AssertionFailed 41 | withExceptionDo: [ :exception | 42 | self 43 | assert: exception messageText 44 | equals: ( '<1s>. <2s>' expandMacrosWith: firstExplanation with: secondExplanation ); 45 | assertCollection: exception failures hasSameElements: { 46 | firstExplanation. 47 | secondExplanation } 48 | ] 49 | ] 50 | -------------------------------------------------------------------------------- /docs/how-to/how-to-use-as-dependency-in-pharo.md: -------------------------------------------------------------------------------- 1 | # How to use Buoy as dependency in a Pharo product 2 | 3 | In order to include **Buoy** as part of your project, you should reference 4 | the package in your product baseline: 5 | 6 | 1. Define the Buoy repository and version to be used, and the [baseline groups](../reference/Baseline-groups.md) 7 | you want to depend on (usually it will be `Deployment`). 8 | 9 | If you're unsure on what to depend use the *Dependency Analyzer* 10 | tool to choose an appropriate group including the packages you need. 11 | 12 | 2. Create a method like this one in the baseline class of your product: 13 | 14 | ```smalltalk 15 | setUpDependencies: spec 16 | 17 | spec 18 | baseline: 'Buoy' 19 | with: [ spec repository: 'github://github://ba-st/Buoy:v{XX}' ]; 20 | project: 'Buoy-Deployment' 21 | copyFrom: 'Buoy' with: [ spec loads: 'Deployment' ] 22 | ``` 23 | 24 | This will create `Buoy-Deployment` as a valid target that can be used 25 | as requirement in your own packages. 26 | 27 | > Replace `{XX}` with the version you want to depend on 28 | 29 | 3. Use the new loading target as a requirement on your packages. For example: 30 | 31 | ```smalltalk 32 | baseline: spec 33 | 34 | 35 | spec 36 | for: #pharo 37 | do: [ 38 | self setUpDependencies: spec. 39 | spec 40 | package: 'My-Package' 41 | with: [ spec requires: #('Buoy-Deployment') ] ] 42 | ``` 43 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/AssertionCheckerBuilder.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a builder for Assertion Checkers. 3 | " 4 | Class { 5 | #name : 'AssertionCheckerBuilder', 6 | #superclass : 'Object', 7 | #instVars : [ 8 | 'asserter', 9 | 'failurePolicyFactory', 10 | 'errorToSignal' 11 | ], 12 | #category : 'Buoy-Assertions', 13 | #package : 'Buoy-Assertions' 14 | } 15 | 16 | { #category : 'instance creation' } 17 | AssertionCheckerBuilder class >> new [ 18 | 19 | ^ super new initialize 20 | ] 21 | 22 | { #category : 'checking' } 23 | AssertionCheckerBuilder >> build [ 24 | 25 | ^ AssertionChecker applying: (failurePolicyFactory raising: errorToSignal) to: asserter 26 | ] 27 | 28 | { #category : 'checking' } 29 | AssertionCheckerBuilder >> buildAndCheck [ 30 | 31 | self build check 32 | ] 33 | 34 | { #category : 'configuring' } 35 | AssertionCheckerBuilder >> checking: aMonadycBlock [ 36 | 37 | aMonadycBlock value: asserter 38 | ] 39 | 40 | { #category : 'configuring' } 41 | AssertionCheckerBuilder >> failFast [ 42 | 43 | failurePolicyFactory := RaiseOnFirstAssertionFailurePolicy 44 | ] 45 | 46 | { #category : 'initialization' } 47 | AssertionCheckerBuilder >> initialize [ 48 | 49 | super initialize. 50 | asserter := Asserter new. 51 | self raising: AssertionFailurePolicy defaultErrorToSignal. 52 | failurePolicyFactory := CollectingAssertionFailuresPolicy 53 | ] 54 | 55 | { #category : 'configuring' } 56 | AssertionCheckerBuilder >> raising: anErrorToSignal [ 57 | 58 | errorToSignal := anErrorToSignal 59 | ] 60 | -------------------------------------------------------------------------------- /docs/reference/SUnit.md: -------------------------------------------------------------------------------- 1 | # SUnit 2 | 3 | ## `TestAsserter` extensions 4 | 5 | - `assert:hasTheSameElementsInTheSameOrderThat:` asserts that two 6 | sequenceable collections have the same elements in the same order 7 | - `assert:includes:` asserts that a collection includes an element 8 | - `deny:includes:` denies that a collection includes an element 9 | - `should:raise:withMessageText:` asserts that a block raises a specific 10 | exception including a specific message text 11 | - `use:asLocaleDuring:` allows changing the current locale during a block execution 12 | - `use:asNaturalLanguageTranslatorDuring:` allows using and configuring a language 13 | translator during a block execution 14 | - `withTheOnlyOneIn:do:` provides a facility to assert that a collection has 15 | only one element and evaluates a block with it 16 | 17 | ### `TestAsserter` extensions for GS64 18 | 19 | - `assert:identicalTo:` asserts that an object is identical to another one 20 | - `deny:identicalTo:` denies that an object is identical to another one 21 | - `assertCollection:hasSameElements:` asserts that two collections have the 22 | same elements 23 | - `fail` will make the test fail 24 | - `should:raise:withExceptionDo:` asserts that a block raises a specific 25 | exception and evaluates the provided block with the signal 26 | 27 | ## `TestCase` extensions 28 | 29 | - `runOnlyInGemStone64:` evaluates the block only if running in GS64 30 | - `runOnlyInPharo:` evaluates the block only if running in Pharo 31 | - `runOnlyInVAST:` evaluates the block only if running in VAST Platform 32 | -------------------------------------------------------------------------------- /source/Buoy-Collections/CircularIterator.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a circular iterator allowing to cycle between a number of options. 3 | 4 | Implementation Notes: 5 | To ease the rollover I keep the current index in a zero-based fashion to use module arithmetics to perform the rollover. 6 | " 7 | Class { 8 | #name : 'CircularIterator', 9 | #superclass : 'Object', 10 | #instVars : [ 11 | 'options', 12 | 'currentIndex' 13 | ], 14 | #category : 'Buoy-Collections', 15 | #package : 'Buoy-Collections' 16 | } 17 | 18 | { #category : 'Instance Creation' } 19 | CircularIterator class >> cyclingOver: aSequentiableCollection [ 20 | 21 | AssertionChecker 22 | enforce: [ aSequentiableCollection notEmpty ] 23 | because: 'It makes no sense to iterate in a cyclic way an empty collection' 24 | raising: InstanceCreationFailed. 25 | 26 | ^ self new initializeCyclingOver: aSequentiableCollection asArray 27 | ] 28 | 29 | { #category : 'accessing' } 30 | CircularIterator >> current [ 31 | 32 | ^options at: currentIndex + 1 33 | ] 34 | 35 | { #category : 'Testing' } 36 | CircularIterator >> includes: anObject [ 37 | 38 | ^options includes: anObject 39 | ] 40 | 41 | { #category : 'initialization' } 42 | CircularIterator >> initializeCyclingOver: anArray [ 43 | 44 | options := anArray. 45 | self reset 46 | ] 47 | 48 | { #category : 'iterating' } 49 | CircularIterator >> next [ 50 | 51 | currentIndex := (currentIndex + 1) \\ options size. 52 | ^self current 53 | ] 54 | 55 | { #category : 'iterating' } 56 | CircularIterator >> reset [ 57 | 58 | currentIndex := 0 59 | ] 60 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/AssertionCheck.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I represent a check for a specific fact, including the success and failure actions to apply 3 | " 4 | Class { 5 | #name : 'AssertionCheck', 6 | #superclass : 'Object', 7 | #instVars : [ 8 | 'factToCheck', 9 | 'explanationBlockOrString', 10 | 'successAction' 11 | ], 12 | #category : 'Buoy-Assertions', 13 | #package : 'Buoy-Assertions' 14 | } 15 | 16 | { #category : 'instance creation' } 17 | AssertionCheck class >> checking: aFact onFailure: anExplanationBlockOrString [ 18 | 19 | ^ self checking: aFact onSuccess: [ :policy | ] onFailure: anExplanationBlockOrString 20 | ] 21 | 22 | { #category : 'instance creation' } 23 | AssertionCheck class >> checking: aFact onSuccess: aSuccessAction onFailure: anExplanationBlockOrString [ 24 | 25 | ^ self new initializeChecking: aFact onSuccess: aSuccessAction onFailure: anExplanationBlockOrString 26 | ] 27 | 28 | { #category : 'Checking' } 29 | AssertionCheck >> checkApplying: anAssertionFailurePolicy [ 30 | 31 | factToCheck value 32 | then: [ successAction value: anAssertionFailurePolicy ] 33 | otherwise: [ anAssertionFailurePolicy assertionFailedBecause: self explanation ] 34 | ] 35 | 36 | { #category : 'private' } 37 | AssertionCheck >> explanation [ 38 | 39 | ^ explanationBlockOrString value 40 | ] 41 | 42 | { #category : 'initialize' } 43 | AssertionCheck >> initializeChecking: aFact onSuccess: aSuccessAction onFailure: aFailureBlockOrString [ 44 | 45 | factToCheck := aFact. 46 | successAction := aSuccessAction. 47 | explanationBlockOrString := aFailureBlockOrString 48 | ] 49 | -------------------------------------------------------------------------------- /source/Buoy-Localization/EscapingAlgorithm.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'EscapingAlgorithm', 3 | #superclass : 'Object', 4 | #classInstVars : [ 5 | 'UniqueInstace' 6 | ], 7 | #category : 'Buoy-Localization', 8 | #package : 'Buoy-Localization' 9 | } 10 | 11 | { #category : 'class initialization' } 12 | EscapingAlgorithm class >> initialize [ 13 | 14 | 15 | UniqueInstace := super new 16 | ] 17 | 18 | { #category : 'instance creation' } 19 | EscapingAlgorithm class >> new [ 20 | 21 | ^ UniqueInstace 22 | ] 23 | 24 | { #category : 'escaping' } 25 | EscapingAlgorithm >> escape: string [ 26 | 27 | ^ string species new: string size streamContents: [ :result | 28 | | stream | 29 | stream := string readStream. 30 | [ stream atEnd ] whileFalse: [ StringEscapingRule escape: stream next on: result ] 31 | ] 32 | ] 33 | 34 | { #category : 'escaping' } 35 | EscapingAlgorithm >> unescape: string [ 36 | 37 | ^ string species new: string size streamContents: [ :result | 38 | | stream | 39 | stream := string readStream. 40 | [ stream atEnd ] whileFalse: [ 41 | | currentChar | 42 | currentChar := stream next. 43 | currentChar == $\ 44 | ifTrue: [ 45 | stream atEnd 46 | ifTrue: [ AssertionFailed signal: 'Missing escape sequence' ] 47 | ifFalse: [ StringEscapingRule unescape: stream next from: stream on: result ] 48 | ] 49 | ifFalse: [ result nextPut: currentChar ] 50 | ] 51 | ] 52 | ] 53 | -------------------------------------------------------------------------------- /source/Buoy-Math/Percentage.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A percentage is a number or ratio expressed as a fraction of 100. It is often denoted using the percent sign, ""%"". A percentage is a dimensionless number 3 | " 4 | Class { 5 | #name : 'Percentage', 6 | #superclass : 'PartsPerFraction', 7 | #classInstVars : [ 8 | 'zeroPercent', 9 | 'oneHundredPercent' 10 | ], 11 | #category : 'Buoy-Math', 12 | #package : 'Buoy-Math' 13 | } 14 | 15 | { #category : 'private' } 16 | Percentage class >> fraction [ 17 | 18 | ^ 100 19 | ] 20 | 21 | { #category : 'initialization' } 22 | Percentage class >> initialize [ 23 | 24 | oneHundredPercent := self ratio: 1. 25 | zeroPercent := self ratio: 0 26 | ] 27 | 28 | { #category : 'Instance Creation' } 29 | Percentage class >> oneHundred [ 30 | 31 | ^ oneHundredPercent 32 | ] 33 | 34 | { #category : 'Instance Creation' } 35 | Percentage class >> zero [ 36 | 37 | ^zeroPercent 38 | ] 39 | 40 | { #category : 'testing' } 41 | Percentage >> isPercentage [ 42 | 43 | ^true 44 | ] 45 | 46 | { #category : 'testing' } 47 | Percentage >> isWellKnown [ 48 | 49 | ^ #( 0 1 ) includes: ratio 50 | ] 51 | 52 | { #category : 'printing' } 53 | Percentage >> storeOn: aStream [ 54 | 55 | ratio isZero ifTrue: [ 56 | ^ aStream 57 | nextPutAll: self class name asString; 58 | space; 59 | nextPutAll: 'zero' ]. 60 | ratio = 1 ifTrue: [ 61 | ^ aStream 62 | nextPutAll: self class name asString; 63 | space; 64 | nextPutAll: 'oneHundred' ]. 65 | self storeValueOn: aStream. 66 | aStream 67 | space; 68 | nextPutAll: 'percent' 69 | ] 70 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Pharo-Extensions/Behavior.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Behavior' } 2 | 3 | { #category : '*Buoy-Metaprogramming-Pharo-Extensions' } 4 | Behavior >> allLeafSubclasses [ 5 | 6 | | leafs | 7 | 8 | leafs := OrderedCollection new. 9 | self allSubclassesDo: [ :class | class subclasses ifEmpty: [ leafs add: class ] ]. 10 | ^ leafs 11 | ] 12 | 13 | { #category : '*Buoy-Metaprogramming-Pharo-Extensions' } 14 | Behavior >> makeInstancesDbTransient [ 15 | "In GS64 instances of classes that are DbTransient can be committed — that is, there is no error if they are committed — 16 | but their instance variables are not written to disk. 17 | 18 | These properties are written later by our version of the TonelWriterV3" 19 | 20 | self propertyAt: #gs_options put: #( 'dbTransient' ) 21 | ] 22 | 23 | { #category : '*Buoy-Metaprogramming-Pharo-Extensions' } 24 | Behavior >> makeInstancesInvariant [ 25 | "In GS64 instances of this class will be made invariant as soon as they are committed. 26 | 27 | These properties are written later by our version of the TonelWriterV3" 28 | 29 | self propertyAt: #gs_options put: #( 'instancesInvariant' ) 30 | ] 31 | 32 | { #category : '*Buoy-Metaprogramming-Pharo-Extensions' } 33 | Behavior >> makeInstancesNonPersistent [ 34 | "In GS64 instances of this class cannot be committed, so you cannot include references to 35 | instances of non-persistent classes within a persistent data structure. 36 | 37 | These properties are written later by our version of the TonelWriterV3" 38 | 39 | self propertyAt: #gs_options put: #( 'instancesNonPersistent' ) 40 | ] 41 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Tests/InterfaceTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | An InterfaceTest is a test class for testing the behavior of Interface 3 | " 4 | Class { 5 | #name : 'InterfaceTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Metaprogramming-Tests', 8 | #package : 'Buoy-Metaprogramming-Tests' 9 | } 10 | 11 | { #category : 'tests' } 12 | InterfaceTest >> testCantDeclareAnEmptyInterface [ 13 | 14 | self should: [ Interface named: 'Empty' declaring: #() ] raise: InstanceCreationFailed withMessageText: 'An interface must declare at least one message.' 15 | ] 16 | 17 | { #category : 'tests' } 18 | InterfaceTest >> testIsImplementedBy [ 19 | 20 | | assertable | 21 | 22 | assertable := Interface named: 'Assertable' declaring: #(#assert: #deny:). 23 | 24 | self 25 | assert: (assertable isImplementedBy: self); 26 | deny: (assertable isImplementedBy: assertable) 27 | ] 28 | 29 | { #category : 'tests' } 30 | InterfaceTest >> testIsImplementedByInstancesOf [ 31 | 32 | | assertable | 33 | 34 | assertable := Interface named: 'Assertable' declaring: #(#assert: #deny:). 35 | 36 | self 37 | assert: (assertable isImplementedByInstancesOf: self class); 38 | assert: (assertable isImplementedByInstancesOf: TestCase); 39 | assert: (assertable isImplementedByInstancesOf: TestAsserter); 40 | deny: (assertable isImplementedByInstancesOf: Object) 41 | ] 42 | 43 | { #category : 'tests' } 44 | InterfaceTest >> testPrintOn [ 45 | 46 | | assertable | 47 | 48 | assertable := Interface named: 'Assertable' declaring: #(#assert: #deny:). 49 | 50 | self assert: assertable printString equals: 'Assertable' 51 | ] 52 | -------------------------------------------------------------------------------- /rowan/components/Tests.ston: -------------------------------------------------------------------------------- 1 | RwSimpleProjectLoadComponentV2 { 2 | #name : 'Tests', 3 | #condition : 'tests', 4 | #projectNames : [ ], 5 | #componentNames : [ 6 | 'Deployment', 7 | 'Dependent-SUnit-Extensions' 8 | ], 9 | #packageNames : [ 10 | 'Buoy-Assertions-Tests', 11 | 'Buoy-Chronology-Tests', 12 | 'Buoy-Collections-Tests', 13 | 'Buoy-Comparison-Tests', 14 | 'Buoy-Conditions-Tests', 15 | 'Buoy-Dynamic-Binding-Tests', 16 | 'Buoy-Exception-Handling-Tests', 17 | 'Buoy-Localization-Tests', 18 | 'Buoy-Math-Tests', 19 | 'Buoy-Metaprogramming-Tests', 20 | 'Buoy-SUnit-Tests' 21 | ], 22 | #conditionalPackageMapSpecs : { 23 | 'gemstone' : { 24 | 'allusers' : { 25 | #packageNameToPlatformPropertiesMap : { 26 | 'Buoy-Assertions-Tests' : { 'symbolDictName' : 'Buoy' }, 27 | 'Buoy-Chronology-Tests' : { 'symbolDictName' : 'Buoy' }, 28 | 'Buoy-Collections-Tests' : { 'symbolDictName' : 'Buoy' }, 29 | 'Buoy-Comparison-Tests' : { 'symbolDictName' : 'Buoy' }, 30 | 'Buoy-Conditions-Tests' : { 'symbolDictName' : 'Buoy' }, 31 | 'Buoy-Dynamic-Binding-Tests' : { 'symbolDictName' : 'Buoy' }, 32 | 'Buoy-Exception-Handling-Tests' : { 'symbolDictName' : 'Buoy' }, 33 | 'Buoy-Localization-Tests' : { 'symbolDictName' : 'Buoy' }, 34 | 'Buoy-Math-Tests' : { 'symbolDictName' : 'Buoy' }, 35 | 'Buoy-Metaprogramming-Tests' : { 'symbolDictName' : 'Buoy' }, 36 | 'Buoy-SUnit-Tests' : { 'symbolDictName' : 'Buoy' } 37 | } 38 | } 39 | } 40 | }, 41 | #comment : '' 42 | } 43 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-12/TonelWriterV3.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'TonelWriterV3' } 2 | 3 | { #category : '*Buoy-Development-Tools-Pharo-12' } 4 | TonelWriterV3 >> typeClassDefinitionOf: aClassDefinition [ 5 | 6 | | definition | 7 | definition := OrderedDictionary new. 8 | self 9 | at: #name put: aClassDefinition className in: definition; 10 | at: #superclass put: aClassDefinition superclassName in: definition. 11 | aClassDefinition type = #normal ifFalse: [ self at: #type put: aClassDefinition type in: definition ]. 12 | aClassDefinition hasTraitComposition ifTrue: [ definition at: #traits put: aClassDefinition traitCompositionString ]. 13 | aClassDefinition hasClassTraitComposition ifTrue: [ definition at: #classTraits put: aClassDefinition classTraitCompositionString ]. 14 | aClassDefinition instVarNames ifNotEmpty: [ :vars | definition at: #instVars put: vars asArray ]. 15 | (aClassDefinition variables 16 | select: #isClassVariable 17 | thenCollect: #name) ifNotEmpty: [ :vars | definition at: #classVars put: vars asArray ]. 18 | (aClassDefinition variables 19 | select: #isPoolImport 20 | thenCollect: #name) ifNotEmpty: [ :vars | definition at: #pools put: vars asArray ]. 21 | aClassDefinition classInstVarNames ifNotEmpty: [ :vars | definition at: #classInstVars put: vars asArray ]. 22 | self setPackageInfoOf: aClassDefinition in: definition. 23 | "Write gs_options if available as class properties" 24 | (aClassDefinition actualClass ifNotNil:[:actualClass | (actualClass propertyAt: #gs_options) ifNotNil: [ :options | definition at: #gs_options put: options ]]). 25 | ^ self toSTON: definition 26 | ] 27 | -------------------------------------------------------------------------------- /source/Buoy-Development-Tools-Pharo-13/TonelWriterV3.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'TonelWriterV3' } 2 | 3 | { #category : '*Buoy-Development-Tools-Pharo-13' } 4 | TonelWriterV3 >> typeClassDefinitionOf: aClassDefinition [ 5 | 6 | | definition | 7 | definition := OrderedDictionary new. 8 | self 9 | at: #name put: aClassDefinition className in: definition; 10 | at: #superclass put: aClassDefinition superclassName in: definition. 11 | aClassDefinition type = #normal ifFalse: [ self at: #type put: aClassDefinition type in: definition ]. 12 | aClassDefinition hasTraitComposition ifTrue: [ definition at: #traits put: aClassDefinition traitCompositionString ]. 13 | aClassDefinition hasClassTraitComposition ifTrue: [ definition at: #classTraits put: aClassDefinition classTraitCompositionString ]. 14 | aClassDefinition instVarNames ifNotEmpty: [ :vars | definition at: #instVars put: vars asArray ]. 15 | (aClassDefinition variables 16 | select: #isClassVariable 17 | thenCollect: #name) ifNotEmpty: [ :vars | definition at: #classVars put: vars asArray ]. 18 | (aClassDefinition variables 19 | select: #isPoolImport 20 | thenCollect: #name) ifNotEmpty: [ :vars | definition at: #pools put: vars asArray ]. 21 | aClassDefinition classInstVarNames ifNotEmpty: [ :vars | definition at: #classInstVars put: vars asArray ]. 22 | self setPackageInfoOf: aClassDefinition in: definition. 23 | "Write gs_options if available as class properties" 24 | (aClassDefinition actualClass ifNotNil:[:actualClass | (actualClass propertyAt: #gs_options) ifNotNil: [ :options | definition at: #gs_options put: options ]]). 25 | ^ self toSTON: definition 26 | ] 27 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-GS64-Extensions/DateAndTimeANSI.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'DateAndTimeANSI' } 2 | 3 | { #category : '*Buoy-Chronology-GS64-Extensions' } 4 | DateAndTimeANSI >> monthIndex [ 5 | 6 | ^ self month 7 | ] 8 | 9 | { #category : '*Buoy-Chronology-GS64-Extensions' } 10 | DateAndTimeANSI >> printHMSOn: aStream [ 11 | 12 | self printHMSOn: aStream separatedBy: $: 13 | ] 14 | 15 | { #category : '*Buoy-Chronology-GS64-Extensions' } 16 | DateAndTimeANSI >> printHMSOn: aStream separatedBy: separator [ 17 | 18 | aStream 19 | nextPutAll: (self hour printStringLength: 2 padded: true); 20 | nextPut: separator; 21 | nextPutAll: (self minute printStringLength: 2 padded: true); 22 | nextPut: separator; 23 | nextPutAll: (self second asInteger printStringLength: 2 padded: true) 24 | ] 25 | 26 | { #category : '*Buoy-Chronology-GS64-Extensions' } 27 | DateAndTimeANSI >> printYMDOn: aStream [ 28 | 29 | aStream 30 | nextPutAll: (self year printStringLength: 4 padded: true); 31 | nextPut: $-; 32 | nextPutAll: (self monthIndex printStringLength: 2 padded: true); 33 | nextPut: $-; 34 | nextPutAll: (self dayOfMonth printStringLength: 2 padded: true) 35 | ] 36 | 37 | { #category : '*Buoy-Chronology-GS64-Extensions' } 38 | DateAndTimeANSI class >> unixEpoch [ 39 | 40 | ^ self posixSeconds: 0 offset: Duration zero 41 | ] 42 | 43 | { #category : '*Buoy-Chronology-GS64-Extensions' } 44 | DateAndTimeANSI class >> year: year month: month day: day [ 45 | "Return a DateAndTime, midnight local time" 46 | 47 | ^ self 48 | year: year 49 | month: month 50 | day: day 51 | hour: 0 52 | minute: 0 53 | second: 0 54 | ] 55 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Base-Extensions/Number.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Number' } 2 | 3 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 4 | Number >> asNumber [ 5 | 6 | ^ self 7 | ] 8 | 9 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 10 | Number >> closeTo: num [ 11 | "Tell whether the receiver and arguments are close from each." 12 | 13 | ^ self asFloat closeTo: num 14 | ] 15 | 16 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 17 | Number >> closeTo: number precision: precision [ 18 | 19 | ^ number closeTo: self asFloat precision: precision 20 | ] 21 | 22 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 23 | Number >> isInteger [ 24 | 25 | ^ false 26 | ] 27 | 28 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 29 | Number >> isNaN [ 30 | ^ false 31 | ] 32 | 33 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 34 | Number >> isZero [ 35 | 36 | ^ self = 0 37 | ] 38 | 39 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 40 | Number >> nthRoot: aPositiveInteger [ 41 | 42 | ^ self raisedTo: aPositiveInteger reciprocal 43 | ] 44 | 45 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 46 | Number class >> readFrom: aStringOrStream ifFail: aBlock [ 47 | 48 | ^ [ 49 | | stream | 50 | 51 | stream := aStringOrStream isString 52 | ifTrue: [ aStringOrStream readStream ] 53 | ifFalse: [ aStringOrStream ]. 54 | self fromStream: stream 55 | ] 56 | on: ImproperOperation 57 | do: [ :error | error return: aBlock value ] 58 | ] 59 | 60 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 61 | Number >> round: numberOfWishedDecimal [ 62 | 63 | ^ self roundTo: (10 raisedTo: numberOfWishedDecimal negated) 64 | ] 65 | -------------------------------------------------------------------------------- /source/Buoy-Conditions-Tests/ConditionExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an unit test for extensions included in the Conditions package 3 | " 4 | Class { 5 | #name : 'ConditionExtensionsTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Conditions-Tests', 8 | #package : 'Buoy-Conditions-Tests' 9 | } 10 | 11 | { #category : 'tests' } 12 | ConditionExtensionsTest >> testBlockUnless [ 13 | 14 | | blockWasEvaluated | 15 | 16 | blockWasEvaluated := false. 17 | 18 | [ blockWasEvaluated := true ] unless: false. 19 | 20 | self assert: blockWasEvaluated. 21 | 22 | [ self fail ] unless: true 23 | ] 24 | 25 | { #category : 'tests' } 26 | ConditionExtensionsTest >> testBlockUnlessInWhichCase [ 27 | 28 | | collection result | 29 | 30 | collection := #(). 31 | 32 | result := [ self fail ] unless: collection isEmpty inWhichCase: [ 0 ]. 33 | 34 | self assert: result equals: 0. 35 | 36 | collection := #(2 3 4). 37 | 38 | result := [ collection first ] unless: collection isEmpty inWhichCase: [ self fail ]. 39 | 40 | self assert: result equals: 2 41 | ] 42 | 43 | { #category : 'tests' } 44 | ConditionExtensionsTest >> testBooleanThen [ 45 | 46 | | blockWasEvaluated | 47 | 48 | blockWasEvaluated := false. 49 | 50 | true then: [ blockWasEvaluated := true ]. 51 | 52 | self assert: blockWasEvaluated. 53 | 54 | false then: [ self fail ] 55 | ] 56 | 57 | { #category : 'tests' } 58 | ConditionExtensionsTest >> testBooleanThenOtherwise [ 59 | 60 | | blockWasEvaluated | 61 | 62 | blockWasEvaluated := true then: [ true ] otherwise: [ self fail ]. 63 | 64 | self assert: blockWasEvaluated. 65 | 66 | blockWasEvaluated := false then: [ self fail ] otherwise: [ true ]. 67 | 68 | self assert: blockWasEvaluated 69 | ] 70 | -------------------------------------------------------------------------------- /source/Buoy-Collections-Tests/CircularIteratorTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A CircularIteratorTest is a test class for testing the behavior of CircularIterator 3 | " 4 | Class { 5 | #name : 'CircularIteratorTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Collections-Tests', 8 | #package : 'Buoy-Collections-Tests' 9 | } 10 | 11 | { #category : 'tests-accessing' } 12 | CircularIteratorTest >> testCantCreateWithEmptyCollection [ 13 | 14 | self 15 | should: [ CircularIterator cyclingOver: #() ] 16 | raise: InstanceCreationFailed 17 | withMessageText: 'It makes no sense to iterate in a cyclic way an empty collection' 18 | ] 19 | 20 | { #category : 'tests-accessing' } 21 | CircularIteratorTest >> testCurrent [ 22 | 23 | | iterator | 24 | 25 | iterator := CircularIterator cyclingOver: #(1 2 3). 26 | 27 | self assert: iterator current equals: 1. 28 | iterator next. 29 | self assert: iterator current equals: 2. 30 | iterator next. 31 | self assert: iterator current equals: 3. 32 | iterator next. 33 | self assert: iterator current equals: 1. 34 | iterator next. 35 | self assert: iterator current equals: 2 36 | ] 37 | 38 | { #category : 'tests-accessing' } 39 | CircularIteratorTest >> testIncludes [ 40 | 41 | | iterator | 42 | 43 | iterator := CircularIterator cyclingOver: #(1 2 3). 44 | self 45 | assert: iterator includes: 1; 46 | assert: iterator includes: 2; 47 | assert: iterator includes: 3; 48 | deny: iterator includes: 4 49 | ] 50 | 51 | { #category : 'tests-accessing' } 52 | CircularIteratorTest >> testReset [ 53 | 54 | | iterator | 55 | 56 | iterator := CircularIterator cyclingOver: #(1 2 3). 57 | 58 | self assert: iterator current equals: 1. 59 | iterator next. 60 | self assert: iterator current equals: 2. 61 | iterator reset. 62 | self assert: iterator current equals: 1. 63 | 64 | ] 65 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Buoy Documentation 2 | 3 | Buoy aims to complement [Pharo](https://www.pharo.org) and [GS64](https://gemtalksystems.com/products/gs64/) 4 | adding useful extensions. 5 | 6 | To learn about the project, [install it](how-to/how-to-load-in-pharo.md) and 7 | [follow the assertions tutorial](tutorial/Assertions.md), or expand your 8 | understanding over specific topics: 9 | 10 | - **Collections**: Additional abstractions for Collections. 11 | See the [related documentation.](reference/Collections.md) 12 | - **Comparison**: Support to compare objects both for equality and identity. 13 | They are typically used to implement the `=` and `hash` methods. See the 14 | [related documentation.](reference/Comparison.md) 15 | - **Math**: Basic arithmetic abstractions like Percentages. See the 16 | [related documentation.](reference/Math.md) 17 | - **Bindings and Optionals**: Support to express optional values and 18 | required values, that can be unknown at the beginning of an execution. 19 | See the [related documentation.](reference/BindingsAndOptionals.md) 20 | - **Exception Handling**: Extensions to the [exception handling mechanics](reference/ExceptionHandling.md). 21 | - **Meta-programming**: Some abstractions like [namespaces](reference/Namespaces.md), 22 | [interfaces](reference/Interfaces.md) and extensions to the [Object model](reference/MOP.md). 23 | - **Internationalization**: Abstractions and extensions for [localizing](reference/Internationalization.md) 24 | an application. 25 | - **SUnit**: [Extensions to the SUnit framework](reference/SUnit.md). 26 | 27 | --- 28 | 29 | To use the project as a dependency of your project, take a look at: 30 | 31 | - [Pharo: How to use Buoy as a dependency](how-to/how-to-use-as-dependency-in-pharo.md) 32 | - [Baseline groups & components reference](reference/Baseline-groups.md) 33 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | There are several ways to contribute to the project: reporting bugs, sending 4 | feedback, proposing ideas for new features, fixing or adding documentation, 5 | promoting the project, or even contributing code. 6 | 7 | ## Reporting issues 8 | 9 | You can report issues [here](https://github.com/ba-st/Buoy/issues/new) 10 | 11 | ## Contributing Code 12 | 13 | - This project is MIT licensed, so any code contribution MUST be under the same license. 14 | - This project uses [Semantic Versioning](http://semver.org/), so keep it in 15 | mind when you make backwards-incompatible changes. If some backwards 16 | incompatible change is made the major version MUST be increased. 17 | - The source code is hosted in this repository using the Tonel format in the 18 | `source` folder. 19 | - The `release-candidate` branch contains the latest changes and should always 20 | be in a releasable state. 21 | - Feel free to send pull requests or fork the project. 22 | - Code contributions without test cases have a lower probability of being merged 23 | into the main branch. 24 | 25 | 1. [Load the project code in a Pharo image](docs/how-to/how-to-load-in-pharo.md) 26 | 2. Create a new branch to host your code changes 27 | 3. Do the changes 28 | 4. Run the test cases 29 | 5. Commit and push your changes to the branch using the Iceberg UI. You may need 30 | to add your fork if lacking the required permissions to push to the main repo. 31 | 6. Create a Pull Request against the `release-candidate` branch 32 | 33 | ## Contributing documentation 34 | 35 | The project documentation is maintained in this repository in the `docs` folder 36 | and licensed under CC BY-SA 4.0. To contribute some documentation or improve the 37 | existing, feel free to create a branch or fork this repository, make your 38 | changes and send a pull request. 39 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming/KeywordMessageSendingCollector.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'KeywordMessageSendingCollector', 3 | #superclass : 'MessageSendingCollector', 4 | #instVars : [ 5 | 'receiver', 6 | 'filterBlock', 7 | 'arguments' 8 | ], 9 | #category : 'Buoy-Metaprogramming', 10 | #package : 'Buoy-Metaprogramming' 11 | } 12 | 13 | { #category : 'Instance Creation' } 14 | KeywordMessageSendingCollector class >> sendingAllMessagesBeginningWith: aPrefix andEndingWith: aSuffix to: aReceiver with: anArgument [ 15 | 16 | ^ self 17 | sendingAllMessagesMatching: [ :selector | (selector beginsWith: aPrefix) and: [ selector endsWith: aSuffix ] ] 18 | to: aReceiver 19 | withAll: {anArgument} 20 | ] 21 | 22 | { #category : 'Instance Creation' } 23 | KeywordMessageSendingCollector class >> sendingAllMessagesMatching: aFilterBlock to: aReceiver withAll: anArgumentCollection [ 24 | 25 | ^ self new 26 | initializeSendingAllMessagesMatching: [ :selector | selector argumentCount = anArgumentCollection size and: [ aFilterBlock value: selector ] ] 27 | to: aReceiver 28 | withAll: anArgumentCollection asArray 29 | ] 30 | 31 | { #category : 'private' } 32 | KeywordMessageSendingCollector >> filterBlock [ 33 | 34 | ^ filterBlock 35 | ] 36 | 37 | { #category : 'initialization' } 38 | KeywordMessageSendingCollector >> initializeSendingAllMessagesMatching: aFilterBlock to: aReceiver withAll: anArgumentCollection [ 39 | 40 | filterBlock := aFilterBlock. 41 | receiver := aReceiver. 42 | arguments := anArgumentCollection 43 | ] 44 | 45 | { #category : 'private' } 46 | KeywordMessageSendingCollector >> receiver [ 47 | 48 | ^ receiver 49 | ] 50 | 51 | { #category : 'evaluating' } 52 | KeywordMessageSendingCollector >> value [ 53 | 54 | ^ self matchingSelectorsCollect: [ :selector | receiver perform: selector withArguments: arguments ] 55 | ] 56 | -------------------------------------------------------------------------------- /docs/reference/Baseline-groups.md: -------------------------------------------------------------------------------- 1 | # Baseline Groups & GS 64 Components 2 | 3 | ## Pharo Baseline Groups 4 | 5 | Buoy includes the following groups in its Baseline that can be used as 6 | loading targets: 7 | 8 | - `Deployment` will load all the packages needed in a deployed application 9 | - `Tests` will load the test cases 10 | - `Tools` will load tooling extensions 11 | - `Dependent-SUnit-Extensions` will load extensions to SUnit 12 | - `CI` is the group loaded in the continuous integration setup, in this 13 | particular case it is the same as `Tests` 14 | - `Development` will load all the needed packages to develop and contribute to 15 | the project 16 | 17 | ## Pharo - GS64 Development glue 18 | 19 | `GS64-Development` is an optional group that will load `Development` and all 20 | the packages required to develop changes applicable to GS64 in a Pharo image. 21 | 22 | Loading this package can have unexpected consequences on to the Pharo image, 23 | because it extends and changes some kernel classes. To load this group you will 24 | need first to rename `DynamicVariable` to another thing because it will try to 25 | load a GS64 version of it, and it's used during the loading stage. 26 | 27 | Once the packages are loaded remove the extension in `Object class>>#new` 28 | to recover the cursor in the browsers. 29 | 30 | Other packages in the project will be marked as dirty, but this is expected; 31 | just remember to cherry-pick the changes to commit and don't remove the changed 32 | methods in the Pharo related packages. 33 | 34 | ## GS64 Components 35 | 36 | Buoy includes the following components in its Rowan configuration that can be 37 | used as loading targets: 38 | 39 | - `Deployment` will load all the packages needed in a deployed application 40 | - `Tests` will load the test cases 41 | - `Dependent-SUnit-Extensions` will load extensions to SUnit 42 | -------------------------------------------------------------------------------- /source/Buoy-Dynamic-Binding-Tests/BindingTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm an unit test for the Behavior of Binding 3 | " 4 | Class { 5 | #name : 'BindingTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Dynamic-Binding-Tests', 8 | #package : 'Buoy-Dynamic-Binding-Tests' 9 | } 10 | 11 | { #category : 'tests' } 12 | BindingTest >> testIsDefined [ 13 | 14 | self 15 | assert: (Binding to: 1) isDefined; 16 | deny: (Binding undefinedExplainedBy: '') isDefined 17 | ] 18 | 19 | { #category : 'tests' } 20 | BindingTest >> testTo [ 21 | 22 | | binding | 23 | 24 | binding := Binding to: 1. 25 | 26 | self assert: binding content equals: 1 27 | ] 28 | 29 | { #category : 'tests' } 30 | BindingTest >> testUndefinedExplainedBy [ 31 | 32 | | binding explanation | 33 | 34 | explanation := 'Parameter not yet configured'. 35 | binding := Binding undefinedExplainedBy: explanation. 36 | 37 | self should: [ binding content ] raise: AssertionFailed withMessageText: explanation 38 | ] 39 | 40 | { #category : 'tests' } 41 | BindingTest >> testUndefinedExplainedByAllRaising [ 42 | 43 | | binding explanations | 44 | 45 | explanations := {'Parameter not yet configured' . 'Parameter seems wrong'}. 46 | binding := Binding undefinedExplainedByAll: explanations raising: InstanceCreationFailed. 47 | 48 | self 49 | should: [ binding content ] 50 | raise: InstanceCreationFailed 51 | withMessageText: 'Parameter not yet configured. Parameter seems wrong' 52 | ] 53 | 54 | { #category : 'tests' } 55 | BindingTest >> testUndefinedExplainedByRaising [ 56 | 57 | | binding explanation | 58 | 59 | explanation := 'Parameter not yet configured'. 60 | binding := Binding undefinedExplainedBy: explanation raising: InstanceCreationFailed. 61 | 62 | self 63 | should: [ binding content ] 64 | raise: InstanceCreationFailed 65 | withMessageText: explanation 66 | ] 67 | -------------------------------------------------------------------------------- /source/Buoy-Assertions/Asserter.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a helper for Assertion Checker. Not intended to be used directly. 3 | " 4 | Class { 5 | #name : 'Asserter', 6 | #superclass : 'Object', 7 | #instVars : [ 8 | 'checks' 9 | ], 10 | #category : 'Buoy-Assertions', 11 | #package : 'Buoy-Assertions' 12 | } 13 | 14 | { #category : 'private' } 15 | Asserter >> asReverseFact: aFact [ 16 | 17 | ^ [ aFact value not ] 18 | ] 19 | 20 | { #category : 'Checking' } 21 | Asserter >> checkApplying: aPolicy [ 22 | 23 | checks do: [ :check | check checkApplying: aPolicy ] 24 | ] 25 | 26 | { #category : 'configuring' } 27 | Asserter >> enforce: aFact because: aStringOrBlock [ 28 | 29 | checks add: (AssertionCheck checking: aFact onFailure: aStringOrBlock) 30 | ] 31 | 32 | { #category : 'configuring' } 33 | Asserter >> enforce: aFact because: anExplanationStringOrBlock onSuccess: aSuccessAction [ 34 | 35 | checks add: (AssertionCheck checking: aFact onSuccess: [ :policy | self value: aSuccessAction applying: policy ] onFailure: anExplanationStringOrBlock) 36 | ] 37 | 38 | { #category : 'initialization' } 39 | Asserter >> initialize [ 40 | 41 | super initialize. 42 | checks := OrderedCollection new 43 | ] 44 | 45 | { #category : 'configuring' } 46 | Asserter >> refuse: aFact because: aStringOrBlock [ 47 | 48 | self enforce: (self asReverseFact: aFact) because: aStringOrBlock 49 | ] 50 | 51 | { #category : 'configuring' } 52 | Asserter >> refuse: aFact because: anExplanationStringOrBlock onSuccess: aSuccessAction [ 53 | 54 | self enforce: (self asReverseFact: aFact) because: anExplanationStringOrBlock onSuccess: aSuccessAction 55 | ] 56 | 57 | { #category : 'private' } 58 | Asserter >> value: aSuccessAction applying: policy [ 59 | 60 | | asserter | 61 | 62 | asserter := self class new. 63 | aSuccessAction value: asserter. 64 | asserter checkApplying: policy 65 | ] 66 | -------------------------------------------------------------------------------- /source/Buoy-Collections-GS64-Extensions/AbstractDictionary.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'AbstractDictionary' } 2 | 3 | { #category : '*Buoy-Collections-GS64-Extensions' } 4 | AbstractDictionary >> associations [ 5 | 6 | ^ self associationsAsArray 7 | ] 8 | 9 | { #category : '*Buoy-Collections-GS64-Extensions' } 10 | AbstractDictionary >> associationsSelect: aBlock [ 11 | 12 | ^ self selectAssociations: aBlock 13 | ] 14 | 15 | { #category : '*Buoy-Collections-GS64-Extensions' } 16 | AbstractDictionary >> at: key ifPresent: aPresentBlock ifAbsent: anAbsentBlock [ 17 | 18 | | presentValue | 19 | presentValue := self at: key ifAbsent: [ ^ anAbsentBlock value ]. 20 | ^ aPresentBlock cull: presentValue 21 | ] 22 | 23 | { #category : '*Buoy-Collections-GS64-Extensions' } 24 | AbstractDictionary >> at: key ifPresent: aBlock ifAbsentPut: anAbsentBlock [ 25 | 26 | | presentValue | 27 | presentValue := self at: key ifAbsent: [ 28 | | absentValue | 29 | absentValue := anAbsentBlock value. 30 | self at: key put: absentValue. 31 | ^ absentValue ]. 32 | ^ aBlock cull: presentValue 33 | ] 34 | 35 | { #category : '*Buoy-Collections-GS64-Extensions' } 36 | AbstractDictionary >> isDictionary [ 37 | 38 | ^ true 39 | ] 40 | 41 | { #category : '*Buoy-Collections-GS64-Extensions' } 42 | AbstractDictionary class >> newFromPairs: anArray [ 43 | "Answer an instance of me associating (anArray at: i) to (anArray at: i+1) 44 | for each odd i. anArray must have an even number of entries." 45 | 46 | | newDictionary | 47 | newDictionary := self new: anArray size / 2. 48 | 1 to: anArray size - 1 by: 2 do: [ :i | newDictionary at: (anArray at: i) put: (anArray at: i + 1) ]. 49 | ^ newDictionary 50 | ] 51 | 52 | { #category : '*Buoy-Collections-GS64-Extensions' } 53 | AbstractDictionary >> removeAll [ 54 | 55 | ^ self removeAllKeys: self keys 56 | ] 57 | -------------------------------------------------------------------------------- /source/Buoy-Localization/MonoglotNaturalLanguageTranslator.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'MonoglotNaturalLanguageTranslator', 3 | #superclass : 'Object', 4 | #instVars : [ 5 | 'targetLanguageRange', 6 | 'translations' 7 | ], 8 | #category : 'Buoy-Localization', 9 | #package : 'Buoy-Localization' 10 | } 11 | 12 | { #category : 'instance creation' } 13 | MonoglotNaturalLanguageTranslator class >> for: aLanguageRange [ 14 | 15 | ^ self new initializeFor: aLanguageRange 16 | ] 17 | 18 | { #category : 'private' } 19 | MonoglotNaturalLanguageTranslator >> hashCodeFor: string [ 20 | 21 | ^ LanguagePlatform current messageDigest: string 22 | ] 23 | 24 | { #category : 'initialization' } 25 | MonoglotNaturalLanguageTranslator >> initializeFor: aLanguageRange [ 26 | 27 | targetLanguageRange := aLanguageRange. 28 | translations := Dictionary new 29 | ] 30 | 31 | { #category : 'testing' } 32 | MonoglotNaturalLanguageTranslator >> isFor: aLanguageRange [ 33 | 34 | ^ targetLanguageRange = aLanguageRange 35 | ] 36 | 37 | { #category : 'testing' } 38 | MonoglotNaturalLanguageTranslator >> matches: aLanguageTag [ 39 | 40 | ^ targetLanguageRange matches: aLanguageTag 41 | ] 42 | 43 | { #category : 'accessing' } 44 | MonoglotNaturalLanguageTranslator >> specificity [ 45 | 46 | ^targetLanguageRange specificity 47 | 48 | ] 49 | 50 | { #category : 'private' } 51 | MonoglotNaturalLanguageTranslator >> translationAt: hash put: translatedString [ 52 | 53 | translations at: hash put: translatedString 54 | ] 55 | 56 | { #category : 'configuring' } 57 | MonoglotNaturalLanguageTranslator >> translationFor: string is: translatedString [ 58 | 59 | ^ self translationAt: ( self hashCodeFor: string unescaped ) put: translatedString unescaped 60 | ] 61 | 62 | { #category : 'localization' } 63 | MonoglotNaturalLanguageTranslator >> withTranslationOf: string do: block [ 64 | 65 | translations at: ( self hashCodeFor: string ) ifPresent: block 66 | ] 67 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming/UnaryMessageSendingCollector.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'UnaryMessageSendingCollector', 3 | #superclass : 'MessageSendingCollector', 4 | #instVars : [ 5 | 'receiver', 6 | 'filterBlock' 7 | ], 8 | #category : 'Buoy-Metaprogramming', 9 | #package : 'Buoy-Metaprogramming' 10 | } 11 | 12 | { #category : 'Instance Creation' } 13 | UnaryMessageSendingCollector class >> sendingAllMessagesBeginningWith: aPrefix andEndingWith: aSuffix to: aReceiver [ 14 | 15 | ^ self sendingAllMessagesMatching: [ :selector | (selector beginsWith: aPrefix) and: [ selector endsWith: aSuffix ] ] to: aReceiver 16 | ] 17 | 18 | { #category : 'Instance Creation' } 19 | UnaryMessageSendingCollector class >> sendingAllMessagesBeginningWith: aPrefix to: aReceiver [ 20 | 21 | ^ self sendingAllMessagesMatching: [ :selector | selector beginsWith: aPrefix ] to: aReceiver 22 | ] 23 | 24 | { #category : 'Instance Creation' } 25 | UnaryMessageSendingCollector class >> sendingAllMessagesEndingWith: aSuffix to: aReceiver [ 26 | 27 | ^ self sendingAllMessagesMatching: [ :selector | selector endsWith: aSuffix ] to: aReceiver 28 | ] 29 | 30 | { #category : 'Instance Creation' } 31 | UnaryMessageSendingCollector class >> sendingAllMessagesMatching: aFilterBlock to: aReceiver [ 32 | 33 | ^ self new initializeSendingAllMessagesMatching: aFilterBlock to: aReceiver 34 | ] 35 | 36 | { #category : 'private' } 37 | UnaryMessageSendingCollector >> filterBlock [ 38 | 39 | ^ filterBlock 40 | ] 41 | 42 | { #category : 'initialization' } 43 | UnaryMessageSendingCollector >> initializeSendingAllMessagesMatching: aFilterBlock to: aReceiver [ 44 | 45 | filterBlock := aFilterBlock. 46 | receiver := aReceiver 47 | ] 48 | 49 | { #category : 'private' } 50 | UnaryMessageSendingCollector >> receiver [ 51 | 52 | ^ receiver 53 | ] 54 | 55 | { #category : 'evaluating' } 56 | UnaryMessageSendingCollector >> value [ 57 | 58 | ^ self matchingSelectorsCollect: [ :selector | receiver perform: selector ] 59 | ] 60 | -------------------------------------------------------------------------------- /source/Buoy-SUnit-Model/TestAsserter.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'TestAsserter' } 2 | 3 | { #category : '*Buoy-SUnit-Model' } 4 | TestAsserter >> assert: aSequenceableCollection hasTheSameElementsInTheSameOrderThat: anotherSequenceableCollection [ 5 | 6 | self 7 | assert: aSequenceableCollection isSequenceable; 8 | assert: anotherSequenceableCollection isSequenceable; 9 | assert: aSequenceableCollection size equals: anotherSequenceableCollection size. 10 | 11 | aSequenceableCollection with: anotherSequenceableCollection 12 | do: [ :firstElement :secondElement | self assert: firstElement equals: secondElement ] 13 | ] 14 | 15 | { #category : '*Buoy-SUnit-Model' } 16 | TestAsserter >> assert: aCollection includes: anObject [ 17 | 18 | self assert: (aCollection includes: anObject) 19 | ] 20 | 21 | { #category : '*Buoy-SUnit-Model' } 22 | TestAsserter >> deny: aCollection includes: anObject [ 23 | 24 | self deny: (aCollection includes: anObject) 25 | ] 26 | 27 | { #category : '*Buoy-SUnit-Model' } 28 | TestAsserter >> should: aBlock raise: anException withMessageText: aString [ 29 | 30 | self 31 | should: aBlock 32 | raise: anException 33 | withExceptionDo: [ :error | self assert: error messageText equals: aString ] 34 | ] 35 | 36 | { #category : '*Buoy-SUnit-Model' } 37 | TestAsserter >> use: languageTag asLocaleDuring: aBlock [ 38 | 39 | CurrentLocale use: languageTag during: aBlock 40 | ] 41 | 42 | { #category : '*Buoy-SUnit-Model' } 43 | TestAsserter >> use: translatorConfigurationBlock asNaturalLanguageTranslatorDuring: aBlock [ 44 | 45 | | translator | 46 | translator := PolyglotNaturalLanguageTranslator new. 47 | translatorConfigurationBlock value: translator. 48 | NaturalLanguageTranslator use: translator during: aBlock 49 | ] 50 | 51 | { #category : '*Buoy-SUnit-Model' } 52 | TestAsserter >> withTheOnlyOneIn: aCollection do: aBlock [ 53 | 54 | self 55 | assert: aCollection size 56 | equals: 1. 57 | aBlock value: aCollection anyOne 58 | ] 59 | -------------------------------------------------------------------------------- /source/Buoy-Chronology-GS64-Extensions/Duration.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Duration' } 2 | 3 | { #category : '*Buoy-Chronology-GS64-Extensions' } 4 | Duration >> asMicroseconds [ 5 | 6 | ^ self asSeconds * 1000000 7 | ] 8 | 9 | { #category : '*Buoy-Chronology-GS64-Extensions' } 10 | Duration >> asMilliSeconds [ 11 | 12 | ^ self asSeconds * 1000 13 | ] 14 | 15 | { #category : '*Buoy-Chronology-GS64-Extensions' } 16 | Duration >> asNanoSeconds [ 17 | 18 | ^ self asSeconds * 1000000000 19 | ] 20 | 21 | { #category : '*Buoy-Chronology-GS64-Extensions' } 22 | Duration class >> days: aNumber [ 23 | 24 | ^ self seconds: aNumber * 86400 25 | ] 26 | 27 | { #category : '*Buoy-Chronology-GS64-Extensions' } 28 | Duration class >> hours: aNumber [ 29 | 30 | ^ self seconds: aNumber * 3600 31 | ] 32 | 33 | { #category : '*Buoy-Chronology-GS64-Extensions' } 34 | Duration >> isZero [ 35 | 36 | ^ self totalSeconds isZero 37 | ] 38 | 39 | { #category : '*Buoy-Chronology-GS64-Extensions' } 40 | Duration class >> milliSeconds: aNumber [ 41 | 42 | ^ self seconds: aNumber / 1000 43 | ] 44 | 45 | { #category : '*Buoy-Chronology-GS64-Extensions' } 46 | Duration class >> minutes: aNumber [ 47 | 48 | ^ self seconds: aNumber * 60 49 | ] 50 | 51 | { #category : '*Buoy-Chronology-GS64-Extensions' } 52 | Duration >> totalSeconds [ 53 | 54 | ^self asSeconds 55 | ] 56 | 57 | { #category : '*Buoy-Chronology-GS64-Extensions' } 58 | Duration >> wait [ 59 | 60 | ^ Delay waitForMilliseconds: (self seconds * 1000) rounded 61 | ] 62 | 63 | { #category : '*Buoy-Chronology-GS64-Extensions' } 64 | Duration >> wholeMicroseconds [ 65 | 66 | ^ (self asMicroseconds rem: 1000) truncated 67 | ] 68 | 69 | { #category : '*Buoy-Chronology-GS64-Extensions' } 70 | Duration >> wholeMilliseconds [ 71 | 72 | ^ (self asMilliSeconds rem: 1000) truncated 73 | ] 74 | 75 | { #category : '*Buoy-Chronology-GS64-Extensions' } 76 | Duration >> wholeNanoseconds [ 77 | 78 | ^ (self asNanoSeconds rem: 1000) truncated 79 | ] 80 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Tests/BuoyMetaprogrammingExtensionsTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a test case for extensions related to meta programming 3 | " 4 | Class { 5 | #name : 'BuoyMetaprogrammingExtensionsTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Metaprogramming-Tests', 8 | #package : 'Buoy-Metaprogramming-Tests' 9 | } 10 | 11 | { #category : 'tests' } 12 | BuoyMetaprogrammingExtensionsTest >> testBehaviorAllLeafSubclasses [ 13 | 14 | self assert: self class allLeafSubclasses isEmpty. 15 | 16 | self 17 | assert: MessageSendingCollector allLeafSubclasses size equals: 2; 18 | assert: MessageSendingCollector allLeafSubclasses includes: KeywordMessageSendingCollector; 19 | assert: MessageSendingCollector allLeafSubclasses includes: UnaryMessageSendingCollector 20 | ] 21 | 22 | { #category : 'tests' } 23 | BuoyMetaprogrammingExtensionsTest >> testBehaviorAllSubclassesDo [ 24 | 25 | | collectorSubclasses | 26 | self class allSubclassesDo: [ :class | self fail ]. 27 | 28 | collectorSubclasses := OrderedCollection new. 29 | MessageSendingCollector allSubclassesDo: [ :class | 30 | collectorSubclasses add: class ]. 31 | self 32 | assert: collectorSubclasses size equals: 2; 33 | assert: collectorSubclasses 34 | includes: KeywordMessageSendingCollector; 35 | assert: collectorSubclasses includes: UnaryMessageSendingCollector 36 | ] 37 | 38 | { #category : 'tests' } 39 | BuoyMetaprogrammingExtensionsTest >> testBehaviorCompiledMethodAccess [ 40 | 41 | self 42 | assert: (self class >> testSelector) selector 43 | equals: testSelector 44 | ] 45 | 46 | { #category : 'test' } 47 | BuoyMetaprogrammingExtensionsTest >> testIsA [ 48 | 49 | self 50 | assert: (self isA: TestCase); 51 | assert: (self isA: self class); 52 | assert: (self isAn: Object); 53 | deny: (self isA: Number); 54 | deny: (self isAn: Integer); 55 | deny: (self isA: Collection) 56 | ] 57 | 58 | { #category : 'test' } 59 | BuoyMetaprogrammingExtensionsTest >> testIsNotNil [ 60 | 61 | self 62 | assert: self isNotNil; 63 | deny: nil isNotNil 64 | ] 65 | -------------------------------------------------------------------------------- /source/Buoy-Conditions/ArithmeticCondition.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a Condition. 3 | I'm an ArithmeticCondition 4 | 5 | I test arithmetic operations ( =, ~=, <, <=, >, >= ) against a provided value. 6 | 7 | Example: 8 | ArithmeticCondition toBeEqualTo: 1. 9 | " 10 | Class { 11 | #name : 'ArithmeticCondition', 12 | #superclass : 'Condition', 13 | #instVars : [ 14 | 'value', 15 | 'arithmeticOperator' 16 | ], 17 | #category : 'Buoy-Conditions', 18 | #package : 'Buoy-Conditions' 19 | } 20 | 21 | { #category : 'private-instance creation' } 22 | ArithmeticCondition class >> comparingAgainst: aValue using: anArithmeticOperator [ 23 | 24 | ^ self new initializeComparingAgainst: aValue using: anArithmeticOperator 25 | ] 26 | 27 | { #category : 'instance creation' } 28 | ArithmeticCondition class >> toBeDifferentTo: aValue [ 29 | 30 | ^ self comparingAgainst: aValue using: #~= 31 | ] 32 | 33 | { #category : 'instance creation' } 34 | ArithmeticCondition class >> toBeEqualTo: aValue [ 35 | 36 | ^ self comparingAgainst: aValue using: #= 37 | ] 38 | 39 | { #category : 'instance creation' } 40 | ArithmeticCondition class >> toBeGreaterOrEqualThan: aValue [ 41 | 42 | ^ self comparingAgainst: aValue using: #>= 43 | ] 44 | 45 | { #category : 'instance creation' } 46 | ArithmeticCondition class >> toBeGreaterThan: aValue [ 47 | 48 | ^ self comparingAgainst: aValue using: #> 49 | ] 50 | 51 | { #category : 'instance creation' } 52 | ArithmeticCondition class >> toBeLessOrEqualThan: aValue [ 53 | 54 | ^ self comparingAgainst: aValue using: #<= 55 | ] 56 | 57 | { #category : 'instance creation' } 58 | ArithmeticCondition class >> toBeLessThan: aValue [ 59 | 60 | ^ self comparingAgainst: aValue using: #< 61 | ] 62 | 63 | { #category : 'initialize-release' } 64 | ArithmeticCondition >> initializeComparingAgainst: aValue using: anArithmeticOperator [ 65 | 66 | value := aValue. 67 | arithmeticOperator := anArithmeticOperator 68 | ] 69 | 70 | { #category : 'testing' } 71 | ArithmeticCondition >> isSatisfiedBy: aValue [ 72 | 73 | ^ aValue perform: arithmeticOperator with: value 74 | ] 75 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Pharo-Extensions/PharoPlatform.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : 'PharoPlatform', 3 | #superclass : 'LanguagePlatform', 4 | #category : 'Buoy-Metaprogramming-Pharo-Extensions', 5 | #package : 'Buoy-Metaprogramming-Pharo-Extensions' 6 | } 7 | 8 | { #category : 'class initialization' } 9 | PharoPlatform class >> initialize [ 10 | 11 | 12 | LanguagePlatform setCurrentTo: self new 13 | ] 14 | 15 | { #category : 'reflection' } 16 | PharoPlatform >> atInstanceVariableNamed: name on: object put: value [ 17 | 18 | object instVarNamed: name put: value 19 | ] 20 | 21 | { #category : 'process scheduling' } 22 | PharoPlatform >> fork: block named: processName at: priority [ 23 | 24 | ^ block forkAt: priority named: processName 25 | ] 26 | 27 | { #category : 'reflection' } 28 | PharoPlatform >> globalNamed: aSymbol ifAbsent: absentBlock [ 29 | 30 | ^ Smalltalk globals at: aSymbol ifAbsent: absentBlock 31 | ] 32 | 33 | { #category : 'reflection' } 34 | PharoPlatform >> globalNamed: symbol ifAbsentPut: block [ 35 | 36 | ^ Smalltalk globals at: symbol ifAbsentPut: block 37 | ] 38 | 39 | { #category : 'reflection' } 40 | PharoPlatform >> includesGlobalNamed: aSymbol [ 41 | 42 | ^ Smalltalk globals includesKey: aSymbol 43 | ] 44 | 45 | { #category : 'reflection' } 46 | PharoPlatform >> instanceVariableNamed: name on: object [ 47 | 48 | ^ object instVarNamed: name 49 | ] 50 | 51 | { #category : 'message digest' } 52 | PharoPlatform >> messageDigest: string [ 53 | 54 | ^ SHA256 hashMessage: string 55 | ] 56 | 57 | { #category : 'process scheduling' } 58 | PharoPlatform >> newProcessNamed: processName evaluating: block at: priority [ 59 | 60 | ^ block newProcess 61 | priority: priority; 62 | name: processName; 63 | yourself 64 | ] 65 | 66 | { #category : 'accessing' } 67 | PharoPlatform >> os [ 68 | 69 | ^ OSPlatform current 70 | ] 71 | 72 | { #category : 'reflection' } 73 | PharoPlatform >> removeGlobalNamed: aSymbol ifAbsent: absentBlock [ 74 | 75 | ^ Smalltalk globals removeKey: aSymbol ifAbsent: absentBlock 76 | ] 77 | -------------------------------------------------------------------------------- /source/Buoy-Comparison-Tests/BitwiseExclusiveDisjunctionHashCombinatorTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A BitwiseExclusiveDisjunctionHashCombinatorTest is a test class for testing the behavior of BitwiseExclusiveDisjunctionHashCombinator 3 | " 4 | Class { 5 | #name : 'BitwiseExclusiveDisjunctionHashCombinatorTest', 6 | #superclass : 'TestCase', 7 | #instVars : [ 8 | 'hashCombinator' 9 | ], 10 | #category : 'Buoy-Comparison-Tests', 11 | #package : 'Buoy-Comparison-Tests' 12 | } 13 | 14 | { #category : 'running' } 15 | BitwiseExclusiveDisjunctionHashCombinatorTest >> setUp [ 16 | 17 | super setUp. 18 | hashCombinator := BitwiseExclusiveDisjunctionHashCombinator new 19 | ] 20 | 21 | { #category : 'tests' } 22 | BitwiseExclusiveDisjunctionHashCombinatorTest >> testCannotCombineAnEmptyCollection [ 23 | 24 | self 25 | should: [ hashCombinator combineAll: #() ] 26 | raise: AssertionFailed 27 | withMessageText: 'Cannot combine an empty collection of hashes' 28 | ] 29 | 30 | { #category : 'tests' } 31 | BitwiseExclusiveDisjunctionHashCombinatorTest >> testCombineAll [ 32 | 33 | self 34 | assert: ( hashCombinator combineAll: #(2 5 6) ) equals: ( ( 2 bitXor: 5 ) bitXor: 6 ); 35 | assert: ( hashCombinator combineAll: #(20 1) ) equals: ( 1 bitXor: 20 ); 36 | assert: ( hashCombinator combineAll: #(100 0 4 50) ) 37 | equals: ( ( ( 100 bitXor: 50 ) bitXor: 4 ) bitXor: 0 ); 38 | assert: ( hashCombinator combineAll: #(2) ) equals: 2; 39 | assert: ( hashCombinator combineAll: #(20) ) equals: 20; 40 | assert: ( hashCombinator combineAll: #(100) ) equals: 100 41 | ] 42 | 43 | { #category : 'tests' } 44 | BitwiseExclusiveDisjunctionHashCombinatorTest >> testCombineHashOfWith [ 45 | 46 | self 47 | assert: ( hashCombinator combineHashOf: 'alpha' with: 'beta' ) 48 | equals: ( 'alpha' hash bitXor: 'beta' hash ) 49 | ] 50 | 51 | { #category : 'tests' } 52 | BitwiseExclusiveDisjunctionHashCombinatorTest >> testCombineHashesOfAll [ 53 | 54 | self 55 | assert: ( hashCombinator combineHashesOfAll: #('alpha' 'beta' 'gamma') ) 56 | equals: ( ( 'alpha' hash bitXor: 'beta' hash ) bitXor: 'gamma' hash ) 57 | ] 58 | -------------------------------------------------------------------------------- /source/Buoy-Conditions/CompositeCondition.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a Condition. 3 | I'm a CompositeCondition 4 | 5 | I test that the conditions involved are satisfied, either all or any depending on how I was created. 6 | 7 | Example: 8 | CompositeCondition 9 | satisfying: (ArithmeticCondition toBeGreaterOrEqualThan: 0) 10 | and: (ArithmeticCondition toBeLessOrEqualThan: 2). 11 | 12 | " 13 | Class { 14 | #name : 'CompositeCondition', 15 | #superclass : 'Condition', 16 | #instVars : [ 17 | 'conditions', 18 | 'compositionPolicy' 19 | ], 20 | #category : 'Buoy-Conditions', 21 | #package : 'Buoy-Conditions' 22 | } 23 | 24 | { #category : 'instance creation' } 25 | CompositeCondition class >> satisfying: aCondition and: anotherCondition [ 26 | 27 | ^ self satisfyingAll: (Array with: aCondition with: anotherCondition) 28 | ] 29 | 30 | { #category : 'instance creation' } 31 | CompositeCondition class >> satisfying: aCondition or: anotherCondition [ 32 | 33 | ^ self satisfyingAnyOf: (Array with: aCondition with: anotherCondition) 34 | ] 35 | 36 | { #category : 'instance creation' } 37 | CompositeCondition class >> satisfyingAll: aConditionCollection [ 38 | 39 | ^ self toSatisfyAll: aConditionCollection using: #allSatisfy: 40 | ] 41 | 42 | { #category : 'instance creation' } 43 | CompositeCondition class >> satisfyingAnyOf: aConditionCollection [ 44 | 45 | ^ self toSatisfyAll: aConditionCollection using: #anySatisfy: 46 | ] 47 | 48 | { #category : 'private-instance creation' } 49 | CompositeCondition class >> toSatisfyAll: aConditionCollection using: aCompositionPolicy [ 50 | 51 | ^ self new 52 | initializeToSastifyAll: aConditionCollection 53 | using: aCompositionPolicy 54 | ] 55 | 56 | { #category : 'initialize-release' } 57 | CompositeCondition >> initializeToSastifyAll: aConditionCollection using: aCompositionPolicy [ 58 | 59 | compositionPolicy := aCompositionPolicy. 60 | conditions := aConditionCollection 61 | ] 62 | 63 | { #category : 'testing' } 64 | CompositeCondition >> isSatisfiedBy: aValue [ 65 | 66 | ^ conditions perform: compositionPolicy with: [ :condition | condition isSatisfiedBy: aValue ] 67 | ] 68 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming/Namespace.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a namespace, my responsibility is to bind a set of symbols to objects of various kinds, so that these objects may be referred to by name. 3 | " 4 | Class { 5 | #name : 'Namespace', 6 | #superclass : 'Object', 7 | #instVars : [ 8 | 'bindings' 9 | ], 10 | #category : 'Buoy-Metaprogramming', 11 | #package : 'Buoy-Metaprogramming' 12 | } 13 | 14 | { #category : 'accessing' } 15 | Namespace >> >> aName [ 16 | 17 | ^ self at: aName 18 | ] 19 | 20 | { #category : 'private - preconditions' } 21 | Namespace >> assertIsSymbol: aSymbol [ 22 | 23 | AssertionChecker 24 | enforce: [ aSymbol isSymbol] 25 | because: [ 'Only symbols can be bound. <1p> is not valid' expandMacrosWith: aSymbol ] 26 | ] 27 | 28 | { #category : 'accessing' } 29 | Namespace >> at: aName [ 30 | 31 | ^ self at: aName ifAbsent: [ self signalNotFoundFor: aName ] 32 | ] 33 | 34 | { #category : 'accessing' } 35 | Namespace >> at: aName ifAbsent: aBlock [ 36 | 37 | ^ bindings at: aName ifAbsent: aBlock 38 | ] 39 | 40 | { #category : 'binding' } 41 | Namespace >> bind: aSymbol to: anObject [ 42 | 43 | self assertIsSymbol: aSymbol. 44 | bindings 45 | at: aSymbol 46 | ifPresent: [ ConflictingObjectFound 47 | signal: ( '<1s> is already bound to some object.' expandMacrosWith: aSymbol ) ] 48 | ifAbsentPut: anObject 49 | ] 50 | 51 | { #category : 'initialization' } 52 | Namespace >> initialize [ 53 | 54 | super initialize. 55 | bindings := IdentityDictionary new 56 | ] 57 | 58 | { #category : 'accessing' } 59 | Namespace >> names [ 60 | 61 | ^ bindings keys 62 | ] 63 | 64 | { #category : 'binding' } 65 | Namespace >> rebind: aSymbol to: anObject [ 66 | 67 | self assertIsSymbol: aSymbol. 68 | bindings at: aSymbol put: anObject 69 | ] 70 | 71 | { #category : 'binding' } 72 | Namespace >> removeBindingFor: aSymbol [ 73 | 74 | ^ bindings removeKey: aSymbol ifAbsent: [ self signalNotFoundFor: aSymbol ] 75 | ] 76 | 77 | { #category : 'private - signaling' } 78 | Namespace >> signalNotFoundFor: aName [ 79 | 80 | ^ ObjectNotFound signal: ('There''s no object bound to <1s>' expandMacrosWith: aName) 81 | ] 82 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Base-Extensions/DomainError.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I am DomainError, an ArithmeticException indicating that some argument falls outside an expected domain, [from, to] 3 | 4 | When my valid interval is left- or right-open, use signal: creation protocol to provide a custom messageText rather than the default [from, to] notation. 5 | " 6 | Class { 7 | #name : 'DomainError', 8 | #superclass : 'ArithmeticError', 9 | #instVars : [ 10 | 'from', 11 | 'to' 12 | ], 13 | #category : 'Buoy-Math-GS64-Base-Extensions', 14 | #package : 'Buoy-Math-GS64-Base-Extensions' 15 | } 16 | 17 | { #category : 'signaling' } 18 | DomainError class >> signal: signallerText from: start [ 19 | ^ self signal: signallerText from: start to: Float infinity 20 | ] 21 | 22 | { #category : 'signaling' } 23 | DomainError class >> signal: signallerText from: start to: end [ 24 | ^ self new 25 | from: start; 26 | to: end; 27 | signal: signallerText 28 | ] 29 | 30 | { #category : 'signaling' } 31 | DomainError class >> signal: signallerText to: end [ 32 | ^ self signal: signallerText from: Float infinity negated to: end 33 | ] 34 | 35 | { #category : 'signaling' } 36 | DomainError class >> signalFrom: start [ 37 | ^ self signalFrom: start to: Float infinity 38 | ] 39 | 40 | { #category : 'signaling' } 41 | DomainError class >> signalFrom: start to: end [ 42 | | msgStart msgEnd | 43 | msgStart := (start isFloat and: [start isFinite not]) ifTrue: ['(-infinity'] ifFalse: ['[', start printString]. 44 | msgEnd := (end isFloat and: [end isFinite not]) ifTrue: ['infinity)'] ifFalse: [end printString, ']']. 45 | ^ self signal: 'Value outside ', msgStart, ' , ' , msgEnd 46 | from: start 47 | to: end 48 | ] 49 | 50 | { #category : 'signaling' } 51 | DomainError class >> signalTo: end [ 52 | ^ self signalFrom: Float infinity negated to: end 53 | ] 54 | 55 | { #category : 'accessing' } 56 | DomainError >> from [ 57 | 58 | ^ from 59 | ] 60 | 61 | { #category : 'accessing' } 62 | DomainError >> from: start [ 63 | 64 | from := start 65 | ] 66 | 67 | { #category : 'accessing' } 68 | DomainError >> to [ 69 | 70 | ^ to 71 | ] 72 | 73 | { #category : 'accessing' } 74 | DomainError >> to: end [ 75 | 76 | to := end 77 | ] 78 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Base-Extensions/Integer.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'Integer' } 2 | 3 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 4 | Integer >> asHexStringPaddedTo: minimum [ 5 | 6 | ^ (self asHexStringWithLength: minimum) asUppercase 7 | ] 8 | 9 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 10 | Integer >> atRandom [ 11 | 12 | self = 0 ifTrue: [ ^ 0 ]. 13 | ^ Random new integerBetween: 1 and: self abs 14 | ] 15 | 16 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 17 | Integer >> hashMultiply [ 18 | "No need to do something special in GS64" 19 | 20 | ^ self 21 | ] 22 | 23 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 24 | Integer >> isInteger [ 25 | "True for all subclasses of Integer." 26 | 27 | ^ true 28 | ] 29 | 30 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 31 | Integer >> printStringHex [ 32 | 33 | ^ self asHexString asUppercase 34 | ] 35 | 36 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 37 | Integer >> printStringLength: minimum padded: zeroFlag [ 38 | 39 | | numberPrintString preffix | 40 | numberPrintString := self abs printString. 41 | preffix := self negative then: [ '-' ] otherwise: [ '' ]. 42 | ^ String streamContents: [ :stream | 43 | | padLength | 44 | padLength := minimum - numberPrintString size - preffix size. 45 | stream nextPutAll: preffix. 46 | padLength strictlyPositive then: [ 47 | | filler | 48 | filler := zeroFlag 49 | ifTrue: [ $0 ] 50 | ifFalse: [ Character space ]. 51 | padLength timesRepeat: [ stream nextPut: filler ] ]. 52 | stream nextPutAll: numberPrintString ] 53 | ] 54 | 55 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 56 | Integer class >> readFrom: aStringOrStream ifFail: aBlock [ 57 | 58 | ^ [ 59 | aStringOrStream isString 60 | ifTrue: [ self fromString: aStringOrStream ] 61 | ifFalse: [ self fromStream: aStringOrStream ] ] 62 | on: ImproperOperation 63 | do: [ :error | error return: aBlock value ] 64 | ] 65 | 66 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 67 | Integer class >> readFromHex: string ifFail: failBlock [ 68 | ^ [ 69 | Integer fromHexString: string ] 70 | on: ImproperOperation 71 | do: [ :error | error return: failBlock value ] 72 | ] 73 | -------------------------------------------------------------------------------- /source/Buoy-Metaprogramming-Tests/UnaryMessageSendingCollectorTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | An UnaryMessageSendingCollectorTest is a test class for testing the behavior of UnaryMessageSendingCollector 3 | " 4 | Class { 5 | #name : 'UnaryMessageSendingCollectorTest', 6 | #superclass : 'TestCase', 7 | #instVars : [ 8 | 'messagesSent' 9 | ], 10 | #category : 'Buoy-Metaprogramming-Tests', 11 | #package : 'Buoy-Metaprogramming-Tests' 12 | } 13 | 14 | { #category : 'initialization' } 15 | UnaryMessageSendingCollectorTest >> setUp [ 16 | 17 | super setUp. 18 | messagesSent := IdentitySet new 19 | ] 20 | 21 | { #category : 'tests-evaluating' } 22 | UnaryMessageSendingCollectorTest >> testValue [ 23 | 24 | ( UnaryMessageSendingCollector 25 | sendingAllMessagesBeginningWith: 'zzzTest' 26 | andEndingWith: 'Test' 27 | to: self ) value. 28 | 29 | self 30 | assert: messagesSent size equals: 1; 31 | assert: messagesSent includes: #zzzTest 32 | ] 33 | 34 | { #category : 'tests-evaluating' } 35 | UnaryMessageSendingCollectorTest >> testValueWithPrefix [ 36 | 37 | ( UnaryMessageSendingCollector sendingAllMessagesBeginningWith: 'zzzTest' to: self ) value. 38 | 39 | self 40 | assert: messagesSent size equals: 2; 41 | assert: messagesSent includes: #zzzTest; 42 | assert: messagesSent includes: #zzzTest2 43 | ] 44 | 45 | { #category : 'tests-evaluating' } 46 | UnaryMessageSendingCollectorTest >> testValueWithSuffix [ 47 | 48 | ( UnaryMessageSendingCollector sendingAllMessagesEndingWith: 'Test2' to: self ) value. 49 | 50 | self 51 | assert: messagesSent size equals: 2; 52 | assert: messagesSent includes: #zzzTest2; 53 | assert: messagesSent includes: #zzTest2 54 | ] 55 | 56 | { #category : 'private' } 57 | UnaryMessageSendingCollectorTest >> zzTest [ 58 | 59 | 60 | "This methods must exist but not be executed" 61 | self fail 62 | ] 63 | 64 | { #category : 'private' } 65 | UnaryMessageSendingCollectorTest >> zzTest2 [ 66 | 67 | messagesSent add: #zzTest2 68 | ] 69 | 70 | { #category : 'private' } 71 | UnaryMessageSendingCollectorTest >> zzzTest [ 72 | 73 | messagesSent add: #zzzTest 74 | ] 75 | 76 | { #category : 'private' } 77 | UnaryMessageSendingCollectorTest >> zzzTest2 [ 78 | 79 | messagesSent add: #zzzTest2 80 | ] 81 | -------------------------------------------------------------------------------- /source/Buoy-Math-GS64-Base-Extensions/BinaryFloat.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : 'BinaryFloat' } 2 | 3 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 4 | BinaryFloat >> closeTo: num [ 5 | "Tell whether the receiver and arguments are close from each." 6 | 7 | ^ self closeTo: num precision: self class defaultComparisonPrecision 8 | ] 9 | 10 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 11 | BinaryFloat >> closeTo: num precision: aPrecision [ 12 | "Tell whether the receiver and arguments are close from each other given a precision" 13 | 14 | num isNumber ifFalse: [ ^ false ]. 15 | 16 | ^ self = num asFloat or: [ (self - num) abs <= aPrecision ] 17 | ] 18 | 19 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 20 | BinaryFloat class >> defaultComparisonPrecision [ 21 | 22 | "Default precision used for comparing two float numbers. 23 | Using value described in Numerical Recipes, 3rd edition, Section 5.7, which is pages 229-230 24 | corresponding to the square root of the machine epsilon: self epsilon sqrt" 25 | ^ 1.4901161193847656e-8 26 | ] 27 | 28 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 29 | BinaryFloat class >> infinity [ 30 | 31 | ^ PlusInfinity 32 | ] 33 | 34 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 35 | BinaryFloat >> isFinite [ 36 | 37 | ^ #( #normal #subnormal #zero ) includes: self kind 38 | ] 39 | 40 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 41 | BinaryFloat >> isInfinite [ 42 | 43 | ^ self kind = #infinity 44 | ] 45 | 46 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 47 | BinaryFloat >> isNaN [ 48 | 49 | ^ #( #quietNaN #signalingNaN ) includes: self kind 50 | ] 51 | 52 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 53 | BinaryFloat class >> nan [ 54 | 55 | ^ MinusQuietNaN 56 | ] 57 | 58 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 59 | BinaryFloat class >> negativeInfinity [ 60 | 61 | ^ MinusInfinity 62 | ] 63 | 64 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 65 | BinaryFloat class >> readFrom: aStringOrStream [ 66 | 67 | ^ aStringOrStream isString 68 | ifTrue: [ self fromString: aStringOrStream ] 69 | ifFalse: [ self fromStream: aStringOrStream ] 70 | ] 71 | 72 | { #category : '*Buoy-Math-GS64-Base-Extensions' } 73 | BinaryFloat class >> zero [ 74 | ^ 0.0 75 | ] 76 | -------------------------------------------------------------------------------- /source/Buoy-Comparison/PropertyBasedEqualityChecker.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a checker that can be configured to check for certain properties to determine object equality. 3 | I'm the default checker available to any object by sending equalityChecker to itself. 4 | " 5 | Class { 6 | #name : 'PropertyBasedEqualityChecker', 7 | #superclass : 'EqualityChecker', 8 | #instVars : [ 9 | 'base', 10 | 'comparisonRules' 11 | ], 12 | #category : 'Buoy-Comparison', 13 | #package : 'Buoy-Comparison' 14 | } 15 | 16 | { #category : 'instance creation' } 17 | PropertyBasedEqualityChecker class >> on: aBaseObject [ 18 | 19 | ^ self on: aBaseObject checkingTypeUsing: [ :base :target | target isA: base class ] 20 | ] 21 | 22 | { #category : 'instance creation' } 23 | PropertyBasedEqualityChecker class >> on: aBaseObject checkingTypeUsing: aTypeCheckingRule [ 24 | 25 | ^ self new initializeOn: aBaseObject checkingTypeUsing: aTypeCheckingRule 26 | ] 27 | 28 | { #category : 'testing' } 29 | PropertyBasedEqualityChecker >> check: aBaseObject against: aTargetObject [ 30 | 31 | ^ ( self is: aBaseObject identicalTo: aTargetObject ) or: [ 32 | comparisonRules allSatisfy: [ :rule | rule value: aBaseObject value: aTargetObject ] ] 33 | ] 34 | 35 | { #category : 'testing' } 36 | PropertyBasedEqualityChecker >> checkAgainst: aTargetObject [ 37 | 38 | ^ self check: base against: aTargetObject 39 | ] 40 | 41 | { #category : 'configuring' } 42 | PropertyBasedEqualityChecker >> compare: aPropertyOrMonadycBlock [ 43 | 44 | self 45 | compareWith: 46 | [ :first :second | ( aPropertyOrMonadycBlock value: first ) = ( aPropertyOrMonadycBlock value: second ) ] 47 | ] 48 | 49 | { #category : 'configuring' } 50 | PropertyBasedEqualityChecker >> compareAll: aPropertyCollection [ 51 | 52 | aPropertyCollection do: [ :property | self compare: property ] 53 | ] 54 | 55 | { #category : 'configuring' } 56 | PropertyBasedEqualityChecker >> compareWith: aDyadicBlock [ 57 | 58 | comparisonRules add: aDyadicBlock 59 | ] 60 | 61 | { #category : 'initialization' } 62 | PropertyBasedEqualityChecker >> initialize [ 63 | 64 | super initialize. 65 | comparisonRules := OrderedCollection new 66 | ] 67 | 68 | { #category : 'initialization' } 69 | PropertyBasedEqualityChecker >> initializeOn: aBaseObject checkingTypeUsing: aTypeCheckingRule [ 70 | 71 | base := aBaseObject. 72 | self compareWith: aTypeCheckingRule 73 | ] 74 | -------------------------------------------------------------------------------- /source/Buoy-Assertions-Tests/AssertionCheckerTest.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a test case for Assertion Checker 3 | " 4 | Class { 5 | #name : 'AssertionCheckerTest', 6 | #superclass : 'TestCase', 7 | #category : 'Buoy-Assertions-Tests', 8 | #package : 'Buoy-Assertions-Tests' 9 | } 10 | 11 | { #category : 'tests' } 12 | AssertionCheckerTest >> testEnforceOneFactFailing [ 13 | 14 | | explanation | 15 | 16 | explanation := 'A false statement'. 17 | self should: [ AssertionChecker enforce: [ false ] because: explanation ] raise: AssertionFailed withMessageText: explanation 18 | ] 19 | 20 | { #category : 'tests' } 21 | AssertionCheckerTest >> testEnforceOneFactFailingRaisingError [ 22 | 23 | | explanation | 24 | 25 | explanation := 'A false statement'. 26 | "For single fact checking any exception can be configured to be raised, but it's not the case when using multiple fact checking" 27 | self should: [ AssertionChecker enforce: [ false ] because: explanation raising: Error ] raise: Error withMessageText: explanation 28 | ] 29 | 30 | { #category : 'tests' } 31 | AssertionCheckerTest >> testEnforceOneFactFailingRaisingNonDefaultException [ 32 | 33 | | explanation | 34 | 35 | explanation := 'A false statement'. 36 | 37 | self 38 | should: [ AssertionChecker enforce: [ false ] because: explanation raising: InstanceCreationFailed ] 39 | raise: InstanceCreationFailed 40 | withMessageText: explanation 41 | ] 42 | 43 | { #category : 'tests' } 44 | AssertionCheckerTest >> testEnforceOneFactNotFailing [ 45 | 46 | self 47 | shouldnt: [ AssertionChecker enforce: [ true ] because: [ self fail ] ] raise: AssertionFailed; 48 | shouldnt: [ AssertionChecker enforce: [ true ] because: [ self fail ] raising: InstanceCreationFailed ] raise: InstanceCreationFailed 49 | ] 50 | 51 | { #category : 'tests' } 52 | AssertionCheckerTest >> testRefuseOneFactFailing [ 53 | 54 | | explanation | 55 | 56 | explanation := 'A false statement'. 57 | self should: [ AssertionChecker refuse: [ true ] because: explanation ] raise: AssertionFailed withMessageText: explanation 58 | ] 59 | 60 | { #category : 'tests' } 61 | AssertionCheckerTest >> testRefuseOneFactNotFailing [ 62 | 63 | self 64 | shouldnt: [ AssertionChecker refuse: [ false ] because: [ self fail ] ] raise: AssertionFailed; 65 | shouldnt: [ AssertionChecker refuse: [ false ] because: [ self fail ] raising: InstanceCreationFailed ] raise: InstanceCreationFailed 66 | ] 67 | --------------------------------------------------------------------------------