Skip to content

Commit 53a82a6

Browse files
Support loading files from GitHub repositories (#218)
1 parent 0bd14e2 commit 53a82a6

19 files changed

+490
-58
lines changed

README.md

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,40 @@
1212
- Run and print output or show resulting JavaScript
1313
- Multiple view modes: code, output or both
1414
- Persistent session
15-
- Load PureScript code from Github Gists
15+
- Load PureScript code from GitHub Gists or repository files
1616

17-
### Which Libraries are Available?
17+
### Control Features via the Query String
18+
19+
Most of these features can be controlled not only from the toolbar, but also using the [query parameters](https://en.wikipedia.org/wiki/Query_string):
20+
21+
- **Load From GitHub Repo**: Load a PureScript file from a GitHub repository using the `github` parameter
22+
- Format: `github=/<owner>/<repo>/<branch or tag>/<file>.purs`
23+
- Example: `github=/purescript/trypurescript/master/client/examples/Main.purs`.
24+
- Notes: the file should be a single PureScript module with the module name `Main`.
25+
26+
- **Load From Gist**: Load PureScript code from a gist using the `gist` parameter
27+
- Format: `gist=<gist id>`
28+
- Example: `gist=37c3c97f47a43f20c548`
29+
- Notes: the file should be named `Main.purs` with the module name `Main`.
30+
31+
- **View Mode**: Control the view mode using the `view` parameter
32+
- Options are: `code`, `output`, `both` (default)
33+
- Example: `view=output` will only display the output
34+
35+
- **Auto Compile**: Automatic compilation can be turned off using the `compile` parameter
36+
- Options are: `true` (default), `false`
37+
- Example: `compile=false` will turn auto compilation off
38+
39+
- **JavaScript Code Generation**: Print the resulting JavaScript code in the output window instead of the output of the program using the `js` parameter
40+
- Options are: `true`, `false` (default)
41+
- Example: `js=true` will print JavaScript code instead of the program's output
42+
43+
- **Session**: Load code from a session which is stored with [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) using the `session` parameter
44+
- Usually managed by Try PureScript
45+
- Example: `session=9162f098-070f-4053-60ea-eba47021450d` (Note: will probably not work for you)
46+
- When used with the `gist` or `github` query parameters the code will be loaded from the source file and not the session
47+
48+
### Which Libraries Are Available?
1849

1950
Try PureScript aims to provide a complete, recent package set from <https://github.com/purescript/package-sets>. The available libraries are those listed in `staging/spago.dhall`, at the versions in the package set mentioned in `staging/packages.dhall`.
2051

@@ -41,30 +72,6 @@ $ spago ls packages | cut -f 1 -d ' ' | xargs spago install
4172

4273
Before deploying an updated package set, someone (your reviewer) should check that the memory required to hold the package set's externs files does not exceed that of the try.purescript.org server.
4374

44-
### Control Features via the Query String
45-
46-
Most of these features can be controlled not only from the toolbar, but also using the [query parameters](https://en.wikipedia.org/wiki/Query_string):
47-
48-
- **Load From Gist**: Load PureScript code from Gist id using the `gist` parameter
49-
- Example: `gist=37c3c97f47a43f20c548` will load the code from this Gist if the file was named `Main.purs`
50-
51-
- **View Mode**: Control the view mode using the `view` parameter
52-
- Options are: `code`, `output`, `both` (default)
53-
- Example: `view=output` will only display the output
54-
55-
- **Auto Compile**: Automatic compilation can be turned off using the `compile` parameter
56-
- Options are: `true` (default), `false`
57-
- Example: `compile=false` will turn auto compilation off
58-
59-
- **JavaScript Code Generation**: Print the resulting JavaScript code in the output window instead of the output of the program using the `js` parameter
60-
- Options are: `true`, `false` (default)
61-
- Example: `js=true` will print JavaScript code instead of the program's output
62-
63-
- **Session**: Load code from a session which is stored with [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) using the `session` parameter
64-
- Usually managed by Try PureScript
65-
- Example: `session=9162f098-070f-4053-60ea-eba47021450d` (Note: will probably not work for you)
66-
- When used with the `gist` query parameter the code will be loaded from the Gist and not the session
67-
6875
## Development
6976

7077
### 1. Client setup
@@ -98,6 +105,16 @@ stack exec trypurescript 8081 $(spago sources)
98105
# then: Setting phasers to stun... (port 8081) (ctrl-c to quit)
99106
```
100107

108+
### 3. Choosing a Tag
109+
110+
The built-in examples for Try PureScript are loaded from this GitHub repository. To change the tag that the examples are loaded from, you'll need to touch three files:
111+
112+
* `client/config/dev/Try.Config.purs`
113+
* `client/config/prod/Try.Config.purs`
114+
* `client/examples/Main.purs`, in the `fromExample` function.
115+
116+
If you are preparing a release or if you need to adjust examples in development, you should change the tag in these three places (and ensure you're using the same tag in each place!).
117+
101118
## Server API
102119

103120
The server is a very basic web service which wraps the PureScript compiler, allowing clients to send PureScript code to be compiled and receiving either compiled JS or error messages in response.

client/config/dev/Try.Config.purs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
module Try.Config where
22

3+
import Prelude
4+
35
loaderUrl :: String
46
loaderUrl = "js/output"
57

68
compileUrl :: String
79
compileUrl = "http://localhost:8081"
810

9-
mainGist :: String
10-
mainGist = "7ad2b2eef11ac7dcfd14aa1585dd8f69"
11+
tag :: String
12+
tag = "load-from-github"
13+
14+
mainGitHubExample :: String
15+
mainGitHubExample = "/purescript/trypurescript/" <> tag <> "/client/examples/Main.purs"

client/config/prod/Try.Config.purs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
module Try.Config where
22

3+
import Prelude
4+
35
loaderUrl :: String
46
loaderUrl = "https://compile.purescript.org/output"
57

68
compileUrl :: String
79
compileUrl = "https://compile.purescript.org"
810

9-
mainGist :: String
10-
mainGist = "7ad2b2eef11ac7dcfd14aa1585dd8f69"
11+
tag :: String
12+
tag = "load-from-github"
13+
14+
mainGitHubExample :: String
15+
mainGitHubExample = "/purescript/trypurescript/" <> tag <> "/client/examples/Main.purs"

client/examples/ADTs.purs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module Main where
2+
3+
import Prelude
4+
5+
import Effect.Console (logShow)
6+
import Data.Map (Map, lookup, singleton)
7+
import TryPureScript (render, withConsole)
8+
9+
-- | A Name consists of a first name and a last name
10+
data Name = Name String String
11+
12+
-- | With compiler versions >= 0.8.2, we can derive
13+
-- | instances for Eq and Ord, making names comparable.
14+
derive instance eqName :: Eq Name
15+
derive instance ordName :: Ord Name
16+
17+
-- | The Ord instance allows us to use Names as the
18+
-- | keys in a Map.
19+
phoneBook :: Map Name String
20+
phoneBook = singleton (Name "John" "Smith") "555-555-1234"
21+
22+
main = render =<< withConsole do
23+
logShow (lookup (Name "John" "Smith") phoneBook)

client/examples/DoNotation.purs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module Main where
2+
3+
import Prelude
4+
import Control.MonadPlus (guard)
5+
import Effect.Console (logShow)
6+
import Data.Array ((..))
7+
import Data.Foldable (for_)
8+
import TryPureScript
9+
10+
-- Find Pythagorean triples using an array comprehension.
11+
triples :: Int -> Array (Array Int)
12+
triples n = do
13+
z <- 1 .. n
14+
y <- 1 .. z
15+
x <- 1 .. y
16+
guard $ x * x + y * y == z * z
17+
pure [x, y, z]
18+
19+
main = render =<< withConsole do
20+
for_ (triples 20) logShow

client/examples/Generic.purs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
module Main where
2+
3+
import Prelude
4+
import Effect.Console (logShow)
5+
import Data.Generic.Rep (class Generic)
6+
import Data.Eq.Generic (genericEq)
7+
import Data.Ord.Generic (genericCompare)
8+
import Data.Show.Generic (genericShow)
9+
import TryPureScript (render, withConsole)
10+
11+
data Address = Address
12+
{ city :: String
13+
, state :: String
14+
}
15+
16+
data Person = Person
17+
{ first :: String
18+
, last :: String
19+
, address :: Address
20+
}
21+
22+
-- Generic instances can be derived by the compiler,
23+
-- using the derive keyword:
24+
derive instance genericAddress :: Generic Address _
25+
26+
derive instance genericPerson :: Generic Person _
27+
28+
-- Now we can write instances for standard type classes
29+
-- (Show, Eq, Ord) by using standard definitions
30+
instance showAddress :: Show Address where
31+
show = genericShow
32+
33+
instance eqAddress :: Eq Address where
34+
eq = genericEq
35+
36+
instance ordAddress :: Ord Address where
37+
compare = genericCompare
38+
39+
instance showPerson :: Show Person where
40+
show = genericShow
41+
42+
instance eqPerson :: Eq Person where
43+
eq = genericEq
44+
45+
instance ordPerson :: Ord Person where
46+
compare = genericCompare
47+
48+
main = render =<< withConsole do
49+
logShow $ Person
50+
{ first: "John"
51+
, last: "Smith"
52+
, address: Address
53+
{ city: "Faketown"
54+
, state: "CA"
55+
}
56+
}

client/examples/Loops.purs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Main where
2+
3+
import Prelude
4+
5+
import Effect.Console (log)
6+
import Data.Array ((..))
7+
import Data.Foldable (for_)
8+
import TryPureScript (render, withConsole)
9+
10+
main = render =<< withConsole do
11+
for_ (10 .. 1) \n -> log (show n <> "...")
12+
log "Lift off!"

client/examples/Main.purs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
module Main where
2+
3+
import Prelude
4+
5+
import Data.Foldable (fold)
6+
import Effect (Effect)
7+
import TryPureScript (h1, h2, p, text, list, indent, link, render, code)
8+
9+
main :: Effect Unit
10+
main =
11+
render $ fold
12+
[ h1 (text "Try PureScript!")
13+
, p (text "Try out the examples below, or create your own!")
14+
, h2 (text "Examples")
15+
, list (map fromExample examples)
16+
, h2 (text "Share Your Code")
17+
, p (text "A PureScript file can be loaded from GitHub from a gist or a repository. To share code using a gist, simply include the gist ID in the URL as follows:")
18+
, indent (p (code (text " try.purescript.org?gist=<gist id>")))
19+
, p (fold
20+
[ text "The gist should contain PureScript module named "
21+
, code (text "Main")
22+
, text " in a file named "
23+
, code (text "Main.purs")
24+
, text " containing your PureScript code."
25+
])
26+
, p (text "To share code from a repository, include the path to the source file as follows:")
27+
, indent (p (code (text " try.purescript.org?github=/<owner>/<repo>/<branch or tag>/<file>.purs")))
28+
, p (fold
29+
[ text "The file should be a PureScript module named "
30+
, code (text "Main")
31+
, text " containing your PureScript code."
32+
])
33+
]
34+
where
35+
fromExample { title, source } =
36+
link ("https://github.com/purescript/trypurescript/load-from-github/client/examples/" <> source) (text title)
37+
38+
examples =
39+
[ { title: "Algebraic Data Types"
40+
, source: "ADTs.purs"
41+
}
42+
, { title: "Loops"
43+
, source: "Loops.purs"
44+
}
45+
, { title: "Operators"
46+
, source: "Operators.purs"
47+
}
48+
, { title: "Records"
49+
, source: "Records.purs"
50+
}
51+
, { title: "Recursion"
52+
, source: "Recursion.purs"
53+
}
54+
, { title: "Do Notation"
55+
, source: "DoNotation.purs"
56+
}
57+
, { title: "Type Classes"
58+
, source: "TypeClasses.purs"
59+
}
60+
, { title: "Generic Programming"
61+
, source: "Generic.purs"
62+
}
63+
, { title: "QuickCheck"
64+
, source: "QuickCheck.purs"
65+
}
66+
]

client/examples/Operators.purs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module Main where
2+
3+
import Prelude
4+
import Effect.Console (log)
5+
import TryPureScript (render, withConsole)
6+
7+
type FilePath = String
8+
9+
subdirectory :: FilePath -> FilePath -> FilePath
10+
subdirectory p1 p2 = p1 <> "/" <> p2
11+
12+
-- Functions can be given an infix alias
13+
-- The generated code will still use the original function name
14+
infixl 5 subdirectory as </>
15+
16+
filepath :: FilePath
17+
filepath = "usr" </> "local" </> "bin"
18+
19+
main = render =<< withConsole do
20+
log filepath

client/examples/QuickCheck.purs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module Main where
2+
3+
import Prelude
4+
import Data.Array (sort)
5+
import Test.QuickCheck (quickCheck, (===))
6+
import TryPureScript (render, withConsole, h1, h2, p, text)
7+
8+
main = do
9+
render $ h1 $ text "QuickCheck"
10+
render $ p $ text """QuickCheck is a Haskell library which allows us to assert properties
11+
hold for our functions. QuickCheck uses type classes to generate
12+
random test cases to verify those properties.
13+
purescript-quickcheck is a port of parts of the QuickCheck library to
14+
PureScript."""
15+
render $ h2 $ text "Sort function is idempotent"
16+
render =<< withConsole do
17+
quickCheck \(xs :: Array Int) -> sort (sort xs) === sort xs
18+
render $ h2 $ text "Every array is sorted"
19+
render $ p $ text "This test should fail on some array which is not sorted"
20+
render =<< withConsole do
21+
quickCheck \(xs :: Array Int) -> sort xs === xs

client/examples/Records.purs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Main where
2+
3+
import Prelude
4+
import Effect.Console (log)
5+
import TryPureScript (render, withConsole)
6+
7+
-- We can write functions which require certain record labels...
8+
showPerson o = o.lastName <> ", " <> o.firstName
9+
10+
-- ... but we are free to call those functions with any
11+
-- additional arguments, such as "age" here.
12+
main = render =<< withConsole do
13+
log $ showPerson
14+
{ firstName: "John"
15+
, lastName: "Smith"
16+
, age: 30
17+
}

client/examples/Recursion.purs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Main where
2+
3+
import Prelude
4+
import Effect.Console (logShow)
5+
import TryPureScript (render, withConsole)
6+
7+
isOdd :: Int -> Boolean
8+
isOdd 0 = false
9+
isOdd n = isEven (n - 1)
10+
11+
isEven :: Int -> Boolean
12+
isEven 0 = true
13+
isEven n = isOdd (n - 1)
14+
15+
main = render =<< withConsole do
16+
logShow $ isEven 1000
17+
logShow $ isEven 1001

0 commit comments

Comments
 (0)