Loading "modules" in Mojolicious - perl

Need for help. Necessary to implement the installation and loading of "modules". "Module" plug-in is located in the file like lib//. I think I should somehow take the search subdirectories lib/ for "module", load the plugin to check if it is installed, and install it if not (for example, MyApp::MyModule->install()). The plugin contains "module", helpers, etc. Does you have anything ideas?
seems like final code:
# Load Core
my $_core = $self->plugin('FW::Core');
# Load modules
my $plugins = FW::Core::Model::Module->select->hashes();
if(#$plugins) {
$self->plugin('FW::' . ucfirst $_->{name}) for #$plugins;
}

Module::Pluggable

Related

Installing additional files at install time with ExtUtils::MakeMaker/Dist::Zilla (dzil)

tl;dr I want to ship a package.json with my Perl library, run yarn install (or npm install during the installation) and install the downloaded JavaScript dependencies with the Perl modules.
I have the following dist.ini:
name = Foobar
version = 1.2.3
license = Perl_5
copyright_holder = Yours Truly
copyright_year = 2018
[#Filter]
-bundle = #Basic
-remove = GatherDir
[Git::GatherDir]
[Web::FileHeader]
header_filename = EMM-include.pm
file_match = ^Makefile\.PL$
The file EMM-include.pm contains a MY::postamble method:
package MY;
use strict;
use Cwd qw(abs_path);
use File::Spec;
sub postamble {
my ($self) = #_;
my $here = Cwd::abs_path();
my $libdir = File::Spec->catdir($here, 'lib', 'Foobar');
chdir $libdir or die;
0 == system 'yarn', 'install' or die;
chdir $here or die;
return '';
}
The plug-in [Web::FileHeader] takes the file and patches it to the beginning of Makefile.PL.
Then there is a lib/Foobar/package.json:
{
"name": "foobar",
"version": "1.2.3",
"main": "index.js",
"dependencies": {
"ajv": "^6.5.4"
}
}
The MY::postamble section from EMM-include.pm invokes yarn install (replace it with npm install if you don't have yarn) and populate the directory lib/Foobar/node_modules with ajv and its dependencies.
Finally, there must be a module lib/Foobar.pm:
package Foobar;
# ABSTRACT: Just a test.
1;
That almost works as intended: The distribution can be created with dzil build. In the distribution directory, perl Makefile.PL invokes yarn install, the directory lib/Foobar/node_modules gets populated but the files in there are not installed with make install.
If I run perl Makefile.PL a second time, everything works, the JavaScript dependencies make it into blib/ and make install would install the JavaScript modules alongside the Perl modules.
Shipping the JavaScript dependencies with the distribution is not an option. They are already too many and they may have conflicting licenses (I am using GPLv3 here). Downloading the deps at runtime, after the installation will mostly fail because of missing privileges.
True, this has not that much to do with Dist::Zilla, it's rather a problem with ExtUtils::MakeMaker. But I am actually using Dist::Zilla here.
In case it matters, the real distribution is https://github.com/gflohr/qgoda and the last commit at the time of this writing is https://github.com/gflohr/qgoda/commit/3f34a3dfec8da665061432c3a8f7bd8eef28b95e.
First, instead of using [Web::FileHeader] to alter your Makefile.PL, replace [MakeMaker] (used by #Basic) with [MakeMaker::Awesome], which allows you to modify Makefile.PL directly, and correctly enables dynamic_config since your distribution needs it. Also, don't give your include-file a .pm extension since it's not a perl module, and exclude it from being gathered into the resulting distribution so it doesn't accidentally get installed.
[#Filter]
-bundle = #Basic
-remove = GatherDir
-remove = MakeMaker
[Git::GatherDir]
exclude_filename = EMM-include
[MakeMaker::Awesome]
header_file = EMM-include
I strongly suggest using my #Starter bundle instead of the outdated #Basic, but if not at least add [MetaJSON] so you have modern metadata.
[#Starter::Git]
revision = 3
installer = MakeMaker::Awesome
Git::GatherDir.exclude_filename[] = EMM-include
MakeMaker::Awesome.header_file = EMM-include
Regarding what needs to be done at install time. First I will caution that requiring an internet connection to install is not something you can always rely on, nor is having yarn available of course. But the Alien series of modules for installing external libraries does this sort of thing often. Since you don't need to compile this code you probably don't need the whole Alien::Build/Alien::Base setup, but it may turn out to be an easier way to solve your problem than Makefile hacking described below. Basically you would first release an Alien distribution which installs your javascript library if necessary, and then this distribution could depend on that to load the library. If you decide to pursue this direction, check out Alien::Build, and the IRC channel #native on irc.perl.org.
The postamble section for ExtUtils::MakeMaker is not for running arbitrary code; it's for adding custom rules to the Makefile it generates; this is the way you need to influence the make process. I know very little about Makefiles so I can't help you further here, all I can suggest is to read all of the EUMM docs and note that the postamble is a function from MM_Any which you override to add your text, among other options from MM_Any and MM_Unix. You may be able to find people to help you in this direction on the IRC channel #toolchain on irc.perl.org.

Change what directory Babel plugins are resolved against?

I'm getting this error:
Unknown plugin "transform-class-properties" specified in "base" at 0, attempted to resolve relative to "/home/me/Projects/myproj/src"
The message is pretty clear, so I know why it's happening, but I want to change where Babel looks for the plugins/presets/packages.
I'm using Babel with rollup via rollup-plugin-babel.
The options I'm giving it are:
{ plugins: [ 'transform-class-properties', 'transform-object-rest-spread' ],
babelrc: false }
However, I can't find an option to change where Babel looks for the plugins. Is there no way to do this without rewriting my plugins list to use absolute paths?
I also can't find a public API method for extracting the dependencies from .babelrc, so it's pretty hard to manually rewrite the file to use full paths. N.B. Babel configs might also be stored in package.json, and there's been some talk about adding support for .babelrc.js too -- I really don't want to maintain my own project that searches for all the different places a babel config might be hiding, parse the file(s), and scan it for all the plugins, with and without the arbitrary babel-plugin- prefixes.
You can use NODE_PATH to do the same.
$ npx babel test.js
Unknown plugin "external-helpers" specified in "/Users/tarun.lalwani/Desktop/babeltest/.babelrc" at 0, attempted to resolve relative to "/Users/tarun.lalwani/Desktop/babeltest"
After specifying the path for modules in a different location
$ NODE_PATH=/Users/tarun.lalwani/Desktop/babeltest2/node_modules npx babel test.js
function test() {
this.abc = function (url) {
return console.log(url);
};
}
NODE_PATH environment variable allows you to specify additional locations where the modules can be searched for

What is module Vs location Vs package in SystemJS configuration?

I'm little confused by various terminologies used in the SystemJS configuration. It talks about module, location, package etc...
Isn't module in JS is a single file, and package is a collection of modules or files? If so, how a module can be an alias to a package?
This is from the documentation page:
The map option is similar to paths, but acts very early in the normalization process. It allows you to map a module alias to a location or package:
Yes module is a single file, in javascript it's just the file name (with assumed .js extension) in quotes after from keyword in
import ... from 'some-module';
In SystemJS config file, paths and map can be used to define what actual file or URL that some-module refers to.
packages in config file allow you to apply a set of configuration parameters (default extension, module format, custom loader etc) for all modules in or below particular location (the key in packages object).
One of the settings in packages is main, which is similar to main in package.json in node (except that it's default value is empty, not index.js): it determines which file is loaded when the package location itself appears in from in import statement.
So, I think "how a module can be an alias to a package?" question about this
The map option is similar to paths, but acts very early in the
normalization process. It allows you to map a module alias to a
location or package:
can be explained on this example:
paths: {
'npm:': 'node_modules/'
},
map: {
'some-module': 'npm:some-module'
},
packages: {
'some-module': {
main: './index.js'
}
}
when these map, packages and path settings are applied by SystemJS to
import something from 'some-module';
they will cause SystemJS to load a module from node_modules/some-module/index.js under baseURL.
and
import something from 'some-module/subcomponent';
is mapped to node_modules/some-module/subcomponent.js.
Note: this is based on my experience with SystemJS 0.19. I haven't tried 0.20 yet.

How to exclude certain files from a package managed by jspm and systemjs?

For instance with bower I could do something like this to get only the scss files (excluding js):
{
"dependencies": {
"bootstrap-sass": "~3.3.5"
},
"overrides": {
"bootstrap-sass": {
"main": [
"assets/stylesheets/_bootstrap.scss"
]
}
}
}
I am having an hard time understanding how to do it with systemjs. in the config.js file I guess but even reading the docs I could not figure it out.
My use case is: while developing I am loading Material angular with systemjs but I want to load only the js files, not the css, which I want to manage indenpdently in my scss. Instead systemjs keep loading the file angular-material.css. I just started with systemjs and jspm, hope you can help.
nb: my problem is not related to the jspm build or bundle process but to the development time with these tools.
JSPM supports overrides as well. See https://github.com/jspm/registry/wiki/Configuring-Packages-for-jspm#testing-configuration for configuration options.
Using JSPM overrides you can easily override the main file and directories and files that you need from a module.
Upd. The css dependency is defined in the registry: https://github.com/jspm/registry/blob/974beb8b6520f4c1b3c6373db32ad05da5c82446/package-overrides/github/angular/bower-material%400.4.0.json It needs to be overwritten with the local override.

How to add my new plugin to smarty?

I want to add a SmartyFilter class to smarty, but where to put the file so smarty can find it automatically?
Smarty comes with a plugins subdirectory. Throw your script in there and smarty will find your plugin in there.
You can extend that path by adding other directories to $smarty->plugins_dir[]
$smarty->plugins_dir[] = 'includes/my_smarty_plugins';
If your plugins are dependant on each other you may want to require a plugin yourself by doing:
require_once $smarty->_get_plugin_filepath('function', 'html_options');
This would load a plugin in plugin_dir with the name function.html_options.php.
copy and paste theme into "plugins" sub directory in main smarty folder, the file name must be leading with function.filename.php
In recent versions of Smarty, you have a method to add a plugin folder:
// Add a folder of plugins
$smarty->addPluginsDir('./plugins_1/');
// Check what plugins folders are registered
var_dump($smarty->getPluginsDir());
/* DUMP:
array(2) {
[0]=>string() "./plugins/"
[1]=> string() "./plugins_1/"
}
*/
For more information, you can read the addPluginsDir() documentation.