Elm Native Module Save Abandoned

Example of how to do an Elm native module

Project README

Elm native module

This is highly discouraged, and will not be possible in future versions of Elm.

The core Elm libraries need access to JavaScript to expose HTTP in Elm (for example) but this is not a public API. It is not intended for public use. It can change dramatically from release to release. It is not permitted in published packages. And again, in future versions, it will not be accessible.

In summary, it is better to figure out how to structure code such that ports will be a good option. If you cannot achieve what you want after asking around on Slack, the best path may be to circle back around to Elm later when more of the Web Platform is covered to your liking.





What?

This is an example of how to do elm native modules for elm 0.18. It contains a native module with a helloWorld function which receives a name parameter and returns a string with that name appended to the 'Hello ' string and an exclamation at the end.

Why?

There are not too many tutorials about how native modules. One of them is the wiki of take-home but it is not updated for elm 0.17 and up. Also, I have included some tests, so you can learn how to test your own native modules.

How?

Getting Starting

You need to have elm installed, and also elm-test because we are going to write a test for our native module. You can do it with this commands:

$ npm i -g elm
$ npm i -g elm-test

Once you have both installed, we are goint to create a folder and execute elm-test init. That will create two folders, src and tests. Test folder comes with some example elm tests.

.
├── src
└── tests
    ├── Main.elm
    ├── Tests.elm
    └── elm-package.json

You can execute them running elm-test in your command line.

After running elm-test you should see something like this:

first run elm-test

Our next step will be writting our first test. To do that we have to replace the content of tests/Tests.elm with this content:

module Tests exposing (..)

import Test exposing (..)
import Expect

import NativeModule exposing (helloWorld)

all : Test
all =
    describe "Native module test suite"
        [ describe "helloWorld"
            [ test "empty string" <|
                \() ->
                    Expect.equal (helloWorld "") "Hello !"
            ]
        ]

If we try to run elm-test again, an error will show up telling us that the module NativeModule we are trying to import can't be found. That is right... we haven't done it yet!.

Our next step will be create that module, so we have to create a file called NativeModule.elm inside the src folder. (You can replace NativeModule with something more descriptive in your project).

Inside it, we are going write the lines under this:

module NativeModule exposing (helloWorld)

helloWorld: String -> String
helloWorld =
  Native.NativeModule.helloWorld

There, we are creating a module called NativeModule which is exposing a function called helloWorld. That function annotation is telling us that it is going to receive a string as a parameter and it is going to return another string. Also we are telling that its implementation is going to be Native.NativeModule.helloWorld. What is going to happend if we try to run our tests again?

If we do it, we will see an error in the terminal:

ReferenceError: _user$project$Native_NativeModule is not defined

What does it mean? Elm compiler is telling us that it is trying to find a native module with the name _user$project$Native_NativeModule, that it because in Elm all the packages are scoped by the username and the project name where they are stored in github. If you change the content of the line repository in tests/elm-package.json for something like https://github.com/gabrielperales/elm-native-module.git and then you run elm-test again you will see that now it is trying to find _gabrielperales$elm_native_module$Native_NativeModule. Let's going to implement that module!

Create a new file in src/Native called NativeModule.js and write this code there:

var _gabrielperales$elm_native_module$Native_NativeModule = function(){
  function helloWorld(name){
    return "Hello " + name + "!";
  }

  return {
    helloWorld: helloWorld
  };
}();

(In your project, you can again rename NativeModule.js to something more appropriate, but the parent directory must be Native for it to be found, at least with current Elm).

You will also need to modify your elm-package.json file to include the directive:

{
    ...
    "native-modules": true,
    ...
}

The last thing we have to do is import that native module inside our elm module. You only have to type import Native.NativeModule under you module definition.

Your module should end looking like this:

module NativeModule exposing (helloWorld)
{-| Creating our first native module

# helloWorld function
@docs helloWorld
-}
import Native.NativeModule

{-| This function will return 'Hello ' prepended to the name you are passing to it
-}
helloWorld : String -> String
helloWorld =
    Native.NativeModule.helloWorld

Finally, we can run our first test again and it should pass.

Now we can write a new test to check that every thing works as we were expecting.

, test "name" <|
    \() ->
        Expect.equal (helloWorld "Gabi") "Hello Gabi!"

If everything is ok, it also should pass that test.

For functions of more than one argument, you can wrap the function with FN, where N is the number of arguments. This turns the function into one that can be called using Elm conventions, while still being written as a normal Javascript function. For example:

var _gabrielperales$elm_native_module$Native_NativeModule = function(){
  function sum(one, two){
    return one + two;
  }

  return {
    sum: F2(sum)
  };
}();

The functions F2, F3... F9 are provided by Elm.

Open Source Agenda is not affiliated with "Elm Native Module" Project. README Source: gabrielperales/elm-native-module
Stars
34
Open Issues
0
Last Commit
6 years ago

Open Source Agenda Badge

Open Source Agenda Rating