-
-
Notifications
You must be signed in to change notification settings - Fork 2
initial setup and Hello World exercise #3
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
Changes from all commits
fb9ac5d
1562c3e
6761c64
2a15d84
0939121
d592579
1953c96
3a5d6cf
421ec24
bafa6a2
90bb5fa
e03f731
b37106e
2229a38
e0e6464
2bea052
3781718
7c0c5a1
9bcb8cd
6381647
840ce52
cf1f8fc
a808ea7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| [submodule "problem-specifications"] | ||
| path = problem-specifications | ||
| url = https://github.com/exercism/problem-specifications.git |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| .DEFAULT_GOAL := test | ||
|
|
||
| EXERCISE ?= "" | ||
| EXERCISES = $(shell find ./exercises/practice -maxdepth 1 -mindepth 1 -type d | cut -s -d '/' -f4 | sort) | ||
| OUTDIR ?= "tmp" | ||
|
|
||
| # check all package.json and package-lock.json are matching | ||
| check-package-files: | ||
| @echo "Validation package.json files..." | ||
| @for pkg in $(PKG_FILES); do \ | ||
| ! ./bin/md5-hash $$pkg | grep -qv $(SOURCE_PKG_MD5) || { echo "$$pkg does not match main package.json. Please run 'make sync-package-files' locally and commit the results."; exit 1; }; \ | ||
| done | ||
| @echo "Validation package-lock.json files..." | ||
| @for pkg in $(PKG_LOCK_FILES); do \ | ||
| ! ./bin/md5-hash $$pkg | grep -qv $(SOURCE_PKG_LOCK_MD5) || { echo "$$pkg does not match main package.json. Please run 'make sync-package-files' locally and commit the results."; exit 1; }; \ | ||
| done | ||
| @echo "package-file check complete..." | ||
|
|
||
| # copy package.json and package-lock.json for single exercise | ||
| copy-package-file: | ||
| @cp package.json exercises/practice/$(EXERCISE)/package.json | ||
| @cp package-lock.json exercises/practice/$(EXERCISE)/package-lock.json | ||
| @cp rescript.json exercises/practice/$(EXERCISE)/rescript.json | ||
|
|
||
| # copy package files to all exercise directories | ||
| sync-package-files: | ||
| @echo "Syncing package.json and package-lock.json..." | ||
| @for exercise in $(EXERCISES); do EXERCISE=$$exercise $(MAKE) -s copy-package-file || exit 1; done | ||
|
|
||
| copy-exercise: | ||
| if [ -f exercises/practice/$(EXERCISE)/src/*.res ]; then \ | ||
| echo "Copying $(EXERCISE)"; \ | ||
| cp exercises/practice/$(EXERCISE)/.meta/*.res $(OUTDIR)/src/; \ | ||
| cp exercises/practice/$(EXERCISE)/tests/*.res $(OUTDIR)/tests/; \ | ||
| fi | ||
|
|
||
| copy-all-exercises: | ||
| @echo "Copying exercises for testing..." | ||
| @mkdir -p $(OUTDIR)/src | ||
| @mkdir -p $(OUTDIR)/tests | ||
| @for exercise in $(EXERCISES); do EXERCISE=$$exercise $(MAKE) -s copy-exercise || exit 1; done | ||
|
|
||
| # Remove the OUTDIR | ||
| clean: | ||
| @echo "Cleaning tmp directory..." | ||
| @rm -rf $(OUTDIR) | ||
|
|
||
| # Format all ReScript files in the project | ||
| format: | ||
| @echo "Formatting ReScript files..." | ||
| @find . -name "node_modules" -prune -o -name "*.res" -print -o -name "*.resi" -print | xargs npx rescript format | ||
|
|
||
| generate-tests: | ||
| @echo "Generating tests for all exercises..." | ||
| @for exercise in $(EXERCISES); do \ | ||
| if [ -f exercises/practice/$$exercise/.meta/generateTests.js ]; then \ | ||
| echo "-> Generating: $$exercise"; \ | ||
| node exercises/practice/$$exercise/.meta/generateTests.js || exit 1; \ | ||
| else \ | ||
| echo "-> Skipping: $$exercise (no generator found)"; \ | ||
| fi \ | ||
| done | ||
| @echo "All tests generated successfully." | ||
|
|
||
| generate-test: | ||
| ifeq ($(EXERCISE),"") | ||
| $(error EXERCISE variable is required. usage: make generate_test EXERCISE=hello-world) | ||
| endif | ||
| @node exercises/practice/$(EXERCISE)/.meta/generateTests.js | ||
|
|
||
| test: | ||
| $(MAKE) -s clean | ||
| $(MAKE) -s check-package-files | ||
| $(MAKE) -s copy-all-exercises | ||
| npm run ci |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,23 +8,87 @@ | |
| "representer": false, | ||
| "analyzer": false | ||
| }, | ||
| "blurb": "TODO: add blurb", | ||
| "blurb": "ReScript is a strongly typed functional language which compiles to both Javascript and native.", | ||
| "version": 3, | ||
| "online_editor": { | ||
| "indent_style": "space", | ||
| "indent_size": 4 | ||
| "indent_size": 2, | ||
| "highlightjs_language": "reasonml" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How close is the ReasonML syntax for highlighting purposes? https://github.com/tsnobip/highlightjs-rescript might be a possibility. Exercism can load that NPM package or we can even spin up our own if we’re feeling particularly motivated.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. about 90% of the ReasonML syntax highlighting should work, but then it will fail on piping and parametric polymorphism. The package you linked looks good. |
||
| }, | ||
| "test_runner": { | ||
| "average_run_time": 7 | ||
| }, | ||
| "files": { | ||
| "solution": [], | ||
| "test": [], | ||
| "example": [], | ||
| "exemplar": [] | ||
| "solution": [ | ||
| "src/%{pascal_slug}.res" | ||
| ], | ||
| "test": [ | ||
| "tests/%{pascal_slug}_test.res" | ||
| ], | ||
| "example": [ | ||
| ".meta/%{pascal_slug}.res" | ||
| ], | ||
| "exemplar": [ | ||
| ".meta/src/%{pascal_slug}.res" | ||
| ], | ||
| "editor": [ | ||
| "src/%{pascal_slug}.resi" | ||
| ] | ||
| }, | ||
| "exercises": { | ||
| "concept": [], | ||
| "practice": [] | ||
| "practice": [ | ||
| { | ||
| "slug": "hello-world", | ||
| "name": "Hello World", | ||
| "uuid": "63d72b81-c7a4-4a94-8224-69f4c68cc374", | ||
| "practices": [], | ||
| "prerequisites": [], | ||
| "difficulty": 1 | ||
| } | ||
| ] | ||
| }, | ||
| "concepts": [], | ||
| "key_features": [], | ||
| "tags": [] | ||
| "key_features": [ | ||
| { | ||
| "title": "OCaml's type system", | ||
| "content": "ReScript brings OCaml's battle-tested powerful type system to JavaScript.", | ||
| "icon": "stable" | ||
| }, | ||
| { | ||
| "title": "Inferred types", | ||
| "content": "Types are inferred by the ReScript compiler and are guaranteed to be correct.", | ||
| "icon": "immutable" | ||
| }, | ||
| { | ||
| "title": "Functional Programming", | ||
| "content": "Like OCaml, ReScript is a functional programming language with pattern matching, variants and more.", | ||
| "icon": "functional" | ||
| }, | ||
| { | ||
| "title": "JavaScript interop", | ||
| "content": "JavaScript interoperability is easy, allowing existing JavaScript packages to be used.", | ||
| "icon": "interop" | ||
| }, | ||
| { | ||
| "title": "Fast compiler", | ||
| "content": "ReScript compilation times are super fast which means fast iteration cycles.", | ||
| "icon": "fast" | ||
| }, | ||
| { | ||
| "title": "Refactor with ease", | ||
| "content": "Compiler guides you through all places that need to be fixed during refactor until it just works.", | ||
| "icon": "fun" | ||
| } | ||
| ], | ||
| "tags": [ | ||
| "execution_mode/compiled", | ||
| "paradigm/functional", | ||
| "platform/linux", | ||
| "platform/mac", | ||
| "platform/web", | ||
| "platform/windows", | ||
| "typing/static", | ||
| "typing/strong", | ||
| "used_for/frontends", | ||
| "used_for/web_development" | ||
| ] | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an old set of instructions. We don't need to do it right this moment, but before launch, let's make sure to have configlet sync docs and metadata for everything. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Instructions | ||
|
|
||
| The classical introductory exercise. | ||
| Just say "Hello, World!". | ||
|
|
||
| ["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment. | ||
|
|
||
| The objectives are simple: | ||
|
|
||
| - Modify the provided code so that it produces the string "Hello, World!". | ||
| - Run the test suite and make sure that it succeeds. | ||
| - Submit your solution and check it at the website. | ||
|
|
||
| If everything goes well, you will be ready to fetch your first real exercise. | ||
|
|
||
| [hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| let hello = () => "Hello, World!" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| { | ||
| "authors": [ | ||
| "tejasbubane", | ||
| "therealowenrees" | ||
| ], | ||
| "contributors": [ | ||
| "naartjie", | ||
| "ohana54", | ||
| "son1112", | ||
| "stevejb71" | ||
| ], | ||
| "files": { | ||
| "solution": [ | ||
| "src/HelloWorld.res" | ||
| ], | ||
| "test": [ | ||
| "tests/HelloWorld_test.res" | ||
| ], | ||
| "example": [ | ||
| ".meta/HelloWorld.res" | ||
| ], | ||
| "editor": [ | ||
| "src/HelloWorld.resi" | ||
| ] | ||
| }, | ||
| "blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".", | ||
| "source": "This is an exercise to introduce users to using Exercism", | ||
| "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { fileURLToPath } from 'node:url'; | ||
| import path from 'node:path'; | ||
| import getValidCases from '../../../../test_generator/getCases.js'; | ||
| import { generate, toPascalCase } from '../../../../test_generator/testGenerator.js'; | ||
| import * as template from './testTemplate.js'; | ||
|
|
||
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
| const cases = getValidCases(template.slug); | ||
| const outputPath = path.resolve(__dirname, '..', 'tests', `${toPascalCase(template.slug)}_test.res`); | ||
|
|
||
| generate(outputPath, template.slug, cases, template); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| export const slug = 'hello-world'; | ||
|
|
||
| export const assertionFunctions = `let stringEqual = (~message=?, a: string, b: string) => | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to build and document a small library of common assertion functions that can be pulled into templates? We can still have custom functions for more complicated assertions, but then we don’t need to reinvent things like checking if a returned value is true of not.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes I think this would be a good idea. I will scour through the rest of the exercises already implemented for this track in my repo and add those assertions for now, and add more as we move forward |
||
| assertion(~message?, ~operator="stringEqual", (a, b) => a == b, a, b)`; | ||
|
|
||
| export const template = (c, moduleName) => { | ||
| return `stringEqual(~message="${c.description}", ${moduleName}.hello(), "${c.expected}")` | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # This is an auto-generated file. | ||
| # | ||
| # Regenerating this file via `configlet sync` will: | ||
| # - Recreate every `description` key/value pair | ||
| # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications | ||
| # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) | ||
| # - Preserve any other key/value pair | ||
| # | ||
| # As user-added comments (using the # character) will be removed when this file | ||
| # is regenerated, comments can be added via a `comment` key. | ||
|
|
||
| [af9ffe10-dc13-42d8-a742-e7bdafac449d] | ||
| description = "Say Hi!" |
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this LICENSE file?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we do because of the package JSON putting this under a MIT license. At some point, we’ll want a script that runs configlet create and then also copies over the additional files we need like this and the package.json. That’s not an immediate need but the sooner we do it, the less chance for human error. :)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would that be the sync command ? Where do we normally place such a script?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bin is usually where that goes. I think we should create a template folder at the repo root that has these extra files in the relative spots where they are expected to go in the final exercise folder. Then you can copy the template folder to the exercise folder after configlet create does its thing. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| MIT License | ||
|
|
||
| Copyright (c) 2021 Exercism | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This .gitignore is for the students, correct? It probably should only be for build artifacts like node_modules then. There's extra stuff in here they wouldn't be using like configlet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be for this repo, without it I would end up commiting configlet and build artifacts. There is no .gitignore per exercise for the student it seems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I thought this was in the hello world folder. We might as well give the students a .gitignore file in the exercise like the JS track does. At minimum, that means they won’t accidentally commit node_modules if they’re adding their solutions to a GitHub repo.