Tutorial for a new application

When learning a new programming language, it is customary to start with a "Hello, World!" program.

This tutorial will guide you through this process for the KRL programming language* used with picos.

Prerequisites

You need to own/control a pico. The surest way to do this is to own and control a pico engine, as suggested in earlier posts. An even simpler approach is to use a "PLAN pico" obtained by joining the Pico Labs Affiliate Network.

This tutorial will guide you as you use your pico and the KRL programming language to greet the world.

Preparing your PLAN pico

Once you obtain your pico, which PLAN calls a personal agent, you will need to insure that it has three rulesets installed in it. PLAN refers to the rulesets in an agent as "applications" or apps.

  1. io.picolabs.plan.apps (your PLAN pico will already have this)
  2. io.picolabs.plan.introspect
  3. io.picolabs.plan.bazaar

You should be looking at the apps.html page, and can use it to install the second and third rulesets (using the form and "Add" button near the bottom of the page). To do this, copy the link address of each ruleset, paste it into the box labelled "app URL", and click the "Add" button.

You could also follow along in your own pico engine, by creating a pico, installing in it the html.plan ruleset (to be used as a module), and then the three PLAN rulesets listed above. This tutorial will not give detailed instructions for this option.

After your preparations, the Manage applications page will show the new applications:

Create the hello-world ruleset

A ruleset is identified by a RID (ruleset identifier) which begins with a letter, and may contain letters, digits, periods, underscores, and hyphens. In this tutorial, you will use hello-world as the RID.

You will create a new ruleset in the bazaar.html page (linked from the apps page you are looking at). The link to this page is labelled "Manage bazaar apps" as shown in the screenshot above. For convenience, we suggest that you open this page in a new tab.

On the "Manage bazaar apps" page in the new tab, use the form in the "New App" section, near the bottom of the page, which requires that you enter three items:

  • Ruleset ID (enter the RID hello-world)
  • App name (enter hello)
  • App meta name (enter greetings)

With those three entries, the bazaar app will create boilerplate code for your new ruleset, when you click the "Submit" button.

View the new ruleset source code

You can view the generated boilerplate by clicking on the "show KRL" button. It will look like this:

ruleset hello-world {
  meta {
    name "greetings"
    use module io.picolabs.plan.apps alias app
    shares hello
  }
  global {
    hello = function(_headers){
      app:html_page("manage greetings", "",
<<
<h1>Manage greetings</h1>
>>, _headers)
    }
  }
}

Locate the hello function definition, and within it the chevron quoted area (between "<<" and ">>") containing a single line of HTML code (which sets up a page header "Manage greetings"). This is where you will place the HTML code for your hello world page.

Edit the new ruleset source code

We will lead you through four ½ iterations of your new app, as defined by the ruleset that you have before you. After iteration one, you will be displaying the "Hello, World!" message. From there, we'll show you how to use an event to change the greeting.

Dismiss the popup window showing the KRL code and click on the "edit/host KRL" button. This will take you to a code editor page. For each iteration, you will perform these steps:

  1. Save your changes, by clicking on the "Save" button.
  2. Right-click in the link after "Raw URL" and click the "Copy Link Address" option.
  3. Return to the tab with the apps page and install your new ruleset by pasting the raw URL into the box and clicking the "Add" button.
  4. Visit the home page of your new app, clicking on the link labelled "Manage greetings".

Iteration zero

Having completed steps 2-4 (you can omit step 1 because you have not made any changes), you will see the app as it was generated. Bonus: looking at the source code, try to figure out where the tab title ("manage greetings") comes from, and where the heading ("Manage greetings") comes from.

Iteration one

Return to the code editor tab.

Add three lines of HTML (a paragraph tag) so that the chevron quoted area looks like this:

<<
<h1>Manage greetings</h1>
<p>
Hello, World!
</p>
>>

Perform steps 1-4 (above) and when you visit the home page of your modified app, hello.html, you should now see a paragraph with the text "Hello, World!" displayed underneath the heading. This should look like the screenshot at the top of this post.

At this point, you have actually completed the customary hello world program, because you have written code that displays the message. However, this tutorial goes on to show you how to use the pico to make your program greet others, besides just the "world".

Iteration two

Prepare to personalize the greeting. Return to the code editor and modify the HTML code so that it looks like this (notice that there are two changes):

  1. Replace the word "World" by the beesting** expression #{ent:name || "World"}
  2. Add a second level heading and form to accept a new name

<<
<h1>Manage greetings</h1>
<p>
Hello, #{ent:name || "World"}!
</p>

<h2>Change the name</h2>
<form action="#{app:event_url(meta:rid,"new_name_submission")}">
<input name="new_name" value="#{ent:name || "World"}">
<button type="submit">Submit</button>
</form>
>>

Perform steps 1-4 (above) and visit the home page of your modified app. Notice that it still displays "Hello, World!" but if the entity variable ent:name had a value, that value would be displayed instead of "World".

There is also a form showing the name currently displayed but offering to change it. If you submit a change, there will not actually be any change because we have yet to add a rule to react to the hello_world:new_name_submission event. That's the event that is generated by the action of the form when it is submitted.

Iteration two and a half -- correcting a problem

Notice also when you submit a change that the page does not redisplay but instead you see an obscure text message (like {"eid":"cljnfn22202p18npb7laafdsp","directives":[]}). Press the browser back button to return to your page.

To correct this, add a rule at the end of your ruleset (just before the closing curly bracket of the ruleset).

ruleset hello-world {
  ...
  rule redirectToHomePage {
    select when hello_world new_name_submission
    send_directive("_redirect",{"url":app:query_url(meta:rid,"hello.html")})
  }
}

Repeating steps 1-4 (above) you should now be able to submit a change and your app's home page will redisplay, although nothing will have changed in the greeting. We'll fix this in iteration three.

Iteration three

Personalize the greeting, by adding a second rule to change the entity variable to the new name. The rule will look like this:

  rule changeName {
    select when hello_world new_name_submission
    fired {
      ent:name := event:attrs{"new_name"}
    }
  }

Repeat steps 1-4 (above), and you should now be able to change the name in the greeting. 

Bonus: do you see how the HTML form is connected to the rule? 

Bonus: do you see how the entity variable is assigned a new value in the postlude (i.e. the fired block) of the rule? 

Notice also that there are now two rules which select when the hello_world new_name_submission event is generated (when you click on your "Submit" button).

Sharing your app with others

You could now copy the entire source code of your ruleset from within the code editor, and commit it to a public GitHub repository (or store it in a public S3 bucket) that you control, under the name hello-world.krl (following the file naming convention for KRL (the RID as the base filename with a .krl file extension)).

Copy the raw URL of your GitHub file (or public S3 URL) and share this with another PicoStack programmer. They should be able to install your ruleset in among their own apps and run it.

If the person you are sharing with also has a PLAN pico, you can simply share the link you yourself used to add the application (this is the link labelled "Raw URL" in your code editor).

Share if at all possible, and notice that when they change the greeting name in their pico that that does not change the greeting name in yours. Each pico (aka personal agent) is independently owned and operated.

Notes

* KRL used to be an acronym (or more accurately, an initialism), but the letters are no longer considered to represent words, so it is just spoken as "kay are ell" (the  names of the three letters). For the early history, see also "Why KRL?"

"Iteration zero" because like all computer scientists, the author starts counting at zero.

** A beesting embeds the value of a KRL expression as a string into the chevron quoted string. In this case, it is either the value of the entity variable (if it is defined and non-empty) or the string constant "World".

"ruleset" vs. "app"? When using a pico that you control in the Pico Labs Affiliate Network (the PLAN), it will have an app implemented by the io.picolabs.plan.apps ruleset. Each app is listed on the page that manages "apps" and you can add your own app to that pico near the bottom of the management page by giving it the URL of a ruleset that implements your app.

Afterword

An alert reader will have noticed that the same beesting is used twice. What about the "don't repeat yourself" principle?

The complete ruleset can be refactored to avoid this, and would then look like this:

ruleset hello-world {
  meta {
    name "greetings"
    use module io.picolabs.plan.apps alias app
    shares hello
  }
  global {
    hello = function(_headers){
      display_name = ent:name || "World"
      app:html_page("manage greetings", "",
<<
<h1>Manage greetings</h1>
<p>
Hello, #{display_name}!
</p>

<h2>Change the name</h2>
<form action="#{app:event_url(meta:rid,"new_name_submission")}">
<input name="new_name" value="#{display_name}">
<button type="submit">Submit</button>
</form>
>>, _headers)
    }
  }
  rule changeName {
    select when hello_world new_name_submission
    fired {
      ent:name := event:attrs{"new_name"}
    }
  }
  rule redirectToHomePage {
    select when hello_world new_name_submission
    send_directive("_redirect",{"url":app:query_url(meta:rid,"hello.html")})
  }
}

No comments:

Post a Comment