From 30ee5d0352eb990b9649cc2158bbe66cdd98658c Mon Sep 17 00:00:00 2001 From: Peter Damoc Date: Wed, 2 Mar 2016 22:35:40 +0200 Subject: [PATCH] Elm version. --- elm-api-extend/Button.elm | 28 +++++++ elm-api-extend/Counter.elm | 28 +++++++ elm-api-extend/Main.elm | 115 ++++++++++++++++++++++++++++ elm-api-extend/README.md | 9 +++ elm-api-extend/RandomGif.elm | 107 ++++++++++++++++++++++++++ elm-api-extend/RandomGifPair.elm | 71 +++++++++++++++++ elm-api-extend/RandomPairOfPair.elm | 71 +++++++++++++++++ elm-api-extend/elm-package.json | 18 +++++ 8 files changed, 447 insertions(+) create mode 100644 elm-api-extend/Button.elm create mode 100644 elm-api-extend/Counter.elm create mode 100644 elm-api-extend/Main.elm create mode 100644 elm-api-extend/README.md create mode 100644 elm-api-extend/RandomGif.elm create mode 100644 elm-api-extend/RandomGifPair.elm create mode 100644 elm-api-extend/RandomPairOfPair.elm create mode 100644 elm-api-extend/elm-package.json diff --git a/elm-api-extend/Button.elm b/elm-api-extend/Button.elm new file mode 100644 index 0000000..97f31bf --- /dev/null +++ b/elm-api-extend/Button.elm @@ -0,0 +1,28 @@ +module Button where + +import Html exposing (..) +import Html.Attributes exposing (style) +import Html.Events exposing (onClick) + +type Action = Click + +type alias Model = Bool + +init : Model +init = True + +update : Action -> Model -> Model +update action model = not model + +view : Signal.Address Action -> Model -> Html +view address model = + button + [ style [("backgroundColor", if model then "green" else "red")] + , onClick address Click + ] + [ text "Click"] + + + +isActive : Model -> Bool +isActive model = model \ No newline at end of file diff --git a/elm-api-extend/Counter.elm b/elm-api-extend/Counter.elm new file mode 100644 index 0000000..afe748e --- /dev/null +++ b/elm-api-extend/Counter.elm @@ -0,0 +1,28 @@ +module Counter where + +import Html exposing (..) + +type Action = Increment Bool + +type alias Model = Int + +init : Model +init = 0 + +update : Action -> Model -> Model +update action model = + case action of + Increment True -> + if model >= 10 then model + 2 else model + 1 + Increment False -> + model + 1 + +increment : Bool -> Model -> Model +increment button model = + update (Increment button) model + + +view : Signal.Address Action -> Model -> Html +view address model = + div [] + [ text <| toString model] diff --git a/elm-api-extend/Main.elm b/elm-api-extend/Main.elm new file mode 100644 index 0000000..927a75f --- /dev/null +++ b/elm-api-extend/Main.elm @@ -0,0 +1,115 @@ +import Html exposing (..) + +import StartApp +import Task exposing (Task) +import Effects exposing (Effects, Never) + +import RandomGif +import RandomGifPair +import RandomPairOfPair +import Button +import Counter + + +type Action = + Top RandomGif.Action | Pair RandomGifPair.Action + | PairOfPair RandomPairOfPair.Action + | Button Button.Action | Counter Counter.Action + +type alias Model = + { topGif : RandomGif.Model + , gifPair : RandomGifPair.Model + , gifPairOfPair : RandomPairOfPair.Model + , button: Button.Model + , counter : Counter.Model + } + +init : (Model, Effects Action) +init = + let + (topGif, topFx) = RandomGif.init "dogs" + (gifPair, pairFx) = RandomGifPair.init "cats" "lemurs" + (gifPairOfPair', pairOfPaiFx) = RandomPairOfPair.init "unicorns" "minions" "pokemon" "lizards" + model = + { topGif = topGif, gifPair = gifPair + , gifPairOfPair = gifPairOfPair' + , button=Button.init, counter = Counter.init } + + in + (model, Effects.batch [Effects.map Top topFx, Effects.map Pair pairFx, Effects.map PairOfPair pairOfPaiFx]) + + +update : Action -> Model -> (Model, Effects Action) +update action model = + case action of + Top act -> + let + (topGif', fx) = RandomGif.update act model.topGif + counter' = + if RandomGif.isNewGif act + then Counter.increment (Button.isActive model.button) model.counter + else model.counter + in + ({ model | topGif = topGif', counter=counter'}, Effects.map Top fx) + + Pair act -> + let + (gifPair', fx) = RandomGifPair.update act model.gifPair + counter' = + if RandomGifPair.isNewGif act + then Counter.increment (Button.isActive model.button) model.counter + else model.counter + in + ({ model | gifPair = gifPair', counter=counter'}, Effects.map Pair fx) + + PairOfPair act -> + let + (gifPairOfPair', fx) = RandomPairOfPair.update act model.gifPairOfPair + counter' = + if RandomPairOfPair.isNewGif act + then Counter.increment (Button.isActive model.button) model.counter + else model.counter + in + ({ model | gifPairOfPair = gifPairOfPair', counter=counter'}, Effects.map PairOfPair fx) + + Button act -> + let + button' = Button.update act model.button + in + ({ model | button = button'}, Effects.none) + + _ -> + (model, Effects.none) + + +view : Signal.Address Action -> Model -> Html +view address model = + let + fwd = Signal.forwardTo address + sep = br [] [] + in + div [] + [ RandomGif.view (fwd Top) model.topGif + , sep + , RandomGifPair.view (fwd Pair) model.gifPair + , sep + , RandomPairOfPair.view (fwd PairOfPair) model.gifPairOfPair + , sep + , Button.view (fwd Button) model.button + , sep + , Counter.view (fwd Counter) model.counter + ] + +app : StartApp.App Model +app = StartApp.start + { init = init + , update = update + , view = view + , inputs = []} + +main : Signal Html +main = app.html + + +port tasks : Signal (Task Never ()) +port tasks = app.tasks \ No newline at end of file diff --git a/elm-api-extend/README.md b/elm-api-extend/README.md new file mode 100644 index 0000000..4547e35 --- /dev/null +++ b/elm-api-extend/README.md @@ -0,0 +1,9 @@ +# Approach + +The main strategy for this approach is to extend the API of each component to include helpers. + +I have put the business logic into `Counter.elm` and exposed an `increment` function that increments the model based on the button state that it receives. + +The RandomGif family of components API is augmented with a function that answeres the question "is this action a NewGif?" + +RandomGif implements the direct `NewGif` detection, each subsequent enclosure implements its own version using it's child API. diff --git a/elm-api-extend/RandomGif.elm b/elm-api-extend/RandomGif.elm new file mode 100644 index 0000000..531828c --- /dev/null +++ b/elm-api-extend/RandomGif.elm @@ -0,0 +1,107 @@ +module RandomGif where + +import Effects exposing (Effects, Never) +import Html exposing (..) +import Html.Attributes exposing (style) +import Html.Events exposing (onClick) +import Http +import Json.Decode as Json +import Task + + +-- MODEL + +type alias Model = + { topic : String + , gifUrl : String + } + + +init : String -> (Model, Effects Action) +init topic = + ( Model topic waiting + , getRandomGif topic + ) + +-- UPDATE + +type Action + = RequestMore + | NewGif (Maybe String) + +isNewGif : Action -> Bool +isNewGif action = + case action of + NewGif _ -> True + _ -> False + +update : Action -> Model -> (Model, Effects Action) +update action model = + case action of + RequestMore -> + (model, getRandomGif model.topic) + + NewGif maybeUrl -> + ( Model model.topic (Maybe.withDefault model.gifUrl maybeUrl) + , Effects.none + ) + + +-- VIEW + +(=>) : a -> b -> ( a, b ) +(=>) = (,) + + +view : Signal.Address Action -> Model -> Html +view address model = + div [ style [ "width" => "200px" ] ] + [ h2 [headerStyle] [text model.topic] + , div [imgStyle model.gifUrl] [] + , button [ onClick address RequestMore ] [ text "More Please!" ] + ] + + +headerStyle : Attribute +headerStyle = + style + [ "width" => "200px" + , "text-align" => "center" + ] + + +imgStyle : String -> Attribute +imgStyle url = + style + [ "display" => "inline-block" + , "width" => "200px" + , "height" => "200px" + , "background-position" => "center center" + , "background-size" => "cover" + , "background-image" => ("url('" ++ url ++ "')") + ] + +waiting : String +waiting = "data:image/gif;base64,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" + +-- EFFECTS + +getRandomGif : String -> Effects Action +getRandomGif topic = + Http.get decodeUrl (randomUrl topic) + |> Task.toMaybe + |> Task.map NewGif + |> Effects.task + + +randomUrl : String -> String +randomUrl topic = + Http.url "http://api.giphy.com/v1/gifs/random" + [ "api_key" => "dc6zaTOxFJmzC" + , "tag" => topic + ] + + +decodeUrl : Json.Decoder String +decodeUrl = + Json.at ["data", "image_url"] Json.string diff --git a/elm-api-extend/RandomGifPair.elm b/elm-api-extend/RandomGifPair.elm new file mode 100644 index 0000000..e6c658b --- /dev/null +++ b/elm-api-extend/RandomGifPair.elm @@ -0,0 +1,71 @@ +module RandomGifPair where + +import Effects exposing (Effects) +import Html exposing (..) +import Html.Attributes exposing (..) + +import RandomGif + + +-- MODEL + +type alias Model = + { left : RandomGif.Model + , right : RandomGif.Model + } + + +init : String -> String -> (Model, Effects Action) +init leftTopic rightTopic = + let + (left, leftFx) = RandomGif.init leftTopic + (right, rightFx) = RandomGif.init rightTopic + in + ( Model left right + , Effects.batch + [ Effects.map Left leftFx + , Effects.map Right rightFx + ] + ) + + +-- UPDATE + +type Action + = Left RandomGif.Action + | Right RandomGif.Action + +isNewGif : Action -> Bool +isNewGif action = + case action of + Left act -> RandomGif.isNewGif act + Right act -> RandomGif.isNewGif act + +update : Action -> Model -> (Model, Effects Action) +update action model = + case action of + Left act -> + let + (left, fx) = RandomGif.update act model.left + in + ( Model left model.right + , Effects.map Left fx + ) + + Right act -> + let + (right, fx) = RandomGif.update act model.right + in + ( Model model.left right + , Effects.map Right fx + ) + + +-- VIEW + +view : Signal.Address Action -> Model -> Html +view address model = + div [ style [ ("display", "flex") ] ] + [ RandomGif.view (Signal.forwardTo address Left) model.left + , RandomGif.view (Signal.forwardTo address Right) model.right + ] diff --git a/elm-api-extend/RandomPairOfPair.elm b/elm-api-extend/RandomPairOfPair.elm new file mode 100644 index 0000000..ff646c4 --- /dev/null +++ b/elm-api-extend/RandomPairOfPair.elm @@ -0,0 +1,71 @@ +module RandomPairOfPair where + +import Effects exposing (Effects) +import Html exposing (..) +import Html.Attributes exposing (..) + +import RandomGifPair + + +-- MODEL + +type alias Model = + { left : RandomGifPair.Model + , right : RandomGifPair.Model + } + + +init : String -> String -> String -> String -> (Model, Effects Action) +init leftTopic1 leftTopic2 rightTopic1 rightTopic2 = + let + (left, leftFx) = RandomGifPair.init leftTopic1 leftTopic2 + (right, rightFx) = RandomGifPair.init rightTopic1 rightTopic2 + in + ( Model left right + , Effects.batch + [ Effects.map Left leftFx + , Effects.map Right rightFx + ] + ) + + +-- UPDATE + +type Action + = Left RandomGifPair.Action + | Right RandomGifPair.Action + +isNewGif : Action -> Bool +isNewGif action = + case action of + Left act -> RandomGifPair.isNewGif act + Right act -> RandomGifPair.isNewGif act + +update : Action -> Model -> (Model, Effects Action) +update action model = + case action of + Left act -> + let + (left, fx) = RandomGifPair.update act model.left + in + ( Model left model.right + , Effects.map Left fx + ) + + Right act -> + let + (right, fx) = RandomGifPair.update act model.right + in + ( Model model.left right + , Effects.map Right fx + ) + + +-- VIEW + +view : Signal.Address Action -> Model -> Html +view address model = + div [ style [ ("display", "flex") ] ] + [ RandomGifPair.view (Signal.forwardTo address Left) model.left + , RandomGifPair.view (Signal.forwardTo address Right) model.right + ] diff --git a/elm-api-extend/elm-package.json b/elm-api-extend/elm-package.json new file mode 100644 index 0000000..e7f3ef1 --- /dev/null +++ b/elm-api-extend/elm-package.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0", + "summary": "helpful summary of your project, less than 80 characters", + "repository": "https://github.com/user/project.git", + "license": "BSD3", + "source-directories": [ + "." + ], + "exposed-modules": [], + "dependencies": { + "elm-lang/core": "3.0.0 <= v < 4.0.0", + "evancz/elm-effects": "2.0.1 <= v < 3.0.0", + "evancz/elm-html": "4.0.2 <= v < 5.0.0", + "evancz/elm-http": "3.0.0 <= v < 4.0.0", + "evancz/start-app": "2.0.2 <= v < 3.0.0" + }, + "elm-version": "0.16.0 <= v < 0.17.0" +} \ No newline at end of file