Using [] with the Safe Navigation Operator in Ruby - ruby

I currently have a piece of code that looks like:
if match = request.path.match(/\A\/(?<slug>(?!admin|assets)\w+)/)
match[:slug]
end
Is there a way to use the safe navigation operator (introduced in 2.3.0) to avoid this if conditional?

Just use the ordinary (non-sugar) form.
request.path.match(/\A\/(?<slug>(?!admin|assets)\w+)/)&.[](:slug)

For better readability I would pick #dig instead of the #[].
Like,
request.path.match(/\A\/(?<slug>(?!admin|assets)\w+)/)&.dig(:slug)
instead of
request.path.match(/\A\/(?<slug>(?!admin|assets)\w+)/)&.[](:slug)

For readability, I prefer using the match's named_captures method which is available from ruby 1.9.1, with the safe operator which is available from ruby 2.3.0.
request.path.match(/\A\/(?<slug>(?!admin|assets)\w+)/)&.named_captures&.dig('slug')

You can send any method, so using safe-browsing operator this will be:
request.path.match(/\A\/(?<slug>(?!admin|assets)\w+)/)&.send(:[], :slug)

Related

Negate argument matcher in RSpec 3

I have a function I'm calling that I need to test the arguments of. Normally I'd do something like:
expect(my_obj).to_receive(:my_function).with(include('good_value'))
Is there a way to flip this around, though, to be something like
expect(my_obj).to_receive(:my_function).with(exclude('bad_value'))
In a spec on a return value this is simply accomplished using to_not, but that form of negation is not available when matching arguments it seems. I can find nothing in the docs suggesting a way to do this other than writing a custom matcher, which feels like overkill here.
Is there a simple way I can do this without having to write a custom matcher?
RSpec 3.1+ allows you to define a negated version of any matcher using RSpec::Matchers.define_negated_matcher:
RSpec::Matchers.define_negated_matcher :exclude, :include
Once you've done that, this should work:
expect(my_obj).to_receive(:my_function).with(exclude('bad_value'))
You may try:
http://www.rubydoc.info/gems/rspec-mocks/RSpec/Mocks/ArgumentMatchers#hash_excluding-instance_method
expect(object).to receive(:message).with(hash_excluding(:key => val))

Ruby ternary operator method name?

What is the name of the method corresponding to the ternary operator? By name I mean :+ for addition, :== for equality, etc.
I want to override the ternary operator to build a proxy class (same idea as Javascript proxies) but I can't seem to find the name for this.
There are two names that this is known by, if you are talking about the ? : operator, and that is ternary operator or conditional operator.
But it is not a method, as you can see in this table.
You would need to go to Ruby Source itself to override the behavior. Probably not what you would want to do.
I'm pretty sure it's just known as the ternary operator. Usually people know what you mean when you say that, and I've never heard or seen another name, even during research.
If you mean symbol, I'd call it:
?:
(Question mark, Colon)

Define custom Ruby operator

The question is: Can I define my own custom operator in Ruby, except for the ones found in
"Operator Expressions"?
For example: 1 %! 2
Yes, custom operators can be created, although there are some caveats. Ruby itself doesn't directly support it, but the superators gem does a clever trick where it chains operators together. This allows you to create your own operators, with a few limitations:
$ gem install superators19
Then:
require 'superators19'
class Array
superator "%~" do |operand|
"#{self} percent-tilde #{operand}"
end
end
puts [1] %~ [2]
# Outputs: [1] percent-tilde [2]
Due to the aforementioned limitations, I couldn't do your 1 %! 2 example. The Documentation has full details, but Fixnums can't be given a superator, and ! can't be in a superator.
No. You can only define operators already specified in ruby, +,-,!,/,%, etc. (you saw the list)
You can see for yourself this won't work
def HI
def %!
puts "wow"
end
end
This is largely due to the fact that the syntax parser would have to be extended to accept any code using your new operator.
As Darshan mentions this example alone may not be enough to realize the underlying problem. Instead let us take a closer look at how the parser could possibly handle some example code using this operator.
3 %! 0
While with my spacing it may seem obvious that this should be 3.%!(0) without spacing it becomes harder to see.
3%! can also be seen as 3.%(0.!) The parser has no idea which to chose. Currently, there is no way easy way to tell it. Instead, we could possibly hope to override the meaning of 3.%(0.!) but this isn't exactly defining a new operator, as we are still only limited to ruby's parsable symbols
You probably can't do this within Ruby, but only by modifying Ruby itself. I think modifying parse.y would be your best bet. parse.y famtour

How can I splattify an anonymous object so I can use &method on it?

I'm wanting to use the &method(:method_name) idiom when there's more than one object required by method_name. Can I do this under Ruby 1.9?
For example, if I've got
def move_file(old_filename, new_filename)
STDERR.puts "Moving #{old_filename.inspect} to #{new_filename.inspect}"
# Implementation for careful moving goes here
end
old_filenames = ["foo.txt", "bar.txt", "hoge.ja.txt"]
new_filenames = ["foo_20110915.txt", "bar_20110915.txt", "hoge_20110915.ja.txt"]
the code
old_filenames.zip(new_filenames).each(&method(:move_file))
works under Ruby 1.8, but not under Ruby 1.9. Under Ruby 1.9, it's trying to do move_file(["foo.txt", "foo_20110915.txt"]) instead of move_file("foo.txt", "foo_20110915.txt").
How do I splattify it so it has the correct arity?
Workarounds I'm aware of:
Replace def move_file(old_filename, new_filename) with def move_file(*arguments)
Replace each(&method(:move_file)) with
each{|old_filename, new_filename| move_file(old_filename, new_filename)}
Instead
each{|old_filename, new_filename| move_file(old_filename, new_filename)}
you should be able to do
each{|pair| move_file(*pair)}
But I don't know how you'd pull off blockless variant (I needed it couple of times as well). I guess &-shorthand was made to make the syntax simpler, and is not meant to be clogged much (whether it will be passed an array as an array, or splatted, for example). :)
How do I splattify it so it has the correct arity?
I don't think there is a way to do this while being compatible to both Ruby versions. What you could do is wrap it into a lambda
move_from_to = Proc.new {|*both| move_files(*both) }
The thing is - block and proc arity is something that got addressed in Ruby 1.9 so there might be a difference in behavior there. Also see prc.lambda? here http://www.ruby-doc.org/core/classes/Proc.html for info on what it does to the arity.
This question is also related to what you want to do (the solution there is to resplat and unsplat manually): Inconsistency of arity between Hash.each and lambdas

Overload ! operator in Ruby

Is it possible to overload ! operator in Ruby language?
yes, you can overload this ! in Ruby 1.9, see here http://phrogz.net/programmingruby/language.html#table_18.4 , in this url they had given what are the operators, which are overloaded in Ruby
Yes, in Ruby 1.9 ! is a method and can be overridden.
Source

Resources