Do I need to indent my code in Ruby? - ruby

You would think that this would be an easy question, but I can't find the answer anywhere. >_<
Will Ruby throw syntax errors if my code is indented incorrectly? For example, would code like this work?
if str.blank?
str = "Hello World"
no_input = true
end
Obviously, this is bad style and I should indent correctly regardless. I want to know whether I can rule it out as the cause of a bug during debugging sessions.

Yes, it would work. Ruby only looks for the line breaks.
But since code readability is also very important, I'd say you should take care of whitespace if only for that sake.

Indentation is (Usually) a Stylistic Choice
In Ruby, indentation per se is not relevant, although the location of linebreaks and other whitespace may cause ambiguity for the parser or cause it to consider certain things as separate expressions when you didn't mean for them to be. Here-documents and multi-line strings are also areas where indentation will matter.
In all cases, the real question is "what does the parser see?" In your example, it should be functionally equivalent to the properly-indented code. However, if you really want to know what's going on under the hood, take a look at Ruby's Ripper module to see how your code is actually being parsed.

Ruby is not whitespace sensitive. Your code, although not pretty, will work.
However: http://www.ruby-forum.com/topic/56039
irb(main):001:0> a = ( 4 + 5 )
=> 9
irb(main):002:0> a = ( 4
irb(main):003:1> + 5 )
=> 5
irb(main):004:0> a = ( 4 +
irb(main):005:1* 5 )
=> 9

Related

What's the purpose of `do` in the while loop? [duplicate]

This question already has answers here:
Ruby while syntax
(2 answers)
Closed 7 years ago.
A while loop works with or without do. Please explain why the following two snippets works the same way.
Without do
i = 1
while i < 5
i = i + 1
end
With do
i = 1
while i < 5 do
i = i + 1
end
The non-theoretical answer is quite simply: because the Ruby Syntax Guide said so.
The language syntax guide defines the do keyword as optional for both while and until loops.
From what I understand - and it is mostly a theory - allowing the do to be optional rather than required is mostly for compatibility and allowing for harmonic syntax within the language.
I think of it as an acknowledgment for the "gray" areas, where things are less absolute. The same is done in physics, where light behaves both as a particle and as a wave and we should acknowledge both aspects.
Coming from different languages and school of thought, while is somewhere between a pure keyword (like if) and a method (like loop, which is defined under the Kernel module)
if statements do not require a do to begin a block of code and under the same logic, while loops wouldn't require a do keyword.
This is while as a keyword.
On the other hand, loop requires the do keyword (or the {block}), so why shouldn't while have the same semantics?
This is while as a method (as far as syntax goes).
Ruby is about making the programmer happy. Allowing the do to be optional makes all programmers happy and doesn't require that the Ruby programmer resign themselves to just one school of thought related to the nature of while.
x = 0
while x<3 do puts "hello"; x+=1 end
--output:--
hello
hello
hello
The do is optional, and can be used to clarify a code as in the answer to be on one line. Separation can be done with a do, newline, \, or semicolon.

trying to find documentation on ruby's trailing if usage

I'm working in the RSpec book (page 121) and am being presented with a bit of code that is apparently self evident and clear. It's not self evident for me, and I'm hoping someone can help me understand.
I'm coming to ruby from c# so please use small words :)
Here's the original code
def total_match_count
count = 0
secret = #secret.split('')
#guess.split('').map do |n|
if secret.include?(n)
secret.delete_at(secret.index(n))
count += 1
end
end
count
end
here's the refactor
def total_match_count
secret = #secret.split('')
#guess.split('').inject(0) do |count, n|
count + (delete_first(secret, n) ? 1 : 0)
end
end
def delete_first(code, n)
code.delete_at(code.index(n)) if code.index(n)
end
Again, this is supposed to be so obvious as to need no comment.
I'm not understanding the trailing "if code.index(n)" bit and I can't find any documentation on using the keywords "ruby trailing if"
Obviously I'm missing something basic.
Ruby Post-Conditions as Syntactic Sugar
In Ruby, almost everything is an expression, and keywords like if and unless can be used as expression modifiers that follow an expression. Some languages refer to these as post-conditions, but the general idea is that:
if 1 == 1
puts true
end
is intended to be equivalent to:
puts true if 1 == 1
The post-condition can sometimes make the intent of the code clearer, or create a more natural flow. The parser differentiates between the :if and :if_mod tokens that internally represent the "normal" if-statement and its matching post-condition, but from a programmer's perspective the post-conditions are (or should be) largely syntactic sugar to make certain expressions easier or cleaner to read and write.
You don't ever need post-conditions in Ruby, but you will often find them in idiomatic Ruby code. If you don't grok them, or don't find that they improve the readability of your code, then feel free to ignore them until and unless they seem useful to you.
This:
code.delete_at(code.index(n)) if code.index(n)
is the same as this:
if code.index(n)
code.delete_at(code.index(n))
end
Some people think the one-liner is easier to read. It's a matter of style--when lines become long, the "trailing if" can be a gotcha, as you might not think to read to the end of the line to realize it has a condition attached. Use judiciously.
Ruby also has unless, which can be used in the "trailing" form too:
do_stuff unless no_on_second_thought

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

Idiomatic use of parentheses in Ruby

array.include? 'foo' or array.include? 'bar'
is a syntax error (unexpected keyword_or). Parentheses solve the problem, but as I'm new to Ruby I've no idea which of the following is considered more idiomatic:
Option 1
array.include?('foo') or array.include?('bar')
Option 2
(array.include? 'foo') or (array.include? 'bar')
Does this come down to personal preference, or is one approach considered more "correct"?
I'd suggest you take a look at the community-driven Ruby coding style guide, here particularly the section on Syntax.
Omit parentheses around parameters for methods that are part of an internal DSL (e.g. Rake, Rails, RSpec), methods that are with "keyword" status in Ruby (e.g. attr_reader, puts) and attribute access methods. Use parentheses around the arguments of all other method invocations. - excerpt from the guide
class Person
attr_reader :name, :age
# omitted
end
temperance = Person.new('Temperance', 30)
temperance.name
puts temperance.age
x = Math.sin(y)
array.delete(e)
Are you sure that is failing? Your initial example works fine for me.
ruby-1.9.2-p290 :002 > array = ['bar']
=> ["bar"]
ruby-1.9.2-p290 :003 > array.include? 'foo' or array.include? 'bar'
=> true
As a matter of fact, if anything could be considered idiomatic it would be that one. The low precedence of or allows this to work when you leave the parens off. This characteristic is something that should make it idiomatic to Ruby (and even Perl, which or is a hold over from).
Option 1 is super clear, but considering you included the parens you really have no need to use or. It's probably better to use ||, which has a high precedence like other operators and is just more common. I think using or for the sake of it looking like english is not a great practice. It has a semantic meaning within the language and is probably best used for those qualities.
Option 2 is silly of course. If you're going to include parens, you might as well use them for the method signature.
Hope this helps.
Avdi Grimm reckons you shouldn't use and or or for boolean logic. You should only and or or for control flow (analogous to if or unless)
According to his recommendation, you should use || instead:
array.include?('foo') || array.include?('bar')
Option 1 is preferred since it's common to other languages as well. Option 2 looks like LISP, which is not popular nowadays.

Building a "Semi-Natural Language" DSL in Ruby

I'm interested in building a DSL in Ruby for use in parsing microblog updates. Specifically, I thought that I could translate text into a Ruby string in the same way as the Rails gem allows "4.days.ago". I already have regex code that will translate the text
#USER_A: give X points to #USER_B for accomplishing some task
#USER_B: take Y points from #USER_A for not giving me enough points
into something like
Scorekeeper.new.give(x).to("USER_B").for("accomplishing some task").giver("USER_A")
Scorekeeper.new.take(x).from("USER_A").for("not giving me enough points").giver("USER_B")
It's acceptable to me to formalize the syntax of the updates so that only standardized text is provided and parsed, allowing me to smartly process updates. Thus, it seems it's more a question of how to implement the DSL class. I have the following stub class (removed all error checking and replaced some with comments to minimize paste):
class Scorekeeper
attr_accessor :score, :user, :reason, :sender
def give(num)
# Can 'give 4' or can 'give a -5'; ensure 'to' called
self.score = num
self
end
def take(num)
# ensure negative and 'from' called
self.score = num < 0 ? num : num * -1
self
end
def plus
self.score > 0
end
def to (str)
self.user = str
self
end
def from(str)
self.user = str
self
end
def for(str)
self.reason = str
self
end
def giver(str)
self.sender = str
self
end
def command
str = plus ? "giving ##{user} #{score} points" : "taking #{score * -1} points from ##{user}"
"##{sender} is #{str} for #{reason}"
end
end
Running the following commands:
t = eval('Scorekeeper.new.take(4).from("USER_A").for("not giving me enough points").giver("USER_B")')
p t.command
p t.inspect
Yields the expected results:
"#USER_B is taking 4 points from #USER_A for not giving me enough points"
"#<Scorekeeper:0x100152010 #reason=\"not giving me enough points\", #user=\"USER_A\", #score=4, #sender=\"USER_B\">"
So my question is mainly, am I doing anything to shoot myself in the foot by building upon this implementation? Does anyone have any examples for improvement in the DSL class itself or any warnings for me?
BTW, to get the eval string, I'm mostly using sub/gsub and regex, I figured that's the easiest way, but I could be wrong.
Am I understanding you correctly: you want to take a string from a user and cause it to trigger some behavior?
Based on the two examples you listed, you probably can get by with using regular expressions.
For example, to parse this example:
#USER_A: give X points to #USER_B for accomplishing some task
With Ruby:
input = "#abe: give 2 points to #bob for writing clean code"
PATTERN = /^#(.+?): give ([0-9]+) points to #(.+?) for (.+?)$/
input =~ PATTERN
user_a = $~[1] # => "abe"
x = $~[2] # => "2"
user_b = $~[3] # => "bob"
why = $~[4] # => "writing clean code"
But if there is more complexity, at some point you might find it easier and more maintainable to use a real parser. If you want a parser that works well with Ruby, I recommend Treetop: http://treetop.rubyforge.org/
The idea of taking a string and converting it to code to be evaled makes me nervous. Using eval is a big risk and should be avoided if possible. There are other ways to accomplish your goal. I'll be happy to give some ideas if you want.
A question about the DSL you suggest: are you going to use it natively in another part of your application? Or do just plan on using it as part of the process to convert the string into the behavior you want? I'm not sure what is best without knowing more, but you may not need the DSL if you are just parsing the strings.
This echoes some of my thoughts on a tangental project (an old-style text MOO).
I'm not convinced that a compiler-style parser is going to be the best way for the program to deal with the vaguaries of english text. My current thoughts have me splitting up the understanding of english into seperate objects -- so a box understands "open box" but not "press button", etc. -- and then having the objects use some sort of DSL to call centralised code that actually makes things happen.
I'm not sure that you've got to the point where you understand how the DSL is actually going to help you. Maybe you need to look at how the english text gets turned into DSL, first. I'm not saying that you don't need a DSL; you might very well be right.
As for hints as to how to do that? Well, I think if I were you I would be looking for specific verbs. Each verb would "know" what sort of thing it should expect from the text around it. So in your example "to" and "from" would expect a user immediately following.
This isn't especially divergent from the code you've posted here, IMO.
You might get some milage out of looking at the answers to my question. One commenter pointed me to the Interpreter Pattern, which I found especially enlightening: there's a nice Ruby example here.
Building on #David_James' answer, I've come up with a regex-only solution to this since I'm not actually using the DSL anywhere else to build scores and am merely parsing out points to users. I've got two patterns that I'll use to search:
SEARCH_STRING = "#Scorekeeper give a healthy 4 to the great #USER_A for doing something
really cool.Then give the friendly #USER_B a healthy five points for working on this.
Then take seven points from the jerk #USER_C."
PATTERN_A = /\b(give|take)[\s\w]*([+-]?[0-9]|one|two|three|four|five|six|seven|eight|nine|ten)[\s\w]*\b(to|from)[\s\w]*#([a-zA-Z0-9_]*)\b/i
PATTERN_B = /\bgive[\s\w]*#([a-zA-Z0-9_]*)\b[\s\w]*([+-]?[0-9]|one|two|three|four|five|six|seven|eight|nine|ten)/i
SEARCH_STRING.scan(PATTERN_A) # => [["give", "4", "to", "USER_A"],
# ["take", "seven", "from", "USER_C"]]
SEARCH_STRING.scan(PATTERN_B) # => [["USER_B", "five"]]
The regex might be cleaned up a bit, but this allows me to have syntax that allows a few fun adjectives while still pulling the core information using both "name->points" and "points->name" syntaxes. It does not allow me to grab the reason, but that's so complex that for now I'm going to just store the entire update, since the whole update will be related to the context of each score anyway in all but outlier cases. Getting the "giver" username can be done elsewhere as well.
I've written up a description of these expressions as well, in hopes that other people might find that useful (and so that I can go back to it and remember what that long string of gobbledygook means :)

Resources