|
|
(48 intermediate revisions by the same user not shown) |
Line 2: |
Line 2: |
| | | |
| | | |
− | === This page is still a work in progress === | + | == Introduction == |
| | | |
− | Hi you found this page before its finished.
| + | Freeplane supports groovy (.groovy) and javascript (.js) scripts out-of-the-box. |
| | | |
− | My idea is to finish it and **only then** make an announcement in the forum, and ask to add links to it in the addons wiki page.
| + | This addon '''adds support for ruby (.rb) scripts''', enabling you to '''run ruby scripts''' (ex: <code><freeplane-user-dir>/scripts/my_ruby_script.rb</code>) alongside the out-of-the-box .groovy and .js scripts. |
| | | |
− | This is to avoid misunderstandings and be able to explain the addon and how to use it with some good explanations.
| |
| | | |
− | So, if you got here congratulations, but keep the secret! The addon is already in github, so if you cant wait anylonger knock yourself out :)
| |
| | | |
− | PS: This is progressing slow but steadly, at the rythm of my very scarce free time... dont worry though, all the coding is already finished and the addon ready, the last missing piece is to make some extense docs here in this wiki to explain how it works...
| + | The addon was made with 2 purposes: |
| | | |
| + | * To '''''enable Freeplane to use/run ruby scripts'''''. <br /> To run a ruby script, you first need to '''install the FreeplaneJrubyInstaller-addon'''. <br /> Once the FreeplaneJrubyInstaller-addon is installed, you can then '''use ruby scripts in Freeplane''' <br /> This wiki page shows [[FreeplaneJrubyInstaller_Addon#How_to_install_the_FreeplaneJrubyInstaller-Addon_in_Freeplane|How to install the FreeplaneJrubyInstaller-Addon in Freeplane]] and [[FreeplaneJrubyInstaller_Addon#How_to_use_ruby_scripts_in_Freeplane|How to use ruby scripts in Freeplane ]], in a step-by-step fashion. |
| | | |
− | === Introduction === | + | * To '''''be helpfull for non-programmers who want to try first-steps-of-programming with Ruby and make simple Freeplane ruby scripts'''''. <br /> Ruby is easy to learn, has many tutorials/books written for new programmers, and the RubyLiveDebugger (included in this addon) gives an instant-gratification-labtest for ruby and freeplane scripting ([https://www.youtube.com/watch?v=dy6kDGApaKw#t=08m05s demo video]) <br /> Start by installing the addon as explained in this page, and then switch to the [[FreeplaneJrubyInstaller_-_developers|FreeplaneJrubyInstaller - developers]] wiki page. Hope you have fun :) |
| + | |
| + | |
| | | |
− | This addon '''adds support for .rb (ruby) scripts in Freeplane''', so that you can use .groovy .js '''and .rb''' scripts
| |
| | | |
| | | |
| | | |
− | Freeplane supports .groovy and .js (javascript) scripts out-of-the-box. This addon adds support for .rb (ruby) scripts, enabling you to use: <code><freeplane-user-dir>/scripts/my_ruby_script.rb</code> besides .groovy and .js scripts.
| |
| | | |
− | Also, this addon enables other future plugins to as well make use of ruby scripts (via the "scripts" node, just like with .groovy scripts)
| + | == How to install the FreeplaneJrubyInstaller-Addon in Freeplane == |
| | | |
| + | To run a freeplane '''ruby''' script, you first need to '''install the FreeplaneJrubyInstaller-addon''' in Freeplane |
| | | |
− | All this is possible because Freeplane was programmed with good design (applause to the devs :) ), using JSR223 that allows external scripting engines to be added, such as the [http://jruby.org/ Jruby interpreter] that is capable of running ruby scripts with access to Java objects (Freeplane-java-objects!).
| |
| | | |
− |
| |
| | | |
− | === How to install the FreeplaneJrubyInstaller Addon in Freeplane ===
| + | To install the addon follow the instructions bellow (click on any image to enlarge it): |
| | | |
| You dont need to manually download anything, all downloads are automatic. | | You dont need to manually download anything, all downloads are automatic. |
− |
| |
− | To install the addon follow these instructions bellow (click on any image to enlarge it):
| |
| | | |
| | | |
Line 41: |
Line 37: |
| [[File:img0.png|frame|400x200px|none|link={{filepath:img0.png}}]] | | [[File:img0.png|frame|400x200px|none|link={{filepath:img0.png}}]] |
| | | |
− | * Copy to your clipboard (without any spaces!): | + | * Copy to your clipboard THE-URL-TO-THE-ADDON (without any leading/trailing spaces! or it fails): |
| + | |
| + | THE-URL-TO-THE-ADDON: |
| + | |
| + | '''<nowiki>https://raw.githubusercontent.com/zipizap/FreeplaneJrubyInstaller/master/addon_lab/FreeplaneJrubyInstaller-v1.7.0.addon.mm</nowiki>''' |
| + | |
| + | '''<small><strike><nowiki>https://raw.githubusercontent.com/zipizap/FreeplaneJrubyInstaller/master/addon_lab/FreeplaneJrubyInstaller-v1.6.2.addon.mm</nowiki></strike></small>''' |
| + | |
| + | |
| | | |
− | THE-URL-TO-THE-ADDON: '''<nowiki>https://raw.githubusercontent.com/zipizap/FreeplaneJrubyInstaller/master/addon_lab/FreeplaneJrubyInstaller-v1.6.addon.mm</nowiki>'''
| |
| | | |
| | | |
Line 57: |
Line 60: |
| | | |
| * Open Freeplane for a second-time, and: | | * Open Freeplane for a second-time, and: |
| + | [[File:img6_2.png|frame|400x200px|none|link={{filepath:img6_2.png}}]]<br /> |
| + | [[File:img6_3.png|frame|400x200px|none|link={{filepath:img6_3.png}}]]<br /> |
| + | [[File:img6_4.png|frame|400x200px|none|link={{filepath:img6_4.png}}]]<br /> |
| | | |
| [[File:img7.png|frame|400x200px|none|link={{filepath:img7.png}}]]<br /> | | [[File:img7.png|frame|400x200px|none|link={{filepath:img7.png}}]]<br /> |
Line 69: |
Line 75: |
| | | |
| | | |
− | * The following final window should appear, which indicates that Jruby is now installed in Freeplane. Hurray, the addon is now installed! | + | * The following final window should appear, which indicates that the FreeplaneJrubyInstaller-addon is now installed! Hurray! |
| | | |
| [[File:img12.png|frame|400x200px|none|link={{filepath:img12.png}}]]<br /> | | [[File:img12.png|frame|400x200px|none|link={{filepath:img12.png}}]]<br /> |
| | | |
| + | ==== Youtube demo video: install FreeplaneJrubyInstaller Addon ==== |
| | | |
| + | https://youtu.be/sJUWTcPhOk0 |
| | | |
− | === The making of the FreeplaneJrubyInstaller addon - a long story ===
| |
− |
| |
− | I love freeplane. Since like 5 years now I use it everyday to organize my work.
| |
− |
| |
− | At first, the simple tree structure with some background colors was enough to be usefull, but with time I discovered that the multiple options of freeplane could fit my needs to better structure knowledge. No doubt a big part of freeplane-usefullness is '''how''' people use it.
| |
− |
| |
− | So, someday I gave some attention to this '''scripts''' thing that freeplane had - basically you could write some code that would use the '''[http://freeplane.sourceforge.net/doc/api/ Freeplane API]''' to programatically make freeplane do things.
| |
− | The code was in the Groovy language which is a kind of java-with-some-sugar-that-looks-a-bit-like-ruby, and I did not know groovy nor java, but ruby was (is) my prefered language and I feel very comfortable programming in ruby.
| |
− | So although with no knowledge of Groovy, I could slightly understand the groovy scripts, and managed to make a couple of simple scripts, basically from copy/pasting/modifying from examples of the [http://www.freeplane.org/wiki/index.php/Scripts_collection scripts collection page] and got my homemade very-simple-groovy-scripts going on. No groovy knowledge there, just the basic modify-try-and-error cycle, which many times is enough for simple things.
| |
− |
| |
− | Time passed, and sometimes, very rarely, I would notice that my personal usage of freeplane, could be boostered with some little scripty-automation.
| |
− | This lead me to get bolder in making Groovy scripts, and soon enough I got to the point that I had to learn/understand a little more about Groovy to make my scripts more complex - the copy/paste/modify magic was not enough any more.
| |
− |
| |
− | As it turns out, for another project, I passed the last 6 months of scarse freetime learning C++ from a "renowned" book, and out of boredoom and curiosity I casually took a Java book to my one-week-vacations (instead of C++), and in one week of late-nigh-readings I ended up feeling more confortable with Java than with with C++ after so many time.
| |
− | And that was the tipping point to drop the study of C++ in favour of Java and use Jruby for that other project. The book was Head First Java, and it made a very funny reading :)
| |
− |
| |
− | So, luck took me to learning a bit of Java, and I knew that Groovy was like java-with-some-sugar-that-looks-a-bit-like-ruby, so I started to improve my groovy scripts with the new java understanding. And it worked :) To a certain point.
| |
− | I managed to make the more complex scripts that I wanted with Java and Groovy. Still it costed me an enourmous efforth, as I could only do it in scarce free time, which meant sometimes severall weeks between code-session of a few hours, and that was my only practice of java and groovy. It was working, but carried along a steep beginner-overhead, far from efficient/productive.
| |
− |
| |
− |
| |
− |
| |
− | ==== Jruby: Freeplane can also run ruby scripts with Jruby! ====
| |
− |
| |
− | On the other hand, I did read [http://www.freeplane.org/wiki/index.php/Scripting:_Other_languages in the wiki that it is possible to use other programming languages for scripting (scala, jython, etc) through the JSR 223]. With some try-and-error I got jruby to work with freeplane (very simple after all!), and got all excited - using jruby I could write scripts for freeplane in the '''ruby''' language (instead of groovy).
| |
− | So, I started to think about making an addon to easily enable ruby scripts with freeplane. And that motivation slowly lead to the creation of the FreeplaneJrubyInstaller addon.
| |
− |
| |
− | My first intention was for the addon to simply install Jruby in Freeplane, and just that.
| |
− |
| |
− | I had to learn [http://www.freeplane.org/wiki/index.php/Add-ons_%28Develop%29 how to make a freeplane addon] (which after you read it well, its easy!).
| |
− | Then I noticed that to make freeplane aware of jruby it was only necesary to put jruby-xxx.jar in 'freeplane-user-dir/lib/jruby-xxx.jar', but the jruby-xxx.jar file is +20MBytes in size, which is too much to be packaged inside an addon.mm file (gave memory problems, both when building the addon, and when installing the addon - a no go), and the alternative was to make a java-downloader-window, that would be executed after the addon was installed in freeplane, and that would simply download the jruby-xxx.jar file from internet. That was not easy but got it done (the right way!) :) Also, I left the default download url for jruby-9.0.4 (the one I use and know it works!) but that can be easily changed in the future to download more recent versions of jruby (if/when they are needed! a prior 9.0.something did not work because of a bug!).
| |
− | And with that, one could write a freeplane-ruby-script (ex: 'freeplane-user-dir/scripts/my_ruby_script.rb') and then restart freeplane and click in the new menu entry ''Tools/Scripts/my_ruby_script'' to run it.
| |
− |
| |
− |
| |
− | So, I successfully made an addon to install jruby in freeplane. With jruby installed, freeplane could already run ruby scripts.
| |
− | Also, I've seen that it was then possible for other ''addons to use ruby instead of groovy addon-scripts! (A whole new world there!)''
| |
− | A good accomplishment, great!
| |
− |
| |
− |
| |
− |
| |
− | ==== Adding to ruby scripts the variables: c, node, ui, logger, textUtils, ... ====
| |
− |
| |
− | However the ruby scripts did not had these handy variables defined - ''''c, node, ui, logger, textUtils, ...'''' - they had to be manually extracted from java classes... that's possible but it's annoying to do it in every single script. In groovy scripts these variables ''just work'' and that's great, so using ruby metaprogramming I've made that also happen
| |
− |
| |
− | The code is in the file 'freeplane.rb' (with comments!), you can find it in 'freeplane_user_dir/addons/freeplaneJrubyInstaller/FreeplaneJrubyCommonEnvironment/lib/freeplane.rb'. This file is automatically required by '''freeplane_jruby_common_environment.rb''', so in your freeplane-ruby-script you only need to 'require "freeplane_jruby_common_environment.rb"' to set this up.
| |
− |
| |
− | You also need to enable these freeplane preferences, in Tools/Preferences/Plugins
| |
− |
| |
− | [[File:Preferences_jruby_script.png|frame|400x200px|none|link={{filepath:Preferences_jruby_script.png}}]]<br />
| |
− |
| |
− | Just to make this clear:
| |
− | * all freeplane-ruby-scripts need to 'require "freeplane_jruby_common_environment.rb"' to have the variables 'c, node, ui, logger, textUtils, ...'
| |
− | * certain Preferences have to be enabled
| |
− |
| |
− |
| |
− |
| |
− | ==== Rubygems: All ruby scripts share one local gems-home folder ====
| |
− |
| |
− |
| |
− | After, I realized that ruby scripts may at somepoint need to use '''rubygems'''. Rubygems by default use a default system-wide directory to store all the gems, for all ruby programs (freeplane and non-freeplane). I did not wanted to use that systemwide-default-rubygems-folder, I wanted to use an isolated and self-contained rubygems-folder, where only the gems necessary for the freeplane-ruby-scripts could be stored and read from.
| |
− |
| |
− | I've investigated about how to use only a local-rubygems-folder... First I started with [http://bundler.io/ bundler] but it turned our to be a dead-end for this, and finally concluded that the best solution was to (avoid bundler and) define the environment variables GEM_HOME and GEM_PATH (no dependencies, clean-small code, easily understood) to indicate to rubygems that it should only load gems from a specific '''local gem-home folder'''. This results in the '''freeplane-ruby-scripts only see and only use the gems present in this local gem-home folder'''. Great, gems isolation achieved :)
| |
− |
| |
− | I've decided to place the local gem-home folder in 'freeplane_user_dir/addons/freeplaneJrubyInstaller/FreeplaneJrubyCommonEnvironment/gem_home'.
| |
− | The code that sets up this local gem-home, is in the file 'only_gem_home.rb' file, you can find it in 'freeplane_user_dir/addons/freeplaneJrubyInstaller/FreeplaneJrubyCommonEnvironment/lib/only_gem_home.rb'. This file is automatically required by '''freeplane_jruby_common_environment.rb''', so in your freeplane-ruby-script you only need to 'require "freeplane_jruby_common_environment.rb"' to set this up.
| |
− |
| |
− | Just to make this clear:
| |
− | * all freeplane-ruby-scripts need to 'require "freeplane_jruby_common_environment.rb"' to use the local 'gem_home' folder. After that line, the gems (installed in gem_home) can be require'd normally in your script (ex: require 'awesome_print')
| |
− | * all freeplane-ruby-scripts will use one common rubygems folder, which is the local 'gem_home' folder, located in 'freeplane_user_dir/addons/freeplaneJrubyInstaller/FreeplaneJrubyCommonEnvironment/gem_home'
| |
− |
| |
− |
| |
− | NOTE: If you want to '''manage (list/install/uninstall/...) gems from the local gem_home''' then edit the files 'freeplane_user_dir/addons/freeplaneJrubyInstaller/FreeplaneJrubyCommonEnvironment/gem.bat or gem.sh'
| |
− |
| |
− |
| |
− | NOTE2: If you are making an '''addon with ruby-scripts that needs more gems''', then instead of adding gems into the common '.../FreeplaneJrubyCommonEnvironment/gem_home' of all freeplane-ruby-script, its better for you to package your own independent addon_gem_home folder, with a modified 'only_gem_home.rb' pointing to the addon_gem_home folder. This is easier and garantees that your addon be deployed and executed with exactly the same gems that you want (instead of relying on the common '.../FreeplaneJrubyCommonEnvironment/gem_home' which is intended to serve as a common base for the non-addon freeplane-ruby-scripts, and may even be tinkered by curious users out there :) )
| |
− |
| |
− |
| |
− |
| |
− | So, at this point the addon was capable of installing Jruby, and then freeplane-ruby-scripts could be run from menu ''Tools/Scripts/my_ruby_script''
| |
− | The freeplane-ruby-script should have a 'require "freeplane_jruby_common_environment.rb"' that gives the variables 'c, node, ui, ...' and also gives the gems (installed in gem_home) that thereafter can be required normally by the script.
| |
− | Great :)
| |
− |
| |
− |
| |
− |
| |
− |
| |
− |
| |
− | ==== RubyLiveDebugger ====
| |
− |
| |
− |
| |
− |
| |
− | Well, the next step would be to write some freeplane ruby scripts! And, as it happens to everyone, at some point you'll find an error and debug your code for that error...
| |
− | When an error is found during execution of your ruby script, a short error-message-window will show up in freeplane (which tipically will not show the line number of the error). On the other hand the error will also be logged into the freeplane log file, where you may find the line number of the error among other usefull info such as the exception raised. So keep in mind that the log file will have more info about the error than what is shown in the small error-message-window that pops up.
| |
− |
| |
− | And there you go, reading the log file for the line number of your error, then opening the ruby script and rechecking that line and trying to mentally recompute and fing the error. And thats ok, but there is a better way availabe in ruby - there is this gem called [http://pryrepl.org/ Pry] that is used normally to ''debug a program live while it is still executing'' (its a REPL launched inside a running program). Very usefull, you just put a line of code in the middle of your program where you want, and then run your program and when the program execution gets to that line it waits for you to interact with it (read variables, change variables, call methods, etc, it's live conding inside your program in that point). Have a look a some youtube videos to understand it better, or wait 5 min to read this to the end and then it try yourself, its pretty easy.
| |
− |
| |
− | However Pry expects the program to be launched from a terminal and reuses the terminal's stdin/stdout to interact with the user, but we are running a ruby program with jruby which is called from java and the program stdin/stdout is who-knows-where... :) the stdout at least seems to be logged into the log files, but stdin is out-of-reach.
| |
− | For these cases (and other similar like daemon proceses), there is another gem called [https://github.com/Mon-Ouie/pry-remote Pry-remote] which uses tcp/ip to communicate between a pry-remote-server listening on 127.0.0.1:9876, to which its possible to connect with a pry-remote-client. The pry-remote-server is attached to the ruby program, and waits a connection from the pry-remote-client. The pry-remote-client is executed from another terminal, and will connect to the pry-remote-server and use the client-terminal stdin/stdout to allow the user to interact with the ruby program (attached to pry-remote-server). So, using pry + pry-remote, we can debug a freeplane-ruby-script in the middle of its execution, from an external terminal running the pry-remote-client, and inspect the running freeplane-ruby-script to see its variables value and try new commands.
| |
− |
| |
− | Using pry-remote implies severall things:
| |
− | * 1) have the freeplane-ruby-script execute a pry-remote command (in the line where the debug will occur). This will start the pry-remote-server which will stay listening and waiting for a tcp connection in 127.0.0.1:9876
| |
− | * 2) in a separate terminal window, launch the pry-remote-client (using java, and jruby and the pry-remote gem)
| |
− | * 3) finally once pry-remote-client is openned and connected, the user can debug the freeplane-ruby-script using that terminal (typing in keyboard, reading in screen). Tab is very usefull (there is a nice autocompletion!)
| |
| | | |
− | As can be seen, manually setting up a pry-remote debug session is a bit daunting... and repeating it every time we want to debug something is not more pleasant...
| |
− | So I automated it programatically so that a script-developer would not need to think about all this, and instead would only need to call a special command inside the freeplane-ruby-script where one wants to open a debug window: 'RubyLiveDebugger.open_debug_here(binding)'
| |
| | | |
− | You can put multiple lines with 'RubyLiveDebugger.open_debug_here(binding)' - each time one of those lines is executed, a debug window will open.
| |
− | To exit from a debug session, its '''mandatory''' to send the command '!!@'. Only exit with '!!@', and never with 'exit' or 'quit' or closing the debug window directly. This is necesary for the pry-remote-server process to cleanup and continue release execution.
| |
| | | |
| | | |
− | The RubyLiveDebugger class is defined in file 'ruby_live_debugger.rb', located in 'freeplane_user_dir/addons/freeplaneJrubyInstaller/FreeplaneJrubyCommonEnvironment/lib/ruby_live_debugger.rb'. This file is automatically required by '''freeplane_jruby_common_environment.rb''', so in your freeplane-ruby-script you only need to 'require "freeplane_jruby_common_environment.rb"' to set this up.
| + | == How to use ruby scripts in Freeplane == |
− | | |
− | Certain Preferences need to be enabled for a script to be able to use the RubyLiveDebugger:
| |
− | [[File:preferences_jruby_script2.png|frame|400x200px|none|link={{filepath:preferences_jruby_script2.png}}]]<br />
| |
− |
| |
− | | |
− |
| |
− | Just to make this clear:
| |
− | * all freeplane-ruby-scripts need to 'require "freeplane_jruby_common_environment.rb"' to use 'RubyLiveDebugger.open_debug_here(binding)'
| |
− | * all freeplane-ruby-scripts can use debug at any place of the script - just put in a line 'RubyLiveDebugger.open_debug_here(binding)' and when the script is executed it will open a debug window in that point of the script.
| |
− | * certain Preferences have to be enabled
| |
− |
| |
− |
| |
− |
| |
| | | |
| + | Once the FreeplaneJrubyInstaller-addon is installed, you can then '''use ruby scripts in Freeplane''' |
| | | |
| + | Lets take as an example, that you have a '''my_ruby_script.rb''' file, that you got from the wiki or the forum or from a friend, and you want to use it in Freeplane. |
| | | |
| + | Do this: |
| | | |
| + | # In Freeplane goto '''Tools/Open user directory''' to open the <code><freeplane-user-dir></code> in a new window |
| + | # Inside the new window, open the subdirectory <code>scripts</code> |
| + | # Copy/paste the new file into that subdirectory <br /> You should end up with: <code><freeplane-user-dir>/scripts/my_ruby_script.rb</code> |
| + | # Freeplane only detects new ruby scripts after a restart. So now close Freeplane. |
| + | # Open Freeplane again, and you will see that there is a new entry in the menu '''Tools/Scripts'''/'''''My_Ruby_Script''''' - click on it to run the new ruby script! |
| | | |
− | ...
| + | You now have the ruby script in freeplane: from now on whenever you want to run this script, just click again '''Tools/Scripts'''/'''''My_Ruby_Script''''' |
− | ...
| |
| | | |
− | To make it easy for every script, to require all these files at once, I made one single file thats the only one that need to be required by every ruby script - the 'freeplane_jruby_common_environment' (in 'freeplane_user_dir/lib/freeplane_jruby_common_environment.rb').
| + | ==== Youtube demo video: how to use ruby scripts in Freeplane ==== |
| | | |
− | So you should put in the start of your ruby scripts the following:
| + | https://youtu.be/ExqYF0SLGzI |
| | | |
| | | |
| | | |
| + | The first time you run a ruby-script in freeplane, it takes a while to "warm-up" jruby. Since the second and third and xxx times, the script will already run much faster. This also happens (in a lesser degree) with groovy scripts. |
| | | |
− | TODO: continue here
| + | NOTE: To remove a script (either ruby or groovy), just delete the script from <code><freeplane-user-dir>/scripts/my_ruby_script.rb</code> and restart Freeplane. |
− | in freeplane the groovy scripts we have these very handy global variables defined:
| |