RubyMotion app files load order: how to load lib files before other files? - rubymotion

I have a RubyMotion project that needs to load certain directories and files earlier than others.
I want to load the /lib directory files before the /app directory files.
Research turned up many ways to adjust the load order, but no definitive answer IMHO.
Here's what I've found thus far.
To set the app files load order, use the Rakefile App setup block:
Motion::Project::App.setup do |app|
# ... put your code here
end
To choose directories:
app.files =
Dir.glob('./lib/**/*.rb') |
Dir.glob('./app/**/*.rb')
To use dependencies:
app.files_dependencies \
'app/child.rb' => 'lib/parent.rb'
To add files to the start of the load order, before gems:
app.files.unshift \
Dir.glob('./lib/**/*.rb')
To utilize the BubbleWrap gem:
BW.require './lib/**/*.rb'
To utilize the Motion Dependencies gem:
app.files =
Dir.glob('./lib/**/*.rb') |
Dir.glob('./app/**/*.rb')
app.files_dependencies Motion::Dependencies.find_dependencies(app.files)
To load vendor bundle files first, then library files, then everything else -- this seems like the best solution so far to me.
app.files = (
app.files.select{|f| f =~ %r(/vendor/bundle/) } +
app.files.select{|f| f =~ %r(/lib/) } +
app.files
).uniq
Is there a definitive way that's better?

Old question, but my opinion is that your final solution looks the nicest. I also like the DBT gem, but I usually only use it on gems.

Related

Include C++ library in Bazel project

I'm currently messing around with Google's Mediapipe, which uses Bazel as a build tool. The folder has the following structure:
mediapipe
├ mediapipe
| └ examples
| └ desktop
| └ hand_tracking
| └ BUILD
├ calculators
| └ tensor
| └ tensor_to_landmarks_calculator.cc
| └ BUILD
└ WORKSPACE
There are a bunch of other files in there as well, but they are rather irrelevant to this problem. They can be found in the git repo linked above if you need them.
I'm at a stage where I can build and run the hand_tracking example without any problems. Now, I want to include the cereal library to the build, so that I can use #include <cereal/archives/binary.hpp> from within tensors_to_landmarks_calculator.cc. The cereal library is located at C:\\cereal, but can be moved to other locations if it simplifies the process.
Basically, I'm looking for the Bazel equivalent of adding a path to Additional Include Directories in Visual Studio.
How would I need to modify the WORKSPACE and BUILD files in order to include the library in my project, assuming they are in a default state?
Unfortunately, this official doc page only covers one-file libraries, and other implementations kept giving me File could not be found errors at build time.
Thanks in advance!
First you have to tell Bazel about the code living "outside" the
workspace area. It needs to know how to find it, how to build it, and
what to call it, etc. These are known as remote repositories. They
can be local to your disk (outside the Bazel workspace area), or
actually remote on another machine or server, like github. The
important thing is it must be described to Bazel with enough
information that it can use.
As most third party code does not come with BUILD.bazel files, you may
need to provide one yourself and tell Bazel "use this as if it was a
build file found in that code."
For a local directory outside your bazel project
Add a repository rule like this to your WORKSPACE file:
# This could go in your WORKSPACE file
# (But prefer the http_archive solution below)
new_local_repository(
name = "cereal",
build_file = "//third_party:cereal.BUILD.bazel",
path = "<path-to-directory>",
)
("new_local_repository" is built-in to bazel)
Somewhere under your Bazel WORKSPACE area you'll also need to make a
cereal.BUILD.bazel file and export it from the package. I choose a directory called //third_party, but you can put it anywhere
else, and name it anything else, as long as the repository rule
provides a proper bazel label for it.) The contents might look like
this:
# contents of //third_party/cereal.BUILD.bazel
cc_library(
name = "cereal-lib",
srcs = glob(["**/*.hpp"]),
includes = ["include"],
visibility = ["//visibility:public"],
)
Bazel will pretend this was the BUILD file that "came with" the remote
repository, even though it's actually local to your repo. When Bazel fetches this remote repostiory code it copies it, and the BUILD file you provide, into its external area for caching, building, etc.
To make //third_party:cereal.BUILD.bazel a valid target in your directory, add a BUILD.bazel file to that directory:
# contents of //third_party/BUILD.bazel
exports_files = [
"cereal.BUILD.bazel",
]
Without exporting it, you won't be able to refer to the buildfile from your repository rule.
Local disk repositories aren't very portable since people may have
different versions installed and it's not very hermetic (making it
hard to share caches of builds with others), and it requires they put
them in the same place, and that kind of setup can be problematic. It
also will fail when you mix operating systems, etc, if you refer to it as "C:..."
Downloading a tarball of the library from github, for example
A better way is to download a fixed version from github, for example,
and let Bazel manage it for you in its external area:
http_archive(
name = "cereal",
sha256 = "329ea3e3130b026c03a4acc50e168e7daff4e6e661bc6a7dfec0d77b570851d5",
urls =
["https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.0.tar.gz"],
build_file = "//third_party:cereal.BUILD.bazel",
)
The sha256 is important, since it downloads and computes it, compares to what you specified, and can cache it. In the future, it won't re-download it if the local file's sha matches.
Notice, it again says build_file = //third_party:cereal.BUILD.bazel., all
the same things from new_local_repository above apply here. Make sure you provide the build file for it to use, and export it from where you put it.
*To test that the remote repository is setup ok
on the command line issue
bazel fetch #cereal//:cereal-lib
I sometimes have to clear it out to make it try again, if my rule isn't quite right, but the "bad" version sticks around.
bazel clean --expunge
will remove it, but might be overkill.
Finally
We have:
defined a remote repository called #cereal
defined a target in it called cereal-lib
the target is thus #cereal//:cereal-lib
To use it
Go to the package where you would like to include cereal, and add a
dependency on this repository to the rule that builds the c++ code that would like to use cereal. That is, in your case, the BUILD rule that causes tensor_to_landmarks_calculator.cc to get built, add:
deps = [
"#cereal//:cereal-lib",
...
]
And then in your c++ code:
#include "cereal/cereal.hpp"
That should do it.

Problem loading a DLL with boost DLL from a different path when it has dependencies

I use boost::dll for loading libraries at runtime.
With the following code, I'm able to load a DLL even when it's in a different folder than the one with the executable:
auto creator = boost::dll::import_alias<pluginapi_create_t>(fileName, "createPlugin", boost::dll::load_mode::append_decorations);
But I've got a problem when a DLL has other dependencies. This is an example of my folder structure:
Main Folder
|
|-program.exe
|
|-pluginsfolder
|
|-plugin1.dll
|-plugin2.dll
|-dependency.dll
If I load plugin1.dll (which has no other dependencies), it works.
If I load plugin2.dll, that requires dependency.dll, it doesn't work.
I suppose I could put all the DLLs in the same folder, and everything will begin to work again. But I'd like to keep plugins in separate folders because I want other users to be able to load plugins from their respective folders.
How can I load plugins with dependencies regardless their position in the filesystem?
I've found the solution, thanks to Richard comments.
This is the command:
auto creator = boost::dll::import_alias<pluginapi_create_t>(fileName, "createPlugin", boost::dll::load_mode::append_decorations | boost::dll::load_mode::load_with_altered_search_path);
I've added the boost::dll::load_mode::load_with_altered_search_path flag when loading, while searching how to use the corresponding LOAD_WITH_ALTERED_SEARCH_PATH using by windows natively.

Using custom fonts on shinyapps.io

I would like to use a custom font in my shiny app (on plots) on shinyapps.io. I have my Roboto-Regular.ttf in the ./www/ directory. And this is the upper portion of my app.R file:
dir.create('~/.fonts')
system("chmod +x ./www/Roboto-Regular.ttf")
system("cp ./www/Roboto-Regular.ttf ~/.fonts/")
system('fc-cache -f -v ~/.fonts/')
system('fc-match Roboto')
library(ggplot2)
library(shiny)
library(shinythemes)
library(extrafont)
font_import(pattern="Roboto",prompt=FALSE)
loadfonts()
print(fonts())
Upon deploying the app, I end up with an error that looks like this:
Registering fonts with R
Scanning ttf files in /usr/share/fonts/, ~/.fonts/ ...
Extracting .afm files from .ttf files...
/home/shiny/.fonts/Roboto-Regular.ttfWarning in gzfile(dest, "w") :
cannot open compressed file '/opt/R/3.5.1/lib/R/library/extrafontdb/metrics/Roboto-Regular.afm.gz', probable reason 'Permission denied'
Error in value[[3L]](cond) : cannot open the connection
Calls: local ... tryCatch -> tryCatchList -> tryCatchOne -> <Anonymous>
Execution halted
Does anyone see what might be wrong?
After a bit of struggle I found an even simpler solution that works on shinyapps.io:
Here we go:
Place custom font in www directory: e.g. IndieFlower.ttf from here
Follow the steps from here
This leads to the following upper part of the app.R file:
dir.create('~/.fonts')
file.copy("www/IndieFlower.ttf", "~/.fonts")
system('fc-cache -f ~/.fonts')
Since Linux looks into the .fonts directory to search fonts, you don't need the extrafont package, but you can directly use those fonts like:
ggplot(mapping=aes(x=seq(1,10,.1), y=seq(1,10,.1))) +
geom_line(position="jitter", color="red", size=2) + theme_bw() +
theme(text=element_text(size = 16, family = "IndieFlower"))
This is the answer I received from RStudio regarding this. I haven't tested this out myself.
Hi,
Our developer was able to advise this is due to a possibly unfortunate design choice made when they created extrafont and the associated extrafontdb package. The extrafont font database is stored in the extrafontdb package directory -- that's essentially all that the extrafontdb package is used for.
This means that the extrafontdb directory needs to be user-writable. If the user installs the package, this will work fine, but if root installs the package (as is the case on shinyapps.io), then it won't work.
One potential workaround is to install the extrafontdb package to library that is in subdirectory of the app.
To do it: create an r-lib/ subdir, and download the extrafontdb source package there:
dir.create('r-lib')
download.file('https://cran.r-project.org/src/contrib/extrafontdb_1.0.tar.gz','r-lib/extrafontdb_1.0.tar.gz')
When deployed, the app will include this r-lib/ subdirectory and the extrafontdb source package.
Then, at the top of the app, install the extrafontdb package from the source package, into the r-lib directory.
.libPaths(c('r-lib', .libPaths()))
install.packages('r-lib/extrafontdb_1.0.tar.gz',type = 'source',repos = NULL)
They deployed an app on shinyapps.io that does the extrafontdb installation, and it works fine. The libpath is set so so that install.packages() will install from the provided source package to the r-lib/ subdirectory of the app.
Please let us know if you're able to implement the above or have any additional questions.
Thanks,
Adding an alternative answer to symbolrush's answer which I found did not work. Here was the code I used initially:
# Add fonts to shiny linux server
if (Sys.info()[['sysname']] == 'Linux') {
dir.create('~/.fonts')
fonts = c(
"www/IBMPlexSans-Regular.ttf",
"www/IBMPlexSans-Bold.ttf",
"www/IBMPlexSans-Medium.ttf"
)
file.copy(fonts, "~/.fonts")
system('fc-cache -f ~/.fonts')
}
# Load fonts and set theme
font_paths("fonts")
font_add("IBMPlexSans", regular = "IBMPlexSans-Regular.ttf")
font_add("IBMPlexSans-Bold", regular = "IBMPlexSans-Bold.ttf")
font_add("IBMPlexSans-Medium", regular = "IBMPlexSans-Medium.ttf")
showtext_auto()
The bizarre thing is that the first instance of the app on shinyapps.io worked, including the custom fonts. However when the app went to sleep and was opened a second time, I get this error in the log:
Error in value[[3L]](cond) : font file not found for 'regular' type
I was never able to debug why this was the case, but I tried a simpler solution that has worked perfectly so far. I moved my fonts to a /font folder in the app folder (I don't think using the /www folder is necessary) and added the /font folder using path_folder():
library(showtext)
# Load fonts and set theme
font_paths("fonts")
font_add("IBMPlexSans", regular = "IBMPlexSans-Regular.ttf")
font_add("IBMPlexSans-Bold", regular = "IBMPlexSans-Bold.ttf")
font_add("IBMPlexSans-Medium", regular = "IBMPlexSans-Medium.ttf")
showtext_auto()
I hope this helps anyone who is having problems with their app not running after the first instance, as I could not find the same situation anywhere on stackoverflow.

How publish a directory with ring middleware?

I am trying to use Clojure + Compojure + Ring in combination with the qooxdoo JS library. This is actually going well, but qooxdoo runs in two modes "build" (that works for me) and "source" (not so good). In the latter case, the JS generated by qooxdoo actually hardcodes references (well, using relative addresses ../../..) back to the qooxdoo installation and at run time it asks for sth like:
http://localhost:3000/opt/qooxdoo-5.0.1-sdk/framework/source/class/qx/bom/client/OperatingSystem.js
...since I have the library installed under /opt/qooxdoo-5.0.1-sdk.
Serious sanity check: if I directly open the index.html in the browser, it works fine. So it seems I just have to figure out how to serve the static files under the /opt library install.
I have tried wrap-file from the ring.middleware.file because that sounds like what I want but no matter what path I give it I get hundreds of 404s as it tries to pick up each framework file individually from the installed library.
I can work OK under "build" (qooxdoo cobbles together a single minified .js I serve with wrap-resource) but on occasion I need to run in source mode to find JS bugs.
Am I missing something simple?
The correct way to handle this is to configure Qooxdoo to tell it what URIs you would like to use - by default the source build does just use relative paths, but you can easily override this by editing the config.json.
In your config.json you will have a "jobs" section containing a "libraries" section, containing a "library" array - your application is a library, as is Qooxdoo, as is any contribs so it will look something like this:
"jobs" : {
"libraries" : {
"=library" : [ {
"manifest" : "${QOOXDOO_PATH}/framework/Manifest.json"
}, {
"manifest" : "Manifest.json"
}
},
Each "library" object can have a "uri" property, so for your example you probably want something like this:
"jobs" : {
"libraries" : {
"=library" : [ {
"manifest" : "${QOOXDOO_PATH}/framework/Manifest.json",
"uri" : "/opt/qooxdoo-5.0.1-sdk"
}, {
"manifest" : "Manifest.json"
}
},
Simple indeed: (wrap-file "/")
In development/source mode qooxdoo works off the installation directory instead of code pulled into my local tree, and does so by hardcoding relative paths that resolve to an absolute /opt/qooxdoo-etc path.
This looks to the server like a relative "opt/qooxdoo..." file request, so I had to offer root ("/") as a search directory.
(wrap-file "/") is a serious security issue since you're offering the root directory for all.
What you can potentially do is to make a dedicate directory to server your static file, and serve your content from there.
su
mkdir -p /var/clojure/static/opt
cd /var/clojure/static/opt
ln -s /opt/qooxdoo-5.0.1-sdk qooxdoo-5.0.1-sdk
chown -r YOUR-USER-ID /var/clojure/static/opt
And use the middleware: (wrap-file "/var/clojure/static") to serve your file.
There is a section in the manual that deals with the issue of serving a source version through a web server.
I guess you found the basic insight yourself, that the web server must export a root where the relative paths used in the generated loader match URL paths under that web server. (The rational behind this is that the source version uses all the JS files from all involved libraries directly from disk.)
In the worst case that might mean you need to export the file system root ("/") from your web server. As you are doing this on a local development machine this shouldn't be much of a problem. If security is a concern you might want to collect your qooxdoo environment under some innocent path like /home/kenny/devel/qooxdoo, containing the qooxdoo SDK, your app, and all libs/contribs you might be using.
If you follow the above link you will also find some help from the qooxdoo tool chain. E.g. if you run generate.py source-httpd-config[*] it will tell you which path on your local disk is the closest parent directory that will encompass all necessary libraries, i.e. needs to be exported in your web server for the source version to work.
Alternatively, as John wrote you can export each qooxdoo lib through an individual path under your web server, and then tell your main application where to find it. You might actually need to give a proper URL like http://localhost/libs/qooxdoo-5.0.1-sdk/framework, not just a file system path as John suggests. Also remember that you have to go as far as the directory where the Manifest file resides (hence the above path ending in .../framework). See this manual section for a deep dive.

Foundation 5 custom sass project setup

I have a project that I would like to use foundation 5 with. I have been through the steps of creating a new foundation project using the CLI but I don't like it. There is too many files and the structure does not match what I want. So...
I am intending to add only the required files to my project and use compass to compile all the css.
I have noticed in the project created on the CLI a few things that confuse me and would like some help in clearing them up.
In the project created on the CLI there are two _settings.scss files one under the foundation directory in bower_components and one in MY_PROJECT\scss. I'm assuming that because of this add_import_path "bower_components/foundation/scss" line in the config.rb, which of those files has preference?
Why does MY_PROJECT/stylesheets not have normalize.css (or foundation.css) in it? And how are they not there? (in my custom setup they are being generated, albeit in subdirectories of stylesheets, also the foundation.css that is being generated for me has no settings changes applied so I guess it shouldn't be being generated)
If you take a look inside \bower_components\foundation\scss you'll see the file foundation.scss. That file imports all the stylesheets for all the additional components that come in the Foundation 5 "package." In your root scss directory, the app.scss is what compiles the SASS into \stylesheets\app.css. So rather than this:
#import "foundation";
Uncomment the individual components you'll be using. Something like this:
#import
//"foundation/components/accordion",
//"foundation/components/alert-boxes",
"foundation/components/block-grid",
//"foundation/components/breadcrumbs",
//"foundation/components/button-groups",
//"foundation/components/buttons",
"foundation/components/clearing",
"foundation/components/dropdown",
//"foundation/components/dropdown-buttons",
//"foundation/components/flex-video",
"foundation/components/forms",
"foundation/components/grid",
//"foundation/components/inline-lists",
//"foundation/components/joyride",
//"foundation/components/keystrokes",
//"foundation/components/labels",
//"foundation/components/magellan",
//"foundation/components/orbit",
//"foundation/components/pagination",
//"foundation/components/panels",
//"foundation/components/pricing-tables",
//"foundation/components/progress-bars",
"foundation/components/reveal",
"foundation/components/side-nav",
//"foundation/components/split-buttons",
"foundation/components/sub-nav",
//"foundation/components/switches",
"foundation/components/tables",
//"foundation/components/tabs",
//"foundation/components/thumbs",
//"foundation/components/tooltips",
"foundation/components/top-bar",
"foundation/components/type",
"foundation/components/offcanvas",
"foundation/components/visibility";
If you'd like to streamline your file structure, I would suggest you remove any scss files from the \bower_components\foundation\scss\foundation\components directory that you will not use. Same with the js directory. You don't actually need to modify anything in the bower_components directory to get everything to work. Not entirely sure why it's all contained within bower_components, but I imagine it's got something to do with being able to update the core components later with future releases.
Someone else could probably give a more educated answer.
p.s. - make sure to compass watch in your CLI to see any of those changes made to your SASS files.