Sonntag, 26. Oktober 2014

Take a look at Ruby percentages

There are some Ruby %-notations which emerge as nice shortcuts. Those literals are Perl inspired.
Please note, that indeed all non-alpha-numeric delimiters are allowed, but it is highly recommended to use bracket delimiters for readability and unescaping reasons, like:
  1. ()
  2. []
  3. {}
  4. <>

1. Non-interpolated String

allows unescaping and string notation:
%q(Ruby string (syntax) is "pretty" flexible)
=> "Ruby string (syntax) is \"pretty\" flexible"
Please compare with the String result.

2. Interpolated String

allows flexible interpolation:
choosen_language = "Ruby"
%Q(#{choosen_language} string (syntax) is "pretty" flexible)
=> "Ruby string (syntax) is \"pretty\" flexible"
and there is also an even shorter literal. % (percentage) alone is the default for an interpolated String:
choosen_language = "Ruby"
%(#{choosen_language} string (syntax) is "pretty" flexible)
=> "Ruby string (syntax) is \"pretty\" flexible"

3. Non-interpolated Symbol

is maybe unusual:
%s(ruby)
=> :ruby
But dealing with arbitrary characters like spaces and dashes also works:
%s(ruby is awesome)
=> :"ruby is awesome"
and is more concise and idiomatic than:
"ruby is awesome".to_sym
=> :"ruby is awesome"

4. Non-interpolated String Array

is already quite popular:
%w(Ruby Python Clojure)
=> ["Ruby", "Python", "Clojure"]
The Array elements are separated by whitespace.

5. Interpolated String Array

is more flexible:
choosen_language = "Ruby"
%W(#{choosen_language} Python Clojure)
=> ["Ruby", "Python", "Clojure"]
The Array elements also are separated by whitespace.

6. Non-interpolated Symbol Array

maybe is less known but analog to its String companion:
%i(ruby python clojure)
=> [:ruby, :python, :clojure]

7. Interpolated Symbol Array

is also equivalent to its String mate:
choosen_language = "ruby"
%I(#{choosen_language} python clojure)
=> [:ruby, :python, :clojure]

8. Interpolated shell command

is pretty helpful for shell scripting:
language = "ruby"
%x(#{language} --version)
=> "ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]\n"
language = "nodejs"
%x(#{language} --version)
=> "v0.10.32\n"
Although there are also other Ruby shell scripting approaches (Please read Tell shell scripting apart in Ruby!)

9. Interpolated regular expression

can be used with flags after the closing delimiter
disliked_language = "Java"
string = %Q(#{disliked_language} helps to solve my problems.)
regexp = /#{disliked_language}/i
string.gsub(regexp, 'Ruby')
The literal briefing:
Literal Meaning
%qNon-interplated String
%QInterpolated String
%sNon-interpolated Symbol
%wNon-interpolated String Array
%WInterpolated String Array
%iNon-interpolated Symbol Array
%IInterpolated Symbol Array
%xInterpolated Shell command
%rInterpolated regular expression

Further articles of interest:

Supported by Ruby 2.1.1

Sonntag, 19. Oktober 2014

Create a simple Ruby rake task!

Some times simple tasks around the application need to be done. They are not a primary part, but belong to the application. Those tasks are called automated tasks (e.g. automated built system). Rake is such task system based on the make file idea, but scripted in Ruby.
A really simple rake task skeleton in lib/tasks/test.rake looks like:
namespace :awesome do
  desc "Awesome Ruby does awesome things."
  task :ruby do |t| 
    puts "Ruby is awesome!"
  end 
end
and only consists of a task and its description. It can be listed with:
rake -T | grep ruby
=> rake awesome:ruby   # Awesome Ruby does awesome things.
Calling it in bash:
rake awesome:ruby
=> Ruby is awesome!
A little more reasonable rake task could be an automated version system merge of a branch back into the trunk.
Assuming GIT was set up with those configurations:
git config user.name "trinibago"
git config --global credential.helper /usr/share/doc/git/contrib/credential/gnome-keyring/git-credential-gnome-keyring
git config --global push.default current
which configures my github user name, my credentials for the account (prevents account prompts) and the current checked out branch to be the one to push to remotely.
The git rake task in lib/tasks/git.rake:
namespace :git do
  desc "GIT merges branch back into master"
  task :merge, :message do |t, args|
    safe_task do
      branches = %x[git branch]
      current_branch = branches.split("\n").map(&:strip).
        detect { |x| x.match(/^*\s/) }.gsub(/^[*]\s/, '') 
      %x[git commit -a -m "#{args[:message]}"]
      # pushes the current branch changes to the remote
      %x[git push]
      # switches back to master
      %x[git checkout master]
      # merges the current branch
      %x[git merge "#{current_branch}"]
      # pushes the merged mater changes to the remote
      %x[git push]
    end 
  end 
end

private
  def safe_task
    yield
  rescue Errno::ENOENT => e
    puts "Task couldn't be executed.\n#{e.message}"
  end 
demands some explanation.
  1. all parameters are listed in args as a hash
  2. other Ruby functions can be called (like the safe_task, which wraps the exception handling)
  3. %x literal is a Ruby system call (read Tell shell scripting apart in Ruby!)
  4. the result of 'git branch' is parsed for getting the current branch name
  5. simple git commands processed sequentially
In console the task can be invoked by:
rake git:merge["Hottest fix ever"]
=> Counting objects: 13, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 417 bytes | 0 bytes/s, done.
Total 5 (delta 4), reused 0 (delta 0)
To https://github.com/trinibago/nested_set
 * [new branch]      hotfix -> hotfix
Switched to branch 'master'
Everything up-to-date
Rake tasks can be simple helper tools in daily life and also are combinable.
Further articles of interest:

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.19

Sonntag, 12. Oktober 2014

Tell shell scripting apart in Ruby!

Ruby scripting for the shell provides multiple ways, depending on the use case.

Kernel#system

The simplest way to fire a shell command in a Ruby script is to send a message to Kernel#system.
In a nutshell:
  1. the command is assigned as a String
  2. the first parameter is the command itself and all following string parameters are the arguments
  3. executes the command in a subshell
  4. is a blocking operation (waits until the result of operation completes)
  5. returns true (for zero exist status), false (for non zero exit status) or nil (if command execution fails)
  6. The commands result is not available for further processing
  7. captures exceptions raised from the child process
  8. the error status (exception) is available in $?, which returns a Process::Status object
Some examples:
system("find *.rb")
# script.rb
# => true
file_name = "script"
system("find", "#{file_name}.rb")
# script.rb
# => true
system("find", "*.rb")
# find: "*.rb": No such file or directory
# => false
$?
# => #<Process::Status: pid 4438 exit 1>
Please note the third command (and compare with the first command): Assigning wild card as a parameter does not work properly.
Kernel#system is great for simple system calls, if the result (e.g. the found files list) is not needed for further processing.

Kernel#exec

Kernel#exec works similar to Kernel#system, with an essential difference: it ends the current process by running the given external command. Running the script.rb:
exec("find *.rb")
puts "End"
will print out script.rb, but not "End". Another example, using IRB:
christian@Trinidad:~$ irb
2.1.1 :001 > exec("date")
Sun, 12 Oct 2014 06:40:23 CEST
christian@Trinidad:~$
exits IRB (the current process), processes the command and returns to bash.

%x() literal

An interpolated shell command can be achieved with the %x() literal as an alternative to the backtick style.
In a nutshell:
  1. the command can be as assigned as a String or even without string notation
  2. executes the command in a subshell
  3. is a blocking operation (waits until the result of operation completes)
  4. returns the command result
  5. raises exception caused by the child process error
  6. the error status (exception) is available in $?, which returns a Process::Status object (with qualified exit status)
Some examples:
%x[find *.rb]
# => "script.rb"
file_name = "script"
%x["find #{file_name}.rb"]
# => script.rb
Time.parse %x[date].chop
# => 2014-10-10 02:23:10 +0200
%x[foo]
# => Errno::ENOENT: No such file or directory - foo
$?
# => #<Process::Status: pid 5052 exit 127>
for comparison reasons, the same stuff with the backtick notation:
`find *.rb`
# => "script.rb"
file_name = "script"
`find #{file_name}.rb`
# => script.rb
Time.parse `date`.chop
# => 2014-10-10 02:23:10 +0200
`foo`
# => Errno::ENOENT: No such file or directory - foo
$?
# => #<Process::Status: pid 5055 exit 127>
The backtick notation is widely used but can be mixed up with String and therefore is not as readable (and intentional) as the %x literal.

Open3#popen3

Another level of granularity is the Open3#popen3.
It allows to deal with the input, output, error and even the wait thread.
  1. the command is assigned as a String
  2. executes the command in a subshell
  3. can be a non blocking operation (run other commands while processing the thread)
  4. full control over the thread
  5. full control over the stdin, stdout and stderr stream
A script.rb could look like:
stdin, stdout, stderr, wait_thr = Open3.popen3('ping www.google.com -c 3')
puts "Thread alive? #{wait_thr.alive?}"
puts "Some calculation: #{1 + 1}"
puts "Output: " + stdout.read
puts "Thread alive? #{wait_thr.alive?}"
# => Thread alive? true
# Some calculation: 2
# PING www.google.com (74.125.136.103) 56(84) bytes of data.
# 64 bytes from ea-in-f103.1e100.net (74.125.136.103): icmp_seq=1 ttl=46 time=26.8 ms
# 64 bytes from ea-in-f103.1e100.net (74.125.136.103): icmp_seq=2 ttl=46 time=24.7 ms
# 64 bytes from ea-in-f103.1e100.net (74.125.136.103): icmp_seq=3 ttl=46 time=23.2 ms
# --- www.google.com ping statistics ---
# 3 packets transmitted, 3 received, 0% packet loss, time 2001ms
# rtt min/avg/max/mdev = 23.229/24.913/26.804/1.477 ms
# Thread alive? false
Please note, that the stdout.read output waited until the thread was successfully ended. That is why there is 2 seconds gap between the calculations output and the stdout.read.
All 3 stdxxx are IO objects. The fourth wait_thr is a Thread object.
Open3#popen3 is the way to deal with system calls, when advanced processing is needed. Especially the full control over its streams is very powerful.
Further articles of interest:

Supported by Ruby 2.1.1

Sonntag, 5. Oktober 2014

Remove boolean parameters from your Ruby API!

Boolean parameters in method definitions are not a good choice for various reasons. They:
  1. are not readable
  2. duplicate code or responsibility inside and outside the method
There are alternatives to expecting true/ false. Let us assume a Ruby class like:
class Food
  def self.order vegetarian=false
    return "Vegetarian food" if vegetarian
    "Conventional food"
  end
end
The original code works so far, but using it is no laughing matter:
Food.order true # => "Vegetarian food"
Food.order # => "Conventional food"
What does "Food.order true" express? Does it mean "The Food order is no lie and is meant seriously"? TrueClass and FalseClass are not expressive in no way.
Even following the expressive boolean pattern (Express boolean parameters the Ruby way!) is not the best choice:
Food.order :vegetarian # => "Vegetarian food"
Food.order # => "Conventional food"
That is a little nicer, but it would be great to make even this work:
Food.order :conventional # => "Conventional food"
Every time the API is yours you have the choice to make it work great.
Use Enums instead of Booleans!
The original class should be refactored and expect Enum like:
class Food
  def self.order type=:conventional
    types = %i(conventional vegetarian)
    fail "Invalid Food type." unless types.member? type
    return "Conventional food" if type.eql? :conventional
    "Vegetarian food"
  end
end
and then:
Food.order :vegetarian # => "Vegetarian food"
Food.order :conventional # => "Conventional food"
Food.order :something_else # => RuntimeError: 
# Invalid Food type.
# Must one be of :conventional or :vegetarian.
The Enum method definition directs to a strict parameter expectation, which prevents API misinterpretations.
Although it still couples code or responsibility from outside and inside the method, there is another pro for Enums. It is way more extensible than boolean parameters can be.
A new requirement wants vegan food to be added:
class Food
  def self.order type=:conventional
    types = %i(conventional vegetarian vegan)
    fail "Invalid Food type." unless types.member? type
    case type
    when :vegetarian
      "Vegetarian food"
    when :vegan 
      "Vegan food"
    else "Conventional food"
    end
  end
end
Forgive the usage of a case statement for simplicity reasons.
Every time a new type of food has to be added the method can be changed without hurting the message senders, whereas boolean parameters will ruin the public API.
Further articles of interest:

Supported by Ruby 2.1.1