Re: [code] [textadept] Required Modules

From: Qwerky <mr.qwerky.att.gmail.com>
Date: Thu, 15 Aug 2019 12:37:09 -0600

Hi Mitchell,

On 2019-08-15 06:52, Mitchell wrote:
> Hi Qwerky,
>
> On Wed, 14 Aug 2019, Qwerky wrote:
>
>> Hi Mitchell,
>>
>> On 2019-08-14 15:06, Mitchell wrote:
>>> Hi Qwerky,
>>>
>>> On Wed, 14 Aug 2019, Qwerky wrote:
>>>
>>>> Hi Mitchell,
>>>>
>>>> On 2019-08-14 14:24, Mitchell wrote:
>>>>> Hi Qwerky,
>>>>>
>>>>> On Wed, 14 Aug 2019, Qwerky wrote:
>>>>>
>>>>>> Hi.  If the user init.lua requires a module [foo =
>>>>>> require('foo')] which
>>>>>> has
>>>>>> a function 'bar', is that module and its function then available
>>>>>> to all
>>>>>> other
>>>>>> modules?
>>>>>>
>>>>>> So, in keys.lua, can one write 'keys.ab = foo.bar'?  Or, does
>>>>>> 'foo' need
>>>>>> to
>>>>>> be required in keys.lua, as well as every other module which uses
>>>>>> 'foo.bar'?
>>>>>
>>>>> It depends.
>>>>>
>>>>>> From your *~/.textadept/init.lua*, the statement:
>>>>>
>>>>>   foo = require('foo')
>>>>>
>>>>> defines a global variable `foo` that, from this point forward in
>>>>> Textadept's init process, is available to all code that comes after
>>>>> (including required modules). However, any modules loaded prior to
>>>>> that
>>>>> statement (such as *~/.textadept/modules/textadept/keys.lua*) can
>>>>> access
>>>>> global `foo` from within functions (not at top-level file scope).
>>>>>
>>>>> In your case for *keys.lua*, you'd probably need `keys.ab =
>>>>> require('foo').bar` since it's at top-level file scope and Textadept
>>>>> loads
>>>>> that before your *~/.textadept/init.lua*.
>>>>>
>>>>> I hope this makes sense.
>>>>>
>>>>> Cheers,
>>>>> Mitchell
>>>>
>>>> Yes, it does make sense; thanks for a good explanation. That fits my
>>>> experience, where keys.lua gave an error on that key binding /unless/
>>>> 'foo'
>>>> was required, even though it was required in init.lua.
>>>>
>>>> What I am trying to accomplish, is key bindings within keys.lua,
>>>> that do
>>>> not
>>>> fail with an error when the module containing the function is not
>>>> loaded;
>>>> they simply do not have any effect.
>>>>
>>>> So, I tried a global variable within 'foo' (foo_loaded), and then in
>>>> keys.lua:  'keys[foo_loaded and 'ab'] = foo.bar', so that if
>>>> 'foo_loaded'
>>>> does not exist, the key binding should do nothing. But this also
>>>> gave an
>>>> error, even when 'foo' was required in keys.lua.
>>>>
>>>> And, having to require 'foo' within keys.lua also gives an error when
>>>> 'foo'
>>>> does not exist; whereas when it is required in init.lua via the
>>>> /modules/common/ directory and code, there is no error when the module
>>>> isn't
>>>> there.
>>>>
>>>> So, a way to fail silently when a module doesn't exist, is what I'm
>>>> looking
>>>> for.
>>>>
>>>> If the binding 'keys[foo_loaded and 'ab'] = foo.bar' is within a
>>>> function
>>>> within keys.lua, then it should work?  So then the question is, how
>>>> does
>>>> one
>>>> get a function within a module, to execute when the module is loaded?
>>>
>>> You can query `package.loaded['foo']`. It will return a truthy value
>>> if the
>>> module has been loaded, and `nil` if the module hasn't been loaded.
>>>
>>> You can also do `if not pcall(require, 'foo') then ... end` which would
>>> catch a require error without propagating it.
>>>
>>> Cheers,
>>> Mitchell
>>
>> Using Control-E followed by ui.print(package.loaded['foo']) gives
>> 'true' for
>> 'keys', but 'nil' for 'menu', 'init', and every other module I tried
>> (with
>> variations, such as 'menu.lua', etc.).
>
> You need the full module name, as if you were requiring it yourself:
>
>   package.loaded['textadept.menu']
>
>>
>> Placing this code in keys.lua:
>>
>> if pcall(require, 'common/foo') then
>>
>>   keys['ab'] = bar
>>
>> else
>>
>> end
>>
>> causes the binding to work when 'foo' is there, and to fail silently
>> when it
>> is not.  That's great; part way there.  The problem is that it
>> requires the
>> path, so it won't work if the user placed 'foo.lua' as
>> 'modules/foo/init.lua'
>> rather than 'modules/common/foo.lua'.
>>
>> Still not sure how to cause a function within a module, to be
>> executed when
>> the module is loaded?
>
> You need to do this manually, after loading the module. There isn't a
> 'module loaded' event.
>
> Sorry if I'm not following your use case. It seems rather complex.
>
> Cheers,
> Mitchell

Yes, it is complex; sorry.  I'm trying to learn the structure of
TextAdept, so as to code my modules in the correct fashion.  The primary
thing I'm attempting here is to avoid the use of global variables, where
possible.  [Although, I'm not in the camp that says "Absolutely no
global variables allowed!", but rather in the camp which feels that a
few globals are acceptable when necessary; though I'm certainly willing
to listen to the other side.  :-) ]

So, when one module needs to know whether another module is loaded, each
module could set a global variable signifying that it is loaded, which
the others could query.  Or, now that I understand 'package.loaded', it
could be used, the problem being that then the module doing the query
has to know exactly where the user has installed the module being sought.

Likewise, when a module needs to call a function (or examine a variable)
in another module, either those functions/variables could be made
global, or they could be exported (function M.something(), M.variable,
etc.).  But with the latter, there is the same problem of needing to
know the path where the module resides.

Also, to 'require' a module more than once in different modules, caused
an issue for me, when the module being required inserts an entry into
the main menu, in that the entry gets inserted twice when the module is
required twice.

Finally, there is the issued discussed above, where keys.lua won't see a
module that is required in init.lua, unless it is within a function
within keys.lua.  For this reason, and for the general case, I wondered
whether there was a mechanism to cause a module to execute a function
within it (an 'initialization' function, for example), when it is loaded.

qwerky

-- 
You are subscribed to code.att.foicica.com.
To change subscription settings, send an e-mail to code+help.att.foicica.com.
To unsubscribe, send an e-mail to code+unsubscribe.att.foicica.com.
Received on Thu 15 Aug 2019 - 14:37:09 EDT

This archive was generated by hypermail 2.2.0 : Fri 16 Aug 2019 - 06:29:22 EDT