From: Garrett S. <g...@rr...> - 2009-06-27 19:01:00
|
I'm working on an app that uses various appmods. I'm wondering what the typical developer workflow for this type of development is. The obvious problem is that the Erlang source files are changing all the time, requiring a compile and reload. Do folks typically do this the long/obvious way (e.g. run make:all()/make + restart yaws) or are there some common shortcuts? I tried using the --load command (on Windows) but kept getting the yaws usage printout as if I had misspelled something. That still isn't a whole lot faster than just restarting yaws. Garrett |
From: Steve V. <vi...@ie...> - 2009-06-27 22:00:38
|
On Sat, Jun 27, 2009 at 2:59 PM, Garrett Smith<g...@rr...> wrote: > I'm working on an app that uses various appmods. I'm wondering what the > typical developer workflow for this type of development is. > > The obvious problem is that the Erlang source files are changing all > the time, requiring a compile and reload. Do folks typically do this the > long/obvious way (e.g. run make:all()/make + restart yaws) or are there > some common shortcuts? No need to restart yaws -- just use the -i option to yaws to start it in interactive mode. That gives you an erl shell into the running yaws, and in that shell you can use the l(module_name) function to reload a newer version of a module. With -i in effect browsers and other web client user agents see the same behavior from yaws that they always see, but through the interactive shell you're able to interact with yaws programmatically -- you can use erlang tracing, the debugger, appmon, etc. BTW, if these facilities are unfamiliar to you, get Francesco's and Simon's new book "Erlang Programming" (<http://oreilly.com/catalog/9780596518189/>) -- it's outstanding. --steve |
From: Robert R. <rtr...@go...> - 2009-06-29 15:24:13
|
On Sat, Jun 27, 2009 at 11:00 PM, Steve Vinoski <vi...@ie...> wrote: > On Sat, Jun 27, 2009 at 2:59 PM, Garrett Smith<g...@rr...> wrote: > > I'm working on an app that uses various appmods. I'm wondering what the > > typical developer workflow for this type of development is. > > > > The obvious problem is that the Erlang source files are changing all > > the time, requiring a compile and reload. Do folks typically do this the > > long/obvious way (e.g. run make:all()/make + restart yaws) or are there > > some common shortcuts? > > No need to restart yaws -- just use the -i option to yaws to start it > in interactive mode. That gives you an erl shell into the running > yaws, and in that shell you can use the l(module_name) function to > reload a newer version of a module. > > With -i in effect browsers and other web client user agents see the > same behavior from yaws that they always see, but through the > interactive shell you're able to interact with yaws programmatically > -- you can use erlang tracing, the debugger, appmon, etc. BTW, if > these facilities are unfamiliar to you, get Francesco's and Simon's > new book "Erlang Programming" > (<http://oreilly.com/catalog/9780596518189/>) -- it's outstanding. > > --steve > There's a wee module called reloader that comes with mochiweb. Very handy and simple. It should be trivial to tailor it to your needs. Robby |
From: Garrett S. <g...@rr...> - 2009-06-29 15:26:08
|
(Repost to group...I had forgotten to reply-to-all.) Thanks Steve. This is helpful (and I also picked up the book!) Does anyone here develop entirely in Emacs (using the embedded shell) or is it standard practice to run with yaws -i for appmod work? ----- "Steve Vinoski" <vi...@ie...> wrote: > No need to restart yaws -- just use the -i option to yaws to start it > in interactive mode. That gives you an erl shell into the running > yaws, and in that shell you can use the l(module_name) function to > reload a newer version of a module. > > With -i in effect browsers and other web client user agents see the > same behavior from yaws that they always see, but through the > interactive shell you're able to interact with yaws programmatically > -- you can use erlang tracing, the debugger, appmon, etc. BTW, if > these facilities are unfamiliar to you, get Francesco's and Simon's > new book "Erlang Programming" > (<http://oreilly.com/catalog/9780596518189/>) -- it's outstanding. |
From: Edward G. <edw...@ra...> - 2009-06-29 15:56:36
|
Emacs is probably the rule around here, not the exception ;-) Distel goes a long way to alleviating some of the workflow issues you raise. Edward On Mon, 2009-06-29 at 09:47 -0500, Garrett Smith wrote: > (Repost to group...I had forgotten to reply-to-all.) > > Thanks Steve. This is helpful (and I also picked up the book!) > > Does anyone here develop entirely in Emacs (using the embedded shell) > or is it standard practice to run with yaws -i for appmod work? *********************************************************************** This e-mail and its attachments are confidential, legally privileged, may be subject to copyright and sent solely for the attention of the addressee(s). Any unauthorized use or disclosure is prohibited. Statements and opinions expressed in this e-mail may not represent those of Radialpoint. Le contenu de ce courriel est confidentiel, privilégié et peut être soumis à des droits d'auteur. Il est envoyé à l'intention exclusive de son ou de ses destinataires. Il est interdit de l'utiliser ou de le divulguer sans autorisation. Les opinions exprimées dans le présent courriel peuvent diverger de celles de Radialpoint. |
From: Edward G. <edw...@ra...> - 2009-06-29 15:52:13
|
On Sat, 2009-06-27 at 13:59 -0500, Garrett Smith wrote: > I'm working on an app that uses various appmods. I'm wondering what the > typical developer workflow for this type of development is. > Do folks typically do this the > long/obvious way (e.g. run make:all()/make + restart yaws) or are > there some common shortcuts? Typically (at least for me) the game is getting a specific test to pass, so I'm usually only interested to compile and load a couple of modules before running my test: 1> c(foo). ok 2> c(foo_test). ok 3> foo_test:current_test(). The c() built-in compiles, purges and loads the module it's passed so there's no need to additionally `l(foo)'. And like Steve mentioned, the above can execute in an erlang shell that started yaws in interactive mode so yaws reloads the changes. It can get tiring to keep re-typing c(foo) and c(foo_test) and c(whatever_else) and foo_test:current_test() so I often use a wrapper: 3> F = fun() -> c(foo), c(foo_test), foo_test:current_test() end. Then all you need is: 4> F(). I use this a lot; it's extremely quick and convenient, not to mention having a REPL in which to perform exploratory testing. Occasionally a test will affect several modules in which case you want to reload all your modules (as you allude to above). We have a quick and dirty utility function for this, it reloads all the modules under the current working directory: load_all() -> {ok, Cwd} = file:get_cwd(), ModulesUnderCwd = [ Module || {Module,Path} <- code:all_loaded(), is_list(Path) andalso string:str(Path, Cwd) > 0 andalso Module =/= error ], log("Reloading: ~n"), [ shell_default:l(M) || M <- ModulesUnderCwd ]. So we can just do a 5> util:load_all(). That function only reloads modules, we use rake to build our code so we issue a `rake' prior to calling the above. Hope this helps, Edward P.S. I would also like to hear from more experienced Erlangers how they approach some of these micro-tasks. *********************************************************************** This e-mail and its attachments are confidential, legally privileged, may be subject to copyright and sent solely for the attention of the addressee(s). Any unauthorized use or disclosure is prohibited. Statements and opinions expressed in this e-mail may not represent those of Radialpoint. Le contenu de ce courriel est confidentiel, privilégié et peut ętre soumis ŕ des droits d'auteur. Il est envoyé ŕ l'intention exclusive de son ou de ses destinataires. Il est interdit de l'utiliser ou de le divulguer sans autorisation. Les opinions exprimées dans le présent courriel peuvent diverger de celles de Radialpoint. |
From: Claes W. <kl...@ta...> - 2009-06-29 19:13:31
Attachments:
user_default.erl
|
Edward Garson wrote: > > 3> F = fun() -> c(foo), c(foo_test), foo_test:current_test() end. > > Then all you need is: > > 4> F(). > > I use this a lot; it's extremely quick and convenient, not to mention > having a REPL in which to perform exploratory testing. > > Occasionally a test will affect several modules in which case you want > to reload all your modules (as you allude to above). We have a quick and > dirty utility function for this, it reloads all the modules under the > current working directory: > > load_all() -> > {ok, Cwd} = file:get_cwd(), > ModulesUnderCwd = [ Module || {Module,Path} <- code:all_loaded(), > is_list(Path) andalso string:str(Path, Cwd) > 0 andalso Module =/= > error ], > log("Reloading: ~n"), > [ shell_default:l(M) || M <- ModulesUnderCwd ]. > > So we can just do a > > 5> util:load_all(). I work similarly - compiling from the shell with c(Mod) mostly only works for micro tests - pretty soon you're gonna want proper Makefiles for all you work. The problem from 'erl' p.o.v with that, is re-loading all that got recompiled. What I do a lot is replace the std user_defaults.erl with a version that has some funky functions. In particular - relating to the above discussion there is: > lm() That reloads all recompiled modules. There is a lot of good stuff in my user_default.erl - so please - reuse - I attach the module. For those of you that don't (yet) know what user_default.erl is - it's the module that gets called when we invoke things like i() or c(Mod) from the shell. So to have your own version of user_default.erl you can either 1) put is somewhere and have your $HOME/.erlang setup the path to that place and load your own version 2) Have the module as a part of you project files. Also - have a look at the tp/1 tpl/1 functions - I use them all the time. /klacke |
From: Torbjorn T. <to...@to...> - 2009-06-30 09:10:02
|
Regarding the tp/N functions. Lately, I've been totally addicted to redbug, see: http://code.google.com/p/eper/ It is a layer on top of the dbg-tracing stuff which adds some safety nets to avoid choking your production system from too much trace info being produced. So typically, if you want to trace function F in module M, but no longer than 10 seconds and not more than 100 trace messages, show the returend result from the function as well as the call stack: redbug:start(10000, 100, [{M,F,[return,stack]}]). You can also specify argument patterns to trace on a particular function clause. redbug was written by Mats Cronqvist to be used for debugging the Ericsson AXD301 exchanges out in the field. At Kreditor we now also use it when tracing in our production system. Cheers, Tobbe Claes Wikstrom wrote: > Edward Garson wrote: >> >> 3> F = fun() -> c(foo), c(foo_test), foo_test:current_test() end. >> Then all you need is: >> >> 4> F(). >> >> I use this a lot; it's extremely quick and convenient, not to mention >> having a REPL in which to perform exploratory testing. >> >> Occasionally a test will affect several modules in which case you want >> to reload all your modules (as you allude to above). We have a quick and >> dirty utility function for this, it reloads all the modules under the >> current working directory: >> >> load_all() -> >> {ok, Cwd} = file:get_cwd(), >> ModulesUnderCwd = [ Module || {Module,Path} <- code:all_loaded(), >> is_list(Path) andalso string:str(Path, Cwd) > 0 andalso Module =/= >> error ], >> log("Reloading: ~n"), >> [ shell_default:l(M) || M <- ModulesUnderCwd ]. >> >> So we can just do a >> >> 5> util:load_all(). > > > I work similarly - compiling from the shell with c(Mod) mostly > only works for micro tests - pretty soon you're gonna want proper > Makefiles for all you work. The problem from 'erl' p.o.v with that, > is re-loading all that got recompiled. > > What I do a lot is replace the std user_defaults.erl with a version > that has some funky functions. In particular - relating to the above > discussion there is: > > > lm() > > That reloads all recompiled modules. There is a lot of good stuff in > my user_default.erl - so please - reuse - I attach the module. > > For those of you that don't (yet) know what user_default.erl is - it's > the module that gets called when we invoke things like i() or c(Mod) > from the shell. So to have your own version of user_default.erl you > can either > > 1) put is somewhere and have your $HOME/.erlang setup the path to that > place and load your own version > > 2) Have the module as a part of you project files. > > Also - have a look at the tp/1 tpl/1 functions - I use them all the time. > > /klacke > > > > > > > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------------ > > > ------------------------------------------------------------------------ > > _______________________________________________ > Erlyaws-list mailing list > Erl...@li... > https://lists.sourceforge.net/lists/listinfo/erlyaws-list |
From: wde <wd...@fr...> - 2009-06-29 21:19:09
|
I didn't know the user_default module thank you wde ======= le 29/06/2009, 21:13:20 vous écriviez: ======= >Edward Garson wrote: >> >> 3> F = fun() -> c(foo), c(foo_test), foo_test:current_test() end. >> >> Then all you need is: >> >> 4> F(). >> >> I use this a lot; it's extremely quick and convenient, not to mention >> having a REPL in which to perform exploratory testing. >> >> Occasionally a test will affect several modules in which case you want >> to reload all your modules (as you allude to above). We have a quick and >> dirty utility function for this, it reloads all the modules under the >> current working directory: >> >> load_all() -> >> {ok, Cwd} = file:get_cwd(), >> ModulesUnderCwd = [ Module || {Module,Path} <- code:all_loaded(), >> is_list(Path) andalso string:str(Path, Cwd) > 0 andalso Module =/= >> error ], >> log("Reloading: ~n"), >> [ shell_default:l(M) || M <- ModulesUnderCwd ]. >> >> So we can just do a >> >> 5> util:load_all(). > > >I work similarly - compiling from the shell with c(Mod) mostly >only works for micro tests - pretty soon you're gonna want proper >Makefiles for all you work. The problem from 'erl' p.o.v with that, >is re-loading all that got recompiled. > >What I do a lot is replace the std user_defaults.erl with a version >that has some funky functions. In particular - relating to the above >discussion there is: > > > lm() > >That reloads all recompiled modules. There is a lot of good stuff in >my user_default.erl - so please - reuse - I attach the module. > >For those of you that don't (yet) know what user_default.erl is - it's >the module that gets called when we invoke things like i() or c(Mod) >from the shell. So to have your own version of user_default.erl you >can either > >1) put is somewhere and have your $HOME/.erlang setup the path to that > place and load your own version > >2) Have the module as a part of you project files. > >Also - have a look at the tp/1 tpl/1 functions - I use them all the time. > >/klacke > > > > > > >------------------------------------------------------------------------------ > >_______________________________________________ >Erlyaws-list mailing list >Erl...@li... >https://lists.sourceforge.net/lists/listinfo/erlyaws-list > = = = = = = = = = ========= = = = = = = = = = = wde wd...@fr... 29/06/2009 |
From: Hans U. N. <hu...@n-...> - 2009-07-24 14:52:46
|
On Mon, 29 Jun 2009 11:52:04 -0400 Edward Garson <edw...@ra...> wrote: > Typically (at least for me) the game is getting a specific test to > pass, so I'm usually only interested to compile and load a couple of > modules before running my test: > > 1> c(foo). > ok > 2> c(foo_test). > ok [...] > 3> F = fun() -> c(foo), c(foo_test), foo_test:current_test() end. > > Then all you need is: > > 4> F(). > > I use this a lot; it's extremely quick and convenient, not to mention > having a REPL in which to perform exploratory testing. I have been using something like that for some time as well, but have often run into a serious problem: When any of those compilations fails, and I do not very closely watch the compilation output, I don't notice the failure and make the wrong assumptions about the code which now runs during the test case. Therefore, I am now habitually changing all my 5> c(foo). calls to 6> {ok,_} = c(foo). That gives me a clear exception before running the test case which makes sure that I notice it. -- Hans Ulrich Niedermann |
From: Edward G. <edw...@ra...> - 2009-07-24 15:08:24
|
Good one Hans, I'm going to steal that trick ^_^... On Fri, 2009-07-24 at 16:33 +0200, Hans Ulrich Niedermann wrote: > On Mon, 29 Jun 2009 11:52:04 -0400 > Edward Garson <edw...@ra...> wrote: > > > Typically (at least for me) the game is getting a specific test to > > pass, so I'm usually only interested to compile and load a couple of > > modules before running my test: > > > > 1> c(foo). > > ok > > 2> c(foo_test). > > ok > > [...] > > > 3> F = fun() -> c(foo), c(foo_test), foo_test:current_test() end. > > > > Then all you need is: > > > > 4> F(). > > > > I use this a lot; it's extremely quick and convenient, not to mention > > having a REPL in which to perform exploratory testing. > > I have been using something like that for some time as well, but have > often run into a serious problem: When any of those compilations fails, > and I do not very closely watch the compilation output, I don't notice > the failure and make the wrong assumptions about the code which now runs > during the test case. > > Therefore, I am now habitually changing all my > > 5> c(foo). > > calls to > > 6> {ok,_} = c(foo). > > That gives me a clear exception before running the test case which > makes sure that I notice it. > *********************************************************************** This e-mail and its attachments are confidential, legally privileged, may be subject to copyright and sent solely for the attention of the addressee(s). Any unauthorized use or disclosure is prohibited. Statements and opinions expressed in this e-mail may not represent those of Radialpoint. Le contenu de ce courriel est confidentiel, privilégié et peut être soumis à des droits d'auteur. Il est envoyé à l'intention exclusive de son ou de ses destinataires. Il est interdit de l'utiliser ou de le divulguer sans autorisation. Les opinions exprimées dans le présent courriel peuvent diverger de celles de Radialpoint. |