{"id":13772037,"url":"https://github.com/Ducasse/Chrysal","last_synced_at":"2025-05-11T04:31:07.211Z","repository":{"id":147865968,"uuid":"120994265","full_name":"Ducasse/Chrysal","owner":"Ducasse","description":"To manage application configurations","archived":false,"fork":false,"pushed_at":"2022-09-25T20:22:29.000Z","size":140,"stargazers_count":7,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-02T09:04:13.542Z","etag":null,"topics":["configuration-management","configurations","pharo"],"latest_commit_sha":null,"homepage":"","language":"Smalltalk","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ducasse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-02-10T07:22:30.000Z","updated_at":"2025-02-08T20:27:41.000Z","dependencies_parsed_at":"2023-06-18T22:31:30.057Z","dependency_job_id":null,"html_url":"https://github.com/Ducasse/Chrysal","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ducasse%2FChrysal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ducasse%2FChrysal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ducasse%2FChrysal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ducasse%2FChrysal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ducasse","download_url":"https://codeload.github.com/Ducasse/Chrysal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253518941,"owners_count":21921074,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration-management","configurations","pharo"],"created_at":"2024-08-03T17:00:59.107Z","updated_at":"2025-05-11T04:31:06.285Z","avatar_url":"https://github.com/Ducasse.png","language":"Smalltalk","funding_links":[],"categories":["Projects management"],"sub_categories":[],"readme":"# Chrysal\n\n\n![https://github.com/Ducasse/Chrysal/workflows/currentStablePharo/badge.svg](https://github.com/Ducasse/Chrysal/workflows/currentStablePharo/badge.svg)\n![https://github.com/Ducasse/Chrysal/workflows/matrix/badge.svg](https://github.com/Ducasse/Chrysal/workflows/matrix/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github//Ducasse/Chrysal/badge.svg?branch=master)](https://coveralls.io/github//Ducasse/Containers-Grid?branch=master)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)]()\n\u003c!-- [![Build status](https://ci.appveyor.com/api/projects/status/1wdnjvmlxfbml8qo?svg=true)](https://ci.appveyor.com/project/olekscode/dataframe)  --\u003e\n\n\n\nChrysal is a library to express and manage external configurations expressed as JSON files. Chrysal is purely static, it means that given a list of items, a reader class is generated that manages the conversion between the two worlds (what the end-users is declaring and what the application needs). At run time a generated Chrysal configuration can be a subclass of a domain class, subclass of \nChrysalConfiguration. This way we can define behavior that will not be lost during the recompilation of the Chrysal configuration (the one based on the actual description).\n\n* Chrysal creates at compile-time a reader that is responsible for mapping end-user expressed configurations to their internal representations (for example a 'a/b/c.html' into a file reference object). \n* In addition at run time a configuration object can customize the default behavior of the generated reader. \n* Finally the configuration developer can extend Chrysal to support new data. \n\n\n\n## Example of configuration\n\nHere is an example of a configuration. This configuration is the one of a pillar project. The end user specifies different values for given entry. \n\n```\n{\n  \"base_url\": \"/booklet-ReflectiveCore/html\",\n  \"site_name\": \"Pharo Book\",\n  \"title\":\"A simple reflective object kernel\",\n  \"attribution\":\"Stéphane Ducasse\",\n  \"series\": \"The Pharo TextBook Collection\",\n  \"keywords\": \"project template, Pillar, Pharo, Smalltalk\",\n  \"language\": \"en-UK\",\n  \"epub-id\": \"urn:uuid:A1B0D67E-2E81-4DF5-9E67-A64CBE366809\",\n  \"tocFile\": \"index.pillar\",\n  \"latexWriter\" : #'latex:sbabook',\n  \"newLine\": #unix,\n  \"htmlWriter\": #html\n}\n```\n## Example of configuration element\n\nChrysal supports the conversion of elements (file, new lines, custom domain specific,..) entities from a textual format to Pharo object. \nIt supports composite and list of items too. Item descriptions are subclasses of `ChrysalItem`. \n\nFor example the `NewLineConfigurationItem` manages how the word `#unix` will be converted into the correct platform specific encoding. \nThis logic is defined in the class `NewLineConfigurationItem`.\n\n```\nChrysalItem subclass: #NewLineConfigurationItem\n\tinstanceVariableNames: 'defaultDomainObject defaultKey'\n\tclassVariableNames: ''\n\tpackage: 'Chrysal-Model'\n```\n\n\n## Example of configuration description\n\nThe developer of a specific configuration will assemble together a list of configuration item. This is this list that will describe how the actual configuration will be managed. This list will be interpreted and eaten by a reader builder to generate a specific reader. \n\nHere is typical configuration description. \n```\nitemDescriptionForXX\n\t\"just a simple description of items for the tests\"\n\t\n\t^ {(StringConfigurationItem new\n\t\tpropertyName: #title;\n\t\tdefault: 'my super cool book';\n\t\tyourself).\n\t(NumberConfigurationItem new\n\t\tpropertyName: #headingLevelOffset;\n\t\tdefault: 0;\n\t\tyourself).\n\t(BooleanConfigurationItem new\n\t\tpropertyName: #verbose;\n\t\tbeTrueAsDefault;\n\t\tyourself).\n\t(FolderConfigurationItem new\n\t\tpropertyName: #outputDirectory;\n\t\tdefault: 'build').\n\t(FileConfigurationItem new\n\t\tpropertyName: #mainDocument;\n\t\tdefault: 'book').\n\t(FileConfigurationItem new\n\t\tpropertyName: #latexTemplate;\n\t\tdefault: '_support/templates/main.latex.mustache').\n\t(FileConfigurationItem new\n\t\tpropertyName: #latexChapterTemplate;\n\t\tdefault: '_support/templates/chapter.latex.mustache').\n\t(FileConfigurationItem new\n\t\tpropertyName: #htmlTemplate;\n\t\tdefault: '_support/templates/html.mustache').\n\t(FileConfigurationItem new\n\t\tpropertyName: #htmlChapterTemplate;\n\t\tdefault: '_support/templates/html.mustache').\n\t(NewLineConfigurationItem new\n\t\tpropertyName: #newLine;\n\t\tdefaultIsUnix).\n\t(SymbolConfigurationItem new\n\t\tpropertyName: #latexWriter;\n\t\tdefault: #latex:sbabook;\n\t\tyourself)\t\"may be we should turn it into a Pillar specific item that convert to a specific class\".\n\t(CompositeConfigurationItem new\n\t\tpropertyName: #printerComposite;\n\t\tdefault: #ChrysalCompositeDomain;\n\t\tfields: #(level renderAs capitalization numbering headerSize);\n\t\tyourself).\n\t(CompositeConfigurationItem new\n\t\tpropertyName: #convertedComposite;\n\t\tdefault: #ChrysalConvertedCompositeDomain;\n\t\tfields: #(newLine htmlTemplate title);\n\t\tyourself).\n\t(ListConfigurationItem new\n\t\tpropertyName: #levels;\n\t\tdefault: #OrderedCollection;\n\t\telement: 'printerComposite';\n\t\tyourself).\n\t(PathConfigurationItem new\n\t\tpropertyName: #relativeSimple;\n\t\tdefault: 'simple';\n\t\tyourself).\n\t(PathConfigurationItem new\n\t\tpropertyName: #relativeComplex;\n\t\tdefault: 'simple/simple1';\n\t\tyourself).\n\t(PathConfigurationItem new\n\t\tpropertyName: #absoluteSimple;\n\t\tdefault: '/simple';\n\t\tyourself).\t\n\t(PathConfigurationItem new\n\t\tpropertyName: #absoluteComplex;\n\t\tdefault: '/simple/simple1';\n\t\tyourself)\n\t}\n```\n\n## Configuration Reader Builder\n\nThe configuration builder will consume a configuration description as shown above and produce a configuration reader. \n\nHere is a typical way to invoke the builder. \n\n```\nChrysalConfigurationBuilder new \n\tdefineConfigurationClassNamed: #ConfigurationForXX packagedIn: 'Chrysal-Tests'; \n\twithDescriptionItems: ConfigurationDescriptionForXX itemDescriptionForXX\n```\t\n\nNote that it will generate a class and its associated comments so that we can regenerate it too.\n\n## Example of Extensions\n\nPillar extends the `ChrysalConfiguration` (run time class) to be able to perform extra treatment.\n```\nChrysalConfiguration subclass: #ChrysalPillarishConfiguration\n\tinstanceVariableNames: 'printer'\n\tclassVariableNames: ''\n\tpackage: 'Pillar-Chrysal'\n```\n\n```\nChrysalPillarishConfiguration \u003e\u003e postTreat\n\n\t(self propertyAt: #levels ifAbsent: [^ self ]) do: [ \n\t\t\t:levelSpec |\n\t\t\t| instance |\n\t\t\tinstance := (self printer printerSpecFor: levelSpec renderAs).\n\t\t\tinstance fillFromAnother: levelSpec. \n\t\t\tself printer level: instance n: levelSpec level. \n\t\t\t ]\n```\n\n## About Run time Dependencies\n\nNote that neither the items (subclasses of `ChrysalItem` and `ChrysalItems`), nor the builder will be used at run time. \nThere you can package your description outside of Chrysal. This is why you can also store a description configuration in a textual format. \n\nThe only dependency needed at run time is the `Chrysal-Runtime`. This package is minimalistic and it only contains the class `ChrysalConfiguration` that will be extended by the generated configuration reader produced by the builder. \n\n\n## Adding New Configuration Items\n\nSince a configuration item describes information that will be used to generate code, it acts as a static data (from that perspective it can be perceived as data to be fed to a macro expansion engine). \n\nJSON configurations consider the following as literals and not strings: number true false symbol string. Therefore the conversion is not needed. \nTo extend the item hierarchy, a new class should defines the methods: `defaultDomainValueString` and `domainValueConversionString`.\n\n```\ndefaultDomainValueString\n\t\"Returns a string representing the default value but as an object once imported in Pharo and not a string used by the writer of a configuration.\"\n     ...\n```\n\n```\ndomainValueConversionString\n\t\"Returns a string converting a string as written in the configuration file to a pharo object. \n\tNote that this method is like the body of a macro that will be expanded in the configuration class: here aValue is the name of the parameter of the generated method.\n\t\n\tFor example for fileConfigurationItem (inputFile), \n\tthe result of the method will be used in the body of the following generated method \n\t\n\tconvertInputFile: aValue\n\t      ^ (FileSystem workingDirectory / aValue)\n\t\n\t Parameter of the item like baseline should be accessed via self nameOfProperty\"\n\n\t^ '^ aValue'\n\n```\n\nRead the class, `BooleanConfigurationItem` for a simple case and `NewLineConfigurationItem` for a bit more advanced case. \n\n## Loading\n\n```\nMetacello new\n   baseline: 'Chrysal';\n   repository: 'github://Ducasse/Chrysal';\n   load.\n```\n\n## If you want to depend on it\n\n```\nspec \n   baseline: 'Chrysal' \n   with: [ spec repository: 'github://Ducasse/Chrysal' ].\n```\n\n## Known limits:\n- Path management should be revisited. \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDucasse%2FChrysal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDucasse%2FChrysal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDucasse%2FChrysal/lists"}