diff --git a/Main.elm b/Main.elm index 5233427..4f13ae8 100644 --- a/Main.elm +++ b/Main.elm @@ -10,7 +10,7 @@ import Html.App import Auth import Http import Task exposing (Task) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) main : Program Never diff --git a/README.md b/README.md index ddb09e7..4980490 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Getting Started 1. Install [Node.js](http://nodejs.org) 4.0.0 or higher -2. Add an [editor plugin](http://elm-lang.org/install#syntax-highlighting) for your editor of choice. +2. Add a plugin for your editor of choice: [Atom](https://atom.io/packages/language-elm), [Sublime Text](https://packagecontrol.io/packages/Elm%20Language%20Support), [VS Code](https://github.com/sbrink/vscode-elm), [Light Table](https://github.com/rundis/elm-light), [Vim](https://github.com/lambdatoast/elm.vim), [Emacs](https://github.com/jcollard/elm-mode), [Brackets](https://github.com/lepinay/elm-brackets) 3. Not required, but **highly** recommended: [install elm-format](https://github.com/avh4/elm-format#installation-) and integrate it into your editor so that it runs on save. diff --git a/part1/Main.elm b/part1/Main.elm index 43afced..1511f7b 100644 --- a/part1/Main.elm +++ b/part1/Main.elm @@ -16,7 +16,7 @@ model = view model = div [ class "content" ] [ header [] - [ -- TODO add the equivalent of

ElmHub

right before the tagline + [ -- TODO add the equivalent of

ElmHub

right before this span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] ] , ul [ class "results" ] diff --git a/part1/README.md b/part1/README.md index 114a212..515f5bb 100644 --- a/part1/README.md +++ b/part1/README.md @@ -4,19 +4,19 @@ Part 1 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## References * [html-to-elm](http://mbylstra.github.io/html-to-elm/) - paste in HTML, get elm-html code * [elm-html documentation](http://package.elm-lang.org/packages/evancz/elm-html/4.0.2/) -* [record syntax](http://elm-lang.org/docs/syntax#records) (e.g. `{ foo = 1, bar = 2`) +* [record syntax](http://elm-lang.org/docs/syntax#records) (e.g. `{ foo = 1, bar = 2 }`) diff --git a/part10/ElmHub.elm b/part10/ElmHub.elm index 1af4bc5..c7939bd 100644 --- a/part10/ElmHub.elm +++ b/part10/ElmHub.elm @@ -1,119 +1,100 @@ -module ElmHub (..) where +module ElmHub exposing (..) import Html exposing (..) -import Html.Attributes exposing (class, target, href, property) +import Html.Attributes exposing (class, target, href, property, defaultValue) import Html.Events exposing (..) -import Html.Lazy exposing (..) import Http import Auth import Task exposing (Task) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) -import Json.Encode -import Signal exposing (Address) +import Json.Decode exposing (Decoder) import Dict exposing (Dict) import SearchResult -searchFeed : String -> Task x Action +searchFeed : String -> Cmd Msg searchFeed query = - let - -- See https://developer.github.com/v3/search/#example for how to customize! - url = - "https://api.github.com/search/repositories?access_token=" - ++ Auth.token - ++ "&q=" - ++ query - ++ "+language:elm&sort=stars&order=desc" - - task = - Http.get responseDecoder url - |> Task.map SetResults - in - Task.onError task (\_ -> Task.succeed (SetResults [])) + let + url = + "https://api.github.com/search/repositories?access_token=" + ++ Auth.token + ++ "&q=" + ++ query + ++ "+language:elm&sort=stars&order=desc" + in + Task.perform HandleSearchError HandleSearchResponse (Http.get responseDecoder url) responseDecoder : Decoder (List SearchResult.Model) responseDecoder = - -- TODO make use of SearchResult's decoder - Json.Decode.succeed [] + -- TODO make use of SearchResult's decoder + Json.Decode.succeed [] type alias Model = - { query : String - , results : Dict SearchResult.ResultId SearchResult.Model - } + { query : String + , results : Dict SearchResult.ResultId SearchResult.Model + } initialModel : Model initialModel = - { query = "tutorial" - , results = Dict.empty - } + { query = "tutorial" + , results = Dict.empty + } -view : Address Action -> Model -> Html -view address model = - div - [ class "content" ] - [ header - [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] +view : Model -> Html Msg +view model = + div [ class "content" ] + [ header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + , input [ class "search-query", onInput SetQuery, defaultValue model.query ] [] + , button [ class "search-button", onClick Search ] [ text "Search" ] + , ul [ class "results" ] (viewSearchResults model.results) ] - , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] - , button [ class "search-button", onClick address Search ] [ text "Search" ] - , ul - [ class "results" ] - (viewSearchResults address model.results) - ] -viewSearchResults : Address Action -> Dict SearchResult.ResultId SearchResult.Model -> List Html -viewSearchResults address results = - results - |> Dict.values - |> List.sortBy (.stars >> negate) - |> List.map (\_ -> div [] [ text "TODO replace this line with view logic from SearchResult" ]) +viewSearchResults : Dict SearchResult.ResultId SearchResult.Model -> List (Html a) +viewSearchResults results = + results + |> Dict.values + |> List.sortBy (.stars >> negate) + |> List.map (\_ -> div [] [ text "TODO replace this line with view logic from SearchResult" ]) -onInput address wrap = - on "input" targetValue (\val -> Signal.message address (wrap val)) +type Msg + = Search + | SetQuery String + | DeleteById SearchResult.ResultId + | SetResults (List SearchResult.Model) + | HandleSearchResponse (List SearchResult.Model) + | HandleSearchError Http.Error -defaultValue str = - property "defaultValue" (Json.Encode.string str) +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + Search -> + ( model, searchFeed model.query ) + SetQuery query -> + ( { model | query = query }, Cmd.none ) -type Action - = Search - | SetQuery String - | DeleteById SearchResult.ResultId - | SetResults (List SearchResult.Model) + SetResults results -> + let + resultsById : Dict SearchResult.ResultId SearchResult.Model + resultsById = + results + |> List.map (\result -> ( result.id, result )) + |> Dict.fromList + in + ( { model | results = resultsById }, Cmd.none ) - -update : Action -> Model -> ( Model, Effects Action ) -update action model = - case action of - Search -> - ( model, Effects.task (searchFeed model.query) ) - - SetQuery query -> - ( { model | query = query }, Effects.none ) - - SetResults results -> - let - resultsById : Dict SearchResult.ResultId SearchResult.Model - resultsById = - results - |> List.map (\result -> ( result.id, result )) - |> Dict.fromList - in - ( { model | results = resultsById }, Effects.none ) - - DeleteById id -> - let - newModel = - { model | results = Dict.remove id model.results } - in - ( newModel, Effects.none ) + DeleteById id -> + let + newModel = + { model | results = Dict.remove id model.results } + in + ( newModel, Cmd.none ) diff --git a/part10/Main.elm b/part10/Main.elm index fa4bada..c60133a 100644 --- a/part10/Main.elm +++ b/part10/Main.elm @@ -1,27 +1,13 @@ -module Main (..) where +module Main exposing (..) -import StartApp import ElmHub exposing (..) -import Effects exposing (Effects) -import Task exposing (Task) -import Html exposing (Html) -main : Signal Html +main : Program Never main = - app.html - - -app : StartApp.App Model -app = - StartApp.start - { view = view - , update = update - , init = ( initialModel, Effects.task (searchFeed initialModel.query) ) - , inputs = [] - } - - -port tasks : Signal (Task Effects.Never ()) -port tasks = - app.tasks + Html.App.program + { view = view + , update = update + , init = ( initialModel, searchFeed initialModel.query ) + , inputs = [] + } diff --git a/part10/README.md b/part10/README.md index 50a317c..b7be40c 100644 --- a/part10/README.md +++ b/part10/README.md @@ -4,14 +4,14 @@ Part 10 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` diff --git a/part10/SearchResult.elm b/part10/SearchResult.elm index 758566a..47ef0c5 100644 --- a/part10/SearchResult.elm +++ b/part10/SearchResult.elm @@ -1,45 +1,41 @@ -module SearchResult (..) where +module SearchResult exposing (..) import Html exposing (..) -import Html.Attributes exposing (class, target, href, property) -import Html.Events exposing (..) -import Json.Decode exposing (Decoder, (:=)) +import Html.Attributes exposing (class, target, href, property, defaultValue) +import Json.Decode exposing (Decoder) import Json.Decode.Pipeline exposing (..) -import Signal exposing (Address) -import Dict exposing (Dict) type alias ResultId = - Int + Int type alias Model = - { id : ResultId - , name : String - , stars : Int - } + { id : ResultId + , name : String + , stars : Int + } decoder : Decoder Model decoder = - decode Model - |> required "id" Json.Decode.int - |> required "full_name" Json.Decode.string - |> required "stargazers_count" Json.Decode.int + decode Model + |> required "id" Json.Decode.int + |> required "full_name" Json.Decode.string + |> required "stargazers_count" Json.Decode.int -view : Address a -> Model -> Html -view address result = - li - [] - [ span [ class "star-count" ] [ text (toString result.stars) ] - , a - [ href ("https://github.com/" ++ result.name) - , target "_blank" +view : Model -> Html a +view result = + li [] + [ span [ class "star-count" ] [ text (toString result.stars) ] + , a + [ href ("https://github.com/" ++ result.name) + , target "_blank" + ] + [ text result.name ] + , button + -- TODO onClick, send a delete action to the address + [ class "hide-result" ] + [ text "X" ] ] - [ text result.name ] - , button - -- TODO onClick, send a delete action to the address - [ class "hide-result" ] - [ text "X" ] - ] diff --git a/part10/elm-package.json b/part10/elm-package.json index f4a6d00..bd2a209 100644 --- a/part10/elm-package.json +++ b/part10/elm-package.json @@ -10,11 +10,9 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" -} \ No newline at end of file + "elm-version": "0.17.0 <= v < 0.18.0" +} diff --git a/part10/test/elm-package.json b/part10/test/elm-package.json index a440485..bd2a209 100644 --- a/part10/test/elm-package.json +++ b/part10/test/elm-package.json @@ -9,13 +9,10 @@ ], "exposed-modules": [], "dependencies": { - "deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0", - "laszlopandy/elm-console": "1.0.3 <= v < 2.0.0" + "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part11/ElmHub.elm b/part11/ElmHub.elm index 38aead5..d6f42c3 100644 --- a/part11/ElmHub.elm +++ b/part11/ElmHub.elm @@ -1,4 +1,4 @@ -module ElmHub (..) where +module ElmHub exposing (..) import Html exposing (..) import Html.Attributes exposing (..) @@ -6,120 +6,101 @@ import Html.Events exposing (..) import Http import Auth import Task exposing (Task) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Encode -import Signal exposing (Address) import Dict exposing (Dict) import SearchResult -searchFeed : String -> Task x Action +searchFeed : String -> Cmd Msg searchFeed query = - let - -- See https://developer.github.com/v3/search/#example for how to customize! - url = - "https://api.github.com/search/repositories?access_token=" - ++ Auth.token - ++ "&q=" - ++ query - ++ "+language:elm&sort=stars&order=desc" - - task = - Http.get responseDecoder url - |> Task.map SetResults - in - Task.onError task (\_ -> Task.succeed (SetResults [])) + let + url = + "https://api.github.com/search/repositories?access_token=" + ++ Auth.token + ++ "&q=" + ++ query + ++ "+language:elm&sort=stars&order=desc" + in + Task.perform HandleSearchError HandleSearchResponse (Http.get responseDecoder url) responseDecoder : Decoder (List SearchResult.Model) responseDecoder = - "items" := Json.Decode.list SearchResult.decoder + "items" := Json.Decode.list SearchResult.decoder type alias Model = - { query : String - , results : Dict SearchResult.ResultId SearchResult.Model - } + { query : String + , results : Dict SearchResult.ResultId SearchResult.Model + } initialModel : Model initialModel = - { query = "tutorial" - , results = Dict.empty - } + { query = "tutorial" + , results = Dict.empty + } -view : Address Action -> Model -> Html -view address model = - div - [ class "content" ] - [ header - [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] +view : Model -> Html Msg +view model = + div [ class "content" ] + [ header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + , input [ class "search-query", onInput SetQuery, defaultValue model.query ] [] + , button [ class "search-button", onClick Search ] [ text "Search" ] + , ul [ class "results" ] (viewSearchResults model.results) ] - , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] - , button [ class "search-button", onClick address Search ] [ text "Search" ] - , ul - [ class "results" ] - (viewSearchResults address model.results) - ] -viewSearchResults : Address Action -> Dict SearchResult.ResultId SearchResult.Model -> List Html -viewSearchResults address results = - results - |> Dict.values - |> List.sortBy (.stars >> negate) - |> filterResults - |> List.map (SearchResult.view address DeleteById) +viewSearchResults : Dict SearchResult.ResultId SearchResult.Model -> List (Html a) +viewSearchResults results = + results + |> Dict.values + |> List.sortBy (.stars >> negate) + |> filterResults + |> List.map (SearchResult.view address DeleteById) filterResults : List SearchResult.Model -> List SearchResult.Model filterResults results = - -- TODO filter out repos with 0 stars - -- using a case-expression rather than List.filter - results + -- TODO filter out repos with 0 stars + -- using a case-expression rather than List.filter + results -onInput address wrap = - on "input" targetValue (\val -> Signal.message address (wrap val)) +type Msg + = Search + | SetQuery String + | DeleteById SearchResult.ResultId + | SetResults (List SearchResult.Model) -defaultValue str = - property "defaultValue" (Json.Encode.string str) +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + Search -> + ( model, searchFeed model.query ) + SetQuery query -> + ( { model | query = query }, Cmd.none ) -type Action - = Search - | SetQuery String - | DeleteById SearchResult.ResultId - | SetResults (List SearchResult.Model) + SetResults results -> + let + resultsById : Dict SearchResult.ResultId SearchResult.Model + resultsById = + results + |> List.map (\result -> ( result.id, result )) + |> Dict.fromList + in + ( { model | results = resultsById }, Cmd.none ) - -update : Action -> Model -> ( Model, Effects Action ) -update action model = - case action of - Search -> - ( model, Effects.task (searchFeed model.query) ) - - SetQuery query -> - ( { model | query = query }, Effects.none ) - - SetResults results -> - let - resultsById : Dict SearchResult.ResultId SearchResult.Model - resultsById = - results - |> List.map (\result -> ( result.id, result )) - |> Dict.fromList - in - ( { model | results = resultsById }, Effects.none ) - - DeleteById id -> - let - newModel = - { model | results = Dict.remove id model.results } - in - ( newModel, Effects.none ) + DeleteById id -> + let + newModel = + { model | results = Dict.remove id model.results } + in + ( newModel, Cmd.none ) diff --git a/part11/Main.elm b/part11/Main.elm index fa4bada..c60133a 100644 --- a/part11/Main.elm +++ b/part11/Main.elm @@ -1,27 +1,13 @@ -module Main (..) where +module Main exposing (..) -import StartApp import ElmHub exposing (..) -import Effects exposing (Effects) -import Task exposing (Task) -import Html exposing (Html) -main : Signal Html +main : Program Never main = - app.html - - -app : StartApp.App Model -app = - StartApp.start - { view = view - , update = update - , init = ( initialModel, Effects.task (searchFeed initialModel.query) ) - , inputs = [] - } - - -port tasks : Signal (Task Effects.Never ()) -port tasks = - app.tasks + Html.App.program + { view = view + , update = update + , init = ( initialModel, searchFeed initialModel.query ) + , inputs = [] + } diff --git a/part11/README.md b/part11/README.md index 3c33eb9..830bc2e 100644 --- a/part11/README.md +++ b/part11/README.md @@ -4,14 +4,14 @@ Part 11 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` diff --git a/part11/SearchResult.elm b/part11/SearchResult.elm index 95a843c..f36b29d 100644 --- a/part11/SearchResult.elm +++ b/part11/SearchResult.elm @@ -1,50 +1,45 @@ -module SearchResult (..) where +module SearchResult exposing (..) import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) -import Json.Decode exposing (Decoder, (:=)) -import Signal exposing (Address) +import Json.Decode exposing (Decoder) import Dict exposing (Dict) type alias ResultId = - Int + Int type alias Model = - { id : ResultId - , name : String - , stars : Int - } + { id : ResultId + , name : String + , stars : Int + } decoder : Decoder Model decoder = - Json.Decode.object3 - Model - ("id" := Json.Decode.int) - ("full_name" := Json.Decode.string) - ("stargazers_count" := Json.Decode.int) + Json.Decode.object3 Model + ("id" := Json.Decode.int) + ("full_name" := Json.Decode.string) + ("stargazers_count" := Json.Decode.int) view : Address a -> (Int -> a) -> Model -> Html view address delete result = - li - [] - [ span [ class "star-count" ] [ text (toString result.stars) ] - , a - [ href - ("https://github.com/" - ++ (Debug.log - "TODO we should not see this when typing in the search box!" - result.name - ) - ) - , target "_blank" + li [] + [ span [ class "star-count" ] [ text (toString result.stars) ] + , a + [ href + ("https://github.com/" + ++ (Debug.log "TODO we should not see this when typing in the search box!" + result.name + ) + ) + , target "_blank" + ] + [ text result.name ] + , button [ class "hide-result", onClick (delete result.id) ] + [ text "X" ] ] - [ text result.name ] - , button - [ class "hide-result", onClick address (delete result.id) ] - [ text "X" ] - ] diff --git a/part11/elm-package.json b/part11/elm-package.json index f4a6d00..bd2a209 100644 --- a/part11/elm-package.json +++ b/part11/elm-package.json @@ -10,11 +10,9 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" -} \ No newline at end of file + "elm-version": "0.17.0 <= v < 0.18.0" +} diff --git a/part11/test/elm-package.json b/part11/test/elm-package.json index a440485..bd2a209 100644 --- a/part11/test/elm-package.json +++ b/part11/test/elm-package.json @@ -9,13 +9,10 @@ ], "exposed-modules": [], "dependencies": { - "deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0", - "laszlopandy/elm-console": "1.0.3 <= v < 2.0.0" + "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part12/ElmHub.elm b/part12/ElmHub.elm index 89e2a17..3a683b9 100644 --- a/part12/ElmHub.elm +++ b/part12/ElmHub.elm @@ -1,4 +1,4 @@ -module ElmHub (..) where +module ElmHub exposing (..) import Html exposing (..) import Html.Attributes exposing (..) @@ -7,133 +7,118 @@ import Html.Lazy exposing (..) import Http import Auth import Task exposing (Task) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Encode -import Signal exposing (Address) import Dict exposing (Dict) import SearchResult exposing (ResultId) -searchFeed : String -> Task x Action +searchFeed : String -> Task x Msg searchFeed query = - let - -- See https://developer.github.com/v3/search/#example for how to customize! - url = - "https://api.github.com/search/repositories?access_token=" - ++ Auth.token - ++ "&q=" - ++ query - ++ "+language:elm&sort=stars&order=desc" + let + -- See https://developer.github.com/v3/search/#example for how to customize! + url = + "https://api.github.com/search/repositories?access_token=" + ++ Auth.token + ++ "&q=" + ++ query + ++ "+language:elm&sort=stars&order=desc" - task = - Http.get responseDecoder url - |> Task.map SetResults - in - Task.onError task (\_ -> Task.succeed (SetResults [])) + task = + Http.get responseDecoder url + |> Task.map SetResults + in + Task.onError task (\_ -> Task.succeed (SetResults [])) responseDecoder : Decoder (List SearchResult.Model) responseDecoder = - "items" := Json.Decode.list SearchResult.decoder + "items" := Json.Decode.list SearchResult.decoder type alias Model = - { query : String - , results : Dict SearchResult.ResultId SearchResult.Model - } + { query : String + , results : Dict SearchResult.ResultId SearchResult.Model + } initialModel : Model initialModel = - { query = "tutorial" - , results = Dict.empty - } + { query = "tutorial" + , results = Dict.empty + } -view : Address Action -> Model -> Html -view address model = - div - [ class "content" ] - [ header - [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] +view : Model -> Html Msg +view model = + div [ class "content" ] + [ header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + , input [ class "search-query", onInput SetQuery, defaultValue model.query ] [] + , button [ class "search-button", onClick Search ] [ text "Search" ] + , ul [ class "results" ] (viewSearchResults model.results) ] - , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] - , button [ class "search-button", onClick address Search ] [ text "Search" ] - , ul - [ class "results" ] - (viewSearchResults address model.results) - ] -viewSearchResults : Address Action -> Dict ResultId SearchResult.Model -> List Html -viewSearchResults address results = - results - |> Dict.values - |> List.sortBy (.stars >> negate) - |> List.map (viewSearchResult address) +viewSearchResults : Dict ResultId SearchResult.Model -> List Html +viewSearchResults results = + results + |> Dict.values + |> List.sortBy (.stars >> negate) + |> List.map (viewSearchResult address) -viewSearchResult : Address Action -> SearchResult.Model -> Html -viewSearchResult address result = - SearchResult.view - (Signal.forwardTo address (UpdateSearchResult result.id)) - result +viewSearchResult : SearchResult.Model -> Html Msg +viewSearchResult result = + SearchResult.view (Signal.forwardTo address (UpdateSearchResult result.id)) + result -onInput address wrap = - on "input" targetValue (\val -> Signal.message address (wrap val)) +type Msg + = Search + | SetQuery String + | SetResults (List SearchResult.Model) + | UpdateSearchResult ResultId SearchResult.Msg -defaultValue str = - property "defaultValue" (Json.Encode.string str) +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + Search -> + ( model, searchFeed model.query ) + SetQuery query -> + ( { model | query = query }, Cmd.none ) -type Action - = Search - | SetQuery String - | SetResults (List SearchResult.Model) - | UpdateSearchResult ResultId SearchResult.Action - - -update : Action -> Model -> ( Model, Effects Action ) -update action model = - case action of - Search -> - ( model, Effects.task (searchFeed model.query) ) - - SetQuery query -> - ( { model | query = query }, Effects.none ) - - SetResults results -> - let - resultsById : Dict SearchResult.ResultId SearchResult.Model - resultsById = - results - |> List.map (\result -> ( result.id, result )) - |> Dict.fromList - in - ( { model | results = resultsById }, Effects.none ) - - UpdateSearchResult id childAction -> - let - updated = - model.results - |> Dict.get id - |> Maybe.map (SearchResult.update childAction) - in - case updated of - Nothing -> - ( model, Effects.none ) - - Just ( newChildModel, childEffects ) -> + SetResults results -> let - effects = - Effects.map (UpdateSearchResult id) childEffects - - newResults = - Dict.insert id newChildModel model.results + resultsById : Dict SearchResult.ResultId SearchResult.Model + resultsById = + results + |> List.map (\result -> ( result.id, result )) + |> Dict.fromList in - ( { model | results = newResults }, effects ) + ( { model | results = resultsById }, Cmd.none ) + + UpdateSearchResult id childMsg -> + let + updated = + model.results + |> Dict.get id + |> Maybe.map (SearchResult.update childMsg) + in + case updated of + Nothing -> + ( model, Cmd.none ) + + Just ( newChildModel, childEffects ) -> + let + effects = + Effects.map (UpdateSearchResult id) childEffects + + newResults = + Dict.insert id newChildModel model.results + in + ( { model | results = newResults }, effects ) diff --git a/part12/Main.elm b/part12/Main.elm index fa4bada..c60133a 100644 --- a/part12/Main.elm +++ b/part12/Main.elm @@ -1,27 +1,13 @@ -module Main (..) where +module Main exposing (..) -import StartApp import ElmHub exposing (..) -import Effects exposing (Effects) -import Task exposing (Task) -import Html exposing (Html) -main : Signal Html +main : Program Never main = - app.html - - -app : StartApp.App Model -app = - StartApp.start - { view = view - , update = update - , init = ( initialModel, Effects.task (searchFeed initialModel.query) ) - , inputs = [] - } - - -port tasks : Signal (Task Effects.Never ()) -port tasks = - app.tasks + Html.App.program + { view = view + , update = update + , init = ( initialModel, searchFeed initialModel.query ) + , inputs = [] + } diff --git a/part12/README.md b/part12/README.md index f597959..1078d85 100644 --- a/part12/README.md +++ b/part12/README.md @@ -4,16 +4,16 @@ Part 12 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## References diff --git a/part12/SearchResult.elm b/part12/SearchResult.elm index 2d1256d..015814e 100644 --- a/part12/SearchResult.elm +++ b/part12/SearchResult.elm @@ -1,63 +1,59 @@ -module SearchResult (..) where +module SearchResult exposing (..) import Html exposing (..) -import Html.Attributes exposing (class, target, href, property) +import Html.Attributes exposing (class, target, href, property, defaultValue) import Html.Events exposing (..) -import Signal exposing (Address) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Decode.Pipeline exposing (..) type alias Model = - { id : Int - , name : String - , stars : Int - , expanded : Bool - } + { id : Int + , name : String + , stars : Int + , expanded : Bool + } type alias ResultId = - Int + Int -type Action - = Expand - | Collapse +type Msg + = Expand + | Collapse decoder : Decoder Model decoder = - decode Model - |> required "id" Json.Decode.int - |> required "full_name" Json.Decode.string - |> required "stargazers_count" Json.Decode.int - |> hardcoded True + decode Model + |> required "id" Json.Decode.int + |> required "full_name" Json.Decode.string + |> required "stargazers_count" Json.Decode.int + |> hardcoded True -update : Action -> Model -> ( Model, Effects Action ) -update action model = - -- TODO implement Expand and Collapse logic - ( model, Effects.none ) +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + -- TODO implement Expand and Collapse logic + ( model, Cmd.none ) -view : Address Action -> Model -> Html -view address model = - li - [] - <| if model.expanded then - [ span [ class "star-count" ] [ text (toString model.stars) ] - , a - [ href ("https://github.com/" ++ model.name), target "_blank" ] - [ text model.name ] - , button - -- TODO when the user clicks, send a Collapse action - [ class "hide-result" ] - [ text "X" ] - ] - else - [ button - -- TODO when the user clicks, send an Expand action - [ class "expand-result" ] - [ text "Show" ] - ] +view : Model -> Html Msg +view model = + li [] <| + if model.expanded then + [ span [ class "star-count" ] [ text (toString model.stars) ] + , a [ href ("https://github.com/" ++ model.name), target "_blank" ] + [ text model.name ] + , button + -- TODO when the user clicks, send a Collapse action + [ class "hide-result" ] + [ text "X" ] + ] + else + [ button + -- TODO when the user clicks, send an Expand action + [ class "expand-result" ] + [ text "Show" ] + ] diff --git a/part12/elm-package.json b/part12/elm-package.json index f4a6d00..bd2a209 100644 --- a/part12/elm-package.json +++ b/part12/elm-package.json @@ -10,11 +10,9 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" -} \ No newline at end of file + "elm-version": "0.17.0 <= v < 0.18.0" +} diff --git a/part12/test/elm-package.json b/part12/test/elm-package.json index a440485..bd2a209 100644 --- a/part12/test/elm-package.json +++ b/part12/test/elm-package.json @@ -9,13 +9,10 @@ ], "exposed-modules": [], "dependencies": { - "deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0", - "laszlopandy/elm-console": "1.0.3 <= v < 2.0.0" + "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part13/ElmHub.elm b/part13/ElmHub.elm index 89e2a17..2f8a93b 100644 --- a/part13/ElmHub.elm +++ b/part13/ElmHub.elm @@ -1,4 +1,4 @@ -module ElmHub (..) where +module ElmHub exposing (..) import Html exposing (..) import Html.Attributes exposing (..) @@ -7,133 +7,118 @@ import Html.Lazy exposing (..) import Http import Auth import Task exposing (Task) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Encode -import Signal exposing (Address) import Dict exposing (Dict) import SearchResult exposing (ResultId) -searchFeed : String -> Task x Action +searchFeed : String -> Task x Msg searchFeed query = - let - -- See https://developer.github.com/v3/search/#example for how to customize! - url = - "https://api.github.com/search/repositories?access_token=" - ++ Auth.token - ++ "&q=" - ++ query - ++ "+language:elm&sort=stars&order=desc" + let + -- See https://developer.github.com/v3/search/#example for how to customize! + url = + "https://api.github.com/search/repositories?access_token=" + ++ Auth.token + ++ "&q=" + ++ query + ++ "+language:elm&sort=stars&order=desc" - task = - Http.get responseDecoder url - |> Task.map SetResults - in - Task.onError task (\_ -> Task.succeed (SetResults [])) + task = + Http.get responseDecoder url + |> Task.map SetResults + in + Task.onError task (\_ -> Task.succeed (SetResults [])) responseDecoder : Decoder (List SearchResult.Model) responseDecoder = - "items" := Json.Decode.list SearchResult.decoder + "items" := Json.Decode.list SearchResult.decoder type alias Model = - { query : String - , results : Dict SearchResult.ResultId SearchResult.Model - } + { query : String + , results : Dict SearchResult.ResultId SearchResult.Model + } initialModel : Model initialModel = - { query = "tutorial" - , results = Dict.empty - } + { query = "tutorial" + , results = Dict.empty + } -view : Address Action -> Model -> Html -view address model = - div - [ class "content" ] - [ header - [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] +view : Model -> Html Msg +view model = + div [ class "content" ] + [ header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + , input [ class "search-query", onInput SetQuery, defaultValue model.query ] [] + , button [ class "search-button", onClick Search ] [ text "Search" ] + , ul [ class "results" ] (viewSearchResults model.results) ] - , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] - , button [ class "search-button", onClick address Search ] [ text "Search" ] - , ul - [ class "results" ] - (viewSearchResults address model.results) - ] -viewSearchResults : Address Action -> Dict ResultId SearchResult.Model -> List Html -viewSearchResults address results = - results - |> Dict.values - |> List.sortBy (.stars >> negate) - |> List.map (viewSearchResult address) +viewSearchResults : Dict ResultId SearchResult.Model -> List Html +viewSearchResults results = + results + |> Dict.values + |> List.sortBy (.stars >> negate) + |> List.map (viewSearchResult address) viewSearchResult : Address Action -> SearchResult.Model -> Html -viewSearchResult address result = - SearchResult.view - (Signal.forwardTo address (UpdateSearchResult result.id)) - result +viewSearchResult result = + SearchResult.view (Signal.forwardTo address (UpdateSearchResult result.id)) + result -onInput address wrap = - on "input" targetValue (\val -> Signal.message address (wrap val)) +type Msg + = Search + | SetQuery String + | SetResults (List SearchResult.Model) + | UpdateSearchResult ResultId SearchResult.Action -defaultValue str = - property "defaultValue" (Json.Encode.string str) +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + Search -> + ( model, searchFeed model.query ) + SetQuery query -> + ( { model | query = query }, Cmd.none ) -type Action - = Search - | SetQuery String - | SetResults (List SearchResult.Model) - | UpdateSearchResult ResultId SearchResult.Action - - -update : Action -> Model -> ( Model, Effects Action ) -update action model = - case action of - Search -> - ( model, Effects.task (searchFeed model.query) ) - - SetQuery query -> - ( { model | query = query }, Effects.none ) - - SetResults results -> - let - resultsById : Dict SearchResult.ResultId SearchResult.Model - resultsById = - results - |> List.map (\result -> ( result.id, result )) - |> Dict.fromList - in - ( { model | results = resultsById }, Effects.none ) - - UpdateSearchResult id childAction -> - let - updated = - model.results - |> Dict.get id - |> Maybe.map (SearchResult.update childAction) - in - case updated of - Nothing -> - ( model, Effects.none ) - - Just ( newChildModel, childEffects ) -> + SetResults results -> let - effects = - Effects.map (UpdateSearchResult id) childEffects - - newResults = - Dict.insert id newChildModel model.results + resultsById : Dict SearchResult.ResultId SearchResult.Model + resultsById = + results + |> List.map (\result -> ( result.id, result )) + |> Dict.fromList in - ( { model | results = newResults }, effects ) + ( { model | results = resultsById }, Cmd.none ) + + UpdateSearchResult id childAction -> + let + updated = + model.results + |> Dict.get id + |> Maybe.map (SearchResult.update childAction) + in + case updated of + Nothing -> + ( model, Cmd.none ) + + Just ( newChildModel, childEffects ) -> + let + effects = + Effects.map (UpdateSearchResult id) childEffects + + newResults = + Dict.insert id newChildModel model.results + in + ( { model | results = newResults }, effects ) diff --git a/part13/Main.elm b/part13/Main.elm index fa4bada..c60133a 100644 --- a/part13/Main.elm +++ b/part13/Main.elm @@ -1,27 +1,13 @@ -module Main (..) where +module Main exposing (..) -import StartApp import ElmHub exposing (..) -import Effects exposing (Effects) -import Task exposing (Task) -import Html exposing (Html) -main : Signal Html +main : Program Never main = - app.html - - -app : StartApp.App Model -app = - StartApp.start - { view = view - , update = update - , init = ( initialModel, Effects.task (searchFeed initialModel.query) ) - , inputs = [] - } - - -port tasks : Signal (Task Effects.Never ()) -port tasks = - app.tasks + Html.App.program + { view = view + , update = update + , init = ( initialModel, searchFeed initialModel.query ) + , inputs = [] + } diff --git a/part13/README.md b/part13/README.md index 91b1c38..bba625d 100644 --- a/part13/README.md +++ b/part13/README.md @@ -4,16 +4,16 @@ Part 13 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## Compiling CSS diff --git a/part13/SearchResult.elm b/part13/SearchResult.elm index 5099bfd..a6e8e04 100644 --- a/part13/SearchResult.elm +++ b/part13/SearchResult.elm @@ -1,65 +1,59 @@ -module SearchResult (..) where +module SearchResult exposing (..) import Html exposing (..) -import Html.Attributes exposing (class, target, href, property) +import Html.Attributes exposing (class, target, href, property, defaultValue) import Html.Events exposing (..) -import Signal exposing (Address) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Decode.Pipeline exposing (..) type alias Model = - { id : Int - , name : String - , stars : Int - , expanded : Bool - } + { id : Int + , name : String + , stars : Int + , expanded : Bool + } type alias ResultId = - Int + Int -type Action - = Expand - | Collapse +type Msg + = Expand + | Collapse decoder : Decoder Model decoder = - decode Model - |> required "id" Json.Decode.int - |> required "full_name" Json.Decode.string - |> required "stargazers_count" Json.Decode.int - |> hardcoded True + decode Model + |> required "id" Json.Decode.int + |> required "full_name" Json.Decode.string + |> required "stargazers_count" Json.Decode.int + |> hardcoded True -update : Action -> Model -> ( Model, Effects Action ) -update action model = - case action of - Expand -> - ( { model | expanded = True }, Effects.none ) +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + Expand -> + ( { model | expanded = True }, Cmd.none ) - Collapse -> - ( { model | expanded = False }, Effects.none ) + Collapse -> + ( { model | expanded = False }, Cmd.none ) -view : Address Action -> Model -> Html -view address model = - li - [] - <| if model.expanded then - [ span [ class "star-count" ] [ text (toString model.stars) ] - , a - [ href ("https://github.com/" ++ model.name), target "_blank" ] - [ text model.name ] - , button - [ class "hide-result", onClick address Collapse ] - [ text "X" ] - ] - else - [ button - [ class "expand-result", onClick address Expand ] - [ text "Show" ] - ] +view : Model -> Html Msg +view model = + li [] + <| if model.expanded then + [ span [ class "star-count" ] [ text (toString model.stars) ] + , a [ href ("https://github.com/" ++ model.name), target "_blank" ] + [ text model.name ] + , button [ class "hide-result", onClick Collapse ] + [ text "X" ] + ] + else + [ button [ class "expand-result", onClick Expand ] + [ text "Show" ] + ] diff --git a/part13/asdf/elm-package.json b/part13/asdf/elm-package.json index 6968946..53b1f15 100644 --- a/part13/asdf/elm-package.json +++ b/part13/asdf/elm-package.json @@ -10,11 +10,10 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "rtfeldman/elm-css": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part13/elm-package.json b/part13/elm-package.json index 2f19503..53b1f15 100644 --- a/part13/elm-package.json +++ b/part13/elm-package.json @@ -10,12 +10,10 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", "rtfeldman/elm-css": "1.0.0 <= v < 2.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part13/test/elm-package.json b/part13/test/elm-package.json index a440485..53b1f15 100644 --- a/part13/test/elm-package.json +++ b/part13/test/elm-package.json @@ -9,13 +9,11 @@ ], "exposed-modules": [], "dependencies": { - "deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0", - "laszlopandy/elm-console": "1.0.3 <= v < 2.0.0" + "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "rtfeldman/elm-css": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part2/Main.elm b/part2/Main.elm index a7cbf53..e754c06 100644 --- a/part2/Main.elm +++ b/part2/Main.elm @@ -50,14 +50,19 @@ model = } +elmHubHeader : Html a +elmHubHeader = + header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + + {-| TODO add a type annotation to this function -} view model = div [ class "content" ] - [ header [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] - ] + [ elmHubHeader , ul [ class "results" ] [{- TODO use model.results and viewSearchResults to display results -}] ] diff --git a/part2/README.md b/part2/README.md index 06bc153..6f66452 100644 --- a/part2/README.md +++ b/part2/README.md @@ -4,16 +4,16 @@ Part 2 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## References diff --git a/part3/Main.elm b/part3/Main.elm index 494979d..f0fcae4 100644 --- a/part3/Main.elm +++ b/part3/Main.elm @@ -3,6 +3,7 @@ module Main exposing (..) import Html exposing (..) import Html.App import Html.Attributes exposing (..) +import Html.Events exposing (onClick) type alias Model = @@ -50,19 +51,27 @@ initialModel = } -view : Model -> Html Msg -view model = - div [ class "content" ] - [ header [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] - ] - , ul [ class "results" ] - (List.map viewSearchResult model.results) +elmHubHeader : Html a +elmHubHeader = + header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] ] -viewSearchResult : SearchResult -> Html Msg +{-| TODO revise this type annotation once we add our onClick handler +-} +view : Model -> Html a +view model = + div [ class "content" ] + [ elmHubHeader + , ul [ class "results" ] (List.map viewSearchResult model.results) + ] + + +{-| TODO revise this type annotation once we add our onClick handler +-} +viewSearchResult : SearchResult -> Html a viewSearchResult result = li [] [ span [ class "star-count" ] [ text (toString result.stars) ] diff --git a/part3/README.md b/part3/README.md index 7c51cfc..8656678 100644 --- a/part3/README.md +++ b/part3/README.md @@ -4,16 +4,16 @@ Part 3 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## References diff --git a/part4/Main.elm b/part4/Main.elm index 6dd8a3b..794d24d 100644 --- a/part4/Main.elm +++ b/part4/Main.elm @@ -3,6 +3,7 @@ module Main exposing (..) import Html exposing (..) import Html.App import Html.Attributes exposing (..) +import Html.Events exposing (onClick, onInput) type alias Model = @@ -63,13 +64,12 @@ view model = ] , input [ class "search-query" - -- TODO when we receive onInput, set the query in the model + -- TODO onInput, set the query in the model , defaultValue model.query ] [] , button [ class "search-button" ] [ text "Search" ] - , ul [ class "results" ] - (List.map viewSearchResult model.results) + , ul [ class "results" ] (List.map viewSearchResult model.results) ] diff --git a/part4/README.md b/part4/README.md index 3799a0b..dbe132f 100644 --- a/part4/README.md +++ b/part4/README.md @@ -4,16 +4,16 @@ Part 4 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## References diff --git a/part5/Main.elm b/part5/Main.elm index cd310d0..72c3348 100644 --- a/part5/Main.elm +++ b/part5/Main.elm @@ -69,7 +69,7 @@ responseDecoder = searchResultDecoder : Decoder SearchResult searchResultDecoder = -- See https://developer.github.com/v3/search/#example - -- TODO replace these `hardcoded` with calls to `require` + -- TODO replace these calls to `hardcoded` with calls to `require` decode SearchResult |> hardcoded 0 |> hardcoded "" diff --git a/part5/README.md b/part5/README.md index 5956356..095dae0 100644 --- a/part5/README.md +++ b/part5/README.md @@ -4,14 +4,14 @@ Part 5 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` diff --git a/part5/elm-package.json b/part5/elm-package.json index f30d195..bd2a209 100644 --- a/part5/elm-package.json +++ b/part5/elm-package.json @@ -15,4 +15,4 @@ "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, "elm-version": "0.17.0 <= v < 0.18.0" -} \ No newline at end of file +} diff --git a/part6/ElmHub.elm b/part6/ElmHub.elm index cb868e7..f484b49 100644 --- a/part6/ElmHub.elm +++ b/part6/ElmHub.elm @@ -1,200 +1,152 @@ -module ElmHub (..) where +module ElmHub exposing (..) import Auth import Html exposing (..) -import Html.Attributes exposing (class, target, href, property) +import Html.Attributes exposing (class, target, href, property, defaultValue) import Html.Events exposing (..) import Http import Task exposing (Task) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Decode.Pipeline exposing (..) -import Json.Encode -import Signal exposing (Address) -searchFeed : String -> Effects Action +searchFeed : String -> Cmd Msg searchFeed query = - let - url = - "https://api.github.com/search/repositories?access_token=" - ++ Auth.token - ++ "&q=" - ++ query - ++ "+language:elm&sort=stars&order=desc" + let + url = + "https://api.github.com/search/repositories?access_token=" + ++ Auth.token + ++ "&q=" + ++ query + ++ "+language:elm&sort=stars&order=desc" - -- TODO define task as: - -- - -- task = performAction argument1 argument2 argument3 - -- - -- Use these "ingredients" to give `performAction` the arguments it needs: - -- - -- Http.get - -- url - -- responseDecoder - -- HandleSearchResponse - -- HandleSearchError - -- - -- Hint: http://package.elm-lang.org/packages/evancz/elm-http/3.0.0/Http#get - task = - "TODO performAction ..." - in - -- TODO replace this `Effects.none` with a call to: - -- - -- Effects.task task - Effects.none - - -{-| Note: this will be a standard function in the next release of Elm. - -Example: - - -type Action = - HandleResponse String | HandleError Http.Error - - -performAction - (\responseString -> HandleResponse responseString) - (\httpError -> HandleError httpError) - (Http.getString "https://google.com?q=something") - --} -performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b -performAction successToAction errorToAction task = - let - successTask = - Task.map successToAction task - in - Task.onError successTask (\err -> Task.succeed (errorToAction err)) + -- TODO use these ingredients to give Task.perform the arguments it needs: + -- + -- Http.get + -- url + -- responseDecoder + -- HandleSearchResponse + -- HandleSearchError + -- + -- Hint: http://package.elm-lang.org/packages/evancz/elm-http/3.0.0/Http#get + task = + "TODO call Task.perform ..." + in + -- TODO replace this Cmd.none with a call to Task.perform + Cmd.none responseDecoder : Decoder (List SearchResult) responseDecoder = - "items" := Json.Decode.list searchResultDecoder + Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder) searchResultDecoder : Decoder SearchResult searchResultDecoder = - decode SearchResult - |> required "id" Json.Decode.int - |> required "full_name" Json.Decode.string - |> required "stargazers_count" Json.Decode.int + decode SearchResult + |> required "id" Json.Decode.int + |> required "full_name" Json.Decode.string + |> required "stargazers_count" Json.Decode.int type alias Model = - { query : String - , results : List SearchResult - , errorMessage : Maybe String - } + { query : String + , results : List SearchResult + , errorMessage : Maybe String + } type alias SearchResult = - { id : ResultId - , name : String - , stars : Int - } + { id : ResultId + , name : String + , stars : Int + } type alias ResultId = - Int + Int initialModel : Model initialModel = - { query = "tutorial" - , results = [] - , errorMessage = Nothing - } + { query = "tutorial" + , results = [] + , errorMessage = Nothing + } -view : Address Action -> Model -> Html -view address model = - div - [ class "content" ] - [ header - [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] +view : Model -> Html Msg +view model = + div [ class "content" ] + [ header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + , input [ class "search-query", onInput SetQuery, defaultValue model.query ] [] + , button [ class "search-button", onClick Search ] [ text "Search" ] + , viewErrorMessage model.errorMessage + , ul [ class "results" ] (List.map viewSearchResult model.results) ] - , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] - , button [ class "search-button", onClick address Search ] [ text "Search" ] - , viewErrorMessage model.errorMessage - , ul - [ class "results" ] - (List.map (viewSearchResult address) model.results) - ] -viewErrorMessage : Maybe String -> Html +viewErrorMessage : Maybe String -> Html a a viewErrorMessage errorMessage = - case errorMessage of - Just message -> - div [ class "error" ] [ text message ] + case errorMessage of + Just message -> + div [ class "error" ] [ text message ] - Nothing -> - text "" + Nothing -> + text "" -onInput address wrap = - on "input" targetValue (\val -> Signal.message address (wrap val)) +viewSearchResult : SearchResult -> Html Msg +viewSearchResult result = + li [] + [ span [ class "star-count" ] [ text (toString result.stars) ] + , a [ href ("https://github.com/" ++ result.name), target "_blank" ] + [ text result.name ] + , button [ class "hide-result", onClick (DeleteById result.id) ] + [ text "X" ] + ] -defaultValue str = - property "defaultValue" (Json.Encode.string str) +type Msg + = Search + | SetQuery String + | DeleteById ResultId + | HandleSearchResponse (List SearchResult) + | HandleSearchError Http.Error -viewSearchResult : Address Action -> SearchResult -> Html -viewSearchResult address result = - li - [] - [ span [ class "star-count" ] [ text (toString result.stars) ] - , a - [ href ("https://github.com/" ++ result.name), target "_blank" ] - [ text result.name ] - , button - [ class "hide-result", onClick address (DeleteById result.id) ] - [ text "X" ] - ] +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + Search -> + ( model, searchFeed model.query ) + HandleSearchResponse results -> + ( { model | results = results }, Cmd.none ) -type Action - = Search - | SetQuery String - | DeleteById ResultId - | HandleSearchResponse (List SearchResult) - | HandleSearchError Http.Error + HandleSearchError error -> + -- TODO if decoding failed, store the message in model.errorMessage + -- + -- Hint 1: look for "decode" in the documentation for this union type: + -- http://package.elm-lang.org/packages/evancz/elm-http/3.0.1/Http#Error + -- + -- Hint 2: to check if this is working, break responseDecoder + -- by changing "stargazers_count" to "description" + ( model, Cmd.none ) + SetQuery query -> + ( { model | query = query }, Cmd.none ) -update : Action -> Model -> ( Model, Effects Action ) -update action model = - case action of - Search -> - ( model, searchFeed model.query ) + DeleteById idToHide -> + let + newResults = + model.results + |> List.filter (\{ id } -> id /= idToHide) - HandleSearchResponse results -> - ( { model | results = results }, Effects.none ) - - HandleSearchError error -> - -- TODO if decoding failed, store the message in model.errorMessage - -- - -- Hint 1: look for "decode" in the documentation for this union type: - -- http://package.elm-lang.org/packages/evancz/elm-http/3.0.0/Http#Error - -- - -- Hint 2: to check if this is working, break responseDecoder - -- by changing "stargazers_count" to "description" - ( model, Effects.none ) - - SetQuery query -> - ( { model | query = query }, Effects.none ) - - DeleteById idToHide -> - let - newResults = - model.results - |> List.filter (\{ id } -> id /= idToHide) - - newModel = - { model | results = newResults } - in - ( newModel, Effects.none ) + newModel = + { model | results = newResults } + in + ( newModel, Cmd.none ) diff --git a/part6/Main.elm b/part6/Main.elm index 6d09545..c60133a 100644 --- a/part6/Main.elm +++ b/part6/Main.elm @@ -1,27 +1,13 @@ -module Main (..) where +module Main exposing (..) -import StartApp import ElmHub exposing (..) -import Effects exposing (Effects) -import Task exposing (Task) -import Html exposing (Html) -main : Signal Html +main : Program Never main = - app.html - - -app : StartApp.App Model -app = - StartApp.start - { view = view - , update = update - , init = ( initialModel, searchFeed initialModel.query ) - , inputs = [] - } - - -port tasks : Signal (Task Effects.Never ()) -port tasks = - app.tasks + Html.App.program + { view = view + , update = update + , init = ( initialModel, searchFeed initialModel.query ) + , inputs = [] + } diff --git a/part6/README.md b/part6/README.md index cd01c22..c69e27f 100644 --- a/part6/README.md +++ b/part6/README.md @@ -4,16 +4,16 @@ Part 6 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## References diff --git a/part6/elm-package.json b/part6/elm-package.json index 6968946..bd2a209 100644 --- a/part6/elm-package.json +++ b/part6/elm-package.json @@ -10,11 +10,9 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part7/ElmHub.elm b/part7/ElmHub.elm index bcee1b7..819af7e 100644 --- a/part7/ElmHub.elm +++ b/part7/ElmHub.elm @@ -1,189 +1,141 @@ -module ElmHub (..) where +module ElmHub exposing (..) import Auth import Html exposing (..) -import Html.Attributes exposing (class, target, href, property) +import Html.Attributes exposing (class, target, href, property, defaultValue) import Html.Events exposing (..) import Http import Task exposing (Task) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Decode.Pipeline exposing (..) -import Json.Encode -import Signal exposing (Address) -searchFeed : String -> Effects Action +searchFeed : String -> Cmd Msg searchFeed query = - let - url = - "https://api.github.com/search/repositories?access_token=" - ++ Auth.token - ++ "&q=" - ++ query - ++ "+language:elm&sort=stars&order=desc" - - task = - performAction - (\response -> HandleSearchResponse response) - (\error -> HandleSearchError error) - (Http.get responseDecoder url) - in - Effects.task task + let + url = + "https://api.github.com/search/repositories?access_token=" + ++ Auth.token + ++ "&q=" + ++ query + ++ "+language:elm&sort=stars&order=desc" + in + Task.perform HandleSearchError HandleSearchResponse (Http.get responseDecoder url) responseDecoder : Decoder (List SearchResult) responseDecoder = - "items" := Json.Decode.list searchResultDecoder + Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder) searchResultDecoder : Decoder SearchResult searchResultDecoder = - decode SearchResult - |> required "id" Json.Decode.int - |> required "full_name" Json.Decode.string - |> required "stargazers_count" Json.Decode.int - - -{-| Note: this will be a standard function in the next release of Elm. - -Example: - - -type Action = - HandleResponse String | HandleError Http.Error - - -performAction - (\responseString -> HandleResponse responseString) - (\httpError -> HandleError httpError) - (Http.getString "https://google.com?q=something") - --} -performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b -performAction successToAction errorToAction task = - let - successTask = - Task.map successToAction task - in - Task.onError successTask (\err -> Task.succeed (errorToAction err)) + decode SearchResult + |> required "id" Json.Decode.int + |> required "full_name" Json.Decode.string + |> required "stargazers_count" Json.Decode.int type alias Model = - { query : String - , results : List SearchResult - , errorMessage : Maybe String - } + { query : String + , results : List SearchResult + , errorMessage : Maybe String + } type alias SearchResult = - { id : ResultId - , name : String - , stars : Int - } + { id : ResultId + , name : String + , stars : Int + } type alias ResultId = - Int + Int initialModel : Model initialModel = - { query = "tutorial" - , results = [] - , errorMessage = Nothing - } + { query = "tutorial" + , results = [] + , errorMessage = Nothing + } -view : Address Action -> Model -> Html -view address model = - div - [ class "content" ] - [ header - [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] +view : Model -> Html Msg +view model = + div [ class "content" ] + [ header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + , input [ class "search-query", onInput SetQuery, defaultValue model.query ] [] + , button [ class "search-button", onClick Search ] [ text "Search" ] + , viewErrorMessage model.errorMessage + , ul [ class "results" ] (List.map viewSearchResult model.results) ] - , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] - , button [ class "search-button", onClick address Search ] [ text "Search" ] - , viewErrorMessage model.errorMessage - , ul - [ class "results" ] - (List.map (viewSearchResult address) model.results) - ] -viewErrorMessage : Maybe String -> Html +viewErrorMessage : Maybe String -> Html a viewErrorMessage errorMessage = - case errorMessage of - Just message -> - div [ class "error" ] [ text message ] + case errorMessage of + Just message -> + div [ class "error" ] [ text message ] - Nothing -> - text "" + Nothing -> + text "" -onInput address wrap = - on "input" targetValue (\val -> Signal.message address (wrap val)) +viewSearchResult : SearchResult -> Html Msg +viewSearchResult result = + li [] + [ span [ class "star-count" ] [ text (toString result.stars) ] + , a [ href ("https://github.com/" ++ result.name), target "_blank" ] + [ text result.name ] + , button [ class "hide-result", onClick (DeleteById result.id) ] + [ text "X" ] + ] -defaultValue str = - property "defaultValue" (Json.Encode.string str) +type Msg + = Search + | SetQuery String + | DeleteById ResultId + | HandleSearchResponse (List SearchResult) + | HandleSearchError Http.Error -viewSearchResult : Address Action -> SearchResult -> Html -viewSearchResult address result = - li - [] - [ span [ class "star-count" ] [ text (toString result.stars) ] - , a - [ href ("https://github.com/" ++ result.name), target "_blank" ] - [ text result.name ] - , button - [ class "hide-result", onClick address (DeleteById result.id) ] - [ text "X" ] - ] +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + Search -> + ( model, searchFeed model.query ) + HandleSearchResponse results -> + ( { model | results = results }, Cmd.none ) -type Action - = Search - | SetQuery String - | DeleteById ResultId - | HandleSearchResponse (List SearchResult) - | HandleSearchError Http.Error + HandleSearchError error -> + let + errorMessage = + case error of + Http.UnexpectedPayload message -> + Just message + _ -> + Nothing + in + ( { model | errorMessage = errorMessage }, Cmd.none ) -update : Action -> Model -> ( Model, Effects Action ) -update action model = - case action of - Search -> - ( model, searchFeed model.query ) + SetQuery query -> + ( { model | query = query }, Cmd.none ) - HandleSearchResponse results -> - ( { model | results = results }, Effects.none ) + DeleteById idToHide -> + let + newResults = + model.results + |> List.filter (\{ id } -> id /= idToHide) - HandleSearchError error -> - let - errorMessage = - case error of - Http.UnexpectedPayload message -> - Just message - - _ -> - Nothing - in - ( { model | errorMessage = errorMessage }, Effects.none ) - - SetQuery query -> - ( { model | query = query }, Effects.none ) - - DeleteById idToHide -> - let - newResults = - model.results - |> List.filter (\{ id } -> id /= idToHide) - - newModel = - { model | results = newResults } - in - ( newModel, Effects.none ) + newModel = + { model | results = newResults } + in + ( newModel, Cmd.none ) diff --git a/part7/Main.elm b/part7/Main.elm index 6d09545..c60133a 100644 --- a/part7/Main.elm +++ b/part7/Main.elm @@ -1,27 +1,13 @@ -module Main (..) where +module Main exposing (..) -import StartApp import ElmHub exposing (..) -import Effects exposing (Effects) -import Task exposing (Task) -import Html exposing (Html) -main : Signal Html +main : Program Never main = - app.html - - -app : StartApp.App Model -app = - StartApp.start - { view = view - , update = update - , init = ( initialModel, searchFeed initialModel.query ) - , inputs = [] - } - - -port tasks : Signal (Task Effects.Never ()) -port tasks = - app.tasks + Html.App.program + { view = view + , update = update + , init = ( initialModel, searchFeed initialModel.query ) + , inputs = [] + } diff --git a/part7/README.md b/part7/README.md index a39189a..9df214d 100644 --- a/part7/README.md +++ b/part7/README.md @@ -4,23 +4,23 @@ Part 7 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## Running Tests ```bash cd test -elm package install +elm-package install elm test TestRunner.elm ``` diff --git a/part7/elm-package.json b/part7/elm-package.json index 6968946..bd2a209 100644 --- a/part7/elm-package.json +++ b/part7/elm-package.json @@ -10,11 +10,9 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part7/test/elm-package.json b/part7/test/elm-package.json index 8a04845..bd2a209 100644 --- a/part7/test/elm-package.json +++ b/part7/test/elm-package.json @@ -9,14 +9,10 @@ ], "exposed-modules": [], "dependencies": { - "deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0", "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0", - "laszlopandy/elm-console": "1.0.3 <= v < 2.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part8/ElmHub.elm b/part8/ElmHub.elm index e2fd646..ef71143 100644 --- a/part8/ElmHub.elm +++ b/part8/ElmHub.elm @@ -1,187 +1,142 @@ -module ElmHub (..) where +module ElmHub exposing (..) import Html exposing (..) -import Html.Attributes exposing (class, target, href, property) +import Html.Attributes exposing (class, target, href, property, defaultValue) import Html.Events exposing (..) -import Http import Auth import Task exposing (Task) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Decode.Pipeline exposing (..) import Json.Encode -import Signal exposing (Address) -searchFeed : Address String -> String -> Effects Action -searchFeed address query = - let +getQueryUrl : String -> String +getQueryUrl query = -- See https://developer.github.com/v3/search/#example for how to customize! - url = - "https://api.github.com/search/repositories?access_token=" + "https://api.github.com/search/repositories?access_token=" ++ Auth.token ++ "&q=" ++ query ++ "+language:elm&sort=stars&order=desc" - -- These only talk to JavaScript ports now. They never result in Actions - -- actually do any actions themselves. - task = - performAction - (\_ -> DoNothing) - (\_ -> DoNothing) - (Signal.send address query) - in - Effects.task task - responseDecoder : Decoder (List SearchResult) responseDecoder = - "items" := Json.Decode.list searchResultDecoder + Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder) searchResultDecoder : Decoder SearchResult searchResultDecoder = - decode SearchResult - |> required "id" Json.Decode.int - |> required "full_name" Json.Decode.string - |> required "stargazers_count" Json.Decode.int - - -{-| Note: this will be a standard function in the next release of Elm. - -Example: - - -type Action = - HandleResponse String | HandleError Http.Error - - -performAction - (\responseString -> HandleResponse responseString) - (\httpError -> HandleError httpError) - (Http.getString "https://google.com?q=something") - --} -performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b -performAction successToAction errorToAction task = - let - successTask = - Task.map successToAction task - in - Task.onError successTask (\err -> Task.succeed (errorToAction err)) + decode SearchResult + |> required "id" Json.Decode.int + |> required "full_name" Json.Decode.string + |> required "stargazers_count" Json.Decode.int type alias Model = - { query : String - , results : List SearchResult - , errorMessage : Maybe String - } + { query : String + , results : List SearchResult + , errorMessage : Maybe String + } type alias SearchResult = - { id : ResultId - , name : String - , stars : Int - } + { id : ResultId + , name : String + , stars : Int + } type alias ResultId = - Int + Int initialModel : Model initialModel = - { query = "tutorial" - , results = [] - , errorMessage = Nothing - } + { query = "tutorial" + , results = [] + , errorMessage = Nothing + } -view : Address Action -> Model -> Html -view address model = - div - [ class "content" ] - [ header - [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] +view : Model -> Html Msg +view model = + div [ class "content" ] + [ header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + , input [ class "search-query", onInput SetQuery, defaultValue model.query ] [] + , button [ class "search-button", onClick Search ] [ text "Search" ] + , viewErrorMessage model.errorMessage + , ul [ class "results" ] (List.map viewSearchResult model.results) ] - , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] - , button [ class "search-button", onClick address Search ] [ text "Search" ] - , viewErrorMessage model.errorMessage - , ul - [ class "results" ] - (List.map (viewSearchResult address) model.results) - ] -viewErrorMessage : Maybe String -> Html +viewErrorMessage : Maybe String -> Html a viewErrorMessage errorMessage = - case errorMessage of - Just message -> - div [ class "error" ] [ text message ] + case errorMessage of + Just message -> + div [ class "error" ] [ text message ] - Nothing -> - text "" + Nothing -> + text "" -onInput address wrap = - on "input" targetValue (\val -> Signal.message address (wrap val)) +viewSearchResult : SearchResult -> Html Msg +viewSearchResult result = + li [] + [ span [ class "star-count" ] [ text (toString result.stars) ] + , a [ href ("https://github.com/" ++ result.name), target "_blank" ] + [ text result.name ] + , button [ class "hide-result", onClick (DeleteById result.id) ] + [ text "X" ] + ] -defaultValue str = - property "defaultValue" (Json.Encode.string str) +type Msg + = Search + | SetQuery String + | DeleteById ResultId + | SetResults (List SearchResult) + | SetErrorMessage (Maybe String) + | DoNothing -viewSearchResult : Address Action -> SearchResult -> Html -viewSearchResult address result = - li - [] - [ span [ class "star-count" ] [ text (toString result.stars) ] - , a - [ href ("https://github.com/" ++ result.name), target "_blank" ] - [ text result.name ] - , button - [ class "hide-result", onClick address (DeleteById result.id) ] - [ text "X" ] - ] +update : (String -> Cmd Msg) -> Msg -> Model -> ( Model, Cmd Msg ) +update searchFeed msg model = + case msg of + Search -> + ( model, searchFeed (getQueryUrl model.query) ) + + SetQuery query -> + ( { model | query = query }, Cmd.none ) + + SetResults results -> + ( { model | results = results }, Cmd.none ) + + SetErrorMessage errorMessage -> + ( { model | errorMessage = errorMessage }, Cmd.none ) + + DeleteById idToHide -> + let + newResults = + model.results + |> List.filter (\{ id } -> id /= idToHide) + + newModel = + { model | results = newResults } + in + ( newModel, Cmd.none ) + + DoNothing -> + ( model, Cmd.none ) -type Action - = Search - | SetQuery String - | DeleteById ResultId - | SetResults (List SearchResult) - | SetErrorMessage (Maybe String) - | DoNothing - - -update : Address String -> Action -> Model -> ( Model, Effects Action ) -update searchAddress action model = - case action of - Search -> - ( model, searchFeed searchAddress model.query ) - - SetQuery query -> - ( { model | query = query }, Effects.none ) - - SetResults results -> - ( { model | results = results }, Effects.none ) - - SetErrorMessage errorMessage -> - ( { model | errorMessage = errorMessage }, Effects.none ) - - DeleteById idToHide -> - let - newResults = - model.results - |> List.filter (\{ id } -> id /= idToHide) - - newModel = - { model | results = newResults } - in - ( newModel, Effects.none ) - - DoNothing -> - ( model, Effects.none ) +decodeGithubResponse : Json.Encode.Value -> Msg +decodeGithubResponse value = + -- TODO use Json.Decode.DecodeValue to decode the response into an Action. + -- + -- Hint: look at ElmHub.elm, specifically the definition of Action and + -- the deefinition of responseDecoder + SetErrorMessage (Just "TODO decode the response!") diff --git a/part8/Main.elm b/part8/Main.elm index 8e11329..718fc54 100644 --- a/part8/Main.elm +++ b/part8/Main.elm @@ -1,57 +1,31 @@ -module Main (..) where +port module Main exposing (..) -import StartApp import ElmHub exposing (..) -import Effects exposing (Effects) -import Task exposing (Task) -import Html exposing (Html) -import Signal -import Json.Encode -import Json.Decode +import Html.App +import Json.Decode exposing (Value) -main : Signal Html +main : Program Never main = - app.html + Html.App.program + { view = view + , update = update githubSearch + , init = ( initialModel, githubSearch (getQueryUrl initialModel.query) ) + , subscriptions = \_ -> githubResponse decodeResponse + } -app : StartApp.App Model -app = - StartApp.start - { view = view - , update = update search.address - , init = ( initialModel, searchFeed search.address initialModel.query ) - , inputs = [ responseActions ] - } +decodeResponse : Json.Decode.Value -> Msg +decodeResponse json = + case Json.Decode.decodeValue responseDecoder json of + Err err -> + SetErrorMessage (Just err) + + Ok results -> + SetResults results -port tasks : Signal (Task Effects.Never ()) -port tasks = - app.tasks +port githubSearch : String -> Cmd msg -search : Signal.Mailbox String -search = - Signal.mailbox "" - - -port githubSearch : Signal String -port githubSearch = - search.signal - - -responseActions : Signal Action -responseActions = - Signal.map decodeGithubResponse githubResponse - - -decodeGithubResponse : Json.Encode.Value -> Action -decodeGithubResponse value = - -- TODO use Json.Decode.DecodeValue to decode the response into an Action. - -- - -- Hint: look at ElmHub.elm, specifically the definition of Action and - -- the deefinition of responseDecoder - SetErrorMessage (Just "TODO decode the response!") - - -port githubResponse : Signal Json.Encode.Value +port githubResponse : (Json.Decode.Value -> msg) -> Sub msg diff --git a/part8/README.md b/part8/README.md index 3c4517b..d39681a 100644 --- a/part8/README.md +++ b/part8/README.md @@ -4,22 +4,22 @@ Part 8 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` ## Running Tests ```bash cd test -elm package install +elm-package install elm test TestRunner.elm ``` diff --git a/part8/elm-package.json b/part8/elm-package.json index f4a6d00..bd2a209 100644 --- a/part8/elm-package.json +++ b/part8/elm-package.json @@ -10,11 +10,9 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" -} \ No newline at end of file + "elm-version": "0.17.0 <= v < 0.18.0" +} diff --git a/part8/test/elm-package.json b/part8/test/elm-package.json index 8a04845..bd2a209 100644 --- a/part8/test/elm-package.json +++ b/part8/test/elm-package.json @@ -9,14 +9,10 @@ ], "exposed-modules": [], "dependencies": { - "deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0", "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0", - "laszlopandy/elm-console": "1.0.3 <= v < 2.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" + "elm-version": "0.17.0 <= v < 0.18.0" } diff --git a/part9/ElmHub.elm b/part9/ElmHub.elm index 9ea3bfb..f4b0fd1 100644 --- a/part9/ElmHub.elm +++ b/part9/ElmHub.elm @@ -1,182 +1,126 @@ -module ElmHub (..) where +module ElmHub exposing (..) import Html exposing (..) -import Html.Attributes exposing (class, target, href, property) +import Html.Attributes exposing (class, target, href, property, defaultValue) import Html.Events exposing (..) -import Http import Auth -import Task exposing (Task) -import Effects exposing (Effects) -import Json.Decode exposing (Decoder, (:=)) +import Json.Decode exposing (Decoder) import Json.Decode.Pipeline exposing (..) -import Json.Encode -import Signal exposing (Address) import Dict exposing (Dict) -searchFeed : Address String -> String -> Effects Action -searchFeed address query = - let +getQueryUrl : String -> String +getQueryUrl query = -- See https://developer.github.com/v3/search/#example for how to customize! - url = - "https://api.github.com/search/repositories?access_token=" + "https://api.github.com/search/repositories?access_token=" ++ Auth.token ++ "&q=" ++ query ++ "+language:elm&sort=stars&order=desc" - -- These only talk to JavaScript ports now. They never result in Actions - -- actually do any actions themselves. - task = - performAction - (\_ -> DoNothing) - (\_ -> DoNothing) - (Signal.send address query) - in - Effects.task task - responseDecoder : Decoder (List SearchResult) responseDecoder = - "items" := Json.Decode.list searchResultDecoder + Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder) searchResultDecoder : Decoder SearchResult searchResultDecoder = - decode SearchResult - |> required "id" Json.Decode.int - |> required "full_name" Json.Decode.string - |> required "stargazers_count" Json.Decode.int - - -{-| Note: this will be a standard function in the next release of Elm. - -Example: - - -type Action = - HandleResponse String | HandleError Http.Error - - -performAction - (\responseString -> HandleResponse responseString) - (\httpError -> HandleError httpError) - (Http.getString "https://google.com?q=something") - --} -performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b -performAction successToAction errorToAction task = - let - successTask = - Task.map successToAction task - in - Task.onError successTask (\err -> Task.succeed (errorToAction err)) + decode SearchResult + |> required "id" Json.Decode.int + |> required "full_name" Json.Decode.string + |> required "stargazers_count" Json.Decode.int type alias Model = - { query : String - , results : Dict ResultId SearchResult - , errorMessage : Maybe String - } + { query : String + , results : Dict ResultId SearchResult + , errorMessage : Maybe String + } type alias SearchResult = - { id : ResultId - , name : String - , stars : Int - } + { id : ResultId + , name : String + , stars : Int + } type alias ResultId = - Int + Int initialModel : Model initialModel = - { query = "tutorial" - , results = Dict.empty - , errorMessage = Nothing - } + { query = "tutorial" + , results = Dict.empty + , errorMessage = Nothing + } -view : Address Action -> Model -> Html -view address model = - div - [ class "content" ] - [ header - [] - [ h1 [] [ text "ElmHub" ] - , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] +view : Model -> Html Msg +view model = + div [ class "content" ] + [ header [] + [ h1 [] [ text "ElmHub" ] + , span [ class "tagline" ] [ text "“Like GitHub, but for Elm things.”" ] + ] + , input [ class "search-query", onInput SetQuery, defaultValue model.query ] [] + , button [ class "search-button", onClick Search ] [ text "Search" ] + , ul [ class "results" ] (viewSearchResults model.results) ] - , input [ class "search-query", onInput address SetQuery, defaultValue model.query ] [] - , button [ class "search-button", onClick address Search ] [ text "Search" ] - , ul - [ class "results" ] - (viewSearchResults address model.results) - ] -viewSearchResults : Address Action -> Dict ResultId SearchResult -> List Html -viewSearchResults address results = - -- TODO sort by star count and render - [] - - -onInput address wrap = - on "input" targetValue (\val -> Signal.message address (wrap val)) - - -defaultValue str = - property "defaultValue" (Json.Encode.string str) - - -viewSearchResult : Address Action -> SearchResult -> Html -viewSearchResult address result = - li +viewSearchResults : Dict ResultId SearchResult -> List (Html Msg) +viewSearchResults results = + -- TODO sort by star count and render [] - [ span [ class "star-count" ] [ text (toString result.stars) ] - , a - [ href ("https://github.com/" ++ result.name), target "_blank" ] - [ text result.name ] - , button - [ class "hide-result", onClick address (DeleteById result.id) ] - [ text "X" ] - ] -type Action - = Search - | SetQuery String - | DeleteById ResultId - | SetResults (List SearchResult) - | SetErrorMessage (Maybe String) - | DoNothing +viewSearchResult : SearchResult -> Html Msg +viewSearchResult result = + li [] + [ span [ class "star-count" ] [ text (toString result.stars) ] + , a [ href ("https://github.com/" ++ result.name), target "_blank" ] + [ text result.name ] + , button [ class "hide-result", onClick (DeleteById result.id) ] + [ text "X" ] + ] -update : Address String -> Action -> Model -> ( Model, Effects Action ) -update searchAddress action model = - case action of - Search -> - ( model, searchFeed searchAddress model.query ) +type Msg + = Search + | SetQuery String + | DeleteById ResultId + | SetResults (List SearchResult) + | SetErrorMessage (Maybe String) + | DoNothing - SetQuery query -> - ( { model | query = query }, Effects.none ) - SetResults results -> - let - resultsById : Dict ResultId SearchResult - resultsById = - -- TODO convert results list into a Dict - Dict.empty - in - ( { model | results = resultsById }, Effects.none ) +update : (String -> Cmd Msg) -> Msg -> Model -> ( Model, Cmd Msg ) +update searchFeed msg model = + case msg of + Search -> + ( model, searchFeed (getQueryUrl model.query) ) - DeleteById id -> - -- TODO delete the result with the given id - ( model, Effects.none ) + SetQuery query -> + ( { model | query = query }, Cmd.none ) - SetErrorMessage errorMessage -> - ( { model | errorMessage = errorMessage }, Effects.none ) + SetResults results -> + let + resultsById : Dict ResultId SearchResult + resultsById = + -- TODO convert results list into a Dict + Dict.empty + in + ( { model | results = resultsById }, Cmd.none ) - DoNothing -> - ( model, Effects.none ) + DeleteById id -> + -- TODO delete the result with the given id + ( model, Cmd.none ) + + SetErrorMessage errorMessage -> + ( { model | errorMessage = errorMessage }, Cmd.none ) + + DoNothing -> + ( model, Cmd.none ) diff --git a/part9/Main.elm b/part9/Main.elm index e5f7839..718fc54 100644 --- a/part9/Main.elm +++ b/part9/Main.elm @@ -1,58 +1,31 @@ -module Main (..) where +port module Main exposing (..) -import StartApp import ElmHub exposing (..) -import Effects exposing (Effects) -import Task exposing (Task) -import Html exposing (Html) -import Signal -import Json.Encode -import Json.Decode +import Html.App +import Json.Decode exposing (Value) -main : Signal Html +main : Program Never main = - app.html + Html.App.program + { view = view + , update = update githubSearch + , init = ( initialModel, githubSearch (getQueryUrl initialModel.query) ) + , subscriptions = \_ -> githubResponse decodeResponse + } -app : StartApp.App Model -app = - StartApp.start - { view = view - , update = update search.address - , init = ( initialModel, searchFeed search.address initialModel.query ) - , inputs = [ responseActions ] - } +decodeResponse : Json.Decode.Value -> Msg +decodeResponse json = + case Json.Decode.decodeValue responseDecoder json of + Err err -> + SetErrorMessage (Just err) + + Ok results -> + SetResults results -port tasks : Signal (Task Effects.Never ()) -port tasks = - app.tasks +port githubSearch : String -> Cmd msg -search : Signal.Mailbox String -search = - Signal.mailbox "" - - -port githubSearch : Signal String -port githubSearch = - search.signal - - -responseActions : Signal Action -responseActions = - Signal.map decodeGithubResponse githubResponse - - -decodeGithubResponse : Json.Encode.Value -> Action -decodeGithubResponse value = - case Json.Decode.decodeValue responseDecoder value of - Ok results -> - SetResults results - - Err message -> - SetErrorMessage (Just message) - - -port githubResponse : Signal Json.Encode.Value +port githubResponse : (Json.Decode.Value -> msg) -> Sub msg diff --git a/part9/README.md b/part9/README.md index f08ee4f..739e188 100644 --- a/part9/README.md +++ b/part9/README.md @@ -4,14 +4,14 @@ Part 9 ## Installation ```bash -elm package install +elm-package install ``` (Answer `y` at the prompt. In rare cases a known issue can cause the download -to fail; in that case, just run `elm package install` again.) +to fail; in that case, just run `elm-package install` again.) ## Building ```bash -elm live Main.elm --open -- --output=elm.js +elm-live Main.elm --open -- --output=elm.js ``` diff --git a/part9/elm-package.json b/part9/elm-package.json index f4a6d00..bd2a209 100644 --- a/part9/elm-package.json +++ b/part9/elm-package.json @@ -10,11 +10,9 @@ "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0", - "elm-lang/core": "3.0.0 <= v < 4.0.0", - "evancz/elm-effects": "2.0.0 <= v < 3.0.0", - "evancz/elm-html": "4.0.0 <= v < 5.0.0", - "evancz/elm-http": "3.0.0 <= v < 4.0.0", - "evancz/start-app": "2.0.0 <= v < 3.0.0" + "elm-lang/core": "4.0.1 <= v < 5.0.0", + "elm-lang/html": "1.0.0 <= v < 2.0.0", + "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, - "elm-version": "0.16.0 <= v < 0.17.0" -} \ No newline at end of file + "elm-version": "0.17.0 <= v < 0.18.0" +}