Elegant Chained 'Or's for Tests on Same Variable in Ruby

Elegant chained 'or's for tests on same variable in Ruby

Make an array and use .include?

if ["01","02","03","04","05"].include?(@thing)

If the values really are all consecutive, you can use a range like (1..5).include? For strings, you can use:

if ("01".."05").include?(@thing)

Are there shorter ways to perform checks on the same variable?

Here's one way:

if %w[A B C].include? variable

or if you have an actual range of values:

if ('A'..'Z').include? variable

How to chain methods in ruby passing the output of one method to consecutive methods

You can leave the ()

def a s
"hello #{s}"
end

def b s
"hi #{s}"
end

puts b a "Tom"

If you have many methods :

puts [:a,:b].inject("Tom"){|result,method| self.send(method,result)}

If you want to use those methods with any object (including Classes) :

module Kernel
def chain_methods(start_value, *methods)
methods.inject(start_value){|result,method| self.send(method,result)}
end
end

class D
def a s
"hello #{s}"
end

def b s
"hi #{s}"
end
end

class E
class << self
def a s
"hello #{s}"
end

def b s
"hi #{s}"
end
end
end


# Example with instance methods
puts D.new.chain_methods("Tom", :a, :b)

# Example with class methods
puts E.chain_methods("Tom", :a, :b)

# Thanks mudasobwa :
E.chain_methods("Tom", :a, :b, :puts)

Is there a more elegant way of writing a while loop in Ruby where the array size is not known?

Assuming your goal is to create an array of odd numbers up to a limit, you can use a range with a step.

limit = 20 
array = (1..limit).step(2).to_a

EDIT

If you want to be able to descend as well as ascend you can use step.

#Ascending 
start = 1
limit = 20

array = start.step(limit, 2).to_a

#Descending
start = 20
limit = 1

array = start.step(limit, -2).to_a

.? (existence) operator in ruby?

Easiest thing to do is use the andand gem, although there are some other, pretty trivially-implemented options, like this, or this, or etc.

Method chaining - why is it a good practice, or not?

I agree that this is subjective. For the most part I avoid method chaining, but recently I also found a case where it was just the right thing - I had a method which accepted something like 10 parameters, and needed more, but for the most time you only had to specify a few. With overrides this became very cumbersome very fast. Instead I opted for the chaining approach:

MyObject.Start()
.SpecifySomeParameter(asdasd)
.SpecifySomeOtherParameter(asdasd)
.Execute();

The method chaining approach was optional, but it made writing code easier (especially with IntelliSense). Mind you that this is one isolated case though, and is not a general practice in my code.

The point is - in 99% cases you can probably do just as well or even better without method chaining. But there is the 1% where this is the best approach.

Accessing elements of nested hashes in ruby

The way I usually do this these days is:

h = Hash.new { |h,k| h[k] = {} }

This will give you a hash that creates a new hash as the entry for a missing key, but returns nil for the second level of key:

h['foo'] -> {}
h['foo']['bar'] -> nil

You can nest this to add multiple layers that can be addressed this way:

h = Hash.new { |h, k| h[k] = Hash.new { |hh, kk| hh[kk] = {} } }

h['bar'] -> {}
h['tar']['zar'] -> {}
h['scar']['far']['mar'] -> nil

You can also chain indefinitely by using the default_proc method:

h = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }

h['bar'] -> {}
h['tar']['star']['par'] -> {}

The above code creates a hash whose default proc creates a new Hash with the same default proc. So, a hash created as a default value when a lookup for an unseen key occurs will have the same default behavior.

EDIT: More details

Ruby hashes allow you to control how default values are created when a lookup occurs for a new key. When specified, this behavior is encapsulated as a Proc object and is reachable via the default_proc and default_proc= methods. The default proc can also be specified by passing a block to Hash.new.

Let's break this code down a little. This is not idiomatic ruby, but it's easier to break it out into multiple lines:

1. recursive_hash = Hash.new do |h, k|
2. h[k] = Hash.new(&h.default_proc)
3. end

Line 1 declares a variable recursive_hash to be a new Hash and begins a block to be recursive_hash's default_proc. The block is passed two objects: h, which is the Hash instance the key lookup is being performed on, and k, the key being looked up.

Line 2 sets the default value in the hash to a new Hash instance. The default behavior for this hash is supplied by passing a Proc created from the default_proc of the hash the lookup is occurring in; ie, the default proc the block itself is defining.

Here's an example from an IRB session:

irb(main):011:0> recursive_hash = Hash.new do |h,k|
irb(main):012:1* h[k] = Hash.new(&h.default_proc)
irb(main):013:1> end
=> {}
irb(main):014:0> recursive_hash[:foo]
=> {}
irb(main):015:0> recursive_hash
=> {:foo=>{}}

When the hash at recursive_hash[:foo] was created, its default_proc was supplied by recursive_hash's default_proc. This has two effects:

  1. The default behavior for recursive_hash[:foo] is the same as recursive_hash.
  2. The default behavior for hashes created by recursive_hash[:foo]'s default_proc will be the same as recursive_hash.

So, continuing in IRB, we get the following:

irb(main):016:0> recursive_hash[:foo][:bar]
=> {}
irb(main):017:0> recursive_hash
=> {:foo=>{:bar=>{}}}
irb(main):018:0> recursive_hash[:foo][:bar][:zap]
=> {}
irb(main):019:0> recursive_hash
=> {:foo=>{:bar=>{:zap=>{}}}}

rspec test model for minimum and maximum values

To test if all valid values are covered you can write something like:

it "should allow valid values" do
(1..24).to_a.each do |v|
should allow_value(v).for(:hours)
end

You can also implement boundary testing. For each boundary one can test at, above and below any boundary to ensure that the conditional logic works as expected as posted by David Chelimsky-2.

So you would have 6 tests in total for the 2 boundaries.



Related Topics



Leave a reply



Submit