Ruby Zucker 10
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. Almost every Zucker feature comes with specs. Everything is documented on this page. The source is available at github.
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 packs. Since there aren't any dependencies within the gem, you can easily require only the packs or cubes you want:
require 'zucker/cube_or_pack_name'
Packs
- control: Cubes that change program behaviour.
- env: Cubes for collecting information.
- extensions: More extensions for Ruby base classes.
- object: Extensions for
Object.
- to_proc: Adds some
to_proc extensions to use with &.
- shortcuts: Cubes that save you keystrokes or disambiguate things.
- debug: Print debugging tools.
Furthermore, there are two meta packs available: all simply requires all cubes and default requires all cubes except debug.
Which methods and constants are added directly to the global namespace by the default pack?
Info, RubyVersion, RubyEngine, OS, Infinity, NaN, alias_for, aliases_for, egonil, nn, iterate, instance_variables_from, ivars, activate_warnings!, deactivate_warnings!, executed_directly?, directly_executed?, 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, nnegonil 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
it 'should raise other Exceptions' do
proc do
egonil{ 5 / 0 }
end.should raise_exception ZeroDivisionError
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 | iterateiterate [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]
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
res = Hash.new {[]} # TODO: why?
res[:iter_a_b] = [] # ....
res[:iter_b_a] = [] # ....
enumerator = iterate a,b
enumerator.should be_kind_of(RUBY_VERSION < '1.9' ? Enumerable::Enumerator : Enumerator)
enumerator.to_a.should == [[1,'a'], [2,'b'], [3,'c'], [nil, 'd']]
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?, directly_executed, 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 or RIPL 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?
alias directly_executed? executed_directly?
def irb?
(defined?(IRB) && $0 =~ /irb/) || (defined?(Ripl) && $0 =~ /ripl/)
end
def ignore_sigint! # ctrl+c
Signal.trap *%w|SIGINT IGNORE|
true
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 | sandboxsandbox do
# dangerous commands throw SecurityErrors ($SAFE=4)
end
# everything's normal again
|
|---|
| Specification | (show)
require 'zucker/sandbox'
describe 'sandbox' do
unless defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
it 'should throw a SecurityError if bad commands are issued' do
proc do
sandbox do
`ls`
end
end.should raise_exception SecurityError
end
end
end |
|---|
| Source | (show)
require 'zucker'
module Kernel
private
def sandbox
Thread.start do
$SAFE = 4
yield
end.value
end
end
# J-_-L |
|---|
| Compatibility | 1.9, 1.8, Does not work on JRuby, since $SAFE is not supported there |
|---|
| 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_ontap_on [1,2] do |obj|
obj[4] = 5
end #=> [1, 2, nil, nil, 5]
make_newmake_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
make_new Hash do |obj|
obj[1] = 2
end.should.send(:'==', { 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, 1.8 |
|---|
| 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? /x/ # 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 |
|---|
file
| Summary | Extensions for File. |
|---|
| Methods/Usage | File.gsubFile.gsub 'some_filename', # will read the file and substitute the hash keys with their values
/hi/ => 'cu',
/\d/ => proc{ |m| (m.to_i+1).to_s }
File.delete!File.delete! 'some_filename' # will delete the file, don't care if it exist. |
|---|
| Information | Idea for File.delete! from sugar-high. |
|---|
| Specification | (show)
require 'zucker/file'
require 'fileutils'
describe 'File.gsub' do
let :random_filename do
'test_' + (0..20).map{|e| [*'a'..'z'].send RUBY_VERSION > '1.9' ? :sample : :choice }*''
end
it 'should read filename in arg1, substitute every key in the arg2 with its value and save the file' do
File.open(random_filename,'w'){ |file|
file.print 'should read filename in arg1, substitute every key in the arg2 with its value and save the file'
}
File.gsub random_filename,
/read/ => 'write',
/\d+/ => proc{|m| (m.to_i+1).to_s }
File.read(random_filename).should ==
'should write filename in arg2, substitute every key in the arg3 with its value and save the file'
FileUtils.rm random_filename
end
end
describe 'File.delete!' do
let :random_filename do
'test_' + (0..20).map{|e| [*'a'..'z'].send RUBY_VERSION > '1.9' ? :sample : :choice }*''
end
it 'should delete the filename given as argument if it exists + return non-nil' do
FileUtils.touch random_filename
res = false
proc do
res = File.delete! random_filename
end.should_not raise_exception
res.should be_true
end
it 'should do nothing if the filename given as argument does not exist + return nil' do
res = false
proc do
res = File.delete! random_filename
end.should_not raise_exception
res.should be_false
end
end |
|---|
| Source | (show)
class << File
def gsub(filename, regex_hash)
data = File.read filename
File.open(filename,'w'){ |file|
regex_hash.each{ |regex, new_string|
regex = regex.to_s unless regex.is_a? Regexp
if new_string.is_a? Proc
data.gsub! regex, &new_string
else
data.gsub! regex, new_string
end
}
file.print data
}
end
def delete! filename
return nil if !File.exist?(filename)
File.delete filename
end
end |
|---|
| Compatibility | 1.9, 1.8 |
|---|
| Discussion | github wiki |
|---|
hash
| Summary | Some sugar for dealing with hashes. |
|---|
| Methods/Usage | Hash.zipHash.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
'Zucker::VERSION'.constantize.should == Zucker::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, 1.8 |
|---|
| Discussion | github wiki |
|---|
Cubes[object]
blank
| Summary | Does pretty the same as in ActiveSupport (Every object can be asked if it is blank or present). |
|---|
| Why? | It's too familiar ;) |
|---|
| Methods/Usage | Object#blank?["'an object'.blank? # => false", "nil.present? # => 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#mcopya = %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 the 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)
if defined? BasicObject # 1.9 only
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
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]
array_to_proc
| 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/array_to_proc'
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 |
|---|
class_to_proc
| 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/class_to_proc'
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 |
|---|
hash_to_proc
| 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/hash_to_proc'
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 |
|---|
regexp_to_proc
| 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/regexp_to_proc'
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_foralias_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#withEnumerable#zip Enumerable#%Enumerable#zip Array#**Array#product Hash#+Hash#merge Binding#[]Binding#eval File.filenameFile.basename Dir.joinFile.join Dir.splitFile.split Infinity1.0 / 0.0 NaN0.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 variables, for example this one:
def initialize(variable1, variable2) @variable1, @variable2 = variable1, variable2 end
|
|---|
| Methods/Usage | instance_variables_from, ivarsdef 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_forclass 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 Binding#vars. It gives you information about the current environment variables. |
|---|
| Methods/Usage | Binding#variables, Binding#vars# shows your current environment's variables, irb example:
>> a=3
=> 3
>> binding.vars
=> #<Binding:0x94c4b50>
local variables
- a: 3
- _: #<Binding:0x94c4b50>
(instance variables)
- none
self
- main
block_given?
- false
|
|---|
| Specification | (show)
require 'zucker/binding'
describe 'Binding#variables' do
it 'should output information about the current environment' do; end
end |
|---|
| Source | (show)
require 'zucker'
class Binding
def variables
put_vars = lambda { |array|
if array.empty?
' - none'
else
array.map{|e|
val = (self.eval "#{e}").inspect
" - #{e}: #{ val }"
}.join "\n"
end
}
puts "#{self.to_s}
local variables
#{ put_vars[ self.eval 'local_variables' ] }
(instance variables)
#{ put_vars[ self.eval 'instance_variables' ] }
self
- #{self.eval 'self'}
block_given?
- #{self.eval 'block_given?'}"
end
alias vars variables
end
# J-_-L |
|---|
| Compatibility | 1.9, 1.8 |
|---|
| Discussion | github wiki |
|---|
cc
| Summary | c outputs the current method callstack. |
|---|
| Methods/Usage | c, ccc # shows the method callstack
c true # do not hide irb/ripl 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
if a = method_stack.index( 'irb_binding' )
method_stack = [ method_stack[0], '(irb)', *method_stack[a+1..-1] ]
elsif a = method_stack[1..-1].index( '<main>' )
method_stack = [ method_stack[0], '(ripl)', *method_stack[a+2..-1] ]
end
end
# puts method_stack.map.with_index{ |m, i|
method_stack.each_with_index{ |m, i|
puts " "*i + m
}
nil
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#ddsome.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>> 5.mm 2 # outputs the list (2 levels deep), for example:
# = Fixnum
# to_s -@ + - * / div % modulo divmod fdiv ** abs magnitude == === <=> > >= < <= ~ & | ^ [] << >> to_f size zero? odd? even? succ
# = Integer
# integer? odd? even? upto downto times succ next pred chr ord to_i to_int floor ceil truncate round gcd lcm gcdlcm numerator denominator to_r rationalize
|
|---|
| 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)
# output helper
mputs = proc{ |e| puts e.map(&:to_s)*' ' }
# how to get results
if self.is_a? Module
klass, method_function = self, :public_methods
else
klass, method_function = self.class, :public_instance_methods
end
# eigenclass
eigen = self.singleton_methods
if !eigen.empty?
puts '= Eigenclass' # sorry for not being up to date, I just love the word
mputs[ self.singleton_methods ]
end
# display
levels.times{ |level|
if cur = klass.ancestors[level]
puts "= #{cur}" # put class name
mputs[ cur.send method_function, false ] # put methods of the class
else
break
end
}
nil
end
alias mm m
alias method_list m
end
# J-_-L |
|---|
| Compatibility | 1.9, 1.8 |
|---|
| Discussion | github wiki |
|---|
oo
| Summary | The o method outputs the current method, line, file and label (if given). |
|---|
| Methods/Usage | o, ooo # 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 outputs multiple arguments on the same line. |
|---|
| Methods/Usage | q, qqq "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 |
|---|
regexp_visualize
| Summary | Test your regex against a string, handy for the command line. |
|---|
| Methods/Usage | Regexp#visualize, Regexp#vis# regex = /\b([A-Z0-9._%+-]+)@([A-Z0-9.-]+\.[A-Z]{2,4})\b/i
regex.vis 'I do not contain an email address.'
# no match
regex.vis 'I contain an email address: mail@example.com'
# I contain an email address: >mail@example.com<
regex.vis 'mail@example.com', 1
# 1: >mail< @example.com
regex.vis 'mail@example.com', 2
# 2: mail@ >example.com<
regex.vis 'mail@example.com', 3
# 3: no match
regex.vis 'mail@example.com', [0,1,2]
# 0: >mail@example.com<
# 1: >mail< @example.com
# 2: mail@ >example.com<
|
|---|
| Specification | (show)
require 'zucker/regexp_visualize'
describe 'Regexp#visualize' do
let :regex do /\b([A-Z0-9._%+-]+)@([A-Z0-9.-]+\.[A-Z]{2,4})\b/i end # regex from regular-expressions.info/email.html
it 'should display a string where >and< mark the found regex' do
capture_stdout do
regex.vis 'I do not contain an email address.'
end.chomp.should == 'no match'
end
it 'should display "no match" if the regex could not be matched' do
capture_stdout do
regex.vis 'I contain an email address: mail@example.com'
end.chomp.should == 'I contain an email address: >mail@example.com< '
end
it 'should display a string where >and< mark the found regex group if group identifier is given as arg2' do
capture_stdout do
regex.vis 'mail@example.com', 1
end.chomp.should == '1: >mail< @example.com'
end
it 'should display "group identifier: no match" the arg2 group could not be matched' do
capture_stdout do
regex.vis 'mail@example.com', 3
end.chomp.should == '3: no match'
end
it 'should also take an array of group identfiers as arg2' do
capture_stdout do
regex.vis 'mail@example.com', [0,1,2]
end.chomp.should == "0: >mail@example.com< \n"\
"1: >mail< @example.com\n"\
"2: mail@ >example.com< "
end
end |
|---|
| Source | (show)
class Regexp
def visualize(string, groups = nil)
if self =~ string
if !groups
puts $` + ' >' + $& + '< ' + $'
else
Array( groups ).each{ |group|
begin
gr_string = string.dup
gr_string[ $~.end( group ), 0 ] = '< '
gr_string[ $~.begin( group ), 0 ] = ' >'
puts group.to_s + ': ' + gr_string
rescue IndexError
puts group.to_s + ': no match'
end
}
end
else
puts 'no match'
end
nil
end
alias vis visualize
end |
|---|
| 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
2011-04-29 | Zucker 10
* doc/spec tweaks
* make test.rubygems.org-testable
* fix zucker 9 permission issue
2011-01-22 | Zucker 9
* remove history versions (sorry, it caused too much gem/rdoc troubles)
* add file cube: File.delete! and File.gsub
* debug pack improvements
* binding: typos + return nil
* cc: support for ripl + return nil
* mm: also show eigenclass for modules + nicer displaying + return nil
* added Regexp#visualize
* remove optional sandbox param
* rename xxx2proc to xxx_to_proc
* change rakefile/rspec/gemspec structure
* more minor fixes and improvements
2010-10-06 | Zucker 8
* fix a little alias_for bug
* disable rdoc creation when installing (in favour of the custom docs)
* change Binding#inspect to Binding.variables (was too verbose and dangerous)
2010-10-03 | Zucker 7
* fix critical OS.windows? bug
2010-10-03 | Zucker 6
* no new cubes
* bugfix for OS.posix?
* small changes + bugfixes + doc improvements
* add two user methods to Info
* change egonil semantics ( using method_missing, see http://rbjl.net/26/catch_nil.rb )
* bugfix for vv
2010-09-04 | Zucker 5
* debug edition - add two debug helpers: oo (output line, method, file) and cc (output method callstack)
* rename cube D to dd add add more debug aliases (for mm and binding)
* fix __SPECIAL_VARS__ in info and kernel cube and some minor bugfixes
* Zucker.activate_more_aliases! option
* add Hash#&
* add aliases: File.filename (for basename), Dir.join and Dir.split (for File.join, split)
* add a flexible requiring mechansim in zucker.rb (no api changes)
* restructure packages
* add rake tasks for releasing
* improve RubyVersion constant (cleaner and more flexible)
2010-09-01 | Zucker 4
* fix Binding#inspect
* add RubyEngine constant
* add RubyVersion constant
* add OS constant
* add q debug method (like p but on one line)
* add String#-
2010-08-14 | Zucker 3
* add tap cube
* add Object#not
* add alias_for for an alternative alias syntax
* add String#constantize (improved AS version)
* improve Info module
* make Array#sum Rails compatibile
* improve docs
* change directory layout (no changes for requiring)
* more small changes
2010-08-08 | Zucker 2
* add info cube
* add chaining for array2proc
* fix Hash.zip
* fix 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