Skip to content

Commit 22bdc0e

Browse files
committed
Scala w/ fragment support
1 parent 666b3eb commit 22bdc0e

File tree

6 files changed

+271
-3
lines changed

6 files changed

+271
-3
lines changed

scala/Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,10 @@ COPY --chown=human:human ./artifacts /artifacts
1010
RUN cd /artifacts && make install
1111

1212
COPY --chown=human:human ./files /hello-world
13+
COPY --chown=human:human ./fraglet /
14+
15+
ENV CI_DISABLE_PROGRESS_BAR=1 \
16+
COURSIER_PROGRESS=0 \
17+
COURSIER_NO_TERM=1
18+
19+
ENTRYPOINT [ "/fraglet-entrypoint" ]

scala/artifacts/Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ install:
22
curl -fL https://github.com/coursier/coursier/releases/download/v2.1.8/cs-x86_64-pc-linux.gz | gzip -d > cs && chmod +x cs
33
# Coursier doesn't work with musl libc, so we need to use gcompat in alpine
44
./cs setup --install-dir /usr/local/bin
5-
# This is to prefetch + cache dependencies
5+
# Pre-download coursier index and cache dependencies
6+
export CI_DISABLE_PROGRESS_BAR=1
7+
export COURSIER_PROGRESS=0
8+
# Pre-warm coursier cache by fetching the index
9+
curl -s -o /dev/null https://github.com/coursier/jvm-index/raw/master/index.json || true
610
echo 'object Test { def main(args: Array[String]) = println("Hello") }' > Test.scala
7-
scala run Test.scala
11+
scala run --quiet Test.scala

scala/files/hello-world.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
#!/usr/bin/env sh
22

3-
scala run HelloWorld.scala
3+
cd /hello-world
4+
scala run --quiet HelloWorld.scala

scala/fraglet/fraglet.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fragletTempPath: /FRAGLET
2+
3+
injection:
4+
codePath: /hello-world/HelloWorld.scala
5+
match: "Hello World!"
6+
7+
guide: /guide.md
8+
9+
execution:
10+
path: /hello-world/hello-world.sh
11+
makeExecutable: true

scala/fraglet/guide.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Scala Fraglet Guide
2+
3+
## Language Version
4+
Scala (installed via Coursier)
5+
6+
## Execution Model
7+
- Compiled, then executed
8+
- Uses `scala run` to compile and execute in one step
9+
- Requires an object with a `main` method
10+
- Code executes when `main()` is called
11+
- Can define functions, classes, traits, and objects outside `main()`
12+
13+
## Key Characteristics
14+
- JVM-based language (runs on Java)
15+
- Statically typed with type inference
16+
- Case-sensitive
17+
- Semicolons optional
18+
- Supports both object-oriented and functional programming
19+
- Immutable by default (val vs var)
20+
- Pattern matching
21+
22+
## Fragment Authoring
23+
Write valid Scala statements or expressions. Code executes inside `main()`, so you can write statements directly. You can also define functions, classes, traits, and objects outside `main()` and call them from within.
24+
25+
## Available Libraries
26+
- Standard Scala library
27+
- Java standard library (via JVM)
28+
- No additional dependencies pre-installed
29+
30+
## Common Patterns
31+
- Print: `println("message")`
32+
- String interpolation: `s"Total: $count"` or `s"Total: ${expression}"`
33+
- Lists: `List(1, 2, 3).sum`
34+
- Functions: `def methodName(): Unit = { }`
35+
- Classes: `class MyClass { }`
36+
- Objects: `object MyObject { }`
37+
- Traits: `trait MyTrait { }`
38+
- Pattern matching: `x match { case 1 => ... }`
39+
- Immutable variables: `val x = 5`
40+
- Mutable variables: `var x = 5`
41+
- Higher-order functions: `list.map(x => x * 2)`
42+
- For comprehensions: `for (i <- 1 to 10) println(i)`
43+
44+
## Examples
45+
46+
```scala
47+
// Simple output
48+
println("Hello, World!")
49+
```
50+
51+
```scala
52+
// Function definition
53+
def greet(name: String): String = {
54+
s"Hello, $name!"
55+
}
56+
57+
println(greet("Alice"))
58+
```
59+
60+
```scala
61+
// List processing
62+
val numbers = List(1, 2, 3, 4, 5)
63+
val squared = numbers.map(x => x * x)
64+
println(s"Sum of squares: ${squared.sum}")
65+
```
66+
67+
```scala
68+
// Higher-order function
69+
val multiply = (a: Int, b: Int) => a * b
70+
println(s"5 * 3 = ${multiply(5, 3)}")
71+
```
72+
73+
```scala
74+
// Class definition
75+
class Calculator {
76+
def add(a: Int, b: Int): Int = {
77+
a + b
78+
}
79+
}
80+
81+
val calc = new Calculator()
82+
println(s"10 + 20 = ${calc.add(10, 20)}")
83+
```
84+
85+
```scala
86+
// String interpolation
87+
val name = "Scala"
88+
val version = 3
89+
println(s"Welcome to $name $version!")
90+
```
91+
92+
```scala
93+
// Case class
94+
case class Person(name: String, age: Int)
95+
96+
val person = Person("Bob", 30)
97+
println(s"${person.name} is ${person.age} years old")
98+
```
99+
100+
```scala
101+
// Pattern matching
102+
val x = 5
103+
val result = x match {
104+
case n if n < 0 => "negative"
105+
case 0 => "zero"
106+
case _ => "positive"
107+
}
108+
println(s"x is $result")
109+
```
110+
111+
```scala
112+
// For comprehension
113+
val numbers = List(1, 2, 3, 4, 5)
114+
val doubled = for (n <- numbers) yield n * 2
115+
println(s"Doubled: ${doubled.mkString(", ")}")
116+
```
117+
118+
```scala
119+
// Option handling
120+
val name: Option[String] = Some("Scala")
121+
name.foreach(n => println(s"Name: $n"))
122+
123+
val empty: Option[String] = None
124+
println(empty.getOrElse("Default value"))
125+
```
126+
127+
```scala
128+
// Extension methods (Scala 3) or implicit classes (Scala 2)
129+
implicit class StringOps(s: String) {
130+
def double(): String = s + s
131+
}
132+
133+
val text = "Hello"
134+
println(text.double())
135+
```
136+
137+
## Notes
138+
- Use `val` for immutable variables, `var` for mutable
139+
- Type inference works well, but explicit types can improve clarity
140+
- Pattern matching is powerful for control flow
141+
- Case classes provide convenient data structures
142+
- For comprehensions are syntactic sugar for map/flatMap/filter
143+
- Scala 2 and Scala 3 syntax may differ slightly

scala/fraglet/verify.sh

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
IMAGE="${1:-100hellos/scala:local}"
5+
6+
echo "Testing default execution..."
7+
docker run --rm "$IMAGE" | grep -Fq "Hello World!"
8+
9+
echo "Testing fraglet examples from guide.md..."
10+
11+
# Example 1: Simple output
12+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "Hello, World!"
13+
println("Hello, World!")
14+
EOF
15+
16+
# Example 2: Function definition
17+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "Hello, Alice!"
18+
def greet(name: String): String = {
19+
s"Hello, $name!"
20+
}
21+
22+
println(greet("Alice"))
23+
EOF
24+
25+
# Example 3: List processing
26+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "Sum of squares:"
27+
val numbers = List(1, 2, 3, 4, 5)
28+
val squared = numbers.map(x => x * x)
29+
println(s"Sum of squares: ${squared.sum}")
30+
EOF
31+
32+
# Example 4: Higher-order function
33+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "5 * 3 = 15"
34+
val multiply = (a: Int, b: Int) => a * b
35+
println(s"5 * 3 = ${multiply(5, 3)}")
36+
EOF
37+
38+
# Example 5: Class definition
39+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "10 + 20 = 30"
40+
class Calculator {
41+
def add(a: Int, b: Int): Int = {
42+
a + b
43+
}
44+
}
45+
46+
val calc = new Calculator()
47+
println(s"10 + 20 = ${calc.add(10, 20)}")
48+
EOF
49+
50+
# Example 6: String interpolation
51+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "Welcome to Scala"
52+
val name = "Scala"
53+
val version = 3
54+
println(s"Welcome to $name $version!")
55+
EOF
56+
57+
# Example 7: Case class
58+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "Bob is 30 years old"
59+
case class Person(name: String, age: Int)
60+
61+
val person = Person("Bob", 30)
62+
println(s"${person.name} is ${person.age} years old")
63+
EOF
64+
65+
# Example 8: Pattern matching
66+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "x is positive"
67+
val x = 5
68+
val result = x match {
69+
case n if n < 0 => "negative"
70+
case 0 => "zero"
71+
case _ => "positive"
72+
}
73+
println(s"x is $result")
74+
EOF
75+
76+
# Example 9: For comprehension
77+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "Doubled:"
78+
val numbers = List(1, 2, 3, 4, 5)
79+
val doubled = for (n <- numbers) yield n * 2
80+
println(s"Doubled: ${doubled.mkString(", ")}")
81+
EOF
82+
83+
# Example 10: Option handling
84+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "Name: Scala"
85+
val name: Option[String] = Some("Scala")
86+
name.foreach(n => println(s"Name: $n"))
87+
88+
val empty: Option[String] = None
89+
println(empty.getOrElse("Default value"))
90+
EOF
91+
92+
# Example 11: Extension methods (implicit class)
93+
fragletc --image "$IMAGE" - <<'EOF' 2>&1 | grep -Fq "HelloHello"
94+
implicit class StringOps(s: String) {
95+
def double(): String = s + s
96+
}
97+
98+
val text = "Hello"
99+
println(text.double())
100+
EOF
101+
102+
echo "✓ All tests passed"

0 commit comments

Comments
 (0)