Fix intro/part9

This commit is contained in:
Richard Feldman
2018-08-15 17:37:42 -05:00
parent 0efe239ae4
commit bb38d331b4

View File

@@ -40,7 +40,7 @@ import Html.Attributes exposing (class)
import Html.Events exposing (stopPropagationOn) import Html.Events exposing (stopPropagationOn)
import Http import Http
import HttpBuilder exposing (RequestBuilder, withBody, withExpect, withQueryParams) import HttpBuilder exposing (RequestBuilder, withBody, withExpect, withQueryParams)
import Json.Decode as Decode exposing (Decoder, bool, int, list, string) import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (custom, hardcoded, required) import Json.Decode.Pipeline exposing (custom, hardcoded, required)
import Json.Encode as Encode import Json.Encode as Encode
import Markdown import Markdown
@@ -83,6 +83,47 @@ type Article a
= Article Internals a = Article Internals a
{-| Metadata about the article - its title, description, and so on.
Importantly, this module's public API exposes a way to read this metadata, but
not to alter it. This is read-only information!
If we find ourselves using any particular piece of metadata often,
for example `title`, we could expose a convenience function like this:
Article.title : Article a -> String
If you like, it's totally reasonable to expose a function like that for every one
of these fields!
(Okay, to be completely honest, exposing one function per field is how I prefer
to do it, and that's how I originally wrote this module. However, I'm aware that
this code base has become a common reference point for beginners, and I think it
is _extremely important_ that slapping some "getters and setters" on a record
does not become a habit for anyone who is getting started with Elm. The whole
point of making the Article type opaque is to create guarantees through
_selectively choosing boundaries_ around it. If you aren't selective about
where those boundaries are, and instead expose a "getter and setter" for every
field in the record, the result is an API with no more guarantees than if you'd
exposed the entire record directly! It is so important to me that beginners not
fall into the terrible "getters and setters" trap that I've exposed this
Metadata record instead of exposing a single function for each of its fields,
as I did originally. This record is not a bad way to do it, by any means,
but if this seems at odds with <https://youtu.be/x1FU3e0sT1I> - now you know why!
See commit c2640ae3abd60262cdaafe6adee3f41d84cd85c3 for how it looked before.
)
-}
type alias Metadata =
{ description : String
, title : String
, tags : List String
, createdAt : Time.Posix
, favorited : Bool
, favoritesCount : Int
}
type alias Internals = type alias Internals =
{ slug : Slug { slug : Slug
, author : Author , author : Author
@@ -170,39 +211,15 @@ internalsDecoder maybeCred =
|> custom metadataDecoder |> custom metadataDecoder
type alias Metadata =
{ description : String
, title : String
, tags : List String
, favorited : Bool
, favoritesCount : Int
, createdAt : Time.Posix
}
metadataDecoder : Decoder Metadata metadataDecoder : Decoder Metadata
metadataDecoder = metadataDecoder =
{- 👉 TODO: replace the calls to `hardcoded` with calls to `required`
in order to decode these fields:
--- "description" -------> description : String
--- "title" -------------> title : String
--- "tagList" -----------> tags : List String
--- "favorited" ---------> favorited : Bool
--- "favoritesCount" ----> favoritesCount : Int
Once this is done, the articles in the feed should look normal again.
💡 HINT: Order matters! These must be decoded in the same order
as the order of the fields in `type alias Metadata` above.
-}
Decode.succeed Metadata Decode.succeed Metadata
|> hardcoded "(needs decoding!)" |> required "description" (Decode.map (Maybe.withDefault "") (Decode.nullable Decode.string))
|> hardcoded "(needs decoding!)" |> required "title" Decode.string
|> hardcoded [] |> required "tagList" (Decode.list Decode.string)
|> hardcoded False
|> hardcoded 0
|> required "createdAt" Timestamp.iso8601Decoder |> required "createdAt" Timestamp.iso8601Decoder
|> required "favorited" Decode.bool
|> required "favoritesCount" Decode.int