Hello World! == Description == This tutorial shows how to implement a minimalist HOP program. It involves only //server// programming. It teaches how to program a HOP ,( ( "weblet") "service.wiki") that displays the string ++Hello World!++ in web browser. == Preliminary considerations == When developing a Web application it is highly recommended to **disable the caching mechanisms** of the browser used for testing. Caching improve the overall performance of the browser but it also introduces effects that make debugging harder. ~~ Some browsers propose settings for augmenting the number of reported errors in HTML document, CSS style sheet, and JavaScript code. We recommend to use the maximum verbosity. On [[http://www.mozilla.org|Firefox]] this can be accomplished using the fake URL ++about:config++. On this configuration panel, select the following options: javascript.options.strict: true javascript.options.showInConsole: true == Preparing Hop == HOP can only execute programs on behalf of //authenticated users//. For that, before executing any program, **user accounts** must created. A user account specifies which program a user may run and which directories a user may access to. The easiest way to create a user account is to use the HOP [[/hop/wizard|Wizard]] weblet. If you don't feel like using this weblet, you can add in your HOP RC file (see ,( "RC file" "07-hoprc.wiki")) expressions such as: (add-user! "test" :password "4f4ac66d8c71f57bf04d2e00b5360cc8" :directories '* :services '*) This specifies that the user ++test++ may execute all the available programs and that he may access all the directories accessible by the user that is running the HOP process on the host server. The password encrypted key must be generated with [[/hop/epassword|Epassword]]. == Defining the service == In this example, we define a ,( "service" "service.wiki") named ++hello++. A named service is defined using the ,( "define-service" "service.wiki") special form. (define-service (hello/world) ( ( "Hello World!"))) (define (say-hello) ( ( ( :href "/hop/hello/world" "click me")))) (define-service (hello) (say-hello)) (say-hello) This automatically binds the URL ++/hop/hello++ to the service. The prefix ++/hop++ is used for all the URLs associated with services. Let's assume that ++hop++ is running and that it waits connections to be established on the port ++8080++. The actual URL ,( "http://localhost:8080/hop/hello") refers to our previously defined service. Since HOP predefines the alias //hop// for ++localhost:8080++ hence, provided you have configured your browser for using HOP has your web proxy, the URL ,( "http://localhost:8080/hop/hello") also refers to our service. ~~ Once, you have evaluated the code above once, the service ++hello++ being bound, you can directly go to the URL [[http://localhost:8080/hop/hello]] in your browser. ,( :style { color: red; font-weight: bold } "Note:") For the sake of security, the default Hop setting disables services re-definition. Hence, a module loaded afterward cannot change the definition of services already existing. As a consequence, the examples of the documentation that define services can only be executed once (//i.e.,,// the "Run" button can only be clicked once). This behavior can be changed when spawning Hop. Invoking Hop with either the ++-g++ (debug) or ++-allow-service-override++ will enable multiple service definitions. == Storing the service on a file == There is three main ways for storing and loading services on files. The two first ones consists in loading the file defining the service on HOP startup. The second one, more efficient, consists in placing the definition in a file that is //autoloaded// by HOP. === Load on startup === When invoked from the command line, HOP may be specified files to be loaded. These files may contain service definitions. Assuming that the definition of the service ++hello++ is store into a file named ++/tmp/hello.hop++, running HOP as follows load the file and binds the service: hop /tmp/hello.hop Alternatively, the service definitions can be stored in the ,( "RC file" "07-hoprc.wiki") file is automatically loaded on startup: ,(let ((path (make-file-name (hop-rc-directory) (hop-rc-file)))) (if (file-exists? path) ( ( ( path) (with-input-from-file path (lambda () (
		       :style "max-width: 80em; overflow: auto"
		       :class "source"
		       (decorate-api-code
			(read-string (current-input-port))))))))
	path))
This file may contain definition of services so the definition
above might directly be located on that file. In order to avoiding
cluttering that file with too many definitions, it might be a good
idea to store the definition on another file and to
,( "hop-load" "read.wiki") it from the RC file.

=== Autoload ===

On startup, the HOP server scans the disk of the local computer in order
to find all the ,( ( "weblets") "service.wiki") currently 
[[/hop/hop/hz|available]]. For this, it scans the directories returned by
++(,( "hop-autoload-directories" "service.wiki"))++. The current
weblets path is:

,(
:align "center" (
 
	   (with-output-to-string 
	      (lambda () 
		 (print "(")
		 (for-each (lambda (v) (display " ") (write v) (newline))
			   (hop-autoload-directories))
		 (display ")")))))

HOP scans the subdirectories in this path. For each subdirectory ++DIR++,
HOP checks if a file named ++DIR.hop++ exists. If it exists, then HOP
adds an //autoload// rule on a weblet named ++DIR++. That is, if HOP
has to server a request of the form ,( "http://localhost:8080/hop/DIR"), then it
loads the previously mentioned file and it executes the service ++DIR++.

~~ In consequence, for creating a pervasive ++hello++ service, a file named
++hello/hello.hop++ containing the declaration given above has to be saved
in the ,( "autoload" "service.wiki") path.

== Adding text decorations ==

We improve the visual presentation by adding decorations to the displayed
text. The world //Hello// is now displayed using a bold font and the
text is centered.


  (define-service (hello)
     (
        (
           (
:align "center" ( "Hello ") "World!")))) ( ( ( :href "/hop/hello" "click me"))) == Adding a parameter to the service == We now add a parameter to the service. (define-service (hello #!key who) ( ( (
:align "center" ( "Hello ") who "!")))) ( ( ( :href "/hop/hello?who=foo" "click me"))) ~~ Note that in this example, the parameter is specified in the URL after the question mark (++?++). This conforms to the [[http://www.w3.org/Protocols/rfc2616/rfc2616.html|HTTP]] URL encoding. == Style Sheets, Scripts, and Images == In this section, we denote //resource// any additional file related to a service. A resource can either be a script file, image, etc. This section presents how to refer to them with a Hop source code. ~~ Frequently, it is convenient to store the resources in the same directory that the one containing the source code of the service. This directory can be obtained with the following expression: (service-resource svc) In order to forge an absolute path for a resource ++rsc++ a second argument can be sent to ++service-resource++. That is, the absolute path for the resource ++rsc++ of the service ++svc++ is given by: (service-resource svc rsc) Here is a complete example that uses ++service-resource++. First it is used to provide a value to a ++>++ attribute :dir. Then, it is used to refer to a image. (define-service (hello #!key who) ( ( :title "A simple weblet" :dir (service-resource hello) :css "hello.hss") ( ( :src (service-resource hello :who "hello.jpg")))))