Ruby Zucker 3

What is it?

Zucker is the German word for sugar (pronunciation). It adds syntactic sugar in the form of independent, small scripts that make Ruby even more sweet. Read this blog post for a little introduction. See the github wiki for discussion and information about contributing.

Install

gem install zucker # might need sudo

Usage / Organisation

The gem consists of many small snippets, called cubes, which are bundled in packages. Currently, there are two packages available: default and debug. You can use a package be requiring it in this way: require 'zucker/default' and require 'zucker/debug' Since there aren't any dependencies within the gem, you could also pick only the cubes you want: require 'zucker/egonil'

You can also lock your require to a specific version of Zucker by simply putting the version before the cube name in this way: require 'zucker/1/egonil'. Future releases of the gem will include all previous (main) versions, so the behaviour of these directly required cubes will not change (except for critical bugs).

Cubes[default]

alias_for

Summary A different way to create aliases: Reversed order and you can pass multiple alias names.
Why? It's clearer in which order to put the arguments.
Methods/Usage
alias_for, aliases_for
alias_for :methods, :ms # creates an alias for the method :methods with the name ms
module Enumerable
  aliases_for :zip, :with, :%
end # creates multiple aliases
Module#method_alias_for, Module#method_aliases_for
# same as alias_for, but using Module#alias_method instead of alias
Further information Thanks to Kristian Mandrup for the idea and alias method specs.
Specification (show)
require 'zucker/alias_for'

describe 'alias_for' do
  it 'should create an alias for global methods' do
    # rspec bug? 
    # def m1
    #   1
    # end
    # alias_for :m1, :a1
    #
    # proc do
    #   a1.should == 1
    # end.should_not raise_exception
  end

  it 'should create an alias for instance methods' do
    class Array
      def m2
        2
      end
      alias_for :m2, :a2
    end
    proc do

      [1,2,3].a2.should == 2
    end.should_not raise_exception
  end

  it 'should create an alias for class (singleton) methods' do
    class Array
      class << Array
        def m3
          3
        end
        alias_for :m3, :a3
      end
    end

    proc do
      Array.a3.should == 3
    end.should_not raise_exception
  end


  it 'should create aliases for the first argument with all other arguments' do
    class Object
      def m4
        4
      end
    alias_for :m4, :ma, :mb, :mc
    end
    proc do
      1.ma.should   == 4
      "1".mb.should == 4
      [1].mc.should == 4
    end.should_not raise_exception
  end
end

# alias_method
module Blip
  def blip
    'blip'
  end
  alias_methods_for :blip, :blap, :blup
  
  class << self
    def self_blip
      'blip'
    end
    alias_methods_for :self_blip, :self_blap, :self_blup
  end
end

class Hello
  include Blip
  
  def hello
    'hello'
  end
  alias_methods_for :hello, :hi, :howdy
  
  class << self
    def self_hello
      'hello'
    end
    alias_methods_for :self_hello, :self_hi, :self_howdy
  end
end

describe 'alias_methods_for' do
  let(:h) { Hello.new }

  context "module context" do
    it "should alias instance methods" do
      h.blap.should == h.blip
      h.blup.should == h.blip
    end

    it "should alias class methods" do
      Blip.self_blap.should == Blip.self_blip
      Blip.self_blup.should == Blip.self_blip
    end
  end

  context "class context" do
    it "should alias instance methods" do
      h.hi.should == h.hello
      h.howdy.should == h.hello
    end

    it "should alias class methods" do
      Hello.self_hi.should == Hello.self_hello
      Hello.self_howdy.should == Hello.self_hello
    end
  end
end
Source (show)
def alias_for(m, *aliases)
  aliases.each{ |a|
    class_eval "alias #{a} #{m}"
  }
end
alias aliases_for alias_for

class Module
  def alias_method_for(m, *alias_methods)
    alias_methods.each{ |a|
      class_eval do
        alias_method a.to_sym, m.to_sym
      end
    }
  end
  alias alias_methods_for alias_method_for
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

aliases

Summary Some convenient aliases (and constants) for existing methods.
Methods/Usage
Object#is_an?
Object.is_a?
Enumerable#with
Enumerable#zip
Enumerable#%
Enumerable#zip
Array#**
Array#product
Hash#+
Hash#merge
Binding#[]
Binding#eval
Infinity
1.0 / 0.0
NaN
0.0 / 0.0
Specification (show)
require 'zucker/aliases'

describe '(aliases)' do
  it 'should create these aliases' do
    # see aliases.rb for aliase list
  end

  it 'should define these constants' do
    Infinity.finite?.should == false
    NaN.nan?.should         == true
  end
end
Source (show)
alias is_an? is_a?

module Enumerable
  alias with zip
  alias %    zip
end

class Array
  alias ** product
end

class Hash
  alias + merge
end

class Binding
  #alias [] eval
  def [](expr)
    self.eval "#{expr}"
  end
end

# constants - who would use these in real-world code for other things?
Infinity = 1.0 / 0.0 # or 2*Float::MAX
NaN      = 0.0 / 0.0

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

array

Summary Methods one could miss for Array.
Why?

Array has & and |, but why does it not have ^?

sum is just needed pretty often..

Methods/Usage
Array#^
[1,2,3,4] ^ [3,4,5,6]  # => [1,2,5,6]
Array#sum
[1,2,3,4,5].sum  # => 15
Array#chrs
[72, 97, 108, 108, 111].chrs  # => 'Hallo'
Specification (show)
require 'zucker/array'

describe 'Array#^' do
  it 'should do an exclusive or' do
    a = [1,2,3,4]
    b = [3,4,5,6]
    (a^b).should == [1,2,5,6]
  end
end

describe 'Array#sum' do
  it 'should sum the array' do
    [1,2,3,4,5].sum.should   == 15
    %w|More Ruby|.sum.should == 'MoreRuby'
  end
end

describe 'Array#chrs' do
  it 'should convert the array to a string, using each element as ord value for the char' do
    [72, 97, 108, 108, 111].chrs.should == 'Hallo'
  end
end
Source (show)
class Array
  def ^(other) # TODO: more efficient
    (self - other) +
    (other - self)
  end

  # can take an argument & block to be Rails compatible
  def sum(identity = 0, &block)
    # inject(:+)
    if block_given?
      map(&block).sum( identity )
    else
      inject(:+) || identity
    end
  end

  def chrs
    self.pack 'C*'
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

array2proc

Summary Calls the method named by the first paramenter and passes the other elements as paramaters.
Why? When using Symbol#to_proc, you often wish to pass parameters.
Methods/Usage
Array#to_proc
[1,2,3,4].map &[:*, 5] # => [5, 10, 15, 20]
# you can also chain them, if the first parameter is an Array
[1,2,3,4].map &[[:to_s, 2],[:+, 'b']]   # => ["1b", "10b", "11b", "100b"]
Further information Inspired by this article.
More about to_proc.
Chaining inspired by eregon.
Specification (show)
require 'zucker/array2proc'

describe 'Array#to_proc' do
  it 'should call the method of the first symbol, using the remaining elements as paramaters' do
    [1,2,3,4].map( &[:to_s, 2] ).should == ["1", "10", "11", "100"]
  end

  it "should convert each element to a proc and chain it, if the first parameter is an array" do
    [1,2,3,4].map( &[[:*,2],[:+,4]] ).should == [1,2,3,4].map{|i| i*2 + 4 }
  end
end
Source (show)
class Array
  def to_proc
    Proc.new{ |obj|
      if self.first.is_a? Array
        self.inject(obj){ |result, nested_array|
          nested_array.to_proc.call result
        }
      else
        obj.send *self
      end
    }
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

blank

Summary Does pretty the same as in ActiveSupport (Every object can be asked if it is blank).
Why? It's too familiar ;)
Methods/Usage
Object#blank?
'an object'.blank? # => false
Specification (show)
require 'zucker/blank'

describe 'Object#blank?' do
  it 'should be blank for blank values' do
    blank_values   = [ nil, false, '', '   ', "  \n\t  \r ", [], {}, // ]

    blank_values.each{ |blank|
      blank.blank?.should == true
    }
  end

  it 'should not be blank for non blank values' do
    present_values = [ Object.new, true, 0, 1, 'a', [nil], { nil => nil } ]

    present_values.each{ |present|
      present.blank?.should == false
    }
  end
end
Source (show)
class Object
  def blank?
    if respond_to? :empty? then empty? else !self end
  end

  def present?
    !blank?
  end
end


{ # what to do              # for which classes
  lambda{ true }         => [FalseClass, NilClass],
  lambda{ false }        => [TrueClass, Numeric],
  lambda{ empty? }       => [Array, Hash],
  lambda{ self !~ /\S/ } => [String],
  lambda{ self == //   } => [Regexp],

}.each{ |action, klass_array|
  klass_array.each{ |klass|
    klass.send :define_method, :blank?, &action
  }
}

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

class2proc

Summary Creates a new instance of the class.
Methods/Usage
Class#to_proc
[ [1,2],[3,5,6,7,3] ].map(&Set) # => [ Set[1,2], Set[5,6,7,3] ]
Further information Inspired by Ruby Facets.
More about to_proc.
Specification (show)
require 'zucker/class2proc'
require 'set'

describe 'Class#to_proc' do
  it 'should create new instances of the class' do
    [ [1,2],[3,5,6,7,3] ].map(&Set).should == [ Set[1,2], Set[5,6,7,3] ]
  end
end
Source (show)
class Class
  def to_proc
    Proc.new do |*args|
      self.new *args
    end
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

egonil

Summary Creates a block, where nil does not raise NoMethodErrors.
Methods/Usage
egonil, nn
egonil do
  nil.some_methods.that[:do].not.exist
end # => nil

nn(5){ nil.some_methods.that[:do].not.exist }
# => 5
Further information See this post for more information and discussion.
Specification (show)
require 'zucker/egonil'

describe 'egonil' do
  it 'should not raise nil exceptions in the block' do
    proc do
      egonil{ nil.some_methods.that[:do].not.exist }
    end.should_not raise_exception
  end

  it 'should return the nil_value if given' do
    egonil(9){ nil.some_methods.that[:do].not.exist }.should == 9
  end

  it 'should restore default behaviour after the block' do
    proc do
      egonil{ nil.some_methods.that[:do].not.exist }
    end.should_not raise_exception

    proc do
      nil.a_method
    end.should raise_exception NoMethodError
  end

  it 'raise NoMethodError for non-nil objects' do
    proc do
      egonil{ 5.a_method }
    end.should raise_exception NoMethodError
  end
end
Source (show)
def egonil(nil_value = nil)
  yield
rescue NoMethodError => e
  if e.message =~ /NilClass$/
    nil_value
  else
    raise NoMethodError
  end
end

alias nn egonil

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

enumerable

Summary Enumerable extensions.
Methods/Usage
Enumerable#mash
[1,2,3].mash{|e| [e, e.to_s] } # => {1=>'1',2=>'2',3=>'3'}
Further information Inspired by Ruby Facets' mash.
Specification (show)
require 'zucker/enumerable'

describe 'Enumerable#mash' do
  it 'should "map" a hash' do
    [1,2,3].mash{|e| [e, e.to_s] }.should == {1=>'1',2=>'2',3=>'3',}
  end
end
Source (show)
module Enumerable
  def mash
    ret = {}
    each{ |kv|
      ret.store *( yield(kv)[0,2] )
    }
    ret
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

hash

Summary Some sugar for dealing with hashs.
Methods/Usage
Hash.zip
Hash.zip [1,2,3], [4,5,6] # => {1 => 4, 2 => 5, 3 => 6}
Hash#<<
{1 => 2} << [3, 4]   # => { 1 => 2, 3 => 4 }
{1 => 2} << { 5=>6 } # => { 1 => 2, 5 => 6 }
Further information Some of the operators are inspired by Ruby Facets.
Specification (show)
require 'zucker/hash'

describe 'Hash.zip' do
  it 'should zip together both given enumerables and take them as key=>values for a new hash' do
    Hash.zip( [1,2,3], [4,5,6] ).should == { 1=>4, 2=>5, 3=>6 }
  end
end

describe 'Hash#<<' do
  it 'should append new elements to the hash' do
    a =  { 1=>4, 2=>5, 3=>6 }
    a << { 4=>7 }
    a << [5, 8]
    a.should == { 1=>4, 2=>5, 3=>6, 4=>7, 5=>8 }
  end
end
Source (show)
class Hash
  def self.zip(keys,values)
    Hash[ *keys.zip( values ).flatten ]
  end

  def <<(other)
    case
    when other.is_a?(Hash)
      merge! other
    when other.is_a?(Enumerable) || other.respond_to?(:to_splat)
      merge! Hash[*other]
    else
      raise TypeError, 'can only append other Hashs and Enumerables (or Classes that implement to_splat)'
    end
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

hash2proc

Summary Use a hash to apply procs to specific objects.
Methods/Usage
Hash#to_proc
[1,2,3,4].map(&{
2 => lambda {|e| e + 1000},
4 => :to_s,
}) # => [1, 1002, 3, '4']
Further information More about to_proc.
Specification (show)
require 'zucker/hash2proc'

describe 'Hash#to_proc' do
  it 'should run the proc given in the value for a key in the hash' do
    [1,2,3,4].map(&{
      4 => :to_s,
      # 3 => [:to_s, 2]  # "11" =>  if array2proc is used
      2 => lambda {|e| e + 1000}
    }).should == [1, 1002, 3, "4"]
  end
end
Source (show)
class Hash
  def to_proc
    Proc.new{ |obj|
      if self.member? obj
        self[obj].to_proc.call obj
      else
        obj
      end
    }
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

info

Summary Access environment information with the Info module.
Why? You don't need to remember in which global variable, constant or special method the information you are searching for is hidden.
Methods/Usage
Info
# for example
Info.current_file      # __FILE__
Info.working_directory # Dir.pwd
Info.load_path         # $:
Info.platform          # RUBY_PLATFORM
# you could also add them to the global namespace with: include Info
# see the source file for the list of accessors or
Info.list
Specification (show)
require 'zucker/info'

describe 'Info' do
  it 'should define accessors for global variables, constants and some special methods/keywords' do
    # see sourcefile for the list
  end
end
Source (show)
module Info
  class << Info
    # hash like access
    def [](what)
      send what
    end

    # list available info methods
    def list
      singleton_methods - [:[], :list, '[]', 'list']
    end
  end

  module_function

  # current script file
  def current_file
    __FILE__
  end

  def current_file_directory
    File.dirname(__FILE__)
  end

  # input
  def last_input_file
    $FILENAME
  end

  def last_input_line_number
    $.
  end

  def last_input
    $_
  end

  # program
  def program_name
    $0
  end

  def program_arguments
    $:
  end

  def loaded_programs
    $"
  end

  def program_data
    ::DATA
  end

  def child_program_status
    $CHILD_STATUS
  end

  # system info
  def environment
    ::ENV
  end
  alias env environment

  def working_directory
    Dir.pwd
  end

  def platform
    ::RUBY_PLATFORM
  end

  def process_id
    $$
  end

  def load_path
    $:
  end

  # current
  def current_line
    __LINE__
  end

  def current_method # 1.9
    __method__
  end

  def current_callstack
    caller
  end

  # dealing with strings
  def gets_separator
    $/
  end

  def join_separator
    $,
  end

  def print_separator
    $,
  end

  def split_separator
    $;
  end

  # misc
  def security_level
    $SAFE
  end

  def warnings_activated?
    $VERBOSE
  end

  def debug_activated?
    $DEBUG
  end

  def last_exception
    $!
  end

  # defined objects
  def global_variables
    Object.send :global_variables
  end

  def global_constants
    Object.constants
  end

  # encoding (1.9)
  def source_encoding
    __ENCODING__
  end

  def external_encoding
    Encoding.default_external
  end

  def internal_encoding
    Encoding.default_internal
  end

  # ruby version info
  def ruby_version
    ::RUBY_VERSION
  end

  def ruby_patchlevel
    ::RUBY_PATCHLEVEL
  end

  def ruby_description
    ::RUBY_DESCRIPTION
  end

  def ruby_release_date
    ::RUBY_RELEASE_DATE
  end
end
Compatibility 1.9, 1.8 (not all information)
Discussion github wiki

iterate

Summary Iterate over one or more collections.
Why? It's like .each with two differences: It feels more like a control structure and you can easily iterate over multiple objects.
Methods/Usage
iterate
iterate [1,2], [3,4,5] do |e,f|
  puts "#{e},#{f}"
end
# outputs
#  1,3
#  2,4
#  ,5
Specification (show)
require 'zucker/iterate'

describe 'Object#iterate' do
  let :a   do [1, 2, 3]     end
  let :b   do %w|a b c d|   end
  let :res do Hash.new {[]} end

  it 'should behave like Enumerable#each for a single argument' do
    iterate a do |ele|
      res[:iter] << ele
    end

    a.each do |ele|
      res[:each] << ele
    end

    res[:iter].should == res[:each]
  end

  it 'should pass the right params to the block' do
    res = Hash.new {[]} # TODO: why?
    res[:iter_a_b] = [] # ....
    res[:iter_b_a] = [] # ....


    iterate a, b do |e,f|
      res[:iter_a_b] << [e, f]
#      p res[:iter_a_b], e, f
    end

    res[:iter_a_b].should == [
      [1, 'a'],
      [2, 'b'],
      [3, 'c'],
      [nil, 'd'],
    ]

    iterate b, a do |e,f|
      res[:iter_b_a] << [e, f]
    end

    res[:iter_b_a].should == [
      ['a', 1],
      ['b', 2],
      ['c', 3],
      ['d', nil],
    ]

  end

  it 'should return enumerators if no block is applied' do
  end
end
Source (show)
def iterate(*params)
  # params.shift.zip(*params).each{ |*elements| yield *elements }

  first = params.shift
  if params.empty? # single param - like each
    if block_given?
      first.map{|e| yield e }
    else
      first.map
    end
  else
    padded_first = Array.new( [first, *params].max_by(&:size).size ){|i| first[i] } # append nils
    obj = padded_first.zip *params
    if block_given?
      obj.map{|es| yield *es }
    else
      obj.map.to_enum
    end
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

ivars

Summary This method lets you easily assign lots of instance variables.
Why? Often, you have to write boilerplate code for assigning instance varialbles, for example this one:
def initialize(variable1, variable2)
  @variable1, @variable2 = variable1, variable2
end

Methods/Usage
instance_variables_from, ivars
def a_method(a = 1, b = 2)
  instance_variables_from binding # assigns @a and @b

  params = {:c => 3, :d => 4}
  instance_variables_from params # # assigns @c and @d
end
Specification (show)
require 'zucker/ivars'

describe 'instance_variables_from' do
  it 'should tansform the given parameter to instance variables' do
    def a_method(a = 1, b = 2)
      instance_variables_from binding # assigns @a and @b

      params = {:c => 3, :d => 4}
      ivars params # # assigns @c and @d
    end

    a_method
    @a.should == 1
    @b.should == 2
    @c.should == 3
    @d.should == 4

  end
end
Source (show)
def instance_variables_from(obj, *only)
  iter =
  if    obj.is_a? Binding
    obj.eval('local_variables').map{|e| [obj.eval("#{e}"), e] }
  elsif obj.is_a? Hash
    obj.map{|k,v| [v,k] }
  else
#  elsif obj.is_a? Enumerable
    obj.each.with_index
  end

  ret = []
  iter.each{ |value, arg|
    arg = arg.to_s
    if only.include?(arg) || only.include?(arg.to_sym) || only.empty?
      arg = '_' + arg  if (48..57).member? arg.unpack('C')[0]  # 1.8+1.9
      ret << ivar = :"@#{arg}"
      self.instance_variable_set ivar, value
    end
  }
  ret
end
alias ivars instance_variables_from

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

kernel

Summary Some useful general shortcut methods.
Why? Readability.
Methods/Usage
activate_warnings!
activate_warnings! # sets $VERBOSE to 1
deactivate_warnings!
deactivate_warnings! # sets $VERBOSE to 0
executed_directly?, standalone?
executed_directly? # checks, if the current file is run directly -> true
library?
library? # checks, if the current file is run directly -> false
ignore_sigint!
ignore_sigint! # blocks CTRL+C
ruby_1_8?
ruby_1_8? # returns true for 1.8.x
ruby_1_9?
ruby_1_9? # returns true for 1.9.x
ruby_1_8!, ruby_1_9!
# raises a NotImplementedError if not executed with the right ruby version
Specification (show)
require 'zucker/kernel'

describe 'activate_warnings!' do
  it 'should set $VERBOSE to true' do
    activate_warnings!
    $VERBOSE.should == true
  end
end

describe 'deactivate_warnings!' do
  it 'should set $VERBOSE to false' do
    deactivate_warnings!
    $VERBOSE.should == false
  end
end

describe 'library?' do
  it 'should return false if the file is invoked directly' do
    library?.should == ( __FILE__ != $PROGRAM_NAME )
  end
end

describe 'executed_directly?' do
  it 'should return true if the file is invoked directly' do
    executed_directly?.should == ( __FILE__ == $PROGRAM_NAME )
  end
end

describe 'ignore_sigint!' do
  it 'should catch ctrl+c signals' do
    # ...
  end
end

describe 'ruby_1_8? and ruby_1_9?' do
  it 'should return true if run with the right ruby version' do
    # ...
  end
end

describe 'ruby_1_8! and ruby_1_9!' do
  it 'should throw a NotImplementedError if run with the wrong ruby version' do
    # ...
  end
end
Source (show)
module Kernel
  def activate_warnings!
    $VERBOSE = true
  end
  
  def deactivate_warnings!
    $VERBOSE = false
  end
  
  def library?
    __FILE__ != $PROGRAM_NAME
  end
  
  def executed_directly?
    __FILE__ == $PROGRAM_NAME
  end
  alias standalone? executed_directly?
  
  def ignore_sigint! # ctrl+c
     Signal.trap *%w|SIGINT IGNORE|
  end

  # version getter  
  def ruby_1_9?
    RUBY_VERSION[2,1] == '9'
  end

  def ruby_1_8?
    RUBY_VERSION[2,1] == '8'
  end

  def ruby_1_9!
    if RUBY_VERSION[2,1] != '9'
      fail NotImplementedError, "Sorry, this script requires Ruby 1.9, but was executed with a different Ruby version!"
    end
    true
  end

  def ruby_1_8!
    if RUBY_VERSION[2,1] != '8'
      fail NotImplementedError, "Sorry, this script requires Ruby 1.8, but was executed with a different Ruby version!"
    end
    true
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

mcopy

Summary Adds Object#mcopy to create a deep copy using Marshal.
Why? Every Ruby book describes, you can do Marshal.load Marshal.dump object to create a deep copy... But who needs this verbose syntax in everyday coding?
Methods/Usage
Object#mcopy
a = %w[hello world]
b = a.mcopy
Specification (show)
require 'zucker/mcopy'

describe 'Object#mcopy' do
  it 'create a (deep) copy via marshalling' do
    a = %w[hello world]
    b = a.mcopy
    b.should == a

    b[0][1,1] = ''
    b.should_not == a
  end
end
Source (show)
class Object
  def mcopy
    Marshal.load Marshal.dump self
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

not

Summary not returns an object on which all methods are redirected to it's receiver object, but returns inverted boolean.
Why? Better readability.
Methods/Usage
Object#not
[1,2,3].not.empty? # true
Further information See this article by Jay Field for more information.
Specification (show)
FIXME: missing
Source (show)
class Object
  def not
    NotClass.new self
  end

  class NotClass < BasicObject
    def initialize(receiver)
      @receiver = receiver
    end
    
    def method_missing(m, *args, &block)
      not @receiver.public_send( m, *args, &block )
    end
  end
end

# J-_-L
Compatibility 1.9
Discussion github wiki

regexp2proc

Summary Use &/regex/ to match it against strings.
Methods/Usage
Regexp#to_proc
%w|just another string array|.map    &/[jy]/  # => ["j", nil, nil, "y"]
%w|just another string array|.select &/[jy]/  # => ["just", "array"]
Further information More about to_proc.
Specification (show)
require 'zucker/regexp2proc'

describe 'Regexp#to_proc' do
  it 'should match the regex' do
    %w|just another string array|.map(     &/[jy]/).should == ["j", nil, nil, "y"]
    %w|just another string array|.select(  &/[jy]/).should == ["just", "array"]
  end
end
Source (show)
class Regexp
  def to_proc
    proc do |e|
      e.to_s[self]
    end
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

sandbox

Summary Creates a sandbox area.
Why? Ruby comes with sandboxes, but they are hidden (-> integrated) in the $SAFE concept.
Methods/Usage
sandbox
sandbox do
  # dangerous commands throw SecurityErrors ($SAFE=4)
end
# everything's normal again

sandbox( lambda{} ) do
  # no Exception is thrown, if non-nil parameter is passed
end
# if it is a proc, it will be run instead, if an SecurityError gets raised
Specification (show)
require 'zucker/sandbox'

describe 'sandbox' do
  it 'should throw a SecurityError if bad commands are issued' do
    proc do
      sandbox do
        `ls`
      end
    end.should raise_exception SecurityError
  end

  it 'should not throw an exception for errors, if the given parameter is not nil' do
    proc do
      sandbox( true ) do
        `ls`
      end
    end.should_not raise_exception
  end

  it 'should run the proc passed as parameter for errors, if it is given' do
    sandbox( lambda{|e| e.class } ) do
      `ls`
    end.should == SecurityError
  end
end
Source (show)
def sandbox(rescueblock_or_default=nil)
  Thread.start do
    $SAFE = 4
    yield
  end.value
rescue SecurityError => e
  if !rescueblock_or_default.nil?
    if rescueblock_or_default.is_a? Proc
      rescueblock_or_default.call e
    else
      rescueblock_or_default
    end
  else
    raise e
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

square_brackets_for

Summary This helper methods defines [] and []= for accesing an instance variable.
Methods/Usage
square_brackets_for
class Klass
  def initialize
    @var = {
      :a_key => 1,
      :another_one => 2,
    }
  end

  square_brackets_for :var # creates [] and []=
  # square_brackets_for :var, false # would create only []
end

a = Klass.new
a[:a_key] # => 1
Specification (show)
require 'zucker/square_brackets_for'

describe 'square_brackets_for' do

  before do
    class Klass
      def initialize
        @var = {
          :a_key => 1,
          :another_one => 2,
        }
      end

      @eigenvar = {
        :a_key => 99
      }
    end
  end

  it 'should define a [] getter (not a setter) for an instance var, if the second parameter is false' do

    class Klass
      square_brackets_for :var, nil
    end

    a = Klass.new
    a[:a_key].should == 1

    proc do
      a[:this_is] = 'not possible'
    end.should raise_exception NoMethodError
  end

  it 'should define [] and []= for accessing an instance variable' do

    class Klass
      square_brackets_for :var
    end

    a = Klass.new
    a[:a_key].should == 1

    a[:this_is] = 'useful'
    a[:this_is].should == 'useful'
  end

  it 'should also work for class-instance variables' do

    class Klass
      class << Klass
        square_brackets_for :eigenvar
      end
    end

    Klass[:a_key].should == 99
  end

end
Source (show)
def square_brackets_for(ivar, assignment = true)
#  undef []   if respond_to? :[]
#  undef []=  if respond_to? :[]=

#instance_eval do
  define_method :[] do |key|
    (instance_variable_get :"@#{ivar}")[key]
  end

  if assignment
    define_method :[]= do |key, value|
      (instance_variable_get :"@#{ivar}")[key] = value
    end
  end
#end

end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

string

Summary String extensions.
Why? Strings cannot be comfortable enough ;).
Methods/Usage
String#^
'Yes vs No'^3 # => 'Yes'
String#lchomp
'   Yes'.lchomp  # => 'Yes'
String#lchomp!
# mutable lchomp version
String#ords
'Hallo'.ords # => [72, 97, 108, 108, 111]
String#constantize
'Object'.constantize # => Object
'Spec::VERSION'.constantize # => Spec::VERSION if rspec is loaded
# you can also pass a parameter or block to define what happens, when constant does not exist
'IdontExist'.constantize(Array) # => Array
'String5'.constantize do |string|
  string.chop.constantize
end # => String
Further information constantize is an improved version of ActiveSupport's one
Specification (show)
require 'zucker/string'

describe 'String#^' do
  it 'should give C-like substring access to strings' do
    string = 'Theoretische Informatik ist voll geil!'

    (string^0).should  == 'Theoretische Informatik ist voll geil!'
    (string^1).should  == 'heoretische Informatik ist voll geil!'
    (string^13).should == 'Informatik ist voll geil!'
    (string^-1).should == 'Theoretische Informatik ist voll geil'
    (string^38).should == ''
    (string^99).should == nil
  end
end

describe 'String#lchomp' do
  it 'should chomp on the left side' do
    string = 'Theoretische Informatik ist voll geil!'
    string.lchomp('T').should  == 'heoretische Informatik ist voll geil!'
  end
end

describe 'String#ords' do
  it 'should unpack characters' do
    string = 'Theoretische Informatik ist voll geil!'
    string.ords.should  == [84, 104, 101, 111, 114, 101, 116, 105, 115, 99, 104, 101, 32, 73, 110, 102, 111, 114, 109, 97, 116, 105, 107, 32, 105, 115, 116, 32, 118, 111, 108, 108, 32, 103, 101, 105, 108, 33]
  end

  describe 'String#constantize' do
    it 'should return the constant with that name' do
      'Object'.constantize.should == Object
    end

    it 'should also work for nested constants' do
      'Spec::VERSION'.constantize.should == Spec::VERSION
    end

    it 'should throw name error if constant does not exist (and no parameter is given)' do
      proc do
        'ObfsefsefsefafesafaefRubyZuckerafdfselijfesject'.constantize
      end.should raise_exception NameError
    end

    it 'should call the block (and not raise an error) if constant does not exist and block given' do
      proc do
        'ObfsefsefsefafesafaefRubyZuckerafdfselijfesject'.constantize do |string|
           Default = [1,2,3]
        end.should == [1,2,3]
      end.should_not raise_exception NameError
    end

    it 'should return the second parameter (and not raise an error) if constant does not exist and parameter given' do
      proc do
        'ObfsefsefsefafesafaefRubyZuckerafdfselijfesject'.constantize(Array).should == Array
      end.should_not raise_exception NameError
    end
  end
end
Source (show)
class String
  def ^(pos)
    pos = pos.to_i
    if pos >= 0
      self[pos..-1]
    else
      self[0...pos]
    end
  end

  def lchomp(arg = $/)
    self.reverse.chomp(arg).reverse
  end

  def lchomp!(arg = $/)
    self.reverse.chomp!(arg).reverse
  end

  def ords
    self.unpack 'C*'
  end

  def constantize(default_value = nil) # always uses global scope as in AS... is this good?
    get_constant = lambda{
      self.split(/::/).inject( Object ){ |base_constant, current_constant|
        base_constant.const_get current_constant
      }      
    }

    if !default_value && !block_given?
      get_constant.call
    else
      begin
        get_constant.call
      rescue NameError
        if block_given?
          yield self
        else
          default_value
        end
      end
    end
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

tap

Summary This cube adds the two tap variants tap_on (known as returning in ActiveSupport) and make_new.
Methods/Usage
tap_on
tap_on [1,2] do |obj|
  obj[4] => 5
end #=> [1, 2, nil, nil, 5]
make_new
make_new Hash do |obj|
  obj[1] = 2
end #=> {1 => 2}
Further information Read more about using tap on the ruby best practises blog.
Specification (show)
require 'zucker/tap'

describe 'tap_on' do
  it 'should call tap on the argument and apply the block' do
    obj = "an_object"
    block = :reverse.to_proc

    tap_on( obj, &block ).should == obj.tap( &block )
  end
end

describe 'make_new' do
  it 'should create a new instance of the class given as argument, apply the block on it and return result' do
    res = make_new Hash do |obj|
      obj[1] = 2
    end
    res.should == { 1=>2 }
  end
end
Source (show)
def tap_on(obj, &block)
  obj.tap &block
end

def make_new(what, *args, &block)
  what.new(*args).tap &block
end

# J-_-L
Compatibility 1.9
Discussion github wiki

unary

Summary Easy conversion between strings and symbols.
Why? Sometimes, you do not care if you get a String or Symbol as input - but when analysing it, you often need to choose one format. A concise possibility for this conversion is using the unary operators String#-@ and Symbol#+@.
Methods/Usage
String#+@
+'was_string' # => 'was_string'
String#-@
-'was_string' # => :was_string
Symbol#+@
+:was_symbol  # => 'was_symbol'
Symbol#-@
-:was_symbol  # => :was_symbol
Further information Inspired by (I've seen the unary + for Symbol somewhere on the net... but cannot remember where...)
Specification (show)
require 'zucker/unary'

describe Symbol, '#+@' do
  it 'should convert to_s' do
    +(:matz) == 'matz' # () 1.8 bug
  end
end

describe Symbol, '#-@' do
  it 'should do nothing' do
    -:matz == :matz
  end
end

describe String, '#+@' do
  it 'should do nothing' do
    +'matz' == 'matz'
  end
end

describe String, '#-@' do
  it 'should convert to_sym' do
    -'matz' == :matz
  end
end
Source (show)
class String
  def +@
    self
  end

  def -@
    to_sym
  end
end

class Symbol
  def +@
    to_s
  end

  def -@
    self
  end
end

# J-_-L
Compatibility 1.9, 1.8 (+:literal not possible)
Discussion github wiki

union

Summary Easy creation of Regexp.unions.
Methods/Usage
Regexp#|, String#|
/Ruby\d/ | /test/i | "cheat"
# creates a Regexp similar to:
# /(Ruby\d|[tT][eE][sS][tT]|cheat)/
Specification (show)
require 'zucker/union'

shared_examples_for "Regexp.union operator" do
  it "should create an Regexp.union of both operands" do
    (/Ruby\d/ | /test/i | "cheat").should ==
      Regexp.union( Regexp.union( /Ruby\d/, /test/i ), "cheat" )
  end
end

describe 'Regexp#|' do
  it_should_behave_like 'Regexp.union operator'
end

describe 'String#|' do
  it_should_behave_like 'Regexp.union operator'
end
Source (show)
class Regexp
  def |(arg)
    Regexp.union self, arg.is_a?(Regexp) ? arg : arg.to_s
  end
end

class String
  def |(arg)
    Regexp.union self, arg.is_a?(Regexp) ? arg : arg.to_s
  end
end

# J-_-L
Compatibility 1.9
Discussion github wiki

Cubes[debug]

D

Summary Easy debug printing with the p alternative .D. It outputs to stdout and returns self. Accepts a block.
Methods/Usage
Object#D
some.D.methods.D.noone.D.knows.D
# ...outputs 4 lines with the inspected objects
# => (result)

21+Math.sin(42).D
# outputs -0.916521547915634
# => 20.0834784520844

name = 'Earth'
'Hello ' + name.D{|e| "The length is: #{e.size}"}
# outputs "The length is: 5"
# => 'Hello Earth'
Further information This is inspired by the .tap method.
There is also tap cube with more tap methods.
Specification (show)
require 'zucker/D'

describe 'Object#D' do

  let :a do
    [ 1, "1", 2..5, [], {:hallo => :du}, nil, true ]
  end

  it 'should not change the object"s value' do
    a.each{ |e|
      (e.D).should == e
    }

    a.each{ |e|
      (e.D{|value| "This is a: #{value}"}).should == e
    }
  end

  it "should puts .inspect if no block is given (and not change the object's value)" do
    capture_stdout do
      a[0].D
      a[1].D
      a[6].D
    end.should == %{1\n"1"\ntrue\n}
  end

  it "should puts the block if it is given (and not change the object's value)" do
    capture_stdout do
      a[0].D{|value| "This is a: #{value}"}
      a[1].D{|value| "This is a: #{value}"}
      a[6].D{|value| "This is a: #{value}"}
    end.should == %{This is a: 1\nThis is a: 1\nThis is a: true\n}
  end
end
Source (show)
module Kernel
  def D(*args, &block)
    if args.empty?
      tap{
        if block_given?
          puts yield self
        else
          puts self.inspect
        end
      }
    else
      raise ArgumentError, ".D - The parser thought that the code after .D are method arguments... Please don't put a space after D or use .D() or .D{} in this case!"
#      eval ...
    end
  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

binding

Summary Adds a verbose Binding#inspect.
Why? It gives you information about the current environment.
Methods/Usage
Binding#inspect
binding.inspect # shows your current environment
Specification (show)
require 'zucker/binding'

describe 'Binding#inspect' do
  it 'should output the current environment' do
    #pending '#TODO: write spec'
  end
end
Source (show)
class Binding
  def inspect
    put_vars = lambda { |array|
      if array.empty?
        ' - none'
      else
        array.map{|e| " - #{e}: #{ self.eval '#{e}'}"}*"\n"
      end
    }

"#{self.to_s}
local vars
#{ put_vars[ self.eval 'local_variables' ] }
(instance vars)
#{ put_vars[ self.eval 'instance_variables' ] }
self
 - #{self.eval 'self'}
block_given?
 - #{self.eval 'block_given?'}"

  end
end

# J-_-L
Compatibility 1.9, 1.8
Discussion github wiki

mm

Summary mm displays an ordered public method list.
Why? See one object's methods without those rarely used inherited methods.
Methods/Usage
Object#method_list, Object#mm
'test'.mm 2 # outputs the list (2 levels deep)
Further information See this article for more information.
Specification (show)
require 'zucker/mm'

describe 'Object#method_list' do
  it 'should display an ordered method list' do
    #pending '#TODO: write spec'
  end
end
Source (show)
module Kernel
  def method_list(levels = 1)
    if self.is_a? Module
      klass, method_function = self, :public_methods
    else
      klass, method_function = self.class, :public_instance_methods

      eigen = self.singleton_methods
      if !eigen.empty?
        puts :Eigenclass # sorry for not being up to date, I just love the word
        p self.singleton_methods
      end
    end

    levels.times{ |level|
      if cur = klass.ancestors[level]
        p cur                               # put class name
        p cur.send method_function, false   # put methods of the class
      else
        break
      end
    }

    self # or whatever
  end

  alias mm method_list
end

# J-_-L
Compatibility 1.9, 1.8 (returns strings instead of symbols)
Discussion github wiki

Changelog

2010-08-14 | Zucker 3
* added tap cube
* added Object#not
* added alias_for for an alternative alias syntax
* added String#constantize (improved AS version)
* improved Info module
* made Array#sum Rails compatibile
* improved docs
* changed directory layout (no changes for requiring)
* more small changes


2010-08-08 | Zucker 2
* added info cube
* added chaining for array2proc
* fixed Hash.zip
* fixed instance_variables_from binding for 1.9
* more specs


2010-08-06 | Zucker 1
* initial release


2010-08-05 | Zucker 0
* pre-release for rug-b talk