๐Ÿ“ฆ sleepyfran / duets

๐Ÿ“„ Item.fs ยท 96 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96module Duets.Entities.Item

open Microsoft.FSharp.Reflection

module Property =
    /// Attempts to retrieve the main property of the given item, if any.
    let tryMain item = item.Properties |> List.tryHead

    /// Attempts to pick a property from the given item.
    let tryPick fn item = item.Properties |> List.tryPick fn

    /// Checks if the given item has a property that satisfies the given function.
    let has fn item = item.Properties |> List.exists fn

    /// Removes the current given property from the item and re-adds the updated
    /// one, returning the updated item. The matching of the property is done
    /// against the name of the case via reflection, so it'd match even if
    /// the values inside the property are different.
    let update property item =
        let updatedPropertyInfo, _ =
            FSharpValue.GetUnionFields(property, property.GetType())

        item.Properties
        |> List.filter (fun currentProperty ->
            let currentPropertyInfo, _ =
                FSharpValue.GetUnionFields(
                    currentProperty,
                    currentProperty.GetType()
                )

            currentPropertyInfo.Name <> updatedPropertyInfo.Name)
        |> (@) [ property ]

/// Updates the given item by removing the current property that matches
/// the given one, and re-adds the updated property returning the updated item.
let updateProperty property item =
    let updatedProperties = Property.update property item

    { item with
        Properties = updatedProperties }

module Beer =
    /// Creates a beer item.
    let create brand amount alcoholContent =
        { Brand = brand
          Name = "beer"
          Properties =
            [ Drinkable(
                  { Amount = amount
                    DrinkType = Beer(alcoholContent) }
              ) ] }

module Key =
    /// Creates a chip to access a place in a city.
    let createGymChipFor cityId placeId =
        { Brand = "DuetsCorp"
          Name = "Chip"
          Properties = [ TemporaryChip(cityId, placeId) |> Key ] }

    /// Creates an entrance card to access a place in a city.
    let createEntranceCardFor cityId placeId =
        { Brand = "DuetsCorp"
          Name = "EntranceCard"
          Properties = [ EntranceCard(cityId, placeId) |> Key ] }

module Coffee =
    /// Creates a coffee item.
    let create name amount caffeineAmount =
        { Brand = "DuetsBeans"
          Name = name
          Properties =
            [ Drinkable(
                  { Amount = amount
                    DrinkType = Coffee(caffeineAmount) }
              ) ] }

module Food =
    /// Creates a food item.
    let create name amount foodType cookingSkillRequired =
        { Brand = "DuetsFoods"
          Name = name
          Properties =
            [ Edible(
                  { Amount = amount
                    FoodType = foodType
                    CookingSkillRequired = cookingSkillRequired }
              )
              PlaceableInStorage(Fridge) ] }

module Soda =
    /// Creates a soda item.
    let create brand amount =
        { Brand = brand
          Name = brand
          Properties = [ Drinkable({ Amount = amount; DrinkType = Soda }) ] }