diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index eaf91e2..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/tutorial/step_2_business_language/Agile and Dependable Service Development with Bosque and Morphir - LF OSS 2021.pdf b/tutorial/step_2_business_language/Agile and Dependable Service Development with Bosque and Morphir - LF OSS 2021.pdf new file mode 100644 index 0000000..408504e Binary files /dev/null and b/tutorial/step_2_business_language/Agile and Dependable Service Development with Bosque and Morphir - LF OSS 2021.pdf differ diff --git a/tutorial/step_2_business_language/elm.json b/tutorial/step_2_business_language/elm.json new file mode 100644 index 0000000..2ae609a --- /dev/null +++ b/tutorial/step_2_business_language/elm.json @@ -0,0 +1,26 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0", + "elm-explorations/test": "1.2.2" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/random": "1.0.0", + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.2" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} \ No newline at end of file diff --git a/tutorial/step_2_business_language/morphir.json b/tutorial/step_2_business_language/morphir.json new file mode 100644 index 0000000..7e58fb2 --- /dev/null +++ b/tutorial/step_2_business_language/morphir.json @@ -0,0 +1,10 @@ +{ + "name": "Morphir.Example.App", + "sourceDirectory": "src", + "exposedModules": [ + "App", + "Forecast", + "Rentals", + "Winds" + ] +} \ No newline at end of file diff --git a/tutorial/step_2_business_language/readme.md b/tutorial/step_2_business_language/readme.md new file mode 100644 index 0000000..4e6f1b3 --- /dev/null +++ b/tutorial/step_2_business_language/readme.md @@ -0,0 +1,72 @@ +# Morphir Tutorial: First Logic Model + +We'll start out with a very simple example of modeling logic: whether we have enough surfboards to satisfy a rental request. First up, let's create the Elm source file for our code. + +First create the file ```src/Morphir/Examples/App/Rentals.elm```. In linux that's: + +``` +mkdir src/Morphir +mkdir src/Morphir/Examples +mkdir src/Morphir/Examples/App +touch src/Morphir/Examples/App/Rentals.elm +``` + +We need to update ```morphir.json``` to reflect our new module. Edit it to add the ```Morphir.Example.App``` package and the ```Rentals``` module and like this: + +``` +{ + "name": "Morphir.Example.App", + "sourceDirectory": "src", + "exposedModules": [ + "Rentals" + ] +} +``` + +Now edit the ```Rentals.eml``` file. First, we want to reflect the module (aka namespace). Add: + +``` Elm +module Morphir.Example.App.Rentals exposing (..) + + +``` + +That takes care of the boilerplate. Now we can focus on the business logic. We'll put that into a function: + +``` Elm +request : Int -> Int -> Result String Int +request availability requestedQuantity = + if requestedQuantity <= availability then + Ok requestedQuantity + else + Err "Insufficient availability" +``` +This is Elm's way of declaring a function. In this case, the function takes the current availability and the requested amount and returns a Result, which is either the quantity to be rented or an error message. At this point, we might want to play around to test that we got everything covered. We can do this with Morphir's developer tools. On the command line, type: + +``` +morphir-elm make +morphir-elm develop +``` + +Go ahead and click on the http://0.0.0.0:3000 link (note: you can also find an online example at [Insight Sample](https://finos.github.io/morphir-service)). Click on the "Rentals" link. You should see a page like: + + + +We can test out our logic by trying different values and checking the execution paths below: + + + +### Generating code +You might be interested in using this logic in a larger application. One option is to use the base Scala generator to transpile to a Scala library. This would allow you to use it as you would any other Scala library. To generate into the ```dist``` folder default, run: + +``` +morphir-elm gen +``` + +The full source code for the model can be found at [Rentals.elm](src/Morphir/Example/App/Rentals.elm) + +That wraps up our first Morphir model! + + + +[Home](../../readme.md) | [Prev](../../install.md) | [Next](step_2_refined_logic/readme.md) diff --git a/tutorial/step_2_business_language/src/Morphir/Example/App/App.elm b/tutorial/step_2_business_language/src/Morphir/Example/App/App.elm new file mode 100644 index 0000000..4f29c04 --- /dev/null +++ b/tutorial/step_2_business_language/src/Morphir/Example/App/App.elm @@ -0,0 +1,25 @@ +module Morphir.Example.App.App exposing (..) + +import Morphir.Example.App.Forecast exposing (..) +import Morphir.Example.App.Rentals exposing (..) +import Morphir.Example.App.Winds exposing (..) + + +processRequest : Forecast -> CurrentInventory -> ExistingReservations -> PendingReturns -> RequestedQuantity -> AllowPartials -> Result Reason ReservedQuantity +processRequest forecast inventory reservations returns requestedQuantity allowPartials = + let + windCategory : WindCategory + windCategory = + categorizeWindForForecast forecast + in + decide windCategory forecast.shortForcast inventory reservations returns requestedQuantity allowPartials + + +categorizeWindForForecast : Forecast -> WindCategory +categorizeWindForForecast forecast = + let + windCategory : WindCategory + windCategory = + categorizeWind forecast.windSpeed.max + in + windCategory diff --git a/tutorial/step_2_business_language/src/Morphir/Example/App/Forecast.elm b/tutorial/step_2_business_language/src/Morphir/Example/App/Forecast.elm new file mode 100644 index 0000000..3ca48e0 --- /dev/null +++ b/tutorial/step_2_business_language/src/Morphir/Example/App/Forecast.elm @@ -0,0 +1,36 @@ +module Morphir.Example.App.Forecast exposing (..) + + +type alias MPH = + Int + + +type WindDirection + = North + | South + | East + | West + + +type alias Celcius = + Int + + +type ForecastDetail + = Showers + | Thunderstorms + | Snow + | Fog + + +type alias ForecastPercent = + Float + + +type alias Forecast = + { temp : { low : Celcius, high : Celcius } + , windSpeed : { min : MPH, max : MPH } + , windDirection : WindDirection + , shortForcast : ForecastDetail + , forecastPercent : ForecastPercent + } diff --git a/tutorial/step_2_business_language/src/Morphir/Example/App/Rentals.elm b/tutorial/step_2_business_language/src/Morphir/Example/App/Rentals.elm new file mode 100644 index 0000000..bbcc17a --- /dev/null +++ b/tutorial/step_2_business_language/src/Morphir/Example/App/Rentals.elm @@ -0,0 +1,75 @@ +module Morphir.Example.App.Rentals exposing (..) + +import Morphir.Example.App.Forecast exposing (..) +import Morphir.Example.App.Winds exposing (..) + + +type alias CurrentInventory = + Int + + +type alias ExistingReservations = + Int + + +type alias PendingReturns = + Int + + +type alias RequestedQuantity = + Int + + +type alias ReservedQuantity = + Int + + +type alias Availability = + Int + + +type alias AllowPartials = + Bool + + +type Reason + = InsufficientAvailability + | ClosedDueToConditions + + +type ExpertiseLevel + = Novice + | Intermediate + | Expert + + +decide : WindCategory -> ForecastDetail -> CurrentInventory -> ExistingReservations -> PendingReturns -> RequestedQuantity -> AllowPartials -> Result Reason ReservedQuantity +decide windCategory forecastDetail inventory reservations returns requestedQuantity allowPartials = + let + isClosed : Bool + isClosed = + case ( windCategory, forecastDetail ) of + ( DangerousWinds, _ ) -> + True + + ( _, Thunderstorms ) -> + True + + _ -> + False + + availability : Availability + availability = + inventory - reservations + returns + in + if isClosed then + Err ClosedDueToConditions + + else if requestedQuantity <= availability then + Ok requestedQuantity + + else if allowPartials then + Ok availability + + else + Err InsufficientAvailability diff --git a/tutorial/step_2_business_language/src/Morphir/Example/App/Winds.elm b/tutorial/step_2_business_language/src/Morphir/Example/App/Winds.elm new file mode 100644 index 0000000..a9330e3 --- /dev/null +++ b/tutorial/step_2_business_language/src/Morphir/Example/App/Winds.elm @@ -0,0 +1,25 @@ +module Morphir.Example.App.Winds exposing (..) + +import Morphir.Example.App.Forecast exposing (..) + + +type WindCategory + = Calm + | Windy + | HighWinds + | DangerousWinds + + +categorizeWind : Int -> WindCategory +categorizeWind windSpeed = + if windSpeed < 10 then + Calm + + else if windSpeed < 20 then + HighWinds + + else if windSpeed < 30 then + Windy + + else + DangerousWinds