Current section

14 Versions

Jump to

Compare versions

5 files changed
+340 additions
-7 deletions
  @@ -13,7 +13,7 @@ If [available in Hex](https://hex.pm/docs/publish), the package can be installed
13 13 1. Add elmer to your list of dependencies in `mix.exs`:
14 14
15 15 def deps do
16 - [{:elmer, "~> 0.0.10", only: :dev}]
16 + [{:elmer, "~> 0.0.12", only: :dev}]
17 17 end
18 18
19 19 # V1 Roadmap
  @@ -26,4 +26,5 @@ If [available in Hex](https://hex.pm/docs/publish), the package can be installed
26 26 - ~~Cmd generator~~
27 27 - ~~Port generator~~
28 28 - ~~Resource generator (Msg, View, Model, Update)~~
29 + - ~~Hop generator~~
29 30 - Phoenix resource generator (Resource + phoenix gen.json for API)
  @@ -10,12 +10,12 @@
10 10 <<"lib/mix/tasks/gen_port.ex">>,<<"lib/mix/tasks/gen_resource.ex">>,
11 11 <<"lib/mix/tasks/gen_update.ex">>,<<"lib/mix/tasks/gen_view.ex">>,
12 12 <<"lib/mix/tasks/new.ex">>,<<"lib/templates.ex">>,
13 - <<"lib/templates/beginner.ex">>,<<"lib/templates/html.ex">>,
14 - <<"lib/templates/navigation.ex">>,<<"mix.exs">>,<<"README.md">>,
15 - <<"LICENSE.md">>]}.
13 + <<"lib/templates/beginner.ex">>,<<"lib/templates/hop.ex">>,
14 + <<"lib/templates/html.ex">>,<<"lib/templates/navigation.ex">>,<<"mix.exs">>,
15 + <<"README.md">>,<<"LICENSE.md">>]}.
16 16 {<<"licenses">>,[<<"MIT">>]}.
17 17 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/nathanjohnson320/elmer">>}]}.
18 18 {<<"maintainers">>,[<<"Nathan Johnson">>]}.
19 19 {<<"name">>,<<"elmer">>}.
20 20 {<<"requirements">>,[]}.
21 - {<<"version">>,<<"0.0.11">>}.
21 + {<<"version">>,<<"0.0.12">>}.
  @@ -33,6 +33,16 @@ defmodule Mix.Tasks.Elmer.New do
33 33 * Update.elm
34 34 * View.elm
35 35 * elm-package.json
36 + * Hop (https://github.com/sporto/hop) which generates:
37 + * Main.elm
38 + * Models.elm
39 + * Msgs.elm
40 + * Ports.elm
41 + * RouteMsgs.elm
42 + * Routing.Elm
43 + * Update.elm
44 + * View.elm
45 + * elm-package.json
36 46
37 47 These types correspond to the main types of elm programs.
38 48
  @@ -48,7 +58,7 @@ defmodule Mix.Tasks.Elmer.New do
48 58 case File.mkdir(Path.expand(app_path)) do
49 59 :ok ->
50 60 # Get what type of app this is
51 - app_type = Mix.shell.prompt("What type of application is this?\n(B)eginner\n(H)TML\n(N)avigation\n|>")
61 + app_type = Mix.shell.prompt("What type of application is this?\n(B)eginner\n(H)TML\n(N)avigation\n(Ho)p\n|>")
52 62
53 63 # Write the default Main files based on the app type
54 64 create_main(app_path, app_type)
  @@ -85,6 +95,16 @@ defmodule Mix.Tasks.Elmer.New do
85 95 {&Elmer.Templates.Navigation.render_update/0, "Update.elm"},
86 96 {&Elmer.Templates.Navigation.render_view/0, "View.elm"},
87 97 {&Elmer.Templates.Navigation.render_package_json/0, "elm-package.json"}
98 + ],
99 + "ho" => [{&Elmer.Templates.Hop.render_main/0, "Main.elm"},
100 + {&Elmer.Templates.Hop.render_models/0, "Models.elm"},
101 + {&Elmer.Templates.Hop.render_msgs/0, "Msgs.elm"},
102 + {&Elmer.Templates.Hop.render_ports/0, "Ports.elm"},
103 + {&Elmer.Templates.Hop.render_routemsgs/0, "RouteMsgs.elm"},
104 + {&Elmer.Templates.Hop.render_routing/0, "Routing.elm"},
105 + {&Elmer.Templates.Hop.render_update/0, "Update.elm"},
106 + {&Elmer.Templates.Hop.render_view/0, "View.elm"},
107 + {&Elmer.Templates.Hop.render_package_json/0, "elm-package.json"}
88 108 ]
89 109 }
  @@ -0,0 +1,312 @@
1 + defmodule Elmer.Templates.Hop do
2 + @moduledoc """
3 + Renders an elm-html application with navigation leveraging sporto/Hop. Use this if you want to build a single page application. Documentation here: https://github.com/sporto/hop
4 + """
5 + def render_main do
6 + """
7 + module Main exposing (..)
8 +
9 + import Html.App as App
10 + import Navigation
11 + import View exposing (view)
12 + import Models exposing (AppModel, initialModel)
13 + import Update exposing (update)
14 + import Navigation
15 + import Routing exposing (urlParser, urlUpdate)
16 + import RouteMsgs exposing (..)
17 + import Msgs exposing (Msg)
18 + import Ports exposing (subscriptions)
19 + import Hop.Types
20 +
21 +
22 + -- MAIN
23 +
24 +
25 + init : ( Route, Hop.Types.Location ) -> ( AppModel, Cmd Msg )
26 + init ( route, location ) =
27 + let
28 + cmds =
29 + []
30 +
31 + cmd =
32 + Cmd.batch cmds
33 + in
34 + ( Models.initialModel location route, cmd )
35 +
36 +
37 + main : Program Never
38 + main =
39 + Navigation.program urlParser
40 + { init = init
41 + , view = view
42 + , update = update
43 + , urlUpdate = urlUpdate
44 + , subscriptions = subscriptions
45 + }
46 + """
47 + end
48 +
49 + def render_package_json do
50 + """
51 + {
52 + "version": "1.0.0",
53 + "summary": "helpful summary of your project, less than 80 characters",
54 + "repository": "https://github.com/user/project.git",
55 + "license": "BSD3",
56 + "source-directories": [
57 + "."
58 + ],
59 + "exposed-modules": [],
60 + "dependencies": {
61 + "elm-lang/core": "4.0.0 <= v < 5.0.0",
62 + "elm-lang/html": "1.0.0 <= v < 2.0.0",
63 + "elm-lang/navigation": "1.0.0 <= v < 2.0.0",
64 + "evancz/elm-http": "3.0.1 <= v < 4.0.0",
65 + "sporto/hop": "5.0.1 <= v < 6.0.0"
66 + },
67 + "elm-version": "0.17.0 <= v < 0.18.0"
68 + }
69 + """
70 + end
71 +
72 + def render_models do
73 + """
74 + module Models exposing (..)
75 +
76 + import RouteMsgs exposing (Route)
77 + import Hop.Types exposing (Location, Router)
78 +
79 +
80 + type alias AppModel =
81 + { location : Location
82 + , route : Route
83 + }
84 +
85 +
86 + initialModel : Location -> Route -> AppModel
87 + initialModel location route =
88 + { location = location
89 + , route = route
90 + }
91 + """
92 + end
93 +
94 + def render_msgs do
95 + """
96 + module Msgs exposing (..)
97 +
98 + import Hop.Types exposing (Query)
99 +
100 + type Msg
101 + = NoOp
102 + | NavigateTo String
103 + | SetQuery Query
104 + """
105 + end
106 +
107 + def render_ports do
108 + """
109 + port module Ports exposing (..)
110 +
111 + import Models exposing (AppModel)
112 + import Msgs exposing (..)
113 +
114 +
115 + subscriptions : AppModel -> Sub Msg
116 + subscriptions model =
117 + Sub.batch
118 + [ Sub.none
119 + ]
120 + """
121 + end
122 +
123 + def render_routemsgs do
124 + """
125 + module RouteMsgs exposing (..)
126 +
127 + {-|
128 + Define your routes as union types
129 + You need to provide a route for when the current URL doesn't match any known route i.e. NotFoundRoute
130 + -}
131 +
132 +
133 + type Route
134 + = AboutRoute
135 + | MainRoute
136 + | NotFoundRoute
137 + """
138 + end
139 +
140 + def render_routing do
141 + """
142 + module Routing exposing (..)
143 +
144 + import Navigation
145 + import Hop exposing (makeUrl, makeUrlFromLocation, matchUrl, setQuery)
146 + import Hop.Types exposing (Config, Query, Location, PathMatcher, Router)
147 + import Hop.Matchers exposing (..)
148 + import Msgs exposing (..)
149 + import RouteMsgs exposing (..)
150 + import Models exposing (AppModel)
151 +
152 +
153 + -- ROUTES
154 +
155 +
156 + {-|
157 + Define matchers
158 + For example:
159 + match1 AboutRoute "/about"
160 + Will match "/about" and return AboutRoute
161 + match2 UserRoute "/users/" int
162 + Will match "/users/1" and return (UserRoute 1)
163 + `int` is a matcher that matches only integers, for a string use `str` e.g.
164 + match2 UserRoute "/users/" str
165 + Would match "/users/abc"
166 + -}
167 + matchers : List (PathMatcher Route)
168 + matchers =
169 + [ match1 MainRoute ""
170 + , match1 AboutRoute "/about"
171 + ]
172 +
173 +
174 + {-|
175 + Define your router configuration
176 + Use `hash = True` for hash routing e.g. `#/users/1`
177 + Use `hash = False` for push state e.g. `/users/1`
178 + The `basePath` is only used for path routing.
179 + This is useful if you application is not located at the root of a url e.g. `/app/v1/users/1` where `/app/v1` is the base path.
180 + - `matchers` is your list of matchers defined above.
181 + - `notFound` is a route that will be returned when the path doesn't match any known route.
182 + -}
183 + routerConfig : Config Route
184 + routerConfig =
185 + { hash = True
186 + , basePath = ""
187 + , matchers = matchers
188 + , notFound = NotFoundRoute
189 + }
190 +
191 +
192 + urlParser : Navigation.Parser ( Route, Hop.Types.Location )
193 + urlParser =
194 + Navigation.makeParser (.href >> matchUrl routerConfig)
195 +
196 +
197 + urlUpdate : ( Route, Hop.Types.Location ) -> AppModel -> ( AppModel, Cmd Msg )
198 + urlUpdate ( route, location ) model =
199 + ( { model | route = route, location = location }, Cmd.none )
200 + """
201 + end
202 +
203 + def render_update do
204 + """
205 + module Update exposing (..)
206 +
207 + import Navigation
208 + import Hop exposing (makeUrl, makeUrlFromLocation, setQuery)
209 + import Models exposing (..)
210 + import Msgs exposing (..)
211 + import Routing exposing (routerConfig)
212 +
213 +
214 + update : Msg -> AppModel -> ( AppModel, Cmd Msg )
215 + update msg model =
216 + case msg of
217 + NavigateTo path ->
218 + let
219 + command =
220 + makeUrl routerConfig path
221 + |> Navigation.modifyUrl
222 + in
223 + ( model, command )
224 +
225 + SetQuery query ->
226 + let
227 + command =
228 + model.location
229 + |> setQuery query
230 + |> makeUrlFromLocation routerConfig
231 + |> Navigation.modifyUrl
232 + in
233 + ( model, command )
234 +
235 + NoOp ->
236 + ( model, Cmd.none )
237 + """
238 + end
239 +
240 + def render_view do
241 + """
242 + module View exposing (..)
243 +
244 + import Html exposing (..)
245 + import Html.App as App
246 + import Html.Events exposing (onClick)
247 + import Html.Attributes exposing (..)
248 + import Dict
249 + import Msgs exposing (..)
250 + import RouteMsgs exposing (..)
251 + import Models exposing (..)
252 +
253 +
254 + view : AppModel -> Html Msg
255 + view model =
256 + div []
257 + [ menu model
258 + , pageView model
259 + ]
260 +
261 +
262 + menu : AppModel -> Html Msg
263 + menu model =
264 + div []
265 + [ div []
266 + [ button
267 + [ class "btnMain"
268 + , onClick (NavigateTo "")
269 + ]
270 + [ text "Main" ]
271 + , button
272 + [ class "btnAbout"
273 + , onClick (NavigateTo "about")
274 + ]
275 + [ text "About" ]
276 + , button
277 + [ class "btnQuery"
278 + , onClick (SetQuery (Dict.singleton "keyword" "elm"))
279 + ]
280 + [ text "Set query string" ]
281 + , currentQuery model
282 + ]
283 + ]
284 +
285 +
286 + currentQuery : AppModel -> Html msg
287 + currentQuery model =
288 + let
289 + query =
290 + toString model.location.query
291 + in
292 + span [ class "labelQuery" ]
293 + [ text query ]
294 +
295 +
296 + {-|
297 + Views can decide what to show using `model.route`.
298 + -}
299 + pageView : AppModel -> Html msg
300 + pageView model =
301 + case model.route of
302 + MainRoute ->
303 + div [] [ h2 [ class "title" ] [ text "Main" ] ]
304 +
305 + AboutRoute ->
306 + div [] [ h2 [ class "title" ] [ text "About" ] ]
307 +
308 + NotFoundRoute ->
309 + div [] [ h2 [ class "title" ] [ text "Not found" ] ]
310 + """
311 + end
312 + end
  @@ -7,7 +7,7 @@ defmodule Elmer.Mixfile do
7 7 description: "Helper mix tasks for generating elm files like Main, Ports, Models, Msgs, etc.",
8 8 source_url: "https://github.com/nathanjohnson320/elmer",
9 9 package: package,
10 - version: "0.0.11",
10 + version: "0.0.12",
11 11 elixir: "~> 1.2",
12 12 build_embedded: Mix.env == :prod,
13 13 start_permanent: Mix.env == :prod,