Ruby Zucker 7

What is it?

Zucker (pronunciation) is the German word for sugar. It adds syntactic sugar in the form of independent, small scripts that make Ruby even more sweet. It adds a lot of useful helper methods for an improved readability and usage. Everything is documented on this page.

Read this blog post for some more examples. See the github wiki for discussion and information about contributing.

Install

gem install zucker --no-rdoc --no-ri # might need sudo

Quickstart

require 'zucker/all'

Usage / organisation

The gem consists of many small snippets, called cubes, which are bundled in packages. Since there aren't any dependencies within the gem, you can easily require only the packages or cubes you want: require 'zucker/cube_or_package_name'

Packages

Furthermore, there are two meta packages available: all simply requires all cubes and default requires all cubes except debug. 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 very critical bugs).

Which methods and constants are added directly to the global namespace by the default package?

Info, RubyVersion, RubyEngine, OS, Infinity, NaN, alias_for, aliases_for, egonil, nn, iterate, instance_variables_from, ivars, activate_warnings!, deactivate_warnings!, executed_directly?, standalone?, library?, ignore_sigint!, sandbox, tap_on, make_new, (blank?, present?, mcopy)

Cubes[control]

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{ nil.some_methods.that[:do].not.exist } # => nil
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 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)
require 'zucker'

# code by Yohan, slightly edited and comments by me
def egonil(&block)
  # grip methods
  ori_method_missing   = NilClass.instance_method(:method_missing)
  catch_method_missing = NilClass.instance_method(:catch_method_missing)
  # activate ego mode
  NilClass.send :define_method, :method_missing, catch_method_missing
  # run code
  yield
ensure
  # no matter what happens: restore default nil behaviour
  NilClass.send :define_method, :method_missing, ori_method_missing
end

# this is the ego nil
class NilClass
  def catch_method_missing(m, *args, &block)
    nil
  end
end

alias nn egonil

# J-_-L
Compatibility 1.9, 1.8
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)
require 'zucker'

def iterate(*params)
  # params.shift.zip(*params).each{ |*elements| yield *elements }
  raise ArgumentError, "wrong number of arguments (0)" if params.empty?

  first = params.shift
  if params.empty? # single param - like each
    if block_given?
      first.map{|e| yield e }
    else
      first.map.to_enum
    end
  else # multiple params
    max_size = [first, *params].max_by(&:count).size
    padded_first = first.to_a + [nil]*(max_size - first.count)  # 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

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
irb?
irb? # returns false if not called from IRB
ignore_sigint!
ignore_sigint! # blocks CTRL+C
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 'irb?' do
  it 'should return true if called in IRB' do; end
end

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

# J-_-L
Source (show)
require 'zucker'

module Kernel
  private

  def activate_warnings!
    $VERBOSE = true
  end

  def deactivate_warnings!
    $VERBOSE = false
  end

  def library?
    caller[0].rindex(/:\d+(:in `.*')?$/)
    $PROGRAM_NAME != $` # __FILE__
  end

  def executed_directly?
    caller[0].rindex(/:\d+(:in `.*')?$/)
    $PROGRAM_NAME == $` # __FILE__
  end
  alias standalone? executed_directly?

  def irb?
    !!(( IRB and $0 == 'irb' ) rescue nil)
  end

  def ignore_sigint! # ctrl+c
     Signal.trap *%w|SIGINT IGNORE|
  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)
require 'zucker'

module Kernel
  private

  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
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}
Information Read more about using tap on the ruby best practices 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)
require 'zucker'

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

Cubes[env]

engine

Summary Adds a RubyEngine class for easy compatibility checks.
Methods/Usage
RubyEngine
# outputs the interpreter name
RubyEngine.mri?
RubyEngine.mri? # true if using the official Ruby interpreter
RubyEngine.jruby?
RubyEngine.jruby? # true if using JRuby
RubyEngine.rubinius?
RubyEngine.rubinius? # true if using rubinius
RubyEngine.ree?
RubyEngine.ree? # true if using enterprise edition
RubyEngine.ironruby?
RubyEngine.ironruby? # true if using IronRuby
RubyEngine.macruby?
RubyEngine.macruby? # true if using MacRuby
RubyEngine.cardinal?
RubyEngine.cardinal? # true if using parrot
Specification (show)
require 'zucker/engine'

describe 'RubyEngine' do
  it 'should display the current ruby interpreter (to_s)' do
    RubyEngine
  end

  it 'should create many method aliases for asking for a specific interpreter' do
    # please see the source or description file
  end
end
Source (show)
require 'zucker'

module RubyEngine
    # try to guess the interpreter
    @interpreter = case
    when RUBY_PLATFORM == 'parrot'
      'cardinal'
    when Object.const_defined?(:RUBY_ENGINE)
      if RUBY_ENGINE == 'ruby'
        if RUBY_DESCRIPTION =~ /Enterprise/
          'ree'
        else
          'mri'
        end
      else
        RUBY_ENGINE.to_s # jruby, rbx, ironruby, macruby, etc.
      end
    else # probably 1.8
      'mri'
    end

  class << self
    def is?(what)
      what === @interpreter
    end
    alias is is?

    def to_s
      @interpreter.to_s
    end

    # ask methods

    def mri?
      RubyEngine.is? 'mri'
    end
    alias official_ruby? mri?
    alias ruby? mri?

    def jruby?
      RubyEngine.is? 'jruby'
    end
    alias java? jruby?

    def rubinius?
      RubyEngine.is? 'rbx'
    end
    alias rbx? rubinius?

    def ree?
      RubyEngine.is? 'ree'
    end
    alias enterprise? ree?

    def ironruby?
      RubyEngine.is? 'ironruby'
    end
    alias iron_ruby? ironruby?

    def cardinal?
      RubyEngine.is? 'cardinal'
    end
    alias parrot? cardinal?
    alias perl? cardinal?
  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.working_directory # Dir.pwd
Info.load_path         # $:
Info.platform          # RUBY_PLATFORM
Info.current_file      # similar to __FILE__
# you could also add them to the global namespace with: include Info
# see the source file for the list of accessors or
Info.list
Information Please note that it is not possible to put some of __THOSE_KEYWORDS__ in methods, so the result might slightly differ. This might affect current_file, current_file_directory, current_line and current_method.
Thanks to Facets for the caller Regexp.
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)
require 'zucker'
require 'rbconfig'
require 'etc'

module Info
  class << self
    # hash like access
    def [](what)
      send what
    end

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

  module_function

  # 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 os
    RbConfig::CONFIG['host_os']
  end

  def process_id
    $$
  end

  def load_path
    $:
  end

  # user
  def user_login
    Etc.getlogin
  end

  def user_name
    Etc.getpwnam(user_login).gecos.split(',')[0]
  end

  # current

  def current_file #  __FILE__
    return $` if caller[0].rindex(/:\d+(:in `.*')?$/)
  end

  def current_file_directory
    if current_file[0,1] == '(' && current_file[-1,1] == ')'
      current_file
    else
      File.dirname(current_file)
    end
  end

  def current_line # __LINE__
    return $1.to_i if caller[0].rindex( /:(\d+)(:in `.*')?$/ )
  end

  def current_method # __method__ (except aliases)
    return $1.to_sym if caller(1)[0].rindex( /\`([^\']+)\'/ )
  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 # also see the RubyVersion cube
    ::RUBY_VERSION
  end

  def ruby_patchlevel
    ::RUBY_PATCHLEVEL
  end

  def ruby_description
    ::RUBY_DESCRIPTION
  end

  def ruby_release_date
    ::RUBY_RELEASE_DATE
  end

  def ruby_engine # warning! not support by every implementation. It's saver to use the RubyEngine cube
    ::RUBY_ENGINE
  end
end
Compatibility 1.9, 1.8 (not all information)
Discussion github wiki

os

Summary Detect the operating system.
Why? Checking for RUBY_PLATFORM does not report the OS when using JRuby and for better readability.
Methods/Usage
OS
# displays the operating system
OS.linux?
OS.linux? # true if you are on a linux machine
OS.mac?
OS.mac? # true for macs
OS.bsd?
OS.bsd? # true for bsds
OS.windows?
include OS; windows? # true for windows. Example of including OS to get the os methods into the global namespace
OS.solaris?
OS.solaris? # true for solaris/sunos
OS.posix?
OS.posix? # true if system is posix compatible
OS.is?
OS.is? /win/ # matches the regex against the os string
Information This cube depends on system information and may not be 100% accurate.
Syntax and semantic inspired by Roger Pack's os gem.
Specification (show)
require 'zucker/os'

describe 'OS' do
  it 'should display the used operation system (to_s)' do; end
end

describe 'linux?' do
  it 'should return true if OS is a linux' do; end
end

describe 'mac?' do
  it 'should return true if OS is a mac or darwin' do; end
end

describe 'bsd?' do
  it 'should return true if OS is a bsd' do; end
end

describe 'windows?' do
  it 'should return true if OS is a windows' do; end
end

describe 'solaris?' do
  it 'should return true if OS is a solaris or sunos' do; end
end

describe 'posix?' do
  it 'should return true if OS is posix compatible' do; end
end

describe 'OS.is?' do
  it "should test if RbConfig::CONFIG['host_os'] matches the regex (boolean value)" do
    OS.is?(/linux/).should ==
    !!( RbConfig::CONFIG['host_os'] =~ /linux/ )
  end
end
Source (show)
require 'zucker'
require 'rbconfig'

module OS
  class << self
    def is?(what)
      what === RbConfig::CONFIG['host_os']
    end
    alias is is?

    def to_s
      RbConfig::CONFIG['host_os']
    end
  end

  module_function

  def linux?
    OS.is?( /linux|cygwin/ )
  end

  def mac?
    OS.is?( /mac|darwin/ )
  end

  def bsd?
    OS.is?( /bsd/ )
  end

  def windows?
    OS.is?( /mswin|mingw/ )
  end

  def solaris?
    OS.is?( /solaris|sunos/ )
  end

  def posix?
    linux? or mac? or bsd? or solaris? or begin 
        fork do end
        true
      rescue NotImplementedError, NoMethodError
        false
      end
  end

  #def symbian?
    #TODO who knows what symbian returns?
  #end

  # ...
end

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

version

Summary Adds a RubyVersion class for easy compatibility checks.
Methods/Usage
RubyVersion
# return RUBY_VERSION
RubyVersion
# check for the main version with a Float
RubyVersion.is? 1.8
# use strings for exacter checking
RubyVersion.is.above '1.8.7'
RubyVersion.is.at_least '1.8.7' # or exactly, below, at_most
# you can use the common comparison operators
RubyVersion >= '1.8.7'
RubyVersion.between? '1.8.6', '1.8.7'
# relase date checks
RubyVersion.is.older_than Date.today
RubyVersion.is.newer_than '2009-08-19'
# accessors
RubyVersion.major # e.g. => 1
RubyVersion.minor # e.g. => 8
RubyVersion.tiny  # e.g. => 7
RubyVersion.patchlevel # e.g. => 249
RubyVersion.description # e.g. => "ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]"
Information Thanks to Hanmac for a nice improvement.
Specification (show)
require 'zucker/version'
require 'date'

describe 'RubyVersion' do
  before :all do
    @remember_version = RUBY_VERSION
    capture_stderr{ RUBY_VERSION = '1.8.7' }
  end

  it 'should display RUBY_VERSION if called directly (to_s)' do
    RubyVersion.to_s.should == '1.8.7'
  end

  context 'using is method with parameter' do
    it 'should check for main version (1.8 or 1.9) when Float paramater is given' do
      RubyVersion.is?( 1.8 ).should == true
      RubyVersion.is?( 1.9 ).should == false
    end

    it 'should check with string comparison if parameter is not Float' do
      RubyVersion.is?( '1.8' ).should == false
    end
  end

  context 'using is method without parameter but method chaining' do
    it 'should return a string for usage with comparison operators' do
      (RubyVersion.is > '1.8.7').should == false
      (RubyVersion <= '1.8.7').should == true
      (RubyVersion.is.between? '1.8.6', '1.8.7').should == true
    end

    it 'should create some handy compare aliases' do
      RubyVersion.is.above( '1.8.7' ).should == false
      RubyVersion.is.at_least( '1.8.7' ).should == true
      RubyVersion.is.exactly( '1.8.7' ).should == true
    end

    it 'also allows to check for the release dates' do
      RubyVersion.is.older_than( Date.today ).should == true
      RubyVersion.is.newer_than( '2000-01-01' ).should == true
    end
  end

  it 'should define some accessors' do
    RubyVersion.major.should == 1
    RubyVersion.minor.should == 8
    RubyVersion.tiny.should == 7
    # RubyVersion.patchlevel  # => RUBY_PATCHLEVEL
    # RubyVersion.description # => RUBY_DESCRIPTION
  end

  after :all do
    capture_stderr{ RUBY_VERSION = @remember_version }
  end
end
Source (show)
require 'zucker'
require 'date'
require 'time'

module RubyVersion
  class << self
    def to_s
      RUBY_VERSION
    end

    # comparable
    def <=>(other)
      value = case other
        when Integer
          RUBY_VERSION.to_i
        when Float
          RUBY_VERSION.to_f
        when String
          RUBY_VERSION
        when Date, Time
          other.class.parse(RUBY_RELEASE_DATE)
        else
          other = other.to_s
          RUBY_VERSION
        end
      value <=> other
    end
    include Comparable

    # chaining for dsl-like language
    def is?(other = nil)
      if other
        RubyVersion == other
      else
        RubyVersion
      end
    end
    alias is is?

    # aliases
    alias below     <
    alias below?    <
    alias at_most   <=
    alias at_most?  <=
    alias above     >
    alias above?    >
    alias at_least  >=
    alias at_least? >=
    alias exactly   ==
    alias exactly?  ==
    def not(other)
      self != other
    end
    alias not?     not
    alias between between?

    # compare dates
    def newer_than(other)
      if other.is_a? Date or other.is_a? Time
        RubyVersion > other
      else
        RUBY_RELEASE_DATE > other.to_s
      end
    end
    alias newer_than? newer_than

    def older_than(other)
      if other.is_a? Date or other.is_a? Time
        RubyVersion < other
      else
        RUBY_RELEASE_DATE < other.to_s
      end
    end
    alias older_than? older_than

    def released_today
      RubyVersion.date == Date.today
    end
    alias released_today? released_today

    # accessors

    def major
      RUBY_VERSION.to_i
    end
    alias main major

    def minor
      RUBY_VERSION.split('.')[1].to_i
    end
    alias mini minor

    def tiny
      RUBY_VERSION.split('.')[2].to_i
    end

    alias teeny tiny

    def patchlevel
      RUBY_PATCHLEVEL
    end

    def platform
      RUBY_PLATFORM
    end

    def release_date
      Date.parse RUBY_RELEASE_DATE
    end
    alias date release_date

    def description
      RUBY_DESCRIPTION
    end
  end
end

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

Cubes[extensions]

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)
require 'zucker'

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

enumerable

Summary Enumerable extensions.
Methods/Usage
Enumerable#mash
[1,2,3].mash{|e| [e, e.to_s] } # => {1=>'1',2=>'2',3=>'3'}
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)
require 'zucker'

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 }
Hash#&
{ 1=>4, 2=>5, 3=>6 } & { 1=>4, 2=>7 } # => { 1=>4 }
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

describe 'Hash#&' do
  it 'should select a sub hash containt only equal key-value pairs' do
    a =  { 1=>4, 2=>5, 3=>6 }
    b=   { 1=>4, 2=>7 }
    (a & b).should == { 1=>4 }
  end
end
Source (show)
require 'zucker'

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

  def &(other)
    Hash[ *select{ |k,v|
      other[k] == v
    }.flatten ]
  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#-
'1234abc5678' - 'b' - /\d/ # => ac
String#^
'Yes vs No'^7 # => 'No'
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
Information constantize is an improved version of ActiveSupport's one.
Specification (show)
require 'zucker/string'

describe 'String#-' do
  it 'should remove the applied Regexp or String from self via gsub' do
    ('1234abc5678' - 'b' - /\d/).should == 'ac'
  end
end

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)
require 'zucker'

class String
  def -(rem)
    gsub( Regexp === rem ? rem : rem.to_s, '' )
  end

  def ^(pos)
    pos = pos.to_i
    if pos >= 0
      self[pos..-1]
    else
      self[0...pos]
    end
  end

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

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

  def ords
    unpack 'C*'
   # bytes.to_a
  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

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
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)
require 'zucker'

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)
require 'zucker'

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[object]

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)
require 'zucker'

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

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)
require 'zucker'

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
Information See this article by Jay Field for more information.
Specification (show)
require 'zucker/not'

describe 'Object#not' do
  it "should return an object on which all methods are redirected to it's receiver object, but return an inverted boolean" do
    [1,2,3].not.empty?.should == true
    nil.not.nil?.should == false
  end
end
Source (show)
require 'zucker'

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

Cubes[to_proc]

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"]
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)
require 'zucker'

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

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] ]
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)
require 'zucker'

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

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']
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)
require 'zucker'

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

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"]
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)
require 'zucker'

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

Cubes[shortcuts]

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
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)
require 'zucker'

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
File.filename
File.basename
Dir.join
File.join
Dir.split
File.split
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)
require 'zucker'

class Object
  alias is_an? is_a? # thanks to utility_belt
end

module Enumerable
  alias with zip
  alias %    zip
end

class Array
  alias ** product
  alias contains? include?
end

class String
  alias contains? include?
end

class Hash
  alias + merge
end

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

class << File
  alias filename basename # thanks rdp :)
end

class << Dir
  def join(*args)
    File.join(*args)
  end

  def split(*args)
    File.split(*args)
  end
end

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

# 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)
require 'zucker'

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

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)
require 'zucker'

class Module
  def square_brackets_for(ivar, assignment = true)
    #  undef []   if respond_to? :[]
    #  undef []=  if respond_to? :[]=

    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

Cubes[debug]

(not included by require 'zucker/default')

binding

Summary Adds a verbose Binding#inspect.
Why? It gives you information about the current environment variables.
Methods/Usage
Binding#inspect, v, vv
# shows your current environment's variables, irb example:
>> a=3
=> 3
>> binding
=> #<Binding:0x94c4b50>
local vars
 - a: 3
 - _: #<Binding:0x94c4b50>
(instance vars)
 - none
self
 - main
block_given?
 - false
Specification (show)
require 'zucker/binding'

describe 'Binding#inspect' do
  it 'should output the current environment' do; end
end
Source (show)
require 'zucker'

class Binding
  def inspect
    put_vars = lambda { |array|
      if array.empty?
        ' - none'
      else
        array.map{|e|
          val = self.eval "#{e}"
          val = val.is_a?( Binding ) ? val.to_s : val.inspect
          " - #{e}: #{ val }"
        }.join "\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

alias v  binding
alias vv binding

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

cc

Summary c outputs the current method callstack.
Methods/Usage
c, cc
c # shows the method callstack
c true # do not hide irb callstack
Specification (show)
require 'zucker/cc'

describe 'c' do
  it 'should output the method callstack' do; end
end
Source (show)
require 'zucker'

module Kernel
  private

  def c(show_irb = false)
    method_stack = caller.reverse.map{ |m|
      m.rindex( /:\d+(:in `(.*)')?$/ )
      $2
    }.compact
    
    if !show_irb && a = method_stack.index( 'irb_binding' )
      method_stack = [ method_stack[0], '(irb)', *method_stack[a+1..-1] ]
    end

    # puts method_stack.map.with_index{ |m, i|
    method_stack.each_with_index{ |m, i|
      puts "  "*i + m
    }
  end

  alias cc c
end

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

dd

Summary Easy debug printing with the p alternative .d. It outputs to stdout and returns self. Accepts a block.
Methods/Usage
Object#d, Object#dd
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'
Information This is inspired by the .tap method.
There is also tap cube with more tap methods.
Specification (show)
require 'zucker/dd'

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
    capture_stdout do
      a.each{ |e|
        (e.d).should == e
      }

      a.each{ |e|
        (e.d{|value| "This is a: #{value}"}).should == e
      }
    end
  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)
require 'zucker'

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

  alias dd d
end

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

mm

Summary m displays an ordered public method list.
Why? See one object's methods without those rarely used inherited methods.
Methods/Usage
Object#m, Object#mm, Object#method_list
'test'.m 2 # outputs the list (2 levels deep), for example:
 String
 [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[], :[]=, :insert, :length, :size, :bytesize, :empty?, :=~, :match, :succ, :succ!, :next, :next!, :upto, :index, :rindex, :replace, :clear, :chr, :getbyte, :setbyte, :to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase, :downcase, :capitalize, :swapcase, :upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split, :lines, :bytes, :chars, :codepoints, :reverse, :reverse!, :concat, :<<, :crypt, :intern, :to_sym, :ord, :include?, :start_with?, :end_with?, :scan, :ljust, :rjust, :center, :sub, :gsub, :chop, :chomp, :strip, :lstrip, :rstrip, :sub!, :gsub!, :chop!, :chomp!, :strip!, :lstrip!, :rstrip!, :tr, :tr_s, :delete, :squeeze, :count, :tr!, :tr_s!, :delete!, :squeeze!, :each_line, :each_byte, :each_char, :each_codepoint, :sum, :slice, :slice!, :partition, :rpartition, :encoding, :force_encoding, :valid_encoding?, :ascii_only?, :unpack, :encode, :encode!, :to_r, :to_c, :blank?, :^, :lchomp, :lchomp!, :ords, :constantize, :+@, :-@, :|]
 Comparable
 [:==, :>, :>=, :<, :<=, :between?]
Information See this article for more information.
Specification (show)
require 'zucker/mm'

describe 'Object#mm' do
  it 'should display an ordered method list' do; end
end
Source (show)
require 'zucker'

module Kernel
  def m(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          m
  alias method_list m
end

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

oo

Summary The o method outputs the current method, line, file and label (if given).
Methods/Usage
o, oo
o # e.g: Reached method `irb_binding', line 1 of file (irb)
o:Label # e.g: Label: reached method `abc', line 7 of file (irb)
Specification (show)
require 'zucker/oo'

describe 'o' do
  it 'should output the current line, file, method and label (if given)' do; end
end
Source (show)
require 'zucker'

module Kernel
  private

  def o(desc = nil)
    caller[0].rindex( /:(\d+)(:in (`.*'))?$/ )
    m = $3 ? "method #$3, " : ""
    d = desc ? "#{desc}: r" : 'R'

    puts "#{d}eached #{m}line #$1 of file #$`"
    # [$`, $1.to_i, $3.to_sym,  desc]
  end 
  alias oo o
end

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

qq

Summary The q method does the same like p, but puts out multiple arguments on the same line.
Methods/Usage
q, qq
q "zucker", '', {6=>7}, 5, 2.3, :o # outputs "zucker"  ""  {6=>7}  5  2.3  :o
Information Inspired by rdp.
Specification (show)
require 'zucker/qq'

describe 'q' do

  it 'should output the same as p for a single arg' do
    capture_stdout{p /some object/}.should ==
    capture_stdout{q /some object/}
  end

  it "should output the same as p but for multiple args one one line, values separated by two spaces" do
    capture_stdout do
      q 1, "1", 2..5, [], {:hallo => :du}, nil, true
    end.chop.should ==
    capture_stdout do
      p 1, "1", 2..5, [], {:hallo => :du}, nil, true
    end.chop.gsub( "\n", '  ' )
  end
end
Source (show)
require 'zucker'

module Kernel
  private

  def q(*args)
    puts args.map( &:inspect )*'  ' unless args.empty?
  end
  alias qq q
end

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

Extras

You can activate some additional aliases for Zucker functionality by executing Zucker.more_aliases! # => [:copy, :n, :init, :returning, :lib?, :RV, :RE]

Changelog

2010-10-03 | Zucker 7
* fixed critical OS.windows? bug


2010-10-03 | Zucker 6
* no new cubes
* bugfix for OS.posix?
* small changes + bugfixes + doc improvements
* added two user methods to Info
* changed egonil semantics ( using method_missing, see http://rbjl.net/26/catch_nil.rb )
* bugfix for vv


2010-09-04 | Zucker 5
* debug edition -  added two debug helpers: oo (output line, method, file) and cc (output method callstack)
* renamed cube D to dd add added more debug aliases (for mm and binding)
* fixed __SPECIAL_VARS__ in info and kernel cube and some minor bugfixes
* Zucker.activate_more_aliases! option
* added Hash#&
* added aliases: File.filename (for basename), Dir.join and Dir.split (for File.join, split)
* added a flexible requiring mechansim in zucker.rb (no api changes)
* restructered packages
* added rake tasks for releasing
* improved RubyVersion constant (cleaner and more flexible)


2010-09-01 | Zucker 4
* fixed Binding#inspect
* added RubyEngine constant
* added RubyVersion constant
* added OS constant
* added q debug method (like p but on one line)
* added String#-


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