Conveniently start a JavaScript shell (jsc) on macOS

For one of my projects I wanted an easy way to try JavaScript on a command line (similar to pry or irb in Ruby). Here’s how I found out where the program is located and how to set up my Mac to conveniently start it.

1. Find out where jsc is located on the machine:

$ find / -name jsc -type f 2>/dev/null
/System/iOSSupport/…/JavaScriptCore.framework/Versions/A/Helpers/jsc
/System/…/JavaScriptCore.framework/Versions/A/Helpers/jsc
/System/Volumes/Data/…/JavaScriptCore.framework/Versions/A/Helpers/jsc
/System/Volumes/Data/…/JavaScriptCore.framework/Versions/A/Helpers/jsc    

Searching from the root folder may be a bit excessive, though. You may consider a more limited search.

2. Look into the ‘system frameworks’ for versions

The path /System/Library/Frameworks/… was where I went to look what else is inside:

$ ll /System/Library/Frameworks/JavaScriptCore.framework/Versions
total 0
drwxr-xr-x  4 root  wheel  128 Jan  1  2020 .
drwxr-xr-x  4 root  wheel  128 Jan  1  2020 ..
drwxr-xr-x  5 root  wheel  160 Jan  1  2020 A
lrwxr-xr-x  1 root  wheel    1 Jan  1  2020 Current -> A

Aha, there’s a link named Current that (currently) points to A. I used this link in the next step. This way I can still use the same link, even if (when!) an OS update causes the file that’s linked to changes.

3. Link to the current version

I set a link somewhere in within $PATH. I have a bin folder in my home directory, so it put the link there:

ln -s /System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Helpers/jsc ~/bin/jsc

3. Set a variable ‘console’ for output

To output things, use this to define a variable console in a running JavaScript shell.

var console = {log : debug};

While jsc provides a print function, I find it convenient to stick to the more idiomatic console.log.

4. Use ‘jsc’

$ jsc
>>> var console = {log : debug};
undefined
>>> console.log(function(){})
--> function (){}
undefined
>>> 1 + 1
2 

The Different Ways of Pry and Irb

I ran into an interesting little problem when doing sone Ruby (and Rails) work today: I wanted to try something in pry and, inside that Rails project I issued the following command:

$ pry -r sqlite3
…/gems/pry-0.14.1/lib/pry/pry_class.rb:103:in `require': cannot load such file -- sqlite3 (LoadError)
  from …/gems/pry-0.14.1/lib/pry/pry_class.rb:103:in `block in load_requires'
  from …/gems/pry-0.14.1/lib/pry/pry_class.rb:102:in `each'
  from …/gems/pry-0.14.1/lib/pry/pry_class.rb:102:in `load_requires'
  from …/gems/pry-0.14.1/lib/pry/pry_class.rb:143:in `final_session_setup'
  from …/gems/pry-0.14.1/lib/pry/cli.rb:82:in `parse_options'
  from …/gems/pry-0.14.1/bin/pry:12:in `<top (required)>'
  from …/bin/pry:23:in `load'
  from …/bin/pry:23:in `<main>'
  from …/bin/ruby_executable_hooks:22:in `eval'
  from …/bin/ruby_executable_hooks:22:in `<main>'

Interesting! I have both gems, pry and sqlite3 installed. A similar attempt using irb worked fine:

$ irb -r sqlite3
3.0.1 :001 > SQLite3::VERSION
 => "1.4.2"
3.0.1 :002 >

Maybe I confused the environment by setting some environment variable or other? With a newly opened command shell I got this:

$ pry -r sqlite3
[1] pry(main)> SQLite3::VERSION
=> "1.4.2"
[2] pry(main)>

Remarkable. In that new shell the irb command behaved the same as before.

The only difference I could find was that the original call to pry happened in a Rails project – which is using Bundler to organise the Rubygems used in the project and resolve dependencies. As a small experiment I set up a minimal project that uses bundler and a rather short Gemfile:

source "https://rubygems.org"

gem  'limit_detectors'

The gem ‘limit_detectors’ is one I wrote and I know that is doesn’t depend on other gems. Issuing the pry command again … worked? Why? Some more investigation was needed…

Finally, I realised that another gem (Guard, to be specific), uses pry. Therefore my Rails project’s development environment indirectly depends on pry. It looks like pry recognises that it’s running as part of a Bundler project, even when it is not explicitly called using bundle exec pry …, which in turn causes it (pry) to ‘only’ recognise the gems that are also installed using Bundler. – And sqlite3 isn’t in this case, since I’m using PostgreSQL throughout.

Since irb comes with the Ruby installation and is not part of the bundled gems, it ignores the bundler context when called like this:

irb -r sqlite3

However, explicitly calling it in the bundler context in a project that doesn’t depend on ‘sqlite3’ (directly or indirectly) will cause an error message:

$ bundle exec irb -r sqlite3
…/rubies/ruby-3.0.1/lib/ruby/3.0.0/irb/init.rb:376: warning: LoadError: cannot load such file -- sqlite3
3.0.1 :001 >

Nice! This is essentially the same problem, I faced at the very beginning, when pry couldn’t find the sqlite3 gem.

A Local Rails Server in a Local Network

I’m currently working on a Rails app, that I want to have available in my local network on the default port that Ruby on Rails uses: 3000.

To do that, I added a line to the development config (config/environments/development.rb):

config.hosts << 'hostname.local'

Update: Apparently adding the line config.hosts.clear works as well. Details about this are explained in the Rails Guides.

I started using Foreman to achieve this, and installed it using:

gem install foreman

Note that, according to a Wiki Page on Github, it’s not recommended to put foreman into the Gemfile.

Then I created a Procfile that Foreman uses to start the web server (which currently is the only process I need it to start):

web: bundle exec rails s -b 0.0.0.0 -p 3000

The -b 0.0.0.0 binds the process to that IP address and -p 3000 instructs it to use port 3000.

With that set up foreman start can be used to start a Rails server in development which is available in the local network.

This way I can check the layout and functionality on a mobile phone or one of my iPads.

Monitoring Tomcat

Recently, I faced an issue with an application which is deployed in a Tomcat web container: In one of the environments it started to consume a lot of CPU cycles and memory.

My first attempt to investigate, is to run things locally and have a look at the Activity Monitor that comes with macOS. Often enough it’s enough to notice which app uses a lot of memory or CPU cycles.

This time though, I wanted some deeper insight and I already knew what I was looking for. Some searching in the net brought up Glowroot.

Even though I’m not experienced in using Tomcat, it was pleasantly easy and quick to get going:

  • Download a zip file and unpack it.
  • Copy the folder to a place where it’s convenient. I copied it into an existing folder I’m using to keep configuration info for Tomcat anyway.
  • Set up a way for Tomcat to find and use the Glowroot jar file.
  • Start Tomcat
  • Open a Browser at http://localhost:4000

The details for these steps are nicely explained on the GitHub Wiki of this project.

An example graph is this, taken from the projects demo site at https://demo.glowroot.org/

The my project this (so far) only confirmed that memory consumption can increase a lot when the system gets some traffic. Using well over 10GB of memory within a few minutes is a lot, especially when that memory isn’t released any time soon.

Are you using a tool that was particularly easy to use and provided what you were looking for? Which one?

Moving Left and Right in zsh (in macOS)

I use the command line a lot on my Macs, in particular, I use iTerm2.

When moving left and right in a command the shortcuts I knew about so far were:

Key (combination)Moves Cursor…
Right Arrow ‘→’One character right
Left Arrow ‘←’One character left
CTRL + aBeginning of the line
CTRL+ eEnd of the line

After adding the following lines to ~/.zshrc, I now can also move left and right per word using ALT-← and ALT-→ respectively:

bindkey "[D" backward-word # ALT-left-arrow  ⌥ + ←
bindkey "[C" forward-word  # ALT-right-arrow ⌥ + →

Especially when moving around in long command lines, this is really convenient & saves a lot of time.

Do you have keyboard shortcuts that you use regularly on the command line (or elsewhere)? I’d love to hear about them!

Tips for Conference Proposals & Sessions

Disclaimer: This year I’m one of the reviewers for the Agile Testing Days.

It’s proposal season again, at least for one of my favourite conferences, the Agile Testing Days; the call for papers is open until March 28th (for 2021).

There is a good number of articles and blogs available on the topic of Agile Testing Days proposals alone: I suggest to follow the advice Uwe gives with his blog post “Call for Papers Submission Pitfalls & How to Do it Better! Tales from a Conference Organizer“. There’s more info to find from that same conference over on YouTube: https://youtu.be/QxC-Ee51xmM

Mind The Context

Another important tip (especially for those thinking about a keynote) comes from Liz Keogh:

If it’s an opening keynote, I try to open people’s minds to learn and question. If it’s a closing keynote, I try to help them reflect on what they learned. Keynotes are there to frame the rest of the conference.

Liz Keogh on Twitter

I believe similar thinking applies to other sessions too: Make your session fit into the frame of the conference and what you know about the attendees expectations.

Tell a Story

I personally try to at least come up with a story, either one I made up or a personal one. Both worked well for me:

For a ½-day tutorial about testing and the Internet of Things (IoT), I set up the story of Goblin King Jareth the 42nd, who wanted to control his kingdom with a set of IoT devices and tasked the participants with testings these devices. The framing story helped to provide some reason to actually participate in the exercises.

For a (read: ‘the’ 🙂) keynote I gave at Agile Testing Days 2019, I chose the most personal story I possibly could: My diagnosis of and treatment for cancer – and why I still consider myself lucky. Read about it in “Being Lucky — A Keynote at the Agile Testing Days 2019“.

If you like to know more about telling a good story, be sure to read Huib Schoots’ blog post “Storytelling“! You’ll find — no surprise — a good story (and many links to more information, too).

Be Prepared

Things can go wrong: The notebook you planned to give the presentation with may crash. The projector may break or the sound system my fail. You may forget what you wanted to say. These things all happened to someone somewhere.

It’s better (and impressive!) to be prepared. For my keynote, I prepared index cards with notes of what I wanted to say when, when to make extra long breaks and other instructions, such as when to proceed to the next slide. At first I numbered them, so I could sort them, if I dropped them on the floor.

Numbered index cards

Later, I also put them on a thread: Now, even when I would drop them, they would still be sorted! This would have saved the talk, had I dropped those cards.

Index cards on a thread, to prevent shuffling

Some of the directions didn’t work out in the moment the presentation was live: The introduction was totally different from what I expected (and significantly louder!).

Mind the Last Possible Moment

One important, even obvious, aspect: Don’t miss the dead line. I did once and it’s annoying. Very annoying. — Most of the work was done for nothing, because I forgot to check the calendar. I learned it the hard way: If I’m too late to submit, it doesn’t matter how good the proposal was. Only if submitted within time, a paper has a chance to be selected.

I hope to see many great and inspiring proposals for the Agile Testing Days 2021!

Collecting Lists In a Ruby Hash and the ‘<<=' operator

The other day, I needed to quickly analyse a data set that came in form of a large CSV file. I wanted to collect a particular column of that table and collect all entries categorised by a key in another column.

A simplified version of the table could look like this:

Key Value1 Interesting_Value Other_Value
foo1723.5X
bar211.75Q
foo4212.6B
baz2717.8F
bar4947.2K

I strived for something like this:

result = { 
  foo: [23.5, 12.6],
  bar: [1.75, 47.2],
  baz: [17.8],
 }

Iterating over the rows is easy, and getting to the columns is no problem either: The CSV gem is well documented and supports this easily.

A nice way to accumulate data is Enumerable#each_with_object. Since I wanted the result to be grouped by a key value, I’d pass a Hash as the initial argument.

Step 1: each_with_object({})

However, since I’ve planned to append values for changing keys, the default value needed to be an Array, not the default of nil.

Step 2: each_with_object(Hash.new([])

This, however, returns the same empty Array, when a key isn’t found, but I wanted a new empty Array:

Step 3: each_with_object(Hash.new { [] })

This executs the block every time a default values is needed (i.e. the given key isn’t yet in the Hash).

The next step is to append the value found in a row to the (potentially new and empty) Array for the given key.

I thought it would work this way:

data_table.each_with_object( Hash.new { [] }) do |row, acc|
  acc[row['Key']] << row['Interesting_Value'] 
end

But, no, the result of this code is an empty Hash! It needs to be the <<= operator to work, as shown in the snippet of a pry session:

[2] pry(main)> data_table = CSV.read 'table.csv', headers: true
=> #<CSV::Table mode:col_or_row row_count:6>
[3] pry(main)> data_table.each_with_object( Hash.new { [] }) do |row, acc|
[3] pry(main)*   acc[row['Key']] <<= row['Interesting_Value']
[3] pry(main)* end
=> {"foo"=>["23.5", "12.6"], "bar"=>["1.75", "47.2"], "baz"=>["17.8"]}

It seems to me, that the Hash lookup with the given default value [] returns an Array, and the append operator << does in fact append the passed object to that Array, but then the result of that does not end up as a (new) value fo the given Hash key. In contrast, the <<= operator does assign the result of the append operation.