jmettraux.skepti.ch

index

20170321 zero indent en programming

As I wrote earlier, I don't use a debugger, lately I've started placing the puts, p and pp I use to help me develop at indentation zero, like this:


    def self.get_tzone(o)

p [ :gtz, o ]
      return nil if o == nil
      return local_tzone if o == :local

      return o if o.is_a?(::TZInfo::Timezone)

      if o.is_a?(Numeric)
        i = o.to_i
        sn = i < 0 ? '-' : '+'; i = i.abs
        hr = i / 3600; mn = i % 3600; sc = i % 60
        o = (sc > 0 ? "%s%02d:%02d:%02d" : "%s%02d:%02d") % [ sn, hr, mn, sc ]
      end

      return nil unless o.is_a?(String)

      return ::TZInfo::Timezone.get('Zulu') if o == 'Z'

      z = (@custom_tz_cache ||= {})[o]
      return z if z

      z = (::TZInfo::Timezone.get(o) rescue nil)
      return z if z

      z = get_offset_tzone(o)
      return z if z

      nil
    end

The code that is here for debugging immediately stands out. I can easily locate it with the /^p regular expression as well.

Example taken out of et-orbi.

20161128 rufus-scheduler 3.3.0 released en rufus-scheduler ruby

I have just released rufus-scheduler 3.3.0.

Rufus-scheduler is a job scheduling (at, in, every, cron) library available as a Ruby gem. It is not meant as a cron replacement, it lives within the Ruby process using it and dies with it.

Why the jump from 3.2.x to 3.3.x? It's because of a mistake I made: I was relying on ENV['TZ'] to get timezoned Time instances. It works fine and cuts the dependency on the tzinfo gem, but when you're working with multiple threads and one is setting ENV['TZ'] to Europe/Helsinki while another is setting it to America/Houston, both might end up with Time instances in Houston or Helsinki. Chaos.

This rufus-scheduler 3.3.0 brings back the tzinfo dependency and uses it to support its Rufus::Scheduler::ZoTime class. Instances of ZoTime quack like if they were Ruby Time instances but keep their zone as an instance of TZInfo::TimeZone.

Should problems appear after an upgrade to 3.3.0, please fill a clear and detailed issue at https://github.com/jmettraux/rufus-scheduler/issues.

This ENV['TZ'] problem was pointed out (gh-220) by Musha Akinori. Many thanks to him!

A new feature made it into this 3.3.0, it was requested/contributed by Piavka in gh-214. It's a Rufus::Scheduler::Job#trigger_off_schedule method. It lets you trigger a job, off of its schedule. If, during the off schedule run, the job is started "in schedule", overlap settings kick in. Off-schedule or in-schedule, calls to Job#running? will return true. It has its uses with repeat jobs.

This release also contains two fixes. One for .parse_to_time vs Date instances (gh-216), thanks to Nicolás Satragno. And one for "day 0 cronlines" (gh-221), thanks to Ramon Tayag.

Thanks again.

20160905 patterns at Hiroshima Lightning Talks en

I gave a lightning talk about patterns at the Hiroshima Lightning Talks gathering.

I started by showing my GR1 ruck and pitching the two "patterns" it sports that are important for me:

I then went further and switched to software patterns and the well known Elements of Reusable Objected-Oriented Software, from there I shew two further books but then switched to the origin of the patterns in the Pattern Language movement (some say "permatecture").

Some people with only peripheral knowledge of programming think that only the GoF book exists and that quizzing a programmer about them is a valid "interview" technique. Some of the patterns in there are object-oriented language specific and when you dwell back in functional programming (back from computer techniques into science), those patterns are gone with the wind. The patterns in the books beyond that book are more important.

Here are the slides, they are rough, they were only pillars to my talk.

 

The building picture are from the Eishin Campus that Christopher Alexander with and for the teachers and students there.

My rucksack was the first point of the talk because it contained all the books described in the talk, I could then hand the books to the participants and let them get a feel for the volumes.

Among the Christopher Alexander books, my current favourite is A Pattern Language, I get lost in it, trying to absorb the wisdom it distils. As a programmer I love to grow interesting, useful, nice pieces of sofware, but I also crave for places where I can sit or stand and let that growing happen.

There is a great documentary about Christopher Alexander on YouTube: "Life cannot be produced from a drawing, life can only be produced from a process" (minute 3:40).

20160504 rufus-scheduler 3.2.1 released en rufus-scheduler ruby

I've just released rufus-scheduler 3.2.1.

Rufus-scheduler is a Ruby gem for scheduling pieces of code. You instantiate a scheduler and you tell it after how long you want a block of code to run or how often you want it to run.

require 'rufus-scheduler'

scheduler = Rufus::Scheduler.new

scheduler.in '3h' do
  # do something in 3 hours
end

scheduler.at '2030/12/12 23:30:00' do
  # do something at a given point in time
end

scheduler.every '3h' do
  # do something every 3 hours
end

scheduler.cron '5 0 * * *' do
  # do something every day, five minutes after midnight
  # (see "man 5 crontab" in your terminal)
end

scheduler.join
  # let the current thread join the scheduler thread

This 3.2.1 release mostly brings negative weekdays to cron strings. It lets you write crons like:

require 'rufus-scheduler'

scheduler = Rufus::Scheduler.new

scheduler.cron '5 0 * * 5L' do
  # do something every last Friday of the month, at 00:05
end

scheduler.cron '5 0 * * 4#-2,4#-1' do
  # do something every second to last and last Thursday of the month, at 00:05
end
  #
  # or
  #
scheduler.cron '5 0 * * thu#-2,thu#-1' do
  # do something every second to last and last Thursday of the month, at 00:05
end

scheduler.join

Many thanks to all the people that contributed to the development of rufus-scheduler.

20160227 dot errors rspec custom formatter en ruby rspec

I work with two terminals side by side, a wide one of the left for running and an 80 columns one on the right for editing. The left one often gets hidden behind a browser window but I can easily bring it back with a keyboard shortcut.

My Ruby coding is a long back and forth between those two terminals, write some code on the right, run one or more specs on the left, read the error messages, fix on the right... It happens without clicking, only keyboard interactions.

I wanted to navigate immediately from an error to its location in its spec file. At first, I was thinking about letting the click on the spec/nasty_spec.rb:66trigger something but it would kill the "only keyboard interactions" joy.

I came up with a custom Rspec formatter.

# ~/.bash/rspec_dot_errors_formatter.rb

class DotErrorsFormatter

  RSpec::Core::Formatters.register self, :dump_failures

  def initialize(output)

    @output = output
  end

  def dump_failures(notification) # as registered above

    notification.failure_notifications.each do |fn|
      m = fn.formatted_backtrace.first.match(/\A([^:]+_spec\.rb:\d+):in /)
      @output << m[1] << "\n"
      break
    end
  end
end
No magic here, it simply produces a list of lines looking like:
./spec/p/val_spec.rb:78
./spec/z/applications_spec.rb:92

I placed this rspec_dot_errors_formatter.rb file in my .bash/ directory and made sure my usual bxs alias includes this formatter when calling rspec:

alias bxs="bundle exec rspec \
    --require ~/.bash/rspec_dot_errors_formatter.rb \
    --format DotErrorsFormatter --out .errors \
    --format d"

Note how I require the source file containing the custom formatter, then ask for it via --format, ensure its output is piped to .errors thanks to --out and then fall back to my default formatter d (for "documentation") followed by nothing. The --out is only for the preceding --format.

When running my specs, it will write down in a file named .errors the error locations in the specs.

I combined that with my ListFiles() function in Vim and get my list of error location beween my list of open buffers and of recently opened files:

I can now navigate to the "== .errors" section and jump directly to the error in the spec.

The next refinement will probably consist in mining each failure stacktrace for relevant file locations in the source itself, not in the spec source.

2016-12-05 update: let the ~/.bash/rspec_dot_errors_formatter.rb script add to .errors only the first _spec.rb files it encounters in the backtraces

20160222 vim :ListOld en vim

The initial version of this post was about a ListOld function. After a few days, I changed my mind about it and rewrote as ListFiles, including current buffers and recently opened files in a single "view". The original post is still visible.

I use Vim as my main text editor. It's ubiquitous. I have a minimal .vim/ setup. It moves around with me easily, as long as I have ssh and git, I can get comfortable on a host very quickly.

I needed a way to access the most recently updated files. :bro old is painful to use.

Here is a vimscript function that pipes the output of :bro old in a file then lets you roam in it with j and k and then hit <space> to open a file. Use the standard ctrl-6 or ctrl-^ to get back in the file list.

It also outputs the result of :buffers, so you're presented with a list of currently open buffers followed by a list of recently opened files. I find it convenient for quickly navigating or getting back into context.

function! s:ListFiles()

  exe 'silent bwipeout ==ListFiles'
    " close previous ListFiles if any

  exe 'new | only'
    " | only makes it full window
  exe 'file ==ListFiles'
    " replace buffer name
  exe 'setlocal buftype=nofile'
  exe 'setlocal bufhidden=hide'
  exe 'setlocal noswapfile'
  exe 'setlocal nobuflisted'

  exe 'redir @z'
  exe 'silent echo "== recent"'
  exe 'silent echo ""'
  exe 'silent bro ol'
  exe 'redir END'
  exe 'silent 0put z'
    " list recently opened files, put at top

  exe 'redir @y'
  exe 'silent echo "== buffers"'
  exe 'silent echo ""'
  exe 'silent buffers'
  exe 'redir END'
  exe 'silent 0put y'
    " list currently open buffers, put at top

  exe '%s/^\s\+\d\+[^\"]\+"//'
  exe '%s/"\s\+line /:/'
  exe 'g/^Type number and /d'
  exe 'g/COMMIT_EDITMSG/d'
  exe 'g/NetrwTreeListing/d'
  exe 'silent %s/^[0-9]\+: //'
    " remove unnecessary lines and ensure format {filepath}:{linenumber}

  call feedkeys('1Gjj')
    " position just above the first buffer, if any

  setlocal syntax=listold
    " syntax highlight as per ~/.vim/syntax/listold.vim

  nmap <buffer> o gF
  nmap <buffer> <space> gF
  nmap <buffer> <CR> gF
    "
    " hitting o, space or return opens the file under the cursor
    " just for the current buffer

endfunction

command! -nargs=0 ListFiles :call <SID>ListFiles()
nnoremap <silent> <leader>b :call <SID>ListFiles()<CR>
  "
  " when I hit ";b" it shows my list

The original is at https://github.com/jmettraux/dotvim/blob/fe1d1c3f/vimrc#L346-L390.

Here is an example output:

I move up and down with k and j and hit space to open the file under the cursor. I hit ctrl-6 (;; in my setting) to get back to the list of files.

I also added:

alias vo='vim -c "ListFiles"'
to my .bashrc so that vo fires up Vim directly in this list of files.

This script is condensed from a series of google searches and stackoverflow scans. I felt like quitting in the middle, but there is always an answer somewhere that unlocks it all.

20160210 radial and flon en flon

to Ruby

I'm currently reworking flon in Ruby. I might use it for a customer, hence this preparatory work. I did a first pass at flor but I noticed that I was copying too much.

This effort towards Ruby is interesting. I had a need for a parsing tool so I ported flon's aabro to Ruby as raabro and since I also needed it client-side, I ported it again to Javascript as jaabro.

My old rufus-mnemo became flon's mnemo. For this Ruby port, I didn't re-use rufus-mnemo but ported mnemo back to Ruby as munemo.

These ports aren't part of the "I was copying too much" complaint I emitted above. I had simply noticed that I was porting flon one to one to Ruby and I felt uneasy about it as it progressed.

a radial core to flon

Looking back a flon itself, I was quite happy at the libraries I had built to support it. I was telling myself: so, I'm building an interpreter, all this difficult C will be hidden behind it and life will be good. I was thinking about the fun radial language I was stashing together for flon, a language strong at JSON.

I started to wonder: what if the flon business logic was written in radial itself?

I started prototyping a core radial interpreter and I named the project flar.

This core would be a minimal, non-concurrent radial interpreter, a core for flon and flor (Ruby flon). The non-core instructions, like "concurrence", "task" and the non-core attributes like "timeout", etc would be implemented as libraries (either radial, either C or Ruby depending on the target).

By non-core, I think workflow-esque stuff. The core language would be a limited yet funny programming language.

That's the plan. I try to devote one or two hours per day to it. It feels right for now.

20160205 hyperbooks en litterature

Books reference each other, directly or indirectly. You can now spend a life spidering from one book to the other.

Are there starting points? Certainly, the Illiad, the Epic of Gilgamesh and more.

At some points in the history of litterature there has to be books that bridge between the Illiad and the I Ching (even before the Man in the High Castle).

Then, all those who toil away at writing new books that echo the voice of the old bards.

20160128 familiarity en jp litterature

A man should avoid displaying deep familiarity with any subject. Can one imagine a well-bred man talking with the airs of a know-it-all, even about a matter with which he is in fact familiar? ... It is impressive when a man is always slow to speak, even on subjects he knows thoroughly, and does not speak at all unless questioned.

Kenkō "Essays in Idleness" (79) As translated by Donald Keene

20160111 banausic occupations en xenophon philosophy

Very good, Critobulus; for to be sure, the so-called banausic occupations are scorned and, naturally enough, held in low regard in our states. For they spoil the bodies of the workmen and the foremen, forcing them to sit still and stay indoors, and in some cases to spend the whole day by the fire. As their bodies become womanish their souls lose strength too. Moreover, these so-called banausic occupations leave no spare time for attention to one's friend and city, so that those who follow them are reputed bad at dealing with friends and bad defenders of their country.

Socrates to Critobulus in Xenophon's Oeconomicus (3.15-4.3)

20151231 munemo 1.0 en ruby

munemo is a rewrite of rufus-mnemo. The first rewrite was actually in C as mnemo, munemo is a port of mnemo from C to Ruby.

I use munemo and its siblings to turn integers into somehow rememberable words. The rememberable attribute usually has to span a debug session, as I am manually scanning a set of grepped log files for patterns. It helps me to have words I can say out loud instead of numbers. It also helps (not always) when transmitting an identifier over the phone to someone else.

Rufus-mnemo started with the japanese syllables, but mnemo and munemo work with a wider index, 100 syllables, and unlike rufus-mnemo they don't accept wovels on their own.

Munemo exposes two methods, here they are:


# Munemo.to_s(i)

Munemo.to_s(0) # => 'ba'
Munemo.to_s(1) # => 'bi'
Munemo.to_s(99) # => 'zo'
Munemo.to_s(100) # => 'biba'
Munemo.to_s(101) # => 'bibi'
Munemo.to_s(392406) # => 'kogochi'
Munemo.to_s(25437225) # => 'haleshuha'

Munemo.to_s(-1) # => 'xabi'
Munemo.to_s(-99) # => 'xazo'
Munemo.to_s(-100) # => 'xabiba'


# Munemo.to_i(s)

Munemo.to_i('blah blah blah') # => ArgumentError: "unknown syllable 'bl'"

Munemo.to_i('xabixabi') # => ArgumentError: "unknown syllable 'xa'"

Munemo.to_i('munemo') # => 475349
Munemo.to_i('yoshida') # => 947110
Munemo.to_i('bajo') # => 34
Munemo.to_i('xabaji') # => -31
Munemo.to_i('tonukatsu') # => 79523582

I wish you a happy new year!

20151229 small, custom-built interpreters en programming link

There's not much personal appeal to a Z80 emulator, but many applications I've written have small, custom-built interpreters in them, and maybe I didn't take them far enough. Is all the complaining about C++ misguided, in that the entire reason for the existence of C++ is so you can write systems that prevent having to use that language?

James Hague in Alternate Retrocomputing Histories

20151228 released rufus-scheduler 3.2.0 en ruby rufus-scheduler

I have just released rufus-scheduler 3.2.0.

Rufus-scheduler is a job scheduling (at, in, every, cron) library available as a Ruby gem. It is not meant as a cron replacement, it lives within the Ruby process using it and dies with it.

The switch from 3.1.x to 3.2.x is motivated by the change worked on with @Korrigan. "every" schedules now more carefully stick to their "@next_time".

There is also a little bit of caching that got added to CronLine to prevent computing frequencies again and again when scheduling cron jobs.

Happy new year!

20151227 blank in the thinking en fr language

I'm an avid reader of Jacqueline de Romilly. She wrote a serie of essays about the health and the evolution of the french language. Here is a quote:

(...) Le blanc dans l'expression correspondait, je le crains, à un blanc dans la pensée. Car une impression globale et vague ne peut se préciser qu'à l'aide des mots, de leur distinction, de leur emploi délibéré et contrôlé. On pense avec des mots. On distingue les notions avec des mots. Le language est, en effet, l'instrument même de la pensée, et le seul moyen de lui donner des contours fermes."

"Dans le jardin des mots" Jacqueline de Romilly

Let me make an attempt at a translation:

(...) The blank in the sentence corresponded, I fear, to a blank in the thinking. A global and vague impression can only be refined thanks to words, their distinction, their deliberate and controlled use. We think with words. We distinguish notions with words. The language is, in fact, the instrument of thought, and the only mean to give it a firm outline.

20151226 I don't use a debugger en programming

I spiral around the problem with a test, the smallest test possible that demonstrates the symptom of the bug.

Once I have my test, I go through a phase of analysis where I add print or log statements to see what is going on and find the cause of the bug. I run the test and add/modify the print statements in loop until I understand the cause.

Once the cause is found, it's time for the fixing phase. Again, running the test and modifying the code, but this time until the bug is fixed.

The next phase is running the test suite or a relevant subset of it to make sure the fix didn't break something elsewhere.

The print/log statements introduced in the first phase are slowly discarded in the second phase. Sometimes they stay, but commented out.

I like to leave commented out variants or explanations, for when I come back to the code in later developments or for fellow programmers.

I find it tedious to fire a debugger and tinker with breakpoints. In the time necessary to do 1 debugger cycle, I think I can do 5 cycles of analysis (add print statements, run, analyse, repeat).

Tight feedback loop.

Development is lots of debugging, so I treat debugging as development. Me, the editor, the code and its test suite.

I don't use a debugger, but I know how to use one and I won't hesitate to use it if my debug routine is not effective in given circumstances. Debugger or not, the test reproducing the bug is a necessary by-product.

Triggered by this tweet.

Further:

20151224 programmer arrogance en programming

My friend said to me: "to tell you the truth, I've never met a programmer who'd tell me good things about what another programmer built".

He went further: "I had hired a young developer to make a tool for me. It was a continuous struggle to make him accept our needs over the needs he 'envisioned' for the tool. Each of his defeats were punctuated by a warning and an arrogant grin".

20151221 a world split apart en litterature

If, as claimed by humanism, man were born only to be happy, he would not be born to die. Since his body is doomed to death, his task on earth evidently must be more spiritual: not a total engrossment in everyday life, not the search for the best ways to obtain material goods and then their carefree consumption. It has to be the fulfillment of a permanent, earnest duty so that one's life journey may become above all an experience of moral growth: to leave life a better human being than one started it.

Aleksandr Solzhenitsyn - A World Split Apart

20151218 stuff and fluff en workflow

"Stuff" is tangible. Examples of stuff: documents, business entities, mandates, folder.

"Fluff" is not tangible. If you accept the "what may be touched" definition for tangible, you might accept that fluff is "what does the touching".

Stuff has only two states, "alive" and "dead", but stuff as it traces its arc from birth to death intersects with many fluffs.

Fluff might intersect the stuff's arc or may parallel it for a while and then head away or vanish, or the stuff might vanish before the fluff.

(In passing, here is a link to two releated links: resource lifecycle tuple)

At first, I was tempted to oppose "tangible" to "intangible". Business entities would be "tangible", while business processes would be "intangible".

"Tangible" means "may be touched", ok for business entities, now is "intangible" OK for business processes? I want to express "that does the touching", not "may not be touched". So no "tangible" vs "intangible".

20151216 John Boyd en misc

Currently reading John Boyd's biography

Love it so far.