Ruby equivalent for Python's for / else
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
Python's equivalent of Ruby's ||=
I think there is some confusion from the people who aren't really sure what the conditional assignment operator (||=
) does, and also some misunderstanding about how variables are spawned in Ruby.
Everyone should read this article on the subject. A TLDR quote:
A common misconception is that a ||= b is equivalent to a = a || b, but it behaves like a || a = b
In a = a || b, a is set to something by the statement on every run, whereas with a || a = b, a is only set if a is logically false (i.e. if it's nil or false) because || is 'short circuiting'. That is, if the left hand side of the || comparison is true, there's no need to check the right hand side.
And another very important note:
...a variable assignment, even if not run, immediately summons that variable into being.
# Ruby
x = 10 if 2 == 5
puts x
Even though the first line won't be run, x will exist on the second line and no exception will be raised.
This means that Ruby will absolutely ensure that there is a variable container for a value to be placed into before any righthand conditionals take place. ||=
doesn't assign if a
is not defined, it assigns if a
is falsy (again, false
or nil
- nil
being the default nothingness value in Ruby), whilst guaranteeing a
is defined.
What does this mean for Python?
Well, if a
is defined, the following:
# Ruby
a ||= 10
is actually equivalent to:
# Python
if not a:
a = 10
while the following:
# Either language
a = a or 10
is close, but it always assigns a value, whereas the previous examples do not.
And if a
is not defined the whole operation is closer to:
# Python
a = None
if not a:
a = 10
Because a very explicit example of what a ||= 10
does when a
is not defined would be:
# Ruby
if not defined? a
a = nil
end
if not a
a = 10
end
At the end of the day, the ||=
operator is not completely translatable to Python in any kind of 'Pythonic' way, because of how it relies on the underlying variable spawning in Ruby.
Coffeescript idiom equivalent to Python's for/else?
For this certain usage, you can use EcmaScript 6 .find
function. Similar method exists in Underscore.js, if you want to be compatible with browsers not supporting EcmaScript 6.
result = lst.find cond
if result?
do_stuff_with result
else
do_other_stuff()
However, there is no direct replacement for for else
loop from Python. In general case, you will need to declare a boolean to store the state.
equivalent of Python's with in Ruby
Ruby has syntactically lightweight support for literal anonymous procedures (called blocks in Ruby). Therefore, it doesn't need a new language feature for this.
So, what you normally do, is to write a method which takes a block of code, allocates the resource, executes the block of code in the context of that resource and then closes the resource.
Something like this:
def with(klass, *args)
yield r = klass.open(*args)
ensure
r.close
end
You could use it like this:
with File, 'temp.txt', 'w' do |f|
f.write 'hi'
raise 'spitespite'
end
However, this is a very procedural way to do this. Ruby is an object-oriented language, which means that the responsibility of properly executing a block of code in the context of a File
should belong to the File
class:
File.open 'temp.txt', 'w' do |f|
f.write 'hi'
raise 'spitespite'
end
This could be implemented something like this:
def File.open(*args)
f = new(*args)
return f unless block_given?
yield f
ensure
f.close if block_given?
end
This is a general pattern that is implemented by lots of classes in the Ruby core library, standard libraries and third-party libraries.
A more close correspondence to the generic Python context manager protocol would be:
def with(ctx)
yield ctx.setup
ensure
ctx.teardown
end
class File
def setup; self end
alias_method :teardown, :close
end
with File.open('temp.txt', 'w') do |f|
f.write 'hi'
raise 'spitespite'
end
Note that this is virtually indistinguishable from the Python example, but it didn't require the addition of new syntax to the language.
Equivalent of .presence in Python
In Python, you can achieve this by doing the following, assuming params
is a dict
:
state = params.get('state')
country = params.get('country')
region = 'US' if (state and country) else None
The method dict.get(key)
will return the value associated to the key that has been passed. If no such key exists, it returns None
.
If you need to replace the empty values with actual empty strings, you may do this instead:
state = params.get('state', '')
country = params.get('country', '')
region = 'US' if (state and country) else ''
Overall, the "Pythonic" way of doing this is to use a Form:
class Address(Model):
state = ...
country = ...
region = ...
AddressForm = modelform_factory(Address)
#inside view
def view(request):
if request.method == 'POST':
form = AddressForm(request.POST, request.FILES)
if form.is_valid():
address = form.save(commit=False)
address.region = 'US' if address.state and address.country
address.save()
By creating a custom AddressForm class you can do this processing automatically on the instance before saving it. This is the precise role of Form classes.
Searching through a list of objects in Ruby and returning result(s) or raising an error if not found
If you are doing complex things with each, then reading this documentation is the
first step.
Documentation for Enumerable
find is the obvious method that comes to mind, but there are others such as collect or map that might meet your needs as well. Two nested each loops is very un-Ruby like. The inner loop might look like this
matches = @obj_list.find { |obj| func_returning_hash(obj.some_method)[@key] == search }
raise "ERROR: No obj found matching search #{search}" if matches.nil?
results << matches.map { |obj| func_creating_result(obj) }
That's still fairly ugly and not very Ruby-like.
There are lots of ruby style checkers out there these days. Sandi-meter, reek, etc. Using these tools will help you a lot with grokking the ruby way. Coming from python they will seem quite picky and silly, but if you want to get the Ruby way they are very useful.
As an aside, this code screams for a refactoring. You are breaking almost all the basic rules for designing reusable objects. But that can wait...
Sandi Metz Rules for Object Design
From Ruby to Python - Is there an equivalent of try?
Dictionaries: dict.get
You can use dict.get
:
d = {'foo' : 'bar'}
print(d.get('foo'))
'bar'
print(d.get('xxxxx'))
None
You can also pass a default parameter to get
:
print(d.get('xxxxx', 'Invalid Key!'))
Invalid Key!
The default value is printed out when the key does not exist in the dictionary.
Lists: custom try
-except
block
Unfortunately, lists do not have a dict.get
equivalent in their API, so you'll need to implement one yourself. Thankfully, you can extend the list
class and override __getitem__
to do this cleanly.
class MyList(list):
def __getitem__(self, idx, default='oops'):
try:
return super().__getitem__(idx)
except IndexError:
return default
l = MyList([10, 20])
l[1]
# 20
l[3]
# 'oops'
What's the Ruby equivalent of Python's output[:-1]?
I don't want to get too nitpicky, but if you want to be more like Python's approach, rather than doing "StackOverflow"[0..-2]
you can do "StackOverflow"[0...-1]
for the same result.
In Ruby, a range with 3 dots excludes the right argument, where a range with two dots includes it. So, in the case of string slicing, the three dots is a bit more close to Python's syntax.
Related Topics
Bundle Uses Wrong Ruby Version
How to Get a Listing of Only Files Using Dir.Glob
How to Get Today's Date in Ruby 1.9.3
Ruby: "If !Object.Nil" or "If Object"
How to Set a Proxy in Rubys Net/Http
How to Upload a JSON File with Secret Keys to Heroku
No Such File to Load -- Bundler/Setup (Ruby on Rails)
Markdown to Plain Text in Ruby
Can't Find Gem Railties (>= 0.A) with Executable Rails (Gem::Gemnotfoundexception)
What Is the Advantage of Creating an Enumerable Object Using To_Enum in Ruby
Behaviour of Array Bang Methods
How to Generate a Unique Request Id in Rails