Difference between revisions of "Require"

From ComputerCraft
Jump to navigation Jump to search
m (Fix code formatting)
(Try to explain modules and require in more detail)
Line 20: Line 20:
 
     }}
 
     }}
 
}}
 
}}
 +
 +
==Creating a library for <code>require</code>==
 +
A library is a collection of useful functions and other definitions which is stored separately to your main program. You might want to create a library because you have some functions which are used in multiple programs, or just to split your program into multiple more modular files.
 +
 +
Let's say we want to create a small library to make working with the [[term|terminal]] a little easier. We'll provide two functions: <code>reset</code>, which clears the terminal and sets the cursor to (1, 1), and <code>write_center</code>, which prints some text in the middle of the screen.
 +
 +
Start off by creating a file called <code>more_term.lua</code>:
 +
 +
<nowiki>
 +
local function reset()
 +
  term.clear()
 +
  term.setCursorPos(1, 1)
 +
end
 +
 +
local function write_center(text)
 +
  local x, y = term.getCursorPos()
 +
  local width, height = term.getSize()
 +
  term.setCursorPos(math.floor((width - #text) / 2) + 1, y)
 +
  term.write(text)
 +
end
 +
 +
return { reset = reset, write_center = write_center }
 +
</nowiki>
 +
 +
Now, what's going on here? We define our two functions as one might expect, and then at the bottom return a table with the two functions. When we require this library, this table is what is returned. With that, we can then call the original functions. Now create a new file, with the following:
 +
 +
<nowiki>
 +
local more_term = require("more_term")
 +
more_term.reset()
 +
more_term.write_center("Hello, world!")
 +
</nowiki>
 +
 +
When run, this'll clear the screen and print some text in the middle of the first line.
 +
 +
==<code>require</code> in depth==
 +
While the previous section is a good introduction to how <code>require</code> operates, there are a couple of remaining points which are worth mentioning for more advanced usage.
 +
 +
===Libraries can return anything===
 +
In our above example, we return a table containing the functions we want to expose. However, it's worth pointing out that you can return ''anything'' from your library - a table, a function or even just a string! <code>require</code> treats them all the same, and just returns whatever your library provides.
 +
 +
===Module resolution and the package path===
 +
In the above examples, we defined our library in a file, and <code>require</code> read from it. While this is what you'll do most of the time, it is possible to make <code>require</code> look elsewhere for your library, such as downloading from a website or loading from an in-memory library store.
 +
 +
As a result, the ''module name'' you pass to <code>require</code> doesn't correspond to a file path. One common mistake is to load code from a sub-directory using <code>require("folder/library")</code> or even <code>require("folder/library.lua")</code>, neither of which will do quite what you expect.
 +
 +
When loading libraries (also referred to as ''modules'') from files, <code>require</code> searches along the [[package.path|''module path'']. By default, this looks something like:
 +
 +
* <code>?.lua</code>
 +
* <code>?/init.lua</code>
 +
* <code>/rom/modules/main/?.lua</code>
 +
* etc...
 +
 +
When you call <code>require("my_library")</code>, <code>require</code> replaces the <code>?</code> in each element of the path with your module name, and checks if the file exists. In this case, we'd look for <code>my_library.lua</code>, <code>my_library/init.lua</code>, <code>/rom/modules/main/my_library.lua</code> and so on. Note that this works ''relative to the current program'', so if your program is actually called <code>folder/program</code>, then we'll look for <code>folder/my_library.lua</code>, etc...
 +
 +
One other caveat is loading libraries from sub-directories. For instance, say we have a file <code>my/fancy/library.lua</code>. This can be loaded by using <code>require("my.fancy.library")</code> - the '.'s are replaced with '/' before we start looking for the library.
  
 
==External links==
 
==External links==
 
*[http://lua-users.org/wiki/ModulesTutorial Lua Module tutorial]
 
*[http://lua-users.org/wiki/ModulesTutorial Lua Module tutorial]
 
*[https://www.lua.org/manual/5.1/manual.html#pdf-require Lua manual for <code>require</code>]
 
*[https://www.lua.org/manual/5.1/manual.html#pdf-require Lua manual for <code>require</code>]

Revision as of 13:20, 1 February 2020

require
Function
Syntax
require()
Returns anything
API shell
Source CC:Tweaked

Searches for a module on the current library path, returning the module or raising an error if it cannot be found.

ExampleExampleLoading the cc.expect library
Loads the built-in cc.expect module, and uses it within a function
Code
local expect = require("cc.expect").expect
local function check_string(x)
  expect(1, x, "string")
end

check_string(123)
Output
bad argument #1 to 'check_string' (expected string, got number)

Creating a library for require

A library is a collection of useful functions and other definitions which is stored separately to your main program. You might want to create a library because you have some functions which are used in multiple programs, or just to split your program into multiple more modular files.

Let's say we want to create a small library to make working with the terminal a little easier. We'll provide two functions: reset, which clears the terminal and sets the cursor to (1, 1), and write_center, which prints some text in the middle of the screen.

Start off by creating a file called more_term.lua:

local function reset()
  term.clear()
  term.setCursorPos(1, 1)
end

local function write_center(text)
  local x, y = term.getCursorPos()
  local width, height = term.getSize()
  term.setCursorPos(math.floor((width - #text) / 2) + 1, y)
  term.write(text) 
end

return { reset = reset, write_center = write_center }

Now, what's going on here? We define our two functions as one might expect, and then at the bottom return a table with the two functions. When we require this library, this table is what is returned. With that, we can then call the original functions. Now create a new file, with the following:

local more_term = require("more_term")
more_term.reset()
more_term.write_center("Hello, world!")

When run, this'll clear the screen and print some text in the middle of the first line.

require in depth

While the previous section is a good introduction to how require operates, there are a couple of remaining points which are worth mentioning for more advanced usage.

Libraries can return anything

In our above example, we return a table containing the functions we want to expose. However, it's worth pointing out that you can return anything from your library - a table, a function or even just a string! require treats them all the same, and just returns whatever your library provides.

Module resolution and the package path

In the above examples, we defined our library in a file, and require read from it. While this is what you'll do most of the time, it is possible to make require look elsewhere for your library, such as downloading from a website or loading from an in-memory library store.

As a result, the module name you pass to require doesn't correspond to a file path. One common mistake is to load code from a sub-directory using require("folder/library") or even require("folder/library.lua"), neither of which will do quite what you expect.

When loading libraries (also referred to as modules) from files, require searches along the [[package.path|module path]. By default, this looks something like:

  • ?.lua
  • ?/init.lua
  • /rom/modules/main/?.lua
  • etc...

When you call require("my_library"), require replaces the ? in each element of the path with your module name, and checks if the file exists. In this case, we'd look for my_library.lua, my_library/init.lua, /rom/modules/main/my_library.lua and so on. Note that this works relative to the current program, so if your program is actually called folder/program, then we'll look for folder/my_library.lua, etc...

One other caveat is loading libraries from sub-directories. For instance, say we have a file my/fancy/library.lua. This can be loaded by using require("my.fancy.library") - the '.'s are replaced with '/' before we start looking for the library.

External links