I'm reading The "Rails 3 Way" and on page 39, it shows a code sample of the match :to => redirect method. In that method the following code exists. Whilst I know what modulo does with numbers, I'm unsure what the % is doing below because both path and params are clearly not numbers. If anyone can help me understand the use of % in this situation, I'd appreciate it.
proc { |params| path % params }
That's probably the String#% method which works a lot like sprintf does in other languages:
'%05d' % 10
# => "00010"
It can take either a single argument or an array:
'%.3f %s' % [ 10.341412, 'samples' ]
# => "10.341 samples"
Update: As Philip points out, this method also takes a hash:
'%{count} %{label}' % { count: 20, label: 'samples' }
# => "20 samples"
Of course, this is presuming that path is a String. In Ruby you never really know for sure unless you carefully read the code. It's unlikely, but it could be % meaning modulo.
The thing you can be sure of is it's calling method % on path.
It does string interpolation. In the simplest case, it's equivalent to:
"foo %s baz" % 'bar'
#=> "foo bar baz"
However, you can use more complex format specifiers to interpolate from Array or Hash objects too, such as the Rails params hash. See the String#% and Kernel#sprintf methods for details on how to construct a valid format specification.
Related
I have a string like this solution_10 and I would like to remove the part solution_ from it, the number after the underscore will increase, it can be 100, 1000 and even larger. I cant seem to wrap my head around on how to do this.
I have tried to use slice!(0, 9) but that gives me solution_, I then tried slice!(0, -2) but that gives me null,
I then tried using solution_10[1..9] this gives me ortable_1
So my question is how to get rid of all characters till underscore, all I want is the number after the underscore.
Use String#split method
'solution_10'.split('_').last #will return original string if no underscore present
#=> "10"
'solution_10'.split('_')[1] #will return nil if no underscore present
#=> "10"
"solution_10"[/(?<=_).*/]
#⇒ "10"
or simply just get digits until the end of the line:
"solution_10"[/\d+\z/]
#⇒ "10"
I cant seem to wrap my head around on how to do this.
First of all, slice and its shortcut [] can be used in many ways. One way is by providing a start index and a length:
'hello'[2, 3] #=> "llo" # 3 characters, starting at index 2
# ^^^
You can use that variant if you know the length in advance. But since the number part in your string could be 10 or 100 or 1000, you don't.
Another way is to provide a range, denoting the start and end index:
'hello'[2..3] #=> "ll" # substring from index 2 to index 3
# ^^
In this variant, Ruby will determine the length for you. You can also provide negative indices to count from the end. -1 is the last character, -2 the second to last and so on.
So my question is how to get rid of all characters till underscore, all I want is the number after the underscore.
We have to get the index of the underscore:
s = "solution_10"
i = s.index('_') #=> 8
Now we can get the substring from that index to the last character via:
s[i..-1] #=> "_10"
Apparently, we're off by one, so let's add 1:
s[i+1..-1] #=> "10"
There you go.
Note that this approach will not necessarily return a number (or numeric string), it will simply return everything after the first underscore:
s = 'foo_bar'
i = s.index('_') #=> 3
s[i+1..-1] #=> "bar"
It will also fail miserably if the string does not contain an underscore, because i would be nil:
s = 'foo'
i = s.index('_') #=> nil
s[i+1..-1] #=> NoMethodError: undefined method `+' for nil:NilClass
For a more robust solution, you can pass a regular expression to slice / [] as already shown in the other answers. Here's a version that matches an underscored followed by a number at the end of the string. The number part is captured and returned:
"solution_10"[/_(\d+)\z/, 1] #=> "10"
# _ literal underscore
# ( ) capture group (the `1` argument refers to this)
# \d+ one or more digits
# \z end of string
Another way:
'solution_10'[/\d+/]
#=> "10"
Why don't just make use of regex
"solution_10".scan(/\d+/).last
#=> "10"
I have a string of the form "award.x_initial_value.currency" and I would like to camelize everything except the leading "x_" so that I get a result of the form: "award.x_initialValue.currency".
My current implementation is:
a = "award.x_initial_value.currency".split(".")
b = a.map{|s| s.slice!("x_")}
a.map!{|s| s.camelize(:lower)}
a.zip(b).map!{|x, y| x.prepend(y.to_s)}
I am not very happy with it since it's neither fast nor elegant and performance is key since this will be applied to large amounts of data.
I also googled it but couldn't find anything.
Is there a faster/better way of achieving this?
Since "performance is key" you could skip the overhead of ActiveSupport::Inflector and use a regular expression to perform the "camelization" yourself:
a = "award.x_initial_value.currency"
a.gsub(/(?<!\bx)_(\w)/) { $1.capitalize }
#=> "award.x_initialValue.currency"
▶ "award.x_initial_value.x_currency".split('.').map do |s|
"#{s[/\Ax_/]}#{s[/(\Ax_)?(.*)\z/, 2].camelize(:lower)}"
end.join('.')
#⇒ "award.x_initialValue.x_currency"
or, with one gsub iteration:
▶ "award.x_initial_value.x_currency".gsub(/(?<=\.|\A)(x_)?(.*?)(?=\.|\z)/) do |m|
"#{$~[1]}" << $~[2].camelize(:lower)
end
#⇒ "award.x_initialValue.x_currency"
In the latter version we use global substitution:
$~ is a short-hand to a global, storing the last regexp match occured;
$~[1] is the first matched entity, corresponding (x_)?, because of ? it might be either matched string, or nil; that’s why we use string extrapolation, in case of nil "#{nil}" will result in an empty string;
after all, we append the camelized second match to the string, discussed above;
NB Instead of $~ for the last match, one might use Regexp::last_match
Could you try solmething like this:
'award.x_initial_value.currency'.gsub(/(\.|\A)x_/,'\1#').camelize(:lower).gsub('#','x_')
# => award.x_initialValue.currency
NOTE: for # char can be used any of unused char for current name/char space.
To my mind the following three examples are logically equivalent and ought to generate identical results.
print "Enter your string: "
my_string = gets.chomp
#Example 1
my_string.include? ("j" or "J")
puts "1. Your string includes a j or J."
#Example 2
if
my_string.include? ("j" or "J")
puts "2. Your string includes a j or J."
end
#Example 3
if
my_string.include? ("j") or my_string.include? ("J")
puts "3. Your string includes a j or J."
end
Here are the results with a capital J.
Enter your string: Jack
1. Your string includes a j or J.
3. Your string includes a j or J.
Here are the results with a lower case j.
Enter your string: jack
1. Your string includes a j or J.
2. Your string includes a j or J.
3. Your string includes a j or J.
For reasons I don't understand, only examples 1 and 3 generate identical results. In example 2, by contrast, only the first item in the brackets (the lower case j) is evaluated.
But why? If example 1 works perfectly, why does example 2 fail simply because the "include?" method is nested within an "if/end"?
And if we need to wrap the code in an "if/elsif/end" conditional, is there a way in which to list multiple values to be assessed in an "include?" method without needing to write them out individually as in example 3? This would be tedious - almost "anti-Ruby" - if there were many values to be evaluated!
In other words, is there a means of making example 2 work correctly?
Here's what's happening in each of these examples:
First Example
This example outputs 1. Your string includes a j or J. regardless of the previous line. The my_string.include? check is being ignored as it's not used in a comparison anywhere, so the second line is just a regular puts.
Second Example
The second example is a little more interesting. ("j" or "J") is syntax in Ruby which will output the first of the provided arguments which evaluates to true. "j" evaluates to true because it's not nil or false, so it becomes the argument of the second include? method. include? is case-sensitive, so it will return false – the string Jack does not include a lowercase j.
You can try this out by running irb and entering something like 1 or 2 or false and 1; you'll see pretty quickly that the first true argument is returned (or false if no arguments are true).
There's no good way to make this work as-is, other than updating the include? check to use something like set intersections. An easier solution may be to downcase the input before checking characters.
Avdi Grimm posted a good video on using and and or in Ruby.
Third Example
The third example is calling include? twice on the string, and returning true when it hits the second call, hence the if statement being evaluated.
Update
papirtiger's answer got me thinking, so I did a bit of digging with Ripper using the following script:
require 'ripper'
require 'pp'
expression = <<-FOO
if true
puts 'Hello'
end
FOO
pp Ripper.sexp(expression)
Here's the result:
[:program,
[[:if,
[:var_ref, [:#kw, "true", [1, 3]]],
[[:command,
[:#ident, "puts", [2, 2]],
[:args_add_block,
[[:string_literal,
[:string_content, [:#tstring_content, "Hello", [2, 8]]]]],
false]]],
nil]]]
After updating the expression to the following:
expression = <<-FOO
if
true
puts 'Hello'
end
FOO
This was the new output:
[:program,
[[:if,
[:var_ref, [:#kw, "true", [2, 2]]],
[[:command,
[:#ident, "puts", [3, 2]],
[:args_add_block,
[[:string_literal,
[:string_content, [:#tstring_content, "Hello", [3, 8]]]]],
false]]],
nil]]]
It looks as though Ruby does indeed ignore any whitespace and evaluate the next expression. I don't have enough expertise to dig much deeper, but after trying a few more examples (such as throwing a dozen newlines in after an if statement), I'm convinced.
Ruby interpreter evaluates everything line by line and arguments are evaluated first before calling the method. so for example if you have a code that reads foo(bar('test')), then interpreter will evaluate 'test' first that will return string test, then it will pass that as argument to bar and whatever bar returns will be passed to foo.
Lets apply same analysis to each example.
# Example 1
my_string.include? ("j" or "J")
puts "1. Your string includes a j or J."
interpreter will evaluate "j" or "J" on line my_string.include? ("j" or "J"). If you type in irb "j" or "J", you will see the output is "j". So that line becomes my_string.include?("j"). my_string evaluates to "Jack" so whole expression becomes "Jack".include?("j") which returns false and we dont do anything with that information, we just move to next line and print a statement to screen puts "1. Your string includes a j or J.". So no matter what you enter for string, you will always get same answer from Example 1.
Lets go to example 2. If you remove unnecessary new line after if, you can rewrite it in more understandable way:
#Example 2
if my_string.include?("j" or "J")
puts "2. Your string includes a j or J."
end
No we already analyzed my_string.include?("j" or "J") and we know it will be same as "Jack".include?("j") which will return false. so we get if false ..., therefore puts statement in if statement will not be executed and nothing is printed to screen.
Last example can be written in clearer way by removing extra new line after if
if my_string.include? ("j") or my_string.include? ("J")
puts "3. Your string includes a j or J."
end
It will evaluate to if false or true.. which will be if true so it will print the statement.
#Example 2
if
my_string.include? ("j" or "J")
puts "2. Your string includes a j or J."
end
In this case "j" or "J" is an expression which evaluates to "j". You can run this in irb to test for yourself. Expressions are always evaluated using a right-left style walk (see http://www.cs.uml.edu/~canning/101/RLWM.pdf). Ruby is a little fuzzy on this as the last method doesn't need parentheses, so you have to just imagine them being there
Thus, an input of "Jack" doesn't cause this to pass because it doesn't include "j"
It's also worth noting that the or operator is not the same as the ||, and it will likely bite you if you don't use it correctly.
It is really more of a Perl-ism for control flow. See Avdi's screencast on it here: http://devblog.avdi.org/2014/08/26/how-to-use-rubys-english-andor-operators-without-going-nuts/
You may solve this by using the || operator, instead of or - they are not interchangeable. For example 2, try my_string.include?('j') || my_string.include?("J") or even better, my_string.downcase.include?('j')
This question already has an answer here:
Anyone can comment this ruby code? [closed]
(1 answer)
Closed 8 years ago.
I don't know ruby language. I was reading a very interesting article which contain a following 2 line ruby code which i need to understand.
(0..0xFFFFFFFFFF).each do |i|
puts "#{"%010x" % i}"
end
By googling, i get the 1st line. But i am not able to understand 2nd line. Can someone please explain its meaning?
puts "#{"%010x" % i}" has actually two parts - string interpolation (which G.B tells you about), and string format using %:
Format—Uses str as a format specification, and returns the result of
applying it to arg. If the format specification contains more than one
substitution, then arg must be an Array or Hash containing the values
to be substituted. See Kernel::sprintf for details of the format
string.
"%05d" % 123 #=> "00123"
"%-5s: %08x" % [ "ID", self.object_id ] #=> "ID : 200e14d6"
"foo = %{foo}" % { :foo => 'bar' } #=> "foo = bar"
So "%010x" % i formats the integer in hex format (x) with at least 10 digits (10), padding with zeros (the leading 0):
"%010x" % 150000
# => "00000249f0"
Actually
puts "#{"%010x" % i}"
is exactly the same as
puts "%010x" % i
since the interpolation simply puts the resulting value (a string) within a string....
Puts key word is used to print the data on the console.
for example
puts "writing data to console"
above line will print exact line to the console "writing data to console"
#a = "this is a string"
puts #a
this will print "this is a test string"
puts "My variable a contains #{#a}"
this will print "My variable a contains this is a string" and this merging technique is called string interpolation.
this first argument in puts "#{"%010x" % i}" specifies the format and second represents the value.
and for your exact question and further details see this link
it's string interpolation and sprintf
documents:
http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Literals#Interpolation
http://www.ruby-doc.org/core-2.1.2/Kernel.html#method-i-sprintf
http://batsov.com/articles/2013/06/27/the-elements-of-style-in-ruby-number-2-favor-sprintf-format-over-string-number-percent/
"%010x" % i is same as sprintf("%010x", i)
puts "#{"%010x" % i}"
This line print the content. and if you want o interpolated the string please used single quote inside the double quote. like this "#{'%010x' % i }"
and %x means convert integer into hexadecimal and %010x means make it 10 place value means if out is 0 then make it like this 0000000000.
Print
puts is the equivalent of echo in PHP and printf in C
When included in either a command-line app, or as part of a larger application, it basically allows you to output the text you assign to the method:
puts "#{"%010x" % i}"
This will basically print the contents of "#{"%010x" % i}" on the screen - the content of which means that ruby will output the calculaton of what's inside the curly braces (which has been explained in another answer)
I have a heredoc where I am using #{} to interpolate some other strings, but there is an instance where I also want to write the actual text #{some_ruby_stuff} in my heredoc, WITHOUT it being interpolated. Is there a way to escape the #{.
I've tried "\", but no luck. Although it escapes the #{}, it also includes the "\":
>> <<-END
#{RAILS_ENV} \#{RAILS_ENV}
END
=> " development \#{RAILS_ENV}\n"
For heredoc without having to hand-escape all your potential interpolations, you can use single-quote-style-heredoc. It works like this:
item = <<-'END'
#{code} stuff
whatever i want to say #{here}
END
I think the backslash-hash is just Ruby being helpful in some irb-only way.
>> a,b = 1,2 #=> [1, 2]
>> s = "#{a} \#{b}" #=> "1 \#{b}"
>> puts s #=> 1 #{b}
>> s.size #=> 6
So I think you already have the correct answer.
You can use ' quotes instead. Anything enclosed in them is not being interpolated.
Your solution with escaping # also works for me. Indeed Ruby interpreter shows
=> "\#{anything}"
but
> puts "\#{anything}"
#{anything}
=> nil
Your string includes exactly what you wanted, only p method shows it with escape characters. Actually, p method shows you, how string should be written to get exactly object represented by its parameter.