Ruby "don't care variable" same as Prolog's? [duplicate] - ruby-on-rails

This question already has answers here:
Where and how is the _ (underscore) variable specified?
(2 answers)
Closed 9 years ago.
So I'm both new to Prolog and Ruby. Learning Prolog at university and Ruby at my own. And I was thinking if there is a "don't care" or "trow away" variable in Ruby as there is in Prolog.
I just opened irb and just did this (supposing underscore was the "don't care" sign)
1.9.2-p290 :003 > _, b, c = [1,2,3]
=> [1, 2, 3]
1.9.2-p290 :004 > b
=> 2
1.9.2-p290 :005 > c
=> 3
The results are actually what I expected. But then I was curious about what where the value of underscore and what class it was
1.9.2-p290 :006 > _
=> 3
1.9.2-p290 :008 > _.class
=> Fixnum
Well, that's odd. Shouldn't it trow the value away? Why other value being stored?
Then doing more tests with underscore I saw what actually it was happening, it has the last evaluated value.
1.9.2-p290 :017 > 1
=> 1
1.9.2-p290 :018 > _
=> 1
1.9.2-p290 :019 > "string"
=> "string"
1.9.2-p290 :020 > _
=> "string"
1.9.2-p290 :021 > Hash
=> Hash
1.9.2-p290 :022 > _
=> Hash
So my question is: What's actually underscore for? Is it really a don't care variable or something else? What's the real name for it? (because I don't find many thing with "don't care ruby variable" with google)

What's throwing you is that you're seeing two different uses of the underscore.
In argument lists, it acts like a "don't care variable," like in Prolog.
Outside of argument lists, it's just a normal identifier. In IRB, it's bound to the previous result. Since your last input was c = 3, _ is 3. This is only in IRB, though — it doesn't happen in normal Ruby programs.

In the Ruby community, _ means "don't care".
In the Ruby language, _ doesn't mean anything, it's an identifier like any other.
In the YARV Ruby interpreter, the "unused local variable" warning is suppressed for _, thus encoding the convention in #1.
In IRb, _ is bound to the value of the last expression.

The underscore in Ruby acts like any normal variable, except it's a bit more special than that. It really does stand for "I don't care".
For, example, let's say you're looping through a array who's elements are 3-element arrays:
array = [[1,2,3],[4,5,6],[7,8,9],...]
Let's say you're only interested in the middle value. With _ you could do this:
array.each do |_, number, _|
# do something
end
If you try to do this with another variable, you will get the (expected) error that you duplicated a variable:
array.each do |v, number, v|
# do something
end
=> SyntaxError: (eval):2: duplicated argument name

Related

Ruby: interpolated string to variable name [duplicate]

This question already has answers here:
How to dynamically create a local variable?
(4 answers)
Closed 5 years ago.
In Ruby, how can I interpolate a string to make a variable name?
I want to be able to set a variable like so:
"post_#{id}" = true
This returns a syntax error, funnily enough:
syntax error, unexpected '=', expecting keyword_end
I believe you can do something like:
send("post_#{id}=", true)
That would require, of course, that you have appropriate setter/getter. Which, since you're doing this dynamically, you probably don't.
So, perhaps you could do:
instance_variable_set("#post_#{id}",true)
To retrieve the variable:
instance_variable_get("#post_#{id}")
BTW, if you get tired of typing instance_variable_set("#post_#{id}",true), just for fun you could do something like:
class Foo
def dynamic_accessor(name)
class_eval do
define_method "#{name}" do
instance_variable_get("##{name}")
end
define_method "#{name}=" do |val|
instance_variable_set("##{name}",val)
end
end
end
end
In which case you could:
2.3.1 :017 > id = 2
=> 2
2.3.1 :018 > f = Foo.new
=> #<Foo:0x00000005436f20>
2.3.1 :019 > f.dynamic_accessor("post_#{id}")
=> :post_2=
2.3.1 :020 > f.send("post_#{id}=", true)
=> true
2.3.1 :021 > f.send("post_#{id}")
=> true
2.3.1 :022 > f.send("post_#{id}=", "bar")
=> "bar"
2.3.1 :023 > f.send("post_#{id}")
=> "bar"
This concerns the getting and setting of local variables. Suppose
id = 1
s = "post_#{id}"
#=> "post_1"
Since Ruby v1.8 it has not been possible to create local variables dynamically. Therefore, if a local variable post_1 does not exist, the only way you can create it is by using an assignment statement:
post_1 = false
If the local variable post_1 exists, you can retrieve its value dynamically with
b = binding
b.local_variable_get(s)
#=> false
(or b.local_variable_get(s.to_sym)) and set its value dynamically with
b.local_variable_set(s, true)
#=> true
post_1
#=> true
(or b.local_variable_set(s.to_sym, true)).
See Binding#local_variable_get and Binding#local_variable_set.

trying to understand specific bit of ruby syntax

I'm new to both Ruby and Rails, and as I go over various tutorials, I occasionally hit on a bit of Ruby syntax that I just can't grok.
For instance, what does this actually do?
root to: "welcome#index"
I can gather that this is probably a method named "root", but I'm lost after that. "To" isn't a symbol, is it? The colon would be before, as in ":to" if it were. Is this some form of keyword argument utilizing hashes? I can't make this syntax work when trying it in irb with ruby1.9.3.
I know this might be a RTFM question, but I can't even think of what to google for this.
Thanks!
I'm still playing around with this syntax,
def func(h)
puts h[:to]
end
x = { :to => "welcome#index" }
y = :to => "welcome#index"
z = to: "welcome#index"
func to: "welcome#index"
I see that this example only works with the lines defining "y" and "z" commented out. So the braceless and the "colon-after" syntax are only valid in the context of calling a method?
First, that's right - root is a method call.
Now
to: 'welcome#index'
is equivalent to
:to => 'welcome#index'
and it's a Hash where the key is :to symbol and value is 'welcome#index' string. You can use this syntax in defining hashes since Ruby 1.9.
It's equivalent to
root(:to => "welcome#index")
I'm having trouble finding the official documentation on the new hash syntax, but when you see foo: bar, it means that foo is a symbol used as a key in the hash and has a value bar.
Here is an example of defining a function foo which takes a hash, and prints to screen.
def foo(hash)
puts hash.inspect
puts hash[:to]
end
foo to: "wecome#index" #method call without paratheses
Output of method call above:
{:to=>"welcome#index"}
welcome#index
Equivalent declarations:
h = {:to => "welcome#index"}
h = {to: "wecolme#index"}
Also, you can use Ripper (part of Ruby standard library) to understand how Ruby parses code. In the example below, I have already defined foo as above. Now, I call foo without using Ripper. Then I use Ripper to see how Ruby parses the method call.
[2] pry(main)> foo to: "welcome#index"
{:to=>"welcome#index"}
welcome#index
=> nil
[3] pry(main)> require 'ripper'
=> true
[4] pry(main)> Ripper.sexp 'foo to: "welcome#index"'
=> [:program,
[[:command,
[:#ident, "foo", [1, 0]],
[:args_add_block,
[[:bare_assoc_hash,
[[:assoc_new,
[:#label, "to:", [1, 4]],
[:string_literal,
[:string_content, [:#tstring_content, "welcome#index", [1, 9]]]]]]]],
false]]]]
In ruby braces in method calls are optional, so it can be rewritten as:
root(to: "welcome#index")
and it can be rewritten again as
root(:to => "welcome#index")
Hashes as keyword arguments(ruby 1.9) explained here as well: hash-constructor-parameter-in-1-9
P.S. and by the way general rule of the thumb for the rails-newcomers is "learn ruby first, then learn rails" ;)
As you correctly gathered, root is a method call. Or rather, it's a message send. Ruby, like Smalltalk, builds upon a messaging metaphor, where objects send messages to other objects, and those objects (called the receiver) respond to those messages.
In this case, you pass an argument to root, that's how you know it's a message send. Message sends are the only thing that can take arguments, if you see an argument, then it must be a message send. There are no functions, no static methods, no constructors, no procedures, only methods and message sends.
So, what is the argument? Well, in Ruby, a lot of things that are syntactically required in other languages are optional. For example, parenthesis around the argument list:
foo.bar(baz)
# can also be written as
foo.bar baz
If the very last argument to the message send is a Hash literal, you can leave off the curly braces:
foo.bar({ :baz => 23, :quux => 42 })
# can also be written as
foo.bar(:baz => 23, :quux => 42)
Put the two together, and you get:
foo.bar({ :baz => 23, :quux => 42 })
# can also be written as
foo.bar :baz => 23, :quux => 42
In Ruby 1.9, a new alternative Hash literal syntax was introduced. This literal syntax is very limited compared to the original one, because it can only express Hashes whose keys are Symbols which are also valid Ruby identifiers, whereas with the original syntax, you can write down a Hash with any arbitrary object as key. But, for that limited use case, it is very readable:
{ :baz => 23, :quux => 42 }
# can also be written as
{ baz: 23, quux: 42 }
If we put that feature together with the other two, we get the message send syntax you are asking about:
foo.bar baz: 23, quux: 42
If we have method declared with a single argument like this:
def foo.bar(opts) p opts end
opts will be bound to a single Hash with two key-value pairs.
These features were often used to emulate keyword arguments as found in other languages. And it has long been a desire of the Ruby community to get support for real keyword arguments. This support was implemented in two steps: first, the new Hash literal syntax was introduced in Ruby 1.9, which allows you to make message sends which look like they are using keyword arguments, even though they are really just a Hash. And then in a second step, in Ruby 2.0 real keyword arguments were introduced. The modified method signature would look like this:
def foo.bar(baz: nil, quux: nil) p baz, quux end
Note that at the moment, it is not possible to have required keyword arguments, they always need to have a default value and are thus always optional. You can, however, use the fact that default values can be arbitrary expressions and do something like this:
def foo.bar(baz: raise ArgumentError '`baz` must be supplied!',
quux: raise ArgumentError '`quux` must be supplied!') p baz, quux end
In a future version of Ruby (it was actually already implemented in February and will likely be in 2.1), required keyword arguments can be specified by omitting the default value:
def foo.bar(baz:, quux:) p baz, quux end
Note that there is a syntactic ambiguity now:
foo.bar baz: 23, quux: 42
# is this sending the message `bar` to `foo` with *one* `Hash` or *two* keywords?
This ambiguity is actually intentional, because it allows old client code written against APIs which use a Hash argument to work unchanged with new APIs that use keyword arguments. There are some semi-complex rules which determine whether that syntax will be interpreted as a Hash or as keywords, but mostly those rules work out the way you would expect them to.

Regex global variables are not being set

I came across something that seems unusual and I was wondering if anyone could explain why.
1.8.7 :001 > some_str = "Hello World"
=> "Hello World"
1.8.7 :002 > some_str.try(:match, /^(\w*)/)
=> #<MatchData "Hello" 1:"Hello">
1.8.7 :003 > $1
=> nil
1.8.7 :004 > some_str.match(/^(\w*)/)
=> #<MatchData "Hello" 1:"Hello">
1.8.7 :005 > $1
=> "Hello"
I'm not sure why the global variable $1 is not being set the first time, but is set the second. Any insights?
Let me show you how try is implemented. If you want to see it yourself, then take a look at the activesupport source. It's defined in /lib/active_support/core_ext/object/try.rb
class Object
def try(*a, &b)
if a.empty? && block_given?
yield self
else
public_send(*a, &b)
end
end
end
What this basically does, is just sending the method name and the complete arguments to the Object. public_send is the same as send, but can only be used to call public methods.
So I rewrote this, to debug your issue:
class Object
def try(*a)
result = public_send(*a)
puts $1.inspect
result
end
end
string = "Hello"
string.try(:match, /^(\w*)/)
puts $1.inspect
This outputs
"Hello"
nil
So the great question arises: Is this a bug in the ruby interpreter?. Maybe. At least it's not documented in any official source. I found a reference that tells the following (See Global variables.)
[...], $_ and $~ have local scope. Their names suggest they should be global, but they are much more useful this way, and there are historical reasons for using these names.
So it seems like $1 is not a global variable as well, even though it is reported by the Kernel as a global variable:
1.9.3-p194 :001 > global_variables
=> [:$;, :$-F, :$#, :$!, :$SAFE, :$~, :$&, :$`, :$', :$+, :$=, :$KCODE, :$-K,
:$,, :$/, :$-0, :$\, :$_, :$stdin, :$stdout, :$stderr, :$>, :$<, :$.,
:$FILENAME, :$-i, :$*, :$?, :$$, :$:, :$-I, :$LOAD_PATH, :$",
:$LOADED_FEATURES, :$VERBOSE, :$-v, :$-w, :$-W, :$DEBUG, :$-d, :$0,
:$PROGRAM_NAME, :$-p, :$-l, :$-a, :$binding, :$1, :$2, :$3, :$4, :$5, :$6,
:$7, :$8, :$9]
To make sure, I forwarded this incosistency to the Ruby Bug Tracker. See Ruby Bug #6723
try is defined as
def try(method, *args, &block)
send(method, *args, &block)
end
except of course on nil where it just returns nil. Why does this matter? Because the regexp globals aren't real globals: they're maintained on a per method and per thread basis (it's easy enough to see this by perusing the ruby source). When you call match via try the globals are set in the scope for try but in the next case they are set at the top level. It's easy to verify this
def do_match string, regexp
string =~ regexp
$1
end
do_match "Hello World", /^(\w*)/ #=> returns 'Hello'
$1 #=> returns nil

What does "<<" exactly do in ruby?

I am new to Ruby, so I am still learning several things. But, I do have good experience with Java and C.
I would like to know what this does exactly:
[ 'a','b', 'c' ].each_with_index {|item, index| result << [item, index] }
Specifically, I am interested in the <<. Some research tells me that it is used for bit shifting, but it's obvious that is not the case here, so what is it doing here?
The << operator is adding items to the result array in this case.
See " how to add elements to ruby array (solved)".
In Ruby, all the things which are operators in C/Java, like +, -, *, /, and so on, are actually method calls. You can redefine them as desired.
class MyInteger
def +(other)
42 # or anything you want
end
end
Array defines the << method to mean "push this item on the end of this array". For integers, it's defined to do a bit shift.
Aside from Array, many other classes define << to represent some kind of "appending" operation.
It's the Array append operator.
<< is a method, and will do different things for different classes. Array uses it to push an object onto the end of an array. Fixnums use it to shift.
This is basically an Append Operator.
It was be used with to append either an element to an array or a substring to string
For Arrays
1.9.2-p290 :009 > arr = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
1.9.2-p290 :010 > arr << 6
=> [1, 2, 3, 4, 5, 6]
1.9.2-p290 :011 >
For Strings
1.9.2-p290 :011 > str = "ruby"
=> "ruby"
1.9.2-p290 :012 > str << 'rails'
=> "rubyrails"
1.9.2-p290 :013 >

How to check if a param is true or false?

This is really racking my brain, but maybe I'm trying to hard.
I'm passing a param via a URL (example.com?debug=true)
So I basically want to say:
if params[:debug] == true
do xyz
else
do abc
end
But for whatever reason that if statement just isn't doing like it seems like it should.
Is there a better way to do that if/else statement based on a param being true or false?
The debug param will either have a value of true, no value, or a value of false (as far as the URL goes).
params come in as strings, so you need to compare against "true", not true.
You could use ActiveRecord's method of checking truthful values if you don't want to reinvent the wheel (this is what is used when passing params inside an ActiveRecord object
Rails 3-4.1
if ActiveRecord::ConnectionAdapters::Column.value_to_boolean(params[:debug])
do xyz
else
do abc
Rails 4.2.0
ActiveRecord::Type::Boolean.new.type_cast_from_database(params[:debug])
Rails 5
ActiveModel::Type::Boolean.new.cast(params[:debug])
Might be worth wrapping in a helper but never the less it's quite flexible:
rails c
Loading development environment (Rails 3.2.6)
1.9.3p194 :001 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean '1'
=> true
1.9.3p194 :002 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean '0'
=> false
1.9.3p194 :003 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean 1
=> true
1.9.3p194 :004 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean true
=> true
1.9.3p194 :005 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean 'true'
=> true
1.9.3p194 :006 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean 'on'
=> true
1.9.3p194 :007 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean 'off'
Custom extension
Some people frown on extending core classes but this does fit with the DRY principle.
# config/initializer/boolean.rb
class Boolean
def self.parse(value)
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
end
Then used like
if Boolean.parse(params[:debug])
then xyz
Since Rails/ActiveRecord 4.2.0 it is
if ActiveRecord::Type::Boolean.new.type_cast_from_user params[:debug]
do xyz
else
do abc
end
In Rails 5 it is:
if ActiveModel::Type::Boolean.new.cast params[:debug]
do xyz
else
do abc
end
But for whatever reason that if statement just isn't doing like it seems like it should.
I can almost guarantee that it is doing exactly what it should. When things don't make sense, one of our assumptions is wrong.
Is the value actually a boolean or is it string (or something else?). If the value is a string then of course the comparison to the boolean value true will fail. Try comparing to 'true' and see if that works.
how about this?
params[:debug].to_s.downcase == 'true'

Resources