So the loose tolerance of Ruby to use braces sometimes and not REQUIRE them has led to alot of confusion for me as I'm trying to learn Rails and when/where to use each and why?
Sometimes parameters or values are passed as (#user, #comment) and other times they seem to be [ :user => comment ] and still others it's just: :action => 'edit'
I'm talking about the us of [ ] vs ( ) vs { }
What ARE the rules? And are there any tricks you have to help you remember?
Parentheses () are for grouping logical or mathematical expressions and grouping arguments to a function call, e.g.:
a = 2 * (3 + 4)
b = (x==y) || (m==n)
Hash.new.send('[]=', :a, :b)
Curly Braces {} are used for hash literals and blocks, e.g.:
h = {1=>2, 2=>3}
h.each {|k,v| puts k+v}
Square Brackets [] are used for array literals, array indexing and slicing, and fetching from a hash, e.g.:
arr = [1, 2, 3]
two = arr[1]
three = h[2]
To confuse the matter, hash literals can also be used in-place as an argument to a method call without needing the curly braces or parentheses as long as it is the last argument (thanks samuil). Additionally, hash literals can be used in-place in square brackets to create a single-item array containing the hash:
puts 1=>2, 3=>4 #=> 1234
[5=>6, 7=>8] #=> [{5=>6, 7=>8}]
When in doubt, always use parentheses to group items and wrap your hashes in curly braces.
Related
I have:
event = {"first_type_a" => 100, "first_type_b" => false, "second_type_a" => "abc", "second_type_b" => false}
I am trying to change the keys of event based on the original. If the name contains a substring, the name will be changed, and the new key, pair value should be added, and the old pair should be removed. I expect to get:
event = {"important.a_1" => 100, "important.b_1" => false, "second_type_a" => "abc", "second_type_b" => false}
What would be the most efficient way to update event?
I expected this to work:
event.each_pair { |k, v|
if !!(/first_type_*/ =~ k) do
key = "#{["important", k.split("_", 3)[2]].join(".")}";
event.merge!(key: v);
event.delete(k)
end
}
but it raises an error:
simpleLoop.rb:5: syntax error, unexpected keyword_do, expecting keyword_then or ';' or '\n'
... if !!(/first_type_*/ =~ k) do
... ^~
simpleLoop.rb:9: syntax error, unexpected keyword_end, expecting '}'
end
^~~
simpleLoop.rb:21: embedded document meets end of file
I thought to approach it differently:
if result = event.keys.find { |k| k.include? "first_type_" } [
key = "#{["important", k.split("_", 3)[2]].join(".")}"
event.merge!(key: v)
event.delete(k)
]
but still no luck. I am counting all brackets, and as the error indicates, it is something there, but I can't find it. Does the order matter?
I will just show how this can be done quite economically in Ruby. Until recently, when wanting to modify keys of a hash one usually would do one of two things:
create a new empty hash and then add key/values pairs to the hash; or
convert the hash to an array a of two-element arrays (key-value pairs), modify the first element of each element of a (the key) and then convert a to the desired hash.
Recently (with MRI v2.4) the Ruby monks bestowed on us the handy methods Hash#transform_keys and Hash#transform_keys!. We can use the first of these profitably here. First we need a regular expression to match keys.
r = /
\A # match beginning of string
first_type_ # match string
(\p{Lower}+) # match 1+ lowercase letters in capture group 1
\z # match the end of the string
/x # free-spacing regex definition mode
Conventionally, this is written
r = /\Afirst_type_(\p{Lower}+)\z/
The use of free-spacing mode makes the regex self-documenting. We now apply the transform_keys method, together with the method String#sub and the regex just defined.
event = {"first_type_a"=>100, "first_type_b"=>false,
"second_type_a"=>"abc", "second_type_b"=>false}
event.transform_keys { |k| k.sub(r, "important.#{'\1'}_1") }
#=> {"important.a_1"=>100, "important.b_1"=>false,
# "second_type_a"=>"abc", "second_type_b"=>false}
In the regex the p{} construct expression \p{Lower} could be replaced with \p{L}, the POSIX bracket expression [[:lower:]] (both match Unicode letters) or [a-z], but the last has the disadvantage that it will not match letters with diacritical marks. That includes letters of words borrowed from other languages that are used in English text (such as rosé, the wine). Search Regexp for documentation of POSIX and \p{} expressions.
If "first_type_" could be followed by lowercase or uppercase letters use \p{Alpha}; if it could be followed by alphanumeric characters, use \p{Alnum}, and so on.
The if starts a block, such as other structures if ... else ... end do ... end begin ... rescue ... end
Therefore your first example remove the do after the if, the block is already open. I also made it clearer by changing the block after each_pair to use do ... end rather than braces to help avoid confusing a hash with a block.
event = { 'first_type_a' => 100, 'first_type_b' => false, 'second_type_a' => 'abc', 'second_type_b' => false }
new_event = {}
event.each_pair do |k, v|
if !!(/first_type_*/ =~ k)
important_key = ['important', k.split('_', 3)[2]].join('.')
new_event[important_key] = v
else
new_event[k] = v
end
end
You could define a method to be used inside the transform key call:
def transform(str)
return ['important.', str.split('_').last, '_1'].join() if str[0..4] == 'first' # I checked just for "first"
str
end
event.transform_keys! { |k| transform(k) } # Ruby >= 2.5
event.map { |k, v| [transform(k), v] }.to_h # Ruby < 2.5
Using Hash#each_pair but with Enumerable#each_with_object:
event.each_pair.with_object({}) { |(k, v), h| h[transform(k)] = v }
Or use as one liner:
event.transform_keys { |str| str[0..4] == 'first' ? ['important.', str.split('_').last, '_1'].join() : str }
I'm trying to build my own evaluator for mathematical expressions in ruby, and before doing that am trying to implement a parser to break the expression into a tree(of arrays). It correctly breaks down expressions with parenthesis, but I am having lots of trouble trying to figure out how to make it correctly break up an expression with operator precedence for addition.
Right now, a string like 1+2*3+4 becomes 1+[2*[3+4]] instead of 1+[2*3]+4. I'm trying to do the simplest solution possible.
Here is my code:
#d = 0
#error = false
#manipulate an array by reference
def calc_expr expr, array
until #d == expr.length
c = expr[#d]
case c
when "("
#d += 1
array.push calc_expr(expr, Array.new)
when ")"
#d += 1
return array
when /[\*\/]/
#d +=1
array.push c
when /[\+\-]/
#d+=1
array.push c
when /[0-9]/
x = 0
matched = false
expr[#d]
until matched == true
y = expr.match(/[0-9]+/,#d).to_s
case expr[#d+x]
when /[0-9]/
x+=1
else matched = true
end
end
array.push expr[#d,x].to_i
#d +=(x)
else
unless #error
#error = true
puts "Problem evaluating expression at index:#{#d}"
puts "Char '#{expr[#d]}' not recognized"
end
return
end
end
return array
end
#expression = ("(34+45)+(34+67)").gsub(" ","")
evaluated = calc #expression
puts evaluated.inspect
For fun, here's a fun regex-based 'parser' that uses the nice "inside-out" approach suggested by #DavidLjungMadison. It performs simple "a*b" multiplication and division first, followed by "a+b" addition and subtraction, and then unwraps any number left in parenthesis (a), and then starts over.
For simplicity in the regex I've only chosen to support integers; expanding each -?\d+ to something more robust, and replacing the .to_i with .to_f would allow it to work with floating point values.
module Math
def self.eval( expr )
expr = expr.dup
go = true
while go
go = false
go = true while expr.sub!(/(-?\d+)\s*([*\/])\s*(-?\d+)/) do
m,op,n = $1.to_i, $2, $3.to_i
op=="*" ? m*n : m/n
end
go = true while expr.sub!(/(-?\d+)\s*([+-])\s*(-?\d+)/) do
a,op,b = $1.to_i, $2, $3.to_i
op=="+" ? a+b : a-b
end
go = true while expr.gsub!(/\(\s*(-?\d+)\s*\)/,'\1')
end
expr.to_i
end
end
And here's a bit of testing for it:
tests = {
"1" => 1,
"1+1" => 2,
"1 + 1" => 2,
"1 - 1" => 0,
"-1" => -1,
"1 + -1" => 0,
"1 - -1" => 2,
"2*3+1" => 7,
"1+2*3" => 7,
"(1+2)*3" => 9,
"(2+(3-4) *3 ) * -6 * ( 3--4)" => 42,
"4*6/3*2" => 16
}
tests.each do |expr,expected|
actual = Math.eval expr
puts [expr.inspect,'=>',actual,'instead of',expected].join(' ') unless actual == expected
end
Note that I use sub! instead of gsub! on the operators in order to survive the last test case. If I had used gsub! then "4*6/3*2" would first be turned into "24/6" and thus result in 4, instead of the correct expansion "24/3*2" → "8*2" → 16.
If you really need to do the expression parsing yourself, then you should search for both sides of an expression (such as '2*3') and replace that with either your answer (if you are trying to calculate the answer) or an expression object (such as your tree of arrays, if you want to keep the structure of the expressions and evaluate later). If you do this in the order of precedence, then precedence will be preserved.
As a simplified example, your expression parser should:
Repeatedly search for all inner parens: /(([^)+]))/ and replace that with a call to the expression parser of $1 (sorry about the ugly regexp :)
Now all parens are gone, so you are looking at math operations between numbers and/or expression objects - treat them the same
Search for multiplication: /(expr|number)*(expr|number)/
Replace this with either the answer or encapsulate the two expressions in
a new expression. Again, depending on whether you need the answer now or
if you need the expression tree.
Search for addition: ... etc ...
If you are calculating the answer now then this is easy, each call to the expression parser eventually (after necessary recursion) returns a number which you can just replace the original expression with. It's a different story if you want to build the expression tree, and how you deal with a mixture of strings and expression objects so you can run a regexp on it is up to you, you could encode a pointer to the expression object in the string or else replace the entire string at the outside with an array of objects and use something similar to regexp to search the array.
You should also consider dealing with unary operators: "3*+3"
(It might simplify things if the very first step you take is to convert all numbers to a simple expression object just containing the number, you might be able to deal with unary operators here, but that can involve tricky situations like "-3++1")
Or just find an expression parsing library as suggested. :)
When I used respond_with and passed a literal hash, it gave me the error:
syntax error, unexpected tASSOC, expecting '}'
`respond_with {:status => "Not found"}`
However, when I enclosed the literal hash in parentheses like so:
respond_with({:status => "Not found"})
the function runs without a hitch. Why do the parentheses make a difference? Isn't a hash an enclosed call?
When calling a method, the opening curly bracket directly after the method name is interpreted as the start of a block. This has precedence over the interpretation as a hash. One way to circumvent the issue is to use parenthesis to enforce the interpretation as a method argument. As an example, please note the difference in meaning of these two method calls:
# interpreted as a block
[:a, :b, :c].each { |x| puts x }
# interpreted as a hash
{:a => :b}.merge({:c => :d})
Another way is to just get rid of the curly brackets as you can always skip the brackets on the last argument of a method. Ruby is "clever" enough to interpret everything which looks like an association list at the end of an argument list as a single hash. Please have a look at this example:
def foo(a, b)
puts a.inspect
puts b.inspect
end
foo "hello", :this => "is", :a => "hash"
# prints this:
# "hello"
# {:this=>"is", :a=>"hash"}
I'm looking at the documentation for FileUtils.
I'm confused by the following line:
FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'
What does the %w mean? Can you point me to the documentation?
%w(foo bar) is a shortcut for ["foo", "bar"]. Meaning it's a notation to write an array of strings separated by spaces instead of commas and without quotes around them. You can find a list of ways of writing literals in zenspider's quickref.
I think of %w() as a "word array" - the elements are delimited by spaces and it returns an array of strings.
Here are all % literals:
%w() array of strings
%r() regular expression.
%q() string
%x() a shell command (returning the output string)
%i() array of symbols (Ruby >= 2.0.0)
%s() symbol
%() (without letter) shortcut for %Q()
The delimiters ( and ) can be replaced with a lot of variations, like [ and ], |, !, etc.
When using a capital letter %W() you can use string interpolation #{variable}, similar to the " and ' string delimiters. This rule works for all the other % literals as well.
abc = 'a b c'
%w[1 2#{abc} d] #=> ["1", "2\#{abc}", "d"]
%W[1 2#{abc} d] #=> ["1", "2a b c", "d"]
There is also %s that allows you to create any symbols, for example:
%s|some words| #Same as :'some words'
%s[other words] #Same as :'other words'
%s_last example_ #Same as :'last example'
Since Ruby 2.0.0 you also have:
%i( a b c ) # => [ :a, :b, :c ]
%i[ a b c ] # => [ :a, :b, :c ]
%i_ a b c _ # => [ :a, :b, :c ]
# etc...
%W and %w allow you to create an Array of strings without using quotes and commas.
Though it's an old post, the question keep coming up and the answers don't always seem clear to me, so, here's my thoughts:
%w and %W are examples of General Delimited Input types, that relate to Arrays. There are other types that include %q, %Q, %r, %x and %i.
The difference between the upper and lower case version is that it gives us access to the features of single and double quotes. With single quotes and (lowercase) %w, we have no code interpolation (#{someCode}) and a limited range of escape characters that work (\\, \n). With double quotes and (uppercase) %W we do have access to these features.
The delimiter used can be any character, not just the open parenthesis. Play with the examples above to see that in effect.
For a full write up with examples of %w and the full list, escape characters and delimiters, have a look at "Ruby - %w vs %W – secrets revealed!"
Instead of %w() we should use %w[]
According to Ruby style guide:
Prefer %w to the literal array syntax when you need an array of words (non-empty strings without spaces and special characters in them). Apply this rule only to arrays with two or more elements.
# bad
STATES = ['draft', 'open', 'closed']
# good
STATES = %w[draft open closed]
Use the braces that are the most appropriate for the various kinds of percent literals.
[] for array literals(%w, %i, %W, %I) as it is aligned with the standard array literals.
# bad
%w(one two three)
%i(one two three)
# good
%w[one two three]
%i[one two three]
For more read here.
Excerpted from the documentation for Percent Strings at http://ruby-doc.org/core/doc/syntax/literals_rdoc.html#label-Percent+Strings:
Besides %(...) which creates a String, the % may create other types of object. As with strings, an uppercase letter allows interpolation and escaped characters while a lowercase letter disables them.
These are the types of percent strings in ruby:
...
%w: Array of Strings
I was given a bunch of columns from a CSV spreadsheet of full names of users and I needed to keep the formatting, with spaces. The easiest way I found to get them in while using ruby was to do:
names = %(Porter Smith
Jimmy Jones
Ronald Jackson).split("\n")
This highlights that %() creates a string like "Porter Smith\nJimmyJones\nRonald Jackson" and to get the array you split the string on the "\n" ["Porter Smith", "Jimmy Jones", "Ronald Jackson"]
So to answer the OP's original question too, they could have wrote %(cgi\ spaeinfilename.rb;complex.rb;date.rb).split(';') if there happened to be space when you want the space to exist in the final array output.
match, text, number = *"foobar 123".match(/([A-z]*) ([0-9]*)/)
I know this is doing some kind of regular expression match but what role does the splat play here and is there a way to do this without the splat so it's less confusing?
The splat is decomposing the regex match results (a MatchData with three groups: the whole pattern, the letters, and the numbers) into three variables. So we end up with:
match = "foobar 123"
text = "foobar"
number = "123"
Without the splat, there'd only be the one result (the MatchData) so Ruby wouldn't know how to assign it to the three separate variables.
is there a way to do this without the splat so it's less confusing?
Since a,b = [c,d] is the same as a,b = *[c,d] and splat calls to_a on its operand when it's not an array you could simply call to_a explicitly and not need the splat:
match, text, number = "foobar 123".match(/([A-z]*) ([0-9]*)/).to_a
Don't know whether that's less confusing, but it's splatless.
There's a good explanation in the documentation for MatchData:
Because to_a is called when expanding
*variable, there‘s a useful assignment shortcut for extracting matched
fields. This is slightly slower than
accessing the fields directly (as an
intermediate array is generated).
all,f1,f2,f3 = *(/(.)(.)(\d+)(\d)/.match("THX1138."))
all #=> "HX1138"
f1 #=> "H"
f2 #=> "X"
f3 #=> "113"
String.match returns a MatchData object, which contains all the matches of the regular expression. The splat operator splits this object and returns all the matches separately.
If you just run
"foobar 123".match(/([A-z]*) ([0-9]*)/)
in irb, you can see the MatchData object, with the matches collected.
MatchData is a special variable, for all intents and purposes an array (kind of) so you can in fact do this as well:
match, text, number = "foobar 123".match(/([A-z]*) ([0-9]*)/)[0..2]
Learn more about the special variable MatchData