Is there a way to have an iterator that iterates anyways even when the object is nil?
For example, I'd like to strip my views from my application and create a dummy app for a designer.
So I would like it to iterate or loop.
How can this be done?
I've just found a way of doing it
<%
(#messages.count == 0 ? Array.new(5).map { Message.new } : #messages.each).each do |m|
%>
You should be able to use something like this:
(#things || dummy_things).each do |thing|
# do something with thing
end
def dummy_things
dummies = []
5.times do
dummies.push(Thing.new)
end
dummies
end
So what this does is to iterarte over dummy things if #things was nil, otherwise only iterate over #things.
EDIT
A more concise version of dummy_things, as mentioned by Victor, would be something like this:
def dummy_things
(0..4).map{ Thing.new }
end
Answer is in your question only, even if you don't have any object, you can iterate 5 times using
5.times do |i|
puts "Dummy page"
end
Related
Does Ruby's Enumerable offer a better way to do the following?
output = things
.find { |thing| thing.expensive_transform.meets_condition? }
.expensive_transform
Enumerable#find is great for finding an element in an enumerable, but returns the original element, not the return value of the block, so any work done is lost.
Of course there are ugly ways of accomplishing this...
Side effects
def constly_find(things)
output = nil
things.each do |thing|
expensive_thing = thing.expensive_transform
if expensive_thing.meets_condition?
output = expensive_thing
break
end
end
output
end
Returning from a block
This is the alternative I'm trying to refactor
def costly_find(things)
things.each do |thing|
expensive_thing = thing.expensive_transform
return expensive_thing if expensive_thing.meets_condition?
end
nil
end
each.lazy.map.find
def costly_find(things)
things
.each
.lazy
.map(&:expensive_transform)
.find(&:meets_condition?)
end
Is there something better?
Of course there are ugly ways of accomplishing this...
If you had a cheap operation, you'd just use:
collection.map(&:operation).find(&:condition?)
To make Ruby call operation only "on a as-needed basis" (as the documentation says), you can simply prepend lazy:
collection.lazy.map(&:operation).find(&:condition?)
I don't think this is ugly at all—quite the contrary— it looks elegant to me.
Applied to your code:
def costly_find(things)
things.lazy.map(&:expensive_transform).find(&:meets_condition?)
end
I would be inclined to create an enumerator that generates values thing.expensive_transform and then make that the receiver for find with meets_condition? in find's block. For one, I like the way that reads.
Code
def costly_find(things)
Enumerator.new { |y| things.each { |thing| y << thing.expensive_transform } }.
find(&:meets_condition?)
end
Example
class Thing
attr_reader :value
def initialize(value)
#value = value
end
def expensive_transform
self.class.new(value*2)
end
def meets_condition?
value == 12
end
end
things = [1,3,6,4].map { |n| Thing.new(n) }
#=> [#<Thing:0x00000001e90b78 #value=1>, #<Thing:0x00000001e90b28 #value=3>,
# #<Thing:0x00000001e90ad8 #value=6>, #<Thing:0x00000001e90ab0 #value=4>]
costly_find(things)
#=> #<Thing:0x00000001e8a3b8 #value=12>
In the example I have assumed that expensive_things and things are instances of the same class, but if that is not the case the code would need to be modified in the obvious way.
I don't think there is a "obvious best general solution" for your problem, which is also simple to use. You have two procedures involved (expensive_transform and meets_condition?), and you also would need - if this were a library method to use - as a third parameter the value to return, if no transformed element meets the condition. You return nil in this case, but in a general solution, expensive_transform might also yield nil, and only the caller knows what unique value would indicate that the condition as not been met.
Hence, a possible solution within Enumerable would have the signature
class Enumerable
def find_transformed(default_return_value, transform_proc, condition_proc)
...
end
end
or something similar, so this is not particularily elegant either.
You could do it with a single block, if you agree to merge the semantics of the two procedures into one: You have only one procedure, which calculates the transformed value and tests it. If the test succeeds, it returns the transformed value, and if it fails, it returns the default value:
class Enumerable
def find_by(default_value, &block)
result = default_value
each do |element|
result = block.call(element)
break if result != default_value
end
end
result
end
You would use it in your case like this:
my_collection.find_by(nil) do |el|
transformed_value = expensive_transform(el)
meets_condition?(transformed_value) ? transformed_value : nil
end
I'm not sure whether this is really intuitive to use...
in Ruby it's easy to tell loop to go to next item
(1..10).each do |a|
next if a.even?
puts a
end
result =>
1
3
5
7
9
but what if I need to call next from outside of the loop (e.g.: method)
def my_complex_method(item)
next if item.even? # this will obviously fail
end
(1..10).each do |a|
my_complex_method(a)
puts a
end
only solution I found and works is to use throw & catch like in SO question How to break outer cycle in Ruby?
def my_complex_method(item)
throw(:skip) if item.even?
end
(1..10).each do |a|
catch(:skip) do
my_complex_method(a)
puts a
end
end
My question is: anyone got any more niftier solution to do this ?? or is throw/catch only way to do this ??
Also what If I want to call my_complex_method not only as a part of that loop (=> don't throw :skip) , can I somehow tell my method it's called from a loop ?
You complex method could return a boolean, and then you compare on your loop like this:
def my_complex_method(item)
true if item.even?
end
(1..10).each do |a|
next if my_complex_method(a)
puts a
end
A simple approach, but different from the try catch one.
UPDATE
As item.even? already return a boolean value, you don't need the true if item.even? part, you can do as follow:
def my_complex_method(item)
item.even?
end
Enumerator#next and Enumerator#peek will be good option to goo :
def my_complex_method(e)
return if e.peek.even?
p e.peek
end
enum = (1..5).each
enum.size.times do |a|
my_complex_method(enum)
enum.next
end
Output
1
3
5
If all you need is to take actions on only some of values, based on value returned by my_complex_method you could use enumerators wisely:
(1..10).map { |a| [a, my_complex_method(a)] }.each do |a, success|
puts a if success
end
You could define method accepting block and take some action in this block based on success or failure there:
(1..10).each do |a|
my_complex_method { |success| next if success }
end
Thanks to scoping, you are able not to use `catch`/`throw`, and call `next` based on processing status.
I've been sifting through the prior questions and answers on stackoverflow, and I have gotten most of my question figured out. I figured out that I can't place a function call within a hash, without placing it within a proc, or a similar container.
What I'm ultimately trying to do is have a menu displayed, grab user input, and then iterate through the hash, and run the specified function:
def Main()
menu_titles = {"Answer1" => Proc.new{Choice1()}}
Menu(menu_titles)
end
def Choice1()
puts "Response answer"
end
def Menu(menu_titles)
menu_titles.each_with_index do |(key, value),index|
puts "#{index+1}. #{key}"
end
user_input = 0
menu_titles.each_with_index do |(key, value), index|
if index.eql?(user_input)
menu_titles[value]
break
end
end
end
Main()
The issue I'm having right now is that I'm not entering the functions that my hash calls for. Whether I use a return or a "puts", I either get a blank line or nothing at all. If anyone has other recommendations about my code, I'm all ears also. To be honest, I don't like using procs, but that's mostly because I don't entirely know how they work and where to use them.
Right now for my menus I have:
user_input = 1
if user_input == 1
Choice1()
...
end
Here's how I would refactor this:
class Menu
attr_reader :titles
# initialize sets up a hard-coded titles instance variable,
# but it could easily take an argument.
def initialize
#titles = {
"Answer1" => Proc.new{ puts "choice 1" },
"Answer2" => Proc.new{ puts "choice 2" }
}
end
# This is the only public instance method in your class,
# which should give some idea about what the class is for
# to whoever reads your code
def choose
proc_for_index(display_for_choice)
end
private
# returns the index of the proc.
def display_for_choice
titles.each_with_index { |(key,value), index| puts "#{index + 1}. #{key}" }
gets.chomp.to_i - 1 # gets will return the string value of user input (try it in IRB)
end
# first finds the key for the selected index, then
# performs the hash lookup.
def proc_for_index(index)
titles[titles.keys[index]]
end
end
If you're serious about Ruby (or object-oriented programming in general), I would highly recommend learning about the advantages of packaging your code into behavior-specific classes. This example allows you to do this:
menu = Menu.new
proc = menu.choose
#=> 1. Answer1
#=> 2. Answer2
2 #(user input)
proc.call
#=> choice 2
And you could actually run it on one line:
Menu.new.choose.call
I've always been searching for something like Python's while / else struct in Ruby to improve my code.
That means that the loop is executed and if the condition in the loop hasn't been true any time, then it returns the value in the else statement.
In ruby, I can do like this :
if #items.empty?
"Empty"
else
#items.each do |item|
item
end
end
So is there a way to improve this ?
Thank you in advance.
Remember that the iterator block returns what you put into it, which can be tested for further use.
if arr.each do |item|
item.some_action(some_arg)
end.empty?
else_condition_here
end
Hm, you could write it as a ternary:
#items.empty? ? 'Empty' : #items.each { |item| item }
You may want to do something more useful in your block though, since each is executed for its side effects and returns the original receiver.
Update as per your comment: I guess the closest you could get is something like
unless #items.empty?
#items.each { |item| p item }
else
'Empty'
end
Since we are in Ruby, let's have fun. Ruby has powerful case construct, which could be used such as this:
case items
when -:empty? then "Empty"
else items.each { |member|
# do something with each collection member
}
end
But to make the above code work, we have to modify the native class Symbol first. Modification of native classes is Ruby specialty. This needs to be done only once, typically in a library (gem), and it helps you ever after. In this case, the modification will be:
class Symbol
def -#
Object.new
.define_singleton_method :=== do |o| o.send self end
end
end
This code overloads the unary minus (-) operator of Symbol class in such way, that saying -:sym returns a new empty object monkey patched with :=== method, that is used behind the scenes by the case statement.
A more or less functional way:
empty_action = { true => proc{ "Empty"},
false => proc{ |arr| arr.each { |item| item }} }
empty_action[#items.empty?][#items]
I have a variable "x" in my view. I need to display some code "x" number of times.
I basically want to set up a loop like this:
for i = 1 to x
do something on (i)
end
Is there a way to do this?
If you're doing this in your erb view (for Rails), be mindful of the <% and <%= differences. What you'd want is:
<% (1..x).each do |i| %>
Code to display using <%= stuff %> that you want to display
<% end %>
For plain Ruby, you can refer to: http://www.tutorialspoint.com/ruby/ruby_loops.htm
x.times do |i|
something(i+1)
end
for i in 0..max
puts "Value of local variable is #{i}"
end
All Ruby loops
You can perform a simple each loop on the range from 1 to `x´:
(1..x).each do |i|
#...
end
Try Below Simple Ruby Magics :)
(1..x).each { |n| puts n }
x.times { |n| puts n }
1.upto(x) { |n| print n }