How can a function get the module name of the caller? - reflection

Say I have two lua modules, like this.
Filename: my/lua/app/caller.lua
Module name: my.lua.app.caller
local reflect = require('my.lib.reflect')
-- should return "my.lua.app.caller"
reflect.get_caller_module_name()
Filename: my/lib/reflect.lua
Module name: my.lib.reflect
M = {}
function M.get_caller_module_name()
-- magic here?
return module_name
end
return M
Now running my.lua.app.caller should allow it to get its own module name, my.lua.app.caller. Is this doable in Lua?
(I realize that I can get the module name by inserting local module_name, _ = ... as the very first line of the caller's module, but I want to be able to do this without this without needing any special modifications to the caller's module.)

Related

Can't create or update records in a loop, using ActiveStorage

Ruby 2.6.3
Rails 6.0.3
I don't why, when I try to create or update a record in a loop, adding an attachment or attachments, just only one or two recoreds can be updated. I also tested this behaviour with only one attachment and only for creating. But the behaviour is the same.
In the code below, I'm trying to reload attachments on aws, using active storage. But only 1 record is updated.
namespace :uploads do
task migrate_to_active_storage: :environment do
Upload.where.not(csv_file_name: nil).find_each do |upload|
%w[csv log].map do |attachment_type|
attach_url = [
'https://',
ENV['AWS_BUCKET'],
".s3-#{ENV['AWS_REGION']}.amazonaws.com/",
upload.business.normalized_name,
'/upload/',
upload.id.to_s,
"/#{attachment_type}/",
upload.csv_file_name
].join
upload.send(attachment_type).attach(
io: open(attach_url),
filename: upload["#{attachment_type}_file_name"],
content_type: upload["#{attachment_type}_content_type"]
)
end
end
ap 'DONe WITH SUCCESS' # never appears
end
end
I've managed to fix this, using threds. But I don't know why it doesn't work in the code above.
This solution works fine.
namespace :uploads do
task migrate_to_active_storage: :environment do
uploads = Thread.new { Upload.ids }.value
uploads.each do |id|
Thread.new do
sleep 2
upload = Upload.find id
upload.update csv: get_attachment(upload, 'csv'),
log: get_attachment(upload, 'log')
end.join
end
end
end
def get_attachment(upload, attachment_type)
attachment_url = [
'https://',
ENV['AWS_BUCKET'],
".s3-#{ENV['AWS_REGION']}.amazonaws.com/",
upload.business.normalized_name,
'/upload/',
upload.id.to_s,
"/#{attachment_type}/",
upload["#{attachment_type}_file_name"]
].join
{
io: open(attachment_url),
filename: "#{upload.id}_#{upload["#{attachment_type}_file_name"]}",
content_type: upload["#{attachment_type}_content_type"]
}
end
And what is really a mystic. When I try to call a differen model, for instance, like User. And even if it does nothing, the code above won't work. Only 1 record will'be updated.

PHP Deployer: How to get user name from host setup

I am trying to deploy my code via php deployer, but I am facing a syntax issue, which is how can I re-use the host user on task?
For instance, I would like to replace USERNAME with barfoo in dynamic way. Not hard code.
Can anyone give me a suggestion? Much appropriate.
host('17.99.88.225')
->user('barfoo') // This is the server user name
->stage('production')
->set('deploy_path', '/SERVER_PATH/{{application}}')
->set('branch', 'develop');
...
task('upload:env', function () {
runLocally('scp .env USERNAME#{{hostname}}:{{release_path}}/.env');
})->desc('Environment setup');
I just figure it out myself. I would like to share here:
All I need to do is set a new variable and use it on my script. LOL
set('username', 'nanomed1'); // set my own variable
...
task('upload:env', function () {
$username = get( 'username'); // use the variable I created on the top
runLocally('scp .env '.$username.'#{{hostname}}:{{release_path}}/.env');
})->desc('Environment setup');
That's it!

How to pass a parameter from the Jupyter backend to a frontend extension

I currently have a value that is stored as an environment variable the environment where a jupyter server is running. I would like to somehow pass that value to a frontend extension. It does not have to read the environment variable in real time, I am fine with just using the value of the variable at startup. Is there a canonical way to pass parameters a frontend extension on startup? Would appreciate an examples of both setting the parameter from the backend and accessing it from the frontend.
[update]
I have posted a solution that works for nbextentions, but I can't seem to find the equivalent pattern for labextensions (typescript), any help there would be much appreciated.
I was able to do this by adding the following code to my jupter_notebook_config.py
from notebook.services.config import ConfigManager
cm = ConfigManager()
cm.update('notebook', {'variable_being_set': value})
Then I had the parameters defined in my extension in my main.js
// define default values for config parameters
var params = {
variable_being_set : 'default'
};
// to be called once config is loaded, this updates default config vals
// with the ones specified by the server's config file
var update_params = function() {
var config = Jupyter.notebook.config;
for (var key in params) {
if (config.data.hasOwnProperty(key) ){
params[key] = config.data[key];
}
}
};
I also have the parameters declared in my main.yaml
Parameters:
- name: variable_being_set
description: ...
input_type: text
default: `default_value`
This took some trial and error to find out because there is very little documentation on the ConfigManager class and none of it has an end-to-end example.

Meteor Package: Add Custom Options

I've created a Meteor smart package, and would like to add user generated custom options to the API.
However, I'm having issues due to Meteor's automatic load ordering.
SocialButtons.config({
facebook: false
});
This runs a config block that adds defaults.
SocialButtons.config = function (options) {
... add to options if valid ...
};
Which in turn grabs a set of defaults:
var defaults = {
facebook: true,
twitter: true
}
Which are mixed into the settings.
var settings = _.extend(defaults, options);
...(program starts, uses settings)...
The problem is that everything must run in the proper order.
Create SocialButtons object
Run the optional SocialButtons.config()
Create settings & run the program
How can I control the load order in Meteor without knowing where a user might place the optional configuration?
Step 2 will be in a different folder/file, but must run sandwiched between steps 1 & 3.
You can't really control load order right now so it's not guaranteed but placing files at /libs are loaded first but in your case it's doesn't really matter it might be something else here is a very simple package you can view the source on how I setup default options and allow to replace those easily https://github.com/voidale/meteor-bootstrap-alerts
Figured this out.
Put your package into a /lib directory.
Include a setup function that sets the settings when called, and loads the data
Return the data from the startup function
In this case:
SocialButtons.get = function () {
return initButtons();
}
function initButtons() { ... settings, startup, return final value ... }

How to list files in folder

How can I list all files inside a folder with Meteor.I have FS collection and cfs:filesystem installed on my app. I didn't find it in the doc.
Another way of doing this is by adding the shelljs npm module.
To add npm modules see: https://github.com/meteorhacks/npm
Then you just need to do something like:
var shell = Meteor.npmRequire('shelljs');
var list = shell.ls('/yourfolder');
Shelljs docs:
https://github.com/arturadib/shelljs
The short answer is that FS.Collection creates a Mongo collection that you can treat like any other, i.e., you can list entries using find().
The long answer...
Using cfs:filesystem, you can create a mongo database that mirrors a given folder on the server, like so:
// in lib/files.js
files = new FS.Collection("my_files", {
stores: [new FS.Store.FileSystem("my_files", {"~/test"})] // creates a ~/test folder at the home directory of your server and will put files there on insert
});
You can then access this collection on the client to upload files to the server to the ~test/ directory:
files.insert(new File(['Test file contents'], 'my_test_file'));
And then you can list the files on the server like so:
files.find(); // returns [ { createdByTransform: true,
_id: 't6NoXZZdx6hmJDEQh',
original:
{ name: 'my_test_file',
updatedAt: (Date)
size: (N),
type: '' },
uploadedAt: (Date),
copies: { my_files: [Object] },
collectionName: 'my_files'
}
The copies object appears to contain the actual names of the files created, e.g.,
files.findOne().copies
{
"my_files" : {
"name" : "testy1",
"type" : "",
"size" : 6,
"key" : "my_files-t6NoXZZdx6hmJDEQh-my_test_file", // This is the name of the file on the server at ~/test/
"updatedAt" : ISODate("2015-03-29T16:53:33Z"),
"createdAt" : ISODate("2015-03-29T16:53:33Z")
}
}
The problem with this approach is that it only tracks the changes made through the Collection; if you add something manually to the ~/test directory, it won't get mirrored into the Collection. For instance, if on the server I run something like...
mkfile 1k ~/test/my_files-aaaaaaaaaa-manually-created
Then I look for it in the collection, it won't be there:
files.findOne({"original.name": {$regex: ".*manually.*"}}) // returns undefined
If you just want a straightforward list of files on the server, you might consider just running an ls. From https://gentlenode.com/journal/meteor-14-execute-a-unix-command/33 you can execute any arbitrary UNIX command using Node's child_process.exec(). You can access the app root directory with process.env.PWD (from this question). So in the end if you wanted to list all the files in your public directory, for instance, you might do something like this:
exec = Npm.require('child_process').exec;
console.log("This is the root dir:");
console.log(process.env.PWD); // running from localhost returns: /Users/me/meteor_apps/test
child = exec('ls -la ' + process.env.PWD + '/public', function(error, stdout, stderr) {
// Fill in this callback with whatever you actually want to do with the information
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if(error !== null) {
console.log('exec error: ' + error);
}
});
This will have to run on the server, so if you want the information on the client, you'll have to put it in a method. This is also pretty insecure, depending on how you structure it, so you'd want to think about how to stop people from listing all the files and folders on your server, or worse -- running arbitrary execs.
Which method you choose probably depends on what you're really trying to accomplish.

Resources