Skip to content

Add Scala version picker to Scala Book Hello World Page, remember preference #2450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 5, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 75 additions & 6 deletions _overviews/scala3-book/taste-hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,45 @@ previous-page: taste-intro
next-page: taste-repl
---

> **Hint**: in the following examples try picking your preferred Scala version.
> <noscript><span style="font-weight: bold;">Info</span>: JavaScript is currently disabled, code tabs will still work, but preferences will not be remembered.</noscript>

## Your First Scala Program

A Scala 3 “Hello, world!” example goes as follows.

A Scala “Hello, World!” example goes as follows.
First, put this code in a file named _hello.scala_:


<!-- Display Hello World for each Scala Version -->
{% tabs hello-world-demo class=tabs-scala-version %}

{% tab 'Scala 2' for=hello-world-demo %}
```scala
object hello {
def main(args: Array[String]) = {
println("Hello, World!")
}
}
```
> In this code, we defined a method named `main`, inside a Scala `object` named `hello`.
> An `object` in Scala is similar to a `class`, but defines a singleton instance that you can pass around.
> `main` takes an input parameter named `args` that must be typed as `Array[String]`, (ignore `args` for now).

{% endtab %}

{% tab 'Scala 3' for=hello-world-demo %}
```scala
@main def hello() = println("Hello, world!")
@main def hello() = println("Hello, World!")
```
> In this code, `hello` is a method.
> It’s defined with `def`, and declared to be a “main” method with the `@main` annotation.
> It prints the `"Hello, World!"` string to standard output (STDOUT) using the `println` method.

{% endtab %}

In this code, `hello` is a method.
It’s defined with `def`, and declared to be a “main” method with the `@main` annotation.
It prints the `"Hello, world!"` string to standard output (STDOUT) using the `println` method.
{% endtabs %}
<!-- End tabs -->

Next, compile the code with `scalac`:

Expand All @@ -28,6 +55,19 @@ $ scalac hello.scala

If you’re coming to Scala from Java, `scalac` is just like `javac`, so that command creates several files:

<!-- Display Hello World compiled outputs for each Scala Version -->
{% tabs hello-world-outputs class=tabs-scala-version %}

{% tab 'Scala 2' for=hello-world-outputs %}
```bash
$ ls -1
hello$.class
hello.class
hello.scala
```
{% endtab %}

{% tab 'Scala 3' for=hello-world-outputs %}
```bash
$ ls -1
hello$package$.class
Expand All @@ -37,14 +77,18 @@ hello.scala
hello.class
hello.tasty
```
{% endtab %}

{% endtabs %}
<!-- End tabs -->

Like Java, the _.class_ files are bytecode files, and they’re ready to run in the JVM.

Now you can run the `hello` method with the `scala` command:

```bash
$ scala hello
Hello, world!
Hello, World!
```

Assuming that worked, congratulations, you just compiled and ran your first Scala application.
Expand All @@ -64,6 +108,27 @@ import scala.io.StdIn.readLine

To demonstrate how this works, let’s create a little example. Put this source code in a file named _helloInteractive.scala_:

<!-- Display interactive Hello World application for each Scala Version -->
{% tabs hello-world-interactive class=tabs-scala-version %}

{% tab 'Scala 2' for=hello-world-interactive %}
```scala
import scala.io.StdIn.readLine

object helloInteractive {

def main(args: Array[String]) = {
println("Please enter your name:")
val name = readLine()

println("Hello, " + name + "!")
}

}
```
{% endtab %}

{% tab 'Scala 3' for=hello-world-interactive %}
```scala
import scala.io.StdIn.readLine

Expand All @@ -73,6 +138,10 @@ import scala.io.StdIn.readLine

println("Hello, " + name + "!")
```
{% endtab %}

{% endtabs %}
<!-- End tabs -->

In this code we save the result of `readLine` to a variable called `name`, we then
use the `+` operator on strings to join `"Hello, "` with `name` and `"!"`, making one single string value.
Expand Down
4 changes: 2 additions & 2 deletions _plugins/jekyll-tabs-lib/template.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
<input
type="radio"
name="<%= @name %>_tabs"
id="<%= tab.anchor %>_description"
id="<%= @name %>_<%= tab.anchor %>_description"
data-target="<%= tab.anchor %>"
hidden aria-hidden="true"
<%= tab.defaultTab ? 'checked' : ''%>>
<% end %>
<ul hidden aria-hidden="true" class="nav-tab">
<% environment["tabs-#{@name}"].each do | tab | %>
<li class="item-tab">
<label class="item-tab-link" for="<%= tab.anchor %>_description"><%= tab.label %></label>
<label class="item-tab-link" for="<%= @name %>_<%= tab.anchor %>_description"><%= tab.label %></label>
</li>
<% end %>
</ul>
Expand Down
6 changes: 2 additions & 4 deletions _sass/components/tab.scss
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,8 @@
}

.tabsection {
border-bottom: $base-border-gray;
border-left: $base-border-gray;
border-right: $base-border-gray;
border-radius: $border-radius-medium;
padding: 0.1px 0; // ensure inner content is correctly padded
border-left: 2px solid $base-border-color-gray;

.nav-tab {
padding-left: 0;
Expand Down
80 changes: 80 additions & 0 deletions resources/js/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,86 @@ $(document).ready(function() {
}
});

// Browser Storage Support (https://stackoverflow.com/a/41462752/2538602)
function storageAvailable(type) {
try {
var storage = window[type],
x = '__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);
return true;
}
catch (e) {
return false;
}
}

// Store preference for Scala 2 vs 3
$(document).ready(function() {

const Storage = (namespace) => {
return ({
getPreference(key, defaultValue) {
const res = localStorage.getItem(`${namespace}.${key}`);
return res === null ? defaultValue : res;
},
setPreference(key, value, onChange) {
const old = this.getPreference(key, null);
if (old !== value) { // activate effect only if value changed.
localStorage.setItem(`${namespace}.${key}`, value);
onChange(old);
}
}
});
};

/** Links all tabs created in Liquid templates with class ".tabs-scala-version"
* on the page together, such that
* changing a tab to `Scala 2` will activate all other tab sections to
* also change to "Scala 2".
* Also records a preference for the Scala version in localStorage, so
* that when the page is refreshed, the same tab will be selected.
* On page load, selects the tab corresponding to stored Scala version.
*/
function setupScalaVersionTabs(scalaVersionTabs) {
const BookStorage = Storage('org.scala-lang.docs.scala3.book');
const Scala3 = 'scala-3';
const scalaVersion = BookStorage.getPreference('scalaVersion', Scala3);

function activateTab(tabs, scalaVersion) {
// click the code tab corresponding to the preferred Scala version.
tabs.find('input[data-target=' + scalaVersion + ']').prop("checked", true);
}

activateTab(scalaVersionTabs, scalaVersion);

// setup listeners to record new preferred Scala version.
scalaVersionTabs.find('input').on('change', function() {
// if checked then set the preferred version, and activate the other tabs on page.
if ($(this).is(':checked')) {
const parent = $(this).parent();
const scalaVersion = $(this).data('target');

BookStorage.setPreference('scalaVersion', scalaVersion, oldValue => {
// when we set a new scalaVersion, find scalaVersionTabs except current one
// and activate those tabs.
activateTab(scalaVersionTabs.not(parent), scalaVersion);
});

}

});
}

if (storageAvailable('localStorage')) {
var scalaVersionTabs = $(".tabsection.tabs-scala-version");
if (scalaVersionTabs.length) {
setupScalaVersionTabs(scalaVersionTabs);
}
}

});

// OS detection
function getOS() {
var osname = "linux";
Expand Down