From ac2d4852fab9809c5527986e6b8af28e14f0bb78 Mon Sep 17 00:00:00 2001 From: Roman Tsisyk <roman@tsisyk.com> Date: Thu, 28 Aug 2014 15:31:32 +0400 Subject: [PATCH] Import tutorial --- src/CMakeLists.txt | 1 + src/lua/help.lua | 34 +++ src/lua/help_en_US.lua | 558 +++++++++++++++++++++++++++++++++++++++++ src/lua/init.cc | 4 +- test/box/admin.result | 1 + 5 files changed, 597 insertions(+), 1 deletion(-) create mode 100644 src/lua/help_en_US.lua diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1df16558df..a61138a0ed 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ lua_source(lua_sources lua/errno.lua) lua_source(lua_sources lua/log.lua) lua_source(lua_sources lua/box_net_box.lua) lua_source(lua_sources lua/help.lua) +lua_source(lua_sources lua/help_en_US.lua) lua_source(lua_sources lua/tap.lua) lua_source(lua_sources lua/fio.lua) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/third_party/luafun) diff --git a/src/lua/help.lua b/src/lua/help.lua index 4fadcf3b09..6a9fe0ba93 100644 --- a/src/lua/help.lua +++ b/src/lua/help.lua @@ -1,8 +1,14 @@ +local doc = require('help.en_US') + help = {} help[1] = {} help[1]["Help topics"] = { "Tutorial", "Basics", "Administration" } help[2] = "To get help on a topic, type help('topic') (with quotes)" help[3] = "To get help on a function/object, type help(function) (without quotes)" +help[4] = "To start tutorial, type tutorial()" + +tutorial = {} +tutorial[1] = help[4] local help_function_data = {}; help_function_data["Administration"] = {} @@ -40,4 +46,32 @@ end setmetatable(help, { __call = help_call }) +local screen_id = 1; + +local function tutorial_call(table, action) + if action == 'start' then + screen_id = 1; + elseif action == 'next' or action == 'more' then + screen_id = screen_id + 1 + elseif action == 'prev' then + screen_id = screen_id - 1 + elseif type(action) == 'number' and action % 1 == 0 then + screen_id = tonumber(action) + elseif action ~= nil then + error('Usage: tutorial("start" | "next" | "prev" | 1 .. '.. + #doc.tutorial..')') + end + if screen_id < 1 then + screen_id = 1 + elseif screen_id > #doc.tutorial then + screen_id = #doc.tutorial + end + return doc.tutorial[screen_id] +end + +setmetatable(tutorial, { __call = tutorial_call }) +return { + help = help; + tutorial= tutorial; +} diff --git a/src/lua/help_en_US.lua b/src/lua/help_en_US.lua new file mode 100644 index 0000000000..4a7b80bb54 --- /dev/null +++ b/src/lua/help_en_US.lua @@ -0,0 +1,558 @@ +--- help (en_US) + +return { + tutorial = { + [[ +Tutorial -- Screen #1 -- Hello, Moon +==================================== + +Welcome to the Tarantool tutorial. +It will introduce you to Tarantool's Lua application server +and database server, which is what's running what you're seeing. +This is INTERACTIVE -- you're expected to enter requests +based on the suggestions or examples in the screen's text. + +The first request is: + +print(5.1, {'Olá', 'Lua'}) +-------------------------- + +This isn't your grandfather's "Hello World" ... +5.1 is a decimal literal, and the two strings inside +single quotes ('Hello Moon' in Portuguese) are inside +braces because they're elements of a TABLE. +More in the Lua manual: http://www.lua.org/pil/2.html + +Take that one-line request and enter it below after the +"tarantool>" prompt, then type Enter. +You'll see the response: 5.1 table: 0x40c6be58. +Then you'll get a chance to repeat -- perhaps entering +something else such as ('Longer String',, {-1,-3,0}). +When you're ready to go to the next screen, enter "tutorial('next')". +]]; + +[[ +Tutorial -- Screen #2 -- Variables +================================== + +Improve on "print(5.1, {'Olá', 'Lua'})" +by using variables rather than literals. +You don't need to declare variables in advance +because Lua figures out the data type from what +you assign to it. If the data type of variable t +is table, then the elements can be referenced +as t[1], t[2], and so on. +More in the Lua manual: http://www.lua.org/pil/1.2.html + +Request #2 is: + +n = 5.1 +t = {'Olá', 'Lua'} +print(n, t[1], t[2]) +-------------------- + +Take all three lines and enter them below after the +"tarantool>" prompt, then type Enter. +Or try different values in a different order. +When you're ready to go to the next screen, enter "tutorial('next')". +]]; + +[[ +Tutorial -- Screen #3 -- Loops +============================== + +Add action by using loops rather than static displays. +There are several syntaxes for loops in Lua, +but we'll just use one: +for variable-name = start-value, end-value, 1 do loop-body end +which is good enough if you want to assign a +start-value to a variable, do what's in the loop body, +add 1 to the variable, and repeat until it equals end-value. +More in the Lua manual: http://www.lua.org/pil/4.3.4.html. + +Request #3 is: + +n = 5.1 +t = {'Olá', 'Lua'} +for i=1,2,1 do print(n,t[i]) end +-------------------------------- + +Take all three lines and enter them below after the +"tarantool>" prompt, then type Enter. +For adventure, change the loop to "for i=1,3,1" +(don't worry, it won't crash). +When you're ready to go to the next screen, enter "tutorial('next')". +]]; + +[[ +Tutorial -- Screen #4 -- Operators +================================== + +Among the many operators that Lua supports, you most often see: +For arithmetic: * (multiply), + (add), - (subtract), / (divide). +For strings: .. (concatenate) +More in the Lua manual: http://www.lua.org/pil/3.1.html + +Request #4 is: + +n = 5.1 +t = {'Olá', 'Lua'} +for i=1,2,1 do n = n * 2 t[1] = t[1] .. t[2] end +print(n,t[1],t[2]) +------------------------------------------------ + +Before you type that in and see Tarantool display the result, +try to predict whether the display will be +(a) 20.4 OláLuaLua Lua +(b) 10.2 Olá Lua Lua Lua +(c) 5.1 Olá Lua + +The answer will appear when you type in the request. +When you're ready to go to the next screen, enter "tutorial('next')". +]]; + +[[ +Tutorial -- Screen #5 -- Conditions +=================================== + +A condition involves a comparison operator such as '==', +'>', '>=', '<', '<='. Conditions are used in statements +of the form if ... then. +More in the Lua manual: http://www.lua.org/pil/4.3.1.html + +Request #5 is: + +x = 17 +if x * 2 > 34 then print(x) else print('no') end +------------------------------------------------ + +Before you type in those two lines and see Tarantool display +the result, try to predict whether the display will be +(a) 17 +(b) 34 +(c) no +The answer will appear when you type in the request. +When you're ready to go to the next screen, enter "tutorial('next')". +]]; + +[[ +Tutorial -- Screen #6 -- Delimiters +=================================== + +This is just to prepare for later exercises +which will go over many lines. There is a +Tarantool instruction that means "don't execute +every time I type Enter; wait until I type a +special string called the 'delimiter'." +More in the Tarantool manual: http://tarantool.org/doc/master/user_guide.html#utility-tarantool-delim + +Request #4 is: + +session = require('session'); session.delimiter('!') +----------------------------------------------------- + +It's not an exercise -- just do it. +Cancelling the delimiter could be done with +session.delimiter('')! +but you'll see '!' in following exercises. + +When you're ready to go to the next screen, enter "tutorial('next')!". +Yes, "tutorial('next')!|" has to end with an exclamation mark too! +]]; + +[[ +Tutorial -- Screen #7 -- Simple Functions +========================================= + +A function, or a stored procedure that returns a value, +is a named set of Lua requests whose simplest form is +function function_name () body end +More in the Lua manual: http://www.lua.org/pil/5.html + +Request #7 is: + +n = 0 +function func () + for i=1,100,1 do n = n + i end + return n + end! +func()! +------------------------------------ + +This defines a function which sums all the numbers +between 1 and 100, and returns the final result. +The request "func()!" invokes the function. + +An admission: all the exercises that you've seen +so far have included a function invocation, namely +print(). +]]; + +[[ +Tutorial -- Screen #8 -- Improved Functions +=========================================== + +Improve the simple function by avoiding globals. +The variable n could be passed as a parameter +and the variable i could be declared as local. +More in the Lua manual: http://www.lua.org/pil/4.2.html + +Request #8 is: + +function func (n) + local i + for i=1,100,1 do n = n + i end + return n + end! +func(0)! +------------------------------------ +]]; + +[[ +Tutorial -- Screen #9 -- Comments +================================= + +There are several ways to add comments, but +one will do: (minus sign) (minus sign) comment-text. +More in the Lua manual: http://www.lua.org/pil/1.3.html + +Request #9 is: + +-- func is a function which returns a sum. +-- n is a parameter. i is a local variable. +-- '!' is a delimiter (introduced in Screen #6) +-- func is a function (introduced in Screen #7) +-- n is a parameter (introduced in Screen #8) +-- "n = n + 1" is an operator usage (introduced in Screen #4) +-- "for ... do ... end" is a loop (introduced in Screen #3) +function func (n) -- n is a parameter + local i -- i is a local variable + for i=1,100,1 do n = n + i end + return n + end! +-- invoke the function +func(0)! +------------------------------------------- + +Obviously it will work, so just type "tutorial('next')!" now. +]]; + +[[ +Tutorial -- Screen #10 -- Packages +================================== + +Many developers have gone to the trouble of making +packages of functions (sometimes called "modules") +that have a general utility. +More in the Luarocks list: http://luarocks.org/ + +Most packages have to be "required", with the syntax +variable_name = require('package-name') +which should look familiar because earlier you said +session = require('session') + +At this point, if you just say the variable_name, +yuou'll see a list of the package's members and +functions. If then you use a "." operator as in +package-variable-name . function_name() +you'll invoke a package's function. +(At a different level you'll have to use a ':' +operator, as you'll see in later examples.) + +Request #10 is: + +session! +session.user()! +--------------- + +First you'll see a list of functions, one of which +is 'user'. Then you'll see the name of the current +user, which happens to be 'admin', which happens to +be you. +]]; + +[[ +Tutorial -- Screen #11 -- The socket package +============================================ + +Connect to the Internet and send a message to the parent of +Tarantool, the mail.ru corporation. + +Request #11 is: + +function socket_get () + local socket, sock + socket = require('socket') + sock = socket.tcp() + sock:connect('mail.ru', 80) + sock:send('GET / HTTP/1.0\n\n') + sock:recv(17) + sock:close() + end! +socket_get()! +-------------------------------- + +Briefly these requests are opening a socket +and sending a 'GET' request to mail.ru's server. +The response will be short -- "- "HTTP/1.0 200 OK\r\n"" -- +but it shows you've gotten in touch with a distant server. +More in the Tarantool manual: +http://tarantool.org/doc/master/user_guide.html#sp-box-socket +]]; + +[[ +Tutorial -- Section #12 -- Fibers +================================= + +Make a function that will run like a daemon in the +background until you cancel it. For this you need +a fiber. Tarantool is a "cooperative multitasking" +application server, which means that multiple +tasks each get a slice, but they have to yield +occasionally so that other tasks get a chance. +That's what a properly designed fiber will do. +More in the Tarantool manual: +http://tarantool.org/doc/master/user_guide.html#sp-box-fiber + +Request #12 is: + +fiber = require('fiber')! +function function_x() + local i + gvar = 0 + for i=0,600,1 do + gvar = gvar + 1 + fiber.sleep(1) + end + end! +fid = fiber.wrap(function_x)! +print(gvar)! +----------------------------- + +The fiber.sleep(1) function will go to sleep for +one second, which is one way of yielding. +So the "for i=0,600,1" loop will go on for about 600 seconds (10 minutes). +During waking moments, gvar will go up by 1 -- and +gvar is deliberately a global variable. So it's +possible to monitor it: slowly type print(gvar)! a few +times and notice how the value mysteriously increases. +]]; + +[[ +Tutorial -- Screen #13 -- Tarantool's box package +================================================= + +So far you've seen Tarantool in action as a +Lua application server. Henceforth you'll see +it as a DBMS (database management system) server +-- with Lua stored procedures. + +The database administrator has already created some +database objects and granted read/write access to a user +named 'admin' -- that's you -- so you can start +manipulating data immediately. +More in the Tarantool manual: +http://tarantool.org/doc/master/user_guide.html#databases + +Request #13 is: + +box.space.tutor! +---------------- + +You'll see a description of a space named tutor. +To understand the description, you just have to know that: +** fields are numbered item-storage areas + (vaguely like columns in an SQL DBMS) +** tuples are collections of fields, as are Lua tables + (vaguely like rows in an SQL DBMS) +** spaces are where Tarantool stores sets of tuples + (vaguely like databases in an SQL DBMS) +** indexes are objects that make lookups of tuples faster + (vaguely like indexes in an SQL DBMS) +Much of the description doesn't mattter right now; it's +enough if you see that package box has a space which is +named tutor, and it has one index on the first field. +]]; + +[[ +Tutorial -- Screen #14 -- box.select() +====================================== + +The most common data-manipulation function is box.select(). + +One of the syntaxes is: +box.space.tutor.index.primary:select({1}, {iterator = 'GE'}) +and it returns a set of tuples via the index of the tutor +space. +Now that you know that, and considering that you already +know how to make functions and loops in Lua, it's simple +to figure out how to search and display the first five +tuples in the database. + +Request #14 is: + +-- This function will select and display 5 tuples in space=tutor +function database_display (space_name) +local t, i +t = box.space[space_name].index.primary:select({1}, {iterator = 'GE'}) +for i=1,5,1 do + print(t[i]) + end +end! +database_display('tutor')! + +So select() is returning a set of tuples into a Lua table +named t, and the loop is going to print each element of +the table. That is, when you call database_display()! you'll +see a display of what's in the tuples. +]]; + +[[ +Tutorial -- Screen #15 -- box.replace() +======================================= + +Pick any of the tuples that were displayed on the last screen. +Recall that the first field is the indexed field. +That's all you need to replace the rest of the fields with +new values. The syntax of box.replace(), pared down, is: +box.space.tutor:replace{primary-key-field, other-fields} +More in the Tarantool manual: +More in the Tarantool manual: +http://tarantool.org/doc/master/user_guide.html#box.replace +Tarantool by default keeps database changes in memory, +but box.replace() will cause a write to a log, and log +information can later be consolidated with another box +function (box.snapshot). + +Request #15 is: + +box.space.tutors:replace{1, 'My First Piece Of Data'}! +------------------------------------------------------ + +If there is already a "tuple" (our equivalent of a record) +whose number is equal to 1, it will be replaced with your +new data. Otherwise it will be created for the first time. +The display will be the formal description of the new tuple. +]]; + +[[ +Tutorial -- Screen #16 -- Create your own space +=============================================== + +You've now selected and replaced tuples from the +tutor space, and you could select and replace many +tuples because you know how to make variables and +functions and loops that do selecting or replacing. +But you've been confined to a space and an index +that Tarantool started with. +Suppose that you want to create your own. +More in the Tarantool manual: +http://tarantool.org/doc/master/user_guide.html#box.schema + +Request #16 is: + +box.schema.create_space('test', {engine='memtx'})! + +The new space's name will be 'test' and the engine +will be 'memtx' -- the engine which keeps all tuples +in memory, and writes changes to a log file to ensure +that data can't be lost. Although 'memtx' is the +default engine anyway, specifying it does no harm. +]]; + +[[ +Tutorial -- Screen #17 -- Create your own index +=============================================== + +Having a space isn't enough -- you must have at +least one index. Indexes make access faster. +Indexes can be declared to be "unique", which +is important because some combination of the +fields must be unique, for identification purposes. +More in the Tarantool manual: +http://tarantool.org/doc/master/user_guide.html#box.create_index + +Request #17 is: + +box.space.test:create_index('primary',{unique = true, parts = {1, 'NUM'}})! +box.space.test:create_index('secondary',{parts = {2, 'STR'}})! +-------------------------------------------------------------- + +This means the first index will be named primary, +will be unique, will be on the first field of each +tuple, and will be numeric. The second index will +be named secondary, doesn't have to be unique, will +be on the second field of each tuple, and will be +in order by string value. +]]; + +[[ +Tutorial -- Screen #18 -- Insert multiple tuples +================================================ + +In a loop, put some tuples in your new space. +Because of the index definitions, the first field +must be a number, the second field must be a string, +and the later fields can be anything. +Use a function in the Lua string library to make +values for the second field. +More in the Lua manual: http://www.lua.org/pil/20.html + +Request #18 is: + +for i=65,70,1 do + box.space.test:replace{i, string.char(i)} + end! +------------------------------------------- + +Tip: to select the tuples later, use the function +that you created earlier: database_display('test')! +]]; + +[[ +Tutorial -- Screen #19 -- Become another user +============================================= + +Remember, you're currently 'admin' -- administrator. +Now switch to being 'guest', a much less powerful user. + +Request #19 is: +session.su('guest') -- switch user to 'guest'! +box.space.test:replace{100,''} -- try to add a tuple! +------------------------------- + +The result will be an error message telling you that +you don't have the privilege to do that any more. +That's good news. It shows that Tarantool prevents +unauthorized users from working with databases. +But you can say session.su('admin')! to become +a powerful user again, because for this tutorial +the 'admin' user isn't protected by a password. +]]; + +[[ +Tutorial -- Screen #20 -- The Bigger Tutorials +============================================== + +You can continue to type in whatever Lua instructions, +package requires, and database-manipulations you want, +here on this screen. But to really get into Tarantool, +you should download it so that you can be your own +administrator and create your own databases. The +Tarantool manual has two significant tutorials: + +Insert one million tuples with a Lua stored procedure +http://tarantool.org/doc/master/user_guide.html#lua-tutorial-insert +and +Sum a JSON field for all tuples +http://tarantool.org/doc/master/user_guide.html#lua-tutorial-sum + +Request #20 is: + +((Whatever you want. Enjoy!)) + +When you're finished, don't type "tutorial('next')!", just wander off +and have a nice day. +]]; + }; --[[ tutorial ]]-- +} diff --git a/src/lua/init.cc b/src/lua/init.cc index 87e23d225a..d15539dce8 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -75,12 +75,12 @@ extern char uuid_lua[], console_lua[], box_net_box_lua[], help_lua[], + help_en_US_lua[], tap_lua[], fio_lua[]; static const char *lua_sources[] = { init_lua, - help_lua, NULL }; @@ -94,6 +94,8 @@ static const char *lua_modules[] = { "console", console_lua, "tap", tap_lua, "fio", fio_lua, + "help.en_US", help_en_US_lua, + "help", help_lua, NULL }; diff --git a/test/box/admin.result b/test/box/admin.result index b6f0ca7529..23cc870ad5 100644 --- a/test/box/admin.result +++ b/test/box/admin.result @@ -15,6 +15,7 @@ help() - Administration - To get help on a topic, type help('topic') (with quotes) - To get help on a function/object, type help(function) (without quotes) + - To start tutorial, type tutorial() ... box.cfg --- -- GitLab